--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<stylesheet xmlns="http://www.w3.org/1999/XSL/Transform" version="1.0">
+<param name="chunk.quietly">1</param>
+<param name="funcsynopsis.style">ansi</param>
+</stylesheet>
--- /dev/null
+# install the aoe-specific udev rules from udev.txt into
+# the system's udev configuration
+#
+
+me="`basename $0`"
+
+# find udev.conf, often /etc/udev/udev.conf
+# (or environment can specify where to find udev.conf)
+#
+if test -z "$conf"; then
+ if test -r /etc/udev/udev.conf; then
+ conf=/etc/udev/udev.conf
+ else
+ conf="`find /etc -type f -name udev.conf 2> /dev/null`"
+ if test -z "$conf" || test ! -r "$conf"; then
+ echo "$me Error: no udev.conf found" 1>&2
+ exit 1
+ fi
+ fi
+fi
+
+# find the directory where udev rules are stored, often
+# /etc/udev/rules.d
+#
+rules_d="`sed -n '/^udev_rules=/{ s!udev_rules=!!; s!\"!!g; p; }' $conf`"
+if test -z "$rules_d" || test ! -d "$rules_d"; then
+ echo "$me Error: cannot find udev rules directory" 1>&2
+ exit 1
+fi
+sh -xc "cp `dirname $0`/udev.txt $rules_d/60-aoe.rules"
--- /dev/null
+ HP IPAQ H1940
+ =============
+
+http://www.handhelds.org/projects/h1940.html
+
+Introduction
+------------
+
+ The HP H1940 is a S3C2410 based handheld device, with
+ bluetooth connectivity.
+
+
+Support
+-------
+
+ A variety of information is available
+
+ handhelds.org project page:
+
+ http://www.handhelds.org/projects/h1940.html
+
+ handhelds.org wiki page:
+
+ http://handhelds.org/moin/moin.cgi/HpIpaqH1940
+
+ Herbert Pötzl pages:
+
+ http://vserver.13thfloor.at/H1940/
+
+
+Maintainers
+-----------
+
+ This project is being maintained and developed by a variety
+ of people, including Ben Dooks, Arnaud Patard, and Herbert Pötzl.
+
+ Thanks to the many others who have also provided support.
+
+
+(c) 2005 Ben Dooks
\ No newline at end of file
--- /dev/null
+ Samsung/Meritech SMDK2440
+ =========================
+
+Introduction
+------------
+
+ The SMDK2440 is a two part evaluation board for the Samsung S3C2440
+ processor. It includes support for LCD, SmartMedia, Audio, SD and
+ 10MBit Ethernet, and expansion headers for various signals, including
+ the camera and unused GPIO.
+
+
+Configuration
+-------------
+
+ To set the default configuration, use `make smdk2440_defconfig` which
+ will configure the common features of this board, or use
+ `make s3c2410_config` to include support for all s3c2410/s3c2440 machines
+
+
+Support
+-------
+
+ Ben Dooks' SMDK2440 site at http://www.fluff.org/ben/smdk2440/ which
+ includes linux based USB download tools.
+
+ Some of the h1940 patches that can be found from the H1940 project
+ site at http://www.handhelds.org/projects/h1940.html can also be
+ applied to this board.
+
+
+Peripherals
+-----------
+
+ There is no current support for any of the extra peripherals on the
+ base-board itself.
+
+
+MTD
+---
+
+ The NAND flash should be supported by the in kernel MTD NAND support,
+ NOR flash will be added later.
+
+
+Maintainers
+-----------
+
+ This board is being maintained by Ben Dooks, for more info, see
+ http://www.fluff.org/ben/smdk2440/
+
+ Many thanks to Dimitry Andric of TomTom for the loan of the SMDK2440,
+ and to Simtec Electronics for allowing me time to work on this.
+
+
+(c) 2004 Ben Dooks
\ No newline at end of file
--- /dev/null
+This README escorted the skystar2-driver rewriting procedure. It describes the
+state of the new flexcop-driver set and some internals are written down here
+too.
+
+This document hopefully describes things about the flexcop and its
+device-offsprings. Goal was to write an easy-to-write and easy-to-read set of
+drivers based on the skystar2.c and other information.
+
+Remark: flexcop-pci.c was a copy of skystar2.c, but every line has been
+touched and rewritten.
+
+History & News
+==============
+ 2005-04-01 - correct USB ISOC transfers (thanks to Vadim Catana)
+
+
+
+
+General coding processing
+=========================
+
+We should proceed as follows (as long as no one complains):
+
+0) Think before start writing code!
+
+1) rewriting the skystar2.c with the help of the flexcop register descriptions
+and splitting up the files to a pci-bus-part and a flexcop-part.
+The new driver will be called b2c2-flexcop-pci.ko/b2c2-flexcop-usb.ko for the
+device-specific part and b2c2-flexcop.ko for the common flexcop-functions.
+
+2) Search for errors in the leftover of flexcop-pci.c (compare with pluto2.c
+and other pci drivers)
+
+3) make some beautification (see 'Improvements when rewriting (refactoring) is
+done')
+
+4) Testing the new driver and maybe substitute the skystar2.c with it, to reach
+a wider tester audience.
+
+5) creating an usb-bus-part using the already written flexcop code for the pci
+card.
+
+Idea: create a kernel-object for the flexcop and export all important
+functions. This option saves kernel-memory, but maybe a lot of functions have
+to be exported to kernel namespace.
+
+
+Current situation
+=================
+
+0) Done :)
+1) Done (some minor issues left)
+2) Done
+3) Not ready yet, more information is necessary
+4) next to be done (see the table below)
+5) USB driver is working (yes, there are some minor issues)
+
+What seems to be ready?
+-----------------------
+
+1) Rewriting
+1a) i2c is cut off from the flexcop-pci.c and seems to work
+1b) moved tuner and demod stuff from flexcop-pci.c to flexcop-tuner-fe.c
+1c) moved lnb and diseqc stuff from flexcop-pci.c to flexcop-tuner-fe.c
+1e) eeprom (reading MAC address)
+1d) sram (no dynamic sll size detection (commented out) (using default as JJ told me))
+1f) misc. register accesses for reading parameters (e.g. resetting, revision)
+1g) pid/mac filter (flexcop-hw-filter.c)
+1i) dvb-stuff initialization in flexcop.c (done)
+1h) dma stuff (now just using the size-irq, instead of all-together, to be done)
+1j) remove flexcop initialization from flexcop-pci.c completely (done)
+1l) use a well working dma IRQ method (done, see 'Known bugs and problems and TODO')
+1k) cleanup flexcop-files (remove unused EXPORT_SYMBOLs, make static from
+non-static where possible, moved code to proper places)
+
+2) Search for errors in the leftover of flexcop-pci.c (partially done)
+5a) add MAC address reading
+5c) feeding of ISOC data to the software demux (format of the isochronous data
+and speed optimization, no real error) (thanks to Vadim Catana)
+
+What to do in the near future?
+--------------------------------------
+(no special order here)
+
+5) USB driver
+5b) optimize isoc-transfer (submitting/killing isoc URBs when transfer is starting)
+
+Testing changes
+---------------
+
+O = item is working
+P = item is partially working
+X = item is not working
+N = item does not apply here
+<empty field> = item need to be examined
+
+ | PCI | USB
+item | mt352 | nxt2002 | stv0299 | mt312 | mt352 | nxt2002 | stv0299 | mt312
+-------+-------+---------+---------+-------+-------+---------+---------+-------
+1a) | O | | | | N | N | N | N
+1b) | O | | | | | | O |
+1c) | N | N | | | N | N | O |
+1d) | O | O
+1e) | O | O
+1f) | P
+1g) | O
+1h) | P |
+1i) | O | N
+1j) | O | N
+1l) | O | N
+2) | O | N
+5a) | N | O
+5b)* | N |
+5c) | N | O
+
+* - not done yet
+
+Known bugs and problems and TODO
+--------------------------------
+
+1g/h/l) when pid filtering is enabled on the pci card
+
+DMA usage currently:
+ The DMA is splitted in 2 equal-sized subbuffers. The Flexcop writes to first
+ address and triggers an IRQ when it's full and starts writing to the second
+ address. When the second address is full, the IRQ is triggered again, and
+ the flexcop writes to first address again, and so on.
+ The buffersize of each address is currently 640*188 bytes.
+
+ Problem is, when using hw-pid-filtering and doing some low-bandwidth
+ operation (like scanning) the buffers won't be filled enough to trigger
+ the IRQ. That's why:
+
+ When PID filtering is activated, the timer IRQ is used. Every 1.97 ms the IRQ
+ is triggered. Is the current write address of DMA1 different to the one
+ during the last IRQ, then the data is passed to the demuxer.
+
+ There is an additional DMA-IRQ-method: packet count IRQ. This isn't
+ implemented correctly yet.
+
+ The solution is to disable HW PID filtering, but I don't know how the DVB
+ API software demux behaves on slow systems with 45MBit/s TS.
+
+Solved bugs :)
+--------------
+1g) pid-filtering (somehow pid index 4 and 5 (EMM_PID and ECM_PID) aren't
+working)
+SOLUTION: also index 0 was affected, because net_translation is done for
+these indexes by default
+
+5b) isochronous transfer does only work in the first attempt (for the Sky2PC
+USB, Air2PC is working) SOLUTION: the flexcop was going asleep and never really
+woke up again (don't know if this need fixes, see
+flexcop-fe-tuner.c:flexcop_sleep)
+
+NEWS: when the driver is loaded and unloaded and loaded again (w/o doing
+anything in the while the driver is loaded the first time), no transfers take
+place anymore.
+
+Improvements when rewriting (refactoring) is done
+=================================================
+
+- split sleeping of the flexcop (misc_204.ACPI3_sig = 1;) from lnb_control
+ (enable sleeping for other demods than dvb-s)
+- add support for CableStar (stv0297 Microtune 203x/ALPS) (almost done, incompatibilities with the Nexus-CA)
+
+Debugging
+---------
+- add verbose debugging to skystar2.c (dump the reg_dw_data) and compare it
+ with this flexcop, this is important, because i2c is now using the
+ flexcop_ibi_value union from flexcop-reg.h (do you have a better idea for
+ that, please tell us so).
+
+Everything which is identical in the following table, can be put into a common
+flexcop-module.
+
+ PCI USB
+-------------------------------------------------------------------------------
+Different:
+Register access: accessing IO memory USB control message
+I2C bus: I2C bus of the FC USB control message
+Data transfer: DMA isochronous transfer
+EEPROM transfer: through i2c bus not clear yet
+
+Identical:
+Streaming: accessing registers
+PID Filtering: accessing registers
+Sram destinations: accessing registers
+Tuner/Demod: I2C bus
+DVB-stuff: can be written for common use
+
+Acknowledgements (just for the rewriting part)
+================
+
+Bjarne Steinsbo thought a lot in the first place of the pci part for this code
+sharing idea.
+
+Andreas Oberritter for providing a recent PCI initialization template
+(pluto2.c).
+
+Boleslaw Ciesielski for pointing out a problem with firmware loader.
+
+Vadim Catana for correcting the USB transfer.
+
+comments, critics and ideas to linux-dvb@linuxtv.org.
--- /dev/null
+Kernel driver i2c-ali1535
+
+Supported adapters:
+ * Acer Labs, Inc. ALI 1535 (south bridge)
+ Datasheet: Now under NDA
+ http://www.ali.com.tw/eng/support/datasheet_request.php
+
+Authors:
+ Frodo Looijaard <frodol@dds.nl>,
+ Philip Edelbrock <phil@netroedge.com>,
+ Mark D. Studebaker <mdsxyz123@yahoo.com>,
+ Dan Eaton <dan.eaton@rocketlogix.com>,
+ Stephen Rousset<stephen.rousset@rocketlogix.com>
+
+Description
+-----------
+
+This is the driver for the SMB Host controller on Acer Labs Inc. (ALI)
+M1535 South Bridge.
+
+The M1535 is a South bridge for portable systems. It is very similar to the
+M15x3 South bridges also produced by Acer Labs Inc. Some of the registers
+within the part have moved and some have been redefined slightly.
+Additionally, the sequencing of the SMBus transactions has been modified to
+be more consistent with the sequencing recommended by the manufacturer and
+observed through testing. These changes are reflected in this driver and
+can be identified by comparing this driver to the i2c-ali15x3 driver. For
+an overview of these chips see http://www.acerlabs.com
+
+The SMB controller is part of the M7101 device, which is an ACPI-compliant
+Power Management Unit (PMU).
+
+The whole M7101 device has to be enabled for the SMB to work. You can't
+just enable the SMB alone. The SMB and the ACPI have separate I/O spaces.
+We make sure that the SMB is enabled. We leave the ACPI alone.
+
+
+Features
+--------
+
+This driver controls the SMB Host only. This driver does not use
+interrupts.
--- /dev/null
+Kernel driver i2c-ali1563
+
+Supported adapters:
+ * Acer Labs, Inc. ALI 1563 (south bridge)
+ Datasheet: Now under NDA
+ http://www.ali.com.tw/eng/support/datasheet_request.php
+
+Author: Patrick Mochel <mochel@digitalimplant.org>
+
+Description
+-----------
+
+This is the driver for the SMB Host controller on Acer Labs Inc. (ALI)
+M1563 South Bridge.
+
+For an overview of these chips see http://www.acerlabs.com
+
+The M1563 southbridge is deceptively similar to the M1533, with a few
+notable exceptions. One of those happens to be the fact they upgraded the
+i2c core to be SMBus 2.0 compliant, and happens to be almost identical to
+the i2c controller found in the Intel 801 south bridges.
+
+Features
+--------
+
+This driver controls the SMB Host only. This driver does not use
+interrupts.
--- /dev/null
+Kernel driver i2c-ali15x3
+
+Supported adapters:
+ * Acer Labs, Inc. ALI 1533 and 1543C (south bridge)
+ Datasheet: Now under NDA
+ http://www.ali.com.tw/eng/support/datasheet_request.php
+
+Authors:
+ Frodo Looijaard <frodol@dds.nl>,
+ Philip Edelbrock <phil@netroedge.com>,
+ Mark D. Studebaker <mdsxyz123@yahoo.com>
+
+Module Parameters
+-----------------
+
+* force_addr: int
+ Initialize the base address of the i2c controller
+
+
+Notes
+-----
+
+The force_addr parameter is useful for boards that don't set the address in
+the BIOS. Does not do a PCI force; the device must still be present in
+lspci. Don't use this unless the driver complains that the base address is
+not set.
+
+Example: 'modprobe i2c-ali15x3 force_addr=0xe800'
+
+SMBus periodically hangs on ASUS P5A motherboards and can only be cleared
+by a power cycle. Cause unknown (see Issues below).
+
+
+Description
+-----------
+
+This is the driver for the SMB Host controller on Acer Labs Inc. (ALI)
+M1541 and M1543C South Bridges.
+
+The M1543C is a South bridge for desktop systems.
+The M1541 is a South bridge for portable systems.
+They are part of the following ALI chipsets:
+
+ * "Aladdin Pro 2" includes the M1621 Slot 1 North bridge with AGP and
+ 100MHz CPU Front Side bus
+ * "Aladdin V" includes the M1541 Socket 7 North bridge with AGP and 100MHz
+ CPU Front Side bus
+ Some Aladdin V motherboards:
+ Asus P5A
+ Atrend ATC-5220
+ BCM/GVC VP1541
+ Biostar M5ALA
+ Gigabyte GA-5AX (** Generally doesn't work because the BIOS doesn't
+ enable the 7101 device! **)
+ Iwill XA100 Plus
+ Micronics C200
+ Microstar (MSI) MS-5169
+
+ * "Aladdin IV" includes the M1541 Socket 7 North bridge
+ with host bus up to 83.3 MHz.
+
+For an overview of these chips see http://www.acerlabs.com. At this time the
+full data sheets on the web site are password protected, however if you
+contact the ALI office in San Jose they may give you the password.
+
+The M1533/M1543C devices appear as FOUR separate devices on the PCI bus. An
+output of lspci will show something similar to the following:
+
+ 00:02.0 USB Controller: Acer Laboratories Inc. M5237 (rev 03)
+ 00:03.0 Bridge: Acer Laboratories Inc. M7101 <= THIS IS THE ONE WE NEED
+ 00:07.0 ISA bridge: Acer Laboratories Inc. M1533 (rev c3)
+ 00:0f.0 IDE interface: Acer Laboratories Inc. M5229 (rev c1)
+
+** IMPORTANT **
+** If you have a M1533 or M1543C on the board and you get
+** "ali15x3: Error: Can't detect ali15x3!"
+** then run lspci.
+** If you see the 1533 and 5229 devices but NOT the 7101 device,
+** then you must enable ACPI, the PMU, SMB, or something similar
+** in the BIOS.
+** The driver won't work if it can't find the M7101 device.
+
+The SMB controller is part of the M7101 device, which is an ACPI-compliant
+Power Management Unit (PMU).
+
+The whole M7101 device has to be enabled for the SMB to work. You can't
+just enable the SMB alone. The SMB and the ACPI have separate I/O spaces.
+We make sure that the SMB is enabled. We leave the ACPI alone.
+
+Features
+--------
+
+This driver controls the SMB Host only. The SMB Slave
+controller on the M15X3 is not enabled. This driver does not use
+interrupts.
+
+
+Issues
+------
+
+This driver requests the I/O space for only the SMB
+registers. It doesn't use the ACPI region.
+
+On the ASUS P5A motherboard, there are several reports that
+the SMBus will hang and this can only be resolved by
+powering off the computer. It appears to be worse when the board
+gets hot, for example under heavy CPU load, or in the summer.
+There may be electrical problems on this board.
+On the P5A, the W83781D sensor chip is on both the ISA and
+SMBus. Therefore the SMBus hangs can generally be avoided
+by accessing the W83781D on the ISA bus only.
+
--- /dev/null
+Kernel driver i2c-amd756
+
+Supported adapters:
+ * AMD 756
+ * AMD 766
+ * AMD 768
+ * AMD 8111
+ Datasheets: Publicly available on AMD website
+
+ * nVidia nForce
+ Datasheet: Unavailable
+
+Authors:
+ Frodo Looijaard <frodol@dds.nl>,
+ Philip Edelbrock <phil@netroedge.com>
+
+Description
+-----------
+
+This driver supports the AMD 756, 766, 768 and 8111 Peripheral Bus
+Controllers, and the nVidia nForce.
+
+Note that for the 8111, there are two SMBus adapters. The SMBus 1.0 adapter
+is supported by this driver, and the SMBus 2.0 adapter is supported by the
+i2c-amd8111 driver.
--- /dev/null
+Kernel driver i2c-i810
+
+Supported adapters:
+ * Intel 82810, 82810-DC100, 82810E, and 82815 (GMCH)
+
+Authors:
+ Frodo Looijaard <frodol@dds.nl>,
+ Philip Edelbrock <phil@netroedge.com>,
+ Kyösti Mälkki <kmalkki@cc.hut.fi>,
+ Ralph Metzler <rjkm@thp.uni-koeln.de>,
+ Mark D. Studebaker <mdsxyz123@yahoo.com>
+
+Main contact: Mark Studebaker <mdsxyz123@yahoo.com>
+
+Description
+-----------
+
+WARNING: If you have an '810' or '815' motherboard, your standard I2C
+temperature sensors are most likely on the 801's I2C bus. You want the
+i2c-i801 driver for those, not this driver.
+
+Now for the i2c-i810...
+
+The GMCH chip contains two I2C interfaces.
+
+The first interface is used for DDC (Data Display Channel) which is a
+serial channel through the VGA monitor connector to a DDC-compliant
+monitor. This interface is defined by the Video Electronics Standards
+Association (VESA). The standards are available for purchase at
+http://www.vesa.org .
+
+The second interface is a general-purpose I2C bus. It may be connected to a
+TV-out chip such as the BT869 or possibly to a digital flat-panel display.
+
+Features
+--------
+
+Both busses use the i2c-algo-bit driver for 'bit banging'
+and support for specific transactions is provided by i2c-algo-bit.
+
+Issues
+------
+
+If you enable bus testing in i2c-algo-bit (insmod i2c-algo-bit bit_test=1),
+the test may fail; if so, the i2c-i810 driver won't be inserted. However,
+we think this has been fixed.
--- /dev/null
+Kernel driver i2c-parport-light
+
+Author: Jean Delvare <khali@linux-fr.org>
+
+This driver is a light version of i2c-parport. It doesn't depend
+on the parport driver, and uses direct I/O access instead. This might be
+prefered on embedded systems where wasting memory for the clean but heavy
+parport handling is not an option. The drawback is a reduced portability
+and the impossibility to daisy-chain other parallel port devices.
+
+Please see i2c-parport for documentation.
--- /dev/null
+Kernel driver i2c-pca-isa
+
+Supported adapters:
+This driver supports ISA boards using the Philips PCA 9564
+Parallel bus to I2C bus controller
+
+Author: Ian Campbell <icampbell@arcom.com>, Arcom Control Systems
+
+Module Parameters
+-----------------
+
+* base int
+ I/O base address
+* irq int
+ IRQ interrupt
+* clock int
+ Clock rate as described in table 1 of PCA9564 datasheet
+
+Description
+-----------
+
+This driver supports ISA boards using the Philips PCA 9564
+Parallel bus to I2C bus controller
--- /dev/null
+Kernel driver i2c-prosavage
+
+Supported adapters:
+
+ S3/VIA KM266/VT8375 aka ProSavage8
+ S3/VIA KM133/VT8365 aka Savage4
+
+Author: Henk Vergonet <henk@god.dyndns.org>
+
+Description
+-----------
+
+The Savage4 chips contain two I2C interfaces (aka a I2C 'master' or
+'host').
+
+The first interface is used for DDC (Data Display Channel) which is a
+serial channel through the VGA monitor connector to a DDC-compliant
+monitor. This interface is defined by the Video Electronics Standards
+Association (VESA). The standards are available for purchase at
+http://www.vesa.org . The second interface is a general-purpose I2C bus.
+
+Usefull for gaining access to the TV Encoder chips.
+
--- /dev/null
+Kernel driver i2c-savage4
+
+Supported adapters:
+ * Savage4
+ * Savage2000
+
+Authors:
+ Alexander Wold <awold@bigfoot.com>,
+ Mark D. Studebaker <mdsxyz123@yahoo.com>
+
+Description
+-----------
+
+The Savage4 chips contain two I2C interfaces (aka a I2C 'master'
+or 'host').
+
+The first interface is used for DDC (Data Display Channel) which is a
+serial channel through the VGA monitor connector to a DDC-compliant
+monitor. This interface is defined by the Video Electronics Standards
+Association (VESA). The standards are available for purchase at
+http://www.vesa.org . The DDC bus is not yet supported because its register
+is not directly memory-mapped.
+
+The second interface is a general-purpose I2C bus. This is the only
+interface supported by the driver at the moment.
+
--- /dev/null
+Kernel driver i2c-sis5595
+
+Authors:
+ Frodo Looijaard <frodol@dds.nl>,
+ Mark D. Studebaker <mdsxyz123@yahoo.com>,
+ Philip Edelbrock <phil@netroedge.com>
+
+Supported adapters:
+ * Silicon Integrated Systems Corp. SiS5595 Southbridge
+ Datasheet: Publicly available at the Silicon Integrated Systems Corp. site.
+
+Note: all have mfr. ID 0x1039.
+
+ SUPPORTED PCI ID
+ 5595 0008
+
+ Note: these chips contain a 0008 device which is incompatible with the
+ 5595. We recognize these by the presence of the listed
+ "blacklist" PCI ID and refuse to load.
+
+ NOT SUPPORTED PCI ID BLACKLIST PCI ID
+ 540 0008 0540
+ 550 0008 0550
+ 5513 0008 5511
+ 5581 0008 5597
+ 5582 0008 5597
+ 5597 0008 5597
+ 5598 0008 5597/5598
+ 630 0008 0630
+ 645 0008 0645
+ 646 0008 0646
+ 648 0008 0648
+ 650 0008 0650
+ 651 0008 0651
+ 730 0008 0730
+ 735 0008 0735
+ 745 0008 0745
+ 746 0008 0746
+
+Module Parameters
+-----------------
+
+* force_addr=0xaddr Set the I/O base address. Useful for boards
+ that don't set the address in the BIOS. Does not do a
+ PCI force; the device must still be present in lspci.
+ Don't use this unless the driver complains that the
+ base address is not set.
+
+Description
+-----------
+
+i2c-sis5595 is a true SMBus host driver for motherboards with the SiS5595
+southbridges.
+
+WARNING: If you are trying to access the integrated sensors on the SiS5595
+chip, you want the sis5595 driver for those, not this driver. This driver
+is a BUS driver, not a CHIP driver. A BUS driver is used by other CHIP
+drivers to access chips on the bus.
+
--- /dev/null
+Kernel driver i2c-sis630
+
+Supported adapters:
+ * Silicon Integrated Systems Corp (SiS)
+ 630 chipset (Datasheet: available at http://amalysh.bei.t-online.de/docs/SIS/)
+ 730 chipset
+ * Possible other SiS chipsets ?
+
+Author: Alexander Malysh <amalysh@web.de>
+
+Module Parameters
+-----------------
+
+* force = [1|0] Forcibly enable the SIS630. DANGEROUS!
+ This can be interesting for chipsets not named
+ above to check if it works for you chipset, but DANGEROUS!
+
+* high_clock = [1|0] Forcibly set Host Master Clock to 56KHz (default,
+ what your BIOS use). DANGEROUS! This should be a bit
+ faster, but freeze some systems (i.e. my Laptop).
+
+
+Description
+-----------
+
+This SMBus only driver is known to work on motherboards with the above
+named chipsets.
+
+If you see something like this:
+
+00:00.0 Host bridge: Silicon Integrated Systems [SiS] 630 Host (rev 31)
+00:01.0 ISA bridge: Silicon Integrated Systems [SiS] 85C503/5513
+
+or like this:
+
+00:00.0 Host bridge: Silicon Integrated Systems [SiS] 730 Host (rev 02)
+00:01.0 ISA bridge: Silicon Integrated Systems [SiS] 85C503/5513
+
+in your 'lspci' output , then this driver is for your chipset.
+
+Thank You
+---------
+Philip Edelbrock <phil@netroedge.com>
+- testing SiS730 support
+Mark M. Hoffman <mhoffman@lightlink.com>
+- bug fixes
+
+To anyone else which I forgot here ;), thanks!
+
--- /dev/null
+Kernel driver i2c-via
+
+Supported adapters:
+ * VIA Technologies, InC. VT82C586B
+ Datasheet: Publicly available at the VIA website
+
+Author: Kyösti Mälkki <kmalkki@cc.hut.fi>
+
+Description
+-----------
+
+i2c-via is an i2c bus driver for motherboards with VIA chipset.
+
+The following VIA pci chipsets are supported:
+ - MVP3, VP3, VP2/97, VPX/97
+ - others with South bridge VT82C586B
+
+Your lspci listing must show this :
+
+ Bridge: VIA Technologies, Inc. VT82C586B ACPI (rev 10)
+
+ Problems?
+
+ Q: You have VT82C586B on the motherboard, but not in the listing.
+
+ A: Go to your BIOS setup, section PCI devices or similar.
+ Turn USB support on, and try again.
+
+ Q: No error messages, but still i2c doesn't seem to work.
+
+ A: This can happen. This driver uses the pins VIA recommends in their
+ datasheets, but there are several ways the motherboard manufacturer
+ can actually wire the lines.
+
--- /dev/null
+Kernel driver i2c-voodoo3
+
+Supported adapters:
+ * 3dfx Voodoo3 based cards
+ * Voodoo Banshee based cards
+
+Authors:
+ Frodo Looijaard <frodol@dds.nl>,
+ Philip Edelbrock <phil@netroedge.com>,
+ Ralph Metzler <rjkm@thp.uni-koeln.de>,
+ Mark D. Studebaker <mdsxyz123@yahoo.com>
+
+Main contact: Philip Edelbrock <phil@netroedge.com>
+
+The code is based upon Ralph's test code (he did the hard stuff ;')
+
+Description
+-----------
+
+The 3dfx Voodoo3 chip contains two I2C interfaces (aka a I2C 'master' or
+'host').
+
+The first interface is used for DDC (Data Display Channel) which is a
+serial channel through the VGA monitor connector to a DDC-compliant
+monitor. This interface is defined by the Video Electronics Standards
+Association (VESA). The standards are available for purchase at
+http://www.vesa.org .
+
+The second interface is a general-purpose I2C bus. The intent by 3dfx was
+to allow manufacturers to add extra chips to the video card such as a
+TV-out chip such as the BT869 or possibly even I2C based temperature
+sensors like the ADM1021 or LM75.
+
+Stability
+---------
+
+Seems to be stable on the test machine, but needs more testing on other
+machines. Simultaneous accesses of the DDC and I2C busses may cause errors.
+
+Supported Devices
+-----------------
+
+Specifically, this driver was written and tested on the '3dfx Voodoo3 AGP
+3000' which has a tv-out feature (s-video or composite). According to the
+docs and discussions, this code should work for any Voodoo3 based cards as
+well as Voodoo Banshee based cards. The DDC interface has been tested on a
+Voodoo Banshee card.
+
+Issues
+------
+
+Probably many, but it seems to work OK on my system. :')
+
+
+External Device Connection
+--------------------------
+
+The digital video input jumpers give availability to the I2C bus.
+Specifically, pins 13 and 25 (bottom row middle, and bottom right-end) are
+the I2C clock and I2C data lines, respectively. +5V and GND are probably
+also easily available making the addition of extra I2C/SMBus devices easy
+to implement.
--- /dev/null
+
+krefs allow you to add reference counters to your objects. If you
+have objects that are used in multiple places and passed around, and
+you don't have refcounts, your code is almost certainly broken. If
+you want refcounts, krefs are the way to go.
+
+To use a kref, add one to your data structures like:
+
+struct my_data
+{
+ .
+ .
+ struct kref refcount;
+ .
+ .
+};
+
+The kref can occur anywhere within the data structure.
+
+You must initialize the kref after you allocate it. To do this, call
+kref_init as so:
+
+ struct my_data *data;
+
+ data = kmalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+ kref_init(&data->refcount);
+
+This sets the refcount in the kref to 1.
+
+Once you have an initialized kref, you must follow the following
+rules:
+
+1) If you make a non-temporary copy of a pointer, especially if
+ it can be passed to another thread of execution, you must
+ increment the refcount with kref_get() before passing it off:
+ kref_get(&data->refcount);
+ If you already have a valid pointer to a kref-ed structure (the
+ refcount cannot go to zero) you may do this without a lock.
+
+2) When you are done with a pointer, you must call kref_put():
+ kref_put(&data->refcount, data_release);
+ If this is the last reference to the pointer, the release
+ routine will be called. If the code never tries to get
+ a valid pointer to a kref-ed structure without already
+ holding a valid pointer, it is safe to do this without
+ a lock.
+
+3) If the code attempts to gain a reference to a kref-ed structure
+ without already holding a valid pointer, it must serialize access
+ where a kref_put() cannot occur during the kref_get(), and the
+ structure must remain valid during the kref_get().
+
+For example, if you allocate some data and then pass it to another
+thread to process:
+
+void data_release(struct kref *ref)
+{
+ struct my_data *data = container_of(ref, struct my_data, refcount);
+ kfree(data);
+}
+
+void more_data_handling(void *cb_data)
+{
+ struct my_data *data = cb_data;
+ .
+ . do stuff with data here
+ .
+ kref_put(data, data_release);
+}
+
+int my_data_handler(void)
+{
+ int rv = 0;
+ struct my_data *data;
+ struct task_struct *task;
+ data = kmalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+ kref_init(&data->refcount);
+
+ kref_get(&data->refcount);
+ task = kthread_run(more_data_handling, data, "more_data_handling");
+ if (task == ERR_PTR(-ENOMEM)) {
+ rv = -ENOMEM;
+ kref_put(&data->refcount, data_release);
+ goto out;
+ }
+
+ .
+ . do stuff with data here
+ .
+ out:
+ kref_put(&data->refcount, data_release);
+ return rv;
+}
+
+This way, it doesn't matter what order the two threads handle the
+data, the kref_put() handles knowing when the data is not referenced
+any more and releasing it. The kref_get() does not require a lock,
+since we already have a valid pointer that we own a refcount for. The
+put needs no lock because nothing tries to get the data without
+already holding a pointer.
+
+Note that the "before" in rule 1 is very important. You should never
+do something like:
+
+ task = kthread_run(more_data_handling, data, "more_data_handling");
+ if (task == ERR_PTR(-ENOMEM)) {
+ rv = -ENOMEM;
+ goto out;
+ } else
+ /* BAD BAD BAD - get is after the handoff */
+ kref_get(&data->refcount);
+
+Don't assume you know what you are doing and use the above construct.
+First of all, you may not know what you are doing. Second, you may
+know what you are doing (there are some situations where locking is
+involved where the above may be legal) but someone else who doesn't
+know what they are doing may change the code or copy the code. It's
+bad style. Don't do it.
+
+There are some situations where you can optimize the gets and puts.
+For instance, if you are done with an object and enqueuing it for
+something else or passing it off to something else, there is no reason
+to do a get then a put:
+
+ /* Silly extra get and put */
+ kref_get(&obj->ref);
+ enqueue(obj);
+ kref_put(&obj->ref, obj_cleanup);
+
+Just do the enqueue. A comment about this is always welcome:
+
+ enqueue(obj);
+ /* We are done with obj, so we pass our refcount off
+ to the queue. DON'T TOUCH obj AFTER HERE! */
+
+The last rule (rule 3) is the nastiest one to handle. Say, for
+instance, you have a list of items that are each kref-ed, and you wish
+to get the first one. You can't just pull the first item off the list
+and kref_get() it. That violates rule 3 because you are not already
+holding a valid pointer. You must add locks or semaphores. For
+instance:
+
+static DECLARE_MUTEX(sem);
+static LIST_HEAD(q);
+struct my_data
+{
+ struct kref refcount;
+ struct list_head link;
+};
+
+static struct my_data *get_entry()
+{
+ struct my_data *entry = NULL;
+ down(&sem);
+ if (!list_empty(&q)) {
+ entry = container_of(q.next, struct my_q_entry, link);
+ kref_get(&entry->refcount);
+ }
+ up(&sem);
+ return entry;
+}
+
+static void release_entry(struct kref *ref)
+{
+ struct my_data *entry = container_of(ref, struct my_data, refcount);
+
+ list_del(&entry->link);
+ kfree(entry);
+}
+
+static void put_entry(struct my_data *entry)
+{
+ down(&sem);
+ kref_put(&entry->refcount, release_entry);
+ up(&sem);
+}
+
+The kref_put() return value is useful if you do not want to hold the
+lock during the whole release operation. Say you didn't want to call
+kfree() with the lock held in the example above (since it is kind of
+pointless to do so). You could use kref_put() as follows:
+
+static void release_entry(struct kref *ref)
+{
+ /* All work is done after the return from kref_put(). */
+}
+
+static void put_entry(struct my_data *entry)
+{
+ down(&sem);
+ if (kref_put(&entry->refcount, release_entry)) {
+ list_del(&entry->link);
+ up(&sem);
+ kfree(entry);
+ } else
+ up(&sem);
+}
+
+This is really more useful if you have to call other routines as part
+of the free operations that could take a long time or might claim the
+same lock. Note that doing everything in the release routine is still
+preferred as it is a little neater.
+
+
+Corey Minyard <minyard@acm.org>
+
+A lot of this was lifted from Greg Kroah-Hartman's 2004 OLS paper and
+presentation on krefs, which can be found at:
+ http://www.kroah.com/linux/talks/ols_2004_kref_paper/Reprint-Kroah-Hartman-OLS2004.pdf
+and:
+ http://www.kroah.com/linux/talks/ols_2004_kref_talk/
+
--- /dev/null
+Known issues :
+ * Please read the associated RELEASE-NOTES file !!!
+ * This source release intended for upstream kernel releases only!
+
+Changes from 20050323 to 20050413
+
+ * Changed version number to 8.0.28
+ * Fixed build warning for 2.6.12-rc2 kernels: mempool_alloc now
+ requires a function which takes an unsigned int for gfp_flags.
+ * Removed pci dma sync calls to coherent/consistent pci memory.
+ * Merged patch from Christoph Hellwig <hch@lst.de>: split helpers
+ for fabric and nport logins out of lpfc_cmpl_els_flogi.
+ * Removed sysfs attributes that are used to dump the various
+ discovery lists.
+ * Fix for issue where not all luns are seen. Search all lists
+ other than unmap list in lpfc_find_target(). Otherwise INQUIRY
+ to luns on nodes in NPR or other relevant states (PLOGI,
+ PRLI...) are errored back and scan() terminates.
+ * Removed FC_TRANSPORT_PATCHESxxx defines. They're in 2.6.12-rc1.
+ * Compare return value of lpfc_scsi_tgt_reset against SCSI
+ midlayer codes SUCCESS/FAILED which that function returns rather
+ than SLI return code.
+ * Removed extraneous calls to lpfc_sli_next_iotag which should
+ only be called from lpfc_sli_submit_iocb. Also make
+ lpfc_sli_next_iotag static.
+ * Added PCI ID for LP10000-S.
+ * Changes in lpfc_abort_handler(): Return SUCCESS if we did not
+ find command in both TX and TX completion queues. Return ERROR
+ if we timed out waiting for command to complete after abort was
+ issued.
+ * Zero-out response sense length in lpfc_scsi_prep_cmnd to prevent
+ interpretation of stale sense length when the command completes
+ - was causing spurious 0710 messages.
+ * Moved clearing of host_scribble inside host_lock in IO
+ completion path.
+ * Fixed a bunch of mixed tab/space indentation.
+ * Allow hex format numbers in sysfs attribute setting. Fix
+ application hang when invalid numbers are used in sysfs
+ settings.
+ * Removed extra iotag allocation by lpfc_abort_handler.
+ * Clear host_scribble in the scsi_cmnd structure when failing in
+ queuecommand.
+ * Changed logic at top of lpfc_abort_handler so that if the
+ command's host_scibble field is NULL, return SUCCESS because the
+ driver has already returned the command to the midlayer.
+
+Changes from 20050308 to 20050323
+
+ * Changed version number to 8.0.27
+ * Changed a few lines from patch submitted by Christoph Hellwig
+ (3/19). MAILBOX_WSIZE * (uint32_t) is replaced with an
+ equivalent MAILBOX_CMDSIZE macro.
+ * Merged patch from Christoph Hellwig (3/19): some misc patches
+ against the latest drivers:
+ - stop using volatile. if you need special ordering use memory
+ barriers but that doesn't seem to be the case here
+ - switch lpfc_sli_pcimem_bcopy to take void * arguments.
+ - remove typecast for constants - a U postfix marks them
+ unsigned int in C
+ - add a MAILBOX_CMD_SIZE macro, as most users of
+ MAILBOX_CMD_WSIZE didn't really want the word count
+ - kill struct lpfc_scsi_dma_buf and embedded the two members
+ directly in struct lpfc_scsi_buf
+ - don't call dma_sync function on allocations from
+ pci_pool_alloc - it's only for streaming mappings (pci_map_*)
+ * Merged patch from Christoph Hellwig (3/19) - nlp_failMask isn't
+ ever used by the driver, just reported to userspace (and that in
+ a multi-value file which is against the sysfs guidelines).
+ * Change pci_module_init to pci_register_module() with appropriate
+ ifdefs.
+ * Added #include <linux/dma-mapping.h> as required by the DMA
+ 32bit and 64bit defines on some archs.
+ * Merged patch from Christoph Hellwig (03/19) - fix initialization
+ order - scsi_add_host must happen last from scsi POV. Also some
+ minor style/comment fixups.
+ * Fixed use of TRANSPORT_PATCHES_V2 by changing to
+ FC_TRANSPORT_PATCHES_V2.
+
+Changes from 20050223 to 20050308
+
+ * Changed version number to 8.0.26
+ * Revise TRANSPORT_PATCHES_V2 so that lpfc_target is removed and
+ rport data is used instead. Removed device_queue_hash[].
+ * Changed RW attributes of scan_down, max_luns and fcp_bind_method
+ to R only.
+ * Fixed RSCN handling during initial link initialization.
+ * Fixed issue with receiving PLOGI handling when node is on NPR
+ list and marked for ADISC.
+ * Fixed RSCN timeout issues.
+ * Reduced severity of "SCSI layer issued abort device" message to
+ KERN_WARNING.
+ * Feedback from Christoph Hellwig (on 2/5) - In the LPFC_EVT_SCAN
+ case the caller already has the target ID handly, so pass that
+ one in evt_arg1.
+ * Fix compile warning/resultant panic in
+ lpfc_register_remote_port().
+
+Changes from 20050215 to 20050223
+
+ * Changed version number to 8.0.25
+ * Add appropriate comments to lpfc_sli.c.
+ * Use DMA_64BIT_MASK and DMA_32BIT_MASK defines instead of
+ 0xffffffffffffffffULL & 0xffffffffULL respectively. Use pci
+ equivalents instead of dma_set_mask and also modify condition
+ clause to actually exit on error condition.
+ * Restart els timeout handler only if txcmplq_cnt. On submission,
+ mod_timer the els_tmofunc. This prevents the worker thread from
+ waking up the els_tmo handler un-necessarily. The thread was
+ being woken up even when there were no pending els commands.
+ * Added new typedefs for abort and reset functions.
+ * Collapsed lpfc_sli_abort_iocb_xxx into a single function.
+ * Collapsed lpfc_sli_sum_iocb_xxx into a single function.
+ * Removed TXQ from all abort and reset handlers since it is never
+ used.
+ * Fixed Oops panic in 8.0.23 (reported on SourceForge). The
+ driver was not handling LPFC_IO_POLL cases correctly in
+ fast_ring_event and was setting the tgt_reset timeout to 0 in
+ lpfc_reset_bus_handler. This 0 timeout would not allow the FW
+ to timeout ABTS's on bad targets and allow the driver to have an
+ iocb on two lists. Also split the lpfc_sli_ringtxcmpl_get
+ function into two routines to match the fast and slow completion
+ semantics - ELS completions worked for the wrong reasons. Also
+ provided new log message number - had two 0326 entries.
+ * Removed unused #define LPFC_SCSI_INITIAL_BPL_SIZE.
+ * Removed unused struct lpfc_node_farp_pend definition.
+ * Removed unused #define LPFC_SLIM2_PAGE_AREA.
+ * Changed zeros used as pointers to NULL.
+ * Removed unneeded braces around single line in lpfc_do_work.
+ * Close humongous memory leak in lpfc_sli.c - driver was losing 13
+ iocbq structures per LIP.
+ * Removed last of GFP_ATOMIC allocations.
+ * Locks are not taken outside of nportdisc, hbadisc, els and most
+ of the init, sli, mbox and ct groups of functions
+ * Fix comment for lpfc_sli_iocb_cmd_type to fit within 80 columns.
+ * Replaced wait_event() with wait_event_interruptible().
+ wait_event() puts the woker thread in an UNINTERRUPTIBLE state
+ causing it to figure in load average calculations. Also add a
+ BUG_ON to the ret code of wait_event_interruptible() since the
+ premise is that the worker thread is signal-immune.
+
+Changes from 20050208 to 20050215
+
+ * Changed version number to 8.0.24
+ * Fixed a memory leak of iocbq structure. For ELS solicited iocbs
+ sli layer now frees the response iocbs after processing it.
+ * Closed large memory leak -- we were losing 13 iocbq structures
+ per LIP.
+ * Changing EIO and ENOMEM to -EIO and -ENOMEM respectively.
+ * Cleanup of lpfc_sli_iocb_cmd_type array and typing of iocb type.
+ * Implemented Christoph Hellwig's feedback from 02/05: Remove
+ macros putLunHigh, putLunLow. Use lpfc_put_lun() inline instead.
+ * Integrated Christoph Hellwig's feedback from 02/05: Instead of
+ cpu_to_be32(), use swab16((uint16_t)lun). This is the same as
+ "swab16() on LE" and "<<16 on BE".
+ * Added updates for revised FC remote port patch (dev_loss_tmo
+ moved to rport, hostdata renamed dd_data, add fc_remote_host()
+ on shutdown).
+ * Removed unnecessary function prototype.
+ * Added code to prevent waking up worker thread after the exit of
+ worker thread. Fixes panic seen with insmod/rmmod testing with
+ 70 disks.
+ * Integrated Christoph Hellwig's patch from 1/30: Make some
+ variables/code static (namely lpfcAlpaArray and
+ process_nodev_timeout()).
+ * Integrated Christoph Hellwig's patch from 1/30: Use
+ switch...case instead of if...else if...else if while decoding
+ JDEC id.
+
+Changes from 20050201 to 20050208
+
+ * Changed version number to 8.0.23
+ * Make lpfc_work_done, lpfc_get_scsi_buf,
+ lpfc_mbx_process_link_up, lpfc_mbx_issue_link_down and
+ lpfc_sli_chipset_init static.
+ * Cleaned up references to list_head->next field in the driver.
+ * Replaced lpfc_discq_post_event with lpfc_workq_post_event.
+ * Implmented Christoph Hellwig's review from 2/5: Check for return
+ values of kmalloc.
+ * Integrated Christoph Hellwig's patch from 1/30: Protecting
+ scan_tmo and friends in !FC_TRANSPORT_PATCHES_V2 &&
+ !USE_SCAN_TARGET.
+ * Integrated Christoph Hellwig's patch from 1/30: Some fixes in
+ the evt handling area.
+ * Integrated Christoph Hellwig's patch from 1/30: Remove usage of
+ intr_inited variable. The interrupt initilization from OS side
+ now happens in lpfc_probe_one().
+ * Integrated Christoph Hellwig's patch from 1/30: remove shim
+ lpfc_alloc_transport_attr - remove shim lpfc_alloc_shost_attrs -
+ remove shim lpfc_scsi_host_init - allocate phba mem in scsi's
+ hostdata readjust code so that they are no use after free's
+ (don't use after scsi_host_put) - make lpfc_alloc_sysfs_attr
+ return errors
+ * Fixed panic in lpfc_probe_one(). Do not delete in a list
+ iterator that is not safe.
+ * Clean up fast lookup array of the fcp_ring when aborting iocbs.
+ * Following timeout handlers moved to the lpfc worker thread:
+ lpfc_disc_timeout, lpfc_els_timeout, lpfc_mbox, lpfc_fdmi_tmo,
+ lpfc_nodev_timeout, lpfc_els_retry_delay.
+ * Removed unused NLP_NS_NODE #define.
+ * Integrated Christoph Hellwig's patch from 1/30: remove unused
+ lpfc_hba_list; remove unused lpfc_rdrev_wd30; remove
+ lpfc_get_brd_no and use Linux provided IDR.
+ * Changed board reset procedure so that lpfc_sli_send_reset()
+ writes the INITFF bit and leaves lpfc_sli_brdreset() to clear
+ the bit.
+ * Removed outfcpio sysfs device attribute.
+ * VPD changes: 1) Modify driver to use the model name and
+ description from the VPD data if it exists 2) Rework use of DUMP
+ mailbox command to support HBAs with 256 bytes of SLIM.
+ * Fixed compile error for implicit definition of struct
+ scsi_target
+
+Changes from 20050124 to 20050201
+
+ * Changed version number to 8.0.22
+ * Moved discovery timeout handler to worker thread. There are
+ function calls in this function which are not safe to call from
+ HW interrupt context.
+ * Removed free_irq from the error path of HBA initialization.
+ This will fix the free of uninitialised IRQ when config_port
+ fails.
+ * Make sure function which processes unsolicited IOCBs on ELS ring
+ still is called with the lock held.
+ * Clear LA bit from work_ha when we are not supposed to handle LA.
+ * Fix double locking bug in the error handling part of
+ lpfc_mbx_cmpl_read_la.
+ * Implemented fast IOCB processing for FCP ring.
+ * Since mboxes are now unconditionally allocated outside of the
+ lock, free them in cases where they are not used.
+ * Moved out a couple of GFP_ATOMICs in lpfc_disc_timeout, to
+ before locks so that they can GFP_KERNEL instead. Also cleaned
+ up code.
+ * Collapsed interrupt handling code into one function.
+ * Removed event posting and handling of solicited and unsolicited
+ iocbs.
+ * Remove ELS ring handling leftovers from the lpfc_sli_inter().
+ * ELS ring (any slow ring) moved from the lpfc_sli_inter() into a
+ worker thread. Link Attention, Mbox Attention, and Error
+ Attention, as well as slow rings' attention is passed to the
+ worker thread via worker thread copy of Host Attention
+ register. Corresponding events are removed from the event queue
+ handling.
+ * Add entries to hba structure to delegate some functionality from
+ the lpfc_sli_inter() to a worker thread.
+ * Reduced used of GFP_ATOMIC for memory allocations.
+ * Moved locks deeper in order to change GFP_ATOMIC to GFP_KERNEL.
+ * IOCB initialization fix for Raw IO.
+ * Removed qcmdcnt, iodonecnt, errcnt from lpfc_target and from
+ driver.
+ * Added call to lpfc_els_abort in lpfc_free_node. Modified
+ lpfc_els_abort to reset txq and txcmplq iterator after a
+ iocb_cmpl call.
+ * Fixed a use after free issue in lpfc_init.c.
+ * Defined default mailbox completion routine and removed code in
+ the sli layer which checks the mbox_cmpl == 0 to free mail box
+ resources.
+ * In lpfc_workq_post_event, clean up comment formatting and remove
+ unneeded cast of kmalloc's return.
+ * Removed loop which calls fc_remote_port_unblock and
+ fc_remote_port_delete for every target as this same effect is
+ accomplished by the scsi_remove_host call.
+ * Minor cleanup of header files. Stop header files including
+ other header files. Removed sentinels which hide multiple
+ inclusions. Removed unneeded #include directives.
+ * Fixed memory leaks in mailbox error paths.
+ * Moved lock from around of lpfc_work_done to lpfc_work_done
+ itself.
+ * Removed typedef for LPFC_WORK_EVT_t and left just struct
+ lpfc_work_evt to comply with linux_scsi review coding style.
+ * Fixed some trailing whitespaces, spaces used for indentation and
+ ill-formatting multiline comments.
+ * Bug fix for Raw IO errors. Reuse of IOCBs now mandates setting
+ of ulpPU and fcpi_parm to avoid incorrect read check of Write IO
+ and incorrect read length.
+
+Changes from 20050110 to 20050124
+
+ * Changed version number to 8.0.21
+ * Removed unpleasant casting in the definition and use of
+ lpfc_disc_action function pointer array.
+ * Makefile cleanup. Use ?= operator for setting default
+ KERNELVERSION and BASEINCLUDE values. Use $(PWD) consistently.
+ * Removed call to lpfc_sli_intr from lpfc_config_port_post. All
+ Linux systems will service hardware interrupts while bringing up
+ the driver.
+ * Christoph Hellwig change request: Reorg of contents of
+ lpfc_hbadisc.c, lpfc_scsi.h, lpfc_init.c, lpfc_sli.c,
+ lpfc_attr.c, lpfc_scsi.c.
+ * Renamed discovery thread to lpfc_worker thread. Moved handling
+ of error attention and link attention and mbox event handler to
+ lpfc_worker thread.
+ * Removed .proc_info and .proc_name from the driver template and
+ associated code.
+ * Removed check of FC_UNLOADING flag in lpfc_queuecommand to
+ determine what result to return.
+ * Move modification of FC_UNLOADING flag under host_lock.
+ * Fix IOERR_RCV_BUFFER_WAITING handling for CT and ELS subsystem.
+ * Workaround firmware bug for IOERR_RCV_BUFFER_WAITING on ELS
+ ring.
+ * Fixed a couple lpfc_post_buffer problems in lpfc_init.c.
+ * Add missing spaces to the parameter descriptions for
+ lpfc_cr_delay, lpfc_cr_count and lpfc_discovery_threads.
+ * Lock before calling lpfc_sli_hba_down().
+ * Fix leak of "host" in the error path in the remove_one() path.
+ * Fix comment for lpfc_cr_count. It defaults to 1.
+ * Fix issue where we are calling lpfc_disc_done() recursively from
+ lpfc_linkdown(), but list_for_each_entry_safe() is not safe for
+ such use.
+ * Bump lpfc_discovery_threads (count of outstading ELS commands in
+ discovery) to 32
+ * If the SCSI midlayer tries to recover from an error on a lun
+ while the corresponding target is in the NPR state, lpfc driver
+ will reject all the resets. This will cause the target to be
+ moved to offline state and block all the I/Os. The fix for this
+ is to delay the lun reset to a target which is not in MAPPED
+ state until the target is rediscovered or nodev timeout is
+ fired.
+
+Changes from 20041229 to 20050110
+
+ * Changed version number to 8.0.20
+ * rport fix: use new fc_remote_port_rolechg() function instead of
+ direct structure change
+ * rport fix: last null pointer check
+ * Phase II of GFP_ATOMIC effort. Replaced iocb_mem_pool and
+ scsibuf_mem_pool with kmalloc and linked list. Inserted list
+ operations for mempool_alloc calls. General code cleanup. All
+ abort and reset routines converted. Handle_ring_event
+ converted.
+ * If the mbox_cmpl == lpfc_sli_wake_mbox_wait in
+ lpfc_sli_handle_mb_event, pmb->context1 points to a waitq. Do
+ not free the structure.
+ * rport fixes: fix for rmmod crash
+ * rport fixes: when receiving PRLI's, set node/rport role values
+ * rport fixes: fix for unload and for fabric port deletes
+ * VPD info bug fix.
+ * lpfc_linkdown() should be able to process all outstanding events
+ by calling lpfc_disc_done() even if it is called from
+ lpfc_disc_done() Moving all events from phba->dpc_disc to local
+ local_dpc_disc prevents those events from being processed.
+ Removing that queue. From now on we should not see "Illegal
+ State Transition" messages.
+ * Release host lock and enable interrupts when calling
+ del_timer_sync()
+ * All related to rports: Clean up issues with rport deletion
+ Convert to using block/unblock on list remove (was del/add)
+ Moved rport delete to freenode - so rport tracks node.
+ * rport fixes: for fport, get maxframe and class support
+ information
+ * Added use of wait_event to work with kthread interface.
+ * Ensure that scsi_transport_fc.h is always pulled in by
+ lpfc_scsiport.c
+ * In remote port changes: no longer nulling target->pnode when
+ removing from mapped list. Pnode get nulled when the node is
+ freed (after nodev tmo). This bug was causing i/o recieved in
+ the small window while the device was blocked to be errored w/
+ did_no_connect. With the fix, it returns host_busy
+ (per the pre-remote port changes).
+ * Merge in support for fc transport remote port use. This removes
+ any consistent bindings within the driver. All scanning is now
+ on a per-target basis driven by the discovery engine.
+
+Changes from 20041220 to 20041229
+
+ * Changed version number to 8.0.19
+ * Fixed bug for handling RSCN type 3. Terminate RSCN mode
+ properly after ADISC handling completes.
+ * Add list_remove_head macro. Macro cleans up memory allocation
+ list handling. Also clean up lpfc_reset_bus_handler - routine
+ does not need to allocate its own scsi_cmnd and scsi_device
+ structures.
+ * Fixed potential discovery bug, nlp list corrutpion fix potential
+ memory leak
+ * Part 1 of the memory allocation rework request by linux-scsi.
+ This effort fixes the number of bdes per scsi_buf to 64, makes
+ the scatter-gather count a module parameter, builds a linked
+ list of scsi_bufs, and removes all dependencies on lpfc_mem.h.
+ * Reverted lpfc_do_dpc, probe_one, remove_one to original
+ implementation. Too many problems (driver not completing
+ initial discovery, and IO not starting to disks). Backs out
+ kthread patch.
+ * Fix race condition in lpfc_do_dpc. If wake_up interrupt occurs
+ while lpfc_do_dpc is running disc_done and the dpc list is
+ empty, the latest insertion is missed and the schedule_timeout
+ does not wakeup. The sleep interval is MAX_SCHEDULE_TIMEOUT
+ defined as ~0UL >> 1, a very large number. Hacked it to 5*HZ
+ for now.
+ * Fixed bug introduced when discovery thread implementation was
+ moved to kthread. kthread_stop() is not able to wake up thread
+ waiting on a semaphore and "modprobe -r lpfc" is not always
+ (most of the times) able to complete. Fix is in not using
+ semaphore for the interruptable sleep.
+ * Small Makefile cleanup - Remove remnants of 2.4 vs. 2.6
+ determination.
+
+Changes from 20041213 to 20041220
+
+ * Changed version number to 8.0.18
+ * Janitorial cleanup after removal of sliinit and ringinit[] ring
+ statistic is owned by the ring and SLI stats are in sli
+ structure.
+ * Integrated patch from Christoph Hellwig <hch@lst.de> Kill
+ compile warnings on 64 bit platforms: %variables for %llx format
+ specifiers must be caste to long long because %(u)int64_t can
+ just be long on 64bit platforms.
+ * Integrated patch from Christoph Hellwig <hch@lst.de> Removes
+ dead code.
+ * Integrated patch from Christoph Hellwig <hch@lst.de>: use
+ kthread interface.
+ * Print LPFC_MODULE_DESC banner in module init routine.
+ * Removed sliinit structure and ringinit[] array.
+ * Changed log message number from 324 to 326 in lpfc_sli.c.
+ * Wait longer for commands to complete in lpfc_reset_bus_handler
+ and lpfc_reset_bus_handler. Also use schedule_timeout() instead
+ of msleep() and add error message in lpfc_abort_handler()
+ * When setting lpfc_nodev_tmo, from dev_loss set routine, make 1
+ sec minimum value.
+ * Functions which assume lock being held were called without lock
+ and kernel complained about unlocking lock which is not locked.
+ * Added code in linkdown to unreg if we know login session will be
+ terminated.
+ * Removed automap config parameter and fixed up use_adisc logic to
+ include FCP2 devices.
+
+Changes from 20041207 to 20041213
+
+ * Changed version number to 8.0.17
+ * Fix sparse warnings by adding __iomem markers to lpfc_compat.h.
+ * Fix some sparse warnings -- 0 used as NULL pointer.
+ * Make sure there's a space between every if and it's (.
+ * Fix some overly long lines and make sure hard tabs are used for
+ indentation.
+ * Remove all trailing whitespace.
+ * Integrate Christoph Hellwig's patch for 8.0.14: if
+ pci_module_init fails we need to release the transport template.
+ (also don't print the driver name at startup, linux drivers can
+ be loaded without hardware present, and noise in the log for
+ that case is considered unpolite, better print messages only for
+ hardware actually found).
+ * Integrate Christoph Hellwig's patch for 8.0.14: Add missing
+ __iomem annotations, remove broken casts, mark functions static.
+ Only major changes is chaning of some offsets from word-based to
+ byte-based so we cans simply do void pointer arithmetics (gcc
+ extension) instead of casting to uint32_t.
+ * Integrate Christoph Hellwig's patch for 8.0.14: flag is always
+ LPFC_SLI_ABORT_IMED, aka 0 - remove dead code.
+ * Modified preprocessor #ifdef, #if, #ifndef to reflect upstream
+ kernel submission. Clean build with make clean;make and make
+ clean;make ADVANCED=1 on SMP x86, 2.6.10-rc2 on RHEL 4 Beta
+ 1. IO with a few lips and a long cable pull behaved accordingly.
+ * Implement full VPD support.
+ * Abort handler will try to wait for abort completion before
+ returning. Fixes some panics in iocb completion code path.
+
+Changes from 20041130 to 20041207
+
+ * Changed version number to 8.0.16
+ * Hung dt session fix. When the midlayer calls to abort a scsi
+ command, make sure the driver does not complete post-abort
+ handler. Just NULL the iocb_cmpl callback handler and let SLI
+ take over.
+ * Add Read check that uses SLI option to validate all READ data
+ actually received.
+
+
+Changes from 20041123 to 20041130
+
+ * Changed version number to 8.0.15
+ * Ifdef'd unused "binary" attributes by DFC_DEBUG for clean
+ compiles
+ * Stop DID_ERROR from showing up along with QUEUE_FULL set by the
+ Clarion array (SCSI error ret. val. 0x70028) There is no need
+ for driver to hard fail command which was failed by the target
+ device.
+ * Fix for Scsi device scan bug reported on SourceForge. Driver
+ was returning a DID_ERROR in lpfc_handle_fcp_error causing
+ midlayer to mark report luns as failing even though it
+ succeeded.
+ * Don't ignore SCSI status on underrun conditions for inquiries,
+ test unit ready's, etc. This was causing us to lose
+ reservation conflicts, etc
+
+Changes from 20041018 to 20041123
+
+ * Changed version number to 8.0.14
+ * Added new function "iterator" lpfc_sli_next_iocb_slot() which
+ returns pointer to iocb entry at cmdidx if queue is not full.
+ It also updates next_cmdidx, and local_getidx (but not cmdidx)
+ * lpfc_sli_submit_iocb() copies next_cmdidx into cmdidx. Now it is
+ the only place were we are updating cmdidx.
+ * lpfc_sli_update_ring() is split in to two --
+ lpfc_sli_update_ring() and lpfc_sli_update_full_ring().
+ * lpfc_sli_update_ring() don't to read back correct value of
+ cmdidx.
+ * Simplified lpfc_sli_resume_iocb() and its use.
+ * New static function lpfc_sli_next_iocb(phba, pring, &piocb) to
+ iterate through commands in the TX queue and new command (at the
+ end).
+ * Reduced max_lun to 256 (due to issues reported to some arrays).
+ Fixed comment, and macro values so def=256, min=1, max=32768.
+ * Fix an obvious typo/bug: kfree was used to free lpfc_scsi_buf
+ instead of mempool_free in lpfc_scsiport.c.
+ * Suppress nodev_tmo message for FABRIC nodes.
+ * Fixed some usage of plain integer as NULL pointer.
+ * Bug fix for FLOGI cmpl, lpfc_els_chk_latt error path code
+ cleanup.
+ * Fixup lpfc_els_chk_latt() to have Fabric NPorts go thru
+ discovery state machine as well.
+ * Fixes to lpfc_els_chk_latt().
+ * Use DID not SCSI target id as a port_id and add some missing
+ locks in lpfc_fcp.c.
+ * Changed eh_abort_handler to return FAILED if command is not
+ found in driver.
+ * Fix crash: paging request at virtual address 0000000000100108 -
+ a result of removing from the txcmpl list item which was already
+ removed (100100 is a LIST_POISON1 value from the next pointer
+ and 8 is an offset of the "prev") Driver runs out of iotags and
+ does not handle that case well. The root of the proble is in the
+ initialization code in lpfc_sli.c
+ * Changes to work with proposed linux kernel patch to support
+ hotplug.
+ * Zero out seg_cnt in prep_io failure path to prevent double sg
+ unmap calls.
+ * Fix setting of upper 32 bits for Host Group Ring Pointers if in
+ SLIM. Old code was inappropriately masking off low order bits.
+ * Use scsi_[activate|deactivate]_tcq calls provided in scsi_tcq.h.
+ * Integrated patch from Christoph Hellwig (hch@lst.de): don't call
+ pci_dma_sync_* on coherent memory. pci_dma_sync_* is need and
+ must be used only with streaming dma mappings pci_map_*, not
+ coherent mappings. Note: There are more consistent mappings
+ that are using pci_dma_sync calls. Probably these should be
+ removed as well.
+ * Modified lpfc_free_scsi_buf to accomodate all three scsi_buf
+ free types to alleviate miscellaneous panics with cable pull
+ testing.
+ * Set hotplug to default 0 and lpfc_target_remove to not remove
+ devices unless hotplug is enabled.
+ * Fixed discovery bug: plogi cmpl uses ndlp after its freed.
+ * Fixed discovery bug: rnid acc cmpl, can potentially use ndlp
+ after its freed.
+ * Modularize code path in lpfc_target_remove().
+ * Changes to support SCSI hotplug (ifdef'ed out because they need
+ kernel support USE_SCAN_TARGET requires kernel support to export
+ the interface to scsi_scan_target and to move the SCAN_WILD_CARD
+ define to a general scsi header file. USE_RESCAN_HOST requires
+ kernel support to export an interface to scan_scsi_host() with
+ the rescan flag turned on).
+ * Removed redundant variable declaration of lpfc_linkdown_tmo.
+ * Fix for large port count remove test.
+ * Added check to see if BAR1 register is valid before using BAR1
+ register for programming config_port mail box command.
+ * Added lpfc_scsi_hotplug to enable/disable driver support of SCSI
+ hotplug.
+ * Changed lpfc_disc_neverdev() to lpfc_disc_illegal() and changed
+ lpfc_disc_nodev() to lpfc_disc_noop(). Adjusted appropriate
+ events to use these routines.
+ * Add support for SCSI device hotplug.
+ * Take dummy lpfc_target's into account for lpfc_slave_destroy().
+ * Bug fix to store WWPN / WWNN in NameServer / FDMI lpfc_nodelist
+ entries.
+ * Added slavecnt in lpfc_target for diagnostic purposes.
+ * Added lpfc_hba load/unload flags to take care of special cases
+ for add/remove device.
+ * Have target add/remove delay before scanning.
+ * Have rmmod path cleanup blocked devices before scsi_remove_host.
+ * Added a #define for msleep for 2.6.5 kernels.
+ * In reset bus handler if memory allocation fails, return FAILED
+ and not SUCCESS.
+ * Have lpfc eh handlers, bus_reset and lun_reset, wait for all
+ associated I/Os to complete before returning.
+ * Fix memset byte count in lpfc_hba_init so that
+ LP1050 would initialize correctly.
+ * Backround nodev_timeout processing to DPC This enables us to
+ unblock (stop dev_loss_tmo) when appopriate.
+ * Fix array discovery with multiple luns. The max_luns was 0 at
+ the time the host structure was intialized. lpfc_cfg_params
+ then set the max_luns to the correct value afterwards.
+ * Remove unused define LPFC_MAX_LUN and set the default value of
+ lpfc_max_lun parameter to 512.
+ * Reduced stack usage of lpfc_hba_init.
+ * Cleaned up the following warning generated by
+ scripts/checkincludes.pl lpfc_fcp.c: scsi/scsi_cmnd.h is
+ included more than once.
+ * Replaced "set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(timeout)" with "msleep(timeout)".
+ * Fixnode was loosing starget when rediscovered. We saw messages
+ like: lpfc 0000:04:02.0: 0:0263 Cannot block scsi target as a
+ result. Moved starget field into struct lpfc_target which is
+ referenced from the node.
+ * Add additional SLI layer logging in lpfc_sli.c.
+ * Ignore more unexpected completions in lpfc_nportdisc.c.
+ * Can not call lpfc_target_unblock from the soft interrupt
+ context. It seems to be not nessasery to unblock target from
+ nodev timeout.
+ * Introduce and use less lethal event handler for unexpected
+ events in lpfc_nportdisc.c.
+ * Can not call fc_target_(un)block() functions with interrupts
+ disabled in lpfc_scsiport.c.
+ * Added new configuration parameter, lpfc_max_luns range 1-32768,
+ default 32768.
+ * Allow lpfc_fcp.c to call lpfc_get_hba_sym_node_name().
+ * Increase nodev timeout from 20 seconds to 30 seconds.
+ * Replace some kfree((void*)ptr) with kfree(ptr).
+ * Make 3 functions static: lpfc_get_hba_sym_node_name,
+ lpfc_intr_prep and lpfc_setup_slim_access. Move lpfc_intr_prep
+ and lpfc_setup_slim_access so they're defined before being used.
+ * Remove an unecessary list_del() in lpfc_hbadisc.c.
+ * Set nlp_state before calling lpfc_nlp_list() since this will
+ potentially call fc_target_unblock which may cause a race in
+ queuecommand by releasing host_lock.
+ * Since lpfc_nodev_tmo < dev_loss_tmo remove queuecommand
+ DID_BAD_TARGET return for now.
+ * Fix a problem with rcv logo.
+ * Remove unused portstatistics_t structure.
+ * Remove #if 0 and unnecessary checks in lpfc_fcp.c.
+ * Simplify lpfc_issue_lip: Extra layer of protection removed.
+ * Grab lock before calling lpfc_sli_issue_mbox(phba, pmb,
+ MBX_NOWAIT) in lpfc_sli_issue_mbox_wait().
+
+Changes from 20040920 to 20041018
+
+ * Changed version number to 8.0.13
+ * Hide some attributes using #ifndef DFC_DEBUG ... #endif.
+ * Modify Makefile to (1) make BUILD_NO_DEBUG=1 will hide some
+ (binary) attributes (2) make BUILD_FC_TRANS=0 will build driver
+ for 2.6.5 kernel with block/unblock patch.
+ * Modified #ifdef names.
+ * Added support for proposed FC transport host attributes (which
+ replaces some of the attributes we had local to the driver).
+ Removed the binary statistics sysfs attribute.
+ * Added extra ELS verbose logging for ELS responses.
+ * Added recognition for BUILD_FC_TRANS=2 to Makefile to define
+ FC_TRANS_VER2.
+ * Add a pointer for link stats allocation.
+ * Exported lpfc_get_hba_sym_node_name for use by FC_TRANS_VER2
+ sysfs routines.
+ * Fix discovery problem in lip testing: if device sends an ELS cmd
+ (i.e. LOGO) before our FLOGI completes it should be LS_RJT'ed.
+ * Moved #defines around to provide target_add/remove for upstream
+ kernel deliverables only not SLES9. Provided ifdefs to #include
+ target_block/unblock only if FC_TRANS_VER1.
+ * Add sanity check in lpfc_nlp_list move setting nlp_Target
+ outside #ifdef.
+ * Added a blocked member to the lpfc_target structure for
+ block/unblock. This member allows the driver to know when to
+ unblock for pci_remove_one or pci_add_one. #ifdef'd some more
+ block/unblock stuff and removed some defensive checks from
+ target_block/unblock.
+ * Moved + 5 second window to dev_loss_tmo setting and updated
+ comments.
+ * Removed NULL target check from target_block/unblock and fixed up
+ a few comments.
+ * Enable sysfs attributes on 2.6.5 kernels and remove extra
+ compatibility code.
+ * Remove any and all trailing whitespace.
+ * Added message 0718 and return error when dma_map_single fails.
+ * Changed the fcpCntl2 commands to include an FCP_ prefix to get
+ rid of build warnings on later 2.6.9-rc kernels. Build
+ conflicts with scsi/scsi.h. Remove inclusions of scsi/scsi.h
+ from hbadisc.c, sli.c, and fcp.c since these modules had no
+ dependencies on scsi.h.
+ * Fixed a bug with RSCN handling. A RSCN received on one device,
+ shouldn't affect other devices not referenced by the RSCN.
+ * Moved #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,6) to include
+ lpfc_jedec_to_ascii to prevent warning in SLES 9.
+ * Update Makefile to account for SLES 9 and scsi-target upstream
+ kernel.
+ * This checkin provides block/unblock hooks for the upstream scsi
+ target kernel and 2.6.5 on SLES9 SP1 with the block/unblock
+ patch.
+ * Discovery changes regarding setting targetp->pnode and
+ ndlp->nlp_Target Ensure fc_target_* routines are called properly
+ from discovery. Remove list_del's from lpfc_cleanup(). Ensure
+ all the lpfc_consistent_bind_* routines don't set any driver
+ structure objects.
+ * Fix for timeout of READ_LA or READ_SPARAM mailbox command
+ causing panic.
+ * Cleanup list_del()'s for Discovery ndlp lists.
+ * Bug fixes for some insmod/rmmod crashes, link down crashes and
+ device loss crashes.
+ * Removed NLP_SEARCH_DEQUE.
+ * Call lpfc_target_unblock only if the targetp is nonNull and with
+ the host_lock held.
+ * Added qcmdcnt back along with misc bug fixes to discovery.
+ * Changed tgt_io to outfcpio lpfc_fcp.c.
+ * Fixed errors caused by LIP and cable pulls both with and without
+ block/unblock patch.
+ * For now we have to call fc_target_unblock and fc_target_block
+ with interrupts enabled.
+ * Save seg_cnt from dma_map_sg. Save scatter-gather start address
+ and pass back to dma_unmap_sg in error with seg_cnt.
+ * Incorporating block/unblock calls into driver with ifdefs. This
+ change is supported by scsi-target-2.6 kernel and forward only.
+ * Merged in some discovery bug fixes and added tgt io counters.
+ * Added sysfs attributes/interfaces: read only attribute
+ "management_version" and write only attribute "issue_lip".
+ * Fix build on big endian machines: while #if was OK with
+ __BIG_ENDIAN which defined as 4321, __BIG_ENDIAN_BITFIELD has to
+ be tested with #ifdef because it does not have any value, it is
+ either defined or not.
+ * Add fabric_name and port_type attributes.
+ * Change mdelay to msleep. mdelay works, but wastefully uses cpu
+ resources without a lock held. Revert to msleep. Tested with
+ sg_reset for bus and three attached targets.
+ * Added the customary #ifndef...#define...#endif to
+ lpfc_version.h.
+ * Integrate patches from Christoph Hellwig: two new helpers common
+ to lpfc_sli_resume_iocb and lpfc_sli_issue_iocb - singificant
+ cleanup of those two functions - the unused SLI_IOCB_USE_TXQ is
+ gone - lpfc_sli_issue_iocb_wait loses it's flags argument
+ totally.
+ * Fix in lpfc_sli.c: we can not store a 5 bit value in a 4-bit
+ field.
+ * Moved some routines out of lpfc_fcp.c into more appropriate
+ files.
+ * Whitespace cleanup: remove all trailing whitespace.
+ * Make lpfc_disc_ndlp_show static to lpfc_fcp.c.
+ * Remove leftover printk and replace some with
+ printk(KERN_WARNING)
+ * Trivial: fix a few long lines and a soft tab.
+ * Remove warnings generated by Sparse against driver (make
+ C=1). Mostly these are "using integer as pointer warnings"
+ i.e. use NULL instead of 0.
+ * Integrated patch from Christoph Hellwig: Quite a lot of changes
+ here, the most notable is that the phba->slim2p lpfc_dmabuf goes
+ away in favour of a typede pointer and a dma_addr_t. Due to the
+ typed pointer lots of the cast mess can go away, and while at it
+ I also replaced the messy SLI2_SLIM_t with a simple struct
+ lpfc2_sli2_slim that only contains the part of the union we care
+ about while using SLI2_SLIM_SIZE for all size calculations
+ directly.
+ * Integrated patch from Christoph Hellwig: This streamlines the
+ I/O completion path a little more, especially taking care of
+ fast-pathing the non-error case. Also removes tons of dead
+ members and defines from lpfc_scsi.h - e.g. lpfc_target is down
+ to nothing more then the lpfc_nodelist pointer.
+ * Added binary sysfs file to issue mbox commands
+ * Replaced #if __BIG_ENDIAN with #if __BIG_ENDIAN_BITFIELD for
+ compatibility with the user space applications.
+ * Decrease the amount of data in proc_info.
+ * Condense nodelist flag members.
+ * Expand INFO for discovery sysfs shost entries.
+ * Notify user if information exceeds 4k sysfs limit.
+ * Removed a bunch of unused #defines.
+ * Added initial sysfs discovery shost attributes.
+ * Remove unused #defines lpfc_disc.h.
+ * Fixed failMask nodelist settings.
+ * Cleanup some old comments / unused variables.
+ * Add LP101 to list of recognized adapters.
+
+Changes from 20040908 to 20040920
+
+ * Changed version number to 8.0.12
+ * Removed used #defines: DEFAULT_PCI_LATENCY_CLOCKS and
+ PCI_LATENCY_VALUE from lpfc_hw.h.
+ * Changes to accomodate rnid.
+ * Fix RSCN handling so RSCN NS queries only effect NPorts found in
+ RSCN data.
+ * If we rcv a plogi on a NPort queued up for discovery, clear the
+ NLP_NPR_2B_DISC bit since rcv plogi logic will force NPort thru
+ discovery.
+ * Ensure lpfc_target is also cleaned up in lpfc_cleanup().
+ * Preliminary changes for block/unblock kernel API extensions in
+ progress with linux-scsi list. These are name changes and
+ prototype changes only.
+ * Added send_abts flag to lpfc_els_abort. For rcv LOGO when ADISC
+ sent, the XRI of the LOGO rcv'ed is the same as the ADISC
+ sent. Thus we cannot ABTS the ADISC before sending the LOGO ACC.
+ * Weed out some unused fc_flags. Add FC_DISC_TMO.
+ * board_online sysfs attribute added to support libdfc functions
+ InitDiagEnv and SetBrdEnv.
+ * Streamline code in lpfc_els_retry fixup abort case in
+ lpfc_els_timeout_handler().
+ * Flush discovery/ELS events when we bring SLI layer down.
+ * ctlreg and slimem binary attributes added to support libdfc
+ read/write mem/ctl functions.
+ * Integrated Christoph Hellwig's patch: Cleanup
+ lpfc_sli_ringpostbuf_get.
+ * Modified lpfc_slave_alloc and lpfc_slave_destroy to allocate and
+ free a dummy target pointer. This allows queuecommand to skip
+ the NULL target pointer check and avoid the console spam when
+ slave_alloc fails.
+ * Fix cfg_scan_down logic, it was reversed.
+ * Init list head ctrspbuflist.
+ * Change name of lpfc_driver_abort to lpfc_els_abort since it is
+ only valid for ELS ring.
+ * Remove unused third argument for lpfc_consistent_bind_get().
+ * Fix up iotag fields in lpfc_prep_els_iocb().
+ * Remove log message on code path triggered by lpfc_els_abort().
+ * Set host->unique_id in lpfc_fcp.c.
+ * Removed deadwood: lpfc_target.pHba not necessary anymore.
+ * Integrated patch from Christoph Hellwig: remove dead
+ SLI_IOCB_POLL handling.
+ * Integrated patch from Christoph Hellwig: Streamline I/O
+ submission and completion path a little.
+ * Remove unnecessary lpfc_brd_no. Ensure brd_no assignment is
+ unique.
+ * Removed unused MAX_FCP_LUN.
+ * Use mod_timer instead of add_timer for fdmi in lpfc_ct.c.
+ * Fixed misc discovery problems.
+ * Move stopping timers till just before lpfc_mem_free() call.
+ * Fix up NameServer reglogin error path.
+ * Cleanup possible outstanding discovery timers on rmmod.
+ * Fix discovery NPort to NPort pt2pt problem.
+ * Get rid of ip_tmofunc / scsi_tmofunc.
+ * Integrated patch from Christoph Hellwig:
+ lpfc_disc_done/lpfc_do_dpc cleanup - lpfc_disc_done can return
+ void - move lpfc_do_dpc and lpfc_disc_done to lpfc_hbadisc.c -
+ remove checking of list emptiness before calling lpfc_disc_done,
+ it handles the emtpy list case just fine and the additional
+ instructions cost less then the bustlocked spinlock operations.
+ * Integrated patch from Christoph Hellwig: This adds a new 64bit
+ counter instead, brd_no isn't reused anymore. Also some tiny
+ whitespace cleanups in surrounding code.
+ * Reorder functions in lpfc_els.c to remove need for prototypes.
+ * Removed unsed prototypes from lpfc_crtn.h -
+ lpfc_ip_timeout_handler, lpfc_read_pci and lpfc_revoke.
+ * Removed some unused prototypes from lpfc_crtn.h -
+ lpfc_scsi_hba_reset, lpfc_scsi_issue_inqsn,
+ lpfc_scsi_issue_inqp0, lpfc_scsi_timeout_handler.
+ * Integrated patch from Christoph Hellwig: remove TRUE/FALSE
+ usage.
+ * Integrated patch from Christoph Hellwig: Remove unused function
+ prototypes lpfc_set_pkt_len and lpfc_get_pkt_data from
+ lpfc_crtn.h - fixes build warnings.
+ * Removed unused struct lpfc_dmabufip definition from lpfc_mem.h.
+ * Removed pre-2.6.5 MODULE_VERSION macro from lpfc_compat.h.
+ * Fixing missing static and removing dead code.
+ * Adding nodewwn, portwwn and portfcid shost attributes.
+ * Initial support for CT via sysfs. request payloads of size less
+ than PAGE_SIZE and rsp payloads of size PAGE_SIZE are supported.
+ Driver maintains a list of rsp's and passes back rsp's
+ corresponding to the pid of the calling process.
+ * Support for RefreshInformation, GetAdapterAttributes,
+ GetPortStatistics.
+ * Make nodev-tmo default to 20 seconds.
+ * Fix up some DSM error cases, unreg_login rpi where needed.
+ * Fix up comments for fc_target_block / fc_target_unblock.
+ * Fix up code for scsi_block_requests / scsi_unblock_requests.
+ * Add NLP_FCP_TARGET for nodeinfo support.
+ * Move suspend/resume in lpfc_nlp_list under appropriate case -
+ Used host_lock for DPC to avoid race (remove dpc_lock)
+ * Fix some corner cases for PLOGI receive - simplify error case
+ for cmpl_reglogin_reglogin_issue.
+ * Bug fix for ppc64 EEH MMIO panic - always do readl after
+ writel's of HBA registers to force flush.
+ * Get rid of initial static routine declarations in lpfc_hbadisc.c
+ and lpfc_els.c.
+ * Updates to discovery processing.
+
+Changes from 20040823 to 20040908
+
+ * Changed version number to 8.0.11
+ * Removed persistent binding code.
+ * Display both ASC and ASCQ info.
+ * Fixed link down->up transitions when linkdown tmo expires. Fix
+ was in the defensive error checking at the start of
+ queuecommand.
+ * Removed lpfc_scsi_timeout_handler as this timer is no longer
+ required. The midlayer will exhaust retries and then call
+ lpfc_abort_handler, lpfc_reset_lun_handler, and
+ lpfc_reset_target_handler.
+ * Minimal support for SCSI flat space addressing/volume set
+ addressing. Use 16 bits of LUN address so that flat
+ addressing/VSA will work.
+ * Changed 2 occurences of if( 1 != f(x)) to if(f(x) != 1)
+ * Drop include of lpfc_cfgparm.h.
+ * Reduce stack usage of lpfc_fdmi_cmd in lpfc_ct.c.
+ * Add minimum range checking property to /sys write/store
+ functions.
+ * Fix display of node_name and port_name via fc transport
+ attr.
+ * Removed biosparam code.
+ * Removed range checking. phba->config[] array elements are now
+ embedded into the hba struct. lpfc_config_setup() has been
+ removed.
+ * Collapsed lpfc_scsi_cmd_start into lpfc_queuecommand and cleaned
+ up combined routines.
+ * Removed unused prototypes myprint and
+ lpfc_sched_service_high_priority_queue.
+ * Removed unused function lpfc_nodev.
+ * Removed scsi_cmnd->timeout_per_command cancelation. SCSI midlayer
+ now times out all commands - FW is instructed to not timeout.
+ * Removed polling code from lpfc_scsi_cmd_start. Reorganized
+ queuecommand and cmd_start some.
+
+Changes from 20040810 to 20040823
+
+ * Changed version number to 8.0.10
+ * Additional timer changes as per Arjan / Christoph's comments.
+ * Used mod_timer() instead of del_timer_sync() where appropriate.
+ * Fixed a use after free case (panic on 2.6.8.1 with
+ CONFIG_DEBUG_SLAB set).
+ * Fix compile warning in lpfc_fcp.c.
+ * Minor fix for log message, that prints unassigned brdno which is
+ zero.
+ * Move scsi_host_alloc() to the beginning of probe_one(). This
+ ensures that host_lock is available at later stages and also
+ avoids tons of unnecessary initializing if host_alloc()
+ fails.
+ * Removed else clause from lpfc_slave_configure that set
+ sdev->queue_depth. The driver informs the midlayer of its
+ setting in the template and only overrides if queue tagging is
+ enabled.
+ * Added PCI_DEVICE_ID_ZEPHYR and PCI_DEVICE_ID_ZFLY (Junior
+ Zephyr) support
+
+Changes from 20040730 to 20040810
+
+ * Changed version number to 8.0.9
+ * Removed per HBA driver lock. Driver now uses the host->host_lock
+ * Restored support for the 2.6.5 kernel for those linux distributions
+ shipped with the 2.6.5 kernel.
+ * Applied patch from Christoph Hellwig (hch@infradead.org) as follows
+ "[PATCH] use scsi host private data in ->proc_info.
+ * Applied patch from Christoph Hellwig (hch@infradead.org) as follows
+ "Re: [Emulex] Ready for next round. This patch cleans up the memory
+ allocation routines a little and fixes a missing mempool_destroy and
+ some missing error handling."
+ * Changed pointers assignments from 0 to NULL.
+ * Added fixes to the lpfc_reset_lun_handler and lpfc_reset_bus_handler
+ entry points that caused kernel to Oops or hang.
+ * Added fixes to targetless hosts that caused modprobe and insmod to hang.
+ * Ongoing cleanup to many files
+
+Changes from 20040723 to 20040730
+
+ * Changed version number to 8.0.8
+ * Removed unused LPFN_DRIVER_VERSION #define.
+ * Folded lpfc_findnode_scsiid into lpfc_find_target, its only
+ caller.
+ * Removed 2 unneeded arguments to lpfc_find_target (lun and
+ create_flag).
+ * Make lpfc_sli_reset_on_init = 1
+ * Minor cleanup to quieten sparse.
+ * Removed missing function = 0 in tmo routine in lpfc_els.c.
+ * Moved additional binding parameters into lpfc_defaults.c:
+ lpfc_automap / lpfc_fcp_bind_method
+ * Use msecs_to_jiffies() where applicable.
+ * Only use queue depth attribute only after SLI HBA setup was
+ completed.
+ * Put in memory barriers for PPC
+ * Added PCI_DEVICE_ID_HELIOS and PCI_DEVICE_ID_JFLY (Junior
+ Helios) support
+ * Added 4&10 gigabit choices in user option link_speed
+ * Updated timer logic: Set timer data after init_timer use
+ timer_pending() instead of expires.
+ * Removed some remnants of IP over FC support from Kconfig and
+ Makefile.
+ * Remove redundant prototypes for lpfc_handle_eratt,
+ lpfc_handle_latt and lpfc_read_pci.
+ * Ongoing cleanup of lpfc_init.c.
+ * Changed LPFC_CFG_DFT_HBA_Q_DEPTH -> LPFC_CFG_HBA_Q_DEPTH.
+ * Another cleanup stab at lpfc_ct.c. Remove castings, structure
+ code sanely, remove redundant code, reorganize code so that
+ functions are invoked after definition.
+
+Changes from 20040716 to 20040723
+
+ * Changed version number to 8.0.7
+ * Cleanup of lpfc_ct.c. Removed number of casts, removed tons of
+ dead/redundant code, cleaned up badly and poorly written code,
+ cleaned up return values.
+ * Fixed Persistent binding implementation
+ * Removed all references to lpfc_scsi_req_tmo
+ * Removed last references to lun_skip config parameter.
+ * Removed LPFC_DEV_RPTLUN node failure bit because we don't issue
+ REPORT_LUNS from the driver anymore.
+ * Removed LUN-tracking in driver. Removed lpfc_lun struct and
+ moved any functionality we still need to lpfc_target.
+ * Added new lpfc_jedec_to_ascii() call and replace two instances
+ of duplicate code with calls to this function.
+ * Removed Volume Set Addressing handling on LUN IDs.
+ * Applied patch from Christoph Hellwig (hch@infradead.org) that
+ removes dead code belonging to lpfc_build_scsi_cmnd() and its
+ call path. This is related to the recently removed report_lun
+ code.
+
+Changes from 20040709 to 20040716
+
+ * Changed version number to 8.0.6
+ * Removed internal report LUNs usage. Removed functions:
+ lpfc_disc_issue_rptlun, lpfc_disc_cmpl_rptlun,
+ lpfc_disc_retry_rptlun and their use.
+ * Removed usused scheduler prototypes in lpfc_crtn.h
+ * Replace lpfc_geportname() with generic memcmp().
+ * Rearrange code in lpfc_rcv_plogi_plogi_issue() to make it a
+ little more readable.
+ * Remove redundant port_cmp != 2 check in if
+ (!port_cmp) { .... if (port_cmp != 2).... }
+ * Clock changes: removed struct clk_data and timerList.
+ * Clock changes: seperate nodev_tmo and els_retry_delay into 2
+ seperate timers and convert to 1 argument changed
+ LPFC_NODE_FARP_PEND_t to struct lpfc_node_farp_pend convert
+ ipfarp_tmo to 1 argument convert target struct tmofunc and
+ rtplunfunc to 1 argument * cr_count, cr_delay and
+ discovery_threads are only needed to be module_params and not
+ visible via sysfs.
+
+Changes from 20040614 to 20040709
+
+ * Changed version number to 8.0.5
+ * Make lpfc_info static.
+ * Make lpfc_get_scsi_buf static.
+ * Print a warning if pci_set_mwi returns an error.
+ * Changed SERV_PARM to struct serv_parm.
+ * Changed LS_RJT to struct ls_rjt.
+ * Changed CSP to struct csp.
+ * Changed CLASS_PARMS to struct class_parms.
+ * Some cosmetic coding style cleanups to lpfc_fcp.c.
+ * Providing a sysfs interface that dumps the last 32
+ LINK_[UP|DOWN] and RSCN events.
+ * Get rid of delay_iodone timer.
+ * Remove qfull timers and qfull logic.
+ * Convert mbox_tmo, nlp_xri_tmo to 1 argment clock handler
+ * Removed duplicate extern defs of the bind variables.
+ * Streamline usage of the defines CLASS2 and CLASS3, removing
+ un-necessary checks on config[LPFC_CFG_FCP_CLASS].
+ * Moving the persistent binding variables to new file
+ lpfc_defaults.c
+ * Changed LPFC_SCSI_BUF_t to struct lpfc_scsi_buf.
+ * Moved config specific code from probe_one() into
+ config_setup(). Removing a redundant check on scandown value
+ from bind_setup() as this is already done in config_setup().
+ * Changed LPFC_SLI_t to struct lpfc_sli.
+ * Changed FCP_CMND to struct fcp_cmnd.
+ * Changed FCP_RSP to struct fcp_rsp.
+ * Remove the need for buf_tmo.
+ * Changed ULP_BDE64 to struct ulp_bde64.
+ * Changed ULP_BDE to struct ulp_bde.
+ * Cleanup lpfc_os_return_scsi_cmd() and it's call path.
+ * Removed lpfc_no_device_delay.
+ * Consolidating lpfc_hba_put_event() into lpfc_put_event().
+ * Removed following attributes and their functionality:
+ lpfc_extra_io_tmo, lpfc_nodev_holdio, lpfc_delay_rsp_err,
+ lpfc_tgt_queue_depth and lpfc_check_cond_err.
+ * Clock changes consolidating timers, just in the struct lpfc_hba,
+ to get rid of clkData and pass only one argument to timeout
+ routine. Also, removing need for outstanding clock linked list
+ to stop these timers at rmmod.
+ * Move lpfc.conf contents into lpfc_fcp.c. Removing per adapter
+ attributes in favor of global attributes.
+ * Fix a potential null pointer reference of pmbuf in lpfc_ct.c.
+ * On reset_lun, issue LUN_RESET as opposed to ABORT_TASK_SET.
+ * Removed SCSI_REQ_TMO related code.
+ * Introducing two new defines LPFC_ATTR_R and LPFC_ATTR_RW that do
+ a module_param, MODULE_PARM_DESC, lpfc_param_show,
+ [lpfc_param_store] and CLASS_DEVICE_ATTRIBUTE.
+ * Properly clean up when allocation of a linked BDE fails in the
+ SCSI queuecommand path.
+ * Fail SCSI command if dma_map_sg call fails.
+ * Remove unused macros SWAP_ALWAYS and SWAP_ALWAYS16.
+ * Reset context2 to 0 on exit in
+ lpfc_sli_issue_iocb_wait_high_priority() and
+ lpfc_sli_issue_iocb_wait().
+ * Arranging lpfc_scsiport.c to follow style of use after
+ definition. This removes the need for the cruft of forward
+ declarations. Also removing a redundant #define ScsiResult as it
+ already available elsewhere.
+ * Applying "Streamline lpfc error handling" patch from Christoph
+ Hellwig (hch@infradead.org) with following modifications: fix
+ mem leaks, remove some misplaced code that need not be there,
+ print a message on exit (old code prints two (entry/exit)), make
+ ret values consistent (either 1/0 or SUCCESS/FAILURE), keep all
+ eh routines in a single file (lpfc_scsiport.c).
+ * Move contents of lpfc_module_param.h into lpfc_fcp.c.
+ * Changed sysfs attributes to CLASS_DEVICE_ATTRIBUTES (previously
+ DEVICE_ATTRIBUTES). They now appear in
+ /sys/class/scsi_host/hostx (previously in
+ /sys/bus/pci/drivers/lpfc/devx).
+ * Removed lpfc_syfs.h and lpfc_sysfs.c.
+ * Cleanup of config params. Throttle params have been removed.
+ max_lun has been removed. max_target is replaced with a #define,
+ lun_skip is removed. Remove ipfc config params and related
+ code.
+ * Changed DMABUF_t usage to struct lpfc_dmabuf.
+ * Downsizing iCfgParam structure to include a_string, a_low, a_hi
+ and a_default values only.
+ * Free SCSI buf safety memory pool on shutdown to eliminate memory
+ leak.
+ * Change lpfc_printf_log to a #define. Also include phba->brd_no
+ and newline in the print string rather than in the #define.
+ * Remove code that optionally locates Host Group Pointers in host
+ memory SLIM since this is no longer needed for PPC64, once
+ CONFIG_PORT uses HBA's view of its BAR0.
+ * Removed the forward declarations of the sli functions and
+ rearranging the code in lpfc_sli.c.
+ * Removed the preamble functionality from logging.
+ * Make lpfc_sli_hba_setup() return negative error codes on error
+ and correct the comment left over in lpfc_fcp.c
+ * Removed the lpfc_loadtime variable.
+ * Put a space between all ifs and their open parens '('.
+ * Change Studly_Caps LPFC_SCSI_BUF_t to struct lpfc_scsi_buf.
+ * Fixed insmod hang after hardware error.
+ * Relocated scsi_host alloc to before we enable the interrupt
+ handler
+ * Add .tmp_versions directory to Makefile clean target. This
+ directory is created in the 2.6.5+ build process (with Red Hat
+ kernels at least).
+ * Changing phba->config to kmalloc lpfc_icfgparam and not
+ *phba->config. This is manifesting itself as a panic in
+ pci_release_region().
+ * Fix for firmware download / board reset problem.
+ * Integrated patch from Christoph Hellwig (hch@infradead.org) to
+ reorganize and cleanup lpfc_fcp.c
+ * Don't abort commands immediately when there is an RSCN event to
+ give driver time to rediscover targets before the midlayer
+ retries the SCSI commands.
+
+Changes from 20040604 to 20040614
+
+ * Changed version number to 8.0.4
+ * Removed lpfc_valid_lun function.
+ * Added scsi_buf safety pool to address scsi_buf failures in
+ queuecommand under low memory conditions. Allocations now come
+ from kmalloc initially, but if kmalloc fails, the allocation
+ comes from the safety pool.
+ * Modified lpfc_slave_alloc to only set the scsi_device->hostdata
+ pointer if the driver has discovered the target. This routine
+ always returns success now as well since no error ever occurs in
+ the alloc routine.
+ * Mask only info and warning messages. Print all error messages
+ irrespective of mask.
+ * Removing lpfc_log_chk_msg_disabled()
+ * Changed lpfc_printf_log to take struct lpfc_hba * directly
+ instead of a "board number".
+ * Convert dma_sync_single to pci_dma_sync_single_for_{device/cpu}.
+ * Implemented new style log messages. The message strings are now
+ embedded in the call to lpfc_printf_log.
+ * Decreased FLOGI discovery timeout to 20 seconds.
+ * On error in lpfc_pci_probe_one() return -1 and not 1.
+ * Allow for board numbers that are not sequential, paving the way
+ for hotplug support.
+ * scsi_add_host() can fail, so wrap it around in an if(). Also
+ initiate scsi_scan_host() after attaching the sysfs attributes.
+ * lpfc_release_version is used only in lpfc_ct.c, so move it there
+ and mark it as static.
+ * Removed lpfc_sleep_ms and replaced with mdelay or schedule calls
+ directly
+ * Removed all (struct list_head *) casts from clkData-related list
+ handling in list_add, list_del macros.
+ * Removed EXPORT_SYMBOLs.
+ * Removed LPFC_MIN_QFULL and lpfc_qthrottle_up.
+ * Replace LPFCSCSITARGET_t with struct lpfc_target.
+ * Replace LPFCSCSILUN_t with struct lpfc_lun.
+ * Remove unused struct declarations (fcPathId and fcRouteId) from
+ lpfc_scsi.h.
+ * Rewrite use of FC transport attributes.
+ * Fix crash when link is lost. This was due to lpfc_delay_iodone
+ calling list_del on an object that was never put on a list.
+ * Remove trailing spaces at the end of all lines.
+ * Set MAX_FCP_TARGET to 256 from 0xff. Set MAX_FCP_LUN and
+ MAX_FCP_CMDS to their decimal equivalents and updated
+ documentation.
+
+Changes from 20040526 to 20040604
+
+ * Changed version number to 8.0.3
+ * Completed sysfs FC transport support.
+ * Removed unused fields in SCSI LUN and SCSI Target structures:
+ void *pTargetProto; void *pTargetOSEnv; void *pLunOSEnv;
+ * Modified list_for_each to list_for_each_entry. Modified
+ list_for_each_safe to list_for_each_entry_safe.
+ * Remove lpfc_dfc.h file.
+ * Changed pHba->phba, pCommand->pcmd
+ * Changed plogi_ndlp -> plogindlp, pos_tmp->postmp, pRsp->prsp,
+ pCmd->pcmd
+ * Changed pText -> ptext
+ * Changed p_tmp_buff -> ptmpbuff
+ * Changed pBufList -> pbuflist, pRsp -> prsp, pCmd -> pcmd
+ * Changed *pos_tmp -> *postmp, *p_mbuf -> *pmbuf
+ * Following changes are made to the SCSI fast path: Added
+ DMA_BUF_t member to the lpfc_scsi_buf_t. This will reduce a
+ memory allocation in the scsi fast path. Added check for
+ targetp == NULL in the scsi fast path. Increased number of
+ scatter gather entries in lpfc_scsi_dma_ext to 4 from 3 and
+ changed the size of lpfc_scsi_dma_ext to 264
+ * Fixing some missing static lpfc_nportdisc.c.
+ * Reordered #include lines so that lpfc.h doesn't have to #include
+ other header files.
+ * Remove lpfc_get_hba_sym_node_name() as a global EXPORT and make
+ it static.
+ * Move struct clk_data definition from lpfc_hw.h to lpfc_sli.h.
+ * Changed LPFC_IOCBQ_t to struct lpfc_iocbq.
+ * Changed LPFC_SLI_RING_t to struct lpfc_sli_ring.
+ * Changed LPFC_NODELIST_t to struct lpfc_nodelist.
+ * Rearranged lpfc_nportdisc.c by moving state machine array
+ (lpfc_disc_action) and the one function that uses it,
+ lpfc_disc_state_machine, to the end of the file, removing the
+ need for the raft of prototypes at the top.
+ * Changed LPFC_BINDLIST_t to struct lpfc_bindlist.
+ * Removed lpfc_issue_ct_rsp(), lpfc_sleep(), lpfc_add_bind(),
+ lpfc_del_bind(), lpfc_sli_wake_mbox_wait() and
+ lpfc_sli_issue_mbox_wait().
+ * Fixed a large number of overly-long lines.
+ * Fixed some discovery problems: Introduced deferred ndlp removal
+ when in DSM to avoid panic when in nested DMSs Fix NportId
+ fffc01 handling to not relogin after LOGO fixed handling of LOGO
+ on PLOGI issue.
+ * Changed SLI_CT_REQUEST to lpfc_sli_ct_request.
+ * Changed NAME_TYPE to struct lpfc_name.
+ * Changed lpfcCfgParam_t to struct lpfc_cfgparam.
+ * Changed LPFC_STAT_t to struct lpfc_stats.
+ * Changed HBAEVT_t to struct lpfc_hba_event.
+ * Changed Studly_Caps lpfcHBA_t to struct lpfc_hba.
+ * Removed no longer used tasklet_running flag.
+ * Removing *PSOME_VAR typedefs and using SOME_VAR* directly.
+ * Changing .use_clustering to ENABLE_CLUSTERING.
+ * Modify lpfc_queuecommand to return SCSI_MLQUEUE_HOST_BUSY when
+ it can't queue a SCSI command. Also, remove cmnds_in_flight
+ member of struct lpfcHBA for 2.6 kernels as it was only needed
+ to determine what to return from queuecommand.
+ * Change return type of lpfc_evt_iocb_free to void as it doesn't
+ return anything.
+ * Remove unused cmnd_retry_list and in_retry members in struct
+ lpfcHBA.
+ * Remove some instances of unneeded casting of kmalloc's return in
+ lpfc_scsiport.c
+ * Remove lpfc_linux_attach() and lpfc_linux_detach(). Integrate
+ them into lpfc_probe_one() and lpfc_release_one() respectively.
+ * Remove lpfc_num_iocbs, lpfc_num_bufs module parameters
+ * Remove #defines for NUM_NODES, NUM_BUFS and NUM_IOCBS
+
+Changes from 20040515 to 20040526
+
+ * Changing version number to 8.0.2.
+ * Including dma-mapping.h as one of the include headers. Also
+ rearrange the #include order.
+ * Make functions static as appropriate.
+ * queuecommand() will now return SCSI_MLQUEUE_HOST_BUSY instead of
+ 1 to backpressure midlayer.
+ * Removed function prototypes for lpfc_start_timer() and
+ lpfc_stop_timer()
+ * Changed timer support to be inline. Clk_data is now declared
+ right next to the corresponding timer_list entry so we don't
+ have to allocate these clk_data dynamically.
+ * Add readls after writels to PCI space to flush the writes.
+ * Fix misspelled word "safety" in function names.
+ * Fix up comments in lpfc.conf for per HBA parameters to reflect
+ new implementation.
+ * Change lpfc_proc_info handler to get the Nodename from
+ fc_nodename and not fc_portname.
+ * Fix up some comments and whitespace in lpfc_fcp.c.
+ * Formatting changes: get rid of leading spaces in code
+ * Move discovery processing from tasklet to a kernel thread.
+ * Move ndlp node from unmap list to map list if ADISC completed
+ successfully.
+ * Flush all the ELS IOCBs when there is a link event.
+ * LP9802 qdepth is twice the LP9802DC qdepth. Delay
+ elx_sched_init after READ_CONFIG to get max_xri from the
+ firmware. Reset ELX_CFG_DFT_HBA_Q_DEPTH to max_xri after
+ READ_CONFIG
+ * Fix fc_get_cfg_parm() to be more robust and support embedded hex
+ values. The lpfc_param's are now defined as:
+ lpfc_log_verbose="lpfc:0,lpfc0:0x10,lpfc1:4,lpfc100:0xffff" The
+ "," delimter does not matter. It can be anything or not exist at
+ all. ie param = "lpfc:0lpfc0:0x10.lpfc1:4txtlpfc100:0xffff" will
+ also work. Additionally the string is treated as case
+ insensitive.
+ * Changed all usage of lpfc_find_lun_device() to lpfc_find_lun().
+ * Removed unnecessary wrappers lpfc_find_lun_device() and
+ lpfc_tran_find_lun().
+ * Switch from using internal bus/id/lun to similar data from
+ scsi_device structure.
+ * Eliminate one-line function lpfc_find_target()
+ * Added slave_alloc, slave_destory
+ * lpfc_scsi_cmd_start can now acquire lun pointer from
+ scsi_device->hostdata, which is setup in slave_alloc.
+ * Eliminate unnecessary checking on every cmd just to see if we
+ are accessing the device the first time.
+ * Remove assumption in lpfc_reset_lun_handler that a valid
+ lpfc_scsi_buf is hung off of linux's scsi_cmnd->host_scribble
+ when our reset is called.
+
+Changes from 20040507 to 20040515
+
+ * Changed version to 8.0.1
+ * Fixed crash on driver rmmod after error injection tests and
+ lpfc_tasklet deadlock.
+ * Modified lpfc.conf to remove limit on number of support hosts
+ * Removed HBAAPI
+ * Removed duplication of SCSI opcodes from lpfc_fcp.h that are
+ available in scsi/scsi.h
+ * Rework module_param usage
+ * Added MODULE_PARAM_DESC for various module_params
+ * Removed #define EXPORT_SYMTAB
+ * Removed #includes of if_arp.h and rtnetlink.h
+ * Removed string "Open Source" from MODULE_DESC
+ * Cleanup duplicated string definitions used by MODULE_DESC
+ * Renamed lpfc_pci_[detect|release] to lpfc_pci_[probe|remove]_one
+ * Fix formatting of lpfc_driver
+ * Remove unnecessary memset to 0 of lpfcDRVR
+ * Attach driver attributes always unless pci_module_init failed
+ * Remove all one-line wrappers from lpfc_mem.
+ * Remove lpfc_sysfs_set_[show|store] as it is no longer needed
+ * Redo lpfc_sysfs_params_[show|store] to one value per attribute rule
+ * Breakdown lpfc_sysfs_info_show into smaller one value per attribute
+ * Use device attributes instead of driver attributes where appropriate
+ * Remove no longer needed EXPORT_SYMBOLs
+ * Remove some unused code (1600 msg's related)
+
+Changes from 20040429 to 20040507
+
+ * Change version to 8.0.0
+ * Fix the number of cmd / rsp ring entries in lpfc_fcp.c to match
+ the divisions setup in lpfc_hw.h.
+ * Remove phba->iflag reference.
+ * Several locking improvements.
+ * Remove functions lpfc_drvr_init_lock, lpfc_drvr_lock,
+ lpfc_drvr_unlock and lpfc_hipri_*.
+ * Remove LPFC_DRVR_LOCK and LPFC_DRVR_UNLOCK macros.
+ * Make lpfc_info() use lpfc_get_hba_model_desc() instead of
+ rewriting almost identical code.
+ * Fix 1 overly long line in each of lpfc_cfgparm.h, lpfc_ftp.c and
+ lpfc_sli.c.
+ * Fix build for Red Hat 2.6.3 kernel by #defining MODULE_VERSION
+ only if it isn't already defined.
+ * Change elx_sli_issue_mbox_wait to return correct error code to
+ the caller.
+ * In some of the els completion routines, after calling
+ lpfc_elx_chk_latt, driver ignores the return code of the
+ lpfc_elx_chk_latt. This will prevent the discovery state machine
+ restarting correctly when there are link events in the middle of
+ discovery state machine running. Fix this by exiting discovery
+ state machine if lpfc_els_chk_latt returns a non zero value.
+ * Removed MAX_LPFC_BRDS from lpfc_diag.h
+ * Removed unused first_check.
+ * Remove some unused fields and defines.
+ * Change lpfc-param names to lpfc_param.
+ * Add use of MODULE_VERSION macro for 2.6 kernels.
+ * Shorten length of some of the comment lines to make them more
+ readable.
+ * Move FCP_* definitions to their own header file, lpfc_fcp.h.
+ * Remove unused prototypes from lpfc_crtn.h: fcptst, iptst,
+ lpfc_DELAYMS.
+ * Remove duplicated prototypes from lpfc_crtn.h:
+ lpfc_config_port_prep, lpfc_config_port_post,
+ lpfc_hba_down_prep.
+ * Removed some unused export_symbols.
+ * Install driver files into */drivers/scsi/lpfc instead of
+ */drivers/scsi.
+
+Changes from 20040426 to 20040429
+
+ * Declared export symbol lpfc_page_alloc and lpfc_page_free
+ * Changed lpfc version number to 6.98.3
+ * Move the definition of MAX_LPFC_BRDS to the only header file
+ that uses it (lpfc_diag.h).
+ * Change lpfc_sli_wake_iocb_wait to do a regular wake_up since
+ lpfc_sli_issue_iocb_wait now sleeps uninterruptible.
+ * Replace list_for_each() with list_for_each_safe() when a list
+ element could be deleted.
+ * Fix IOCB memory leak
+
+Changes from 20040416 to 20040426
+
+ * Change lpfc_config_port_prep() to interpret word 4 of the DUMP
+ mbox response as a byte-count
+ * Add info attribute to sysfs
+ * Minor formatting (spaces to tabs) cleanup in lpfc_sched.h
+ * Remove unused log message number 732
+ * Completing MODULE_PARM -> module_param changes
+ * Removed unused targetenable module parameter
+ * Removed locks from lpfc_sli_issue_mbox_wait routine
+ * Removed code that retry 29,00 check condition
+ * Removed code that manipulates rspSnsLen.
+ * Fix use of lun-q-depth config param
+ * Fix severity inconsistency with log message 249
+ * Removed lpfc_max_target from lpfc_linux_attach
+ * Replace references to lpfcDRVR.pHba[] with lpfc_get_phba_by_inst()
+ * Change lpfc_param to lpfc-param
+ * Partially removed 32 HBA restriction within driver. Incorported
+ lpfc_instcnt, lpfc_instance[], and pHba[] into lpfcDRVR
+ structure Added routines lpfc_get_phba_by_inst()
+ lpfc_get_inst_by_phba() lpfc_check_valid_phba()
+ * Turn on attributes "set" & "params" by default.
+ * Further formatting/whitespace/line length cleanup on: lpfc_ct.c
+ lpfc_els.c lpfc_fcp.c lpfc_hbadisc.c lpfc_init.c lpfc_ipport.c
+ lpfc_mbox.c lpfc_nportdisc.c lpfc_sched.c lpfc_sched.h
+ lpfc_scsi.h lpfc_scsiport.c lpfc_sli.c and lpfc_sli.h
+ * Add log message 249 to log any unsupported device addressing
+ modes encountered.
+ * Add support for 256 targets and 256 LUNs
+ * Fixed panic in lpfc_linkdown.
+ * Removed (struct list_head*) casting in several calls to list_del
+ * Free irq reservation and kill running timers when insmod or
+ modprobe are killed via ctrl-c
+ * Remove drivers/scsi from include path
+ * Wrap use of log message 311 in macro
+ * Detect failure return from pci_map_sg call in lpfc_os_prep_io
+ * Fix use-after-free of IOCB in lpfc_sli_process_sol_iocb which
+ was causing an Oops on 2.6.5 kernel.
+ * Cleanup use of several gotos not used for error exit.
+ * Replace memcpy_toio() and memcpy_toio() with endian-dependent
+ lpfc_memcpy_to_slim() and lpfc_memcpy_from_slim() so that for
+ big endian hosts like PPC64, the SLIM is accessed 4 bytes at a
+ time instead of as a byte-stream.
+
+Changes from 20040409 to 20040416
+
+ * The scsi_register and scsi_alloc_host OS calls can fail and
+ return a zero-valued host pointer. A ctrl-C on 2.6 kernels
+ during driver load will cause this and the driver to panic.
+ Fixed this bug. Also found a bug in the error_x handling with
+ lpfc_sli_hba_down - it was in the wrong place and the driver
+ lock was not held, but needed to be (in lpfc_linux_attach) Fixed
+ both. Did some minor comment clean up.
+ * Removed unwanted (void *) castings.
+ * Replace define of INVALID_PHYS, with kernel 2.6.5's
+ dma_mapping_error() and add a inline function for earlier
+ kernels. Remove lpfc_bad_scatterlist().
+ * Clean up formatting in hbaapi.h, lpfc.h, lpfc_cfgparm.h,
+ lpfc_crtn.h, lpfc_ct.c, lpfc_diag.h, lpfc_disc.h, lpfc_els.c,
+ lpfc_fcp.c, lpfc_hbadisc.c, lpfc_hw.h, lpfc_init.c,
+ lpfc_ipport.c, lpfc_logmsg.c, lpfc_logmsg.h and lpfc_scsiport.c
+ - mostly replacing groups of 8 spaces with hard tabs and keeping
+ lines to 80 column max..
+ * Removed LPFC_DRVR_LOCK call from lpfc_unblock_requests for 2.4
+ kernels. The lpfc_scsi_done routine already unlocks the driver
+ lock since it expects this lock to be held.
+ * Removed global lock capabilities from driver lock routines
+ * Remove SA_INTERRUPT flag from request_irq
+ * Move dma_addr_t cast inside of getPaddr macro as everywhere
+ getPaddr is used, the return is cast to dma_addr_t.
+ * Clean up formatting in lpfc_sli.c and lpfc_sysfs.c - mostly
+ replacing groups of 8 spaces with hard tabs and keeping lines
+ to 80 column max.
+ * Fix build for RHEL 2.1 BOOT kernels by always #including
+ interrupt.h in lpfc.h.
+ * Fix RHEL 3 build by #defining EXPORT_SYMTAB.
+ * Replace sprintf with snprintf in lpfc_proc_info.
+ * Fix build warnings on 2.6 kernels - remove no longer used calls
+ to character device initialization.
+ * Initial support code for discovery in tasklet conversion.
+ * Removing char interface and ioctl code.
+ * Change all elx prefixes to lpfc
+ * Replace lpfc_write_slim() & lpfc_read_slim() with memcpy_toio(),
+ memcpy_fromio(), writel() & readl().
+
+Changes from 20040402 to 20040409
+
+ * Replaced lpfc_read_hbaregs_plus_offset and
+ lpfc_write_hbaregs_plus_offset functions with readl and writel.
+ * Get rid of long mdelay's in insmod path
+ * Changed the way our pci_device_id structures are initialized
+ * Replace lpfc_read/write_CA/HA/HC/HS with calls to readl() &
+ writel() directly.
+ * Increase SLI2_SLIM to 16K Increase cmd / rsp IOCBs accordingly
+ * Removed lpfc_els_chk_latt from the lpfc_config_post function.
+ lpfc_els_chk_latt will enable the link event interrupts when
+ flogi is pending which causes two discovery state machines
+ running parallely.
+ * Add pci_disable_device to unload path.
+ * Move lpfc_sleep_event from lpfc_fcp.c to lpfc_util_ioctl.c
+ * Call dma_map_single() & pci_map_single() directly instead of via
+ macro lpfc_pci_map(). Allow address 0 for PPC64.
+ * Change sleep to uninterruptible in lpfc_sli_issue_icob_wait
+ because this function doesn't handle signals.
+ * Move lpfc_wakeup_event from lpfc_fcp.c to lpfc_ioctl.c
+ * Remove unneeded #include <linux/netdevice.h>
+ * Remove unused clock variables lpfc_clkCnt and lpfc_sec_clk.
+ * Get rid of capitalization of function names.
+ * Removed lpfc_addr_sprintf.
+ * Implemented gotos in lpfc_linux_attach for error cases.
+ * Replace mlist->dma.list = dmp->dma.list; to mlist = dmp.
+ * Remove functions lpfc_get_OsNameVersion and elx_wakeup. Change
+ elx_wakeup to wake_up_interruptible
+ * Add function lpfc_get_os_nameversion and change
+ lpfc_get_OsNameVersion to lpfc_get_os_nameversion.
+ * Remove lpfc_get_OsNameVersion
+ * Change driver name to a consistent lpfc in every visible place.
+ * Fix build warning: removed unused variable ret in lpfc_fdmi_tmo.
+ * Remove lpfc_utsname_nodename_check function
+ * Remove functions lpfc_register_intr and lpfc_unregister_intr
+ * Fill in owner field in lpfc_ops file_operations struct and
+ remove now unnecessary open and close entry points.
+ * Change function name prefixes from elx_ to lpfc_
+ * Remove special case check for TUR in elx_os_prep_io()
+ * Renamed elx_scsi.h to lpfc_scsi.h
+ * Renamed elx_sched.h to lpfc_sched.h
+ * Renamed elx_mem.h to lpfc_mem.h
+ * Renamed elx_sli.h to lpfc_sli.h
+ * Renamed elx_logmsg.h to lpfc_logmsg.h
+ * Renamed elx.h to lpfc.h
+ * Renamed elx_sli.c to lpfc_sli.c
+ * Renamed elx_sched.c to lpfc_sched.c
+ * Renamed elx_mem.c to lpfc_mem.c
+ * Renamed elx_logmsg.c to lpfc_logmsg.c
+ * Renamed lpfcLINUXfcp.c lpfc_fcp.c
+ * Renamed elx_clock.c to lpfc_clock.c
+ * Reduce stack usage in lpfc_info().
+ * Move lpip_stats structure from lpfc_hba.h to lpfc_ip.h.
+ * Move lpfc_stats and HBAEVT_t structures from lpfc_hba.h to
+ lpfc.h
+ * Remove lpfc_hba.h
+ * Remove duplicate rc definitions from
+ * Removed code which used next pointer to store mbox structure.
+ * Cleaned up list iterations.
+ * Removed non list manipulation of the next pointers.
+ * Change list_del()/INIT_LIST_HEAD sequences to list_del_init()
+ * In ELX_IOCBQ_t: Moved hipri_trigger field to iocb_flag. Combined
+ hipri_wait_queue and rsp_iocb in union
+ * Replaced casting from list_head with list_entry macro.
+ * Added ct_ndlp_context field to the ELX_IOCBQ_t.
+ * Do not use DMABUf_t list to store ndlp context
+ * Return 0 from lpfc_process_iotcl_util() when ELX_INITBRDS
+ succeeds.
+ * remove elx_os_scsiport.h
+ * Do not use DMABUf_t list to hold rpi context
+ * Replace elx_cfg_* names with lpfc_cfg-*
+ * Moved FCP activity to ring 0. Moved ELS/CT activity to ring 2.
+ * Clean up formatting of elx_sli.h (tabs for indents, 80 column
+ lines).
+ * Remove unused elxclock declaration in elx_sli.h.
+ * Since everywhere IOCB_ENTRY is used, the return value is cast,
+ move the cast into the macro.
+ * Split ioctls out into seperate files
+
+Changes from 20040326 to 20040402
+
+ * Updated ChangeLog for 20040402 SourceForge drop.
+ * Use safe list iterator for ndlp list
+ * Added code to return NLP_STE_FREED_NODE from the discovery
+ state machine functions if the node is freed from the
+ function.
+ * Fixes to DMABUF_t handling
+ * Fix for load error in discovery
+ * Remove loop_cnt variable from lpfc_rcv_plogi_unused_node.
+ * Remove nle. reference.
+ * Remove support for building 2.4 drivers
+ * Remove elx_util.h and replace elx_disc.h with lpfc_disc.h
+ * Implemented the Linux list macros in the discovery code.
+ Also moved elx_disc.h contents into lpfc_disc.h
+ * Unused variable cleanup
+ * Use Linux list macros for DMABUF_t
+ * Break up ioctls into 3 sections, dfc, util, hbaapi
+ rearranged code so this could be easily seperated into a
+ differnet module later All 3 are currently turned on by
+ defines in lpfc_ioctl.c LPFC_DFC_IOCTL, LPFC_UTIL_IOCTL,
+ LPFC_HBAAPI_IOCTL
+ * Misc cleanup: some goto's; add comments; clarify function
+ args
+ * Added code to use list macro for ELXSCSITARGET_t.
+ * New list implementation for ELX_MBOXQ_t
+ * Cleaned up some list_head casting.
+ * Put IPFC ifdef around two members of struct lpfc_nodelist.
+ * Cleaned up iocb list using list macros and list_head data
+ structure.
+ * lpfc_online() was missing some timer routines that were
+ started by lpfc_linux_attach(). These routines are now also
+ started by lpfc_online(). lpfc_offline() only stopped
+ els_timeout routine. It now stops all timeout routines
+ associated with that hba.
+ * Replace seperate next and prev pointers in struct
+ lpfc_bindlist with list_head type. In elxHBA_t, replace
+ fc_nlpbind_start and _end with fc_nlpbind_list and use
+ list_head macros to access it.
+ * Fix ulpStatus for aborting I/Os overlaps with newer firmware
+ ulpStatus values
+ * Rework params_show/store to be consistent as the other
+ routines. Remove generic'ness and rely on set attribute.
+ * Remove unused log message.
+ * Collapse elx_crtn.h and prod_crtn.h into lpfc_crtn.h
+ * Ifdef Scheduler specific routines
+ * Removed following ununsed ioclt's: ELX_READ_IOCB
+ ELX_READ_MEMSEG ELX_READ_BINFO ELX_READ_EINVAL ELX_READ_LHBA
+ ELX_READ_LXHBA ELX_SET ELX_DBG LPFC_TRACE
+ * Removed variable fc_dbg_flg
+ * Fixed a bug where HBA_Q_DEPTH was set incorrectly for
+ 3-digit HBAs. Also changed can_queue so midlayer will only
+ send (HBA_Q_DEPTH - 10) cmds.
+ * Clean up code in the error path, check condition. Remove
+ ununsed sense-related fields in lun structure.
+ * Added code for safety pools for following objects: mbuf/bpl,
+ mbox, iocb, ndlp, bind
+ * Wrapped '#include <elx_sched.h>' in '#ifdef USE_SCHEDULER'.
+ * Fixed 'make clean' target.
+ * Build now ignores elx_sched.o, and includes lpfc_sysfs.o.
+ * Wrapped lpfndd.o target in BUILD_IPFC ifdef.
+ * Removed elx_os.h inclusion in implementation files.
+ * Removed ELX_OS_IO_t data structure and put data direction
+ and non scatter/gather physical address into the scsi buffer
+ structure directly. Moved DRVR_LOCK, putPaddr, getPaddr
+ macros and some defines into elx.h since they are required
+ by the whole driver.
+ * Migrated following ioctls (debug) ELX_DISPLAY_PCI_ALL
+ ELX_DEVP ELX_READ_BPLIST ELX_RESET_QDEPTH ELX_STAT.
+ * Step 1 of attempt to move all Debug ioctls to sysfs.
+ Implemented the following IOCTLs in sysfs: ELX_WRITE_HC
+ ELX_WRITE_HS ELX_WRITE_HA ELX_WRITE_CA ELX_READ_HC
+ ELX_READ_HS ELX_READ_HA ELX_READ_CA ELX_READ_MB ELX_RESET
+ ELX_READ_HBA ELX_INSTANCE ELX_LIP. Also introduced
+ attribute "set" to be used in conjuction with the above
+ attributes.
+ * Removed DLINK, enque and deque declarations now that clock
+ doesn't use them anymore
+ * Separated install rule so that BUILD_IPFC has to be set when
+ make is called in order for the install rule to attempt to
+ copy the lpfndd.o driver. This change fixes a bug that
+ occurs because the install rule by default attempted to
+ install lpfndd.o, whereas the default make rule did not by
+ default build lpfndd.o.
+ * Keep track if hbaapi index numbers need to be refreshed.
+ * Removed prod_os.h from include list.
+ * Removed LPFC_LOCK and LPFC_UNLOCK macros. Added OS calls
+ into elx_os_scsiport.c. This file is now empty.
+ * Added spin_lock_irqsave and spin_unlock_irqrestore calls
+ into code directly and removed LPFC_LOCK_ and _UNLOCK_
+ macros
+ * Remove references to "elx_clock.h"
+ * Added utsname.h to include list. The previous checkin to
+ elx_os.h removed its inclusion of utsname.h since there is
+ precious little in the file. However, lpfcLINUXfcp.c needs
+ it and now has it.
+ * Removed some commented-out code
+ * Removed elx_lck_t data structure, stray elxDRVR_t type, and
+ include from file. No longer used.
+ * Removed two PCI Sync defines. Removed includes - not
+ needed. Cleaned up macro lines.
+ * Added two functions from elxLINUXfcp.c. These functions
+ were IPFC specific.
+ * Removed hipri lock abstractions and added OS call into code.
+ Removed elx_lck_t and added spinlock_t directly. Moved two
+ IPFC functions into lpfc_ipport.c
+ * Moved IP specific structures to lpfc_ip.h file.
+ * lpfc_ipfarp_timeout() uses system timer. Remove all usages
+ of old internal clock support.
+ * Made changes to compile without IPFC support for the default
+ build. Added ifdef IPFC for all lpfc_ip.h includes.
+ * Patched elx_free_scsi_buf
+ * Removed elx_sched.o from 2.6 dependencies
+ * Reworked lpfc_pcimap.
+ * Use Linux swap macros to replace ELX swapping macros
+ (SWAP_SHORT, SWAP_LONG, SWAP_DATA, SWAP_DATA16,
+ PCIMEM_SHORT, PCIMEM_LONG, PCIMEM_DATA).
+ * move in_interrupt() check inside of elx_sleep_ms()
+ * Moved location of pci.h include.
+ * Restored elx_lck_t types in elxHBA_t.
+ * Removed elx_pci_dma_sync call. Also removed some PCI
+ defines from elx_hw.h and removed the spinlock_t locks that
+ are no longer used in elx.h
+ * elx_iodone() now uses system timer.
+ * elx_qfull_retry() now uses system timer.
+ * lpfc_put_buf(), lpfc_ip_xri_timeout() and
+ lpfc_ip_timeout_handler() now use system timer.
+ * lpfc_fdmi_tmo() and lpfc_qthrottle_up() now use system
+ timer.
+ * Removed num_bufs and num_iocbs configuration parameters.
+ * Fixed a memory corruption bug. This was caused by a memory
+ write to ndlp structure from lpfc_cmpl_els_acc function.
+ This ndlp structure was freed from lpfc_els_unsol_event.
+ * lpfc_disc_timeout() and lpfc_establish_link_tmo() now use
+ system timer. Also update lpfc_els_retry_delay() to do a
+ single lock release at the end.
+ * Remove use of PAN (pseudo adapter number).
+ * Reintroduced usage of the cross compiler for building on
+ ppc64 to remove build errors that were cropping up when
+ using the standard gcc compiler.
+ * Fix no-unlock-before return in lpfc_els_retry_delay which was
+ causing a deadlock on insmod in some environments.
+ * Minor format changes fix up comments
+ * Create utility clock function elx_start_timer() and
+ elx_stop_timer(). All timeout routines now use these common
+ routines.
+ * Minor formating changes fix up comments
+ * Minor formatting changes get rid of failover defines for
+ syntax checking
+ * Minor formatting changes remove ISCSI defines.
+ * Fix typo in install target for 2.4 kernels.
+ * Removed unused elx_scsi_add_timer extern function
+ declaration.
+ * Cleanup casting around DMA masks.
+ * Comment out lpfndd.o modules_install section as lpfndd.o is
+ not generated if CONFIG_NET_LPFC is not set. Also refer to
+ BASEINCLUDE only in out of kernel source module builds as it
+ will not exist otherwise.
+ * Removed unused malloc counters from lpfcLINUXfcp.c.
+ * Remove some unnecessary #includes in lpfcLINUXfcp.c
+ * Remove unncessary #includes in elxLINUXfcp.c
+ * Minor formatting cleanups in Makefile to avoid some
+ linewrapping.
+ * Removed unused elx_mem_pool data structure.
+ * Remove several unnecessary #includes.
+ * Moving fix for memory leak in ioctl lip area to sysfs's lip.
+ * Removed unused elx_dma_handle_t elx_acc_handle_t
+ FC_MAX_SEGSZ and FC_MAX_POOL.
+ * Rewrite of Makefile. Fixes breakages with make -j4 during
+ kernel compile. Does not recompile all files on every
+ build. Uses the kernel build's definitions of CFLAGS,
+ MODFLAGS etc. Removed "make rpm" option.
+ * Removed unused #defines CLOSED, DEAD, OPENED, NORMAL_OPEN
+ and unneeded #include of elx_sched.h in elx.h.
+ * Several log message updates
+ * Add PCI_DEVICE_ID_FIREFLY for LP6000
+ * Fixed known issues in 20040326: driver crashes on rmmod in
+ both 2.4 and 2.6 kernels
+
+
+Changes from 20040319 to 20040326
+
+ * Updated ChangeLog for 20040326 SourceForge drop.
+ * remove lpfc_isr / lpfc_tmr logic fixed up 8 spaces from
+ previous checkins with tabs
+ * replace elx_in_intr() with in_interrupt()
+ * Remove unused messages 1602 and 1603.
+ * Fix the following issues with log messages: Remove unused
+ messages 406, 407, 409, 927, 928, 1201, 1202, 1204, 1205, 1206
+ and 1207. Create a new message 738 to fix duplicate instances
+ of 736.
+ * Removed remaining pci interface abstractions from elxLINUXfcp.c.
+ Implemented OS calls directly in all remaining files and cleaned
+ up modules. Removed prototypes as well.
+ * Removed following functions/structures elx_mem_dmapool
+ elx_idx_dmapool elx_size_dmapool elx_kmem_lock dfc_data_alloc
+ dfc_data_free dfc_mem struct mbuf_info elx_acc_handle_t
+ data_handle elx_dma_handle_t dma_handle struct elx_memseg
+ MEMSEG_t
+ * lpfc_els_timeout_handler() now uses system timer.
+ * Further cleanup of #ifdef powerpc
+ * lpfc_scsi_timeout_handler() now uses system timer.
+ * Replace common driver's own defines for endianess w/ Linux's
+ __BIG_ENDIAN etc.
+ * Added #ifdef IPFC for all IPFC specific code.
+ * lpfc_disc_retry_rptlun() now uses system timer.
+ * lpfc_npr_timeout() now uses system timer.
+ * Modified detect code, on insmod, to only wait a max of 2 secs if
+ link comes up and there are no devices.
+ * Move remaining message logging functions into
+ elx_logmsg.c/elx_logmsg.h.
+ * Added code to clear link attention bit when there is a pending
+ link event and the memory allocation for read_la mail box
+ command fails.
+ * Removed function calls for mapping bar registers and allocating
+ kernel virtual memory mappings to the mapped bars Removed
+ prototypes, lpfc_driver_cache_line, and pci_bar1_map rename to
+ pci_bar2_map.
+ * Allocate mbox only if the hba_state is in ready state.
+ * Complete lip support via sysfs. To lip, echo brdnum >
+ /sys/bus/pci/drivers/lpfc/lip.
+ * moving sysfs show/store implementations to lpfc_sysfs.c. Also add
+ support for lip.
+ * Add files: lpfc_sysfs.c, lpfc_sysfs.h
+ * move LPFC_DRIVER_NAME and LPFC_MODULE_DESC out of lpfcLINUXfcp.c
+ to lpfc_version.h, since it is now needed in lpfc_sysfs.c
+ * elx_mbox_timeout now uses system timer
+ * Changed lpfc_nodev_timeout, lpfc_els_retry_delay and
+ lpfc_linkdown_timeout to use the system timer instead of
+ internal clock support.
+ * Move remaining message logging functions in elx_util.c to
+ elx_logmsg.c.
+ * Remove some unnecessary typecasting.
+ * Remove log message that is no longer used (was used by
+ elx_str_atox).
+ * Replaced DLINK_t and SLINK_t by standard Linux list_head
+ * Removed deque macro
+ * Replaced ELX_DLINK_t ans ELX_SLINK_t by Linux struct list_head
+ (except for clock)
+ * Removed following functions from code: linux_kmalloc linux_kfree
+ elx_alloc_bigbuf elx_free_bigbuf
+ * Removed following abstract functions from the code. elx_malloc
+ elx_free elx_ip_get_rcv_buf elx_ip_free_rcv_buf
+ elx_mem_alloc_dmabuf elx_mem_alloc_dmabufext elx_mem_alloc_dma
+ elx_mem_alloc_buf lpfc_bufmap
+ * Removed custom PCI configuration #defines and replaced with
+ OS-provided #defines. Also added linux/pci.h to *.c files.
+ * Remove elx_str_ctox. Replace elx_str_atox with sscanf.
+ * Many indentation/whitespace fixes.
+ * Replace elx_str_ctox with isxdigit where it was only used to
+ check the value of a character.
+ * Removed following functions from the code. elx_kmem_free
+ elx_kmem_alloc elx_kmem_zalloc
+ * Change use of 2.4 SCSI typedef Scsi_Host_Template to struct
+ scsi_host_template for 2.6 kernels.
+ * Change use of 2.4 SCSI typedefs (Scsi_Device, Scsi_Cmnd,
+ Scsi_Request) the their real struct names.
+ * Move 2.6 compatibility irqreturn definitions to lpfc_compat.h.
+ Protect these definitions from conflicting with similar ones in
+ later 2.4 kernels.
+ * Remove unused definitions: LINUX_TGT_t, LINUX_LUN_t,
+ LINUX_BUF_t, elx_lun_t, SET_ADAPTER_STATUS.
+ * Convert pci_ calls to linux 2.6 dma_ equivalents.
+ * Removed unused types: struct buf, struct sc_buf, T_SCSIBUF
+ typedef.
+ * Fix Makefile so that 2.4 drivers don't always rebuild all files.
+ * Remove unused _static_ and fc_lun_t definitions.
+ * Cleaned up some memory pool implementation code.
+ * Fix panic with char dev changes. Turns out that 2.6.4 code does
+ the same in kernel space with the 2.4 interface style
+ definitions. So remove the new char dev code altogether.
+ * Remove typecasting from fc_get_cfg_param and consolidate
+ multiple instances of the parameter switch into a single
+ instance.
+ * Use lpfc_is_LC_HBA() macro that tests pcidev->device directly
+ instead of saving a private copy that undergoes varied shifting
+ & casting.
+ * Removed usage of all memory pools.
+
+Changes from 20040312 to 20040319
+
+ * Use dev_warn instead of printk for 2.6 kernels
+ * Correct Iocbq completion routine for 2.6 kernel case
+ * Change void *pOSCmd to Scsi_Smnd *pCmd
+ * Change void *pOScmd to struct sk_buff *pCmd
+ * Remove data directon code.
+ * Removed memory pool for buf/bpl buffers and use kmalloc/kfree
+ pci_pool_alloc/free directly.
+ * Move PPC check for DMA address 0 in scatter-gather list, into
+ lpfc_compat.h
+ * Always use pci_unmap_single() instead of pci_unmap_page()
+ * Clean up the 2.6 vs 2.4 #if blocks.
+ * Conditionalize Scheduler
+ * Add a comment to explain a little what the first Makefile
+ section does.
+ * Removed lpfc_intr_post
+ * Sysfs new display format. Also added write functionality. You
+ can [ echo "0 log_verbose 3" >
+ /sys/bus/pci/drivers/lpfc/params]. Hex support yet to be added.
+ * Removed several #ifdef powerpc, including for a discovery issue
+ in lpfc_ValidLun()
+ * Change elx_printf_log to use vsprintf.
+ * Added lpfc_compat.h provides macros to aid compilation in the
+ Linux 2.4 kernel over various platform architectures. Initially
+ support mapping to a DMA address.
+ * Removed memory pool for nlp/bind buffers and use kmalloc/kfree
+ directly.
+ * Removed memory pool for iocb buffers and use kmalloc/kfree
+ directly.
+ * Removed memory pool for mailbox buffers and use kmalloc/kfree
+ directly.
+ * Cleaned up back and forth casts
+ * Initial support for sysfs for 2.6 kernel.
+ * Changed elx_dma_addr_t to dma_addr_t
+ * Fix a 2.6 kernel check to be >= 2.6.0 instead of > (was missing
+ 2.6.0).
+ * Remove elx_printf and elx_str_sprintf. Replace elx_print with
+ printk.
+ * Replace elx_printf with printk.
+ * Replace elx_str_sprintf with sprintf.
+ * Removed the mem_lock, its prototype, function, macro, and
+ iflags.
+ * Use kmalloc/kfree for ELX_SCSI_BUF_t
+ * Use linux pci_pools for SCSI_DMA_EXT
+ * Use linux pci_pools for BPLs.
+ * Minor cleanup of DFC args for PPC64.
+ * Several small indentation cleanups.
+ * New Linux 2.6 style of char device registration.
+ * Migrated members of LPFCHBA_t and LINUX_HBA_t into elxHBA_t
+ * Use strcpy, strncmp, isdigit, strlen instead of abstractions
+ * Cleanup of driver_template.
+ * Facilitate compile time turn on/off of lpfc_network_on.
+ * Split large source files into smaller, better named ones.
+
+Changes from 2.10a to 20040312
+
+ * Fix build for 2.4 kernels
+ * Move driver version macros into lpfc_version.h file.
+ * Fixed data miscompare with LIP.
+ * Removed elx_sli, elx_ioc, elx_disc, elx_sch routines,
+ prototypes, and reference points.
+ * Correct the space insertions with hardtabs
+ * Remove routine call pointers in ELX_SLI_INIT_t struct.
+ * Removed module locks except for drvr, mem, and clock.
+ * Removed unused module locks from sourcebase. Kept drvr_lock,
+ mem_lock, and clock_lock.
+ * Change NULL to 0
--- /dev/null
+
+LPFC Driver Release Notes:
+
+=============================================================================
+
+
+ IMPORTANT:
+
+ Starting in the 8.0.17 release, the driver began to be targeted strictly
+ toward the upstream kernel. As such, we removed #ifdefs for older kernels
+ (pre 2.6.10). The 8.0.16 release should be used if the driver is to be
+ run on one of the older kernels.
+
+ The proposed modifications to the transport layer for FC remote ports
+ and extended attribute support is now part of the upstream kernel
+ as of 2.6.12. We no longer need to provide patches for this support,
+ nor a *full* version which has old an new kernel support.
+
+ The driver now requires a 2.6.12 (if pre-release, 2.6.12-rc1) or later
+ kernel.
+
+ Please heed these dependencies....
+
+
+ ********************************************************************
+
+
+The following information is provided for additional background on the
+history of the driver as we push for upstream acceptance.
+
+Cable pull and temporary device Loss:
+
+ In older revisions of the lpfc driver, the driver internally queued i/o
+ received from the midlayer. In the cases where a cable was pulled, link
+ jitter, or a device temporarily loses connectivity (due to its cable
+ being removed, a switch rebooting, or a device reboot), the driver could
+ hide the disappearance of the device from the midlayer. I/O's issued to
+ the LLDD would simply be queued for a short duration, allowing the device
+ to reappear or link come back alive, with no inadvertant side effects
+ to the system. If the driver did not hide these conditions, i/o would be
+ errored by the driver, the mid-layer would exhaust its retries, and the
+ device would be taken offline. Manual intervention would be required to
+ re-enable the device.
+
+ The community supporting kernel.org has driven an effort to remove
+ internal queuing from all LLDDs. The philosophy is that internal
+ queuing is unnecessary as the block layer already performs the
+ queuing. Removing the queues from the LLDD makes a more predictable
+ and more simple LLDD.
+
+ As a potential new addition to kernel.org, the 8.x driver was asked to
+ have all internal queuing removed. Emulex complied with this request.
+ In explaining the impacts of this change, Emulex has worked with the
+ community in modifying the behavior of the SCSI midlayer so that SCSI
+ devices can be temporarily suspended while transport events (such as
+ those described) can occur.
+
+ The proposed patch was posted to the linux-scsi mailing list. The patch
+ is contained in the 2.6.10-rc2 (and later) patch kits. As such, this
+ patch is part of the standard 2.6.10 kernel.
+
+ By default, the driver expects the patches for block/unblock interfaces
+ to be present in the kernel. No #define needs to be set to enable support.
+
+
+Kernel Support
+
+ This source package is targeted for the upstream kernel only. (See notes
+ at the top of this file). It relies on interfaces that are slowing
+ migrating into the kernel.org kernel.
+
+ At this time, the driver requires the 2.6.12 (if pre-release, 2.6.12-rc1)
+ kernel.
+
+ If a driver is needed for older kernels please utilize the 8.0.16
+ driver sources.
+
+
+Patches
+
+ Thankfully, at this time, patches are not needed.
+
+
--- /dev/null
+
+ VIA82xx mixer
+ =============
+
+On many VIA82xx boards, the 'Input Source Select' mixer control does not work.
+Setting it to 'Input2' on such boards will cause recording to hang, or fail
+with EIO (input/output error) via OSS emulation. This control should be left
+at 'Input1' for such cards.
--- /dev/null
+Notes on Universal Interface for Intel High Definition Audio Codec
+------------------------------------------------------------------
+
+Takashi Iwai <tiwai@suse.de>
+
+
+[Still a draft version]
+
+
+General
+=======
+
+The snd-hda-codec module supports the generic access function for the
+High Definition (HD) audio codecs. It's designed to be independent
+from the controller code like ac97 codec module. The real accessors
+from/to the controller must be implemented in the lowlevel driver.
+
+The structure of this module is similar with ac97_codec module.
+Each codec chip belongs to a bus class which communicates with the
+controller.
+
+
+Initialization of Bus Instance
+==============================
+
+The card driver has to create struct hda_bus at first. The template
+struct should be filled and passed to the constructor:
+
+struct hda_bus_template {
+ void *private_data;
+ struct pci_dev *pci;
+ const char *modelname;
+ struct hda_bus_ops ops;
+};
+
+The card driver can set and use the private_data field to retrieve its
+own data in callback functions. The pci field is used when the patch
+needs to check the PCI subsystem IDs, so on. For non-PCI system, it
+doesn't have to be set, of course.
+The modelname field specifies the board's specific configuration. The
+string is passed to the codec parser, and it depends on the parser how
+the string is used.
+These fields, private_data, pci and modelname are all optional.
+
+The ops field contains the callback functions as the following:
+
+struct hda_bus_ops {
+ int (*command)(struct hda_codec *codec, hda_nid_t nid, int direct,
+ unsigned int verb, unsigned int parm);
+ unsigned int (*get_response)(struct hda_codec *codec);
+ void (*private_free)(struct hda_bus *);
+};
+
+The command callback is called when the codec module needs to send a
+VERB to the controller. It's always a single command.
+The get_response callback is called when the codec requires the answer
+for the last command. These two callbacks are mandatory and have to
+be given.
+The last, private_free callback, is optional. It's called in the
+destructor to release any necessary data in the lowlevel driver.
+
+The bus instance is created via snd_hda_bus_new(). You need to pass
+the card instance, the template, and the pointer to store the
+resultant bus instance.
+
+int snd_hda_bus_new(snd_card_t *card, const struct hda_bus_template *temp,
+ struct hda_bus **busp);
+
+It returns zero if successful. A negative return value means any
+error during creation.
+
+
+Creation of Codec Instance
+==========================
+
+Each codec chip on the board is then created on the BUS instance.
+To create a codec instance, call snd_hda_codec_new().
+
+int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
+ struct hda_codec **codecp);
+
+The first argument is the BUS instance, the second argument is the
+address of the codec, and the last one is the pointer to store the
+resultant codec instance (can be NULL if not needed).
+
+The codec is stored in a linked list of bus instance. You can follow
+the codec list like:
+
+ struct list_head *p;
+ struct hda_codec *codec;
+ list_for_each(p, &bus->codec_list) {
+ codec = list_entry(p, struct hda_codec, list);
+ ...
+ }
+
+The codec isn't initialized at this stage properly. The
+initialization sequence is called when the controls are built later.
+
+
+Codec Access
+============
+
+To access codec, use snd_codec_read() and snd_codec_write().
+snd_hda_param_read() is for reading parameters.
+For writing a sequence of verbs, use snd_hda_sequence_write().
+
+To retrieve the number of sub nodes connected to the given node, use
+snd_hda_get_sub_nodes(). The connection list can be obtained via
+snd_hda_get_connections() call.
+
+When an unsolicited event happens, pass the event via
+snd_hda_queue_unsol_event() so that the codec routines will process it
+later.
+
+
+(Mixer) Controls
+================
+
+To create mixer controls of all codecs, call
+snd_hda_build_controls(). It then builds the mixers and does
+initialization stuff on each codec.
+
+
+PCM Stuff
+=========
+
+snd_hda_build_pcms() gives the necessary information to create PCM
+streams. When it's called, each codec belonging to the bus stores
+codec->num_pcms and codec->pcm_info fields. The num_pcms indicates
+the number of elements in pcm_info array. The card driver is supposed
+to traverse the codec linked list, read the pcm information in
+pcm_info array, and build pcm instances according to them.
+
+The pcm_info array contains the following record:
+
+/* PCM information for each substream */
+struct hda_pcm_stream {
+ unsigned int substreams; /* number of substreams, 0 = not exist */
+ unsigned int channels_min; /* min. number of channels */
+ unsigned int channels_max; /* max. number of channels */
+ hda_nid_t nid; /* default NID to query rates/formats/bps, or set up */
+ u32 rates; /* supported rates */
+ u64 formats; /* supported formats (SNDRV_PCM_FMTBIT_) */
+ unsigned int maxbps; /* supported max. bit per sample */
+ struct hda_pcm_ops ops;
+};
+
+/* for PCM creation */
+struct hda_pcm {
+ char *name;
+ struct hda_pcm_stream stream[2];
+};
+
+The name can be passed to snd_pcm_new(). The stream field contains
+the information for playback (SNDRV_PCM_STREAM_PLAYBACK = 0) and
+capture (SNDRV_PCM_STREAM_CAPTURE = 1) directions. The card driver
+should pass substreams to snd_pcm_new() for the number of substreams
+to create.
+
+The channels_min, channels_max, rates and formats should be copied to
+runtime->hw record. They and maxbps fields are used also to compute
+the format value for the HDA codec and controller. Call
+snd_hda_calc_stream_format() to get the format value.
+
+The ops field contains the following callback functions:
+
+struct hda_pcm_ops {
+ int (*open)(struct hda_pcm_stream *info, struct hda_codec *codec,
+ snd_pcm_substream_t *substream);
+ int (*close)(struct hda_pcm_stream *info, struct hda_codec *codec,
+ snd_pcm_substream_t *substream);
+ int (*prepare)(struct hda_pcm_stream *info, struct hda_codec *codec,
+ unsigned int stream_tag, unsigned int format,
+ snd_pcm_substream_t *substream);
+ int (*cleanup)(struct hda_pcm_stream *info, struct hda_codec *codec,
+ snd_pcm_substream_t *substream);
+};
+
+All are non-NULL, so you can call them safely without NULL check.
+
+The open callback should be called in PCM open after runtime->hw is
+set up. It may override some setting and constraints additionally.
+Similarly, the close callback should be called in the PCM close.
+
+The prepare callback should be called in PCM prepare. This will set
+up the codec chip properly for the operation. The cleanup should be
+called in hw_free to clean up the configuration.
+
+The caller should check the return value, at least for open and
+prepare callbacks. When a negative value is returned, some error
+occurred.
+
+
+Proc Files
+==========
+
+Each codec dumps the widget node information in
+/proc/asound/card*/codec#* file. This information would be really
+helpful for debugging. Please provide its contents together with the
+bug report.
+
+
+Power Management
+================
+
+It's simple:
+Call snd_hda_suspend() in the PM suspend callback.
+Call snd_hda_resume() in the PM resume callback.
+
+
+Codec Preset (Patch)
+====================
+
+To set up and handle the codec functionality fully, each codec may
+have a codec preset (patch). It's defined in struct hda_codec_preset:
+
+ struct hda_codec_preset {
+ unsigned int id;
+ unsigned int mask;
+ unsigned int subs;
+ unsigned int subs_mask;
+ unsigned int rev;
+ const char *name;
+ int (*patch)(struct hda_codec *codec);
+ };
+
+When the codec id and codec subsystem id match with the given id and
+subs fields bitwise (with bitmask mask and subs_mask), the callback
+patch is called. The patch callback should initialize the codec and
+set the codec->patch_ops field. This is defined as below:
+
+ struct hda_codec_ops {
+ int (*build_controls)(struct hda_codec *codec);
+ int (*build_pcms)(struct hda_codec *codec);
+ int (*init)(struct hda_codec *codec);
+ void (*free)(struct hda_codec *codec);
+ void (*unsol_event)(struct hda_codec *codec, unsigned int res);
+ #ifdef CONFIG_PM
+ int (*suspend)(struct hda_codec *codec, pm_message_t state);
+ int (*resume)(struct hda_codec *codec);
+ #endif
+ };
+
+The build_controls callback is called from snd_hda_build_controls().
+Similarly, the build_pcms callback is called from
+snd_hda_build_pcms(). The init callback is called after
+build_controls to initialize the hardware.
+The free callback is called as a destructor.
+
+The unsol_event callback is called when an unsolicited event is
+received.
+
+The suspend and resume callbacks are for power management.
+
+Each entry can be NULL if not necessary to be called.
+
+
+Generic Parser
+==============
+
+When the device doesn't match with any given presets, the widgets are
+parsed via th generic parser (hda_generic.c). Its support is
+limited: no multi-channel support, for example.
+
+
+Digital I/O
+===========
+
+Call snd_hda_create_spdif_out_ctls() from the patch to create controls
+related with SPDIF out. In the patch resume callback, call
+snd_hda_resume_spdif().
+
+
+Helper Functions
+================
+
+snd_hda_get_codec_name() stores the codec name on the given string.
+
+snd_hda_check_board_config() can be used to obtain the configuration
+information matching with the device. Define the table with struct
+hda_board_config entries (zero-terminated), and pass it to the
+function. The function checks the modelname given as a module
+parameter, and PCI subsystem IDs. If the matching entry is found, it
+returns the config field value.
+
+snd_hda_add_new_ctls() can be used to create and add control entries.
+Pass the zero-terminated array of snd_kcontrol_new_t. The same array
+can be passed to snd_hda_resume_ctls() for resume.
+Note that this will call control->put callback of these entries. So,
+put callback should check codec->in_resume and force to restore the
+given value if it's non-zero even if the value is identical with the
+cached value.
+
+Macros HDA_CODEC_VOLUME(), HDA_CODEC_MUTE() and their variables can be
+used for the entry of snd_kcontrol_new_t.
+
+The input MUX helper callbacks for such a control are provided, too:
+snd_hda_input_mux_info() and snd_hda_input_mux_put(). See
+patch_realtek.c for example.
--- /dev/null
+config ICST525
+ bool
+
+config ICST307
+ bool
+
+config SA1111
+ bool
+ select DMABOUNCE
+
+config DMABOUNCE
+ bool
+
+config TIMER_ACORN
+ bool
+
+config SHARP_LOCOMO
+ bool
+
+config SHARP_PARAM
+ bool
+
+config SHARP_SCOOP
+ bool
--- /dev/null
+/*
+ * Hardware parameter area specific to Sharp SL series devices
+ *
+ * Copyright (c) 2005 Richard Purdie
+ *
+ * Based on Sharp's 2.4 kernel patches
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <asm/mach/sharpsl_param.h>
+
+/*
+ * Certain hardware parameters determined at the time of device manufacture,
+ * typically including LCD parameters are loaded by the bootloader at the
+ * address PARAM_BASE. As the kernel will overwrite them, we need to store
+ * them early in the boot process, then pass them to the appropriate drivers.
+ * Not all devices use all paramaters but the format is common to all.
+ */
+#ifdef ARCH_SA1100
+#define PARAM_BASE 0xe8ffc000
+#else
+#define PARAM_BASE 0xa0000a00
+#endif
+#define MAGIC_CHG(a,b,c,d) ( ( d << 24 ) | ( c << 16 ) | ( b << 8 ) | a )
+
+#define COMADJ_MAGIC MAGIC_CHG('C','M','A','D')
+#define UUID_MAGIC MAGIC_CHG('U','U','I','D')
+#define TOUCH_MAGIC MAGIC_CHG('T','U','C','H')
+#define AD_MAGIC MAGIC_CHG('B','V','A','D')
+#define PHAD_MAGIC MAGIC_CHG('P','H','A','D')
+
+struct sharpsl_param_info sharpsl_param;
+
+void sharpsl_save_param(void)
+{
+ memcpy(&sharpsl_param, (void *)PARAM_BASE, sizeof(struct sharpsl_param_info));
+
+ if (sharpsl_param.comadj_keyword != COMADJ_MAGIC)
+ sharpsl_param.comadj=-1;
+
+ if (sharpsl_param.phad_keyword != PHAD_MAGIC)
+ sharpsl_param.phadadj=-1;
+
+ if (sharpsl_param.uuid_keyword != UUID_MAGIC)
+ sharpsl_param.uuid[0]=-1;
+
+ if (sharpsl_param.touch_keyword != TOUCH_MAGIC)
+ sharpsl_param.touch_xp=-1;
+
+ if (sharpsl_param.adadj_keyword != AD_MAGIC)
+ sharpsl_param.adadj=-1;
+}
+
+
--- /dev/null
+/*
+ * The ARM LDRD and Thumb LDRSB instructions use bit 20/11 (ARM/Thumb)
+ * differently than every other instruction, so it is set to 0 (write)
+ * even though the instructions are read instructions. This means that
+ * during an abort the instructions will be treated as a write and the
+ * handler will raise a signal from unwriteable locations if they
+ * fault. We have to specifically check for these instructions
+ * from the abort handlers to treat them properly.
+ *
+ */
+
+ .macro do_thumb_abort
+ tst r3, #PSR_T_BIT
+ beq not_thumb
+ ldrh r3, [r2] @ Read aborted Thumb instruction
+ and r3, r3, # 0xfe00 @ Mask opcode field
+ cmp r3, # 0x5600 @ Is it ldrsb?
+ orreq r3, r3, #1 << 11 @ Set L-bit if yes
+ tst r3, #1 << 11 @ L = 0 -> write
+ orreq r1, r1, #1 << 11 @ yes.
+ mov pc, lr
+not_thumb:
+ .endm
+
+/*
+ * We check for the following insturction encoding for LDRD.
+ *
+ * [27:25] == 0
+ * [7:4] == 1101
+ * [20] == 0
+ */
+ .macro do_ldrd_abort
+ tst r3, #0x0e000000 @ [27:25] == 0
+ bne not_ldrd
+ and r2, r3, #0x000000f0 @ [7:4] == 1101
+ cmp r2, #0x000000d0
+ bne not_ldrd
+ tst r3, #1 << 20 @ [20] == 0
+ moveq pc, lr
+not_ldrd:
+ .endm
+
--- /dev/null
+menu "Kernel hacking"
+
+source "lib/Kconfig.debug"
+
+config EARLY_PRINTK
+ bool "Early printk"
+ depends on EMBEDDED && DEBUG_KERNEL
+ default n
+ help
+ Write kernel log output directly into the VGA buffer or to a serial
+ port.
+
+ This is useful for kernel debugging when your machine crashes very
+ early before the console code is initialized. For normal operation
+ it is not recommended because it looks ugly and doesn't cooperate
+ with klogd/syslogd or the X server. You should normally N here,
+ unless you want to debug such a crash.
+
+config DEBUG_STACKOVERFLOW
+ bool "Check for stack overflows"
+ depends on DEBUG_KERNEL
+
+config DEBUG_PAGEALLOC
+ bool "Page alloc debugging"
+ depends on DEBUG_KERNEL
+ help
+ Unmap pages from the kernel linear mapping after free_pages().
+ This results in a large slowdown, but helps to find certain types
+ of memory corruptions.
+
+config GDBSTUB
+ bool "Remote GDB kernel debugging"
+ depends on DEBUG_KERNEL
+ select DEBUG_INFO
+ select FRAME_POINTER
+ help
+ If you say Y here, it will be possible to remotely debug the kernel
+ using gdb. This enlarges your kernel ELF image disk size by several
+ megabytes and requires a machine with more than 16 MB, better 32 MB
+ RAM to avoid excessive linking time. This is only useful for kernel
+ hackers. If unsure, say N.
+
+choice
+ prompt "GDB stub port"
+ default GDBSTUB_UART1
+ depends on GDBSTUB
+ help
+ Select the on-CPU port used for GDB-stub
+
+config GDBSTUB_UART0
+ bool "/dev/ttyS0"
+
+config GDBSTUB_UART1
+ bool "/dev/ttyS1"
+
+endchoice
+
+config GDBSTUB_IMMEDIATE
+ bool "Break into GDB stub immediately"
+ depends on GDBSTUB
+ help
+ If you say Y here, GDB stub will break into the program as soon as
+ possible, leaving the program counter at the beginning of
+ start_kernel() in init/main.c.
+
+config GDB_CONSOLE
+ bool "Console output to GDB"
+ depends on GDBSTUB
+ help
+ If you are using GDB for remote debugging over a serial port and
+ would like kernel messages to be formatted into GDB $O packets so
+ that GDB prints them as program output, say 'Y'.
+
+endmenu
--- /dev/null
+.data
+ENTRY(sys_call_table)
+ .long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */
+ .long sys_exit
+ .long sys_fork
+ .long sys_read
+ .long sys_write
+ .long sys_open /* 5 */
+ .long sys_close
+ .long sys_waitpid
+ .long sys_creat
+ .long sys_link
+ .long sys_unlink /* 10 */
+ .long sys_execve
+ .long sys_chdir
+ .long sys_time
+ .long sys_mknod
+ .long sys_chmod /* 15 */
+ .long sys_lchown16
+ .long sys_ni_syscall /* old break syscall holder */
+ .long sys_stat
+ .long sys_lseek
+ .long sys_getpid /* 20 */
+ .long sys_mount
+ .long sys_oldumount
+ .long sys_setuid16
+ .long sys_getuid16
+ .long sys_stime /* 25 */
+ .long sys_ptrace
+ .long sys_alarm
+ .long sys_fstat
+ .long sys_pause
+ .long sys_utime /* 30 */
+ .long sys_ni_syscall /* old stty syscall holder */
+ .long sys_ni_syscall /* old gtty syscall holder */
+ .long sys_access
+ .long sys_nice
+ .long sys_ni_syscall /* 35 - old ftime syscall holder */
+ .long sys_sync
+ .long sys_kill
+ .long sys_rename
+ .long sys_mkdir
+ .long sys_rmdir /* 40 */
+ .long sys_dup
+ .long sys_pipe
+ .long sys_times
+ .long sys_ni_syscall /* old prof syscall holder */
+ .long sys_brk /* 45 */
+ .long sys_setgid16
+ .long sys_getgid16
+ .long sys_signal
+ .long sys_geteuid16
+ .long sys_getegid16 /* 50 */
+ .long sys_acct
+ .long sys_umount /* recycled never used phys() */
+ .long sys_ni_syscall /* old lock syscall holder */
+ .long sys_ioctl
+ .long sys_fcntl /* 55 */
+ .long sys_ni_syscall /* old mpx syscall holder */
+ .long sys_setpgid
+ .long sys_ni_syscall /* old ulimit syscall holder */
+ .long sys_olduname
+ .long sys_umask /* 60 */
+ .long sys_chroot
+ .long sys_ustat
+ .long sys_dup2
+ .long sys_getppid
+ .long sys_getpgrp /* 65 */
+ .long sys_setsid
+ .long sys_sigaction
+ .long sys_sgetmask
+ .long sys_ssetmask
+ .long sys_setreuid16 /* 70 */
+ .long sys_setregid16
+ .long sys_sigsuspend
+ .long sys_sigpending
+ .long sys_sethostname
+ .long sys_setrlimit /* 75 */
+ .long sys_old_getrlimit
+ .long sys_getrusage
+ .long sys_gettimeofday
+ .long sys_settimeofday
+ .long sys_getgroups16 /* 80 */
+ .long sys_setgroups16
+ .long old_select
+ .long sys_symlink
+ .long sys_lstat
+ .long sys_readlink /* 85 */
+ .long sys_uselib
+ .long sys_swapon
+ .long sys_reboot
+ .long old_readdir
+ .long old_mmap /* 90 */
+ .long sys_munmap
+ .long sys_truncate
+ .long sys_ftruncate
+ .long sys_fchmod
+ .long sys_fchown16 /* 95 */
+ .long sys_getpriority
+ .long sys_setpriority
+ .long sys_ni_syscall /* old profil syscall holder */
+ .long sys_statfs
+ .long sys_fstatfs /* 100 */
+ .long sys_ioperm
+ .long sys_socketcall
+ .long sys_syslog
+ .long sys_setitimer
+ .long sys_getitimer /* 105 */
+ .long sys_newstat
+ .long sys_newlstat
+ .long sys_newfstat
+ .long sys_uname
+ .long sys_iopl /* 110 */
+ .long sys_vhangup
+ .long sys_ni_syscall /* old "idle" system call */
+ .long sys_vm86old
+ .long sys_wait4
+ .long sys_swapoff /* 115 */
+ .long sys_sysinfo
+ .long sys_ipc
+ .long sys_fsync
+ .long sys_sigreturn
+ .long sys_clone /* 120 */
+ .long sys_setdomainname
+ .long sys_newuname
+ .long sys_modify_ldt
+ .long sys_adjtimex
+ .long sys_mprotect /* 125 */
+ .long sys_sigprocmask
+ .long sys_ni_syscall /* old "create_module" */
+ .long sys_init_module
+ .long sys_delete_module
+ .long sys_ni_syscall /* 130: old "get_kernel_syms" */
+ .long sys_quotactl
+ .long sys_getpgid
+ .long sys_fchdir
+ .long sys_bdflush
+ .long sys_sysfs /* 135 */
+ .long sys_personality
+ .long sys_ni_syscall /* reserved for afs_syscall */
+ .long sys_setfsuid16
+ .long sys_setfsgid16
+ .long sys_llseek /* 140 */
+ .long sys_getdents
+ .long sys_select
+ .long sys_flock
+ .long sys_msync
+ .long sys_readv /* 145 */
+ .long sys_writev
+ .long sys_getsid
+ .long sys_fdatasync
+ .long sys_sysctl
+ .long sys_mlock /* 150 */
+ .long sys_munlock
+ .long sys_mlockall
+ .long sys_munlockall
+ .long sys_sched_setparam
+ .long sys_sched_getparam /* 155 */
+ .long sys_sched_setscheduler
+ .long sys_sched_getscheduler
+ .long sys_sched_yield
+ .long sys_sched_get_priority_max
+ .long sys_sched_get_priority_min /* 160 */
+ .long sys_sched_rr_get_interval
+ .long sys_nanosleep
+ .long sys_mremap
+ .long sys_setresuid16
+ .long sys_getresuid16 /* 165 */
+ .long sys_vm86
+ .long sys_ni_syscall /* Old sys_query_module */
+ .long sys_poll
+ .long sys_nfsservctl
+ .long sys_setresgid16 /* 170 */
+ .long sys_getresgid16
+ .long sys_prctl
+ .long sys_rt_sigreturn
+ .long sys_rt_sigaction
+ .long sys_rt_sigprocmask /* 175 */
+ .long sys_rt_sigpending
+ .long sys_rt_sigtimedwait
+ .long sys_rt_sigqueueinfo
+ .long sys_rt_sigsuspend
+ .long sys_pread64 /* 180 */
+ .long sys_pwrite64
+ .long sys_chown16
+ .long sys_getcwd
+ .long sys_capget
+ .long sys_capset /* 185 */
+ .long sys_sigaltstack
+ .long sys_sendfile
+ .long sys_ni_syscall /* reserved for streams1 */
+ .long sys_ni_syscall /* reserved for streams2 */
+ .long sys_vfork /* 190 */
+ .long sys_getrlimit
+ .long sys_mmap2
+ .long sys_truncate64
+ .long sys_ftruncate64
+ .long sys_stat64 /* 195 */
+ .long sys_lstat64
+ .long sys_fstat64
+ .long sys_lchown
+ .long sys_getuid
+ .long sys_getgid /* 200 */
+ .long sys_geteuid
+ .long sys_getegid
+ .long sys_setreuid
+ .long sys_setregid
+ .long sys_getgroups /* 205 */
+ .long sys_setgroups
+ .long sys_fchown
+ .long sys_setresuid
+ .long sys_getresuid
+ .long sys_setresgid /* 210 */
+ .long sys_getresgid
+ .long sys_chown
+ .long sys_setuid
+ .long sys_setgid
+ .long sys_setfsuid /* 215 */
+ .long sys_setfsgid
+ .long sys_pivot_root
+ .long sys_mincore
+ .long sys_madvise
+ .long sys_getdents64 /* 220 */
+ .long sys_fcntl64
+#ifdef CONFIG_TUX
+ .long __sys_tux
+#else
+# ifdef CONFIG_TUX_MODULE
+ .long sys_tux
+# else
+ .long sys_ni_syscall
+# endif
+#endif
+ .long sys_ni_syscall
+ .long sys_gettid
+ .long sys_readahead /* 225 */
+ .long sys_setxattr
+ .long sys_lsetxattr
+ .long sys_fsetxattr
+ .long sys_getxattr
+ .long sys_lgetxattr /* 230 */
+ .long sys_fgetxattr
+ .long sys_listxattr
+ .long sys_llistxattr
+ .long sys_flistxattr
+ .long sys_removexattr /* 235 */
+ .long sys_lremovexattr
+ .long sys_fremovexattr
+ .long sys_tkill
+ .long sys_sendfile64
+ .long sys_futex /* 240 */
+ .long sys_sched_setaffinity
+ .long sys_sched_getaffinity
+ .long sys_set_thread_area
+ .long sys_get_thread_area
+ .long sys_io_setup /* 245 */
+ .long sys_io_destroy
+ .long sys_io_getevents
+ .long sys_io_submit
+ .long sys_io_cancel
+ .long sys_fadvise64 /* 250 */
+ .long sys_ni_syscall
+ .long sys_exit_group
+ .long sys_lookup_dcookie
+ .long sys_epoll_create
+ .long sys_epoll_ctl /* 255 */
+ .long sys_epoll_wait
+ .long sys_remap_file_pages
+ .long sys_set_tid_address
+ .long sys_timer_create
+ .long sys_timer_settime /* 260 */
+ .long sys_timer_gettime
+ .long sys_timer_getoverrun
+ .long sys_timer_delete
+ .long sys_clock_settime
+ .long sys_clock_gettime /* 265 */
+ .long sys_clock_getres
+ .long sys_clock_nanosleep
+ .long sys_statfs64
+ .long sys_fstatfs64
+ .long sys_tgkill /* 270 */
+ .long sys_utimes
+ .long sys_fadvise64_64
+ .long sys_ni_syscall /* sys_vserver */
+ .long sys_mbind
+ .long sys_get_mempolicy
+ .long sys_set_mempolicy
+ .long sys_mq_open
+ .long sys_mq_unlink
+ .long sys_mq_timedsend
+ .long sys_mq_timedreceive /* 280 */
+ .long sys_mq_notify
+ .long sys_mq_getsetattr
+ .long sys_ni_syscall /* reserved for kexec */
+ .long sys_waitid
+ .long sys_ni_syscall /* 285 */ /* available */
+ .long sys_add_key
+ .long sys_request_key
+ .long sys_keyctl
--- /dev/null
+/*
+ * This supplies .note.* sections to go into the PT_NOTE inside the vDSO text.
+ * Here we can supply some information useful to userland.
+ */
+
+#include <linux/uts.h>
+#include <linux/version.h>
+
+#define ASM_ELF_NOTE_BEGIN(name, flags, vendor, type) \
+ .section name, flags; \
+ .balign 4; \
+ .long 1f - 0f; /* name length */ \
+ .long 3f - 2f; /* data length */ \
+ .long type; /* note type */ \
+0: .asciz vendor; /* vendor name */ \
+1: .balign 4; \
+2:
+
+#define ASM_ELF_NOTE_END \
+3: .balign 4; /* pad out section */ \
+ .previous
+
+ ASM_ELF_NOTE_BEGIN(".note.kernel-version", "a", UTS_SYSNAME, 0)
+ .long LINUX_VERSION_CODE
+ ASM_ELF_NOTE_END
--- /dev/null
+/*
+ * __put_user functions.
+ *
+ * (C) Copyright 2005 Linus Torvalds
+ *
+ * These functions have a non-standard call interface
+ * to make them more efficient, especially as they
+ * return an error value in addition to the "real"
+ * return value.
+ */
+#include <asm/thread_info.h>
+
+
+/*
+ * __put_user_X
+ *
+ * Inputs: %eax[:%edx] contains the data
+ * %ecx contains the address
+ *
+ * Outputs: %eax is error code (0 or -EFAULT)
+ *
+ * These functions should not modify any other registers,
+ * as they get called from within inline assembly.
+ */
+
+#define ENTER pushl %ebx ; GET_THREAD_INFO(%ebx)
+#define EXIT popl %ebx ; ret
+
+.text
+.align 4
+.globl __put_user_1
+__put_user_1:
+ ENTER
+ cmpl TI_addr_limit(%ebx),%ecx
+ jae bad_put_user
+1: movb %al,(%ecx)
+ xorl %eax,%eax
+ EXIT
+
+.align 4
+.globl __put_user_2
+__put_user_2:
+ ENTER
+ movl TI_addr_limit(%ebx),%ebx
+ subl $1,%ebx
+ cmpl %ebx,%ecx
+ jae bad_put_user
+2: movw %ax,(%ecx)
+ xorl %eax,%eax
+ EXIT
+
+.align 4
+.globl __put_user_4
+__put_user_4:
+ ENTER
+ movl TI_addr_limit(%ebx),%ebx
+ subl $3,%ebx
+ cmpl %ebx,%ecx
+ jae bad_put_user
+3: movl %eax,(%ecx)
+ xorl %eax,%eax
+ EXIT
+
+.align 4
+.globl __put_user_8
+__put_user_8:
+ ENTER
+ movl TI_addr_limit(%ebx),%ebx
+ subl $7,%ebx
+ cmpl %ebx,%ecx
+ jae bad_put_user
+4: movl %eax,(%ecx)
+5: movl %edx,4(%ecx)
+ xorl %eax,%eax
+ EXIT
+
+bad_put_user:
+ movl $-14,%eax
+ EXIT
+
+.section __ex_table,"a"
+ .long 1b,bad_put_user
+ .long 2b,bad_put_user
+ .long 3b,bad_put_user
+ .long 4b,bad_put_user
+ .long 5b,bad_put_user
+.previous
--- /dev/null
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (c) 2004-2005 Silicon Graphics, Inc. All Rights Reserved.
+ */
+
+
+/*
+ * Cross Partition (XP) base.
+ *
+ * XP provides a base from which its users can interact
+ * with XPC, yet not be dependent on XPC.
+ *
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <asm/sn/intr.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/xp.h>
+
+
+/*
+ * Target of nofault PIO read.
+ */
+u64 xp_nofault_PIOR_target;
+
+
+/*
+ * xpc_registrations[] keeps track of xpc_connect()'s done by the kernel-level
+ * users of XPC.
+ */
+struct xpc_registration xpc_registrations[XPC_NCHANNELS];
+
+
+/*
+ * Initialize the XPC interface to indicate that XPC isn't loaded.
+ */
+static enum xpc_retval xpc_notloaded(void) { return xpcNotLoaded; }
+
+struct xpc_interface xpc_interface = {
+ (void (*)(int)) xpc_notloaded,
+ (void (*)(int)) xpc_notloaded,
+ (enum xpc_retval (*)(partid_t, int, u32, void **)) xpc_notloaded,
+ (enum xpc_retval (*)(partid_t, int, void *)) xpc_notloaded,
+ (enum xpc_retval (*)(partid_t, int, void *, xpc_notify_func, void *))
+ xpc_notloaded,
+ (void (*)(partid_t, int, void *)) xpc_notloaded,
+ (enum xpc_retval (*)(partid_t, void *)) xpc_notloaded
+};
+
+
+/*
+ * XPC calls this when it (the XPC module) has been loaded.
+ */
+void
+xpc_set_interface(void (*connect)(int),
+ void (*disconnect)(int),
+ enum xpc_retval (*allocate)(partid_t, int, u32, void **),
+ enum xpc_retval (*send)(partid_t, int, void *),
+ enum xpc_retval (*send_notify)(partid_t, int, void *,
+ xpc_notify_func, void *),
+ void (*received)(partid_t, int, void *),
+ enum xpc_retval (*partid_to_nasids)(partid_t, void *))
+{
+ xpc_interface.connect = connect;
+ xpc_interface.disconnect = disconnect;
+ xpc_interface.allocate = allocate;
+ xpc_interface.send = send;
+ xpc_interface.send_notify = send_notify;
+ xpc_interface.received = received;
+ xpc_interface.partid_to_nasids = partid_to_nasids;
+}
+
+
+/*
+ * XPC calls this when it (the XPC module) is being unloaded.
+ */
+void
+xpc_clear_interface(void)
+{
+ xpc_interface.connect = (void (*)(int)) xpc_notloaded;
+ xpc_interface.disconnect = (void (*)(int)) xpc_notloaded;
+ xpc_interface.allocate = (enum xpc_retval (*)(partid_t, int, u32,
+ void **)) xpc_notloaded;
+ xpc_interface.send = (enum xpc_retval (*)(partid_t, int, void *))
+ xpc_notloaded;
+ xpc_interface.send_notify = (enum xpc_retval (*)(partid_t, int, void *,
+ xpc_notify_func, void *)) xpc_notloaded;
+ xpc_interface.received = (void (*)(partid_t, int, void *))
+ xpc_notloaded;
+ xpc_interface.partid_to_nasids = (enum xpc_retval (*)(partid_t, void *))
+ xpc_notloaded;
+}
+
+
+/*
+ * Register for automatic establishment of a channel connection whenever
+ * a partition comes up.
+ *
+ * Arguments:
+ *
+ * ch_number - channel # to register for connection.
+ * func - function to call for asynchronous notification of channel
+ * state changes (i.e., connection, disconnection, error) and
+ * the arrival of incoming messages.
+ * key - pointer to optional user-defined value that gets passed back
+ * to the user on any callouts made to func.
+ * payload_size - size in bytes of the XPC message's payload area which
+ * contains a user-defined message. The user should make
+ * this large enough to hold their largest message.
+ * nentries - max #of XPC message entries a message queue can contain.
+ * The actual number, which is determined when a connection
+ * is established and may be less then requested, will be
+ * passed to the user via the xpcConnected callout.
+ * assigned_limit - max number of kthreads allowed to be processing
+ * messages (per connection) at any given instant.
+ * idle_limit - max number of kthreads allowed to be idle at any given
+ * instant.
+ */
+enum xpc_retval
+xpc_connect(int ch_number, xpc_channel_func func, void *key, u16 payload_size,
+ u16 nentries, u32 assigned_limit, u32 idle_limit)
+{
+ struct xpc_registration *registration;
+
+
+ DBUG_ON(ch_number < 0 || ch_number >= XPC_NCHANNELS);
+ DBUG_ON(payload_size == 0 || nentries == 0);
+ DBUG_ON(func == NULL);
+ DBUG_ON(assigned_limit == 0 || idle_limit > assigned_limit);
+
+ registration = &xpc_registrations[ch_number];
+
+ if (down_interruptible(®istration->sema) != 0) {
+ return xpcInterrupted;
+ }
+
+ /* if XPC_CHANNEL_REGISTERED(ch_number) */
+ if (registration->func != NULL) {
+ up(®istration->sema);
+ return xpcAlreadyRegistered;
+ }
+
+ /* register the channel for connection */
+ registration->msg_size = XPC_MSG_SIZE(payload_size);
+ registration->nentries = nentries;
+ registration->assigned_limit = assigned_limit;
+ registration->idle_limit = idle_limit;
+ registration->key = key;
+ registration->func = func;
+
+ up(®istration->sema);
+
+ xpc_interface.connect(ch_number);
+
+ return xpcSuccess;
+}
+
+
+/*
+ * Remove the registration for automatic connection of the specified channel
+ * when a partition comes up.
+ *
+ * Before returning this xpc_disconnect() will wait for all connections on the
+ * specified channel have been closed/torndown. So the caller can be assured
+ * that they will not be receiving any more callouts from XPC to their
+ * function registered via xpc_connect().
+ *
+ * Arguments:
+ *
+ * ch_number - channel # to unregister.
+ */
+void
+xpc_disconnect(int ch_number)
+{
+ struct xpc_registration *registration;
+
+
+ DBUG_ON(ch_number < 0 || ch_number >= XPC_NCHANNELS);
+
+ registration = &xpc_registrations[ch_number];
+
+ /*
+ * We've decided not to make this a down_interruptible(), since we
+ * figured XPC's users will just turn around and call xpc_disconnect()
+ * again anyways, so we might as well wait, if need be.
+ */
+ down(®istration->sema);
+
+ /* if !XPC_CHANNEL_REGISTERED(ch_number) */
+ if (registration->func == NULL) {
+ up(®istration->sema);
+ return;
+ }
+
+ /* remove the connection registration for the specified channel */
+ registration->func = NULL;
+ registration->key = NULL;
+ registration->nentries = 0;
+ registration->msg_size = 0;
+ registration->assigned_limit = 0;
+ registration->idle_limit = 0;
+
+ xpc_interface.disconnect(ch_number);
+
+ up(®istration->sema);
+
+ return;
+}
+
+
+int __init
+xp_init(void)
+{
+ int ret, ch_number;
+ u64 func_addr = *(u64 *) xp_nofault_PIOR;
+ u64 err_func_addr = *(u64 *) xp_error_PIOR;
+
+
+ if (!ia64_platform_is("sn2")) {
+ return -ENODEV;
+ }
+
+ /*
+ * Register a nofault code region which performs a cross-partition
+ * PIO read. If the PIO read times out, the MCA handler will consume
+ * the error and return to a kernel-provided instruction to indicate
+ * an error. This PIO read exists because it is guaranteed to timeout
+ * if the destination is down (AMO operations do not timeout on at
+ * least some CPUs on Shubs <= v1.2, which unfortunately we have to
+ * work around).
+ */
+ if ((ret = sn_register_nofault_code(func_addr, err_func_addr,
+ err_func_addr, 1, 1)) != 0) {
+ printk(KERN_ERR "XP: can't register nofault code, error=%d\n",
+ ret);
+ }
+ /*
+ * Setup the nofault PIO read target. (There is no special reason why
+ * SH_IPI_ACCESS was selected.)
+ */
+ if (is_shub2()) {
+ xp_nofault_PIOR_target = SH2_IPI_ACCESS0;
+ } else {
+ xp_nofault_PIOR_target = SH1_IPI_ACCESS;
+ }
+
+ /* initialize the connection registration semaphores */
+ for (ch_number = 0; ch_number < XPC_NCHANNELS; ch_number++) {
+ sema_init(&xpc_registrations[ch_number].sema, 1); /* mutex */
+ }
+
+ return 0;
+}
+module_init(xp_init);
+
+
+void __exit
+xp_exit(void)
+{
+ u64 func_addr = *(u64 *) xp_nofault_PIOR;
+ u64 err_func_addr = *(u64 *) xp_error_PIOR;
+
+
+ /* unregister the PIO read nofault code region */
+ (void) sn_register_nofault_code(func_addr, err_func_addr,
+ err_func_addr, 1, 0);
+}
+module_exit(xp_exit);
+
+
+MODULE_AUTHOR("Silicon Graphics, Inc.");
+MODULE_DESCRIPTION("Cross Partition (XP) base");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(xp_nofault_PIOR);
+EXPORT_SYMBOL(xp_nofault_PIOR_target);
+EXPORT_SYMBOL(xpc_registrations);
+EXPORT_SYMBOL(xpc_interface);
+EXPORT_SYMBOL(xpc_clear_interface);
+EXPORT_SYMBOL(xpc_set_interface);
+EXPORT_SYMBOL(xpc_connect);
+EXPORT_SYMBOL(xpc_disconnect);
+
--- /dev/null
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (c) 2004-2005 Silicon Graphics, Inc. All Rights Reserved.
+ */
+
+
+/*
+ * The xp_nofault_PIOR function takes a pointer to a remote PIO register
+ * and attempts to load and consume a value from it. This function
+ * will be registered as a nofault code block. In the event that the
+ * PIO read fails, the MCA handler will force the error to look
+ * corrected and vector to the xp_error_PIOR which will return an error.
+ *
+ * extern int xp_nofault_PIOR(void *remote_register);
+ */
+
+ .global xp_nofault_PIOR
+xp_nofault_PIOR:
+ mov r8=r0 // Stage a success return value
+ ld8.acq r9=[r32];; // PIO Read the specified register
+ adds r9=1,r9 // Add to force a consume
+ br.ret.sptk.many b0;; // Return success
+
+ .global xp_error_PIOR
+xp_error_PIOR:
+ mov r8=1 // Return value of 1
+ br.ret.sptk.many b0;; // Return failure
+
--- /dev/null
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.11
+# Wed Mar 16 12:43:19 2005
+#
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_HAVE_DEC_LOCK=y
+CONFIG_PPC=y
+CONFIG_PPC32=y
+CONFIG_GENERIC_NVRAM=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_LOCK_KERNEL=y
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_HOTPLUG=y
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+# CONFIG_CPUSETS is not set
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+CONFIG_STOP_MACHINE=y
+
+#
+# Processor
+#
+CONFIG_6xx=y
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8xx is not set
+# CONFIG_E500 is not set
+CONFIG_ALTIVEC=y
+# CONFIG_TAU is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_PM is not set
+CONFIG_PPC_STD_MMU=y
+# CONFIG_NOT_COHERENT_CACHE is not set
+
+#
+# Platform options
+#
+# CONFIG_PPC_MULTIPLATFORM is not set
+# CONFIG_APUS is not set
+# CONFIG_KATANA is not set
+# CONFIG_WILLOW is not set
+# CONFIG_CPCI690 is not set
+# CONFIG_PCORE is not set
+# CONFIG_POWERPMC250 is not set
+# CONFIG_CHESTNUT is not set
+# CONFIG_SPRUCE is not set
+CONFIG_HDPU=y
+# CONFIG_EV64260 is not set
+# CONFIG_LOPEC is not set
+# CONFIG_MCPN765 is not set
+# CONFIG_MVME5100 is not set
+# CONFIG_PPLUS is not set
+# CONFIG_PRPMC750 is not set
+# CONFIG_PRPMC800 is not set
+# CONFIG_SANDPOINT is not set
+# CONFIG_RADSTONE_PPC7D is not set
+# CONFIG_ADIR is not set
+# CONFIG_K2 is not set
+# CONFIG_PAL4 is not set
+# CONFIG_GEMINI is not set
+# CONFIG_EST8260 is not set
+# CONFIG_SBC82xx is not set
+# CONFIG_SBS8260 is not set
+# CONFIG_RPX8260 is not set
+# CONFIG_TQM8260 is not set
+# CONFIG_ADS8272 is not set
+# CONFIG_PQ2FADS is not set
+# CONFIG_LITE5200 is not set
+# CONFIG_MPC834x_SYS is not set
+CONFIG_MV64360=y
+CONFIG_MV64X60=y
+
+#
+# Set bridge options
+#
+CONFIG_MV64X60_BASE=0xf1000000
+CONFIG_MV64X60_NEW_BASE=0xf1000000
+# CONFIG_SMP is not set
+# CONFIG_IRQ_ALL_CPUS is not set
+# CONFIG_NR_CPUS is not set
+CONFIG_PREEMPT=y
+CONFIG_HIGHMEM=y
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="root=/dev/nfs ip=auto"
+
+#
+# Bus options
+#
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_LEGACY_PROC=y
+CONFIG_PCI_NAMES=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Advanced setup
+#
+CONFIG_ADVANCED_OPTIONS=y
+# CONFIG_HIGHMEM_START_BOOL is not set
+CONFIG_HIGHMEM_START=0xfe000000
+# CONFIG_LOWMEM_SIZE_BOOL is not set
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START_BOOL=y
+CONFIG_KERNEL_START=0x80000000
+# CONFIG_TASK_SIZE_BOOL is not set
+CONFIG_TASK_SIZE=0x80000000
+# CONFIG_BOOT_LOAD_BOOL is not set
+CONFIG_BOOT_LOAD=0x00800000
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+# CONFIG_MTD_BLOCK is not set
+# CONFIG_MTD_BLOCK_RO is not set
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_START=0xfc000000
+CONFIG_MTD_PHYSMAP_LEN=0x04000000
+CONFIG_MTD_PHYSMAP_BANKWIDTH=4
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_LBD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=y
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_CHR_DEV_SG=y
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+CONFIG_SCSI_AIC7XXX=y
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=32
+CONFIG_AIC7XXX_RESET_DELAY_MS=15000
+# CONFIG_AIC7XXX_DEBUG_ENABLE is not set
+CONFIG_AIC7XXX_DEBUG_MASK=0
+# CONFIG_AIC7XXX_REG_PRETTY_PRINT is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+CONFIG_SCSI_QLA2XXX=y
+# CONFIG_SCSI_QLA21XX is not set
+# CONFIG_SCSI_QLA22XX is not set
+# CONFIG_SCSI_QLA2300 is not set
+# CONFIG_SCSI_QLA2322 is not set
+# CONFIG_SCSI_QLA6312 is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Macintosh device drivers
+#
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+# CONFIG_NETLINK_DEV is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_IP_TCPDIAG is not set
+# CONFIG_IP_TCPDIAG_IPV6 is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_PCI is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+CONFIG_MV643XX_ETH=y
+CONFIG_MV643XX_ETH_0=y
+# CONFIG_MV643XX_ETH_1 is not set
+# CONFIG_MV643XX_ETH_2 is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_MPSC=y
+CONFIG_SERIAL_MPSC_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+CONFIG_GEN_RTC=y
+# CONFIG_GEN_RTC_X is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+
+#
+# XFS support
+#
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+CONFIG_UDF_FS=y
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_FS_NOR_ECC is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_DIRECTIO=y
+CONFIG_NFSD=y
+CONFIG_NFSD_V3=y
+CONFIG_NFSD_V4=y
+CONFIG_NFSD_TCP=y
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=15
+# CONFIG_SERIAL_TEXT_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
--- /dev/null
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.11-rc4
+# Thu Feb 17 16:12:23 2005
+#
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_HAVE_DEC_LOCK=y
+CONFIG_PPC=y
+CONFIG_PPC32=y
+CONFIG_GENERIC_NVRAM=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+CONFIG_FUTEX=y
+# CONFIG_EPOLL is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# Processor
+#
+CONFIG_6xx=y
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8xx is not set
+# CONFIG_E500 is not set
+# CONFIG_CPU_FREQ is not set
+CONFIG_PPC_GEN550=y
+CONFIG_83xx=y
+
+#
+# Freescale 83xx options
+#
+CONFIG_MPC834x_SYS=y
+CONFIG_MPC834x=y
+CONFIG_PPC_STD_MMU=y
+
+#
+# Platform options
+#
+# CONFIG_SMP is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_CMDLINE_BOOL is not set
+
+#
+# Bus options
+#
+CONFIG_GENERIC_ISA_DMA=y
+# CONFIG_PCI is not set
+# CONFIG_PCI_DOMAINS is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PC-card bridges
+#
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_BOOT_LOAD=0x00800000
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=32768
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_LBD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Macintosh device drivers
+#
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+# CONFIG_NETLINK_DEV is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+
+#
+# Ethernet (1000 Mbit)
+#
+CONFIG_GIANFAR=y
+# CONFIG_GFAR_NAPI is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+# CONFIG_SERIO is not set
+# CONFIG_SERIO_I8042 is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+CONFIG_GEN_RTC=y
+# CONFIG_GEN_RTC_X is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ISA is not set
+CONFIG_I2C_MPC=y
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Hardware Sensors Chip support
+#
+# CONFIG_I2C_SENSOR is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+
+#
+# Other I2C Chip support
+#
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+# CONFIG_MSDOS_PARTITION is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_SERIAL_TEXT_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
--- /dev/null
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.11
+# Tue Mar 15 14:31:19 2005
+#
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_HAVE_DEC_LOCK=y
+CONFIG_PPC=y
+CONFIG_PPC32=y
+CONFIG_GENERIC_NVRAM=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Processor
+#
+CONFIG_6xx=y
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8xx is not set
+# CONFIG_E500 is not set
+CONFIG_ALTIVEC=y
+# CONFIG_TAU is not set
+# CONFIG_CPU_FREQ is not set
+CONFIG_PPC_GEN550=y
+# CONFIG_PM is not set
+CONFIG_PPC_STD_MMU=y
+# CONFIG_NOT_COHERENT_CACHE is not set
+
+#
+# Platform options
+#
+# CONFIG_PPC_MULTIPLATFORM is not set
+# CONFIG_APUS is not set
+# CONFIG_KATANA is not set
+# CONFIG_WILLOW is not set
+# CONFIG_CPCI690 is not set
+# CONFIG_PCORE is not set
+# CONFIG_POWERPMC250 is not set
+# CONFIG_CHESTNUT is not set
+# CONFIG_SPRUCE is not set
+# CONFIG_EV64260 is not set
+# CONFIG_LOPEC is not set
+# CONFIG_MCPN765 is not set
+# CONFIG_MVME5100 is not set
+# CONFIG_PPLUS is not set
+# CONFIG_PRPMC750 is not set
+# CONFIG_PRPMC800 is not set
+# CONFIG_SANDPOINT is not set
+CONFIG_RADSTONE_PPC7D=y
+# CONFIG_ADIR is not set
+# CONFIG_K2 is not set
+# CONFIG_PAL4 is not set
+# CONFIG_GEMINI is not set
+# CONFIG_EST8260 is not set
+# CONFIG_SBC82xx is not set
+# CONFIG_SBS8260 is not set
+# CONFIG_RPX8260 is not set
+# CONFIG_TQM8260 is not set
+# CONFIG_ADS8272 is not set
+# CONFIG_PQ2FADS is not set
+# CONFIG_LITE5200 is not set
+# CONFIG_MPC834x_SYS is not set
+CONFIG_MV64360=y
+CONFIG_MV64X60=y
+
+#
+# Set bridge options
+#
+CONFIG_MV64X60_BASE=0xfef00000
+CONFIG_MV64X60_NEW_BASE=0xfef00000
+# CONFIG_SMP is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttyS0,9600"
+
+#
+# Bus options
+#
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_LEGACY_PROC=y
+CONFIG_PCI_NAMES=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Advanced setup
+#
+CONFIG_ADVANCED_OPTIONS=y
+CONFIG_HIGHMEM_START=0xfe000000
+# CONFIG_LOWMEM_SIZE_BOOL is not set
+CONFIG_LOWMEM_SIZE=0x30000000
+# CONFIG_KERNEL_START_BOOL is not set
+CONFIG_KERNEL_START=0xc0000000
+# CONFIG_TASK_SIZE_BOOL is not set
+CONFIG_TASK_SIZE=0x80000000
+# CONFIG_BOOT_LOAD_BOOL is not set
+CONFIG_BOOT_LOAD=0x00800000
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_PARTITIONS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_FTL=y
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_GEOMETRY is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_XIP is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_LBD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=y
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+
+#
+# SCSI Transport Attributes
+#
+CONFIG_SCSI_SPI_ATTRS=y
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+CONFIG_SCSI_SYM53C8XX_2=y
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+CONFIG_SCSI_QLA2XXX=y
+# CONFIG_SCSI_QLA21XX is not set
+# CONFIG_SCSI_QLA22XX is not set
+# CONFIG_SCSI_QLA2300 is not set
+# CONFIG_SCSI_QLA2322 is not set
+# CONFIG_SCSI_QLA6312 is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Macintosh device drivers
+#
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+# CONFIG_NETLINK_DEV is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+CONFIG_BRIDGE=y
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+
+#
+# Tulip family network device support
+#
+CONFIG_NET_TULIP=y
+# CONFIG_DE2104X is not set
+CONFIG_TULIP=y
+# CONFIG_TULIP_MWI is not set
+# CONFIG_TULIP_MMIO is not set
+# CONFIG_TULIP_NAPI is not set
+# CONFIG_DE4X5 is not set
+# CONFIG_WINBOND_840 is not set
+# CONFIG_DM9102 is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEPRO100 is not set
+CONFIG_E100=y
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+CONFIG_R8169=y
+CONFIG_R8169_NAPI=y
+CONFIG_SK98LIN=y
+# CONFIG_VIA_VELOCITY is not set
+CONFIG_TIGON3=y
+CONFIG_MV643XX_ETH=y
+CONFIG_MV643XX_ETH_0=y
+CONFIG_MV643XX_ETH_1=y
+# CONFIG_MV643XX_ETH_2 is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+CONFIG_KEYBOARD_XTKBD=y
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
+#
+# Character devices
+#
+CONFIG_VT=y
+# CONFIG_VT_CONSOLE is not set
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_MPSC=y
+# CONFIG_SERIAL_MPSC_CONSOLE is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+# CONFIG_NVRAM is not set
+CONFIG_GEN_RTC=y
+# CONFIG_GEN_RTC_X is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_ISA is not set
+# CONFIG_I2C_MPC is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
+CONFIG_I2C_MV64XXX=y
+
+#
+# Hardware Sensors Chip support
+#
+CONFIG_I2C_SENSOR=y
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+CONFIG_SENSORS_LM90=y
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+
+#
+# Other I2C Chip support
+#
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_SENSORS_M41T00 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_FS_NOR_ECC is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=y
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_SERIAL_TEXT_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
--- /dev/null
+#
+# Makefile for the PowerPC 83xx linux kernel.
+#
+obj-$(CONFIG_MPC834x_SYS) += mpc834x_sys.o
--- /dev/null
+
+#ifndef _PPC_KERNEL_M82XX_PCI_H
+#define _PPC_KERNEL_M82XX_PCI_H
+
+#include <asm/m8260_pci.h>
+/*
+ * Local->PCI map (from CPU) controlled by
+ * MPC826x master window
+ *
+ * 0xF6000000 - 0xF7FFFFFF IO space
+ * 0x80000000 - 0xBFFFFFFF CPU2PCI memory space PCIBR0
+ *
+ * 0x80000000 - 0x9FFFFFFF PCI Mem with prefetch (Outbound ATU #1)
+ * 0xA0000000 - 0xBFFFFFFF PCI Mem w/o prefetch (Outbound ATU #2)
+ * 0xF6000000 - 0xF7FFFFFF 32-bit PCI IO (Outbound ATU #3)
+ *
+ * PCI->Local map (from PCI)
+ * MPC826x slave window controlled by
+ *
+ * 0x00000000 - 0x07FFFFFF MPC826x local memory (Inbound ATU #1)
+ */
+
+/*
+ * Slave window that allows PCI masters to access MPC826x local memory.
+ * This window is set up using the first set of Inbound ATU registers
+ */
+
+#ifndef M82xx_PCI_SLAVE_MEM_LOCAL
+#define M82xx_PCI_SLAVE_MEM_LOCAL (((struct bd_info *)__res)->bi_memstart)
+#define M82xx_PCI_SLAVE_MEM_BUS (((struct bd_info *)__res)->bi_memstart)
+#define M82xx_PCI_SLAVE_MEM_SIZE (((struct bd_info *)__res)->bi_memsize)
+#endif
+
+/*
+ * This is the window that allows the CPU to access PCI address space.
+ * It will be setup with the SIU PCIBR0 register. All three PCI master
+ * windows, which allow the CPU to access PCI prefetch, non prefetch,
+ * and IO space (see below), must all fit within this window.
+ */
+
+#ifndef M82xx_PCI_LOWER_MEM
+#define M82xx_PCI_LOWER_MEM 0x80000000
+#define M82xx_PCI_UPPER_MEM 0x9fffffff
+#define M82xx_PCI_MEM_OFFSET 0x00000000
+#define M82xx_PCI_MEM_SIZE 0x20000000
+#endif
+
+#ifndef M82xx_PCI_LOWER_MMIO
+#define M82xx_PCI_LOWER_MMIO 0xa0000000
+#define M82xx_PCI_UPPER_MMIO 0xafffffff
+#define M82xx_PCI_MMIO_OFFSET 0x00000000
+#define M82xx_PCI_MMIO_SIZE 0x20000000
+#endif
+
+#ifndef M82xx_PCI_LOWER_IO
+#define M82xx_PCI_LOWER_IO 0x00000000
+#define M82xx_PCI_UPPER_IO 0x01ffffff
+#define M82xx_PCI_IO_BASE 0xf6000000
+#define M82xx_PCI_IO_SIZE 0x02000000
+#endif
+
+#ifndef M82xx_PCI_PRIM_WND_SIZE
+#define M82xx_PCI_PRIM_WND_SIZE ~(M82xx_PCI_IO_SIZE - 1U)
+#define M82xx_PCI_PRIM_WND_BASE (M82xx_PCI_IO_BASE)
+#endif
+
+#ifndef M82xx_PCI_SEC_WND_SIZE
+#define M82xx_PCI_SEC_WND_SIZE ~(M82xx_PCI_MEM_SIZE + M82xx_PCI_MMIO_SIZE - 1U)
+#define M82xx_PCI_SEC_WND_BASE (M82xx_PCI_LOWER_MEM)
+#endif
+
+#ifndef POTA_ADDR_SHIFT
+#define POTA_ADDR_SHIFT 12
+#endif
+
+#ifndef PITA_ADDR_SHIFT
+#define PITA_ADDR_SHIFT 12
+#endif
+
+#ifndef _IO_BASE
+#define _IO_BASE isa_io_base
+#endif
+
+#ifdef CONFIG_8260_PCI9
+struct pci_controller;
+extern void setup_m8260_indirect_pci(struct pci_controller* hose,
+ u32 cfg_addr, u32 cfg_data);
+#else
+#define setup_m8260_indirect_pci setup_indirect_pci
+#endif
+
+#endif /* _PPC_KERNEL_M8260_PCI_H */
--- /dev/null
+/* Kernel module help for sh64.
+
+ 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
+
+ Copyright 2004 SuperH (UK) Ltd
+ Author: Richard Curnow
+
+ Based on the sh version, and on code from the sh64-specific parts of
+ modutils, originally written by Richard Curnow and Ben Gaster.
+
+*/
+#include <linux/moduleloader.h>
+#include <linux/elf.h>
+#include <linux/vmalloc.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(fmt...)
+#endif
+
+void *module_alloc(unsigned long size)
+{
+ if (size == 0)
+ return NULL;
+ return vmalloc(size);
+}
+
+
+/* Free memory returned from module_alloc */
+void module_free(struct module *mod, void *module_region)
+{
+ vfree(module_region);
+ /* FIXME: If module_region == mod->init_region, trim exception
+ table entries. */
+}
+
+/* We don't need anything special. */
+int module_frob_arch_sections(Elf_Ehdr *hdr,
+ Elf_Shdr *sechdrs,
+ char *secstrings,
+ struct module *mod)
+{
+ return 0;
+}
+
+int apply_relocate_add(Elf32_Shdr *sechdrs,
+ const char *strtab,
+ unsigned int symindex,
+ unsigned int relsec,
+ struct module *me)
+{
+ unsigned int i;
+ Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
+ Elf32_Sym *sym;
+ Elf32_Addr relocation;
+ uint32_t *location;
+ int align;
+ int is_shmedia;
+
+ DEBUGP("Applying relocate section %u to %u\n", relsec,
+ sechdrs[relsec].sh_info);
+ for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
+ /* This is where to make the change */
+ location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
+ + rel[i].r_offset;
+ /* This is the symbol it is referring to. Note that all
+ undefined symbols have been resolved. */
+ sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
+ + ELF32_R_SYM(rel[i].r_info);
+ relocation = sym->st_value + rel[i].r_addend;
+ align = (int)location & 3;
+
+ /* For text addresses, bit2 of the st_other field indicates
+ * whether the symbol is SHmedia (1) or SHcompact (0). If
+ * SHmedia, the LSB of the symbol needs to be asserted
+ * for the CPU to be in SHmedia mode when it starts executing
+ * the branch target. */
+ is_shmedia = (sym->st_other & 4) ? 1 : 0;
+ if (is_shmedia) {
+ relocation |= 1;
+ }
+
+ switch (ELF32_R_TYPE(rel[i].r_info)) {
+ case R_SH_DIR32:
+ DEBUGP("R_SH_DIR32 @%08lx = %08lx\n", (unsigned long) location, (unsigned long) relocation);
+ *location += relocation;
+ break;
+ case R_SH_REL32:
+ DEBUGP("R_SH_REL32 @%08lx = %08lx\n", (unsigned long) location, (unsigned long) relocation);
+ relocation -= (Elf32_Addr) location;
+ *location += relocation;
+ break;
+ case R_SH_IMM_LOW16:
+ DEBUGP("R_SH_IMM_LOW16 @%08lx = %08lx\n", (unsigned long) location, (unsigned long) relocation);
+ *location = (*location & ~0x3fffc00) |
+ ((relocation & 0xffff) << 10);
+ break;
+ case R_SH_IMM_MEDLOW16:
+ DEBUGP("R_SH_IMM_MEDLOW16 @%08lx = %08lx\n", (unsigned long) location, (unsigned long) relocation);
+ *location = (*location & ~0x3fffc00) |
+ (((relocation >> 16) & 0xffff) << 10);
+ break;
+ case R_SH_IMM_LOW16_PCREL:
+ DEBUGP("R_SH_IMM_LOW16_PCREL @%08lx = %08lx\n", (unsigned long) location, (unsigned long) relocation);
+ relocation -= (Elf32_Addr) location;
+ *location = (*location & ~0x3fffc00) |
+ ((relocation & 0xffff) << 10);
+ break;
+ case R_SH_IMM_MEDLOW16_PCREL:
+ DEBUGP("R_SH_IMM_MEDLOW16_PCREL @%08lx = %08lx\n", (unsigned long) location, (unsigned long) relocation);
+ relocation -= (Elf32_Addr) location;
+ *location = (*location & ~0x3fffc00) |
+ (((relocation >> 16) & 0xffff) << 10);
+ break;
+ default:
+ printk(KERN_ERR "module %s: Unknown relocation: %u\n",
+ me->name, ELF32_R_TYPE(rel[i].r_info));
+ return -ENOEXEC;
+ }
+ }
+ return 0;
+}
+
+int apply_relocate(Elf32_Shdr *sechdrs,
+ const char *strtab,
+ unsigned int symindex,
+ unsigned int relsec,
+ struct module *me)
+{
+ printk(KERN_ERR "module %s: REL RELOCATION unsupported\n",
+ me->name);
+ return -ENOEXEC;
+}
+
+int module_finalize(const Elf_Ehdr *hdr,
+ const Elf_Shdr *sechdrs,
+ struct module *me)
+{
+ return 0;
+}
+
+void module_arch_cleanup(struct module *mod)
+{
+}
+
--- /dev/null
+/* csum_copy.S: Checksum+copy code for sparc64
+ *
+ * Copyright (C) 2005 David S. Miller <davem@davemloft.net>
+ */
+
+#ifdef __KERNEL__
+#define GLOBAL_SPARE %g7
+#else
+#define GLOBAL_SPARE %g5
+#endif
+
+#ifndef EX_LD
+#define EX_LD(x) x
+#endif
+
+#ifndef EX_ST
+#define EX_ST(x) x
+#endif
+
+#ifndef EX_RETVAL
+#define EX_RETVAL(x) x
+#endif
+
+#ifndef LOAD
+#define LOAD(type,addr,dest) type [addr], dest
+#endif
+
+#ifndef STORE
+#define STORE(type,src,addr) type src, [addr]
+#endif
+
+#ifndef FUNC_NAME
+#define FUNC_NAME csum_partial_copy_nocheck
+#endif
+
+ .register %g2, #scratch
+ .register %g3, #scratch
+
+ .text
+
+90:
+ /* We checked for zero length already, so there must be
+ * at least one byte.
+ */
+ be,pt %icc, 1f
+ nop
+ EX_LD(LOAD(ldub, %o0 + 0x00, %o4))
+ add %o0, 1, %o0
+ sub %o2, 1, %o2
+ EX_ST(STORE(stb, %o4, %o1 + 0x00))
+ add %o1, 1, %o1
+1: andcc %o0, 0x2, %g0
+ be,pn %icc, 80f
+ cmp %o2, 2
+ blu,pn %icc, 60f
+ nop
+ EX_LD(LOAD(lduh, %o0 + 0x00, %o5))
+ add %o0, 2, %o0
+ sub %o2, 2, %o2
+ EX_ST(STORE(sth, %o5, %o1 + 0x00))
+ add %o1, 2, %o1
+ ba,pt %xcc, 80f
+ add %o5, %o4, %o4
+
+ .globl FUNC_NAME
+FUNC_NAME: /* %o0=src, %o1=dst, %o2=len, %o3=sum */
+ LOAD(prefetch, %o0 + 0x000, #n_reads)
+ xor %o0, %o1, %g1
+ clr %o4
+ andcc %g1, 0x3, %g0
+ bne,pn %icc, 95f
+ LOAD(prefetch, %o0 + 0x040, #n_reads)
+
+ brz,pn %o2, 70f
+ andcc %o0, 0x3, %g0
+
+ /* We "remember" whether the lowest bit in the address
+ * was set in GLOBAL_SPARE. Because if it is, we have to swap
+ * upper and lower 8 bit fields of the sum we calculate.
+ */
+ bne,pn %icc, 90b
+ andcc %o0, 0x1, GLOBAL_SPARE
+
+80:
+ LOAD(prefetch, %o0 + 0x080, #n_reads)
+ andncc %o2, 0x3f, %g3
+
+ LOAD(prefetch, %o0 + 0x0c0, #n_reads)
+ sub %o2, %g3, %o2
+ brz,pn %g3, 2f
+ LOAD(prefetch, %o0 + 0x100, #n_reads)
+
+ /* So that we don't need to use the non-pairing
+ * add-with-carry instructions we accumulate 32-bit
+ * values into a 64-bit register. At the end of the
+ * loop we fold it down to 32-bits and so on.
+ */
+ ba,pt %xcc, 1f
+ LOAD(prefetch, %o0 + 0x140, #n_reads)
+
+ .align 32
+1: EX_LD(LOAD(lduw, %o0 + 0x00, %o5))
+ EX_LD(LOAD(lduw, %o0 + 0x04, %g1))
+ EX_LD(LOAD(lduw, %o0 + 0x08, %g2))
+ add %o4, %o5, %o4
+ EX_ST(STORE(stw, %o5, %o1 + 0x00))
+ EX_LD(LOAD(lduw, %o0 + 0x0c, %o5))
+ add %o4, %g1, %o4
+ EX_ST(STORE(stw, %g1, %o1 + 0x04))
+ EX_LD(LOAD(lduw, %o0 + 0x10, %g1))
+ add %o4, %g2, %o4
+ EX_ST(STORE(stw, %g2, %o1 + 0x08))
+ EX_LD(LOAD(lduw, %o0 + 0x14, %g2))
+ add %o4, %o5, %o4
+ EX_ST(STORE(stw, %o5, %o1 + 0x0c))
+ EX_LD(LOAD(lduw, %o0 + 0x18, %o5))
+ add %o4, %g1, %o4
+ EX_ST(STORE(stw, %g1, %o1 + 0x10))
+ EX_LD(LOAD(lduw, %o0 + 0x1c, %g1))
+ add %o4, %g2, %o4
+ EX_ST(STORE(stw, %g2, %o1 + 0x14))
+ EX_LD(LOAD(lduw, %o0 + 0x20, %g2))
+ add %o4, %o5, %o4
+ EX_ST(STORE(stw, %o5, %o1 + 0x18))
+ EX_LD(LOAD(lduw, %o0 + 0x24, %o5))
+ add %o4, %g1, %o4
+ EX_ST(STORE(stw, %g1, %o1 + 0x1c))
+ EX_LD(LOAD(lduw, %o0 + 0x28, %g1))
+ add %o4, %g2, %o4
+ EX_ST(STORE(stw, %g2, %o1 + 0x20))
+ EX_LD(LOAD(lduw, %o0 + 0x2c, %g2))
+ add %o4, %o5, %o4
+ EX_ST(STORE(stw, %o5, %o1 + 0x24))
+ EX_LD(LOAD(lduw, %o0 + 0x30, %o5))
+ add %o4, %g1, %o4
+ EX_ST(STORE(stw, %g1, %o1 + 0x28))
+ EX_LD(LOAD(lduw, %o0 + 0x34, %g1))
+ add %o4, %g2, %o4
+ EX_ST(STORE(stw, %g2, %o1 + 0x2c))
+ EX_LD(LOAD(lduw, %o0 + 0x38, %g2))
+ add %o4, %o5, %o4
+ EX_ST(STORE(stw, %o5, %o1 + 0x30))
+ EX_LD(LOAD(lduw, %o0 + 0x3c, %o5))
+ add %o4, %g1, %o4
+ EX_ST(STORE(stw, %g1, %o1 + 0x34))
+ LOAD(prefetch, %o0 + 0x180, #n_reads)
+ add %o4, %g2, %o4
+ EX_ST(STORE(stw, %g2, %o1 + 0x38))
+ subcc %g3, 0x40, %g3
+ add %o0, 0x40, %o0
+ add %o4, %o5, %o4
+ EX_ST(STORE(stw, %o5, %o1 + 0x3c))
+ bne,pt %icc, 1b
+ add %o1, 0x40, %o1
+
+2: and %o2, 0x3c, %g3
+ brz,pn %g3, 2f
+ sub %o2, %g3, %o2
+1: EX_LD(LOAD(lduw, %o0 + 0x00, %o5))
+ subcc %g3, 0x4, %g3
+ add %o0, 0x4, %o0
+ add %o4, %o5, %o4
+ EX_ST(STORE(stw, %o5, %o1 + 0x00))
+ bne,pt %icc, 1b
+ add %o1, 0x4, %o1
+
+2:
+ /* fold 64-->32 */
+ srlx %o4, 32, %o5
+ srl %o4, 0, %o4
+ add %o4, %o5, %o4
+ srlx %o4, 32, %o5
+ srl %o4, 0, %o4
+ add %o4, %o5, %o4
+
+ /* fold 32-->16 */
+ sethi %hi(0xffff0000), %g1
+ srl %o4, 16, %o5
+ andn %o4, %g1, %g2
+ add %o5, %g2, %o4
+ srl %o4, 16, %o5
+ andn %o4, %g1, %g2
+ add %o5, %g2, %o4
+
+60:
+ /* %o4 has the 16-bit sum we have calculated so-far. */
+ cmp %o2, 2
+ blu,pt %icc, 1f
+ nop
+ EX_LD(LOAD(lduh, %o0 + 0x00, %o5))
+ sub %o2, 2, %o2
+ add %o0, 2, %o0
+ add %o4, %o5, %o4
+ EX_ST(STORE(sth, %o5, %o1 + 0x00))
+ add %o1, 0x2, %o1
+1: brz,pt %o2, 1f
+ nop
+ EX_LD(LOAD(ldub, %o0 + 0x00, %o5))
+ sub %o2, 1, %o2
+ add %o0, 1, %o0
+ EX_ST(STORE(stb, %o5, %o1 + 0x00))
+ sllx %o5, 8, %o5
+ add %o1, 1, %o1
+ add %o4, %o5, %o4
+1:
+ /* fold 32-->16 */
+ sethi %hi(0xffff0000), %g1
+ srl %o4, 16, %o5
+ andn %o4, %g1, %g2
+ add %o5, %g2, %o4
+ srl %o4, 16, %o5
+ andn %o4, %g1, %g2
+ add %o5, %g2, %o4
+
+1: brz,pt GLOBAL_SPARE, 1f
+ nop
+
+ /* We started with an odd byte, byte-swap the result. */
+ srl %o4, 8, %o5
+ and %o4, 0xff, %g1
+ sll %g1, 8, %g1
+ or %o5, %g1, %o4
+
+1: add %o3, %o4, %o3
+
+70:
+ retl
+ mov %o3, %o0
+
+95: mov 0, GLOBAL_SPARE
+ brlez,pn %o2, 4f
+ andcc %o0, 1, %o5
+ be,a,pt %icc, 1f
+ srl %o2, 1, %g1
+ sub %o2, 1, %o2
+ EX_LD(LOAD(ldub, %o0, GLOBAL_SPARE))
+ add %o0, 1, %o0
+ EX_ST(STORE(stb, GLOBAL_SPARE, %o1))
+ srl %o2, 1, %g1
+ add %o1, 1, %o1
+1: brz,a,pn %g1, 3f
+ andcc %o2, 1, %g0
+ andcc %o0, 2, %g0
+ be,a,pt %icc, 1f
+ srl %g1, 1, %g1
+ EX_LD(LOAD(lduh, %o0, %o4))
+ sub %o2, 2, %o2
+ srl %o4, 8, %g2
+ sub %g1, 1, %g1
+ EX_ST(STORE(stb, %g2, %o1))
+ add %o4, GLOBAL_SPARE, GLOBAL_SPARE
+ EX_ST(STORE(stb, %o4, %o1 + 1))
+ add %o0, 2, %o0
+ srl %g1, 1, %g1
+ add %o1, 2, %o1
+1: brz,a,pn %g1, 2f
+ andcc %o2, 2, %g0
+ EX_LD(LOAD(lduw, %o0, %o4))
+5: srl %o4, 24, %g2
+ srl %o4, 16, %g3
+ EX_ST(STORE(stb, %g2, %o1))
+ srl %o4, 8, %g2
+ EX_ST(STORE(stb, %g3, %o1 + 1))
+ add %o0, 4, %o0
+ EX_ST(STORE(stb, %g2, %o1 + 2))
+ addcc %o4, GLOBAL_SPARE, GLOBAL_SPARE
+ EX_ST(STORE(stb, %o4, %o1 + 3))
+ addc GLOBAL_SPARE, %g0, GLOBAL_SPARE
+ add %o1, 4, %o1
+ subcc %g1, 1, %g1
+ bne,a,pt %icc, 5b
+ EX_LD(LOAD(lduw, %o0, %o4))
+ sll GLOBAL_SPARE, 16, %g2
+ srl GLOBAL_SPARE, 16, GLOBAL_SPARE
+ srl %g2, 16, %g2
+ andcc %o2, 2, %g0
+ add %g2, GLOBAL_SPARE, GLOBAL_SPARE
+2: be,a,pt %icc, 3f
+ andcc %o2, 1, %g0
+ EX_LD(LOAD(lduh, %o0, %o4))
+ andcc %o2, 1, %g0
+ srl %o4, 8, %g2
+ add %o0, 2, %o0
+ EX_ST(STORE(stb, %g2, %o1))
+ add GLOBAL_SPARE, %o4, GLOBAL_SPARE
+ EX_ST(STORE(stb, %o4, %o1 + 1))
+ add %o1, 2, %o1
+3: be,a,pt %icc, 1f
+ sll GLOBAL_SPARE, 16, %o4
+ EX_LD(LOAD(ldub, %o0, %g2))
+ sll %g2, 8, %o4
+ EX_ST(STORE(stb, %g2, %o1))
+ add GLOBAL_SPARE, %o4, GLOBAL_SPARE
+ sll GLOBAL_SPARE, 16, %o4
+1: addcc %o4, GLOBAL_SPARE, GLOBAL_SPARE
+ srl GLOBAL_SPARE, 16, %o4
+ addc %g0, %o4, GLOBAL_SPARE
+ brz,pt %o5, 4f
+ srl GLOBAL_SPARE, 8, %o4
+ and GLOBAL_SPARE, 0xff, %g2
+ and %o4, 0xff, %o4
+ sll %g2, 8, %g2
+ or %g2, %o4, GLOBAL_SPARE
+4: addcc %o3, GLOBAL_SPARE, %o3
+ addc %g0, %o3, %o0
+ retl
+ srl %o0, 0, %o0
+ .size FUNC_NAME, .-FUNC_NAME
--- /dev/null
+/* csum_copy_from_user.S: Checksum+copy from userspace.
+ *
+ * Copyright (C) 2005 David S. Miller (davem@davemloft.net)
+ */
+
+#define EX_LD(x) \
+98: x; \
+ .section .fixup; \
+ .align 4; \
+99: retl; \
+ mov -1, %o0; \
+ .section __ex_table; \
+ .align 4; \
+ .word 98b, 99b; \
+ .text; \
+ .align 4;
+
+#define FUNC_NAME __csum_partial_copy_from_user
+#define LOAD(type,addr,dest) type##a [addr] %asi, dest
+
+#include "csum_copy.S"
--- /dev/null
+/* csum_copy_to_user.S: Checksum+copy to userspace.
+ *
+ * Copyright (C) 2005 David S. Miller (davem@davemloft.net)
+ */
+
+#define EX_ST(x) \
+98: x; \
+ .section .fixup; \
+ .align 4; \
+99: retl; \
+ mov -1, %o0; \
+ .section __ex_table; \
+ .align 4; \
+ .word 98b, 99b; \
+ .text; \
+ .align 4;
+
+#define FUNC_NAME __csum_partial_copy_to_user
+#define STORE(type,src,addr) type##a src, [addr] %asi
+
+#include "csum_copy.S"
--- /dev/null
+/* rwsem.S: RW semaphore assembler.
+ *
+ * Written by David S. Miller (davem@redhat.com), 2001.
+ * Derived from asm-i386/rwsem.h
+ */
+
+#include <asm/rwsem-const.h>
+
+ .section .sched.text
+
+ .globl __down_read
+__down_read:
+1: lduw [%o0], %g1
+ add %g1, 1, %g7
+ cas [%o0], %g1, %g7
+ cmp %g1, %g7
+ bne,pn %icc, 1b
+ add %g7, 1, %g7
+ cmp %g7, 0
+ bl,pn %icc, 3f
+ membar #StoreLoad | #StoreStore
+2:
+ retl
+ nop
+3:
+ save %sp, -192, %sp
+ call rwsem_down_read_failed
+ mov %i0, %o0
+ ret
+ restore
+ .size __down_read, .-__down_read
+
+ .globl __down_read_trylock
+__down_read_trylock:
+1: lduw [%o0], %g1
+ add %g1, 1, %g7
+ cmp %g7, 0
+ bl,pn %icc, 2f
+ mov 0, %o1
+ cas [%o0], %g1, %g7
+ cmp %g1, %g7
+ bne,pn %icc, 1b
+ mov 1, %o1
+ membar #StoreLoad | #StoreStore
+2: retl
+ mov %o1, %o0
+ .size __down_read_trylock, .-__down_read_trylock
+
+ .globl __down_write
+__down_write:
+ sethi %hi(RWSEM_ACTIVE_WRITE_BIAS), %g1
+ or %g1, %lo(RWSEM_ACTIVE_WRITE_BIAS), %g1
+1:
+ lduw [%o0], %g3
+ add %g3, %g1, %g7
+ cas [%o0], %g3, %g7
+ cmp %g3, %g7
+ bne,pn %icc, 1b
+ cmp %g7, 0
+ bne,pn %icc, 3f
+ membar #StoreLoad | #StoreStore
+2: retl
+ nop
+3:
+ save %sp, -192, %sp
+ call rwsem_down_write_failed
+ mov %i0, %o0
+ ret
+ restore
+ .size __down_write, .-__down_write
+
+ .globl __down_write_trylock
+__down_write_trylock:
+ sethi %hi(RWSEM_ACTIVE_WRITE_BIAS), %g1
+ or %g1, %lo(RWSEM_ACTIVE_WRITE_BIAS), %g1
+1:
+ lduw [%o0], %g3
+ cmp %g3, 0
+ bne,pn %icc, 2f
+ mov 0, %o1
+ add %g3, %g1, %g7
+ cas [%o0], %g3, %g7
+ cmp %g3, %g7
+ bne,pn %icc, 1b
+ mov 1, %o1
+ membar #StoreLoad | #StoreStore
+2: retl
+ mov %o1, %o0
+ .size __down_write_trylock, .-__down_write_trylock
+
+ .globl __up_read
+__up_read:
+1:
+ lduw [%o0], %g1
+ sub %g1, 1, %g7
+ cas [%o0], %g1, %g7
+ cmp %g1, %g7
+ bne,pn %icc, 1b
+ cmp %g7, 0
+ bl,pn %icc, 3f
+ membar #StoreLoad | #StoreStore
+2: retl
+ nop
+3: sethi %hi(RWSEM_ACTIVE_MASK), %g1
+ sub %g7, 1, %g7
+ or %g1, %lo(RWSEM_ACTIVE_MASK), %g1
+ andcc %g7, %g1, %g0
+ bne,pn %icc, 2b
+ nop
+ save %sp, -192, %sp
+ call rwsem_wake
+ mov %i0, %o0
+ ret
+ restore
+ .size __up_read, .-__up_read
+
+ .globl __up_write
+__up_write:
+ sethi %hi(RWSEM_ACTIVE_WRITE_BIAS), %g1
+ or %g1, %lo(RWSEM_ACTIVE_WRITE_BIAS), %g1
+1:
+ lduw [%o0], %g3
+ sub %g3, %g1, %g7
+ cas [%o0], %g3, %g7
+ cmp %g3, %g7
+ bne,pn %icc, 1b
+ sub %g7, %g1, %g7
+ cmp %g7, 0
+ bl,pn %icc, 3f
+ membar #StoreLoad | #StoreStore
+2:
+ retl
+ nop
+3:
+ save %sp, -192, %sp
+ call rwsem_wake
+ mov %i0, %o0
+ ret
+ restore
+ .size __up_write, .-__up_write
+
+ .globl __downgrade_write
+__downgrade_write:
+ sethi %hi(RWSEM_WAITING_BIAS), %g1
+ or %g1, %lo(RWSEM_WAITING_BIAS), %g1
+1:
+ lduw [%o0], %g3
+ sub %g3, %g1, %g7
+ cas [%o0], %g3, %g7
+ cmp %g3, %g7
+ bne,pn %icc, 1b
+ sub %g7, %g1, %g7
+ cmp %g7, 0
+ bl,pn %icc, 3f
+ membar #StoreLoad | #StoreStore
+2:
+ retl
+ nop
+3:
+ save %sp, -192, %sp
+ call rwsem_downgrade_wake
+ mov %i0, %o0
+ ret
+ restore
+ .size __downgrade_write, .-__downgrade_write
--- /dev/null
+#include <string.h>
+#include "slip_common.h"
+#include "net_user.h"
+
+int slip_proto_read(int fd, void *buf, int len, struct slip_proto *slip)
+{
+ int i, n, size, start;
+
+ if(slip->more > 0){
+ i = 0;
+ while(i < slip->more){
+ size = slip_unesc(slip->ibuf[i++], slip->ibuf,
+ &slip->pos, &slip->esc);
+ if(size){
+ memcpy(buf, slip->ibuf, size);
+ memmove(slip->ibuf, &slip->ibuf[i],
+ slip->more - i);
+ slip->more = slip->more - i;
+ return size;
+ }
+ }
+ slip->more = 0;
+ }
+
+ n = net_read(fd, &slip->ibuf[slip->pos],
+ sizeof(slip->ibuf) - slip->pos);
+ if(n <= 0)
+ return n;
+
+ start = slip->pos;
+ for(i = 0; i < n; i++){
+ size = slip_unesc(slip->ibuf[start + i], slip->ibuf,&slip->pos,
+ &slip->esc);
+ if(size){
+ memcpy(buf, slip->ibuf, size);
+ memmove(slip->ibuf, &slip->ibuf[start+i+1],
+ n - (i + 1));
+ slip->more = n - (i + 1);
+ return size;
+ }
+ }
+ return 0;
+}
+
+int slip_proto_write(int fd, void *buf, int len, struct slip_proto *slip)
+{
+ int actual, n;
+
+ actual = slip_esc(buf, slip->obuf, len);
+ n = net_write(fd, slip->obuf, actual);
+ if(n < 0)
+ return n;
+ else return len;
+}
--- /dev/null
+#ifndef __UM_SLIP_COMMON_H
+#define __UM_SLIP_COMMON_H
+
+#define BUF_SIZE 1500
+ /* two bytes each for a (pathological) max packet of escaped chars + *
+ * terminating END char + initial END char */
+#define ENC_BUF_SIZE (2 * BUF_SIZE + 2)
+
+/* SLIP protocol characters. */
+#define SLIP_END 0300 /* indicates end of frame */
+#define SLIP_ESC 0333 /* indicates byte stuffing */
+#define SLIP_ESC_END 0334 /* ESC ESC_END means END 'data' */
+#define SLIP_ESC_ESC 0335 /* ESC ESC_ESC means ESC 'data' */
+
+static inline int slip_unesc(unsigned char c, unsigned char *buf, int *pos,
+ int *esc)
+{
+ int ret;
+
+ switch(c){
+ case SLIP_END:
+ *esc = 0;
+ ret=*pos;
+ *pos=0;
+ return(ret);
+ case SLIP_ESC:
+ *esc = 1;
+ return(0);
+ case SLIP_ESC_ESC:
+ if(*esc){
+ *esc = 0;
+ c = SLIP_ESC;
+ }
+ break;
+ case SLIP_ESC_END:
+ if(*esc){
+ *esc = 0;
+ c = SLIP_END;
+ }
+ break;
+ }
+ buf[(*pos)++] = c;
+ return(0);
+}
+
+static inline int slip_esc(unsigned char *s, unsigned char *d, int len)
+{
+ unsigned char *ptr = d;
+ unsigned char c;
+
+ /*
+ * Send an initial END character to flush out any
+ * data that may have accumulated in the receiver
+ * due to line noise.
+ */
+
+ *ptr++ = SLIP_END;
+
+ /*
+ * For each byte in the packet, send the appropriate
+ * character sequence, according to the SLIP protocol.
+ */
+
+ while (len-- > 0) {
+ switch(c = *s++) {
+ case SLIP_END:
+ *ptr++ = SLIP_ESC;
+ *ptr++ = SLIP_ESC_END;
+ break;
+ case SLIP_ESC:
+ *ptr++ = SLIP_ESC;
+ *ptr++ = SLIP_ESC_ESC;
+ break;
+ default:
+ *ptr++ = c;
+ break;
+ }
+ }
+ *ptr++ = SLIP_END;
+ return (ptr - d);
+}
+
+struct slip_proto {
+ unsigned char ibuf[ENC_BUF_SIZE];
+ unsigned char obuf[ENC_BUF_SIZE];
+ int more; /* more data: do not read fd until ibuf has been drained */
+ int pos;
+ int esc;
+};
+
+#define SLIP_PROTO_INIT { \
+ .ibuf = { '\0' }, \
+ .obuf = { '\0' }, \
+ .more = 0, \
+ .pos = 0, \
+ .esc = 0 \
+}
+
+extern int slip_proto_read(int fd, void *buf, int len,
+ struct slip_proto *slip);
+extern int slip_proto_write(int fd, void *buf, int len,
+ struct slip_proto *slip);
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2004 Fujitsu Siemens Computers GmbH
+ * Author: Bodo Stroesser <bstroesser@fujitsu-siemens.com>
+ * Licensed under the GPL
+ */
+
+#ifndef __FAULTINFO_I386_H
+#define __FAULTINFO_I386_H
+
+/* this structure contains the full arch-specific faultinfo
+ * from the traps.
+ * On i386, ptrace_faultinfo unfortunately doesn't provide
+ * all the info, since trap_no is missing.
+ * All common elements are defined at the same position in
+ * both structures, thus making it easy to copy the
+ * contents without knowledge about the structure elements.
+ */
+struct faultinfo {
+ int error_code; /* in ptrace_faultinfo misleadingly called is_write */
+ unsigned long cr2; /* in ptrace_faultinfo called addr */
+ int trap_no; /* missing in ptrace_faultinfo */
+};
+
+#define FAULT_WRITE(fi) ((fi).error_code & 2)
+#define FAULT_ADDRESS(fi) ((fi).cr2)
+
+#define PTRACE_FULL_FAULTINFO 0
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SYSDEP_I386_SKAS_PTRACE_H
+#define __SYSDEP_I386_SKAS_PTRACE_H
+
+struct ptrace_faultinfo {
+ int is_write;
+ unsigned long addr;
+};
+
+struct ptrace_ldt {
+ int func;
+ void *ptr;
+ unsigned long bytecount;
+};
+
+#define PTRACE_LDT 54
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SYSDEP_IA64_SKAS_PTRACE_H
+#define __SYSDEP_IA64_SKAS_PTRACE_H
+
+struct ptrace_faultinfo {
+ int is_write;
+ unsigned long addr;
+};
+
+struct ptrace_ldt {
+ int func;
+ void *ptr;
+ unsigned long bytecount;
+};
+
+#define PTRACE_LDT 54
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SYSDEP_PPC_SKAS_PTRACE_H
+#define __SYSDEP_PPC_SKAS_PTRACE_H
+
+struct ptrace_faultinfo {
+ int is_write;
+ unsigned long addr;
+};
+
+struct ptrace_ldt {
+ int func;
+ void *ptr;
+ unsigned long bytecount;
+};
+
+#define PTRACE_LDT 54
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2004 Fujitsu Siemens Computers GmbH
+ * Author: Bodo Stroesser <bstroesser@fujitsu-siemens.com>
+ * Licensed under the GPL
+ */
+
+#ifndef __FAULTINFO_X86_64_H
+#define __FAULTINFO_X86_64_H
+
+/* this structure contains the full arch-specific faultinfo
+ * from the traps.
+ * On i386, ptrace_faultinfo unfortunately doesn't provide
+ * all the info, since trap_no is missing.
+ * All common elements are defined at the same position in
+ * both structures, thus making it easy to copy the
+ * contents without knowledge about the structure elements.
+ */
+struct faultinfo {
+ int error_code; /* in ptrace_faultinfo misleadingly called is_write */
+ unsigned long cr2; /* in ptrace_faultinfo called addr */
+ int trap_no; /* missing in ptrace_faultinfo */
+};
+
+#define FAULT_WRITE(fi) ((fi).error_code & 2)
+#define FAULT_ADDRESS(fi) ((fi).cr2)
+
+#define PTRACE_FULL_FAULTINFO 1
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SYSDEP_X86_64_SKAS_PTRACE_H
+#define __SYSDEP_X86_64_SKAS_PTRACE_H
+
+struct ptrace_faultinfo {
+ int is_write;
+ unsigned long addr;
+};
+
+struct ptrace_ldt {
+ int func;
+ void *ptr;
+ unsigned long bytecount;
+};
+
+#define PTRACE_LDT 54
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/init.h"
+#include "linux/bootmem.h"
+#include "linux/initrd.h"
+#include "asm/types.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "initrd.h"
+#include "init.h"
+#include "os.h"
+
+/* Changed by uml_initrd_setup, which is a setup */
+static char *initrd __initdata = NULL;
+
+static int __init read_initrd(void)
+{
+ void *area;
+ long long size;
+ int err;
+
+ if(initrd == NULL) return 0;
+ err = os_file_size(initrd, &size);
+ if(err) return 0;
+ area = alloc_bootmem(size);
+ if(area == NULL) return 0;
+ if(load_initrd(initrd, area, size) == -1) return 0;
+ initrd_start = (unsigned long) area;
+ initrd_end = initrd_start + size;
+ return 0;
+}
+
+__uml_postsetup(read_initrd);
+
+static int __init uml_initrd_setup(char *line, int *add)
+{
+ initrd = line;
+ return 0;
+}
+
+__uml_setup("initrd=", uml_initrd_setup,
+"initrd=<initrd image>\n"
+" This is used to boot UML from an initrd image. The argument is the\n"
+" name of the file containing the image.\n\n"
+);
+
+int load_initrd(char *filename, void *buf, int size)
+{
+ int fd, n;
+
+ fd = os_open_file(filename, of_read(OPENFLAGS()), 0);
+ if(fd < 0){
+ printk("Opening '%s' failed - err = %d\n", filename, -fd);
+ return(-1);
+ }
+ n = os_read_file(fd, buf, size);
+ if(n != size){
+ printk("Read of %d bytes from '%s' failed, err = %d\n", size,
+ filename, -n);
+ return(-1);
+ }
+
+ os_close_file(fd);
+ return(0);
+}
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
--- /dev/null
+#include <linux/vmalloc.h>
+#include <linux/moduleloader.h>
+
+/*Copied from i386 arch/i386/kernel/module.c */
+void *module_alloc(unsigned long size)
+{
+ if (size == 0)
+ return NULL;
+ return vmalloc_exec(size);
+}
+
+/* Free memory returned from module_alloc */
+void module_free(struct module *mod, void *module_region)
+{
+ vfree(module_region);
+ /* FIXME: If module_region == mod->init_region, trim exception
+ table entries. */
+}
+
--- /dev/null
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (c) 2005 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#ifndef __MBCS_H__
+#define __MBCS_H__
+
+/*
+ * General macros
+ */
+#define MB (1024*1024)
+#define MB2 (2*MB)
+#define MB4 (4*MB)
+#define MB6 (6*MB)
+
+/*
+ * Offsets and masks
+ */
+#define MBCS_CM_ID 0x0000 /* Identification */
+#define MBCS_CM_STATUS 0x0008 /* Status */
+#define MBCS_CM_ERROR_DETAIL1 0x0010 /* Error Detail1 */
+#define MBCS_CM_ERROR_DETAIL2 0x0018 /* Error Detail2 */
+#define MBCS_CM_CONTROL 0x0020 /* Control */
+#define MBCS_CM_REQ_TOUT 0x0028 /* Request Time-out */
+#define MBCS_CM_ERR_INT_DEST 0x0038 /* Error Interrupt Destination */
+#define MBCS_CM_TARG_FL 0x0050 /* Target Flush */
+#define MBCS_CM_ERR_STAT 0x0060 /* Error Status */
+#define MBCS_CM_CLR_ERR_STAT 0x0068 /* Clear Error Status */
+#define MBCS_CM_ERR_INT_EN 0x0070 /* Error Interrupt Enable */
+#define MBCS_RD_DMA_SYS_ADDR 0x0100 /* Read DMA System Address */
+#define MBCS_RD_DMA_LOC_ADDR 0x0108 /* Read DMA Local Address */
+#define MBCS_RD_DMA_CTRL 0x0110 /* Read DMA Control */
+#define MBCS_RD_DMA_AMO_DEST 0x0118 /* Read DMA AMO Destination */
+#define MBCS_RD_DMA_INT_DEST 0x0120 /* Read DMA Interrupt Destination */
+#define MBCS_RD_DMA_AUX_STAT 0x0130 /* Read DMA Auxillary Status */
+#define MBCS_WR_DMA_SYS_ADDR 0x0200 /* Write DMA System Address */
+#define MBCS_WR_DMA_LOC_ADDR 0x0208 /* Write DMA Local Address */
+#define MBCS_WR_DMA_CTRL 0x0210 /* Write DMA Control */
+#define MBCS_WR_DMA_AMO_DEST 0x0218 /* Write DMA AMO Destination */
+#define MBCS_WR_DMA_INT_DEST 0x0220 /* Write DMA Interrupt Destination */
+#define MBCS_WR_DMA_AUX_STAT 0x0230 /* Write DMA Auxillary Status */
+#define MBCS_ALG_AMO_DEST 0x0300 /* Algorithm AMO Destination */
+#define MBCS_ALG_INT_DEST 0x0308 /* Algorithm Interrupt Destination */
+#define MBCS_ALG_OFFSETS 0x0310
+#define MBCS_ALG_STEP 0x0318 /* Algorithm Step */
+
+#define MBCS_GSCR_START 0x0000000
+#define MBCS_DEBUG_START 0x0100000
+#define MBCS_RAM0_START 0x0200000
+#define MBCS_RAM1_START 0x0400000
+#define MBCS_RAM2_START 0x0600000
+
+#define MBCS_CM_CONTROL_REQ_TOUT_MASK 0x0000000000ffffffUL
+//#define PIO_BASE_ADDR_BASE_OFFSET_MASK 0x00fffffffff00000UL
+
+#define MBCS_SRAM_SIZE (1024*1024)
+#define MBCS_CACHELINE_SIZE 128
+
+/*
+ * MMR get's and put's
+ */
+#define MBCS_MMR_ADDR(mmr_base, offset)((uint64_t *)(mmr_base + offset))
+#define MBCS_MMR_SET(mmr_base, offset, value) { \
+ uint64_t *mbcs_mmr_set_u64p, readback; \
+ mbcs_mmr_set_u64p = (uint64_t *)(mmr_base + offset); \
+ *mbcs_mmr_set_u64p = value; \
+ readback = *mbcs_mmr_set_u64p; \
+}
+#define MBCS_MMR_GET(mmr_base, offset) *(uint64_t *)(mmr_base + offset)
+#define MBCS_MMR_ZERO(mmr_base, offset) MBCS_MMR_SET(mmr_base, offset, 0)
+
+/*
+ * MBCS mmr structures
+ */
+union cm_id {
+ uint64_t cm_id_reg;
+ struct {
+ uint64_t always_one:1, // 0
+ mfg_id:11, // 11:1
+ part_num:16, // 27:12
+ bitstream_rev:8, // 35:28
+ :28; // 63:36
+ };
+};
+
+union cm_status {
+ uint64_t cm_status_reg;
+ struct {
+ uint64_t pending_reads:8, // 7:0
+ pending_writes:8, // 15:8
+ ice_rsp_credits:8, // 23:16
+ ice_req_credits:8, // 31:24
+ cm_req_credits:8, // 39:32
+ :1, // 40
+ rd_dma_in_progress:1, // 41
+ rd_dma_done:1, // 42
+ :1, // 43
+ wr_dma_in_progress:1, // 44
+ wr_dma_done:1, // 45
+ alg_waiting:1, // 46
+ alg_pipe_running:1, // 47
+ alg_done:1, // 48
+ :3, // 51:49
+ pending_int_reqs:8, // 59:52
+ :3, // 62:60
+ alg_half_speed_sel:1; // 63
+ };
+};
+
+union cm_error_detail1 {
+ uint64_t cm_error_detail1_reg;
+ struct {
+ uint64_t packet_type:4, // 3:0
+ source_id:2, // 5:4
+ data_size:2, // 7:6
+ tnum:8, // 15:8
+ byte_enable:8, // 23:16
+ gfx_cred:8, // 31:24
+ read_type:2, // 33:32
+ pio_or_memory:1, // 34
+ head_cw_error:1, // 35
+ :12, // 47:36
+ head_error_bit:1, // 48
+ data_error_bit:1, // 49
+ :13, // 62:50
+ valid:1; // 63
+ };
+};
+
+union cm_error_detail2 {
+ uint64_t cm_error_detail2_reg;
+ struct {
+ uint64_t address:56, // 55:0
+ :8; // 63:56
+ };
+};
+
+union cm_control {
+ uint64_t cm_control_reg;
+ struct {
+ uint64_t cm_id:2, // 1:0
+ :2, // 3:2
+ max_trans:5, // 8:4
+ :3, // 11:9
+ address_mode:1, // 12
+ :7, // 19:13
+ credit_limit:8, // 27:20
+ :5, // 32:28
+ rearm_stat_regs:1, // 33
+ prescalar_byp:1, // 34
+ force_gap_war:1, // 35
+ rd_dma_go:1, // 36
+ wr_dma_go:1, // 37
+ alg_go:1, // 38
+ rd_dma_clr:1, // 39
+ wr_dma_clr:1, // 40
+ alg_clr:1, // 41
+ :2, // 43:42
+ alg_wait_step:1, // 44
+ alg_done_amo_en:1, // 45
+ alg_done_int_en:1, // 46
+ :1, // 47
+ alg_sram0_locked:1, // 48
+ alg_sram1_locked:1, // 49
+ alg_sram2_locked:1, // 50
+ alg_done_clr:1, // 51
+ :12; // 63:52
+ };
+};
+
+union cm_req_timeout {
+ uint64_t cm_req_timeout_reg;
+ struct {
+ uint64_t time_out:24, // 23:0
+ :40; // 63:24
+ };
+};
+
+union intr_dest {
+ uint64_t intr_dest_reg;
+ struct {
+ uint64_t address:56, // 55:0
+ int_vector:8; // 63:56
+ };
+};
+
+union cm_error_status {
+ uint64_t cm_error_status_reg;
+ struct {
+ uint64_t ecc_sbe:1, // 0
+ ecc_mbe:1, // 1
+ unsupported_req:1, // 2
+ unexpected_rsp:1, // 3
+ bad_length:1, // 4
+ bad_datavalid:1, // 5
+ buffer_overflow:1, // 6
+ request_timeout:1, // 7
+ :8, // 15:8
+ head_inv_data_size:1, // 16
+ rsp_pactype_inv:1, // 17
+ head_sb_err:1, // 18
+ missing_head:1, // 19
+ head_inv_rd_type:1, // 20
+ head_cmd_err_bit:1, // 21
+ req_addr_align_inv:1, // 22
+ pio_req_addr_inv:1, // 23
+ req_range_dsize_inv:1, // 24
+ early_term:1, // 25
+ early_tail:1, // 26
+ missing_tail:1, // 27
+ data_flit_sb_err:1, // 28
+ cm2hcm_req_cred_of:1, // 29
+ cm2hcm_rsp_cred_of:1, // 30
+ rx_bad_didn:1, // 31
+ rd_dma_err_rsp:1, // 32
+ rd_dma_tnum_tout:1, // 33
+ rd_dma_multi_tnum_tou:1, // 34
+ wr_dma_err_rsp:1, // 35
+ wr_dma_tnum_tout:1, // 36
+ wr_dma_multi_tnum_tou:1, // 37
+ alg_data_overflow:1, // 38
+ alg_data_underflow:1, // 39
+ ram0_access_conflict:1, // 40
+ ram1_access_conflict:1, // 41
+ ram2_access_conflict:1, // 42
+ ram0_perr:1, // 43
+ ram1_perr:1, // 44
+ ram2_perr:1, // 45
+ int_gen_rsp_err:1, // 46
+ int_gen_tnum_tout:1, // 47
+ rd_dma_prog_err:1, // 48
+ wr_dma_prog_err:1, // 49
+ :14; // 63:50
+ };
+};
+
+union cm_clr_error_status {
+ uint64_t cm_clr_error_status_reg;
+ struct {
+ uint64_t clr_ecc_sbe:1, // 0
+ clr_ecc_mbe:1, // 1
+ clr_unsupported_req:1, // 2
+ clr_unexpected_rsp:1, // 3
+ clr_bad_length:1, // 4
+ clr_bad_datavalid:1, // 5
+ clr_buffer_overflow:1, // 6
+ clr_request_timeout:1, // 7
+ :8, // 15:8
+ clr_head_inv_data_siz:1, // 16
+ clr_rsp_pactype_inv:1, // 17
+ clr_head_sb_err:1, // 18
+ clr_missing_head:1, // 19
+ clr_head_inv_rd_type:1, // 20
+ clr_head_cmd_err_bit:1, // 21
+ clr_req_addr_align_in:1, // 22
+ clr_pio_req_addr_inv:1, // 23
+ clr_req_range_dsize_i:1, // 24
+ clr_early_term:1, // 25
+ clr_early_tail:1, // 26
+ clr_missing_tail:1, // 27
+ clr_data_flit_sb_err:1, // 28
+ clr_cm2hcm_req_cred_o:1, // 29
+ clr_cm2hcm_rsp_cred_o:1, // 30
+ clr_rx_bad_didn:1, // 31
+ clr_rd_dma_err_rsp:1, // 32
+ clr_rd_dma_tnum_tout:1, // 33
+ clr_rd_dma_multi_tnum:1, // 34
+ clr_wr_dma_err_rsp:1, // 35
+ clr_wr_dma_tnum_tout:1, // 36
+ clr_wr_dma_multi_tnum:1, // 37
+ clr_alg_data_overflow:1, // 38
+ clr_alg_data_underflo:1, // 39
+ clr_ram0_access_confl:1, // 40
+ clr_ram1_access_confl:1, // 41
+ clr_ram2_access_confl:1, // 42
+ clr_ram0_perr:1, // 43
+ clr_ram1_perr:1, // 44
+ clr_ram2_perr:1, // 45
+ clr_int_gen_rsp_err:1, // 46
+ clr_int_gen_tnum_tout:1, // 47
+ clr_rd_dma_prog_err:1, // 48
+ clr_wr_dma_prog_err:1, // 49
+ :14; // 63:50
+ };
+};
+
+union cm_error_intr_enable {
+ uint64_t cm_error_intr_enable_reg;
+ struct {
+ uint64_t int_en_ecc_sbe:1, // 0
+ int_en_ecc_mbe:1, // 1
+ int_en_unsupported_re:1, // 2
+ int_en_unexpected_rsp:1, // 3
+ int_en_bad_length:1, // 4
+ int_en_bad_datavalid:1, // 5
+ int_en_buffer_overflo:1, // 6
+ int_en_request_timeou:1, // 7
+ :8, // 15:8
+ int_en_head_inv_data_:1, // 16
+ int_en_rsp_pactype_in:1, // 17
+ int_en_head_sb_err:1, // 18
+ int_en_missing_head:1, // 19
+ int_en_head_inv_rd_ty:1, // 20
+ int_en_head_cmd_err_b:1, // 21
+ int_en_req_addr_align:1, // 22
+ int_en_pio_req_addr_i:1, // 23
+ int_en_req_range_dsiz:1, // 24
+ int_en_early_term:1, // 25
+ int_en_early_tail:1, // 26
+ int_en_missing_tail:1, // 27
+ int_en_data_flit_sb_e:1, // 28
+ int_en_cm2hcm_req_cre:1, // 29
+ int_en_cm2hcm_rsp_cre:1, // 30
+ int_en_rx_bad_didn:1, // 31
+ int_en_rd_dma_err_rsp:1, // 32
+ int_en_rd_dma_tnum_to:1, // 33
+ int_en_rd_dma_multi_t:1, // 34
+ int_en_wr_dma_err_rsp:1, // 35
+ int_en_wr_dma_tnum_to:1, // 36
+ int_en_wr_dma_multi_t:1, // 37
+ int_en_alg_data_overf:1, // 38
+ int_en_alg_data_under:1, // 39
+ int_en_ram0_access_co:1, // 40
+ int_en_ram1_access_co:1, // 41
+ int_en_ram2_access_co:1, // 42
+ int_en_ram0_perr:1, // 43
+ int_en_ram1_perr:1, // 44
+ int_en_ram2_perr:1, // 45
+ int_en_int_gen_rsp_er:1, // 46
+ int_en_int_gen_tnum_t:1, // 47
+ int_en_rd_dma_prog_er:1, // 48
+ int_en_wr_dma_prog_er:1, // 49
+ :14; // 63:50
+ };
+};
+
+struct cm_mmr {
+ union cm_id id;
+ union cm_status status;
+ union cm_error_detail1 err_detail1;
+ union cm_error_detail2 err_detail2;
+ union cm_control control;
+ union cm_req_timeout req_timeout;
+ uint64_t reserved1[1];
+ union intr_dest int_dest;
+ uint64_t reserved2[2];
+ uint64_t targ_flush;
+ uint64_t reserved3[1];
+ union cm_error_status err_status;
+ union cm_clr_error_status clr_err_status;
+ union cm_error_intr_enable int_enable;
+};
+
+union dma_hostaddr {
+ uint64_t dma_hostaddr_reg;
+ struct {
+ uint64_t dma_sys_addr:56, // 55:0
+ :8; // 63:56
+ };
+};
+
+union dma_localaddr {
+ uint64_t dma_localaddr_reg;
+ struct {
+ uint64_t dma_ram_addr:21, // 20:0
+ dma_ram_sel:2, // 22:21
+ :41; // 63:23
+ };
+};
+
+union dma_control {
+ uint64_t dma_control_reg;
+ struct {
+ uint64_t dma_op_length:16, // 15:0
+ :18, // 33:16
+ done_amo_en:1, // 34
+ done_int_en:1, // 35
+ :1, // 36
+ pio_mem_n:1, // 37
+ :26; // 63:38
+ };
+};
+
+union dma_amo_dest {
+ uint64_t dma_amo_dest_reg;
+ struct {
+ uint64_t dma_amo_sys_addr:56, // 55:0
+ dma_amo_mod_type:3, // 58:56
+ :5; // 63:59
+ };
+};
+
+union rdma_aux_status {
+ uint64_t rdma_aux_status_reg;
+ struct {
+ uint64_t op_num_pacs_left:17, // 16:0
+ :5, // 21:17
+ lrsp_buff_empty:1, // 22
+ :17, // 39:23
+ pending_reqs_left:6, // 45:40
+ :18; // 63:46
+ };
+};
+
+struct rdma_mmr {
+ union dma_hostaddr host_addr;
+ union dma_localaddr local_addr;
+ union dma_control control;
+ union dma_amo_dest amo_dest;
+ union intr_dest intr_dest;
+ union rdma_aux_status aux_status;
+};
+
+union wdma_aux_status {
+ uint64_t wdma_aux_status_reg;
+ struct {
+ uint64_t op_num_pacs_left:17, // 16:0
+ :4, // 20:17
+ lreq_buff_empty:1, // 21
+ :18, // 39:22
+ pending_reqs_left:6, // 45:40
+ :18; // 63:46
+ };
+};
+
+struct wdma_mmr {
+ union dma_hostaddr host_addr;
+ union dma_localaddr local_addr;
+ union dma_control control;
+ union dma_amo_dest amo_dest;
+ union intr_dest intr_dest;
+ union wdma_aux_status aux_status;
+};
+
+union algo_step {
+ uint64_t algo_step_reg;
+ struct {
+ uint64_t alg_step_cnt:16, // 15:0
+ :48; // 63:16
+ };
+};
+
+struct algo_mmr {
+ union dma_amo_dest amo_dest;
+ union intr_dest intr_dest;
+ union {
+ uint64_t algo_offset_reg;
+ struct {
+ uint64_t sram0_offset:7, // 6:0
+ reserved0:1, // 7
+ sram1_offset:7, // 14:8
+ reserved1:1, // 15
+ sram2_offset:7, // 22:16
+ reserved2:14; // 63:23
+ };
+ } sram_offset;
+ union algo_step step;
+};
+
+struct mbcs_mmr {
+ struct cm_mmr cm;
+ uint64_t reserved1[17];
+ struct rdma_mmr rdDma;
+ uint64_t reserved2[25];
+ struct wdma_mmr wrDma;
+ uint64_t reserved3[25];
+ struct algo_mmr algo;
+ uint64_t reserved4[156];
+};
+
+/*
+ * defines
+ */
+#define DEVICE_NAME "mbcs"
+#define MBCS_PART_NUM 0xfff0
+#define MBCS_PART_NUM_ALG0 0xf001
+#define MBCS_MFG_NUM 0x1
+
+struct algoblock {
+ uint64_t amoHostDest;
+ uint64_t amoModType;
+ uint64_t intrHostDest;
+ uint64_t intrVector;
+ uint64_t algoStepCount;
+};
+
+struct getdma {
+ uint64_t hostAddr;
+ uint64_t localAddr;
+ uint64_t bytes;
+ uint64_t DoneAmoEnable;
+ uint64_t DoneIntEnable;
+ uint64_t peerIO;
+ uint64_t amoHostDest;
+ uint64_t amoModType;
+ uint64_t intrHostDest;
+ uint64_t intrVector;
+};
+
+struct putdma {
+ uint64_t hostAddr;
+ uint64_t localAddr;
+ uint64_t bytes;
+ uint64_t DoneAmoEnable;
+ uint64_t DoneIntEnable;
+ uint64_t peerIO;
+ uint64_t amoHostDest;
+ uint64_t amoModType;
+ uint64_t intrHostDest;
+ uint64_t intrVector;
+};
+
+struct mbcs_soft {
+ struct list_head list;
+ struct cx_dev *cxdev;
+ int major;
+ int nasid;
+ void *mmr_base;
+ wait_queue_head_t dmawrite_queue;
+ wait_queue_head_t dmaread_queue;
+ wait_queue_head_t algo_queue;
+ struct sn_irq_info *get_sn_irq;
+ struct sn_irq_info *put_sn_irq;
+ struct sn_irq_info *algo_sn_irq;
+ struct getdma getdma;
+ struct putdma putdma;
+ struct algoblock algo;
+ uint64_t gscr_addr; // pio addr
+ uint64_t ram0_addr; // pio addr
+ uint64_t ram1_addr; // pio addr
+ uint64_t ram2_addr; // pio addr
+ uint64_t debug_addr; // pio addr
+ atomic_t dmawrite_done;
+ atomic_t dmaread_done;
+ atomic_t algo_done;
+ struct semaphore dmawritelock;
+ struct semaphore dmareadlock;
+ struct semaphore algolock;
+};
+
+extern int mbcs_open(struct inode *ip, struct file *fp);
+extern ssize_t mbcs_sram_read(struct file *fp, char __user *buf, size_t len,
+ loff_t * off);
+extern ssize_t mbcs_sram_write(struct file *fp, const char __user *buf, size_t len,
+ loff_t * off);
+extern loff_t mbcs_sram_llseek(struct file *filp, loff_t off, int whence);
+extern int mbcs_gscr_mmap(struct file *fp, struct vm_area_struct *vma);
+
+#endif // __MBCS_H__
--- /dev/null
+/*
+ * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+ *
+ * This file is released under the GPL.
+ */
+
+#ifndef DM_BIO_RECORD_H
+#define DM_BIO_RECORD_H
+
+#include <linux/bio.h>
+
+/*
+ * There are lots of mutable fields in the bio struct that get
+ * changed by the lower levels of the block layer. Some targets,
+ * such as multipath, may wish to resubmit a bio on error. The
+ * functions in this file help the target record and restore the
+ * original bio state.
+ */
+struct dm_bio_details {
+ sector_t bi_sector;
+ struct block_device *bi_bdev;
+ unsigned int bi_size;
+ unsigned short bi_idx;
+ unsigned long bi_flags;
+};
+
+static inline void dm_bio_record(struct dm_bio_details *bd, struct bio *bio)
+{
+ bd->bi_sector = bio->bi_sector;
+ bd->bi_bdev = bio->bi_bdev;
+ bd->bi_size = bio->bi_size;
+ bd->bi_idx = bio->bi_idx;
+ bd->bi_flags = bio->bi_flags;
+}
+
+static inline void dm_bio_restore(struct dm_bio_details *bd, struct bio *bio)
+{
+ bio->bi_sector = bd->bi_sector;
+ bio->bi_bdev = bd->bi_bdev;
+ bio->bi_size = bd->bi_size;
+ bio->bi_idx = bd->bi_idx;
+ bio->bi_flags = bd->bi_flags;
+}
+
+#endif
--- /dev/null
+/*
+ * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
+ *
+ * flexcop-dma.c - methods for configuring and controlling the DMA of the FlexCop.
+ *
+ * see flexcop.c for copyright information.
+ */
+#include "flexcop.h"
+
+int flexcop_dma_allocate(struct pci_dev *pdev, struct flexcop_dma *dma, u32 size)
+{
+ u8 *tcpu;
+ dma_addr_t tdma;
+
+ if (size % 2) {
+ err("dma buffersize has to be even.");
+ return -EINVAL;
+ }
+
+ if ((tcpu = pci_alloc_consistent(pdev, size, &tdma)) != NULL) {
+ dma->pdev = pdev;
+ dma->cpu_addr0 = tcpu;
+ dma->dma_addr0 = tdma;
+ dma->cpu_addr1 = tcpu + size/2;
+ dma->dma_addr1 = tdma + size/2;
+ dma->size = size/2;
+ return 0;
+ }
+ return -ENOMEM;
+}
+EXPORT_SYMBOL(flexcop_dma_allocate);
+
+void flexcop_dma_free(struct flexcop_dma *dma)
+{
+ pci_free_consistent(dma->pdev, dma->size*2,dma->cpu_addr0, dma->dma_addr0);
+ memset(dma,0,sizeof(struct flexcop_dma));
+}
+EXPORT_SYMBOL(flexcop_dma_free);
+
+int flexcop_dma_control_timer_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff)
+{
+ flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208);
+
+ if (no & FC_DMA_1)
+ v.ctrl_208.DMA1_Timer_Enable_sig = onoff;
+
+ if (no & FC_DMA_2)
+ v.ctrl_208.DMA2_Timer_Enable_sig = onoff;
+
+ fc->write_ibi_reg(fc,ctrl_208,v);
+ return 0;
+}
+EXPORT_SYMBOL(flexcop_dma_control_timer_irq);
+
+int flexcop_dma_control_size_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff)
+{
+ flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208);
+
+ if (no & FC_DMA_1)
+ v.ctrl_208.DMA1_IRQ_Enable_sig = onoff;
+
+ if (no & FC_DMA_2)
+ v.ctrl_208.DMA2_IRQ_Enable_sig = onoff;
+
+ fc->write_ibi_reg(fc,ctrl_208,v);
+ return 0;
+}
+EXPORT_SYMBOL(flexcop_dma_control_size_irq);
+
+int flexcop_dma_control_packet_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff)
+{
+ flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208);
+
+ if (no & FC_DMA_1)
+ v.ctrl_208.DMA1_Size_IRQ_Enable_sig = onoff;
+
+ if (no & FC_DMA_2)
+ v.ctrl_208.DMA2_Size_IRQ_Enable_sig = onoff;
+
+ fc->write_ibi_reg(fc,ctrl_208,v);
+ return 0;
+}
+EXPORT_SYMBOL(flexcop_dma_control_packet_irq);
+
+int flexcop_dma_config(struct flexcop_device *fc, struct flexcop_dma *dma, flexcop_dma_index_t dma_idx,flexcop_dma_addr_index_t index)
+{
+
+ flexcop_ibi_value v0x0,v0x4,v0xc;
+ v0x0.raw = v0x4.raw = v0xc.raw = 0;
+
+ v0x0.dma_0x0.dma_address0 = dma->dma_addr0 >> 2;
+ v0xc.dma_0xc.dma_address1 = dma->dma_addr1 >> 2;
+ v0x4.dma_0x4_write.dma_addr_size = dma->size / 4;
+
+ if (index & FC_DMA_SUBADDR_0)
+ v0x0.dma_0x0.dma_0start = 1;
+
+ if (index & FC_DMA_SUBADDR_1)
+ v0xc.dma_0xc.dma_1start = 1;
+
+ if (dma_idx & FC_DMA_1) {
+ fc->write_ibi_reg(fc,dma1_000,v0x0);
+ fc->write_ibi_reg(fc,dma1_004,v0x4);
+ fc->write_ibi_reg(fc,dma1_00c,v0xc);
+ } else { /* (dma_idx & FC_DMA_2) */
+ fc->write_ibi_reg(fc,dma2_010,v0x0);
+ fc->write_ibi_reg(fc,dma2_014,v0x4);
+ fc->write_ibi_reg(fc,dma2_01c,v0xc);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(flexcop_dma_config);
+
+static int flexcop_dma_remap(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, int onoff)
+{
+ flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_00c : dma2_01c;
+ flexcop_ibi_value v = fc->read_ibi_reg(fc,r);
+ v.dma_0xc.remap_enable = onoff;
+ fc->write_ibi_reg(fc,r,v);
+ return 0;
+}
+
+/* 1 cycles = 1.97 msec */
+int flexcop_dma_config_timer(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 cycles)
+{
+ flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014;
+ flexcop_ibi_value v = fc->read_ibi_reg(fc,r);
+
+ flexcop_dma_remap(fc,dma_idx,0);
+
+ v.dma_0x4_write.dmatimer = cycles >> 1;
+ fc->write_ibi_reg(fc,r,v);
+ return 0;
+}
+EXPORT_SYMBOL(flexcop_dma_config_timer);
+
+int flexcop_dma_config_packet_count(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 packets)
+{
+ flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014;
+ flexcop_ibi_value v = fc->read_ibi_reg(fc,r);
+
+ flexcop_dma_remap(fc,dma_idx,1);
+
+ v.dma_0x4_remap.DMA_maxpackets = packets;
+ fc->write_ibi_reg(fc,r,v);
+ return 0;
+}
+EXPORT_SYMBOL(flexcop_dma_config_packet_count);
--- /dev/null
+/*
+ * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
+ *
+ * flexcop-eeprom.c - eeprom access methods (currently only MAC address reading is used)
+ *
+ * see flexcop.c for copyright information.
+ */
+#include "flexcop.h"
+
+#if 0
+/*EEPROM (Skystar2 has one "24LC08B" chip on board) */
+static int eeprom_write(struct adapter *adapter, u16 addr, u8 *buf, u16 len)
+{
+ return flex_i2c_write(adapter, 0x20000000, 0x50, addr, buf, len);
+}
+
+static int eeprom_lrc_write(struct adapter *adapter, u32 addr, u32 len, u8 *wbuf, u8 *rbuf, int retries)
+{
+ int i;
+
+ for (i = 0; i < retries; i++) {
+ if (eeprom_write(adapter, addr, wbuf, len) == len) {
+ if (eeprom_lrc_read(adapter, addr, len, rbuf, retries) == 1)
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* These functions could be used to unlock SkyStar2 cards. */
+
+static int eeprom_writeKey(struct adapter *adapter, u8 *key, u32 len)
+{
+ u8 rbuf[20];
+ u8 wbuf[20];
+
+ if (len != 16)
+ return 0;
+
+ memcpy(wbuf, key, len);
+
+ wbuf[16] = 0;
+ wbuf[17] = 0;
+ wbuf[18] = 0;
+ wbuf[19] = calc_lrc(wbuf, 19);
+
+ return eeprom_lrc_write(adapter, 0x3e4, 20, wbuf, rbuf, 4);
+}
+
+static int eeprom_readKey(struct adapter *adapter, u8 *key, u32 len)
+{
+ u8 buf[20];
+
+ if (len != 16)
+ return 0;
+
+ if (eeprom_lrc_read(adapter, 0x3e4, 20, buf, 4) == 0)
+ return 0;
+
+ memcpy(key, buf, len);
+
+ return 1;
+}
+
+static char eeprom_set_mac_addr(struct adapter *adapter, char type, u8 *mac)
+{
+ u8 tmp[8];
+
+ if (type != 0) {
+ tmp[0] = mac[0];
+ tmp[1] = mac[1];
+ tmp[2] = mac[2];
+ tmp[3] = mac[5];
+ tmp[4] = mac[6];
+ tmp[5] = mac[7];
+
+ } else {
+
+ tmp[0] = mac[0];
+ tmp[1] = mac[1];
+ tmp[2] = mac[2];
+ tmp[3] = mac[3];
+ tmp[4] = mac[4];
+ tmp[5] = mac[5];
+ }
+
+ tmp[6] = 0;
+ tmp[7] = calc_lrc(tmp, 7);
+
+ if (eeprom_write(adapter, 0x3f8, tmp, 8) == 8)
+ return 1;
+
+ return 0;
+}
+
+static int flexcop_eeprom_read(struct flexcop_device *fc, u16 addr, u8 *buf, u16 len)
+{
+ return fc->i2c_request(fc,FC_READ,FC_I2C_PORT_EEPROM,0x50,addr,buf,len);
+}
+
+#endif
+
+static u8 calc_lrc(u8 *buf, int len)
+{
+ int i;
+ u8 sum = 0;
+ for (i = 0; i < len; i++)
+ sum = sum ^ buf[i];
+ return sum;
+}
+
+static int flexcop_eeprom_request(struct flexcop_device *fc, flexcop_access_op_t op, u16 addr, u8 *buf, u16 len, int retries)
+{
+ int i,ret = 0;
+ u8 chipaddr = 0x50 | ((addr >> 8) & 3);
+ for (i = 0; i < retries; i++)
+ if ((ret = fc->i2c_request(fc,op,FC_I2C_PORT_EEPROM,chipaddr,addr & 0xff,buf,len)) == 0)
+ break;
+ return ret;
+}
+
+static int flexcop_eeprom_lrc_read(struct flexcop_device *fc, u16 addr, u8 *buf, u16 len, int retries)
+{
+ int ret = flexcop_eeprom_request(fc,FC_READ,addr,buf,len,retries);
+ if (ret == 0)
+ if (calc_lrc(buf, len - 1) != buf[len - 1])
+ ret = -EINVAL;
+ return ret;
+}
+
+/* JJ's comment about extended == 1: it is not presently used anywhere but was
+ * added to the low-level functions for possible support of EUI64
+ */
+int flexcop_eeprom_check_mac_addr(struct flexcop_device *fc, int extended)
+{
+ u8 buf[8];
+ int ret = 0;
+
+ if ((ret = flexcop_eeprom_lrc_read(fc,0x3f8,buf,8,4)) == 0) {
+ if (extended != 0) {
+ err("TODO: extended (EUI64) MAC addresses aren't completely supported yet");
+ ret = -EINVAL;
+/* memcpy(fc->dvb_adapter.proposed_mac,buf,3);
+ mac[3] = 0xfe;
+ mac[4] = 0xff;
+ memcpy(&fc->dvb_adapter.proposed_mac[3],&buf[5],3); */
+ } else
+ memcpy(fc->dvb_adapter.proposed_mac,buf,6);
+ }
+ return ret;
+}
+EXPORT_SYMBOL(flexcop_eeprom_check_mac_addr);
--- /dev/null
+/*
+ * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
+ *
+ * flexcop-hw-filter.c - pid and mac address filtering and corresponding control functions.
+ *
+ * see flexcop.c for copyright information.
+ */
+#include "flexcop.h"
+
+static void flexcop_rcv_data_ctrl(struct flexcop_device *fc, int onoff)
+{
+ flexcop_set_ibi_value(ctrl_208,Rcv_Data_sig,onoff);
+}
+
+void flexcop_smc_ctrl(struct flexcop_device *fc, int onoff)
+{
+ flexcop_set_ibi_value(ctrl_208,SMC_Enable_sig,onoff);
+}
+
+void flexcop_null_filter_ctrl(struct flexcop_device *fc, int onoff)
+{
+ flexcop_set_ibi_value(ctrl_208,Null_filter_sig,onoff);
+}
+
+void flexcop_set_mac_filter(struct flexcop_device *fc, u8 mac[6])
+{
+ flexcop_ibi_value v418,v41c;
+ v41c = fc->read_ibi_reg(fc,mac_address_41c);
+
+ v418.mac_address_418.MAC1 = mac[0];
+ v418.mac_address_418.MAC2 = mac[1];
+ v418.mac_address_418.MAC3 = mac[2];
+ v418.mac_address_418.MAC6 = mac[3];
+ v41c.mac_address_41c.MAC7 = mac[4];
+ v41c.mac_address_41c.MAC8 = mac[5];
+
+ fc->write_ibi_reg(fc,mac_address_418,v418);
+ fc->write_ibi_reg(fc,mac_address_41c,v41c);
+}
+
+void flexcop_mac_filter_ctrl(struct flexcop_device *fc, int onoff)
+{
+ flexcop_set_ibi_value(ctrl_208,MAC_filter_Mode_sig,onoff);
+}
+
+static void flexcop_pid_group_filter(struct flexcop_device *fc, u16 pid, u16 mask)
+{
+ /* index_reg_310.extra_index_reg need to 0 or 7 to work */
+ flexcop_ibi_value v30c;
+ v30c.pid_filter_30c_ext_ind_0_7.Group_PID = pid;
+ v30c.pid_filter_30c_ext_ind_0_7.Group_mask = mask;
+ fc->write_ibi_reg(fc,pid_filter_30c,v30c);
+}
+
+static void flexcop_pid_group_filter_ctrl(struct flexcop_device *fc, int onoff)
+{
+ flexcop_set_ibi_value(ctrl_208,Mask_filter_sig,onoff);
+}
+
+/* this fancy define reduces the code size of the quite similar PID controlling of
+ * the first 6 PIDs
+ */
+
+#define pid_ctrl(vregname,field,enablefield,trans_field,transval) \
+ flexcop_ibi_value vpid = fc->read_ibi_reg(fc, vregname), \
+ v208 = fc->read_ibi_reg(fc, ctrl_208); \
+\
+ vpid.vregname.field = onoff ? pid : 0x1fff; \
+ vpid.vregname.trans_field = transval; \
+ v208.ctrl_208.enablefield = onoff; \
+\
+ fc->write_ibi_reg(fc,vregname,vpid); \
+ fc->write_ibi_reg(fc,ctrl_208,v208);
+
+static void flexcop_pid_Stream1_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff)
+{
+ pid_ctrl(pid_filter_300,Stream1_PID,Stream1_filter_sig,Stream1_trans,0);
+}
+
+static void flexcop_pid_Stream2_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff)
+{
+ pid_ctrl(pid_filter_300,Stream2_PID,Stream2_filter_sig,Stream2_trans,0);
+}
+
+static void flexcop_pid_PCR_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff)
+{
+ pid_ctrl(pid_filter_304,PCR_PID,PCR_filter_sig,PCR_trans,0);
+}
+
+static void flexcop_pid_PMT_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff)
+{
+ pid_ctrl(pid_filter_304,PMT_PID,PMT_filter_sig,PMT_trans,0);
+}
+
+static void flexcop_pid_EMM_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff)
+{
+ pid_ctrl(pid_filter_308,EMM_PID,EMM_filter_sig,EMM_trans,0);
+}
+
+static void flexcop_pid_ECM_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff)
+{
+ pid_ctrl(pid_filter_308,ECM_PID,ECM_filter_sig,ECM_trans,0);
+}
+
+static void flexcop_pid_control(struct flexcop_device *fc, int index, u16 pid,int onoff)
+{
+ if (pid == 0x2000)
+ return;
+
+ deb_ts("setting pid: %5d %04x at index %d '%s'\n",pid,pid,index,onoff ? "on" : "off");
+
+ /* We could use bit magic here to reduce source code size.
+ * I decided against it, but to use the real register names */
+ switch (index) {
+ case 0: flexcop_pid_Stream1_PID_ctrl(fc,pid,onoff); break;
+ case 1: flexcop_pid_Stream2_PID_ctrl(fc,pid,onoff); break;
+ case 2: flexcop_pid_PCR_PID_ctrl(fc,pid,onoff); break;
+ case 3: flexcop_pid_PMT_PID_ctrl(fc,pid,onoff); break;
+ case 4: flexcop_pid_EMM_PID_ctrl(fc,pid,onoff); break;
+ case 5: flexcop_pid_ECM_PID_ctrl(fc,pid,onoff); break;
+ default:
+ if (fc->has_32_hw_pid_filter && index < 38) {
+ flexcop_ibi_value vpid,vid;
+
+ /* set the index */
+ vid = fc->read_ibi_reg(fc,index_reg_310);
+ vid.index_reg_310.index_reg = index - 6;
+ fc->write_ibi_reg(fc,index_reg_310, vid);
+
+ vpid = fc->read_ibi_reg(fc,pid_n_reg_314);
+ vpid.pid_n_reg_314.PID = onoff ? pid : 0x1fff;
+ vpid.pid_n_reg_314.PID_enable_bit = onoff;
+ fc->write_ibi_reg(fc,pid_n_reg_314, vpid);
+ }
+ break;
+ }
+}
+
+static int flexcop_toggle_fullts_streaming(struct flexcop_device *fc,int onoff)
+{
+ if (fc->fullts_streaming_state != onoff) {
+ deb_ts("%s full TS transfer\n",onoff ? "enabling" : "disabling");
+ flexcop_pid_group_filter(fc, 0, 0x1fe0 * (!onoff));
+ flexcop_pid_group_filter_ctrl(fc,onoff);
+ fc->fullts_streaming_state = onoff;
+ }
+ return 0;
+}
+
+int flexcop_pid_feed_control(struct flexcop_device *fc, struct dvb_demux_feed *dvbdmxfeed, int onoff)
+{
+ int max_pid_filter = 6 + fc->has_32_hw_pid_filter*32;
+
+ fc->feedcount += onoff ? 1 : -1;
+ if (dvbdmxfeed->index >= max_pid_filter)
+ fc->extra_feedcount += onoff ? 1 : -1;
+
+ /* toggle complete-TS-streaming when:
+ * - pid_filtering is not enabled and it is the first or last feed requested
+ * - pid_filtering is enabled,
+ * - but the number of requested feeds is exceeded
+ * - or the requested pid is 0x2000 */
+
+ if (!fc->pid_filtering && fc->feedcount == onoff)
+ flexcop_toggle_fullts_streaming(fc,onoff);
+
+ if (fc->pid_filtering) {
+ flexcop_pid_control(fc,dvbdmxfeed->index,dvbdmxfeed->pid,onoff);
+
+ if (fc->extra_feedcount > 0)
+ flexcop_toggle_fullts_streaming(fc,1);
+ else if (dvbdmxfeed->pid == 0x2000)
+ flexcop_toggle_fullts_streaming(fc,onoff);
+ else
+ flexcop_toggle_fullts_streaming(fc,0);
+ }
+
+ /* if it was the first or last feed request change the stream-status */
+ if (fc->feedcount == onoff) {
+ flexcop_rcv_data_ctrl(fc,onoff);
+ if (fc->stream_control)
+ fc->stream_control(fc,onoff);
+ }
+
+ return 0;
+}
+
+void flexcop_hw_filter_init(struct flexcop_device *fc)
+{
+ int i;
+ flexcop_ibi_value v;
+ for (i = 0; i < 6 + 32*fc->has_32_hw_pid_filter; i++)
+ flexcop_pid_control(fc,i,0x1fff,0);
+
+ flexcop_pid_group_filter(fc, 0, 0x1fe0);
+ flexcop_pid_group_filter_ctrl(fc,0);
+
+ v = fc->read_ibi_reg(fc,pid_filter_308);
+ v.pid_filter_308.EMM_filter_4 = 1;
+ v.pid_filter_308.EMM_filter_6 = 0;
+ fc->write_ibi_reg(fc,pid_filter_308,v);
+
+ flexcop_null_filter_ctrl(fc, 1);
+}
--- /dev/null
+/*
+ * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
+ *
+ * flexcop-misc.c - miscellaneous functions.
+ *
+ * see flexcop.c for copyright information.
+ */
+#include "flexcop.h"
+
+void flexcop_determine_revision(struct flexcop_device *fc)
+{
+ flexcop_ibi_value v = fc->read_ibi_reg(fc,misc_204);
+
+ switch (v.misc_204.Rev_N_sig_revision_hi) {
+ case 0x2:
+ deb_info("found a FlexCopII.\n");
+ fc->rev = FLEXCOP_II;
+ break;
+ case 0x3:
+ deb_info("found a FlexCopIIb.\n");
+ fc->rev = FLEXCOP_IIB;
+ break;
+ case 0x0:
+ deb_info("found a FlexCopIII.\n");
+ fc->rev = FLEXCOP_III;
+ break;
+ default:
+ err("unkown FlexCop Revision: %x. Please report the linux-dvb@linuxtv.org.",v.misc_204.Rev_N_sig_revision_hi);
+ break;
+ }
+
+ if ((fc->has_32_hw_pid_filter = v.misc_204.Rev_N_sig_caps))
+ deb_info("this FlexCop has the additional 32 hardware pid filter.\n");
+ else
+ deb_info("this FlexCop has only the 6 basic main hardware pid filter.\n");
+ /* bus parts have to decide if hw pid filtering is used or not. */
+}
+
+const char *flexcop_revision_names[] = {
+ "Unkown chip",
+ "FlexCopII",
+ "FlexCopIIb",
+ "FlexCopIII",
+};
+
+const char *flexcop_device_names[] = {
+ "Unkown device",
+ "AirStar 2 DVB-T",
+ "AirStar 2 ATSC",
+ "SkyStar 2 DVB-S",
+ "SkyStar 2 DVB-S (old version)",
+ "CableStar 2 DVB-C",
+};
+
+const char *flexcop_bus_names[] = {
+ "USB",
+ "PCI",
+};
+
+void flexcop_device_name(struct flexcop_device *fc,const char *prefix,const
+ char *suffix)
+{
+ info("%s '%s' at the '%s' bus controlled by a '%s' %s",prefix,
+ flexcop_device_names[fc->dev_type],flexcop_bus_names[fc->bus_type],
+ flexcop_revision_names[fc->rev],suffix);
+}
--- /dev/null
+/*
+ * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
+ *
+ * flexcop-reg.h - register abstraction for FlexCopII, FlexCopIIb and FlexCopIII
+ *
+ * see flexcop.c for copyright information.
+ */
+#ifndef __FLEXCOP_REG_H__
+#define __FLEXCOP_REG_H__
+
+
+typedef enum {
+ FLEXCOP_UNK = 0,
+ FLEXCOP_II,
+ FLEXCOP_IIB,
+ FLEXCOP_III,
+} flexcop_revision_t;
+
+extern const char *flexcop_revision_names[];
+
+typedef enum {
+ FC_UNK = 0,
+ FC_AIR_DVB,
+ FC_AIR_ATSC,
+ FC_SKY,
+ FC_SKY_OLD,
+ FC_CABLE,
+} flexcop_device_type_t;
+
+typedef enum {
+ FC_USB = 0,
+ FC_PCI,
+} flexcop_bus_t;
+
+extern const char *flexcop_device_names[];
+
+/* FlexCop IBI Registers */
+
+/* flexcop_ibi_reg - a huge union representing the register structure */
+typedef union {
+ u32 raw;
+
+/* DMA 0x000 to 0x01c
+ * DMA1 0x000 to 0x00c
+ * DMA2 0x010 to 0x01c
+ */
+ struct {
+ u32 dma_0start : 1; /* set: data will be delivered to dma1_address0 */
+ u32 dma_0No_update : 1; /* set: dma1_cur_address will be updated, unset: no update */
+ u32 dma_address0 :30; /* physical/virtual host memory address0 DMA */
+ } dma_0x0;
+
+ struct {
+ u32 DMA_maxpackets : 8; /* (remapped) PCI DMA1 Packet Count Interrupt. This variable
+ is able to be read and written while bit(1) of register
+ 0x00c (remap_enable) is set. This variable represents
+ the number of packets that will be transmitted to the PCI
+ host using PCI DMA1 before an interrupt to the PCI is
+ asserted. This functionality may be enabled using bit(20)
+ of register 0x208. N=0 disables the IRQ. */
+ u32 dma_addr_size :24; /* size of memory buffer in DWORDs (bytesize / 4) for DMA */
+ } dma_0x4_remap;
+
+ struct {
+ u32 dma1timer : 7; /* reading PCI DMA1 timer ... when remap_enable is 0 */
+ u32 unused : 1;
+ u32 dma_addr_size :24;
+ } dma_0x4_read;
+
+ struct {
+ u32 unused : 1;
+ u32 dmatimer : 7; /* writing PCI DMA1 timer ... when remap_enable is 0 */
+ u32 dma_addr_size :24;
+ } dma_0x4_write;
+
+ struct {
+ u32 unused : 2;
+ u32 dma_cur_addr :30; /* current physical host memory address pointer for DMA */
+ } dma_0x8;
+
+ struct {
+ u32 dma_1start : 1; /* set: data will be delivered to dma_address1, when dma_address0 is full */
+ u32 remap_enable : 1; /* remap enable for 0x0x4(7:0) */
+ u32 dma_address1 :30; /* Physical/virtual address 1 on DMA */
+ } dma_0xc;
+
+/* Two-wire Serial Master and Clock 0x100-0x110 */
+ struct {
+// u32 slave_transmitter : 1; /* ???*/
+ u32 chipaddr : 7; /* two-line serial address of the target slave */
+ u32 reserved1 : 1;
+ u32 baseaddr : 8; /* address of the location of the read/write operation */
+ u32 data1_reg : 8; /* first byte in two-line serial read/write operation */
+ u32 working_start : 1; /* when doing a write operation this indicator is 0 when ready
+ * set to 1 when doing a write operation */
+ u32 twoWS_rw : 1; /* read/write indicator (1 = read, 0 write) */
+ u32 total_bytes : 2; /* number of data bytes in each two-line serial transaction (0 = 1 byte, 11 = 4byte)*/
+ u32 twoWS_port_reg : 2; /* port selection: 01 - Front End/Demod, 10 - EEPROM, 11 - Tuner */
+ u32 no_base_addr_ack_error : 1; /* writing: write-req: frame is produced w/o baseaddr, read-req: read-cycles w/o
+ * preceding address assignment write frame
+ * ACK_ERROR = 1 when no ACK from slave in the last transaction */
+ u32 st_done : 1; /* indicator for transaction is done */
+ } tw_sm_c_100;
+
+ struct {
+ u32 data2_reg : 8; /* 2nd data byte */
+ u32 data3_reg : 8; /* 3rd data byte */
+ u32 data4_reg : 8; /* 4th data byte */
+ u32 exlicit_stops : 1; /* when set, transactions are produced w/o trailing STOP flag, then send isolated STOP flags */
+ u32 force_stop : 1; /* isolated stop flag */
+ u32 unused : 6;
+ } tw_sm_c_104;
+
+/* Clock. The register allows the FCIII to convert an incoming Master clock
+ * (MCLK) signal into a lower frequency clock through the use of a LowCounter
+ * (TLO) and a High- Counter (THI). The time counts for THI and TLO are
+ * measured in MCLK; each count represents 4 MCLK input clock cycles.
+ *
+ * The default output for port #1 is set for Front End Demod communication. (0x108)
+ * The default output for port #2 is set for EEPROM communication. (0x10c)
+ * The default output for port #3 is set for Tuner communication. (0x110)
+ */
+ struct {
+ u32 thi1 : 6; /* Thi for port #1 (def: 100110b; 38) */
+ u32 reserved1 : 2;
+ u32 tlo1 : 5; /* Tlo for port #1 (def: 11100b; 28) */
+ u32 reserved2 :19;
+ } tw_sm_c_108;
+
+ struct {
+ u32 thi1 : 6; /* Thi for port #2 (def: 111001b; 57) */
+ u32 reserved1 : 2;
+ u32 tlo1 : 5; /* Tlo for port #2 (def: 11100b; 28) */
+ u32 reserved2 :19;
+ } tw_sm_c_10c;
+
+ struct {
+ u32 thi1 : 6; /* Thi for port #3 (def: 111001b; 57) */
+ u32 reserved1 : 2;
+ u32 tlo1 : 5; /* Tlo for port #3 (def: 11100b; 28) */
+ u32 reserved2 :19;
+ } tw_sm_c_110;
+
+/* LNB Switch Frequency 0x200
+ * Clock that creates the LNB switch tone. The default is set to have a fixed
+ * low output (not oscillating) to the LNB_CTL line.
+ */
+ struct {
+ u32 LNB_CTLHighCount_sig :15; /* It is the number of pre-scaled clock cycles that will be low. */
+ u32 LNB_CTLLowCount_sig :15; /* For example, to obtain a 22KHz output given a 45 Mhz Master
+ Clock signal (MCLK), set PreScalar=01 and LowCounter value to 0x1ff. */
+ u32 LNB_CTLPrescaler_sig : 2; /* pre-scaler divides MCLK: 00 (no division), 01 by 2, 10 by 4, 11 by 12 */
+ } lnb_switch_freq_200;
+
+/* ACPI, Peripheral Reset, LNB Polarity
+ * ACPI power conservation mode, LNB polarity selection (low or high voltage),
+ * and peripheral reset.
+ */
+ struct {
+ u32 ACPI1_sig : 1; /* turn of the power of tuner and LNB, not implemented in FCIII */
+ u32 ACPI3_sig : 1; /* turn of power of the complete satelite receiver board (except FCIII) */
+ u32 LNB_L_H_sig : 1; /* low or high voltage for LNB. (0 = low, 1 = high) */
+ u32 Per_reset_sig : 1; /* misc. init reset (default: 1), to reset set to low and back to high */
+ u32 reserved :20;
+ u32 Rev_N_sig_revision_hi : 4;/* 0xc in case of FCIII */
+ u32 Rev_N_sig_reserved1 : 2;
+ u32 Rev_N_sig_caps : 1; /* if 1, FCIII has 32 PID- and MAC-filters and is capable of IP multicast */
+ u32 Rev_N_sig_reserved2 : 1;
+ } misc_204;
+
+/* Control and Status 0x208 to 0x21c */
+/* Gross enable and disable control */
+ struct {
+ u32 Stream1_filter_sig : 1; /* Stream1 PID filtering */
+ u32 Stream2_filter_sig : 1; /* Stream2 PID filtering */
+ u32 PCR_filter_sig : 1; /* PCR PID filter */
+ u32 PMT_filter_sig : 1; /* PMT PID filter */
+
+ u32 EMM_filter_sig : 1; /* EMM PID filter */
+ u32 ECM_filter_sig : 1; /* ECM PID filter */
+ u32 Null_filter_sig : 1; /* Filters null packets, PID=0x1fff. */
+ u32 Mask_filter_sig : 1; /* mask PID filter */
+
+ u32 WAN_Enable_sig : 1; /* WAN output line through V8 memory space is activated. */
+ u32 WAN_CA_Enable_sig : 1; /* not in FCIII */
+ u32 CA_Enable_sig : 1; /* not in FCIII */
+ u32 SMC_Enable_sig : 1; /* CI stream data (CAI) goes directly to the smart card intf (opposed IBI 0x600 or SC-cmd buf). */
+
+ u32 Per_CA_Enable_sig : 1; /* not in FCIII */
+ u32 Multi2_Enable_sig : 1; /* ? */
+ u32 MAC_filter_Mode_sig : 1; /* (MAC_filter_enable) Globally enables MAC filters for Net PID filteres. */
+ u32 Rcv_Data_sig : 1; /* PID filtering module enable. When this bit is a one, the PID filter will
+ examine and process packets according to all other (individual) PID
+ filtering controls. If it a zero, no packet processing of any kind will
+ take place. All data from the tuner will be thrown away. */
+
+ u32 DMA1_IRQ_Enable_sig : 1; /* When set, a DWORD counter is enabled on PCI DMA1 that asserts the PCI
+ * interrupt after the specified count for filling the buffer. */
+ u32 DMA1_Timer_Enable_sig : 1; /* When set, a timer is enabled on PCI DMA1 that asserts the PCI interrupt
+ after a specified amount of time. */
+ u32 DMA2_IRQ_Enable_sig : 1; /* same as DMA1_IRQ_Enable_sig but for DMA2 */
+ u32 DMA2_Timer_Enable_sig : 1; /* same as DMA1_Timer_Enable_sig but for DMA2 */
+
+ u32 DMA1_Size_IRQ_Enable_sig : 1; /* When set, a packet count detector is enabled on PCI DMA1 that asserts the PCI interrupt. */
+ u32 DMA2_Size_IRQ_Enable_sig : 1; /* When set, a packet count detector is enabled on PCI DMA2 that asserts the PCI interrupt. */
+ u32 Mailbox_from_V8_Enable_sig: 1; /* When set, writes to the mailbox register produce an interrupt to the
+ PCI host to indicate that mailbox data is available. */
+
+ u32 unused : 9;
+ } ctrl_208;
+
+/* General status. When a PCI interrupt occurs, this register is read to
+ * discover the reason for the interrupt.
+ */
+ struct {
+ u32 DMA1_IRQ_Status : 1; /* When set(1) the DMA1 counter had generated an IRQ. Read Only. */
+ u32 DMA1_Timer_Status : 1; /* When set(1) the DMA1 timer had generated an IRQ. Read Only. */
+ u32 DMA2_IRQ_Status : 1; /* When set(1) the DMA2 counter had generated an IRQ. Read Only. */
+ u32 DMA2_Timer_Status : 1; /* When set(1) the DMA2 timer had generated an IRQ. Read Only. */
+ u32 DMA1_Size_IRQ_Status : 1; /* (Read only). This register is read after an interrupt to */
+ u32 DMA2_Size_IRQ_Status : 1; /* find out why we had an IRQ. Reading this register will clear this bit. Packet count*/
+ u32 Mailbox_from_V8_Status_sig: 1; /* Same as above. Reading this register will clear this bit. */
+ u32 Data_receiver_error : 1; /* 1 indicate an error in the receiver Front End (Tuner module) */
+ u32 Continuity_error_flag : 1; /* 1 indicates a continuity error in the TS stream. */
+ u32 LLC_SNAP_FLAG_set : 1; /* 1 indicates that the LCC_SNAP_FLAG was set. */
+ u32 Transport_Error : 1; /* When set indicates that an unexpected packet was received. */
+ u32 reserved :21;
+ } irq_20c;
+
+
+/* Software reset register */
+ struct {
+ u32 reset_blocks : 8; /* Enabled when Block_reset_enable = 0xB2 and 0x208 bits 15:8 = 0x00.
+ Each bit location represents a 0x100 block of registers. Writing
+ a one in a bit location resets that block of registers and the logic
+ that it controls. */
+ u32 Block_reset_enable : 8; /* This variable is set to 0xB2 when the register is written. */
+ u32 Special_controls :16; /* Asserts Reset_V8 => 0xC258; Turns on pci encryption => 0xC25A;
+ Turns off pci encryption => 0xC259 Note: pci_encryption default
+ at power-up is ON. */
+ } sw_reset_210;
+
+ struct {
+ u32 vuart_oe_sig : 1; /* When clear, the V8 processor has sole control of the serial UART
+ (RS-232 Smart Card interface). When set, the IBI interface
+ defined by register 0x600 controls the serial UART. */
+ u32 v2WS_oe_sig : 1; /* When clear, the V8 processor has direct control of the Two-line
+ Serial Master EEPROM target. When set, the Two-line Serial Master
+ EEPROM target interface is controlled by IBI register 0x100. */
+ u32 halt_V8_sig : 1; /* When set, contiguous wait states are applied to the V8-space
+ bus masters. Once this signal is cleared, normal V8-space
+ operations resume. */
+ u32 section_pkg_enable_sig: 1; /* When set, this signal enables the front end translation circuitry
+ to process section packed transport streams. */
+ u32 s2p_sel_sig : 1; /* Serial to parallel conversion. When set, polarized transport data
+ within the FlexCop3 front end circuitry is converted from a serial
+ stream into parallel data before downstream processing otherwise
+ interprets the data. */
+ u32 unused1 : 3;
+ u32 polarity_PS_CLK_sig: 1; /* This signal is used to invert the input polarity of the tranport
+ stream CLOCK signal before any processing occurs on the transport
+ stream within FlexCop3. */
+ u32 polarity_PS_VALID_sig: 1; /* This signal is used to invert the input polarity of the tranport
+ stream VALID signal before any processing occurs on the transport
+ stream within FlexCop3. */
+ u32 polarity_PS_SYNC_sig: 1; /* This signal is used to invert the input polarity of the tranport
+ stream SYNC signal before any processing occurs on the transport
+ stream within FlexCop3. */
+ u32 polarity_PS_ERR_sig: 1; /* This signal is used to invert the input polarity of the tranport
+ stream ERROR signal before any processing occurs on the transport
+ stream within FlexCop3. */
+ u32 unused2 :20;
+ } misc_214;
+
+/* Mailbox from V8 to host */
+ struct {
+ u32 Mailbox_from_V8 :32; /* When this register is written by either the V8 processor or by an
+ end host, an interrupt is generated to the PCI host to indicate
+ that mailbox data is available. Reading register 20c will clear
+ the IRQ. */
+ } mbox_v8_to_host_218;
+
+/* Mailbox from host to v8 Mailbox_to_V8
+ * Mailbox_to_V8 mailbox storage register
+ * used to send messages from PCI to V8. Writing to this register will send an
+ * IRQ to the V8. Then it can read the data from here. Reading this register
+ * will clear the IRQ. If the V8 is halted and bit 31 of this register is set,
+ * then this register is used instead as a direct interface to access the
+ * V8space memory.
+ */
+ struct {
+ u32 sysramaccess_data : 8; /* Data byte written or read from the specified address in V8 SysRAM. */
+ u32 sysramaccess_addr :15; /* 15 bit address used to access V8 Sys-RAM. */
+ u32 unused : 7;
+ u32 sysramaccess_write: 1; /* Write flag used to latch data into the V8 SysRAM. */
+ u32 sysramaccess_busmuster: 1; /* Setting this bit when the V8 is halted at 0x214 Bit(2) allows
+ this IBI register interface to directly drive the V8-space memory. */
+ } mbox_host_to_v8_21c;
+
+
+/* PIDs, Translation Bit, SMC Filter Select 0x300 to 0x31c */
+ struct {
+ u32 Stream1_PID :13; /* Primary use is receiving Net data, so these 13 bits normally
+ hold the PID value for the desired network stream. */
+ u32 Stream1_trans : 1; /* When set, Net translation will take place for Net data ferried in TS packets. */
+ u32 MAC_Multicast_filter : 1; /* When clear, multicast MAC filtering is not allowed for Stream1 and PID_n filters. */
+ u32 debug_flag_pid_saved : 1;
+ u32 Stream2_PID :13; /* 13 bits for Stream 2 PID filter value. General use. */
+ u32 Stream2_trans : 1; /* When set Tables/CAI translation will take place for the data ferried in
+ Stream2_PID TS packets. */
+ u32 debug_flag_write_status00 : 1;
+ u32 debug_fifo_problem : 1;
+ } pid_filter_300;
+
+ struct {
+ u32 PCR_PID :13; /* PCR stream PID filter value. Primary use is Program Clock Reference stream filtering. */
+ u32 PCR_trans : 1; /* When set, Tables/CAI translation will take place for these packets. */
+ u32 debug_overrun3 : 1;
+ u32 debug_overrun2 : 1;
+ u32 PMT_PID :13; /* stream PID filter value. Primary use is Program Management Table segment filtering. */
+ u32 PMT_trans : 1; /* When set, Tables/CAI translation will take place for these packets. */
+ u32 reserved : 2;
+ } pid_filter_304;
+
+ struct {
+ u32 EMM_PID :13; /* EMM PID filter value. Primary use is Entitlement Management Messaging for
+ conditional access-related data. */
+ u32 EMM_trans : 1; /* When set, Tables/CAI translation will take place for these packets. */
+ u32 EMM_filter_4 : 1; /* When set will pass only EMM data possessing the same ID code as the
+ first four bytes (32 bits) of the end-user s 6-byte Smart Card ID number Select */
+ u32 EMM_filter_6 : 1; /* When set will pass only EMM data possessing the same 6-byte code as the end-users
+ complete 6-byte Smart Card ID number. */
+ u32 ECM_PID :13; /* ECM PID filter value. Primary use is Entitlement Control Messaging for conditional
+ access-related data. */
+ u32 ECM_trans : 1; /* When set, Tables/CAI translation will take place for these packets. */
+ u32 reserved : 2;
+ } pid_filter_308;
+
+ struct {
+ u32 Group_PID :13; /* PID value for group filtering. */
+ u32 Group_trans : 1; /* When set, Tables/CAI translation will take place for these packets. */
+ u32 unused1 : 2;
+ u32 Group_mask :13; /* Mask value used in logical "and" equation that defines group filtering */
+ u32 unused2 : 3;
+ } pid_filter_30c_ext_ind_0_7;
+
+ struct {
+ u32 net_master_read :17;
+ u32 unused :15;
+ } pid_filter_30c_ext_ind_1;
+
+ struct {
+ u32 net_master_write :17;
+ u32 unused :15;
+ } pid_filter_30c_ext_ind_2;
+
+ struct {
+ u32 next_net_master_write :17;
+ u32 unused :15;
+ } pid_filter_30c_ext_ind_3;
+
+ struct {
+ u32 unused1 : 1;
+ u32 state_write :10;
+ u32 reserved1 : 6; /* default: 000100 */
+ u32 stack_read :10;
+ u32 reserved2 : 5; /* default: 00100 */
+ } pid_filter_30c_ext_ind_4;
+
+ struct {
+ u32 stack_cnt :10;
+ u32 unused :22;
+ } pid_filter_30c_ext_ind_5;
+
+ struct {
+ u32 pid_fsm_save_reg0 : 2;
+ u32 pid_fsm_save_reg1 : 2;
+ u32 pid_fsm_save_reg2 : 2;
+ u32 pid_fsm_save_reg3 : 2;
+ u32 pid_fsm_save_reg4 : 2;
+ u32 pid_fsm_save_reg300 : 2;
+ u32 write_status1 : 2;
+ u32 write_status4 : 2;
+ u32 data_size_reg :12;
+ u32 unused : 4;
+ } pid_filter_30c_ext_ind_6;
+
+ struct {
+ u32 index_reg : 5; /* (Index pointer) Points at an internal PIDn register. A binary code
+ representing one of 32 internal PIDn registers as well as its
+ corresponding internal MAC_lown register. */
+ u32 extra_index_reg : 3; /* This vector is used to select between sets of debug signals routed to register 0x30c. */
+ u32 AB_select : 1; /* Used in conjunction with 0x31c. read/write to the MAC_highA or MAC_highB register
+ 0=MAC_highB register, 1=MAC_highA */
+ u32 pass_alltables : 1; /* 1=Net packets are not filtered against the Network Table ID found in register 0x400.
+ All types of networks (DVB, ATSC, ISDB) are passed. */
+ u32 unused :22;
+ } index_reg_310;
+
+ struct {
+ u32 PID :13; /* PID value */
+ u32 PID_trans : 1; /* translation will take place for packets filtered */
+ u32 PID_enable_bit : 1; /* When set this PID filter is enabled */
+ u32 reserved :17;
+ } pid_n_reg_314;
+
+ struct {
+ u32 A4_byte : 8;
+ u32 A5_byte : 8;
+ u32 A6_byte : 8;
+ u32 Enable_bit : 1; /* enabled (1) or disabled (1) */
+ u32 HighAB_bit : 1; /* use MAC_highA (1) or MAC_highB (0) as MSB */
+ u32 reserved : 6;
+ } mac_low_reg_318;
+
+ struct {
+ u32 A1_byte : 8;
+ u32 A2_byte : 8;
+ u32 A3_byte : 8;
+ u32 reserved : 8;
+ } mac_high_reg_31c;
+
+/* Table, SMCID,MACDestination Filters 0x400 to 0x41c */
+ struct {
+ u32 reserved :16;
+#define fc_data_Tag_ID_DVB 0x3e
+#define fc_data_Tag_ID_ATSC 0x3f
+#define fc_data_Tag_ID_IDSB 0x8b
+ u32 data_Tag_ID :16;
+ } data_tag_400;
+
+ struct {
+ u32 Card_IDbyte6 : 8;
+ u32 Card_IDbyte5 : 8;
+ u32 Card_IDbyte4 : 8;
+ u32 Card_IDbyte3 : 8;
+ } card_id_408;
+
+ struct {
+ u32 Card_IDbyte2 : 8;
+ u32 Card_IDbyte1 : 8;
+ } card_id_40c;
+
+ /* holding the unique mac address of the receiver which houses the FlexCopIII */
+ struct {
+ u32 MAC1 : 8;
+ u32 MAC2 : 8;
+ u32 MAC3 : 8;
+ u32 MAC6 : 8;
+ } mac_address_418;
+
+ struct {
+ u32 MAC7 : 8;
+ u32 MAC8 : 8;
+ u32 reserved : 16;
+ } mac_address_41c;
+
+ struct {
+ u32 transmitter_data_byte : 8;
+ u32 ReceiveDataReady : 1;
+ u32 ReceiveByteFrameError: 1;
+ u32 txbuffempty : 1;
+ u32 reserved :21;
+ } ci_600;
+
+ struct {
+ u32 pi_d : 8;
+ u32 pi_ha :20;
+ u32 pi_rw : 1;
+ u32 pi_component_reg : 3;
+ } pi_604;
+
+ struct {
+ u32 serialReset : 1;
+ u32 oncecycle_read : 1;
+ u32 Timer_Read_req : 1;
+ u32 Timer_Load_req : 1;
+ u32 timer_data : 7;
+ u32 unused : 1; /* ??? not mentioned in data book */
+ u32 Timer_addr : 5;
+ u32 reserved : 3;
+ u32 pcmcia_a_mod_pwr_n : 1;
+ u32 pcmcia_b_mod_pwr_n : 1;
+ u32 config_Done_stat : 1;
+ u32 config_Init_stat : 1;
+ u32 config_Prog_n : 1;
+ u32 config_wr_n : 1;
+ u32 config_cs_n : 1;
+ u32 config_cclk : 1;
+ u32 pi_CiMax_IRQ_n : 1;
+ u32 pi_timeout_status : 1;
+ u32 pi_wait_n : 1;
+ u32 pi_busy_n : 1;
+ } pi_608;
+
+ struct {
+ u32 PID :13;
+ u32 key_enable : 1;
+#define fc_key_code_default 0x1
+#define fc_key_code_even 0x2
+#define fc_key_code_odd 0x3
+ u32 key_code : 2;
+ u32 key_array_col : 3;
+ u32 key_array_row : 5;
+ u32 dvb_en : 1; /* 0=TS bypasses the Descrambler */
+ u32 rw_flag : 1;
+ u32 reserved : 6;
+ } dvb_reg_60c;
+
+/* SRAM and Output Destination 0x700 to 0x714 */
+ struct {
+ u32 sram_addr :15;
+ u32 sram_rw : 1; /* 0=write, 1=read */
+ u32 sram_data : 8;
+ u32 sc_xfer_bit : 1;
+ u32 reserved1 : 3;
+ u32 oe_pin_reg : 1;
+ u32 ce_pin_reg : 1;
+ u32 reserved2 : 1;
+ u32 start_sram_ibi : 1;
+ } sram_ctrl_reg_700;
+
+ struct {
+ u32 net_addr_read :16;
+ u32 net_addr_write :16;
+ } net_buf_reg_704;
+
+ struct {
+ u32 cai_read :11;
+ u32 reserved1 : 5;
+ u32 cai_write :11;
+ u32 reserved2 : 6;
+ u32 cai_cnt : 4;
+ } cai_buf_reg_708;
+
+ struct {
+ u32 cao_read :11;
+ u32 reserved1 : 5;
+ u32 cap_write :11;
+ u32 reserved2 : 6;
+ u32 cao_cnt : 4;
+ } cao_buf_reg_70c;
+
+ struct {
+ u32 media_read :11;
+ u32 reserved1 : 5;
+ u32 media_write :11;
+ u32 reserved2 : 6;
+ u32 media_cnt : 4;
+ } media_buf_reg_710;
+
+ struct {
+ u32 NET_Dest : 2;
+ u32 CAI_Dest : 2;
+ u32 CAO_Dest : 2;
+ u32 MEDIA_Dest : 2;
+ u32 net_ovflow_error : 1;
+ u32 media_ovflow_error : 1;
+ u32 cai_ovflow_error : 1;
+ u32 cao_ovflow_error : 1;
+ u32 ctrl_usb_wan : 1;
+ u32 ctrl_sramdma : 1;
+ u32 ctrl_maximumfill : 1;
+ u32 reserved :17;
+ } sram_dest_reg_714;
+
+ struct {
+ u32 net_cnt :12;
+ u32 reserved1 : 4;
+ u32 net_addr_read : 1;
+ u32 reserved2 : 3;
+ u32 net_addr_write : 1;
+ u32 reserved3 :11;
+ } net_buf_reg_718;
+
+ struct {
+ u32 wan_speed_sig : 2;
+ u32 reserved1 : 6;
+ u32 wan_wait_state : 8;
+ u32 sram_chip : 2;
+ u32 sram_memmap : 2;
+ u32 reserved2 : 4;
+ u32 wan_pkt_frame : 4;
+ u32 reserved3 : 4;
+ } wan_ctrl_reg_71c;
+} flexcop_ibi_value;
+
+extern flexcop_ibi_value ibi_zero;
+
+typedef enum {
+ FC_I2C_PORT_DEMOD = 1,
+ FC_I2C_PORT_EEPROM = 2,
+ FC_I2C_PORT_TUNER = 3,
+} flexcop_i2c_port_t;
+
+typedef enum {
+ FC_WRITE = 0,
+ FC_READ = 1,
+} flexcop_access_op_t;
+
+typedef enum {
+ FC_SRAM_DEST_NET = 1,
+ FC_SRAM_DEST_CAI = 2,
+ FC_SRAM_DEST_CAO = 4,
+ FC_SRAM_DEST_MEDIA = 8
+} flexcop_sram_dest_t;
+
+typedef enum {
+ FC_SRAM_DEST_TARGET_WAN_USB = 0,
+ FC_SRAM_DEST_TARGET_DMA1 = 1,
+ FC_SRAM_DEST_TARGET_DMA2 = 2,
+ FC_SRAM_DEST_TARGET_FC3_CA = 3
+} flexcop_sram_dest_target_t;
+
+typedef enum {
+ FC_SRAM_2_32KB = 0, /* 64KB */
+ FC_SRAM_1_32KB = 1, /* 32KB - default fow FCII */
+ FC_SRAM_1_128KB = 2, /* 128KB */
+ FC_SRAM_1_48KB = 3, /* 48KB - default for FCIII */
+} flexcop_sram_type_t;
+
+typedef enum {
+ FC_WAN_SPEED_4MBITS = 0,
+ FC_WAN_SPEED_8MBITS = 1,
+ FC_WAN_SPEED_12MBITS = 2,
+ FC_WAN_SPEED_16MBITS = 3,
+} flexcop_wan_speed_t;
+
+typedef enum {
+ FC_DMA_1 = 1,
+ FC_DMA_2 = 2,
+} flexcop_dma_index_t;
+
+typedef enum {
+ FC_DMA_SUBADDR_0 = 1,
+ FC_DMA_SUBADDR_1 = 2,
+} flexcop_dma_addr_index_t;
+
+/* names of the particular registers */
+typedef enum {
+ dma1_000 = 0x000,
+ dma1_004 = 0x004,
+ dma1_008 = 0x008,
+ dma1_00c = 0x00c,
+ dma2_010 = 0x010,
+ dma2_014 = 0x014,
+ dma2_018 = 0x018,
+ dma2_01c = 0x01c,
+
+ tw_sm_c_100 = 0x100,
+ tw_sm_c_104 = 0x104,
+ tw_sm_c_108 = 0x108,
+ tw_sm_c_10c = 0x10c,
+ tw_sm_c_110 = 0x110,
+
+ lnb_switch_freq_200 = 0x200,
+ misc_204 = 0x204,
+ ctrl_208 = 0x208,
+ irq_20c = 0x20c,
+ sw_reset_210 = 0x210,
+ misc_214 = 0x214,
+ mbox_v8_to_host_218 = 0x218,
+ mbox_host_to_v8_21c = 0x21c,
+
+ pid_filter_300 = 0x300,
+ pid_filter_304 = 0x304,
+ pid_filter_308 = 0x308,
+ pid_filter_30c = 0x30c,
+ index_reg_310 = 0x310,
+ pid_n_reg_314 = 0x314,
+ mac_low_reg_318 = 0x318,
+ mac_high_reg_31c = 0x31c,
+
+ data_tag_400 = 0x400,
+ card_id_408 = 0x408,
+ card_id_40c = 0x40c,
+ mac_address_418 = 0x418,
+ mac_address_41c = 0x41c,
+
+ ci_600 = 0x600,
+ pi_604 = 0x604,
+ pi_608 = 0x608,
+ dvb_reg_60c = 0x60c,
+
+ sram_ctrl_reg_700 = 0x700,
+ net_buf_reg_704 = 0x704,
+ cai_buf_reg_708 = 0x708,
+ cao_buf_reg_70c = 0x70c,
+ media_buf_reg_710 = 0x710,
+ sram_dest_reg_714 = 0x714,
+ net_buf_reg_718 = 0x718,
+ wan_ctrl_reg_71c = 0x71c,
+} flexcop_ibi_register;
+
+#define flexcop_set_ibi_value(reg,attr,val) { \
+ flexcop_ibi_value v = fc->read_ibi_reg(fc,reg); \
+ v.reg.attr = val; \
+ fc->write_ibi_reg(fc,reg,v); \
+}
+
+#endif
--- /dev/null
+/*
+ * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
+ *
+ * flexcop-sram.c - functions for controlling the SRAM.
+ *
+ * see flexcop.c for copyright information.
+ */
+#include "flexcop.h"
+
+static void flexcop_sram_set_chip (struct flexcop_device *fc, flexcop_sram_type_t type)
+{
+ flexcop_set_ibi_value(wan_ctrl_reg_71c,sram_chip,type);
+}
+
+int flexcop_sram_init(struct flexcop_device *fc)
+{
+ switch (fc->rev) {
+ case FLEXCOP_II:
+ case FLEXCOP_IIB:
+ flexcop_sram_set_chip(fc,FC_SRAM_1_32KB);
+ break;
+ case FLEXCOP_III:
+ flexcop_sram_set_chip(fc,FC_SRAM_1_48KB);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int flexcop_sram_set_dest(struct flexcop_device *fc, flexcop_sram_dest_t dest, flexcop_sram_dest_target_t target)
+{
+ flexcop_ibi_value v;
+
+ v = fc->read_ibi_reg(fc,sram_dest_reg_714);
+
+ if (fc->rev != FLEXCOP_III && target == FC_SRAM_DEST_TARGET_FC3_CA) {
+ err("SRAM destination target to available on FlexCopII(b)\n");
+ return -EINVAL;
+ }
+
+ deb_sram("sram dest: %x target: %x\n",dest, target);
+
+ if (dest & FC_SRAM_DEST_NET)
+ v.sram_dest_reg_714.NET_Dest = target;
+ if (dest & FC_SRAM_DEST_CAI)
+ v.sram_dest_reg_714.CAI_Dest = target;
+ if (dest & FC_SRAM_DEST_CAO)
+ v.sram_dest_reg_714.CAO_Dest = target;
+ if (dest & FC_SRAM_DEST_MEDIA)
+ v.sram_dest_reg_714.MEDIA_Dest = target;
+
+ fc->write_ibi_reg(fc,sram_dest_reg_714,v);
+ udelay(1000); /* TODO delay really necessary */
+
+ return 0;
+}
+EXPORT_SYMBOL(flexcop_sram_set_dest);
+
+void flexcop_wan_set_speed(struct flexcop_device *fc, flexcop_wan_speed_t s)
+{
+ flexcop_set_ibi_value(wan_ctrl_reg_71c,wan_speed_sig,s);
+}
+EXPORT_SYMBOL(flexcop_wan_set_speed);
+
+void flexcop_sram_ctrl(struct flexcop_device *fc, int usb_wan, int sramdma, int maximumfill)
+{
+ flexcop_ibi_value v = fc->read_ibi_reg(fc,sram_dest_reg_714);
+ v.sram_dest_reg_714.ctrl_usb_wan = usb_wan;
+ v.sram_dest_reg_714.ctrl_sramdma = sramdma;
+ v.sram_dest_reg_714.ctrl_maximumfill = maximumfill;
+ fc->write_ibi_reg(fc,sram_dest_reg_714,v);
+}
+EXPORT_SYMBOL(flexcop_sram_ctrl);
+
+#if 0
+static void flexcop_sram_write(struct adapter *adapter, u32 bank, u32 addr, u8 *buf, u32 len)
+{
+ int i, retries;
+ u32 command;
+
+ for (i = 0; i < len; i++) {
+ command = bank | addr | 0x04000000 | (*buf << 0x10);
+
+ retries = 2;
+
+ while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) {
+ mdelay(1);
+ retries--;
+ };
+
+ if (retries == 0)
+ printk("%s: SRAM timeout\n", __FUNCTION__);
+
+ write_reg_dw(adapter, 0x700, command);
+
+ buf++;
+ addr++;
+ }
+}
+
+static void flex_sram_read(struct adapter *adapter, u32 bank, u32 addr, u8 *buf, u32 len)
+{
+ int i, retries;
+ u32 command, value;
+
+ for (i = 0; i < len; i++) {
+ command = bank | addr | 0x04008000;
+
+ retries = 10000;
+
+ while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) {
+ mdelay(1);
+ retries--;
+ };
+
+ if (retries == 0)
+ printk("%s: SRAM timeout\n", __FUNCTION__);
+
+ write_reg_dw(adapter, 0x700, command);
+
+ retries = 10000;
+
+ while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) {
+ mdelay(1);
+ retries--;
+ };
+
+ if (retries == 0)
+ printk("%s: SRAM timeout\n", __FUNCTION__);
+
+ value = read_reg_dw(adapter, 0x700) >> 0x10;
+
+ *buf = (value & 0xff);
+
+ addr++;
+ buf++;
+ }
+}
+
+static void sram_write_chunk(struct adapter *adapter, u32 addr, u8 *buf, u16 len)
+{
+ u32 bank;
+
+ bank = 0;
+
+ if (adapter->dw_sram_type == 0x20000) {
+ bank = (addr & 0x18000) << 0x0d;
+ }
+
+ if (adapter->dw_sram_type == 0x00000) {
+ if ((addr >> 0x0f) == 0)
+ bank = 0x20000000;
+ else
+ bank = 0x10000000;
+ }
+
+ flex_sram_write(adapter, bank, addr & 0x7fff, buf, len);
+}
+
+static void sram_read_chunk(struct adapter *adapter, u32 addr, u8 *buf, u16 len)
+{
+ u32 bank;
+
+ bank = 0;
+
+ if (adapter->dw_sram_type == 0x20000) {
+ bank = (addr & 0x18000) << 0x0d;
+ }
+
+ if (adapter->dw_sram_type == 0x00000) {
+ if ((addr >> 0x0f) == 0)
+ bank = 0x20000000;
+ else
+ bank = 0x10000000;
+ }
+
+ flex_sram_read(adapter, bank, addr & 0x7fff, buf, len);
+}
+
+static void sram_read(struct adapter *adapter, u32 addr, u8 *buf, u32 len)
+{
+ u32 length;
+
+ while (len != 0) {
+ length = len;
+
+ // check if the address range belongs to the same
+ // 32K memory chip. If not, the data is read from
+ // one chip at a time.
+ if ((addr >> 0x0f) != ((addr + len - 1) >> 0x0f)) {
+ length = (((addr >> 0x0f) + 1) << 0x0f) - addr;
+ }
+
+ sram_read_chunk(adapter, addr, buf, length);
+
+ addr = addr + length;
+ buf = buf + length;
+ len = len - length;
+ }
+}
+
+static void sram_write(struct adapter *adapter, u32 addr, u8 *buf, u32 len)
+{
+ u32 length;
+
+ while (len != 0) {
+ length = len;
+
+ // check if the address range belongs to the same
+ // 32K memory chip. If not, the data is written to
+ // one chip at a time.
+ if ((addr >> 0x0f) != ((addr + len - 1) >> 0x0f)) {
+ length = (((addr >> 0x0f) + 1) << 0x0f) - addr;
+ }
+
+ sram_write_chunk(adapter, addr, buf, length);
+
+ addr = addr + length;
+ buf = buf + length;
+ len = len - length;
+ }
+}
+
+static void sram_set_size(struct adapter *adapter, u32 mask)
+{
+ write_reg_dw(adapter, 0x71c, (mask | (~0x30000 & read_reg_dw(adapter, 0x71c))));
+}
+
+static void sram_init(struct adapter *adapter)
+{
+ u32 tmp;
+
+ tmp = read_reg_dw(adapter, 0x71c);
+
+ write_reg_dw(adapter, 0x71c, 1);
+
+ if (read_reg_dw(adapter, 0x71c) != 0) {
+ write_reg_dw(adapter, 0x71c, tmp);
+
+ adapter->dw_sram_type = tmp & 0x30000;
+
+ ddprintk("%s: dw_sram_type = %x\n", __FUNCTION__, adapter->dw_sram_type);
+
+ } else {
+
+ adapter->dw_sram_type = 0x10000;
+
+ ddprintk("%s: dw_sram_type = %x\n", __FUNCTION__, adapter->dw_sram_type);
+ }
+
+ /* return value is never used? */
+/* return adapter->dw_sram_type; */
+}
+
+static int sram_test_location(struct adapter *adapter, u32 mask, u32 addr)
+{
+ u8 tmp1, tmp2;
+
+ dprintk("%s: mask = %x, addr = %x\n", __FUNCTION__, mask, addr);
+
+ sram_set_size(adapter, mask);
+ sram_init(adapter);
+
+ tmp2 = 0xa5;
+ tmp1 = 0x4f;
+
+ sram_write(adapter, addr, &tmp2, 1);
+ sram_write(adapter, addr + 4, &tmp1, 1);
+
+ tmp2 = 0;
+
+ mdelay(20);
+
+ sram_read(adapter, addr, &tmp2, 1);
+ sram_read(adapter, addr, &tmp2, 1);
+
+ dprintk("%s: wrote 0xa5, read 0x%2x\n", __FUNCTION__, tmp2);
+
+ if (tmp2 != 0xa5)
+ return 0;
+
+ tmp2 = 0x5a;
+ tmp1 = 0xf4;
+
+ sram_write(adapter, addr, &tmp2, 1);
+ sram_write(adapter, addr + 4, &tmp1, 1);
+
+ tmp2 = 0;
+
+ mdelay(20);
+
+ sram_read(adapter, addr, &tmp2, 1);
+ sram_read(adapter, addr, &tmp2, 1);
+
+ dprintk("%s: wrote 0x5a, read 0x%2x\n", __FUNCTION__, tmp2);
+
+ if (tmp2 != 0x5a)
+ return 0;
+
+ return 1;
+}
+
+static u32 sram_length(struct adapter *adapter)
+{
+ if (adapter->dw_sram_type == 0x10000)
+ return 32768; // 32K
+ if (adapter->dw_sram_type == 0x00000)
+ return 65536; // 64K
+ if (adapter->dw_sram_type == 0x20000)
+ return 131072; // 128K
+
+ return 32768; // 32K
+}
+
+/* FlexcopII can work with 32K, 64K or 128K of external SRAM memory.
+ - for 128K there are 4x32K chips at bank 0,1,2,3.
+ - for 64K there are 2x32K chips at bank 1,2.
+ - for 32K there is one 32K chip at bank 0.
+
+ FlexCop works only with one bank at a time. The bank is selected
+ by bits 28-29 of the 0x700 register.
+
+ bank 0 covers addresses 0x00000-0x07fff
+ bank 1 covers addresses 0x08000-0x0ffff
+ bank 2 covers addresses 0x10000-0x17fff
+ bank 3 covers addresses 0x18000-0x1ffff
+*/
+
+static int flexcop_sram_detect(struct flexcop_device *fc)
+{
+ flexcop_ibi_value r208,r71c_0,vr71c_1;
+
+ r208 = fc->read_ibi_reg(fc, ctrl_208);
+ fc->write_ibi_reg(fc, ctrl_208, ibi_zero);
+
+ r71c_0 = fc->read_ibi_reg(fc, wan_ctrl_reg_71c);
+
+ write_reg_dw(adapter, 0x71c, 1);
+
+ tmp3 = read_reg_dw(adapter, 0x71c);
+
+ dprintk("%s: tmp3 = %x\n", __FUNCTION__, tmp3);
+
+ write_reg_dw(adapter, 0x71c, tmp2);
+
+ // check for internal SRAM ???
+ tmp3--;
+ if (tmp3 != 0) {
+ sram_set_size(adapter, 0x10000);
+ sram_init(adapter);
+ write_reg_dw(adapter, 0x208, tmp);
+
+ dprintk("%s: sram size = 32K\n", __FUNCTION__);
+
+ return 32;
+ }
+
+ if (sram_test_location(adapter, 0x20000, 0x18000) != 0) {
+ sram_set_size(adapter, 0x20000);
+ sram_init(adapter);
+ write_reg_dw(adapter, 0x208, tmp);
+
+ dprintk("%s: sram size = 128K\n", __FUNCTION__);
+
+ return 128;
+ }
+
+ if (sram_test_location(adapter, 0x00000, 0x10000) != 0) {
+ sram_set_size(adapter, 0x00000);
+ sram_init(adapter);
+ write_reg_dw(adapter, 0x208, tmp);
+
+ dprintk("%s: sram size = 64K\n", __FUNCTION__);
+
+ return 64;
+ }
+
+ if (sram_test_location(adapter, 0x10000, 0x00000) != 0) {
+ sram_set_size(adapter, 0x10000);
+ sram_init(adapter);
+ write_reg_dw(adapter, 0x208, tmp);
+
+ dprintk("%s: sram size = 32K\n", __FUNCTION__);
+
+ return 32;
+ }
+
+ sram_set_size(adapter, 0x10000);
+ sram_init(adapter);
+ write_reg_dw(adapter, 0x208, tmp);
+
+ dprintk("%s: SRAM detection failed. Set to 32K \n", __FUNCTION__);
+
+ return 0;
+}
+
+static void sll_detect_sram_size(struct adapter *adapter)
+{
+ sram_detect_for_flex2(adapter);
+}
+
+#endif
--- /dev/null
+#ifndef __FLEXCOP_USB_H_INCLUDED__
+#define __FLEXCOP_USB_H_INCLUDED__
+
+#include <linux/usb.h>
+
+/* transfer parameters */
+#define B2C2_USB_FRAMES_PER_ISO 4
+#define B2C2_USB_NUM_ISO_URB 4
+
+#define B2C2_USB_CTRL_PIPE_IN usb_rcvctrlpipe(fc_usb->udev,0)
+#define B2C2_USB_CTRL_PIPE_OUT usb_sndctrlpipe(fc_usb->udev,0)
+#define B2C2_USB_DATA_PIPE usb_rcvisocpipe(fc_usb->udev,0x81)
+
+struct flexcop_usb {
+ struct usb_device *udev;
+ struct usb_interface *uintf;
+
+ u8 *iso_buffer;
+ int buffer_size;
+ dma_addr_t dma_addr;
+ struct urb *iso_urb[B2C2_USB_NUM_ISO_URB];
+
+ struct flexcop_device *fc_dev;
+
+ u8 tmp_buffer[1023+190];
+ int tmp_buffer_length;
+};
+
+#if 0
+/* request types TODO What is its use?*/
+typedef enum {
+
+/* something is wrong with this part
+ RTYPE_READ_DW = (1 << 6),
+ RTYPE_WRITE_DW_1 = (3 << 6),
+ RTYPE_READ_V8_MEMORY = (6 << 6),
+ RTYPE_WRITE_V8_MEMORY = (7 << 6),
+ RTYPE_WRITE_V8_FLASH = (8 << 6),
+ RTYPE_GENERIC = (9 << 6),
+*/
+} flexcop_usb_request_type_t;
+#endif
+
+/* request */
+typedef enum {
+ B2C2_USB_WRITE_V8_MEM = 0x04,
+ B2C2_USB_READ_V8_MEM = 0x05,
+ B2C2_USB_READ_REG = 0x08,
+ B2C2_USB_WRITE_REG = 0x0A,
+/* B2C2_USB_WRITEREGLO = 0x0A, */
+ B2C2_USB_WRITEREGHI = 0x0B,
+ B2C2_USB_FLASH_BLOCK = 0x10,
+ B2C2_USB_I2C_REQUEST = 0x11,
+ B2C2_USB_UTILITY = 0x12,
+} flexcop_usb_request_t;
+
+/* function definition for I2C_REQUEST */
+typedef enum {
+ USB_FUNC_I2C_WRITE = 0x01,
+ USB_FUNC_I2C_MULTIWRITE = 0x02,
+ USB_FUNC_I2C_READ = 0x03,
+ USB_FUNC_I2C_REPEATWRITE = 0x04,
+ USB_FUNC_GET_DESCRIPTOR = 0x05,
+ USB_FUNC_I2C_REPEATREAD = 0x06,
+/* DKT 020208 - add this to support special case of DiSEqC */
+ USB_FUNC_I2C_CHECKWRITE = 0x07,
+ USB_FUNC_I2C_CHECKRESULT = 0x08,
+} flexcop_usb_i2c_function_t;
+
+/*
+ * function definition for UTILITY request 0x12
+ * DKT 020304 - new utility function
+ */
+typedef enum {
+ UTILITY_SET_FILTER = 0x01,
+ UTILITY_DATA_ENABLE = 0x02,
+ UTILITY_FLEX_MULTIWRITE = 0x03,
+ UTILITY_SET_BUFFER_SIZE = 0x04,
+ UTILITY_FLEX_OPERATOR = 0x05,
+ UTILITY_FLEX_RESET300_START = 0x06,
+ UTILITY_FLEX_RESET300_STOP = 0x07,
+ UTILITY_FLEX_RESET300 = 0x08,
+ UTILITY_SET_ISO_SIZE = 0x09,
+ UTILITY_DATA_RESET = 0x0A,
+ UTILITY_GET_DATA_STATUS = 0x10,
+ UTILITY_GET_V8_REG = 0x11,
+/* DKT 020326 - add function for v1.14 */
+ UTILITY_SRAM_WRITE = 0x12,
+ UTILITY_SRAM_READ = 0x13,
+ UTILITY_SRAM_TESTFILL = 0x14,
+ UTILITY_SRAM_TESTSET = 0x15,
+ UTILITY_SRAM_TESTVERIFY = 0x16,
+} flexcop_usb_utility_function_t;
+
+#define B2C2_WAIT_FOR_OPERATION_RW 1*HZ /* 1 s */
+#define B2C2_WAIT_FOR_OPERATION_RDW 3*HZ /* 3 s */
+#define B2C2_WAIT_FOR_OPERATION_WDW 1*HZ /* 1 s */
+
+#define B2C2_WAIT_FOR_OPERATION_V8READ 3*HZ /* 3 s */
+#define B2C2_WAIT_FOR_OPERATION_V8WRITE 3*HZ /* 3 s */
+#define B2C2_WAIT_FOR_OPERATION_V8FLASH 3*HZ /* 3 s */
+
+typedef enum {
+ V8_MEMORY_PAGE_DVB_CI = 0x20,
+ V8_MEMORY_PAGE_DVB_DS = 0x40,
+ V8_MEMORY_PAGE_MULTI2 = 0x60,
+ V8_MEMORY_PAGE_FLASH = 0x80
+} flexcop_usb_mem_page_t;
+
+#define V8_MEMORY_EXTENDED (1 << 15)
+
+#define USB_MEM_READ_MAX 32
+#define USB_MEM_WRITE_MAX 1
+#define USB_FLASH_MAX 8
+
+#define V8_MEMORY_PAGE_SIZE 0x8000 // 32K
+#define V8_MEMORY_PAGE_MASK 0x7FFF
+
+#endif
--- /dev/null
+/*
+ * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
+ *
+ * flexcop.h - private header file for all flexcop-chip-source files.
+ *
+ * see flexcop.c for copyright information.
+ */
+#ifndef __FLEXCOP_H__
+#define __FLEXCOP_H___
+
+#define FC_LOG_PREFIX "b2c2-flexcop"
+#include "flexcop-common.h"
+
+extern int b2c2_flexcop_debug;
+
+/* debug */
+#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG
+#define dprintk(level,args...) \
+ do { if ((b2c2_flexcop_debug & level)) printk(args); } while (0)
+#else
+#define dprintk(level,args...)
+#endif
+
+#define deb_info(args...) dprintk(0x01,args)
+#define deb_tuner(args...) dprintk(0x02,args)
+#define deb_i2c(args...) dprintk(0x04,args)
+#define deb_ts(args...) dprintk(0x08,args)
+#define deb_sram(args...) dprintk(0x10,args)
+
+#endif
--- /dev/null
+/*
+ CA-driver for TwinHan DST Frontend/Card
+
+ Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.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.
+*/
+
+#ifndef _DST_CA_H_
+#define _DST_CA_H_
+
+#define RETRIES 5
+
+
+#define CA_APP_INFO_ENQUIRY 0x9f8020
+#define CA_APP_INFO 0x9f8021
+#define CA_ENTER_MENU 0x9f8022
+#define CA_INFO_ENQUIRY 0x9f8030
+#define CA_INFO 0x9f8031
+#define CA_PMT 0x9f8032
+#define CA_PMT_REPLY 0x9f8033
+
+#define CA_CLOSE_MMI 0x9f8800
+#define CA_DISPLAY_CONTROL 0x9f8801
+#define CA_DISPLAY_REPLY 0x9f8802
+#define CA_TEXT_LAST 0x9f8803
+#define CA_TEXT_MORE 0x9f8804
+#define CA_KEYPAD_CONTROL 0x9f8805
+#define CA_KEYPRESS 0x9f8806
+
+#define CA_ENQUIRY 0x9f8807
+#define CA_ANSWER 0x9f8808
+#define CA_MENU_LAST 0x9f8809
+#define CA_MENU_MORE 0x9f880a
+#define CA_MENU_ANSWER 0x9f880b
+#define CA_LIST_LAST 0x9f880c
+#define CA_LIST_MORE 0x9f880d
+
+
+struct dst_ca_private {
+ struct dst_state *dst;
+ struct dvb_device *dvbdev;
+};
+
+
+#endif
--- /dev/null
+/*
+ * $Id: mt20xx.c,v 1.4 2005/03/04 09:24:56 kraxel Exp $
+ *
+ * i2c tv tuner chip device driver
+ * controls microtune tuners, mt2032 + mt2050 at the moment.
+ */
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/videodev.h>
+#include <linux/moduleparam.h>
+#include <media/tuner.h>
+
+/* ---------------------------------------------------------------------- */
+
+static unsigned int optimize_vco = 1;
+module_param(optimize_vco, int, 0644);
+
+static unsigned int tv_antenna = 1;
+module_param(tv_antenna, int, 0644);
+
+static unsigned int radio_antenna = 0;
+module_param(radio_antenna, int, 0644);
+
+/* ---------------------------------------------------------------------- */
+
+#define MT2032 0x04
+#define MT2030 0x06
+#define MT2040 0x07
+#define MT2050 0x42
+
+static char *microtune_part[] = {
+ [ MT2030 ] = "MT2030",
+ [ MT2032 ] = "MT2032",
+ [ MT2040 ] = "MT2040",
+ [ MT2050 ] = "MT2050",
+};
+
+// IsSpurInBand()?
+static int mt2032_spurcheck(struct i2c_client *c,
+ int f1, int f2, int spectrum_from,int spectrum_to)
+{
+ struct tuner *t = i2c_get_clientdata(c);
+ int n1=1,n2,f;
+
+ f1=f1/1000; //scale to kHz to avoid 32bit overflows
+ f2=f2/1000;
+ spectrum_from/=1000;
+ spectrum_to/=1000;
+
+ tuner_dbg("spurcheck f1=%d f2=%d from=%d to=%d\n",
+ f1,f2,spectrum_from,spectrum_to);
+
+ do {
+ n2=-n1;
+ f=n1*(f1-f2);
+ do {
+ n2--;
+ f=f-f2;
+ tuner_dbg("spurtest n1=%d n2=%d ftest=%d\n",n1,n2,f);
+
+ if( (f>spectrum_from) && (f<spectrum_to))
+ tuner_dbg("mt2032 spurcheck triggered: %d\n",n1);
+ } while ( (f>(f2-spectrum_to)) || (n2>-5));
+ n1++;
+ } while (n1<5);
+
+ return 1;
+}
+
+static int mt2032_compute_freq(struct i2c_client *c,
+ unsigned int rfin,
+ unsigned int if1, unsigned int if2,
+ unsigned int spectrum_from,
+ unsigned int spectrum_to,
+ unsigned char *buf,
+ int *ret_sel,
+ unsigned int xogc) //all in Hz
+{
+ struct tuner *t = i2c_get_clientdata(c);
+ unsigned int fref,lo1,lo1n,lo1a,s,sel,lo1freq, desired_lo1,
+ desired_lo2,lo2,lo2n,lo2a,lo2num,lo2freq;
+
+ fref= 5250 *1000; //5.25MHz
+ desired_lo1=rfin+if1;
+
+ lo1=(2*(desired_lo1/1000)+(fref/1000)) / (2*fref/1000);
+ lo1n=lo1/8;
+ lo1a=lo1-(lo1n*8);
+
+ s=rfin/1000/1000+1090;
+
+ if(optimize_vco) {
+ if(s>1890) sel=0;
+ else if(s>1720) sel=1;
+ else if(s>1530) sel=2;
+ else if(s>1370) sel=3;
+ else sel=4; // >1090
+ }
+ else {
+ if(s>1790) sel=0; // <1958
+ else if(s>1617) sel=1;
+ else if(s>1449) sel=2;
+ else if(s>1291) sel=3;
+ else sel=4; // >1090
+ }
+ *ret_sel=sel;
+
+ lo1freq=(lo1a+8*lo1n)*fref;
+
+ tuner_dbg("mt2032: rfin=%d lo1=%d lo1n=%d lo1a=%d sel=%d, lo1freq=%d\n",
+ rfin,lo1,lo1n,lo1a,sel,lo1freq);
+
+ desired_lo2=lo1freq-rfin-if2;
+ lo2=(desired_lo2)/fref;
+ lo2n=lo2/8;
+ lo2a=lo2-(lo2n*8);
+ lo2num=((desired_lo2/1000)%(fref/1000))* 3780/(fref/1000); //scale to fit in 32bit arith
+ lo2freq=(lo2a+8*lo2n)*fref + lo2num*(fref/1000)/3780*1000;
+
+ tuner_dbg("mt2032: rfin=%d lo2=%d lo2n=%d lo2a=%d num=%d lo2freq=%d\n",
+ rfin,lo2,lo2n,lo2a,lo2num,lo2freq);
+
+ if(lo1a<0 || lo1a>7 || lo1n<17 ||lo1n>48 || lo2a<0 ||lo2a >7 ||lo2n<17 || lo2n>30) {
+ tuner_info("mt2032: frequency parameters out of range: %d %d %d %d\n",
+ lo1a, lo1n, lo2a,lo2n);
+ return(-1);
+ }
+
+ mt2032_spurcheck(c, lo1freq, desired_lo2, spectrum_from, spectrum_to);
+ // should recalculate lo1 (one step up/down)
+
+ // set up MT2032 register map for transfer over i2c
+ buf[0]=lo1n-1;
+ buf[1]=lo1a | (sel<<4);
+ buf[2]=0x86; // LOGC
+ buf[3]=0x0f; //reserved
+ buf[4]=0x1f;
+ buf[5]=(lo2n-1) | (lo2a<<5);
+ if(rfin >400*1000*1000)
+ buf[6]=0xe4;
+ else
+ buf[6]=0xf4; // set PKEN per rev 1.2
+ buf[7]=8+xogc;
+ buf[8]=0xc3; //reserved
+ buf[9]=0x4e; //reserved
+ buf[10]=0xec; //reserved
+ buf[11]=(lo2num&0xff);
+ buf[12]=(lo2num>>8) |0x80; // Lo2RST
+
+ return 0;
+}
+
+static int mt2032_check_lo_lock(struct i2c_client *c)
+{
+ struct tuner *t = i2c_get_clientdata(c);
+ int try,lock=0;
+ unsigned char buf[2];
+
+ for(try=0;try<10;try++) {
+ buf[0]=0x0e;
+ i2c_master_send(c,buf,1);
+ i2c_master_recv(c,buf,1);
+ tuner_dbg("mt2032 Reg.E=0x%02x\n",buf[0]);
+ lock=buf[0] &0x06;
+
+ if (lock==6)
+ break;
+
+ tuner_dbg("mt2032: pll wait 1ms for lock (0x%2x)\n",buf[0]);
+ udelay(1000);
+ }
+ return lock;
+}
+
+static int mt2032_optimize_vco(struct i2c_client *c,int sel,int lock)
+{
+ struct tuner *t = i2c_get_clientdata(c);
+ unsigned char buf[2];
+ int tad1;
+
+ buf[0]=0x0f;
+ i2c_master_send(c,buf,1);
+ i2c_master_recv(c,buf,1);
+ tuner_dbg("mt2032 Reg.F=0x%02x\n",buf[0]);
+ tad1=buf[0]&0x07;
+
+ if(tad1 ==0) return lock;
+ if(tad1 ==1) return lock;
+
+ if(tad1==2) {
+ if(sel==0)
+ return lock;
+ else sel--;
+ }
+ else {
+ if(sel<4)
+ sel++;
+ else
+ return lock;
+ }
+
+ tuner_dbg("mt2032 optimize_vco: sel=%d\n",sel);
+
+ buf[0]=0x0f;
+ buf[1]=sel;
+ i2c_master_send(c,buf,2);
+ lock=mt2032_check_lo_lock(c);
+ return lock;
+}
+
+
+static void mt2032_set_if_freq(struct i2c_client *c, unsigned int rfin,
+ unsigned int if1, unsigned int if2,
+ unsigned int from, unsigned int to)
+{
+ unsigned char buf[21];
+ int lint_try,ret,sel,lock=0;
+ struct tuner *t = i2c_get_clientdata(c);
+
+ tuner_dbg("mt2032_set_if_freq rfin=%d if1=%d if2=%d from=%d to=%d\n",
+ rfin,if1,if2,from,to);
+
+ buf[0]=0;
+ ret=i2c_master_send(c,buf,1);
+ i2c_master_recv(c,buf,21);
+
+ buf[0]=0;
+ ret=mt2032_compute_freq(c,rfin,if1,if2,from,to,&buf[1],&sel,t->xogc);
+ if (ret<0)
+ return;
+
+ // send only the relevant registers per Rev. 1.2
+ buf[0]=0;
+ ret=i2c_master_send(c,buf,4);
+ buf[5]=5;
+ ret=i2c_master_send(c,buf+5,4);
+ buf[11]=11;
+ ret=i2c_master_send(c,buf+11,3);
+ if(ret!=3)
+ tuner_warn("i2c i/o error: rc == %d (should be 3)\n",ret);
+
+ // wait for PLLs to lock (per manual), retry LINT if not.
+ for(lint_try=0; lint_try<2; lint_try++) {
+ lock=mt2032_check_lo_lock(c);
+
+ if(optimize_vco)
+ lock=mt2032_optimize_vco(c,sel,lock);
+ if(lock==6) break;
+
+ tuner_dbg("mt2032: re-init PLLs by LINT\n");
+ buf[0]=7;
+ buf[1]=0x80 +8+t->xogc; // set LINT to re-init PLLs
+ i2c_master_send(c,buf,2);
+ mdelay(10);
+ buf[1]=8+t->xogc;
+ i2c_master_send(c,buf,2);
+ }
+
+ if (lock!=6)
+ tuner_warn("MT2032 Fatal Error: PLLs didn't lock.\n");
+
+ buf[0]=2;
+ buf[1]=0x20; // LOGC for optimal phase noise
+ ret=i2c_master_send(c,buf,2);
+ if (ret!=2)
+ tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret);
+}
+
+
+static void mt2032_set_tv_freq(struct i2c_client *c, unsigned int freq)
+{
+ struct tuner *t = i2c_get_clientdata(c);
+ int if2,from,to;
+
+ // signal bandwidth and picture carrier
+ if (t->std & V4L2_STD_525_60) {
+ // NTSC
+ from = 40750*1000;
+ to = 46750*1000;
+ if2 = 45750*1000;
+ } else {
+ // PAL
+ from = 32900*1000;
+ to = 39900*1000;
+ if2 = 38900*1000;
+ }
+
+ mt2032_set_if_freq(c, freq*62500 /* freq*1000*1000/16 */,
+ 1090*1000*1000, if2, from, to);
+}
+
+static void mt2032_set_radio_freq(struct i2c_client *c, unsigned int freq)
+{
+ struct tuner *t = i2c_get_clientdata(c);
+ int if2 = t->radio_if2;
+
+ // per Manual for FM tuning: first if center freq. 1085 MHz
+ mt2032_set_if_freq(c, freq*62500 /* freq*1000*1000/16 */,
+ 1085*1000*1000,if2,if2,if2);
+}
+
+// Initalization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001
+static int mt2032_init(struct i2c_client *c)
+{
+ struct tuner *t = i2c_get_clientdata(c);
+ unsigned char buf[21];
+ int ret,xogc,xok=0;
+
+ // Initialize Registers per spec.
+ buf[1]=2; // Index to register 2
+ buf[2]=0xff;
+ buf[3]=0x0f;
+ buf[4]=0x1f;
+ ret=i2c_master_send(c,buf+1,4);
+
+ buf[5]=6; // Index register 6
+ buf[6]=0xe4;
+ buf[7]=0x8f;
+ buf[8]=0xc3;
+ buf[9]=0x4e;
+ buf[10]=0xec;
+ ret=i2c_master_send(c,buf+5,6);
+
+ buf[12]=13; // Index register 13
+ buf[13]=0x32;
+ ret=i2c_master_send(c,buf+12,2);
+
+ // Adjust XOGC (register 7), wait for XOK
+ xogc=7;
+ do {
+ tuner_dbg("mt2032: xogc = 0x%02x\n",xogc&0x07);
+ mdelay(10);
+ buf[0]=0x0e;
+ i2c_master_send(c,buf,1);
+ i2c_master_recv(c,buf,1);
+ xok=buf[0]&0x01;
+ tuner_dbg("mt2032: xok = 0x%02x\n",xok);
+ if (xok == 1) break;
+
+ xogc--;
+ tuner_dbg("mt2032: xogc = 0x%02x\n",xogc&0x07);
+ if (xogc == 3) {
+ xogc=4; // min. 4 per spec
+ break;
+ }
+ buf[0]=0x07;
+ buf[1]=0x88 + xogc;
+ ret=i2c_master_send(c,buf,2);
+ if (ret!=2)
+ tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret);
+ } while (xok != 1 );
+ t->xogc=xogc;
+
+ t->tv_freq = mt2032_set_tv_freq;
+ t->radio_freq = mt2032_set_radio_freq;
+ return(1);
+}
+
+static void mt2050_set_antenna(struct i2c_client *c, unsigned char antenna)
+{
+ struct tuner *t = i2c_get_clientdata(c);
+ unsigned char buf[2];
+ int ret;
+
+ buf[0] = 6;
+ buf[1] = antenna ? 0x11 : 0x10;
+ ret=i2c_master_send(c,buf,2);
+ tuner_dbg("mt2050: enabled antenna connector %d\n", antenna);
+}
+
+static void mt2050_set_if_freq(struct i2c_client *c,unsigned int freq, unsigned int if2)
+{
+ struct tuner *t = i2c_get_clientdata(c);
+ unsigned int if1=1218*1000*1000;
+ unsigned int f_lo1,f_lo2,lo1,lo2,f_lo1_modulo,f_lo2_modulo,num1,num2,div1a,div1b,div2a,div2b;
+ int ret;
+ unsigned char buf[6];
+
+ tuner_dbg("mt2050_set_if_freq freq=%d if1=%d if2=%d\n",
+ freq,if1,if2);
+
+ f_lo1=freq+if1;
+ f_lo1=(f_lo1/1000000)*1000000;
+
+ f_lo2=f_lo1-freq-if2;
+ f_lo2=(f_lo2/50000)*50000;
+
+ lo1=f_lo1/4000000;
+ lo2=f_lo2/4000000;
+
+ f_lo1_modulo= f_lo1-(lo1*4000000);
+ f_lo2_modulo= f_lo2-(lo2*4000000);
+
+ num1=4*f_lo1_modulo/4000000;
+ num2=4096*(f_lo2_modulo/1000)/4000;
+
+ // todo spurchecks
+
+ div1a=(lo1/12)-1;
+ div1b=lo1-(div1a+1)*12;
+
+ div2a=(lo2/8)-1;
+ div2b=lo2-(div2a+1)*8;
+
+ if (tuner_debug > 1) {
+ tuner_dbg("lo1 lo2 = %d %d\n", lo1, lo2);
+ tuner_dbg("num1 num2 div1a div1b div2a div2b= %x %x %x %x %x %x\n",
+ num1,num2,div1a,div1b,div2a,div2b);
+ }
+
+ buf[0]=1;
+ buf[1]= 4*div1b + num1;
+ if(freq<275*1000*1000) buf[1] = buf[1]|0x80;
+
+ buf[2]=div1a;
+ buf[3]=32*div2b + num2/256;
+ buf[4]=num2-(num2/256)*256;
+ buf[5]=div2a;
+ if(num2!=0) buf[5]=buf[5]|0x40;
+
+ if (tuner_debug > 1) {
+ int i;
+ tuner_dbg("bufs is: ");
+ for(i=0;i<6;i++)
+ printk("%x ",buf[i]);
+ printk("\n");
+ }
+
+ ret=i2c_master_send(c,buf,6);
+ if (ret!=6)
+ tuner_warn("i2c i/o error: rc == %d (should be 6)\n",ret);
+}
+
+static void mt2050_set_tv_freq(struct i2c_client *c, unsigned int freq)
+{
+ struct tuner *t = i2c_get_clientdata(c);
+ unsigned int if2;
+
+ if (t->std & V4L2_STD_525_60) {
+ // NTSC
+ if2 = 45750*1000;
+ } else {
+ // PAL
+ if2 = 38900*1000;
+ }
+ if (V4L2_TUNER_DIGITAL_TV == t->mode) {
+ // DVB (pinnacle 300i)
+ if2 = 36150*1000;
+ }
+ mt2050_set_if_freq(c, freq*62500, if2);
+ mt2050_set_antenna(c, tv_antenna);
+}
+
+static void mt2050_set_radio_freq(struct i2c_client *c, unsigned int freq)
+{
+ struct tuner *t = i2c_get_clientdata(c);
+ int if2 = t->radio_if2;
+
+ mt2050_set_if_freq(c, freq*62500, if2);
+ mt2050_set_antenna(c, radio_antenna);
+}
+
+static int mt2050_init(struct i2c_client *c)
+{
+ struct tuner *t = i2c_get_clientdata(c);
+ unsigned char buf[2];
+ int ret;
+
+ buf[0]=6;
+ buf[1]=0x10;
+ ret=i2c_master_send(c,buf,2); // power
+
+ buf[0]=0x0f;
+ buf[1]=0x0f;
+ ret=i2c_master_send(c,buf,2); // m1lo
+
+ buf[0]=0x0d;
+ ret=i2c_master_send(c,buf,1);
+ i2c_master_recv(c,buf,1);
+
+ tuner_dbg("mt2050: sro is %x\n",buf[0]);
+ t->tv_freq = mt2050_set_tv_freq;
+ t->radio_freq = mt2050_set_radio_freq;
+ return 0;
+}
+
+int microtune_init(struct i2c_client *c)
+{
+ struct tuner *t = i2c_get_clientdata(c);
+ char *name;
+ unsigned char buf[21];
+ int company_code;
+
+ memset(buf,0,sizeof(buf));
+ t->tv_freq = NULL;
+ t->radio_freq = NULL;
+ name = "unknown";
+
+ i2c_master_send(c,buf,1);
+ i2c_master_recv(c,buf,21);
+ if (tuner_debug) {
+ int i;
+ tuner_dbg("MT20xx hexdump:");
+ for(i=0;i<21;i++) {
+ printk(" %02x",buf[i]);
+ if(((i+1)%8)==0) printk(" ");
+ }
+ printk("\n");
+ }
+ company_code = buf[0x11] << 8 | buf[0x12];
+ tuner_info("microtune: companycode=%04x part=%02x rev=%02x\n",
+ company_code,buf[0x13],buf[0x14]);
+
+#if 0
+ /* seems to cause more problems than it solves ... */
+ switch (company_code) {
+ case 0x30bf:
+ case 0x3cbf:
+ case 0x3dbf:
+ case 0x4d54:
+ case 0x8e81:
+ case 0x8e91:
+ /* ok (?) */
+ break;
+ default:
+ tuner_warn("tuner: microtune: unknown companycode\n");
+ return 0;
+ }
+#endif
+
+ if (buf[0x13] < ARRAY_SIZE(microtune_part) &&
+ NULL != microtune_part[buf[0x13]])
+ name = microtune_part[buf[0x13]];
+ switch (buf[0x13]) {
+ case MT2032:
+ mt2032_init(c);
+ break;
+ case MT2050:
+ mt2050_init(c);
+ break;
+ default:
+ tuner_info("microtune %s found, not (yet?) supported, sorry :-/\n",
+ name);
+ return 0;
+ }
+
+ strlcpy(c->name, name, sizeof(c->name));
+ tuner_info("microtune %s found, OK\n",name);
+ return 0;
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
--- /dev/null
+obj-$(CONFIG_HDPU_FEATURES) := hdpu_cpustate.o hdpu_nexus.o
--- /dev/null
+/*
+ * Sky CPU State Driver
+ *
+ * Copyright (C) 2002 Brian Waite
+ *
+ * This driver allows use of the CPU state bits
+ * It exports the /dev/sky_cpustate and also
+ * /proc/sky_cpustate pseudo-file for status information.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/miscdevice.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include <linux/device.h>
+#include <asm/uaccess.h>
+#include <linux/hdpu_features.h>
+
+#define SKY_CPUSTATE_VERSION "1.1"
+
+static int hdpu_cpustate_probe(struct device *ddev);
+static int hdpu_cpustate_remove(struct device *ddev);
+
+struct cpustate_t cpustate;
+
+static int cpustate_get_ref(int excl)
+{
+
+ int retval = -EBUSY;
+
+ spin_lock(&cpustate.lock);
+
+ if (cpustate.excl)
+ goto out_busy;
+
+ if (excl) {
+ if (cpustate.open_count)
+ goto out_busy;
+ cpustate.excl = 1;
+ }
+
+ cpustate.open_count++;
+ retval = 0;
+
+ out_busy:
+ spin_unlock(&cpustate.lock);
+ return retval;
+}
+
+static int cpustate_free_ref(void)
+{
+
+ spin_lock(&cpustate.lock);
+
+ cpustate.excl = 0;
+ cpustate.open_count--;
+
+ spin_unlock(&cpustate.lock);
+ return 0;
+}
+
+unsigned char cpustate_get_state(void)
+{
+
+ return cpustate.cached_val;
+}
+
+void cpustate_set_state(unsigned char new_state)
+{
+ unsigned int state = (new_state << 21);
+
+#ifdef DEBUG_CPUSTATE
+ printk("CPUSTATE -> 0x%x\n", new_state);
+#endif
+ spin_lock(&cpustate.lock);
+ cpustate.cached_val = new_state;
+ writel((0xff << 21), cpustate.clr_addr);
+ writel(state, cpustate.set_addr);
+ spin_unlock(&cpustate.lock);
+}
+
+/*
+ * Now all the various file operations that we export.
+ */
+
+static ssize_t cpustate_read(struct file *file, char *buf,
+ size_t count, loff_t * ppos)
+{
+ unsigned char data;
+
+ if (count < 0)
+ return -EFAULT;
+ if (count == 0)
+ return 0;
+
+ data = cpustate_get_state();
+ if (copy_to_user(buf, &data, sizeof(unsigned char)))
+ return -EFAULT;
+ return sizeof(unsigned char);
+}
+
+static ssize_t cpustate_write(struct file *file, const char *buf,
+ size_t count, loff_t * ppos)
+{
+ unsigned char data;
+
+ if (count < 0)
+ return -EFAULT;
+
+ if (count == 0)
+ return 0;
+
+ if (copy_from_user((unsigned char *)&data, buf, sizeof(unsigned char)))
+ return -EFAULT;
+
+ cpustate_set_state(data);
+ return sizeof(unsigned char);
+}
+
+static int cpustate_open(struct inode *inode, struct file *file)
+{
+ return cpustate_get_ref((file->f_flags & O_EXCL));
+}
+
+static int cpustate_release(struct inode *inode, struct file *file)
+{
+ return cpustate_free_ref();
+}
+
+/*
+ * Info exported via "/proc/sky_cpustate".
+ */
+static int cpustate_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ char *p = page;
+ int len = 0;
+
+ p += sprintf(p, "CPU State: %04x\n", cpustate_get_state());
+ len = p - page;
+
+ if (len <= off + count)
+ *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len > count)
+ len = count;
+ if (len < 0)
+ len = 0;
+ return len;
+}
+
+static struct device_driver hdpu_cpustate_driver = {
+ .name = HDPU_CPUSTATE_NAME,
+ .bus = &platform_bus_type,
+ .probe = hdpu_cpustate_probe,
+ .remove = hdpu_cpustate_remove,
+};
+
+/*
+ * The various file operations we support.
+ */
+static struct file_operations cpustate_fops = {
+ owner:THIS_MODULE,
+ open:cpustate_open,
+ release:cpustate_release,
+ read:cpustate_read,
+ write:cpustate_write,
+ fasync:NULL,
+ poll:NULL,
+ ioctl:NULL,
+ llseek:no_llseek,
+
+};
+
+static struct miscdevice cpustate_dev = {
+ MISC_DYNAMIC_MINOR,
+ "sky_cpustate",
+ &cpustate_fops
+};
+
+static int hdpu_cpustate_probe(struct device *ddev)
+{
+ struct platform_device *pdev = to_platform_device(ddev);
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ cpustate.set_addr = (unsigned long *)res->start;
+ cpustate.clr_addr = (unsigned long *)res->end - 1;
+
+ misc_register(&cpustate_dev);
+ create_proc_read_entry("sky_cpustate", 0, 0, cpustate_read_proc, NULL);
+
+ printk(KERN_INFO "Sky CPU State Driver v" SKY_CPUSTATE_VERSION "\n");
+ return 0;
+}
+static int hdpu_cpustate_remove(struct device *ddev)
+{
+
+ cpustate.set_addr = 0;
+ cpustate.clr_addr = 0;
+
+ remove_proc_entry("sky_cpustate", NULL);
+ misc_deregister(&cpustate_dev);
+ return 0;
+
+}
+
+static int __init cpustate_init(void)
+{
+ int rc;
+ rc = driver_register(&hdpu_cpustate_driver);
+ return rc;
+}
+
+static void __exit cpustate_exit(void)
+{
+ driver_unregister(&hdpu_cpustate_driver);
+}
+
+module_init(cpustate_init);
+module_exit(cpustate_exit);
+
+MODULE_AUTHOR("Brian Waite");
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * Sky Nexus Register Driver
+ *
+ * Copyright (C) 2002 Brian Waite
+ *
+ * This driver allows reading the Nexus register
+ * It exports the /proc/sky_chassis_id and also
+ * /proc/sky_slot_id pseudo-file for status information.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/proc_fs.h>
+#include <linux/hdpu_features.h>
+#include <linux/pci.h>
+
+#include <linux/device.h>
+
+static int hdpu_nexus_probe(struct device *ddev);
+static int hdpu_nexus_remove(struct device *ddev);
+
+static struct proc_dir_entry *hdpu_slot_id;
+static struct proc_dir_entry *hdpu_chassis_id;
+static int slot_id = -1;
+static int chassis_id = -1;
+
+static struct device_driver hdpu_nexus_driver = {
+ .name = HDPU_NEXUS_NAME,
+ .bus = &platform_bus_type,
+ .probe = hdpu_nexus_probe,
+ .remove = hdpu_nexus_remove,
+};
+
+int hdpu_slot_id_read(char *buffer, char **buffer_location, off_t offset,
+ int buffer_length, int *zero, void *ptr)
+{
+
+ if (offset > 0)
+ return 0;
+ return sprintf(buffer, "%d\n", slot_id);
+}
+
+int hdpu_chassis_id_read(char *buffer, char **buffer_location, off_t offset,
+ int buffer_length, int *zero, void *ptr)
+{
+
+ if (offset > 0)
+ return 0;
+ return sprintf(buffer, "%d\n", chassis_id);
+}
+
+static int hdpu_nexus_probe(struct device *ddev)
+{
+ struct platform_device *pdev = to_platform_device(ddev);
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ int *nexus_id_addr;
+ nexus_id_addr =
+ ioremap(res->start, (unsigned long)(res->end - res->start));
+ if (nexus_id_addr) {
+ slot_id = (*nexus_id_addr >> 8) & 0x1f;
+ chassis_id = *nexus_id_addr & 0xff;
+ iounmap(nexus_id_addr);
+ } else
+ printk("Could not map slot id\n");
+ hdpu_slot_id = create_proc_entry("sky_slot_id", 0666, &proc_root);
+ hdpu_slot_id->read_proc = hdpu_slot_id_read;
+ hdpu_slot_id->nlink = 1;
+
+ hdpu_chassis_id = create_proc_entry("sky_chassis_id", 0666, &proc_root);
+ hdpu_chassis_id->read_proc = hdpu_chassis_id_read;
+ hdpu_chassis_id->nlink = 1;
+ return 0;
+}
+
+static int hdpu_nexus_remove(struct device *ddev)
+{
+ slot_id = -1;
+ chassis_id = -1;
+ remove_proc_entry("sky_slot_id", &proc_root);
+ remove_proc_entry("sky_chassis_id", &proc_root);
+ hdpu_slot_id = 0;
+ hdpu_chassis_id = 0;
+ return 0;
+}
+
+static int __init nexus_init(void)
+{
+ int rc;
+ rc = driver_register(&hdpu_nexus_driver);
+ return rc;
+}
+
+static void __exit nexus_exit(void)
+{
+ driver_unregister(&hdpu_nexus_driver);
+}
+
+module_init(nexus_init);
+module_exit(nexus_exit);
+
+MODULE_AUTHOR("Brian Waite");
+MODULE_LICENSE("GPL");
--- /dev/null
+/*** -*- linux-c -*- **********************************************************
+
+ Driver for Atmel at76c502 at76c504 and at76c506 wireless cards.
+
+ Copyright 2005 Dan Williams and Red Hat, 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 software 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 Atmel wireless lan drivers; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+******************************************************************************/
+
+#ifndef _ATMEL_H
+#define _ATMEL_H
+
+typedef enum {
+ ATMEL_FW_TYPE_NONE = 0,
+ ATMEL_FW_TYPE_502,
+ ATMEL_FW_TYPE_502D,
+ ATMEL_FW_TYPE_502E,
+ ATMEL_FW_TYPE_502_3COM,
+ ATMEL_FW_TYPE_504,
+ ATMEL_FW_TYPE_504_2958,
+ ATMEL_FW_TYPE_504A_2958,
+ ATMEL_FW_TYPE_506
+} AtmelFWType;
+
+struct net_device *init_atmel_card(unsigned short, int, const AtmelFWType, struct device *,
+ int (*present_func)(void *), void * );
+void stop_atmel_card( struct net_device *, int );
+int atmel_open( struct net_device * );
+
+#endif
--- /dev/null
+#
+# Makefile for Jasmine adapter
+#
+
+obj-$(CONFIG_SERIAL_JSM) += jsm.o
+
+jsm-objs := jsm_driver.o jsm_neo.o jsm_tty.o
+
--- /dev/null
+#
+# Makefile for the SuperH specific drivers.
+#
+
+obj-$(CONFIG_SUPERHYWAY) += superhyway/
+
--- /dev/null
+#
+# Makefile for the SuperHyway bus drivers.
+#
+
+obj-$(CONFIG_SUPERHYWAY) += superhyway.o
+obj-$(CONFIG_SYSFS) += superhyway-sysfs.o
+
--- /dev/null
+/*
+ * drivers/sh/superhyway/superhyway-sysfs.c
+ *
+ * SuperHyway Bus sysfs interface
+ *
+ * Copyright (C) 2004, 2005 Paul Mundt <lethal@linux-sh.org>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/superhyway.h>
+
+#define superhyway_ro_attr(name, fmt, field) \
+static ssize_t name##_show(struct device *dev, char *buf) \
+{ \
+ struct superhyway_device *s = to_superhyway_device(dev); \
+ return sprintf(buf, fmt, s->field); \
+}
+
+/* VCR flags */
+superhyway_ro_attr(perr_flags, "0x%02x\n", vcr.perr_flags);
+superhyway_ro_attr(merr_flags, "0x%02x\n", vcr.merr_flags);
+superhyway_ro_attr(mod_vers, "0x%04x\n", vcr.mod_vers);
+superhyway_ro_attr(mod_id, "0x%04x\n", vcr.mod_id);
+superhyway_ro_attr(bot_mb, "0x%02x\n", vcr.bot_mb);
+superhyway_ro_attr(top_mb, "0x%02x\n", vcr.top_mb);
+
+/* Misc */
+superhyway_ro_attr(resource, "0x%08lx\n", resource.start);
+
+struct device_attribute superhyway_dev_attrs[] = {
+ __ATTR_RO(perr_flags),
+ __ATTR_RO(merr_flags),
+ __ATTR_RO(mod_vers),
+ __ATTR_RO(mod_id),
+ __ATTR_RO(bot_mb),
+ __ATTR_RO(top_mb),
+ __ATTR_RO(resource),
+ __ATTR_NULL,
+};
+
--- /dev/null
+/*
+ * drivers/sh/superhyway/superhyway.c
+ *
+ * SuperHyway Bus Driver
+ *
+ * Copyright (C) 2004, 2005 Paul Mundt <lethal@linux-sh.org>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/superhyway.h>
+
+static int superhyway_devices;
+
+static struct device superhyway_bus_device = {
+ .bus_id = "superhyway",
+};
+
+static void superhyway_device_release(struct device *dev)
+{
+ kfree(to_superhyway_device(dev));
+}
+
+/**
+ * superhyway_add_device - Add a SuperHyway module
+ * @mod_id: Module ID (taken from MODULE.VCR.MOD_ID).
+ * @base: Physical address where module is mapped.
+ * @vcr: VCR value.
+ *
+ * This is responsible for adding a new SuperHyway module. This sets up a new
+ * struct superhyway_device for the module being added. Each one of @mod_id,
+ * @base, and @vcr are registered with the new device for further use
+ * elsewhere.
+ *
+ * Devices are initially added in the order that they are scanned (from the
+ * top-down of the memory map), and are assigned an ID based on the order that
+ * they are added. Any manual addition of a module will thus get the ID after
+ * the devices already discovered regardless of where it resides in memory.
+ *
+ * Further work can and should be done in superhyway_scan_bus(), to be sure
+ * that any new modules are properly discovered and subsequently registered.
+ */
+int superhyway_add_device(unsigned int mod_id, unsigned long base,
+ unsigned long long vcr)
+{
+ struct superhyway_device *dev;
+
+ dev = kmalloc(sizeof(struct superhyway_device), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ memset(dev, 0, sizeof(struct superhyway_device));
+
+ dev->id.id = mod_id;
+ sprintf(dev->name, "SuperHyway device %04x", dev->id.id);
+
+ dev->vcr = *((struct vcr_info *)(&vcr));
+ dev->resource.name = dev->name;
+ dev->resource.start = base;
+ dev->resource.end = dev->resource.start + 0x01000000;
+ dev->dev.parent = &superhyway_bus_device;
+ dev->dev.bus = &superhyway_bus_type;
+ dev->dev.release = superhyway_device_release;
+
+ sprintf(dev->dev.bus_id, "%02x", superhyway_devices);
+
+ superhyway_devices++;
+
+ return device_register(&dev->dev);
+}
+
+static int __init superhyway_init(void)
+{
+ device_register(&superhyway_bus_device);
+ return superhyway_scan_bus();
+}
+
+postcore_initcall(superhyway_init);
+
+static const struct superhyway_device_id *
+superhyway_match_id(const struct superhyway_device_id *ids,
+ struct superhyway_device *dev)
+{
+ while (ids->id) {
+ if (ids->id == dev->id.id)
+ return ids;
+
+ ids++;
+ }
+
+ return NULL;
+}
+
+static int superhyway_device_probe(struct device *dev)
+{
+ struct superhyway_device *shyway_dev = to_superhyway_device(dev);
+ struct superhyway_driver *shyway_drv = to_superhyway_driver(dev->driver);
+
+ if (shyway_drv && shyway_drv->probe) {
+ const struct superhyway_device_id *id;
+
+ id = superhyway_match_id(shyway_drv->id_table, shyway_dev);
+ if (id)
+ return shyway_drv->probe(shyway_dev, id);
+ }
+
+ return -ENODEV;
+}
+
+static int superhyway_device_remove(struct device *dev)
+{
+ struct superhyway_device *shyway_dev = to_superhyway_device(dev);
+ struct superhyway_driver *shyway_drv = to_superhyway_driver(dev->driver);
+
+ if (shyway_drv && shyway_drv->remove) {
+ shyway_drv->remove(shyway_dev);
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
+/**
+ * superhyway_register_driver - Register a new SuperHyway driver
+ * @drv: SuperHyway driver to register.
+ *
+ * This registers the passed in @drv. Any devices matching the id table will
+ * automatically be populated and handed off to the driver's specified probe
+ * routine.
+ */
+int superhyway_register_driver(struct superhyway_driver *drv)
+{
+ drv->drv.name = drv->name;
+ drv->drv.bus = &superhyway_bus_type;
+ drv->drv.probe = superhyway_device_probe;
+ drv->drv.remove = superhyway_device_remove;
+
+ return driver_register(&drv->drv);
+}
+
+/**
+ * superhyway_unregister_driver - Unregister a SuperHyway driver
+ * @drv: SuperHyway driver to unregister.
+ *
+ * This cleans up after superhyway_register_driver(), and should be invoked in
+ * the exit path of any module drivers.
+ */
+void superhyway_unregister_driver(struct superhyway_driver *drv)
+{
+ driver_unregister(&drv->drv);
+}
+
+static int superhyway_bus_match(struct device *dev, struct device_driver *drv)
+{
+ struct superhyway_device *shyway_dev = to_superhyway_device(dev);
+ struct superhyway_driver *shyway_drv = to_superhyway_driver(drv);
+ const struct superhyway_device_id *ids = shyway_drv->id_table;
+
+ if (!ids)
+ return -EINVAL;
+ if (superhyway_match_id(ids, shyway_dev))
+ return 1;
+
+ return -ENODEV;
+}
+
+struct bus_type superhyway_bus_type = {
+ .name = "superhyway",
+ .match = superhyway_bus_match,
+#ifdef CONFIG_SYSFS
+ .dev_attrs = superhyway_dev_attrs,
+#endif
+};
+
+static int __init superhyway_bus_init(void)
+{
+ return bus_register(&superhyway_bus_type);
+}
+
+static void __exit superhyway_bus_exit(void)
+{
+ device_unregister(&superhyway_bus_device);
+ bus_unregister(&superhyway_bus_type);
+}
+
+core_initcall(superhyway_bus_init);
+module_exit(superhyway_bus_exit);
+
+EXPORT_SYMBOL(superhyway_bus_type);
+EXPORT_SYMBOL(superhyway_add_device);
+EXPORT_SYMBOL(superhyway_register_driver);
+EXPORT_SYMBOL(superhyway_unregister_driver);
+
+MODULE_LICENSE("GPL");
--- /dev/null
+
+config USB_SISUSBVGA
+ tristate "USB 2.0 SVGA dongle support (Net2280/SiS315)"
+ depends on USB && USB_EHCI_HCD
+ ---help---
+ Say Y here if you intend to attach a USB2VGA dongle based on a
+ Net2280 and a SiS315 chip.
+
+ Note that this device requires a USB 2.0 host controller. It will not
+ work with USB 1.x controllers.
+
+ To compile this driver as a module, choose M here: the module will be
+ called sisusb. If unsure, say N.
+
--- /dev/null
+#
+# Makefile for the sisusb driver (if driver is inside kernel tree).
+#
+
+obj-$(CONFIG_USB_SISUSBVGA) += sisusb.o
+
--- /dev/null
+#
+# USB Monitor configuration
+#
+
+# In normal life, it makes little sense to have usbmon as a module, and in fact
+# it is harmful, because there is no way to autoload the module.
+# The 'm' option is allowed for hackers who debug the usbmon itself,
+# and for those who have usbcore as a module.
+config USB_MON
+ tristate "USB Monitor"
+ depends on USB
+ default y
+ help
+ If you say Y here, a component which captures the USB traffic
+ between peripheral-specific drivers and HC drivers will be built.
+ The USB_MON is similar in spirit and may be compatible with Dave
+ Harding's USBMon.
+
+ This is somewhat experimental at this time, but it should be safe,
+ as long as you aren't building this as a module and then removing it.
+
+ If unsure, say Y. Do not say M.
--- /dev/null
+#
+# Makefile for USB Core files and filesystem
+#
+
+usbmon-objs := mon_main.o mon_stat.o mon_text.o
+
+obj-$(CONFIG_USB_MON) += usbmon.o
--- /dev/null
+/*
+ * drivers/video/geode/display_gx1.c
+ * -- Geode GX1 display controller
+ *
+ * Copyright (C) 2005 Arcom Control Systems Ltd.
+ *
+ * Based on AMD's original 2.4 driver:
+ * Copyright (C) 2004 Advanced Micro Devices, 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.
+ */
+#include <linux/spinlock.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/div64.h>
+#include <asm/delay.h>
+
+#include "geodefb.h"
+#include "display_gx1.h"
+
+static spinlock_t gx1_conf_reg_lock = SPIN_LOCK_UNLOCKED;
+
+static u8 gx1_read_conf_reg(u8 reg)
+{
+ u8 val, ccr3;
+ unsigned long flags;
+
+ spin_lock_irqsave(&gx1_conf_reg_lock, flags);
+
+ outb(CONFIG_CCR3, 0x22);
+ ccr3 = inb(0x23);
+ outb(CONFIG_CCR3, 0x22);
+ outb(ccr3 | CONFIG_CCR3_MAPEN, 0x23);
+ outb(reg, 0x22);
+ val = inb(0x23);
+ outb(CONFIG_CCR3, 0x22);
+ outb(ccr3, 0x23);
+
+ spin_unlock_irqrestore(&gx1_conf_reg_lock, flags);
+
+ return val;
+}
+
+unsigned gx1_gx_base(void)
+{
+ return (gx1_read_conf_reg(CONFIG_GCR) & 0x03) << 30;
+}
+
+int gx1_frame_buffer_size(void)
+{
+ void __iomem *mc_regs;
+ u32 bank_cfg;
+ int d;
+ unsigned dram_size = 0, fb_base;
+
+ mc_regs = ioremap(gx1_gx_base() + 0x8400, 0x100);
+ if (!mc_regs)
+ return -ENOMEM;
+
+
+ /* Calculate the total size of both DIMM0 and DIMM1. */
+ bank_cfg = readl(mc_regs + MC_BANK_CFG);
+
+ for (d = 0; d < 2; d++) {
+ if ((bank_cfg & MC_BCFG_DIMM0_PG_SZ_MASK) != MC_BCFG_DIMM0_PG_SZ_NO_DIMM)
+ dram_size += 0x400000 << ((bank_cfg & MC_BCFG_DIMM0_SZ_MASK) >> 8);
+ bank_cfg >>= 16; /* look at DIMM1 next */
+ }
+
+ fb_base = (readl(mc_regs + MC_GBASE_ADD) & MC_GADD_GBADD_MASK) << 19;
+
+ iounmap(mc_regs);
+
+ return dram_size - fb_base;
+}
+
+static void gx1_set_mode(struct fb_info *info)
+{
+ struct geodefb_par *par = info->par;
+ u32 gcfg, tcfg, ocfg, dclk_div, val;
+ int hactive, hblankstart, hsyncstart, hsyncend, hblankend, htotal;
+ int vactive, vblankstart, vsyncstart, vsyncend, vblankend, vtotal;
+
+ /* Unlock the display controller registers. */
+ readl(par->dc_regs + DC_UNLOCK);
+ writel(DC_UNLOCK_CODE, par->dc_regs + DC_UNLOCK);
+
+ gcfg = readl(par->dc_regs + DC_GENERAL_CFG);
+ tcfg = readl(par->dc_regs + DC_TIMING_CFG);
+
+ /* Blank the display and disable the timing generator. */
+ tcfg &= ~(DC_TCFG_BLKE | DC_TCFG_TGEN);
+ writel(tcfg, par->dc_regs + DC_TIMING_CFG);
+
+ /* Wait for pending memory requests before disabling the FIFO load. */
+ udelay(100);
+
+ /* Disable FIFO load and compression. */
+ gcfg &= ~(DC_GCFG_DFLE | DC_GCFG_CMPE | DC_GCFG_DECE);
+ writel(gcfg, par->dc_regs + DC_GENERAL_CFG);
+
+ /* Setup DCLK and its divisor. */
+ gcfg &= ~DC_GCFG_DCLK_MASK;
+ writel(gcfg, par->dc_regs + DC_GENERAL_CFG);
+
+ par->vid_ops->set_dclk(info);
+
+ dclk_div = DC_GCFG_DCLK_DIV_1; /* FIXME: may need to divide DCLK by 2 sometimes? */
+ gcfg |= dclk_div;
+ writel(gcfg, par->dc_regs + DC_GENERAL_CFG);
+
+ /* Wait for the clock generatation to settle. This is needed since
+ * some of the register writes that follow require that clock to be
+ * present. */
+ udelay(1000); /* FIXME: seems a little long */
+
+ /*
+ * Setup new mode.
+ */
+
+ /* Clear all unused feature bits. */
+ gcfg = DC_GCFG_VRDY | dclk_div;
+
+ /* Set FIFO priority (default 6/5) and enable. */
+ /* FIXME: increase fifo priority for 1280x1024 modes? */
+ gcfg |= (6 << DC_GCFG_DFHPEL_POS) | (5 << DC_GCFG_DFHPSL_POS) | DC_GCFG_DFLE;
+
+ /* FIXME: Set pixel and line double bits if necessary. */
+
+ /* Framebuffer start offset. */
+ writel(0, par->dc_regs + DC_FB_ST_OFFSET);
+
+ /* Line delta and line buffer length. */
+ writel(info->fix.line_length >> 2, par->dc_regs + DC_LINE_DELTA);
+ writel(((info->var.xres * info->var.bits_per_pixel/8) >> 3) + 2,
+ par->dc_regs + DC_BUF_SIZE);
+
+ /* Output configuration. Enable panel data, set pixel format. */
+ ocfg = DC_OCFG_PCKE | DC_OCFG_PDEL | DC_OCFG_PDEH;
+ if (info->var.bits_per_pixel == 8) ocfg |= DC_OCFG_8BPP;
+
+ /* Enable timing generator, sync and FP data. */
+ tcfg = DC_TCFG_FPPE | DC_TCFG_HSYE | DC_TCFG_VSYE | DC_TCFG_BLKE
+ | DC_TCFG_TGEN;
+
+ /* Horizontal and vertical timings. */
+ hactive = info->var.xres;
+ hblankstart = hactive;
+ hsyncstart = hblankstart + info->var.right_margin;
+ hsyncend = hsyncstart + info->var.hsync_len;
+ hblankend = hsyncend + info->var.left_margin;
+ htotal = hblankend;
+
+ vactive = info->var.yres;
+ vblankstart = vactive;
+ vsyncstart = vblankstart + info->var.lower_margin;
+ vsyncend = vsyncstart + info->var.vsync_len;
+ vblankend = vsyncend + info->var.upper_margin;
+ vtotal = vblankend;
+
+ val = (hactive - 1) | ((htotal - 1) << 16);
+ writel(val, par->dc_regs + DC_H_TIMING_1);
+ val = (hblankstart - 1) | ((hblankend - 1) << 16);
+ writel(val, par->dc_regs + DC_H_TIMING_2);
+ val = (hsyncstart - 1) | ((hsyncend - 1) << 16);
+ writel(val, par->dc_regs + DC_H_TIMING_3);
+ writel(val, par->dc_regs + DC_FP_H_TIMING);
+ val = (vactive - 1) | ((vtotal - 1) << 16);
+ writel(val, par->dc_regs + DC_V_TIMING_1);
+ val = (vblankstart - 1) | ((vblankend - 1) << 16);
+ writel(val, par->dc_regs + DC_V_TIMING_2);
+ val = (vsyncstart - 1) | ((vsyncend - 1) << 16);
+ writel(val, par->dc_regs + DC_V_TIMING_3);
+ val = (vsyncstart - 2) | ((vsyncend - 2) << 16);
+ writel(val, par->dc_regs + DC_FP_V_TIMING);
+
+ /* Write final register values. */
+ writel(ocfg, par->dc_regs + DC_OUTPUT_CFG);
+ writel(tcfg, par->dc_regs + DC_TIMING_CFG);
+ udelay(1000); /* delay after TIMING_CFG. FIXME: perhaps a little long */
+ writel(gcfg, par->dc_regs + DC_GENERAL_CFG);
+
+ par->vid_ops->configure_display(info);
+
+ /* Relock display controller registers */
+ writel(0, par->dc_regs + DC_UNLOCK);
+
+ /* FIXME: write line_length and bpp to Graphics Pipeline GP_BLT_STATUS
+ * register. */
+}
+
+static void gx1_set_hw_palette_reg(struct fb_info *info, unsigned regno,
+ unsigned red, unsigned green, unsigned blue)
+{
+ struct geodefb_par *par = info->par;
+ int val;
+
+ /* Hardware palette is in RGB 6-6-6 format. */
+ val = (red << 2) & 0x3f000;
+ val |= (green >> 4) & 0x00fc0;
+ val |= (blue >> 10) & 0x0003f;
+
+ writel(regno, par->dc_regs + DC_PAL_ADDRESS);
+ writel(val, par->dc_regs + DC_PAL_DATA);
+}
+
+struct geode_dc_ops gx1_dc_ops = {
+ .set_mode = gx1_set_mode,
+ .set_palette_reg = gx1_set_hw_palette_reg,
+};
--- /dev/null
+/*
+ * drivers/video/geode/display_gx1.h
+ * -- Geode GX1 display controller
+ *
+ * Copyright (C) 2005 Arcom Control Systems Ltd.
+ *
+ * Based on AMD's original 2.4 driver:
+ * Copyright (C) 2004 Advanced Micro Devices, 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.
+ */
+#ifndef __DISPLAY_GX1_H__
+#define __DISPLAY_GX1_H__
+
+unsigned gx1_gx_base(void);
+int gx1_frame_buffer_size(void);
+
+extern struct geode_dc_ops gx1_dc_ops;
+
+/* GX1 configuration I/O registers */
+
+#define CONFIG_CCR3 0xc3
+# define CONFIG_CCR3_MAPEN 0x10
+#define CONFIG_GCR 0xb8
+
+/* Memory controller registers */
+
+#define MC_BANK_CFG 0x08
+# define MC_BCFG_DIMM0_SZ_MASK 0x00000700
+# define MC_BCFG_DIMM0_PG_SZ_MASK 0x00000070
+# define MC_BCFG_DIMM0_PG_SZ_NO_DIMM 0x00000070
+
+#define MC_GBASE_ADD 0x14
+# define MC_GADD_GBADD_MASK 0x000003ff
+
+/* Display controller registers */
+
+#define DC_PAL_ADDRESS 0x70
+#define DC_PAL_DATA 0x74
+
+#define DC_UNLOCK 0x00
+# define DC_UNLOCK_CODE 0x00004758
+
+#define DC_GENERAL_CFG 0x04
+# define DC_GCFG_DFLE 0x00000001
+# define DC_GCFG_CURE 0x00000002
+# define DC_GCFG_VCLK_DIV 0x00000004
+# define DC_GCFG_PLNO 0x00000004
+# define DC_GCFG_PPC 0x00000008
+# define DC_GCFG_CMPE 0x00000010
+# define DC_GCFG_DECE 0x00000020
+# define DC_GCFG_DCLK_MASK 0x000000C0
+# define DC_GCFG_DCLK_DIV_1 0x00000080
+# define DC_GCFG_DFHPSL_MASK 0x00000F00
+# define DC_GCFG_DFHPSL_POS 8
+# define DC_GCFG_DFHPEL_MASK 0x0000F000
+# define DC_GCFG_DFHPEL_POS 12
+# define DC_GCFG_CIM_MASK 0x00030000
+# define DC_GCFG_CIM_POS 16
+# define DC_GCFG_FDTY 0x00040000
+# define DC_GCFG_RTPM 0x00080000
+# define DC_GCFG_DAC_RS_MASK 0x00700000
+# define DC_GCFG_DAC_RS_POS 20
+# define DC_GCFG_CKWR 0x00800000
+# define DC_GCFG_LDBL 0x01000000
+# define DC_GCFG_DIAG 0x02000000
+# define DC_GCFG_CH4S 0x04000000
+# define DC_GCFG_SSLC 0x08000000
+# define DC_GCFG_VIDE 0x10000000
+# define DC_GCFG_VRDY 0x20000000
+# define DC_GCFG_DPCK 0x40000000
+# define DC_GCFG_DDCK 0x80000000
+
+#define DC_TIMING_CFG 0x08
+# define DC_TCFG_FPPE 0x00000001
+# define DC_TCFG_HSYE 0x00000002
+# define DC_TCFG_VSYE 0x00000004
+# define DC_TCFG_BLKE 0x00000008
+# define DC_TCFG_DDCK 0x00000010
+# define DC_TCFG_TGEN 0x00000020
+# define DC_TCFG_VIEN 0x00000040
+# define DC_TCFG_BLNK 0x00000080
+# define DC_TCFG_CHSP 0x00000100
+# define DC_TCFG_CVSP 0x00000200
+# define DC_TCFG_FHSP 0x00000400
+# define DC_TCFG_FVSP 0x00000800
+# define DC_TCFG_FCEN 0x00001000
+# define DC_TCFG_CDCE 0x00002000
+# define DC_TCFG_PLNR 0x00002000
+# define DC_TCFG_INTL 0x00004000
+# define DC_TCFG_PXDB 0x00008000
+# define DC_TCFG_BKRT 0x00010000
+# define DC_TCFG_PSD_MASK 0x000E0000
+# define DC_TCFG_PSD_POS 17
+# define DC_TCFG_DDCI 0x08000000
+# define DC_TCFG_SENS 0x10000000
+# define DC_TCFG_DNA 0x20000000
+# define DC_TCFG_VNA 0x40000000
+# define DC_TCFG_VINT 0x80000000
+
+#define DC_OUTPUT_CFG 0x0C
+# define DC_OCFG_8BPP 0x00000001
+# define DC_OCFG_555 0x00000002
+# define DC_OCFG_PCKE 0x00000004
+# define DC_OCFG_FRME 0x00000008
+# define DC_OCFG_DITE 0x00000010
+# define DC_OCFG_2PXE 0x00000020
+# define DC_OCFG_2XCK 0x00000040
+# define DC_OCFG_2IND 0x00000080
+# define DC_OCFG_34ADD 0x00000100
+# define DC_OCFG_FRMS 0x00000200
+# define DC_OCFG_CKSL 0x00000400
+# define DC_OCFG_PRMP 0x00000800
+# define DC_OCFG_PDEL 0x00001000
+# define DC_OCFG_PDEH 0x00002000
+# define DC_OCFG_CFRW 0x00004000
+# define DC_OCFG_DIAG 0x00008000
+
+#define DC_FB_ST_OFFSET 0x10
+#define DC_CB_ST_OFFSET 0x14
+#define DC_CURS_ST_OFFSET 0x18
+#define DC_ICON_ST_OFFSET 0x1C
+#define DC_VID_ST_OFFSET 0x20
+#define DC_LINE_DELTA 0x24
+#define DC_BUF_SIZE 0x28
+
+#define DC_H_TIMING_1 0x30
+#define DC_H_TIMING_2 0x34
+#define DC_H_TIMING_3 0x38
+#define DC_FP_H_TIMING 0x3C
+
+#define DC_V_TIMING_1 0x40
+#define DC_V_TIMING_2 0x44
+#define DC_V_TIMING_3 0x48
+#define DC_FP_V_TIMING 0x4C
+
+#define DC_CURSOR_X 0x50
+#define DC_ICON_X 0x54
+#define DC_V_LINE_CNT 0x54
+#define DC_CURSOR_Y 0x58
+#define DC_ICON_Y 0x5C
+#define DC_SS_LINE_CMP 0x5C
+#define DC_CURSOR_COLOR 0x60
+#define DC_ICON_COLOR 0x64
+#define DC_BORDER_COLOR 0x68
+#define DC_PAL_ADDRESS 0x70
+#define DC_PAL_DATA 0x74
+#define DC_DFIFO_DIAG 0x78
+#define DC_CFIFO_DIAG 0x7C
+
+#endif /* !__DISPLAY_GX1_H__ */
--- /dev/null
+/*
+ * drivers/video/geode/geodefb.h
+ * -- Geode framebuffer driver
+ *
+ * Copyright (C) 2005 Arcom Control Systems 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.
+ */
+#ifndef __GEODEFB_H__
+#define __GEODEFB_H__
+
+struct geodefb_info;
+
+struct geode_dc_ops {
+ void (*set_mode)(struct fb_info *);
+ void (*set_palette_reg)(struct fb_info *, unsigned, unsigned, unsigned, unsigned);
+};
+
+struct geode_vid_ops {
+ void (*set_dclk)(struct fb_info *);
+ void (*configure_display)(struct fb_info *);
+ int (*blank_display)(struct fb_info *, int blank_mode);
+};
+
+struct geodefb_par {
+ int enable_crt;
+ int panel_x; /* dimensions of an attached flat panel, non-zero => enable panel */
+ int panel_y;
+ struct pci_dev *vid_dev;
+ void __iomem *dc_regs;
+ void __iomem *vid_regs;
+ struct geode_dc_ops *dc_ops;
+ struct geode_vid_ops *vid_ops;
+};
+
+#endif /* !__GEODEFB_H__ */
--- /dev/null
+/*
+ * drivers/video/geode/video_cs5530.c
+ * -- CS5530 video device
+ *
+ * Copyright (C) 2005 Arcom Control Systems Ltd.
+ *
+ * Based on AMD's original 2.4 driver:
+ * Copyright (C) 2004 Advanced Micro Devices, 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.
+ */
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/delay.h>
+
+#include "geodefb.h"
+#include "video_cs5530.h"
+
+/*
+ * CS5530 PLL table. This maps pixclocks to the appropriate PLL register
+ * value.
+ */
+struct cs5530_pll_entry {
+ long pixclock; /* ps */
+ u32 pll_value;
+};
+
+static const struct cs5530_pll_entry cs5530_pll_table[] = {
+ { 39721, 0x31C45801, }, /* 25.1750 MHz */
+ { 35308, 0x20E36802, }, /* 28.3220 */
+ { 31746, 0x33915801, }, /* 31.5000 */
+ { 27777, 0x31EC4801, }, /* 36.0000 */
+ { 26666, 0x21E22801, }, /* 37.5000 */
+ { 25000, 0x33088801, }, /* 40.0000 */
+ { 22271, 0x33E22801, }, /* 44.9000 */
+ { 20202, 0x336C4801, }, /* 49.5000 */
+ { 20000, 0x23088801, }, /* 50.0000 */
+ { 19860, 0x23088801, }, /* 50.3500 */
+ { 18518, 0x3708A801, }, /* 54.0000 */
+ { 17777, 0x23E36802, }, /* 56.2500 */
+ { 17733, 0x23E36802, }, /* 56.3916 */
+ { 17653, 0x23E36802, }, /* 56.6444 */
+ { 16949, 0x37C45801, }, /* 59.0000 */
+ { 15873, 0x23EC4801, }, /* 63.0000 */
+ { 15384, 0x37911801, }, /* 65.0000 */
+ { 14814, 0x37963803, }, /* 67.5000 */
+ { 14124, 0x37058803, }, /* 70.8000 */
+ { 13888, 0x3710C805, }, /* 72.0000 */
+ { 13333, 0x37E22801, }, /* 75.0000 */
+ { 12698, 0x27915801, }, /* 78.7500 */
+ { 12500, 0x37D8D802, }, /* 80.0000 */
+ { 11135, 0x27588802, }, /* 89.8000 */
+ { 10582, 0x27EC4802, }, /* 94.5000 */
+ { 10101, 0x27AC6803, }, /* 99.0000 */
+ { 10000, 0x27088801, }, /* 100.0000 */
+ { 9259, 0x2710C805, }, /* 108.0000 */
+ { 8888, 0x27E36802, }, /* 112.5000 */
+ { 7692, 0x27C58803, }, /* 130.0000 */
+ { 7407, 0x27316803, }, /* 135.0000 */
+ { 6349, 0x2F915801, }, /* 157.5000 */
+ { 6172, 0x2F08A801, }, /* 162.0000 */
+ { 5714, 0x2FB11802, }, /* 175.0000 */
+ { 5291, 0x2FEC4802, }, /* 189.0000 */
+ { 4950, 0x2F963803, }, /* 202.0000 */
+ { 4310, 0x2FB1B802, }, /* 232.0000 */
+};
+
+#define NUM_CS5530_FREQUENCIES sizeof(cs5530_pll_table)/sizeof(struct cs5530_pll_entry)
+
+static void cs5530_set_dclk_frequency(struct fb_info *info)
+{
+ struct geodefb_par *par = info->par;
+ int i;
+ u32 value;
+ long min, diff;
+
+ /* Search the table for the closest pixclock. */
+ value = cs5530_pll_table[0].pll_value;
+ min = cs5530_pll_table[0].pixclock - info->var.pixclock;
+ if (min < 0) min = -min;
+ for (i = 1; i < NUM_CS5530_FREQUENCIES; i++) {
+ diff = cs5530_pll_table[i].pixclock - info->var.pixclock;
+ if (diff < 0L) diff = -diff;
+ if (diff < min) {
+ min = diff;
+ value = cs5530_pll_table[i].pll_value;
+ }
+ }
+
+ writel(value, par->vid_regs + CS5530_DOT_CLK_CONFIG);
+ writel(value | 0x80000100, par->vid_regs + CS5530_DOT_CLK_CONFIG); /* set reset and bypass */
+ udelay(500); /* wait for PLL to settle */
+ writel(value & 0x7FFFFFFF, par->vid_regs + CS5530_DOT_CLK_CONFIG); /* clear reset */
+ writel(value & 0x7FFFFEFF, par->vid_regs + CS5530_DOT_CLK_CONFIG); /* clear bypass */
+}
+
+static void cs5530_configure_display(struct fb_info *info)
+{
+ struct geodefb_par *par = info->par;
+ u32 dcfg;
+
+ dcfg = readl(par->vid_regs + CS5530_DISPLAY_CONFIG);
+
+ /* Clear bits from existing mode. */
+ dcfg &= ~(CS5530_DCFG_CRT_SYNC_SKW_MASK | CS5530_DCFG_PWR_SEQ_DLY_MASK
+ | CS5530_DCFG_CRT_HSYNC_POL | CS5530_DCFG_CRT_VSYNC_POL
+ | CS5530_DCFG_FP_PWR_EN | CS5530_DCFG_FP_DATA_EN
+ | CS5530_DCFG_DAC_PWR_EN | CS5530_DCFG_VSYNC_EN
+ | CS5530_DCFG_HSYNC_EN);
+
+ /* Set default sync skew and power sequence delays. */
+ dcfg |= (CS5530_DCFG_CRT_SYNC_SKW_INIT | CS5530_DCFG_PWR_SEQ_DLY_INIT
+ | CS5530_DCFG_GV_PAL_BYP);
+
+ /* Enable DACs, hsync and vsync for CRTs */
+ if (par->enable_crt) {
+ dcfg |= CS5530_DCFG_DAC_PWR_EN;
+ dcfg |= CS5530_DCFG_HSYNC_EN | CS5530_DCFG_VSYNC_EN;
+ }
+ /* Enable panel power and data if using a flat panel. */
+ if (par->panel_x > 0) {
+ dcfg |= CS5530_DCFG_FP_PWR_EN;
+ dcfg |= CS5530_DCFG_FP_DATA_EN;
+ }
+
+ /* Sync polarities. */
+ if (info->var.sync & FB_SYNC_HOR_HIGH_ACT)
+ dcfg |= CS5530_DCFG_CRT_HSYNC_POL;
+ if (info->var.sync & FB_SYNC_VERT_HIGH_ACT)
+ dcfg |= CS5530_DCFG_CRT_VSYNC_POL;
+
+ writel(dcfg, par->vid_regs + CS5530_DISPLAY_CONFIG);
+}
+
+static int cs5530_blank_display(struct fb_info *info, int blank_mode)
+{
+ struct geodefb_par *par = info->par;
+ u32 dcfg;
+ int blank, hsync, vsync;
+
+ switch (blank_mode) {
+ case FB_BLANK_UNBLANK:
+ blank = 0; hsync = 1; vsync = 1;
+ break;
+ case FB_BLANK_NORMAL:
+ blank = 1; hsync = 1; vsync = 1;
+ break;
+ case FB_BLANK_VSYNC_SUSPEND:
+ blank = 1; hsync = 1; vsync = 0;
+ break;
+ case FB_BLANK_HSYNC_SUSPEND:
+ blank = 1; hsync = 0; vsync = 1;
+ break;
+ case FB_BLANK_POWERDOWN:
+ blank = 1; hsync = 0; vsync = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ dcfg = readl(par->vid_regs + CS5530_DISPLAY_CONFIG);
+
+ dcfg &= ~(CS5530_DCFG_DAC_BL_EN | CS5530_DCFG_DAC_PWR_EN
+ | CS5530_DCFG_HSYNC_EN | CS5530_DCFG_VSYNC_EN
+ | CS5530_DCFG_FP_DATA_EN | CS5530_DCFG_FP_PWR_EN);
+
+ if (par->enable_crt) {
+ if (!blank)
+ dcfg |= CS5530_DCFG_DAC_BL_EN | CS5530_DCFG_DAC_PWR_EN;
+ if (hsync)
+ dcfg |= CS5530_DCFG_HSYNC_EN;
+ if (vsync)
+ dcfg |= CS5530_DCFG_VSYNC_EN;
+ }
+ if (par->panel_x > 0) {
+ if (!blank)
+ dcfg |= CS5530_DCFG_FP_DATA_EN;
+ if (hsync && vsync)
+ dcfg |= CS5530_DCFG_FP_PWR_EN;
+ }
+
+ writel(dcfg, par->vid_regs + CS5530_DISPLAY_CONFIG);
+
+ return 0;
+}
+
+struct geode_vid_ops cs5530_vid_ops = {
+ .set_dclk = cs5530_set_dclk_frequency,
+ .configure_display = cs5530_configure_display,
+ .blank_display = cs5530_blank_display,
+};
--- /dev/null
+/*
+ * drivers/video/geode/video_cs5530.h
+ * -- CS5530 video device
+ *
+ * Copyright (C) 2005 Arcom Control Systems Ltd.
+ *
+ * Based on AMD's original 2.4 driver:
+ * Copyright (C) 2004 Advanced Micro Devices, 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.
+ */
+#ifndef __VIDEO_CS5530_H__
+#define __VIDEO_CS5530_H__
+
+extern struct geode_vid_ops cs5530_vid_ops;
+
+/* CS5530 Video device registers */
+
+#define CS5530_VIDEO_CONFIG 0x0000
+# define CS5530_VCFG_VID_EN 0x00000001
+# define CS5530_VCFG_VID_REG_UPDATE 0x00000002
+# define CS5530_VCFG_VID_INP_FORMAT 0x0000000C
+# define CS5530_VCFG_8_BIT_4_2_0 0x00000004
+# define CS5530_VCFG_16_BIT_4_2_0 0x00000008
+# define CS5530_VCFG_GV_SEL 0x00000010
+# define CS5530_VCFG_CSC_BYPASS 0x00000020
+# define CS5530_VCFG_X_FILTER_EN 0x00000040
+# define CS5530_VCFG_Y_FILTER_EN 0x00000080
+# define CS5530_VCFG_LINE_SIZE_LOWER_MASK 0x0000FF00
+# define CS5530_VCFG_INIT_READ_MASK 0x01FF0000
+# define CS5530_VCFG_EARLY_VID_RDY 0x02000000
+# define CS5530_VCFG_LINE_SIZE_UPPER 0x08000000
+# define CS5530_VCFG_4_2_0_MODE 0x10000000
+# define CS5530_VCFG_16_BIT_EN 0x20000000
+# define CS5530_VCFG_HIGH_SPD_INT 0x40000000
+
+#define CS5530_DISPLAY_CONFIG 0x0004
+# define CS5530_DCFG_DIS_EN 0x00000001
+# define CS5530_DCFG_HSYNC_EN 0x00000002
+# define CS5530_DCFG_VSYNC_EN 0x00000004
+# define CS5530_DCFG_DAC_BL_EN 0x00000008
+# define CS5530_DCFG_DAC_PWR_EN 0x00000020
+# define CS5530_DCFG_FP_PWR_EN 0x00000040
+# define CS5530_DCFG_FP_DATA_EN 0x00000080
+# define CS5530_DCFG_CRT_HSYNC_POL 0x00000100
+# define CS5530_DCFG_CRT_VSYNC_POL 0x00000200
+# define CS5530_DCFG_FP_HSYNC_POL 0x00000400
+# define CS5530_DCFG_FP_VSYNC_POL 0x00000800
+# define CS5530_DCFG_XGA_FP 0x00001000
+# define CS5530_DCFG_FP_DITH_EN 0x00002000
+# define CS5530_DCFG_CRT_SYNC_SKW_MASK 0x0001C000
+# define CS5530_DCFG_CRT_SYNC_SKW_INIT 0x00010000
+# define CS5530_DCFG_PWR_SEQ_DLY_MASK 0x000E0000
+# define CS5530_DCFG_PWR_SEQ_DLY_INIT 0x00080000
+# define CS5530_DCFG_VG_CK 0x00100000
+# define CS5530_DCFG_GV_PAL_BYP 0x00200000
+# define CS5530_DCFG_DDC_SCL 0x00400000
+# define CS5530_DCFG_DDC_SDA 0x00800000
+# define CS5530_DCFG_DDC_OE 0x01000000
+# define CS5530_DCFG_16_BIT_EN 0x02000000
+
+#define CS5530_VIDEO_X_POS 0x0008
+#define CS5530_VIDEO_Y_POS 0x000C
+#define CS5530_VIDEO_SCALE 0x0010
+#define CS5530_VIDEO_COLOR_KEY 0x0014
+#define CS5530_VIDEO_COLOR_MASK 0x0018
+#define CS5530_PALETTE_ADDRESS 0x001C
+#define CS5530_PALETTE_DATA 0x0020
+#define CS5530_DOT_CLK_CONFIG 0x0024
+#define CS5530_CRCSIG_TFT_TV 0x0028
+
+#endif /* !__VIDEO_CS5530_H__ */
--- /dev/null
+/*
+ * linux/drivers/video/imxfb.h
+ *
+ * Freescale i.MX Frame Buffer device driver
+ *
+ * Copyright (C) 2004 S.Hauer, Pengutronix
+ *
+ * Copyright (C) 1999 Eric A. Thomas
+ * Based on acornfb.c Copyright (C) Russell King.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+/*
+ * These are the bitfields for each
+ * display depth that we support.
+ */
+struct imxfb_rgb {
+ struct fb_bitfield red;
+ struct fb_bitfield green;
+ struct fb_bitfield blue;
+ struct fb_bitfield transp;
+};
+
+#define RGB_16 (0)
+#define RGB_8 (1)
+#define NR_RGB 2
+
+struct imxfb_info {
+ struct device *dev;
+ struct imxfb_rgb *rgb[NR_RGB];
+
+ u_int max_bpp;
+ u_int max_xres;
+ u_int max_yres;
+
+ /*
+ * These are the addresses we mapped
+ * the framebuffer memory region to.
+ */
+ dma_addr_t map_dma;
+ u_char * map_cpu;
+ u_int map_size;
+
+ u_char * screen_cpu;
+ dma_addr_t screen_dma;
+ u_int palette_size;
+
+ dma_addr_t dbar1;
+ dma_addr_t dbar2;
+
+ u_int pcr;
+ u_int pwmr;
+ u_int lscr1;
+ u_int cmap_inverse:1,
+ cmap_static:1,
+ unused:30;
+
+ void (*lcd_power)(int);
+ void (*backlight_power)(int);
+};
+
+#define IMX_NAME "IMX"
+
+/*
+ * Minimum X and Y resolutions
+ */
+#define MIN_XRES 64
+#define MIN_YRES 64
+
--- /dev/null
+
+ /***************************************************************************\
+|* *|
+|* Copyright 2003 NVIDIA, Corporation. All rights reserved. *|
+|* *|
+|* NOTICE TO USER: The source code is copyrighted under U.S. and *|
+|* international laws. Users and possessors of this source code are *|
+|* hereby granted a nonexclusive, royalty-free copyright license to *|
+|* use this code in individual and commercial software. *|
+|* *|
+|* Any use of this source code must include, in the user documenta- *|
+|* tion and internal comments to the code, notices to the end user *|
+|* as follows: *|
+|* *|
+|* Copyright 2003 NVIDIA, Corporation. All rights reserved. *|
+|* *|
+|* NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY *|
+|* OF THIS SOURCE CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" *|
+|* WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. NVIDIA, CORPOR- *|
+|* ATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOURCE CODE, *|
+|* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE- *|
+|* MENT, AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL *|
+|* NVIDIA, CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT, INCI- *|
+|* DENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RE- *|
+|* SULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION *|
+|* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *|
+|* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE. *|
+|* *|
+|* U.S. Government End Users. This source code is a "commercial *|
+|* item," as that term is defined at 48 C.F.R. 2.101 (OCT 1995), *|
+|* consisting of "commercial computer software" and "commercial *|
+|* computer software documentation," as such terms are used in *|
+|* 48 C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Govern- *|
+|* ment only as a commercial end item. Consistent with 48 C.F.R. *|
+|* 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), *|
+|* all U.S. Government End Users acquire the source code with only *|
+|* those rights set forth herein. *|
+|* *|
+ \***************************************************************************/
+
+/*
+ * GPL Licensing Note - According to Mark Vojkovich, author of the Xorg/
+ * XFree86 'nv' driver, this source code is provided under MIT-style licensing
+ * where the source code is provided "as is" without warranty of any kind.
+ * The only usage restriction is for the copyright notices to be retained
+ * whenever code is used.
+ *
+ * Antonino Daplas <adaplas@pol.net> 2005-03-11
+ */
+
+#define SURFACE_FORMAT 0x00000300
+#define SURFACE_FORMAT_DEPTH8 0x00000001
+#define SURFACE_FORMAT_DEPTH15 0x00000002
+#define SURFACE_FORMAT_DEPTH16 0x00000004
+#define SURFACE_FORMAT_DEPTH24 0x00000006
+#define SURFACE_PITCH 0x00000304
+#define SURFACE_PITCH_SRC 15:0
+#define SURFACE_PITCH_DST 31:16
+#define SURFACE_OFFSET_SRC 0x00000308
+#define SURFACE_OFFSET_DST 0x0000030C
+
+#define ROP_SET 0x00002300
+
+#define PATTERN_FORMAT 0x00004300
+#define PATTERN_FORMAT_DEPTH8 0x00000003
+#define PATTERN_FORMAT_DEPTH16 0x00000001
+#define PATTERN_FORMAT_DEPTH24 0x00000003
+#define PATTERN_COLOR_0 0x00004310
+#define PATTERN_COLOR_1 0x00004314
+#define PATTERN_PATTERN_0 0x00004318
+#define PATTERN_PATTERN_1 0x0000431C
+
+#define CLIP_POINT 0x00006300
+#define CLIP_POINT_X 15:0
+#define CLIP_POINT_Y 31:16
+#define CLIP_SIZE 0x00006304
+#define CLIP_SIZE_WIDTH 15:0
+#define CLIP_SIZE_HEIGHT 31:16
+
+#define LINE_FORMAT 0x00008300
+#define LINE_FORMAT_DEPTH8 0x00000003
+#define LINE_FORMAT_DEPTH16 0x00000001
+#define LINE_FORMAT_DEPTH24 0x00000003
+#define LINE_COLOR 0x00008304
+#define LINE_MAX_LINES 16
+#define LINE_LINES(i) 0x00008400\
+ +(i)*8
+#define LINE_LINES_POINT0_X 15:0
+#define LINE_LINES_POINT0_Y 31:16
+#define LINE_LINES_POINT1_X 47:32
+#define LINE_LINES_POINT1_Y 63:48
+
+#define BLIT_POINT_SRC 0x0000A300
+#define BLIT_POINT_SRC_X 15:0
+#define BLIT_POINT_SRC_Y 31:16
+#define BLIT_POINT_DST 0x0000A304
+#define BLIT_POINT_DST_X 15:0
+#define BLIT_POINT_DST_Y 31:16
+#define BLIT_SIZE 0x0000A308
+#define BLIT_SIZE_WIDTH 15:0
+#define BLIT_SIZE_HEIGHT 31:16
+
+#define RECT_FORMAT 0x0000C300
+#define RECT_FORMAT_DEPTH8 0x00000003
+#define RECT_FORMAT_DEPTH16 0x00000001
+#define RECT_FORMAT_DEPTH24 0x00000003
+#define RECT_SOLID_COLOR 0x0000C3FC
+#define RECT_SOLID_RECTS_MAX_RECTS 32
+#define RECT_SOLID_RECTS(i) 0x0000C400\
+ +(i)*8
+#define RECT_SOLID_RECTS_Y 15:0
+#define RECT_SOLID_RECTS_X 31:16
+#define RECT_SOLID_RECTS_HEIGHT 47:32
+#define RECT_SOLID_RECTS_WIDTH 63:48
+
+#define RECT_EXPAND_ONE_COLOR_CLIP 0x0000C7EC
+#define RECT_EXPAND_ONE_COLOR_CLIP_POINT0_X 15:0
+#define RECT_EXPAND_ONE_COLOR_CLIP_POINT0_Y 31:16
+#define RECT_EXPAND_ONE_COLOR_CLIP_POINT1_X 47:32
+#define RECT_EXPAND_ONE_COLOR_CLIP_POINT1_Y 63:48
+#define RECT_EXPAND_ONE_COLOR_COLOR 0x0000C7F4
+#define RECT_EXPAND_ONE_COLOR_SIZE 0x0000C7F8
+#define RECT_EXPAND_ONE_COLOR_SIZE_WIDTH 15:0
+#define RECT_EXPAND_ONE_COLOR_SIZE_HEIGHT 31:16
+#define RECT_EXPAND_ONE_COLOR_POINT 0x0000C7FC
+#define RECT_EXPAND_ONE_COLOR_POINT_X 15:0
+#define RECT_EXPAND_ONE_COLOR_POINT_Y 31:16
+#define RECT_EXPAND_ONE_COLOR_DATA_MAX_DWORDS 128
+#define RECT_EXPAND_ONE_COLOR_DATA(i) 0x0000C800\
+ +(i)*4
+
+#define RECT_EXPAND_TWO_COLOR_CLIP 0x0000CBE4
+#define RECT_EXPAND_TWO_COLOR_CLIP_POINT0_X 15:0
+#define RECT_EXPAND_TWO_COLOR_CLIP_POINT0_Y 31:16
+#define RECT_EXPAND_TWO_COLOR_CLIP_POINT1_X 47:32
+#define RECT_EXPAND_TWO_COLOR_CLIP_POINT1_Y 63:48
+#define RECT_EXPAND_TWO_COLOR_COLOR_0 0x0000CBEC
+#define RECT_EXPAND_TWO_COLOR_COLOR_1 0x0000CBF0
+#define RECT_EXPAND_TWO_COLOR_SIZE_IN 0x0000CBF4
+#define RECT_EXPAND_TWO_COLOR_SIZE_IN_WIDTH 15:0
+#define RECT_EXPAND_TWO_COLOR_SIZE_IN_HEIGHT 31:16
+#define RECT_EXPAND_TWO_COLOR_SIZE_OUT 0x0000CBF8
+#define RECT_EXPAND_TWO_COLOR_SIZE_OUT_WIDTH 15:0
+#define RECT_EXPAND_TWO_COLOR_SIZE_OUT_HEIGHT 31:16
+#define RECT_EXPAND_TWO_COLOR_POINT 0x0000CBFC
+#define RECT_EXPAND_TWO_COLOR_POINT_X 15:0
+#define RECT_EXPAND_TWO_COLOR_POINT_Y 31:16
+#define RECT_EXPAND_TWO_COLOR_DATA_MAX_DWORDS 128
+#define RECT_EXPAND_TWO_COLOR_DATA(i) 0x0000CC00\
+ +(i)*4
+
+#define STRETCH_BLIT_FORMAT 0x0000E300
+#define STRETCH_BLIT_FORMAT_DEPTH8 0x00000004
+#define STRETCH_BLIT_FORMAT_DEPTH16 0x00000007
+#define STRETCH_BLIT_FORMAT_DEPTH24 0x00000004
+#define STRETCH_BLIT_FORMAT_X8R8G8B8 0x00000004
+#define STRETCH_BLIT_FORMAT_YUYV 0x00000005
+#define STRETCH_BLIT_FORMAT_UYVY 0x00000006
+#define STRETCH_BLIT_CLIP_POINT 0x0000E308
+#define STRETCH_BLIT_CLIP_POINT_X 15:0
+#define STRETCH_BLIT_CLIP_POINT_Y 31:16
+#define STRETCH_BLIT_CLIP_POINT 0x0000E308
+#define STRETCH_BLIT_CLIP_SIZE 0x0000E30C
+#define STRETCH_BLIT_CLIP_SIZE_WIDTH 15:0
+#define STRETCH_BLIT_CLIP_SIZE_HEIGHT 31:16
+#define STRETCH_BLIT_DST_POINT 0x0000E310
+#define STRETCH_BLIT_DST_POINT_X 15:0
+#define STRETCH_BLIT_DST_POINT_Y 31:16
+#define STRETCH_BLIT_DST_SIZE 0x0000E314
+#define STRETCH_BLIT_DST_SIZE_WIDTH 15:0
+#define STRETCH_BLIT_DST_SIZE_HEIGHT 31:16
+#define STRETCH_BLIT_DU_DX 0x0000E318
+#define STRETCH_BLIT_DV_DY 0x0000E31C
+#define STRETCH_BLIT_SRC_SIZE 0x0000E400
+#define STRETCH_BLIT_SRC_SIZE_WIDTH 15:0
+#define STRETCH_BLIT_SRC_SIZE_HEIGHT 31:16
+#define STRETCH_BLIT_SRC_FORMAT 0x0000E404
+#define STRETCH_BLIT_SRC_FORMAT_PITCH 15:0
+#define STRETCH_BLIT_SRC_FORMAT_ORIGIN 23:16
+#define STRETCH_BLIT_SRC_FORMAT_ORIGIN_CENTER 0x00000001
+#define STRETCH_BLIT_SRC_FORMAT_ORIGIN_CORNER 0x00000002
+#define STRETCH_BLIT_SRC_FORMAT_FILTER 31:24
+#define STRETCH_BLIT_SRC_FORMAT_FILTER_POINT_SAMPLE 0x00000000
+#define STRETCH_BLIT_SRC_FORMAT_FILTER_BILINEAR 0x00000001
+#define STRETCH_BLIT_SRC_OFFSET 0x0000E408
+#define STRETCH_BLIT_SRC_POINT 0x0000E40C
+#define STRETCH_BLIT_SRC_POINT_U 15:0
+#define STRETCH_BLIT_SRC_POINT_V 31:16
--- /dev/null
+
+
+obj-y += console/
+obj-y += evtchn/
+obj-y += balloon/
+
+obj-$(CONFIG_XEN_PRIVILEGED_GUEST) += privcmd/
+obj-$(CONFIG_XEN_BLKDEV_BACKEND) += blkback/
+obj-$(CONFIG_XEN_NETDEV_BACKEND) += netback/
+obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += blkfront/
+obj-$(CONFIG_XEN_NETDEV_FRONTEND) += netfront/
+obj-$(CONFIG_XEN_BLKDEV_TAP) += blktap/
+
--- /dev/null
+
+obj-y += balloon.o
--- /dev/null
+/******************************************************************************
+ * balloon.c
+ *
+ * Xen balloon driver - enables returning/claiming memory to/from Xen.
+ *
+ * Copyright (c) 2003, B Dragovic
+ * Copyright (c) 2003-2004, M Williamson, K Fraser
+ *
+ * This file may be distributed separately from the Linux kernel, or
+ * incorporated into other software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (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 THE
+ * AUTHORS OR COPYRIGHT HOLDERS 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 <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/smp_lock.h>
+#include <linux/pagemap.h>
+#include <linux/bootmem.h>
+#include <linux/highmem.h>
+#include <linux/vmalloc.h>
+#include <asm-xen/xen_proc.h>
+#include <asm-xen/hypervisor.h>
+#include <asm-xen/ctrl_if.h>
+#include <asm-xen/balloon.h>
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+#include <asm/tlb.h>
+#include <linux/list.h>
+
+static struct proc_dir_entry *balloon_pde;
+
+static DECLARE_MUTEX(balloon_mutex);
+spinlock_t balloon_lock = SPIN_LOCK_UNLOCKED;
+
+/* We aim for 'current allocation' == 'target allocation'. */
+static unsigned long current_pages;
+static unsigned long target_pages;
+
+/* We may hit the hard limit in Xen. If we do then we remember it. */
+static unsigned long hard_limit;
+
+/*
+ * Drivers may alter the memory reservation independently, but they must
+ * inform the balloon driver so that we can avoid hitting the hard limit.
+ */
+static unsigned long driver_pages;
+
+/* List of ballooned pages, threaded through the mem_map array. */
+static LIST_HEAD(ballooned_pages);
+static unsigned long balloon_low, balloon_high;
+
+/* Main work function, always executed in process context. */
+static void balloon_process(void *unused);
+static DECLARE_WORK(balloon_worker, balloon_process, NULL);
+static struct timer_list balloon_timer;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+/* Use the private and mapping fields of struct page as a list. */
+#define PAGE_TO_LIST(p) ( (struct list_head *)&p->private )
+#define LIST_TO_PAGE(l) ( list_entry( ((unsigned long *)l), \
+ struct page, private ) )
+#define UNLIST_PAGE(p) do { list_del(PAGE_TO_LIST(p)); \
+ p->mapping = NULL; \
+ p->private = 0; } while(0)
+#else
+/* There's a dedicated list field in struct page we can use. */
+#define PAGE_TO_LIST(p) ( &p->list )
+#define LIST_TO_PAGE(l) ( list_entry(l, struct page, list) )
+#define UNLIST_PAGE(p) ( list_del(&p->list) )
+#define pte_offset_kernel pte_offset
+#define pud_t pgd_t
+#define pud_offset(d, va) d
+#define pud_none(d) 0
+#define pud_bad(d) 0
+#define subsys_initcall(_fn) __initcall(_fn)
+#define pfn_to_page(_pfn) (mem_map + (_pfn))
+#endif
+
+#define IPRINTK(fmt, args...) \
+ printk(KERN_INFO "xen_mem: " fmt, ##args)
+#define WPRINTK(fmt, args...) \
+ printk(KERN_WARNING "xen_mem: " fmt, ##args)
+
+/* balloon_append: add the given page to the balloon. */
+static void balloon_append(struct page *page)
+{
+ /* Low memory is re-populated first, so highmem pages go at list tail. */
+ if ( PageHighMem(page) )
+ {
+ list_add_tail(PAGE_TO_LIST(page), &ballooned_pages);
+ balloon_high++;
+ }
+ else
+ {
+ list_add(PAGE_TO_LIST(page), &ballooned_pages);
+ balloon_low++;
+ }
+}
+
+/* balloon_retrieve: rescue a page from the balloon, if it is not empty. */
+static struct page *balloon_retrieve(void)
+{
+ struct page *page;
+
+ if ( list_empty(&ballooned_pages) )
+ return NULL;
+
+ page = LIST_TO_PAGE(ballooned_pages.next);
+ UNLIST_PAGE(page);
+
+ if ( PageHighMem(page) )
+ balloon_high--;
+ else
+ balloon_low--;
+
+ return page;
+}
+
+static void balloon_alarm(unsigned long unused)
+{
+ schedule_work(&balloon_worker);
+}
+
+static unsigned long current_target(void)
+{
+ unsigned long target = min(target_pages, hard_limit);
+ if ( target > (current_pages + balloon_low + balloon_high) )
+ target = current_pages + balloon_low + balloon_high;
+ return target;
+}
+
+/*
+ * We avoid multiple worker processes conflicting via the balloon mutex.
+ * We may of course race updates of the target counts (which are protected
+ * by the balloon lock), or with changes to the Xen hard limit, but we will
+ * recover from these in time.
+ */
+static void balloon_process(void *unused)
+{
+ unsigned long *mfn_list, pfn, i, flags;
+ struct page *page;
+ long credit, debt, rc;
+ void *v;
+
+ down(&balloon_mutex);
+
+ retry:
+ mfn_list = NULL;
+
+ if ( (credit = current_target() - current_pages) > 0 )
+ {
+ mfn_list = (unsigned long *)vmalloc(credit * sizeof(*mfn_list));
+ if ( mfn_list == NULL )
+ goto out;
+
+ balloon_lock(flags);
+ rc = HYPERVISOR_dom_mem_op(
+ MEMOP_increase_reservation, mfn_list, credit, 0);
+ balloon_unlock(flags);
+ if ( rc < credit )
+ {
+ /* We hit the Xen hard limit: reprobe. */
+ if ( HYPERVISOR_dom_mem_op(
+ MEMOP_decrease_reservation, mfn_list, rc, 0) != rc )
+ BUG();
+ hard_limit = current_pages + rc - driver_pages;
+ vfree(mfn_list);
+ goto retry;
+ }
+
+ for ( i = 0; i < credit; i++ )
+ {
+ if ( (page = balloon_retrieve()) == NULL )
+ BUG();
+
+ pfn = page - mem_map;
+ if ( phys_to_machine_mapping[pfn] != INVALID_P2M_ENTRY )
+ BUG();
+
+ /* Update P->M and M->P tables. */
+ phys_to_machine_mapping[pfn] = mfn_list[i];
+ xen_machphys_update(mfn_list[i], pfn);
+
+ /* Link back into the page tables if it's not a highmem page. */
+ if ( pfn < max_low_pfn )
+ {
+ HYPERVISOR_update_va_mapping(
+ (unsigned long)__va(pfn << PAGE_SHIFT),
+ __pte_ma((mfn_list[i] << PAGE_SHIFT) |
+ pgprot_val(PAGE_KERNEL)),
+ 0);
+ }
+
+ /* Finally, relinquish the memory back to the system allocator. */
+ ClearPageReserved(page);
+ set_page_count(page, 1);
+ __free_page(page);
+ }
+
+ current_pages += credit;
+ }
+ else if ( credit < 0 )
+ {
+ debt = -credit;
+
+ mfn_list = (unsigned long *)vmalloc(debt * sizeof(*mfn_list));
+ if ( mfn_list == NULL )
+ goto out;
+
+ for ( i = 0; i < debt; i++ )
+ {
+ if ( (page = alloc_page(GFP_HIGHUSER)) == NULL )
+ {
+ debt = i;
+ break;
+ }
+
+ pfn = page - mem_map;
+ mfn_list[i] = phys_to_machine_mapping[pfn];
+
+ if ( !PageHighMem(page) )
+ {
+ v = phys_to_virt(pfn << PAGE_SHIFT);
+ scrub_pages(v, 1);
+ HYPERVISOR_update_va_mapping(
+ (unsigned long)v, __pte_ma(0), 0);
+ }
+#ifdef CONFIG_XEN_SCRUB_PAGES
+ else
+ {
+ v = kmap(page);
+ scrub_pages(v, 1);
+ kunmap(page);
+ }
+#endif
+ }
+
+ /* Ensure that ballooned highmem pages don't have cached mappings. */
+ kmap_flush_unused();
+ flush_tlb_all();
+
+ /* No more mappings: invalidate pages in P2M and add to balloon. */
+ for ( i = 0; i < debt; i++ )
+ {
+ pfn = mfn_to_pfn(mfn_list[i]);
+ phys_to_machine_mapping[pfn] = INVALID_P2M_ENTRY;
+ balloon_append(pfn_to_page(pfn));
+ }
+
+ if ( HYPERVISOR_dom_mem_op(
+ MEMOP_decrease_reservation, mfn_list, debt, 0) != debt )
+ BUG();
+
+ current_pages -= debt;
+ }
+
+ out:
+ if ( mfn_list != NULL )
+ vfree(mfn_list);
+
+ /* Schedule more work if there is some still to be done. */
+ if ( current_target() != current_pages )
+ mod_timer(&balloon_timer, jiffies + HZ);
+
+ up(&balloon_mutex);
+}
+
+/* Resets the Xen limit, sets new target, and kicks off processing. */
+static void set_new_target(unsigned long target)
+{
+ /* No need for lock. Not read-modify-write updates. */
+ hard_limit = ~0UL;
+ target_pages = target;
+ schedule_work(&balloon_worker);
+}
+
+static void balloon_ctrlif_rx(ctrl_msg_t *msg, unsigned long id)
+{
+ switch ( msg->subtype )
+ {
+ case CMSG_MEM_REQUEST_SET:
+ {
+ mem_request_t *req = (mem_request_t *)&msg->msg[0];
+ set_new_target(req->target);
+ req->status = 0;
+ }
+ break;
+
+ default:
+ msg->length = 0;
+ break;
+ }
+
+ ctrl_if_send_response(msg);
+}
+
+static int balloon_write(struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ char memstring[64], *endchar;
+ unsigned long long target_bytes;
+
+ if ( !capable(CAP_SYS_ADMIN) )
+ return -EPERM;
+
+ if ( count <= 1 )
+ return -EBADMSG; /* runt */
+ if ( count > sizeof(memstring) )
+ return -EFBIG; /* too long */
+
+ if ( copy_from_user(memstring, buffer, count) )
+ return -EFAULT;
+ memstring[sizeof(memstring)-1] = '\0';
+
+ target_bytes = memparse(memstring, &endchar);
+ set_new_target(target_bytes >> PAGE_SHIFT);
+
+ return count;
+}
+
+static int balloon_read(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len;
+
+#define K(_p) ((_p)<<(PAGE_SHIFT-10))
+ len = sprintf(
+ page,
+ "Current allocation: %8lu kB\n"
+ "Requested target: %8lu kB\n"
+ "Low-mem balloon: %8lu kB\n"
+ "High-mem balloon: %8lu kB\n"
+ "Xen hard limit: ",
+ K(current_pages), K(target_pages), K(balloon_low), K(balloon_high));
+
+ if ( hard_limit != ~0UL )
+ len += sprintf(
+ page + len,
+ "%8lu kB (inc. %8lu kB driver headroom)\n",
+ K(hard_limit), K(driver_pages));
+ else
+ len += sprintf(
+ page + len,
+ " ??? kB\n");
+
+ *eof = 1;
+ return len;
+}
+
+static int __init balloon_init(void)
+{
+ unsigned long pfn;
+ struct page *page;
+
+ IPRINTK("Initialising balloon driver.\n");
+
+ current_pages = min(xen_start_info.nr_pages, max_pfn);
+ target_pages = current_pages;
+ balloon_low = 0;
+ balloon_high = 0;
+ driver_pages = 0UL;
+ hard_limit = ~0UL;
+
+ init_timer(&balloon_timer);
+ balloon_timer.data = 0;
+ balloon_timer.function = balloon_alarm;
+
+ if ( (balloon_pde = create_xen_proc_entry("balloon", 0644)) == NULL )
+ {
+ WPRINTK("Unable to create /proc/xen/balloon.\n");
+ return -1;
+ }
+
+ balloon_pde->read_proc = balloon_read;
+ balloon_pde->write_proc = balloon_write;
+
+ (void)ctrl_if_register_receiver(CMSG_MEM_REQUEST, balloon_ctrlif_rx, 0);
+
+ /* Initialise the balloon with excess memory space. */
+ for ( pfn = xen_start_info.nr_pages; pfn < max_pfn; pfn++ )
+ {
+ page = &mem_map[pfn];
+ if ( !PageReserved(page) )
+ balloon_append(page);
+ }
+
+ return 0;
+}
+
+subsys_initcall(balloon_init);
+
+void balloon_update_driver_allowance(long delta)
+{
+ unsigned long flags;
+ balloon_lock(flags);
+ driver_pages += delta; /* non-atomic update */
+ balloon_unlock(flags);
+}
+
+void balloon_put_pages(unsigned long *mfn_list, unsigned long nr_mfns)
+{
+ unsigned long flags;
+
+ balloon_lock(flags);
+ if ( HYPERVISOR_dom_mem_op(MEMOP_decrease_reservation,
+ mfn_list, nr_mfns, 0) != nr_mfns )
+ BUG();
+ current_pages -= nr_mfns; /* non-atomic update */
+ balloon_unlock(flags);
+
+ schedule_work(&balloon_worker);
+}
+
+EXPORT_SYMBOL(balloon_update_driver_allowance);
+EXPORT_SYMBOL(balloon_put_pages);
--- /dev/null
+
+obj-y := blkback.o control.o interface.o vbd.o
--- /dev/null
+/******************************************************************************
+ * arch/xen/drivers/blkif/backend/main.c
+ *
+ * Back-end of the driver for virtual block devices. This portion of the
+ * driver exports a 'unified' block-device interface that can be accessed
+ * by any operating system that implements a compatible front end. A
+ * reference front-end implementation can be found in:
+ * arch/xen/drivers/blkif/frontend
+ *
+ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
+ * Copyright (c) 2005, Christopher Clark
+ */
+
+#include "common.h"
+#include <asm-xen/evtchn.h>
+#ifdef CONFIG_XEN_BLKDEV_GRANT
+#include <asm-xen/xen-public/grant_table.h>
+#endif
+
+/*
+ * These are rather arbitrary. They are fairly large because adjacent requests
+ * pulled from a communication ring are quite likely to end up being part of
+ * the same scatter/gather request at the disc.
+ *
+ * ** TRY INCREASING 'MAX_PENDING_REQS' IF WRITE SPEEDS SEEM TOO LOW **
+ * This will increase the chances of being able to write whole tracks.
+ * 64 should be enough to keep us competitive with Linux.
+ */
+#define MAX_PENDING_REQS 64
+#define BATCH_PER_DOMAIN 16
+
+static unsigned long mmap_vstart;
+#define MMAP_PAGES \
+ (MAX_PENDING_REQS * BLKIF_MAX_SEGMENTS_PER_REQUEST)
+#define MMAP_VADDR(_req,_seg) \
+ (mmap_vstart + \
+ ((_req) * BLKIF_MAX_SEGMENTS_PER_REQUEST * PAGE_SIZE) + \
+ ((_seg) * PAGE_SIZE))
+
+/*
+ * Each outstanding request that we've passed to the lower device layers has a
+ * 'pending_req' allocated to it. Each buffer_head that completes decrements
+ * the pendcnt towards zero. When it hits zero, the specified domain has a
+ * response queued for it, with the saved 'id' passed back.
+ */
+typedef struct {
+ blkif_t *blkif;
+ unsigned long id;
+ int nr_pages;
+ atomic_t pendcnt;
+ unsigned short operation;
+ int status;
+} pending_req_t;
+
+/*
+ * We can't allocate pending_req's in order, since they may complete out of
+ * order. We therefore maintain an allocation ring. This ring also indicates
+ * when enough work has been passed down -- at that point the allocation ring
+ * will be empty.
+ */
+static pending_req_t pending_reqs[MAX_PENDING_REQS];
+static unsigned char pending_ring[MAX_PENDING_REQS];
+static spinlock_t pend_prod_lock = SPIN_LOCK_UNLOCKED;
+/* NB. We use a different index type to differentiate from shared blk rings. */
+typedef unsigned int PEND_RING_IDX;
+#define MASK_PEND_IDX(_i) ((_i)&(MAX_PENDING_REQS-1))
+static PEND_RING_IDX pending_prod, pending_cons;
+#define NR_PENDING_REQS (MAX_PENDING_REQS - pending_prod + pending_cons)
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+static kmem_cache_t *buffer_head_cachep;
+#else
+static request_queue_t *plugged_queue;
+static inline void flush_plugged_queue(void)
+{
+ request_queue_t *q = plugged_queue;
+ if ( q != NULL )
+ {
+ if ( q->unplug_fn != NULL )
+ q->unplug_fn(q);
+ blk_put_queue(q);
+ plugged_queue = NULL;
+ }
+}
+#endif
+
+#ifdef CONFIG_XEN_BLKDEV_GRANT
+/* When using grant tables to map a frame for device access then the
+ * handle returned must be used to unmap the frame. This is needed to
+ * drop the ref count on the frame.
+ */
+static u16 pending_grant_handles[MMAP_PAGES];
+#define pending_handle(_idx, _i) \
+ (pending_grant_handles[((_idx) * BLKIF_MAX_SEGMENTS_PER_REQUEST) + (_i)])
+#define BLKBACK_INVALID_HANDLE (0xFFFF)
+#endif
+
+#ifdef CONFIG_XEN_BLKDEV_TAP_BE
+/*
+ * If the tap driver is used, we may get pages belonging to either the tap
+ * or (more likely) the real frontend. The backend must specify which domain
+ * a given page belongs to in update_va_mapping though. For the moment,
+ * the tap rewrites the ID field of the request to contain the request index
+ * and the id of the real front end domain.
+ */
+#define BLKTAP_COOKIE 0xbeadfeed
+static inline domid_t ID_TO_DOM(unsigned long id) { return (id >> 16); }
+#endif
+
+static int do_block_io_op(blkif_t *blkif, int max_to_do);
+static void dispatch_probe(blkif_t *blkif, blkif_request_t *req);
+static void dispatch_rw_block_io(blkif_t *blkif, blkif_request_t *req);
+static void make_response(blkif_t *blkif, unsigned long id,
+ unsigned short op, int st);
+
+static void fast_flush_area(int idx, int nr_pages)
+{
+#ifdef CONFIG_XEN_BLKDEV_GRANT
+ gnttab_op_t aop[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+ unsigned int i, invcount = 0;
+ u16 handle;
+
+ for ( i = 0; i < nr_pages; i++ )
+ {
+ if ( BLKBACK_INVALID_HANDLE != ( handle = pending_handle(idx, i) ) )
+ {
+ aop[i].u.unmap_grant_ref.host_virt_addr = MMAP_VADDR(idx, i);
+ aop[i].u.unmap_grant_ref.dev_bus_addr = 0;
+ aop[i].u.unmap_grant_ref.handle = handle;
+ pending_handle(idx, i) = BLKBACK_INVALID_HANDLE;
+ invcount++;
+ }
+ }
+ if ( unlikely(HYPERVISOR_grant_table_op(
+ GNTTABOP_unmap_grant_ref, aop, invcount)))
+ BUG();
+#else
+
+ multicall_entry_t mcl[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+ int i;
+
+ for ( i = 0; i < nr_pages; i++ )
+ {
+ mcl[i].op = __HYPERVISOR_update_va_mapping;
+ mcl[i].args[0] = MMAP_VADDR(idx, i);
+ mcl[i].args[1] = 0;
+ mcl[i].args[2] = 0;
+ }
+
+ mcl[nr_pages-1].args[2] = UVMF_TLB_FLUSH|UVMF_ALL;
+ if ( unlikely(HYPERVISOR_multicall(mcl, nr_pages) != 0) )
+ BUG();
+#endif
+}
+
+
+/******************************************************************
+ * BLOCK-DEVICE SCHEDULER LIST MAINTENANCE
+ */
+
+static struct list_head blkio_schedule_list;
+static spinlock_t blkio_schedule_list_lock;
+
+static int __on_blkdev_list(blkif_t *blkif)
+{
+ return blkif->blkdev_list.next != NULL;
+}
+
+static void remove_from_blkdev_list(blkif_t *blkif)
+{
+ unsigned long flags;
+ if ( !__on_blkdev_list(blkif) ) return;
+ spin_lock_irqsave(&blkio_schedule_list_lock, flags);
+ if ( __on_blkdev_list(blkif) )
+ {
+ list_del(&blkif->blkdev_list);
+ blkif->blkdev_list.next = NULL;
+ blkif_put(blkif);
+ }
+ spin_unlock_irqrestore(&blkio_schedule_list_lock, flags);
+}
+
+static void add_to_blkdev_list_tail(blkif_t *blkif)
+{
+ unsigned long flags;
+ if ( __on_blkdev_list(blkif) ) return;
+ spin_lock_irqsave(&blkio_schedule_list_lock, flags);
+ if ( !__on_blkdev_list(blkif) && (blkif->status == CONNECTED) )
+ {
+ list_add_tail(&blkif->blkdev_list, &blkio_schedule_list);
+ blkif_get(blkif);
+ }
+ spin_unlock_irqrestore(&blkio_schedule_list_lock, flags);
+}
+
+
+/******************************************************************
+ * SCHEDULER FUNCTIONS
+ */
+
+static DECLARE_WAIT_QUEUE_HEAD(blkio_schedule_wait);
+
+static int blkio_schedule(void *arg)
+{
+ DECLARE_WAITQUEUE(wq, current);
+
+ blkif_t *blkif;
+ struct list_head *ent;
+
+ daemonize(
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+ "xenblkd"
+#endif
+ );
+
+ for ( ; ; )
+ {
+ /* Wait for work to do. */
+ add_wait_queue(&blkio_schedule_wait, &wq);
+ set_current_state(TASK_INTERRUPTIBLE);
+ if ( (NR_PENDING_REQS == MAX_PENDING_REQS) ||
+ list_empty(&blkio_schedule_list) )
+ schedule();
+ __set_current_state(TASK_RUNNING);
+ remove_wait_queue(&blkio_schedule_wait, &wq);
+
+ /* Queue up a batch of requests. */
+ while ( (NR_PENDING_REQS < MAX_PENDING_REQS) &&
+ !list_empty(&blkio_schedule_list) )
+ {
+ ent = blkio_schedule_list.next;
+ blkif = list_entry(ent, blkif_t, blkdev_list);
+ blkif_get(blkif);
+ remove_from_blkdev_list(blkif);
+ if ( do_block_io_op(blkif, BATCH_PER_DOMAIN) )
+ add_to_blkdev_list_tail(blkif);
+ blkif_put(blkif);
+ }
+
+ /* Push the batch through to disc. */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+ run_task_queue(&tq_disk);
+#else
+ flush_plugged_queue();
+#endif
+ }
+}
+
+static void maybe_trigger_blkio_schedule(void)
+{
+ /*
+ * Needed so that two processes, who together make the following predicate
+ * true, don't both read stale values and evaluate the predicate
+ * incorrectly. Incredibly unlikely to stall the scheduler on x86, but...
+ */
+ smp_mb();
+
+ if ( (NR_PENDING_REQS < (MAX_PENDING_REQS/2)) &&
+ !list_empty(&blkio_schedule_list) )
+ wake_up(&blkio_schedule_wait);
+}
+
+
+
+/******************************************************************
+ * COMPLETION CALLBACK -- Called as bh->b_end_io()
+ */
+
+static void __end_block_io_op(pending_req_t *pending_req, int uptodate)
+{
+ unsigned long flags;
+
+ /* An error fails the entire request. */
+ if ( !uptodate )
+ {
+ DPRINTK("Buffer not up-to-date at end of operation\n");
+ pending_req->status = BLKIF_RSP_ERROR;
+ }
+
+ if ( atomic_dec_and_test(&pending_req->pendcnt) )
+ {
+ int pending_idx = pending_req - pending_reqs;
+ fast_flush_area(pending_idx, pending_req->nr_pages);
+ make_response(pending_req->blkif, pending_req->id,
+ pending_req->operation, pending_req->status);
+ blkif_put(pending_req->blkif);
+ spin_lock_irqsave(&pend_prod_lock, flags);
+ pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx;
+ spin_unlock_irqrestore(&pend_prod_lock, flags);
+ maybe_trigger_blkio_schedule();
+ }
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+static void end_block_io_op(struct buffer_head *bh, int uptodate)
+{
+ __end_block_io_op(bh->b_private, uptodate);
+ kmem_cache_free(buffer_head_cachep, bh);
+}
+#else
+static int end_block_io_op(struct bio *bio, unsigned int done, int error)
+{
+ if ( done || error )
+ __end_block_io_op(bio->bi_private, (done && !error));
+ bio_put(bio);
+ return error;
+}
+#endif
+
+
+/******************************************************************************
+ * NOTIFICATION FROM GUEST OS.
+ */
+
+irqreturn_t blkif_be_int(int irq, void *dev_id, struct pt_regs *regs)
+{
+ blkif_t *blkif = dev_id;
+ add_to_blkdev_list_tail(blkif);
+ maybe_trigger_blkio_schedule();
+ return IRQ_HANDLED;
+}
+
+
+
+/******************************************************************
+ * DOWNWARD CALLS -- These interface with the block-device layer proper.
+ */
+
+static int do_block_io_op(blkif_t *blkif, int max_to_do)
+{
+ blkif_back_ring_t *blk_ring = &blkif->blk_ring;
+ blkif_request_t *req;
+ RING_IDX i, rp;
+ int more_to_do = 0;
+
+ rp = blk_ring->sring->req_prod;
+ rmb(); /* Ensure we see queued requests up to 'rp'. */
+
+ for ( i = blk_ring->req_cons;
+ (i != rp) && !RING_REQUEST_CONS_OVERFLOW(blk_ring, i);
+ i++ )
+ {
+ if ( (max_to_do-- == 0) || (NR_PENDING_REQS == MAX_PENDING_REQS) )
+ {
+ more_to_do = 1;
+ break;
+ }
+
+ req = RING_GET_REQUEST(blk_ring, i);
+ switch ( req->operation )
+ {
+ case BLKIF_OP_READ:
+ case BLKIF_OP_WRITE:
+ dispatch_rw_block_io(blkif, req);
+ break;
+
+ case BLKIF_OP_PROBE:
+ dispatch_probe(blkif, req);
+ break;
+
+ default:
+ DPRINTK("error: unknown block io operation [%d]\n",
+ req->operation);
+ make_response(blkif, req->id, req->operation, BLKIF_RSP_ERROR);
+ break;
+ }
+ }
+
+ blk_ring->req_cons = i;
+ return more_to_do;
+}
+
+static void dispatch_probe(blkif_t *blkif, blkif_request_t *req)
+{
+ int rsp = BLKIF_RSP_ERROR;
+ int pending_idx = pending_ring[MASK_PEND_IDX(pending_cons)];
+
+ /* We expect one buffer only. */
+ if ( unlikely(req->nr_segments != 1) )
+ goto out;
+
+ /* Make sure the buffer is page-sized. */
+ if ( (blkif_first_sect(req->frame_and_sects[0]) != 0) ||
+ (blkif_last_sect(req->frame_and_sects[0]) != 7) )
+ goto out;
+
+#ifdef CONFIG_XEN_BLKDEV_GRANT
+ {
+ gnttab_op_t op;
+
+ op.u.map_grant_ref.host_virt_addr = MMAP_VADDR(pending_idx, 0);
+ op.u.map_grant_ref.flags = GNTMAP_host_map;
+ op.u.map_grant_ref.ref = blkif_gref_from_fas(req->frame_and_sects[0]);
+ op.u.map_grant_ref.dom = blkif->domid;
+
+ if ( unlikely(HYPERVISOR_grant_table_op(
+ GNTTABOP_map_grant_ref, &op, 1)))
+ BUG();
+
+ if ( op.u.map_grant_ref.handle < 0 )
+ goto out;
+
+ pending_handle(pending_idx, 0) = op.u.map_grant_ref.handle;
+ }
+#else /* else CONFIG_XEN_BLKDEV_GRANT */
+
+#ifdef CONFIG_XEN_BLKDEV_TAP_BE
+ /* Grab the real frontend out of the probe message. */
+ if (req->frame_and_sects[1] == BLKTAP_COOKIE)
+ blkif->is_blktap = 1;
+#endif
+
+
+#ifdef CONFIG_XEN_BLKDEV_TAP_BE
+ if ( HYPERVISOR_update_va_mapping_otherdomain(
+ MMAP_VADDR(pending_idx, 0),
+ (pte_t) { (req->frame_and_sects[0] & PAGE_MASK) | __PAGE_KERNEL },
+ 0, (blkif->is_blktap ? ID_TO_DOM(req->id) : blkif->domid) ) )
+
+ goto out;
+#else
+ if ( HYPERVISOR_update_va_mapping_otherdomain(
+ MMAP_VADDR(pending_idx, 0),
+ (pte_t) { (req->frame_and_sects[0] & PAGE_MASK) | __PAGE_KERNEL },
+ 0, blkif->domid) )
+
+ goto out;
+#endif
+#endif /* endif CONFIG_XEN_BLKDEV_GRANT */
+
+ rsp = vbd_probe(blkif, (vdisk_t *)MMAP_VADDR(pending_idx, 0),
+ PAGE_SIZE / sizeof(vdisk_t));
+
+ out:
+ fast_flush_area(pending_idx, 1);
+ make_response(blkif, req->id, req->operation, rsp);
+}
+
+static void dispatch_rw_block_io(blkif_t *blkif, blkif_request_t *req)
+{
+ extern void ll_rw_block(int rw, int nr, struct buffer_head * bhs[]);
+ int operation = (req->operation == BLKIF_OP_WRITE) ? WRITE : READ;
+ unsigned long fas = 0;
+ int i, pending_idx = pending_ring[MASK_PEND_IDX(pending_cons)];
+ pending_req_t *pending_req;
+#ifdef CONFIG_XEN_BLKDEV_GRANT
+ gnttab_op_t aop[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+#else
+ unsigned long remap_prot;
+ multicall_entry_t mcl[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+#endif
+ struct phys_req preq;
+ struct {
+ unsigned long buf; unsigned int nsec;
+ } seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+ unsigned int nseg;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+ struct buffer_head *bh;
+#else
+ struct bio *bio = NULL, *biolist[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+ int nbio = 0;
+ request_queue_t *q;
+#endif
+
+ /* Check that number of segments is sane. */
+ nseg = req->nr_segments;
+ if ( unlikely(nseg == 0) ||
+ unlikely(nseg > BLKIF_MAX_SEGMENTS_PER_REQUEST) )
+ {
+ DPRINTK("Bad number of segments in request (%d)\n", nseg);
+ goto bad_descriptor;
+ }
+
+ preq.dev = req->device;
+ preq.sector_number = req->sector_number;
+ preq.nr_sects = 0;
+
+#ifdef CONFIG_XEN_BLKDEV_GRANT
+ for ( i = 0; i < nseg; i++ )
+ {
+ fas = req->frame_and_sects[i];
+ seg[i].nsec = blkif_last_sect(fas) - blkif_first_sect(fas) + 1;
+
+ if ( seg[i].nsec <= 0 )
+ goto bad_descriptor;
+ preq.nr_sects += seg[i].nsec;
+
+ aop[i].u.map_grant_ref.host_virt_addr = MMAP_VADDR(pending_idx, i);
+
+ aop[i].u.map_grant_ref.dom = blkif->domid;
+ aop[i].u.map_grant_ref.ref = blkif_gref_from_fas(fas);
+ aop[i].u.map_grant_ref.flags = ( GNTMAP_host_map |
+ ( ( operation == READ ) ?
+ 0 : GNTMAP_readonly ) );
+ }
+
+ if ( unlikely(HYPERVISOR_grant_table_op(
+ GNTTABOP_map_grant_ref, aop, nseg)))
+ BUG();
+
+ for ( i = 0; i < nseg; i++ )
+ {
+ if ( unlikely(aop[i].u.map_grant_ref.handle < 0) )
+ {
+ DPRINTK("invalid buffer -- could not remap it\n");
+ fast_flush_area(pending_idx, nseg);
+ goto bad_descriptor;
+ }
+
+ phys_to_machine_mapping[__pa(MMAP_VADDR(pending_idx, i))>>PAGE_SHIFT] =
+ FOREIGN_FRAME(aop[i].u.map_grant_ref.dev_bus_addr);
+
+ pending_handle(pending_idx, i) = aop[i].u.map_grant_ref.handle;
+ }
+#endif
+
+ for ( i = 0; i < nseg; i++ )
+ {
+ fas = req->frame_and_sects[i];
+#ifdef CONFIG_XEN_BLKDEV_GRANT
+ seg[i].buf = (aop[i].u.map_grant_ref.dev_bus_addr << PAGE_SHIFT) |
+ (blkif_first_sect(fas) << 9);
+#else
+ seg[i].buf = (fas & PAGE_MASK) | (blkif_first_sect(fas) << 9);
+ seg[i].nsec = blkif_last_sect(fas) - blkif_first_sect(fas) + 1;
+ if ( seg[i].nsec <= 0 )
+ goto bad_descriptor;
+ preq.nr_sects += seg[i].nsec;
+#endif
+ }
+
+ if ( vbd_translate(&preq, blkif, operation) != 0 )
+ {
+ DPRINTK("access denied: %s of [%llu,%llu] on dev=%04x\n",
+ operation == READ ? "read" : "write", preq.sector_number,
+ preq.sector_number + preq.nr_sects, preq.dev);
+ goto bad_descriptor;
+ }
+
+#ifndef CONFIG_XEN_BLKDEV_GRANT
+ if ( operation == READ )
+ remap_prot = _PAGE_PRESENT|_PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_RW;
+ else
+ remap_prot = _PAGE_PRESENT|_PAGE_DIRTY|_PAGE_ACCESSED;
+
+ for ( i = 0; i < nseg; i++ )
+ {
+ mcl[i].op = __HYPERVISOR_update_va_mapping_otherdomain;
+ mcl[i].args[0] = MMAP_VADDR(pending_idx, i);
+ mcl[i].args[1] = (seg[i].buf & PAGE_MASK) | remap_prot;
+ mcl[i].args[2] = 0;
+ mcl[i].args[3] = blkif->domid;
+#ifdef CONFIG_XEN_BLKDEV_TAP_BE
+ if ( blkif->is_blktap )
+ mcl[i].args[3] = ID_TO_DOM(req->id);
+#endif
+ phys_to_machine_mapping[__pa(MMAP_VADDR(pending_idx, i))>>PAGE_SHIFT] =
+ FOREIGN_FRAME(seg[i].buf >> PAGE_SHIFT);
+ }
+
+ BUG_ON(HYPERVISOR_multicall(mcl, nseg) != 0);
+
+ for ( i = 0; i < nseg; i++ )
+ {
+ if ( unlikely(mcl[i].args[5] != 0) )
+ {
+ DPRINTK("invalid buffer -- could not remap it\n");
+ fast_flush_area(pending_idx, nseg);
+ goto bad_descriptor;
+ }
+ }
+#endif /* end ifndef CONFIG_XEN_BLKDEV_GRANT */
+
+ pending_req = &pending_reqs[pending_idx];
+ pending_req->blkif = blkif;
+ pending_req->id = req->id;
+ pending_req->operation = operation;
+ pending_req->status = BLKIF_RSP_OKAY;
+ pending_req->nr_pages = nseg;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+
+ atomic_set(&pending_req->pendcnt, nseg);
+ pending_cons++;
+ blkif_get(blkif);
+
+ for ( i = 0; i < nseg; i++ )
+ {
+ bh = kmem_cache_alloc(buffer_head_cachep, GFP_KERNEL);
+ if ( unlikely(bh == NULL) )
+ {
+ __end_block_io_op(pending_req, 0);
+ continue;
+ }
+
+ memset(bh, 0, sizeof (struct buffer_head));
+
+ init_waitqueue_head(&bh->b_wait);
+ bh->b_size = seg[i].nsec << 9;
+ bh->b_dev = preq.dev;
+ bh->b_rdev = preq.dev;
+ bh->b_rsector = (unsigned long)preq.sector_number;
+ bh->b_data = (char *)MMAP_VADDR(pending_idx, i) +
+ (seg[i].buf & ~PAGE_MASK);
+ bh->b_page = virt_to_page(MMAP_VADDR(pending_idx, i));
+ bh->b_end_io = end_block_io_op;
+ bh->b_private = pending_req;
+
+ bh->b_state = (1 << BH_Mapped) | (1 << BH_Lock) |
+ (1 << BH_Req) | (1 << BH_Launder);
+ if ( operation == WRITE )
+ bh->b_state |= (1 << BH_JBD) | (1 << BH_Req) | (1 << BH_Uptodate);
+
+ atomic_set(&bh->b_count, 1);
+
+ /* Dispatch a single request. We'll flush it to disc later. */
+ generic_make_request(operation, bh);
+
+ preq.sector_number += seg[i].nsec;
+ }
+
+#else
+
+ for ( i = 0; i < nseg; i++ )
+ {
+ while ( (bio == NULL) ||
+ (bio_add_page(bio,
+ virt_to_page(MMAP_VADDR(pending_idx, i)),
+ seg[i].nsec << 9,
+ seg[i].buf & ~PAGE_MASK) == 0) )
+ {
+ bio = biolist[nbio++] = bio_alloc(GFP_KERNEL, nseg-i);
+ if ( unlikely(bio == NULL) )
+ {
+ for ( i = 0; i < (nbio-1); i++ )
+ bio_put(biolist[i]);
+ fast_flush_area(pending_idx, nseg);
+ goto bad_descriptor;
+ }
+
+ bio->bi_bdev = preq.bdev;
+ bio->bi_private = pending_req;
+ bio->bi_end_io = end_block_io_op;
+ bio->bi_sector = preq.sector_number;
+ }
+
+ preq.sector_number += seg[i].nsec;
+ }
+
+ if ( (q = bdev_get_queue(bio->bi_bdev)) != plugged_queue )
+ {
+ flush_plugged_queue();
+ blk_get_queue(q);
+ plugged_queue = q;
+ }
+
+ atomic_set(&pending_req->pendcnt, nbio);
+ pending_cons++;
+ blkif_get(blkif);
+
+ for ( i = 0; i < nbio; i++ )
+ submit_bio(operation, biolist[i]);
+
+#endif
+
+ return;
+
+ bad_descriptor:
+ make_response(blkif, req->id, req->operation, BLKIF_RSP_ERROR);
+}
+
+
+
+/******************************************************************
+ * MISCELLANEOUS SETUP / TEARDOWN / DEBUGGING
+ */
+
+
+static void make_response(blkif_t *blkif, unsigned long id,
+ unsigned short op, int st)
+{
+ blkif_response_t *resp;
+ unsigned long flags;
+ blkif_back_ring_t *blk_ring = &blkif->blk_ring;
+
+ /* Place on the response ring for the relevant domain. */
+ spin_lock_irqsave(&blkif->blk_ring_lock, flags);
+ resp = RING_GET_RESPONSE(blk_ring, blk_ring->rsp_prod_pvt);
+ resp->id = id;
+ resp->operation = op;
+ resp->status = st;
+ wmb(); /* Ensure other side can see the response fields. */
+ blk_ring->rsp_prod_pvt++;
+ RING_PUSH_RESPONSES(blk_ring);
+ spin_unlock_irqrestore(&blkif->blk_ring_lock, flags);
+
+ /* Kick the relevant domain. */
+ notify_via_evtchn(blkif->evtchn);
+}
+
+void blkif_deschedule(blkif_t *blkif)
+{
+ remove_from_blkdev_list(blkif);
+}
+
+static int __init blkif_init(void)
+{
+ int i;
+
+ if ( !(xen_start_info.flags & SIF_INITDOMAIN) &&
+ !(xen_start_info.flags & SIF_BLK_BE_DOMAIN) )
+ return 0;
+
+ blkif_interface_init();
+
+ if ( (mmap_vstart = allocate_empty_lowmem_region(MMAP_PAGES)) == 0 )
+ BUG();
+
+ pending_cons = 0;
+ pending_prod = MAX_PENDING_REQS;
+ memset(pending_reqs, 0, sizeof(pending_reqs));
+ for ( i = 0; i < MAX_PENDING_REQS; i++ )
+ pending_ring[i] = i;
+
+ spin_lock_init(&blkio_schedule_list_lock);
+ INIT_LIST_HEAD(&blkio_schedule_list);
+
+ if ( kernel_thread(blkio_schedule, 0, CLONE_FS | CLONE_FILES) < 0 )
+ BUG();
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+ buffer_head_cachep = kmem_cache_create(
+ "buffer_head_cache", sizeof(struct buffer_head),
+ 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+#endif
+
+ blkif_ctrlif_init();
+
+#ifdef CONFIG_XEN_BLKDEV_GRANT
+ memset( pending_grant_handles, BLKBACK_INVALID_HANDLE, MMAP_PAGES );
+ printk(KERN_ALERT "Blkif backend is using grant tables.\n");
+#endif
+
+#ifdef CONFIG_XEN_BLKDEV_TAP_BE
+ printk(KERN_ALERT "NOTE: Blkif backend is running with tap support on!\n");
+#endif
+
+ return 0;
+}
+
+__initcall(blkif_init);
--- /dev/null
+
+#ifndef __BLKIF__BACKEND__COMMON_H__
+#define __BLKIF__BACKEND__COMMON_H__
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/rbtree.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <asm/io.h>
+#include <asm/setup.h>
+#include <asm/pgalloc.h>
+#include <asm-xen/ctrl_if.h>
+#include <asm-xen/hypervisor.h>
+#include <asm-xen/xen-public/io/blkif.h>
+#include <asm-xen/xen-public/io/ring.h>
+
+#if 0
+#define ASSERT(_p) \
+ if ( !(_p) ) { printk("Assertion '%s' failed, line %d, file %s", #_p , \
+ __LINE__, __FILE__); *(int*)0=0; }
+#define DPRINTK(_f, _a...) printk(KERN_ALERT "(file=%s, line=%d) " _f, \
+ __FILE__ , __LINE__ , ## _a )
+#else
+#define ASSERT(_p) ((void)0)
+#define DPRINTK(_f, _a...) ((void)0)
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+typedef struct rb_root rb_root_t;
+typedef struct rb_node rb_node_t;
+#else
+struct block_device;
+#endif
+
+typedef struct blkif_st {
+ /* Unique identifier for this interface. */
+ domid_t domid;
+ unsigned int handle;
+ /* Physical parameters of the comms window. */
+ unsigned long shmem_frame;
+ unsigned int evtchn;
+ int irq;
+ /* Comms information. */
+ blkif_back_ring_t blk_ring;
+ /* VBDs attached to this interface. */
+ rb_root_t vbd_rb; /* Mapping from 16-bit vdevices to VBDs.*/
+ spinlock_t vbd_lock; /* Protects VBD mapping. */
+ /* Private fields. */
+ enum { DISCONNECTED, DISCONNECTING, CONNECTED } status;
+ /*
+ * DISCONNECT response is deferred until pending requests are ack'ed.
+ * We therefore need to store the id from the original request.
+ */
+ u8 disconnect_rspid;
+#ifdef CONFIG_XEN_BLKDEV_TAP_BE
+ /* Is this a blktap frontend */
+ unsigned int is_blktap;
+#endif
+ struct blkif_st *hash_next;
+ struct list_head blkdev_list;
+ spinlock_t blk_ring_lock;
+ atomic_t refcnt;
+
+ struct work_struct work;
+} blkif_t;
+
+void blkif_create(blkif_be_create_t *create);
+void blkif_destroy(blkif_be_destroy_t *destroy);
+void blkif_connect(blkif_be_connect_t *connect);
+int blkif_disconnect(blkif_be_disconnect_t *disconnect, u8 rsp_id);
+void blkif_disconnect_complete(blkif_t *blkif);
+blkif_t *blkif_find_by_handle(domid_t domid, unsigned int handle);
+#define blkif_get(_b) (atomic_inc(&(_b)->refcnt))
+#define blkif_put(_b) \
+ do { \
+ if ( atomic_dec_and_test(&(_b)->refcnt) ) \
+ blkif_disconnect_complete(_b); \
+ } while (0)
+
+void vbd_create(blkif_be_vbd_create_t *create);
+void vbd_destroy(blkif_be_vbd_destroy_t *delete);
+int vbd_probe(blkif_t *blkif, vdisk_t *vbd_info, int max_vbds);
+void destroy_all_vbds(blkif_t *blkif);
+
+struct phys_req {
+ unsigned short dev;
+ unsigned short nr_sects;
+ struct block_device *bdev;
+ blkif_sector_t sector_number;
+};
+
+int vbd_translate(struct phys_req *req, blkif_t *blkif, int operation);
+
+void blkif_interface_init(void);
+void blkif_ctrlif_init(void);
+
+void blkif_deschedule(blkif_t *blkif);
+
+irqreturn_t blkif_be_int(int irq, void *dev_id, struct pt_regs *regs);
+
+#endif /* __BLKIF__BACKEND__COMMON_H__ */
--- /dev/null
+/******************************************************************************
+ * arch/xen/drivers/blkif/backend/interface.c
+ *
+ * Block-device interface management.
+ *
+ * Copyright (c) 2004, Keir Fraser
+ */
+
+#include "common.h"
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+#endif
+
+#define BLKIF_HASHSZ 1024
+#define BLKIF_HASH(_d,_h) (((int)(_d)^(int)(_h))&(BLKIF_HASHSZ-1))
+
+static kmem_cache_t *blkif_cachep;
+static blkif_t *blkif_hash[BLKIF_HASHSZ];
+
+blkif_t *blkif_find_by_handle(domid_t domid, unsigned int handle)
+{
+ blkif_t *blkif = blkif_hash[BLKIF_HASH(domid, handle)];
+ while ( (blkif != NULL) &&
+ ((blkif->domid != domid) || (blkif->handle != handle)) )
+ blkif = blkif->hash_next;
+ return blkif;
+}
+
+static void __blkif_disconnect_complete(void *arg)
+{
+ blkif_t *blkif = (blkif_t *)arg;
+ ctrl_msg_t cmsg;
+ blkif_be_disconnect_t disc;
+
+ /*
+ * These can't be done in blkif_disconnect() because at that point there
+ * may be outstanding requests at the disc whose asynchronous responses
+ * must still be notified to the remote driver.
+ */
+ unbind_evtchn_from_irq(blkif->evtchn);
+ vfree(blkif->blk_ring.sring);
+
+ /* Construct the deferred response message. */
+ cmsg.type = CMSG_BLKIF_BE;
+ cmsg.subtype = CMSG_BLKIF_BE_DISCONNECT;
+ cmsg.id = blkif->disconnect_rspid;
+ cmsg.length = sizeof(blkif_be_disconnect_t);
+ disc.domid = blkif->domid;
+ disc.blkif_handle = blkif->handle;
+ disc.status = BLKIF_BE_STATUS_OKAY;
+ memcpy(cmsg.msg, &disc, sizeof(disc));
+
+ /*
+ * Make sure message is constructed /before/ status change, because
+ * after the status change the 'blkif' structure could be deallocated at
+ * any time. Also make sure we send the response /after/ status change,
+ * as otherwise a subsequent CONNECT request could spuriously fail if
+ * another CPU doesn't see the status change yet.
+ */
+ mb();
+ if ( blkif->status != DISCONNECTING )
+ BUG();
+ blkif->status = DISCONNECTED;
+ mb();
+
+ /* Send the successful response. */
+ ctrl_if_send_response(&cmsg);
+}
+
+void blkif_disconnect_complete(blkif_t *blkif)
+{
+ INIT_WORK(&blkif->work, __blkif_disconnect_complete, (void *)blkif);
+ schedule_work(&blkif->work);
+}
+
+void blkif_create(blkif_be_create_t *create)
+{
+ domid_t domid = create->domid;
+ unsigned int handle = create->blkif_handle;
+ blkif_t **pblkif, *blkif;
+
+ if ( (blkif = kmem_cache_alloc(blkif_cachep, GFP_KERNEL)) == NULL )
+ {
+ DPRINTK("Could not create blkif: out of memory\n");
+ create->status = BLKIF_BE_STATUS_OUT_OF_MEMORY;
+ return;
+ }
+
+ memset(blkif, 0, sizeof(*blkif));
+ blkif->domid = domid;
+ blkif->handle = handle;
+ blkif->status = DISCONNECTED;
+ spin_lock_init(&blkif->vbd_lock);
+ spin_lock_init(&blkif->blk_ring_lock);
+ atomic_set(&blkif->refcnt, 0);
+
+ pblkif = &blkif_hash[BLKIF_HASH(domid, handle)];
+ while ( *pblkif != NULL )
+ {
+ if ( ((*pblkif)->domid == domid) && ((*pblkif)->handle == handle) )
+ {
+ DPRINTK("Could not create blkif: already exists\n");
+ create->status = BLKIF_BE_STATUS_INTERFACE_EXISTS;
+ kmem_cache_free(blkif_cachep, blkif);
+ return;
+ }
+ pblkif = &(*pblkif)->hash_next;
+ }
+
+ blkif->hash_next = *pblkif;
+ *pblkif = blkif;
+
+ DPRINTK("Successfully created blkif\n");
+ create->status = BLKIF_BE_STATUS_OKAY;
+}
+
+void blkif_destroy(blkif_be_destroy_t *destroy)
+{
+ domid_t domid = destroy->domid;
+ unsigned int handle = destroy->blkif_handle;
+ blkif_t **pblkif, *blkif;
+
+ pblkif = &blkif_hash[BLKIF_HASH(domid, handle)];
+ while ( (blkif = *pblkif) != NULL )
+ {
+ if ( (blkif->domid == domid) && (blkif->handle == handle) )
+ {
+ if ( blkif->status != DISCONNECTED )
+ goto still_connected;
+ goto destroy;
+ }
+ pblkif = &blkif->hash_next;
+ }
+
+ destroy->status = BLKIF_BE_STATUS_INTERFACE_NOT_FOUND;
+ return;
+
+ still_connected:
+ destroy->status = BLKIF_BE_STATUS_INTERFACE_CONNECTED;
+ return;
+
+ destroy:
+ *pblkif = blkif->hash_next;
+ destroy_all_vbds(blkif);
+ kmem_cache_free(blkif_cachep, blkif);
+ destroy->status = BLKIF_BE_STATUS_OKAY;
+}
+
+void blkif_connect(blkif_be_connect_t *connect)
+{
+ domid_t domid = connect->domid;
+ unsigned int handle = connect->blkif_handle;
+ unsigned int evtchn = connect->evtchn;
+ unsigned long shmem_frame = connect->shmem_frame;
+ struct vm_struct *vma;
+ pgprot_t prot;
+ int error;
+ blkif_t *blkif;
+ blkif_sring_t *sring;
+
+ blkif = blkif_find_by_handle(domid, handle);
+ if ( unlikely(blkif == NULL) )
+ {
+ DPRINTK("blkif_connect attempted for non-existent blkif (%u,%u)\n",
+ connect->domid, connect->blkif_handle);
+ connect->status = BLKIF_BE_STATUS_INTERFACE_NOT_FOUND;
+ return;
+ }
+
+ if ( (vma = get_vm_area(PAGE_SIZE, VM_IOREMAP)) == NULL )
+ {
+ connect->status = BLKIF_BE_STATUS_OUT_OF_MEMORY;
+ return;
+ }
+
+ prot = __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED);
+ error = direct_remap_area_pages(&init_mm, VMALLOC_VMADDR(vma->addr),
+ shmem_frame<<PAGE_SHIFT, PAGE_SIZE,
+ prot, domid);
+ if ( error != 0 )
+ {
+ if ( error == -ENOMEM )
+ connect->status = BLKIF_BE_STATUS_OUT_OF_MEMORY;
+ else if ( error == -EFAULT )
+ connect->status = BLKIF_BE_STATUS_MAPPING_ERROR;
+ else
+ connect->status = BLKIF_BE_STATUS_ERROR;
+ vfree(vma->addr);
+ return;
+ }
+
+ if ( blkif->status != DISCONNECTED )
+ {
+ connect->status = BLKIF_BE_STATUS_INTERFACE_CONNECTED;
+ vfree(vma->addr);
+ return;
+ }
+ sring = (blkif_sring_t *)vma->addr;
+ SHARED_RING_INIT(sring);
+ BACK_RING_INIT(&blkif->blk_ring, sring, PAGE_SIZE);
+
+ blkif->evtchn = evtchn;
+ blkif->irq = bind_evtchn_to_irq(evtchn);
+ blkif->shmem_frame = shmem_frame;
+ blkif->status = CONNECTED;
+ blkif_get(blkif);
+
+ request_irq(blkif->irq, blkif_be_int, 0, "blkif-backend", blkif);
+
+ connect->status = BLKIF_BE_STATUS_OKAY;
+}
+
+int blkif_disconnect(blkif_be_disconnect_t *disconnect, u8 rsp_id)
+{
+ domid_t domid = disconnect->domid;
+ unsigned int handle = disconnect->blkif_handle;
+ blkif_t *blkif;
+
+ blkif = blkif_find_by_handle(domid, handle);
+ if ( unlikely(blkif == NULL) )
+ {
+ DPRINTK("blkif_disconnect attempted for non-existent blkif"
+ " (%u,%u)\n", disconnect->domid, disconnect->blkif_handle);
+ disconnect->status = BLKIF_BE_STATUS_INTERFACE_NOT_FOUND;
+ return 1; /* Caller will send response error message. */
+ }
+
+ if ( blkif->status == CONNECTED )
+ {
+ blkif->status = DISCONNECTING;
+ blkif->disconnect_rspid = rsp_id;
+ wmb(); /* Let other CPUs see the status change. */
+ free_irq(blkif->irq, blkif);
+ blkif_deschedule(blkif);
+ blkif_put(blkif);
+ return 0; /* Caller should not send response message. */
+ }
+
+ disconnect->status = BLKIF_BE_STATUS_OKAY;
+ return 1;
+}
+
+void __init blkif_interface_init(void)
+{
+ blkif_cachep = kmem_cache_create("blkif_cache", sizeof(blkif_t),
+ 0, 0, NULL, NULL);
+ memset(blkif_hash, 0, sizeof(blkif_hash));
+}
--- /dev/null
+/******************************************************************************
+ * blkback/vbd.c
+ *
+ * Routines for managing virtual block devices (VBDs).
+ *
+ * NOTE: vbd_lock protects updates to the rb_tree against concurrent lookups
+ * in vbd_translate. All other lookups are implicitly protected because the
+ * only caller (the control message dispatch routine) serializes the calls.
+ *
+ * Copyright (c) 2003-2005, Keir Fraser & Steve Hand
+ */
+
+#include "common.h"
+
+struct vbd {
+ blkif_vdev_t vdevice; /* what the domain refers to this vbd as */
+ unsigned char readonly; /* Non-zero -> read-only */
+ unsigned char type; /* VDISK_TYPE_xxx */
+ blkif_pdev_t pdevice; /* phys device that this vbd maps to */
+ struct block_device *bdev;
+ rb_node_t rb; /* for linking into R-B tree lookup struct */
+};
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+static inline dev_t vbd_map_devnum(blkif_pdev_t cookie)
+{ return MKDEV(cookie>>8, cookie&0xff); }
+#define vbd_sz(_v) ((_v)->bdev->bd_part ? \
+ (_v)->bdev->bd_part->nr_sects : (_v)->bdev->bd_disk->capacity)
+#define bdev_put(_b) blkdev_put(_b)
+#else
+#define vbd_sz(_v) (blk_size[MAJOR((_v)->pdevice)][MINOR((_v)->pdevice)]*2)
+#define bdev_put(_b) ((void)0)
+#endif
+
+void vbd_create(blkif_be_vbd_create_t *create)
+{
+ struct vbd *vbd;
+ rb_node_t **rb_p, *rb_parent = NULL;
+ blkif_t *blkif;
+ blkif_vdev_t vdevice = create->vdevice;
+
+ blkif = blkif_find_by_handle(create->domid, create->blkif_handle);
+ if ( unlikely(blkif == NULL) )
+ {
+ DPRINTK("vbd_create attempted for non-existent blkif (%u,%u)\n",
+ create->domid, create->blkif_handle);
+ create->status = BLKIF_BE_STATUS_INTERFACE_NOT_FOUND;
+ return;
+ }
+
+ rb_p = &blkif->vbd_rb.rb_node;
+ while ( *rb_p != NULL )
+ {
+ rb_parent = *rb_p;
+ vbd = rb_entry(rb_parent, struct vbd, rb);
+ if ( vdevice < vbd->vdevice )
+ {
+ rb_p = &rb_parent->rb_left;
+ }
+ else if ( vdevice > vbd->vdevice )
+ {
+ rb_p = &rb_parent->rb_right;
+ }
+ else
+ {
+ DPRINTK("vbd_create attempted for already existing vbd\n");
+ create->status = BLKIF_BE_STATUS_VBD_EXISTS;
+ return;
+ }
+ }
+
+ if ( unlikely((vbd = kmalloc(sizeof(struct vbd), GFP_KERNEL)) == NULL) )
+ {
+ DPRINTK("vbd_create: out of memory\n");
+ create->status = BLKIF_BE_STATUS_OUT_OF_MEMORY;
+ return;
+ }
+
+ vbd->vdevice = vdevice;
+ vbd->readonly = create->readonly;
+ vbd->type = VDISK_TYPE_DISK | VDISK_FLAG_VIRT;
+
+ /* Mask to 16-bit for compatibility with old tools */
+ vbd->pdevice = create->pdevice & 0xffff;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+ vbd->bdev = open_by_devnum(
+ vbd_map_devnum(vbd->pdevice),
+ vbd->readonly ? FMODE_READ : FMODE_WRITE);
+ if ( IS_ERR(vbd->bdev) )
+ {
+ DPRINTK("vbd_creat: device %08x doesn't exist.\n", vbd->pdevice);
+ create->status = BLKIF_BE_STATUS_PHYSDEV_NOT_FOUND;
+ return;
+ }
+
+ if ( (vbd->bdev->bd_disk == NULL) )
+ {
+ DPRINTK("vbd_creat: device %08x doesn't exist.\n", vbd->pdevice);
+ create->status = BLKIF_BE_STATUS_PHYSDEV_NOT_FOUND;
+ bdev_put(vbd->bdev);
+ return;
+ }
+#else
+ if ( (blk_size[MAJOR(vbd->pdevice)] == NULL) || (vbd_sz(vbd) == 0) )
+ {
+ DPRINTK("vbd_creat: device %08x doesn't exist.\n", vbd->pdevice);
+ create->status = BLKIF_BE_STATUS_PHYSDEV_NOT_FOUND;
+ return;
+ }
+#endif
+
+ spin_lock(&blkif->vbd_lock);
+ rb_link_node(&vbd->rb, rb_parent, rb_p);
+ rb_insert_color(&vbd->rb, &blkif->vbd_rb);
+ spin_unlock(&blkif->vbd_lock);
+
+ DPRINTK("Successful creation of vdev=%04x (dom=%u)\n",
+ vdevice, create->domid);
+ create->status = BLKIF_BE_STATUS_OKAY;
+}
+
+
+void vbd_destroy(blkif_be_vbd_destroy_t *destroy)
+{
+ blkif_t *blkif;
+ struct vbd *vbd;
+ rb_node_t *rb;
+ blkif_vdev_t vdevice = destroy->vdevice;
+
+ blkif = blkif_find_by_handle(destroy->domid, destroy->blkif_handle);
+ if ( unlikely(blkif == NULL) )
+ {
+ DPRINTK("vbd_destroy attempted for non-existent blkif (%u,%u)\n",
+ destroy->domid, destroy->blkif_handle);
+ destroy->status = BLKIF_BE_STATUS_INTERFACE_NOT_FOUND;
+ return;
+ }
+
+ rb = blkif->vbd_rb.rb_node;
+ while ( rb != NULL )
+ {
+ vbd = rb_entry(rb, struct vbd, rb);
+ if ( vdevice < vbd->vdevice )
+ rb = rb->rb_left;
+ else if ( vdevice > vbd->vdevice )
+ rb = rb->rb_right;
+ else
+ goto found;
+ }
+
+ destroy->status = BLKIF_BE_STATUS_VBD_NOT_FOUND;
+ return;
+
+ found:
+ spin_lock(&blkif->vbd_lock);
+ rb_erase(rb, &blkif->vbd_rb);
+ spin_unlock(&blkif->vbd_lock);
+ bdev_put(vbd->bdev);
+ kfree(vbd);
+}
+
+
+void destroy_all_vbds(blkif_t *blkif)
+{
+ struct vbd *vbd;
+ rb_node_t *rb;
+
+ spin_lock(&blkif->vbd_lock);
+
+ while ( (rb = blkif->vbd_rb.rb_node) != NULL )
+ {
+ vbd = rb_entry(rb, struct vbd, rb);
+ rb_erase(rb, &blkif->vbd_rb);
+ spin_unlock(&blkif->vbd_lock);
+ bdev_put(vbd->bdev);
+ kfree(vbd);
+ spin_lock(&blkif->vbd_lock);
+ }
+
+ spin_unlock(&blkif->vbd_lock);
+}
+
+
+static void vbd_probe_single(
+ blkif_t *blkif, vdisk_t *vbd_info, struct vbd *vbd)
+{
+ vbd_info->device = vbd->vdevice;
+ vbd_info->info = vbd->type | (vbd->readonly ? VDISK_FLAG_RO : 0);
+ vbd_info->capacity = vbd_sz(vbd);
+}
+
+
+int vbd_probe(blkif_t *blkif, vdisk_t *vbd_info, int max_vbds)
+{
+ int rc = 0, nr_vbds = 0;
+ rb_node_t *rb;
+
+ spin_lock(&blkif->vbd_lock);
+
+ if ( (rb = blkif->vbd_rb.rb_node) == NULL )
+ goto out;
+
+ new_subtree:
+ /* STEP 1. Find least node (it'll be left-most). */
+ while ( rb->rb_left != NULL )
+ rb = rb->rb_left;
+
+ for ( ; ; )
+ {
+ /* STEP 2. Dealt with left subtree. Now process current node. */
+ vbd_probe_single(blkif, &vbd_info[nr_vbds],
+ rb_entry(rb, struct vbd, rb));
+ if ( ++nr_vbds == max_vbds )
+ goto out;
+
+ /* STEP 3. Process right subtree, if any. */
+ if ( rb->rb_right != NULL )
+ {
+ rb = rb->rb_right;
+ goto new_subtree;
+ }
+
+ /* STEP 4. Done both subtrees. Head back through ancesstors. */
+ for ( ; ; )
+ {
+ /* We're done when we get back to the root node. */
+ if ( rb->rb_parent == NULL )
+ goto out;
+ /* If we are left of parent, then parent is next to process. */
+ if ( rb->rb_parent->rb_left == rb )
+ break;
+ /* If we are right of parent, then we climb to grandparent. */
+ rb = rb->rb_parent;
+ }
+
+ rb = rb->rb_parent;
+ }
+
+ out:
+ spin_unlock(&blkif->vbd_lock);
+ return (rc == 0) ? nr_vbds : rc;
+}
+
+
+int vbd_translate(struct phys_req *req, blkif_t *blkif, int operation)
+{
+ struct vbd *vbd;
+ rb_node_t *rb;
+ int rc = -EACCES;
+
+ /* Take the vbd_lock because another thread could be updating the tree. */
+ spin_lock(&blkif->vbd_lock);
+
+ rb = blkif->vbd_rb.rb_node;
+ while ( rb != NULL )
+ {
+ vbd = rb_entry(rb, struct vbd, rb);
+ if ( req->dev < vbd->vdevice )
+ rb = rb->rb_left;
+ else if ( req->dev > vbd->vdevice )
+ rb = rb->rb_right;
+ else
+ goto found;
+ }
+
+ DPRINTK("vbd_translate; domain %u attempted to access "
+ "non-existent VBD.\n", blkif->domid);
+ rc = -ENODEV;
+ goto out;
+
+ found:
+
+ if ( (operation == WRITE) && vbd->readonly )
+ goto out;
+
+ if ( unlikely((req->sector_number + req->nr_sects) > vbd_sz(vbd)) )
+ goto out;
+
+ req->dev = vbd->pdevice;
+ req->bdev = vbd->bdev;
+ rc = 0;
+
+ out:
+ spin_unlock(&blkif->vbd_lock);
+ return rc;
+}
--- /dev/null
+
+config XENBLOCK
+ tristate "Block device driver"
+ depends on ARCH_XEN
+ help
+ Block device driver for Xen
--- /dev/null
+
+obj-y := blkfront.o vbd.o
+
--- /dev/null
+/******************************************************************************
+ * blkfront.c
+ *
+ * XenLinux virtual block-device driver.
+ *
+ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
+ * Modifications by Mark A. Williamson are (c) Intel Research Cambridge
+ * Copyright (c) 2004, Christian Limpach
+ * Copyright (c) 2004, Andrew Warfield
+ * Copyright (c) 2005, Christopher Clark
+ *
+ * This file may be distributed separately from the Linux kernel, or
+ * incorporated into other software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (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 THE
+ * AUTHORS OR COPYRIGHT HOLDERS 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.
+ */
+
+#if 1
+#define ASSERT(_p) \
+ if ( !(_p) ) { printk("Assertion '%s' failed, line %d, file %s", #_p , \
+ __LINE__, __FILE__); *(int*)0=0; }
+#else
+#define ASSERT(_p)
+#endif
+
+#include <linux/version.h>
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+#include "block.h"
+#else
+#include "common.h"
+#include <linux/blk.h>
+#include <linux/tqueue.h>
+#endif
+
+#include <linux/cdrom.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <scsi/scsi.h>
+#include <asm-xen/ctrl_if.h>
+#include <asm-xen/evtchn.h>
+#ifdef CONFIG_XEN_BLKDEV_GRANT
+#include <asm-xen/xen-public/grant_table.h>
+#include <asm-xen/gnttab.h>
+#endif
+
+typedef unsigned char byte; /* from linux/ide.h */
+
+/* Control whether runtime update of vbds is enabled. */
+#define ENABLE_VBD_UPDATE 1
+
+#if ENABLE_VBD_UPDATE
+static void vbd_update(void);
+#else
+static void vbd_update(void){};
+#endif
+
+#define BLKIF_STATE_CLOSED 0
+#define BLKIF_STATE_DISCONNECTED 1
+#define BLKIF_STATE_CONNECTED 2
+
+#define WPRINTK(fmt, args...) printk(KERN_WARNING "xen_blk: " fmt, ##args)
+
+static int blkif_handle = 0;
+static unsigned int blkif_state = BLKIF_STATE_CLOSED;
+static unsigned int blkif_evtchn = 0;
+static unsigned int blkif_irq = 0;
+
+static int blkif_control_rsp_valid;
+static blkif_response_t blkif_control_rsp;
+
+static blkif_front_ring_t blk_ring;
+
+#define BLK_RING_SIZE __RING_SIZE((blkif_sring_t *)0, PAGE_SIZE)
+
+#ifdef CONFIG_XEN_BLKDEV_GRANT
+static domid_t rdomid = 0;
+static grant_ref_t gref_head, gref_terminal;
+#define MAXIMUM_OUTSTANDING_BLOCK_REQS \
+ (BLKIF_MAX_SEGMENTS_PER_REQUEST * BLKIF_RING_SIZE)
+#define GRANTREF_INVALID (1<<15)
+#endif
+
+static struct blk_shadow {
+ blkif_request_t req;
+ unsigned long request;
+ unsigned long frame[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+} blk_shadow[BLK_RING_SIZE];
+unsigned long blk_shadow_free;
+
+static int recovery = 0; /* Recovery in progress: protected by blkif_io_lock */
+
+static void kick_pending_request_queues(void);
+
+int __init xlblk_init(void);
+
+static void blkif_completion(struct blk_shadow *s);
+
+static inline int GET_ID_FROM_FREELIST(void)
+{
+ unsigned long free = blk_shadow_free;
+ BUG_ON(free > BLK_RING_SIZE);
+ blk_shadow_free = blk_shadow[free].req.id;
+ blk_shadow[free].req.id = 0x0fffffee; /* debug */
+ return free;
+}
+
+static inline void ADD_ID_TO_FREELIST(unsigned long id)
+{
+ blk_shadow[id].req.id = blk_shadow_free;
+ blk_shadow[id].request = 0;
+ blk_shadow_free = id;
+}
+
+
+/************************ COMMON CODE (inlined) ************************/
+
+/* Kernel-specific definitions used in the common code */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+#define DISABLE_SCATTERGATHER()
+#else
+static int sg_operation = -1;
+#define DISABLE_SCATTERGATHER() (sg_operation = -1)
+#endif
+
+static inline void pickle_request(struct blk_shadow *s, blkif_request_t *r)
+{
+#ifndef CONFIG_XEN_BLKDEV_GRANT
+ int i;
+#endif
+
+ s->req = *r;
+
+#ifndef CONFIG_XEN_BLKDEV_GRANT
+ for ( i = 0; i < r->nr_segments; i++ )
+ s->req.frame_and_sects[i] = machine_to_phys(r->frame_and_sects[i]);
+#endif
+}
+
+static inline void unpickle_request(blkif_request_t *r, struct blk_shadow *s)
+{
+#ifndef CONFIG_XEN_BLKDEV_GRANT
+ int i;
+#endif
+
+ *r = s->req;
+
+#ifndef CONFIG_XEN_BLKDEV_GRANT
+ for ( i = 0; i < s->req.nr_segments; i++ )
+ r->frame_and_sects[i] = phys_to_machine(s->req.frame_and_sects[i]);
+#endif
+}
+
+
+static inline void flush_requests(void)
+{
+ DISABLE_SCATTERGATHER();
+ RING_PUSH_REQUESTS(&blk_ring);
+ notify_via_evtchn(blkif_evtchn);
+}
+
+
+/************************** KERNEL VERSION 2.6 **************************/
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+
+module_init(xlblk_init);
+
+#if ENABLE_VBD_UPDATE
+static void update_vbds_task(void *unused)
+{
+ xlvbd_update_vbds();
+}
+
+static void vbd_update(void)
+{
+ static DECLARE_WORK(update_tq, update_vbds_task, NULL);
+ schedule_work(&update_tq);
+}
+#endif /* ENABLE_VBD_UPDATE */
+
+static void kick_pending_request_queues(void)
+{
+ if ( (xlbd_blk_queue != NULL) &&
+ test_bit(QUEUE_FLAG_STOPPED, &xlbd_blk_queue->queue_flags) )
+ {
+ blk_start_queue(xlbd_blk_queue);
+ /* XXXcl call to request_fn should not be needed but
+ * we get stuck without... needs investigating
+ */
+ xlbd_blk_queue->request_fn(xlbd_blk_queue);
+ }
+}
+
+
+int blkif_open(struct inode *inode, struct file *filep)
+{
+ struct gendisk *gd = inode->i_bdev->bd_disk;
+ struct xlbd_disk_info *di = (struct xlbd_disk_info *)gd->private_data;
+
+ /* Update of usage count is protected by per-device semaphore. */
+ di->mi->usage++;
+
+ return 0;
+}
+
+
+int blkif_release(struct inode *inode, struct file *filep)
+{
+ struct gendisk *gd = inode->i_bdev->bd_disk;
+ struct xlbd_disk_info *di = (struct xlbd_disk_info *)gd->private_data;
+
+ /*
+ * When usage drops to zero it may allow more VBD updates to occur.
+ * Update of usage count is protected by a per-device semaphore.
+ */
+ if ( --di->mi->usage == 0 )
+ vbd_update();
+
+ return 0;
+}
+
+
+int blkif_ioctl(struct inode *inode, struct file *filep,
+ unsigned command, unsigned long argument)
+{
+ int i;
+
+ DPRINTK_IOCTL("command: 0x%x, argument: 0x%lx, dev: 0x%04x\n",
+ command, (long)argument, inode->i_rdev);
+
+ switch ( command )
+ {
+ case HDIO_GETGEO:
+ /* return ENOSYS to use defaults */
+ return -ENOSYS;
+
+ case CDROMMULTISESSION:
+ DPRINTK("FIXME: support multisession CDs later\n");
+ for ( i = 0; i < sizeof(struct cdrom_multisession); i++ )
+ if ( put_user(0, (byte *)(argument + i)) ) return -EFAULT;
+ return 0;
+
+ default:
+ printk(KERN_ALERT "ioctl %08x not supported by Xen blkdev\n",
+ command);
+ return -ENOSYS;
+ }
+
+ return 0;
+}
+
+
+/*
+ * blkif_queue_request
+ *
+ * request block io
+ *
+ * id: for guest use only.
+ * operation: BLKIF_OP_{READ,WRITE,PROBE}
+ * buffer: buffer to read/write into. this should be a
+ * virtual address in the guest os.
+ */
+static int blkif_queue_request(struct request *req)
+{
+ struct xlbd_disk_info *di =
+ (struct xlbd_disk_info *)req->rq_disk->private_data;
+ unsigned long buffer_ma;
+ blkif_request_t *ring_req;
+ struct bio *bio;
+ struct bio_vec *bvec;
+ int idx;
+ unsigned long id;
+ unsigned int fsect, lsect;
+#ifdef CONFIG_XEN_BLKDEV_GRANT
+ int ref;
+#endif
+
+ if ( unlikely(blkif_state != BLKIF_STATE_CONNECTED) )
+ return 1;
+
+ /* Fill out a communications ring structure. */
+ ring_req = RING_GET_REQUEST(&blk_ring, blk_ring.req_prod_pvt);
+ id = GET_ID_FROM_FREELIST();
+ blk_shadow[id].request = (unsigned long)req;
+
+ ring_req->id = id;
+ ring_req->operation = rq_data_dir(req) ? BLKIF_OP_WRITE :
+ BLKIF_OP_READ;
+ ring_req->sector_number = (blkif_sector_t)req->sector;
+ ring_req->device = di->xd_device;
+
+ ring_req->nr_segments = 0;
+ rq_for_each_bio(bio, req)
+ {
+ bio_for_each_segment(bvec, bio, idx)
+ {
+ if ( ring_req->nr_segments == BLKIF_MAX_SEGMENTS_PER_REQUEST )
+ BUG();
+ buffer_ma = page_to_phys(bvec->bv_page);
+ fsect = bvec->bv_offset >> 9;
+ lsect = fsect + (bvec->bv_len >> 9) - 1;
+#ifdef CONFIG_XEN_BLKDEV_GRANT
+ /* install a grant reference. */
+ ref = gnttab_claim_grant_reference(&gref_head, gref_terminal);
+ ASSERT( ref != -ENOSPC );
+
+ gnttab_grant_foreign_access_ref(
+ ref,
+ rdomid,
+ buffer_ma >> PAGE_SHIFT,
+ rq_data_dir(req) );
+
+ blk_shadow[id].frame[ring_req->nr_segments] =
+ buffer_ma >> PAGE_SHIFT;
+
+ ring_req->frame_and_sects[ring_req->nr_segments++] =
+ (((u32) ref) << 16) | (fsect << 3) | lsect;
+
+#else
+ ring_req->frame_and_sects[ring_req->nr_segments++] =
+ buffer_ma | (fsect << 3) | lsect;
+#endif
+ }
+ }
+
+ blk_ring.req_prod_pvt++;
+
+ /* Keep a private copy so we can reissue requests when recovering. */
+ pickle_request(&blk_shadow[id], ring_req);
+
+ return 0;
+}
+
+
+/*
+ * do_blkif_request
+ * read a block; request is in a request queue
+ */
+void do_blkif_request(request_queue_t *rq)
+{
+ struct request *req;
+ int queued;
+
+ DPRINTK("Entered do_blkif_request\n");
+
+ queued = 0;
+
+ while ( (req = elv_next_request(rq)) != NULL )
+ {
+ if ( !blk_fs_request(req) )
+ {
+ end_request(req, 0);
+ continue;
+ }
+
+ if ( RING_FULL(&blk_ring) )
+ {
+ blk_stop_queue(rq);
+ break;
+ }
+
+ DPRINTK("do_blk_req %p: cmd %p, sec %lx, (%u/%li) buffer:%p [%s]\n",
+ req, req->cmd, req->sector, req->current_nr_sectors,
+ req->nr_sectors, req->buffer,
+ rq_data_dir(req) ? "write" : "read");
+
+ blkdev_dequeue_request(req);
+ if ( blkif_queue_request(req) )
+ {
+ blk_stop_queue(rq);
+ break;
+ }
+
+ queued++;
+ }
+
+ if ( queued != 0 )
+ flush_requests();
+}
+
+
+static irqreturn_t blkif_int(int irq, void *dev_id, struct pt_regs *ptregs)
+{
+ struct request *req;
+ blkif_response_t *bret;
+ RING_IDX i, rp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&blkif_io_lock, flags);
+
+ if ( unlikely(blkif_state == BLKIF_STATE_CLOSED) ||
+ unlikely(recovery) )
+ {
+ spin_unlock_irqrestore(&blkif_io_lock, flags);
+ return IRQ_HANDLED;
+ }
+
+ rp = blk_ring.sring->rsp_prod;
+ rmb(); /* Ensure we see queued responses up to 'rp'. */
+
+ for ( i = blk_ring.rsp_cons; i != rp; i++ )
+ {
+ unsigned long id;
+
+ bret = RING_GET_RESPONSE(&blk_ring, i);
+ id = bret->id;
+ req = (struct request *)blk_shadow[id].request;
+
+ blkif_completion(&blk_shadow[id]);
+
+ ADD_ID_TO_FREELIST(id);
+
+ switch ( bret->operation )
+ {
+ case BLKIF_OP_READ:
+ case BLKIF_OP_WRITE:
+ if ( unlikely(bret->status != BLKIF_RSP_OKAY) )
+ DPRINTK("Bad return from blkdev data request: %x\n",
+ bret->status);
+
+ if ( unlikely(end_that_request_first
+ (req,
+ (bret->status == BLKIF_RSP_OKAY),
+ req->hard_nr_sectors)) )
+ BUG();
+ end_that_request_last(req);
+
+ break;
+ case BLKIF_OP_PROBE:
+ memcpy(&blkif_control_rsp, bret, sizeof(*bret));
+ blkif_control_rsp_valid = 1;
+ break;
+ default:
+ BUG();
+ }
+ }
+
+ blk_ring.rsp_cons = i;
+
+ kick_pending_request_queues();
+
+ spin_unlock_irqrestore(&blkif_io_lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+#else
+/************************** KERNEL VERSION 2.4 **************************/
+
+static kdev_t sg_dev;
+static unsigned long sg_next_sect;
+
+/*
+ * Request queues with outstanding work, but ring is currently full.
+ * We need no special lock here, as we always access this with the
+ * blkif_io_lock held. We only need a small maximum list.
+ */
+#define MAX_PENDING 8
+static request_queue_t *pending_queues[MAX_PENDING];
+static int nr_pending;
+
+
+#define blkif_io_lock io_request_lock
+
+/*============================================================================*/
+#if ENABLE_VBD_UPDATE
+
+/*
+ * blkif_update_int/update-vbds_task - handle VBD update events.
+ * Schedule a task for keventd to run, which will update the VBDs and perform
+ * the corresponding updates to our view of VBD state.
+ */
+static void update_vbds_task(void *unused)
+{
+ xlvbd_update_vbds();
+}
+
+static void vbd_update(void)
+{
+ static struct tq_struct update_tq;
+ update_tq.routine = update_vbds_task;
+ schedule_task(&update_tq);
+}
+
+#endif /* ENABLE_VBD_UPDATE */
+/*============================================================================*/
+
+static void kick_pending_request_queues(void)
+{
+ /* We kick pending request queues if the ring is reasonably empty. */
+ if ( (nr_pending != 0) &&
+ (RING_PENDING_REQUESTS(&blk_ring) < (BLK_RING_SIZE >> 1)) )
+ {
+ /* Attempt to drain the queue, but bail if the ring becomes full. */
+ while ( (nr_pending != 0) && !RING_FULL(&blk_ring) )
+ do_blkif_request(pending_queues[--nr_pending]);
+ }
+}
+
+int blkif_open(struct inode *inode, struct file *filep)
+{
+ short xldev = inode->i_rdev;
+ struct gendisk *gd = get_gendisk(xldev);
+ xl_disk_t *disk = xldev_to_xldisk(inode->i_rdev);
+ short minor = MINOR(xldev);
+
+ if ( gd->part[minor].nr_sects == 0 )
+ {
+ /*
+ * Device either doesn't exist, or has zero capacity; we use a few
+ * cheesy heuristics to return the relevant error code
+ */
+ if ( (gd->sizes[minor >> gd->minor_shift] != 0) ||
+ ((minor & (gd->max_p - 1)) != 0) )
+ {
+ /*
+ * We have a real device, but no such partition, or we just have a
+ * partition number so guess this is the problem.
+ */
+ return -ENXIO; /* no such device or address */
+ }
+ else if ( gd->flags[minor >> gd->minor_shift] & GENHD_FL_REMOVABLE )
+ {
+ /* This is a removable device => assume that media is missing. */
+ return -ENOMEDIUM; /* media not present (this is a guess) */
+ }
+ else
+ {
+ /* Just go for the general 'no such device' error. */
+ return -ENODEV; /* no such device */
+ }
+ }
+
+ /* Update of usage count is protected by per-device semaphore. */
+ disk->usage++;
+
+ return 0;
+}
+
+
+int blkif_release(struct inode *inode, struct file *filep)
+{
+ xl_disk_t *disk = xldev_to_xldisk(inode->i_rdev);
+
+ /*
+ * When usage drops to zero it may allow more VBD updates to occur.
+ * Update of usage count is protected by a per-device semaphore.
+ */
+ if ( --disk->usage == 0 ) {
+ vbd_update();
+ }
+
+ return 0;
+}
+
+
+int blkif_ioctl(struct inode *inode, struct file *filep,
+ unsigned command, unsigned long argument)
+{
+ kdev_t dev = inode->i_rdev;
+ struct hd_geometry *geo = (struct hd_geometry *)argument;
+ struct gendisk *gd;
+ struct hd_struct *part;
+ int i;
+ unsigned short cylinders;
+ byte heads, sectors;
+
+ /* NB. No need to check permissions. That is done for us. */
+
+ DPRINTK_IOCTL("command: 0x%x, argument: 0x%lx, dev: 0x%04x\n",
+ command, (long) argument, dev);
+
+ gd = get_gendisk(dev);
+ part = &gd->part[MINOR(dev)];
+
+ switch ( command )
+ {
+ case BLKGETSIZE:
+ DPRINTK_IOCTL(" BLKGETSIZE: %x %lx\n", BLKGETSIZE, part->nr_sects);
+ return put_user(part->nr_sects, (unsigned long *) argument);
+
+ case BLKGETSIZE64:
+ DPRINTK_IOCTL(" BLKGETSIZE64: %x %llx\n", BLKGETSIZE64,
+ (u64)part->nr_sects * 512);
+ return put_user((u64)part->nr_sects * 512, (u64 *) argument);
+
+ case BLKRRPART: /* re-read partition table */
+ DPRINTK_IOCTL(" BLKRRPART: %x\n", BLKRRPART);
+ return blkif_revalidate(dev);
+
+ case BLKSSZGET:
+ return hardsect_size[MAJOR(dev)][MINOR(dev)];
+
+ case BLKBSZGET: /* get block size */
+ DPRINTK_IOCTL(" BLKBSZGET: %x\n", BLKBSZGET);
+ break;
+
+ case BLKBSZSET: /* set block size */
+ DPRINTK_IOCTL(" BLKBSZSET: %x\n", BLKBSZSET);
+ break;
+
+ case BLKRASET: /* set read-ahead */
+ DPRINTK_IOCTL(" BLKRASET: %x\n", BLKRASET);
+ break;
+
+ case BLKRAGET: /* get read-ahead */
+ DPRINTK_IOCTL(" BLKRAFET: %x\n", BLKRAGET);
+ break;
+
+ case HDIO_GETGEO:
+ DPRINTK_IOCTL(" HDIO_GETGEO: %x\n", HDIO_GETGEO);
+ if (!argument) return -EINVAL;
+
+ /* We don't have real geometry info, but let's at least return
+ values consistent with the size of the device */
+
+ heads = 0xff;
+ sectors = 0x3f;
+ cylinders = part->nr_sects / (heads * sectors);
+
+ if (put_user(0x00, (unsigned long *) &geo->start)) return -EFAULT;
+ if (put_user(heads, (byte *)&geo->heads)) return -EFAULT;
+ if (put_user(sectors, (byte *)&geo->sectors)) return -EFAULT;
+ if (put_user(cylinders, (unsigned short *)&geo->cylinders)) return -EFAULT;
+
+ return 0;
+
+ case HDIO_GETGEO_BIG:
+ DPRINTK_IOCTL(" HDIO_GETGEO_BIG: %x\n", HDIO_GETGEO_BIG);
+ if (!argument) return -EINVAL;
+
+ /* We don't have real geometry info, but let's at least return
+ values consistent with the size of the device */
+
+ heads = 0xff;
+ sectors = 0x3f;
+ cylinders = part->nr_sects / (heads * sectors);
+
+ if (put_user(0x00, (unsigned long *) &geo->start)) return -EFAULT;
+ if (put_user(heads, (byte *)&geo->heads)) return -EFAULT;
+ if (put_user(sectors, (byte *)&geo->sectors)) return -EFAULT;
+ if (put_user(cylinders, (unsigned int *) &geo->cylinders)) return -EFAULT;
+
+ return 0;
+
+ case CDROMMULTISESSION:
+ DPRINTK("FIXME: support multisession CDs later\n");
+ for ( i = 0; i < sizeof(struct cdrom_multisession); i++ )
+ if ( put_user(0, (byte *)(argument + i)) ) return -EFAULT;
+ return 0;
+
+ case SCSI_IOCTL_GET_BUS_NUMBER:
+ DPRINTK("FIXME: SCSI_IOCTL_GET_BUS_NUMBER ioctl in XL blkif");
+ return -ENOSYS;
+
+ default:
+ printk(KERN_ALERT "ioctl %08x not supported by XL blkif\n", command);
+ return -ENOSYS;
+ }
+
+ return 0;
+}
+
+
+
+/* check media change: should probably do something here in some cases :-) */
+int blkif_check(kdev_t dev)
+{
+ DPRINTK("blkif_check\n");
+ return 0;
+}
+
+int blkif_revalidate(kdev_t dev)
+{
+ struct block_device *bd;
+ struct gendisk *gd;
+ xl_disk_t *disk;
+ unsigned long capacity;
+ int i, rc = 0;
+
+ if ( (bd = bdget(dev)) == NULL )
+ return -EINVAL;
+
+ /*
+ * Update of partition info, and check of usage count, is protected
+ * by the per-block-device semaphore.
+ */
+ down(&bd->bd_sem);
+
+ if ( ((gd = get_gendisk(dev)) == NULL) ||
+ ((disk = xldev_to_xldisk(dev)) == NULL) ||
+ ((capacity = gd->part[MINOR(dev)].nr_sects) == 0) )
+ {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ if ( disk->usage > 1 )
+ {
+ rc = -EBUSY;
+ goto out;
+ }
+
+ /* Only reread partition table if VBDs aren't mapped to partitions. */
+ if ( !(gd->flags[MINOR(dev) >> gd->minor_shift] & GENHD_FL_VIRT_PARTNS) )
+ {
+ for ( i = gd->max_p - 1; i >= 0; i-- )
+ {
+ invalidate_device(dev+i, 1);
+ gd->part[MINOR(dev+i)].start_sect = 0;
+ gd->part[MINOR(dev+i)].nr_sects = 0;
+ gd->sizes[MINOR(dev+i)] = 0;
+ }
+
+ grok_partitions(gd, MINOR(dev)>>gd->minor_shift, gd->max_p, capacity);
+ }
+
+ out:
+ up(&bd->bd_sem);
+ bdput(bd);
+ return rc;
+}
+
+
+/*
+ * blkif_queue_request
+ *
+ * request block io
+ *
+ * id: for guest use only.
+ * operation: BLKIF_OP_{READ,WRITE,PROBE}
+ * buffer: buffer to read/write into. this should be a
+ * virtual address in the guest os.
+ */
+static int blkif_queue_request(unsigned long id,
+ int operation,
+ char * buffer,
+ unsigned long sector_number,
+ unsigned short nr_sectors,
+ kdev_t device)
+{
+ unsigned long buffer_ma = virt_to_bus(buffer);
+ unsigned long xid;
+ struct gendisk *gd;
+ blkif_request_t *req;
+ struct buffer_head *bh;
+ unsigned int fsect, lsect;
+#ifdef CONFIG_XEN_BLKDEV_GRANT
+ int ref;
+#endif
+
+ fsect = (buffer_ma & ~PAGE_MASK) >> 9;
+ lsect = fsect + nr_sectors - 1;
+
+ /* Buffer must be sector-aligned. Extent mustn't cross a page boundary. */
+ if ( unlikely((buffer_ma & ((1<<9)-1)) != 0) )
+ BUG();
+ if ( lsect > 7 )
+ BUG();
+
+ buffer_ma &= PAGE_MASK;
+
+ if ( unlikely(blkif_state != BLKIF_STATE_CONNECTED) )
+ return 1;
+
+ switch ( operation )
+ {
+
+ case BLKIF_OP_READ:
+ case BLKIF_OP_WRITE:
+ gd = get_gendisk(device);
+
+ /*
+ * Update the sector_number we'll pass down as appropriate; note that
+ * we could sanity check that resulting sector will be in this
+ * partition, but this will happen in driver backend anyhow.
+ */
+ sector_number += gd->part[MINOR(device)].start_sect;
+
+ /*
+ * If this unit doesn't consist of virtual partitions then we clear
+ * the partn bits from the device number.
+ */
+ if ( !(gd->flags[MINOR(device)>>gd->minor_shift] &
+ GENHD_FL_VIRT_PARTNS) )
+ device &= ~(gd->max_p - 1);
+
+ if ( (sg_operation == operation) &&
+ (sg_dev == device) &&
+ (sg_next_sect == sector_number) )
+ {
+ req = RING_GET_REQUEST(&blk_ring,
+ blk_ring.req_prod_pvt - 1);
+ bh = (struct buffer_head *)id;
+
+ bh->b_reqnext = (struct buffer_head *)blk_shadow[req->id].request;
+ blk_shadow[req->id].request = (unsigned long)id;
+
+#ifdef CONFIG_XEN_BLKDEV_GRANT
+ /* install a grant reference. */
+ ref = gnttab_claim_grant_reference(&gref_head, gref_terminal);
+ ASSERT( ref != -ENOSPC );
+
+ gnttab_grant_foreign_access_ref(
+ ref,
+ rdomid,
+ buffer_ma >> PAGE_SHIFT,
+ ( operation == BLKIF_OP_WRITE ? 1 : 0 ) );
+
+ blk_shadow[id].frame[req->nr_segments] =
+ buffer_ma >> PAGE_SHIFT;
+
+ req->frame_and_sects[req->nr_segments] =
+ (((u32) ref ) << 16) | (fsect << 3) | lsect;
+#else
+ req->frame_and_sects[req->nr_segments] =
+ buffer_ma | (fsect << 3) | lsect;
+#endif
+ if ( ++req->nr_segments < BLKIF_MAX_SEGMENTS_PER_REQUEST )
+ sg_next_sect += nr_sectors;
+ else
+ DISABLE_SCATTERGATHER();
+
+ /* Update the copy of the request in the recovery ring. */
+ pickle_request(&blk_shadow[req->id], req );
+
+ return 0;
+ }
+ else if ( RING_FULL(&blk_ring) )
+ {
+ return 1;
+ }
+ else
+ {
+ sg_operation = operation;
+ sg_dev = device;
+ sg_next_sect = sector_number + nr_sectors;
+ }
+ break;
+
+ default:
+ panic("unknown op %d\n", operation);
+ }
+
+ /* Fill out a communications ring structure. */
+ req = RING_GET_REQUEST(&blk_ring, blk_ring.req_prod_pvt);
+
+ xid = GET_ID_FROM_FREELIST();
+ blk_shadow[xid].request = (unsigned long)id;
+
+ req->id = xid;
+ req->operation = operation;
+ req->sector_number = (blkif_sector_t)sector_number;
+ req->device = device;
+ req->nr_segments = 1;
+#ifdef CONFIG_XEN_BLKDEV_GRANT
+ /* install a grant reference. */
+ ref = gnttab_claim_grant_reference(&gref_head, gref_terminal);
+ ASSERT( ref != -ENOSPC );
+
+ gnttab_grant_foreign_access_ref(
+ ref,
+ rdomid,
+ buffer_ma >> PAGE_SHIFT,
+ ( operation == BLKIF_OP_WRITE ? 1 : 0 ) );
+
+ blk_shadow[xid].frame[0] = buffer_ma >> PAGE_SHIFT;
+
+ req->frame_and_sects[0] = (((u32) ref)<<16) | (fsect<<3) | lsect;
+#else
+ req->frame_and_sects[0] = buffer_ma | (fsect<<3) | lsect;
+#endif
+
+ /* Keep a private copy so we can reissue requests when recovering. */
+ pickle_request(&blk_shadow[xid], req);
+
+ blk_ring.req_prod_pvt++;
+
+ return 0;
+}
+
+
+/*
+ * do_blkif_request
+ * read a block; request is in a request queue
+ */
+void do_blkif_request(request_queue_t *rq)
+{
+ struct request *req;
+ struct buffer_head *bh, *next_bh;
+ int rw, nsect, full, queued = 0;
+
+ DPRINTK("Entered do_blkif_request\n");
+
+ while ( !rq->plugged && !list_empty(&rq->queue_head))
+ {
+ if ( (req = blkdev_entry_next_request(&rq->queue_head)) == NULL )
+ goto out;
+
+ DPRINTK("do_blkif_request %p: cmd %i, sec %lx, (%li/%li) bh:%p\n",
+ req, req->cmd, req->sector,
+ req->current_nr_sectors, req->nr_sectors, req->bh);
+
+ rw = req->cmd;
+ if ( rw == READA )
+ rw = READ;
+ if ( unlikely((rw != READ) && (rw != WRITE)) )
+ panic("XenoLinux Virtual Block Device: bad cmd: %d\n", rw);
+
+ req->errors = 0;
+
+ bh = req->bh;
+ while ( bh != NULL )
+ {
+ next_bh = bh->b_reqnext;
+ bh->b_reqnext = NULL;
+
+ full = blkif_queue_request(
+ (unsigned long)bh,
+ (rw == READ) ? BLKIF_OP_READ : BLKIF_OP_WRITE,
+ bh->b_data, bh->b_rsector, bh->b_size>>9, bh->b_rdev);
+
+ if ( full )
+ {
+ bh->b_reqnext = next_bh;
+ pending_queues[nr_pending++] = rq;
+ if ( unlikely(nr_pending >= MAX_PENDING) )
+ BUG();
+ goto out;
+ }
+
+ queued++;
+
+ /* Dequeue the buffer head from the request. */
+ nsect = bh->b_size >> 9;
+ bh = req->bh = next_bh;
+
+ if ( bh != NULL )
+ {
+ /* There's another buffer head to do. Update the request. */
+ req->hard_sector += nsect;
+ req->hard_nr_sectors -= nsect;
+ req->sector = req->hard_sector;
+ req->nr_sectors = req->hard_nr_sectors;
+ req->current_nr_sectors = bh->b_size >> 9;
+ req->buffer = bh->b_data;
+ }
+ else
+ {
+ /* That was the last buffer head. Finalise the request. */
+ if ( unlikely(end_that_request_first(req, 1, "XenBlk")) )
+ BUG();
+ blkdev_dequeue_request(req);
+ end_that_request_last(req);
+ }
+ }
+ }
+
+ out:
+ if ( queued != 0 )
+ flush_requests();
+}
+
+
+static void blkif_int(int irq, void *dev_id, struct pt_regs *ptregs)
+{
+ RING_IDX i, rp;
+ unsigned long flags;
+ struct buffer_head *bh, *next_bh;
+
+ spin_lock_irqsave(&io_request_lock, flags);
+
+ if ( unlikely(blkif_state == BLKIF_STATE_CLOSED || recovery) )
+ {
+ spin_unlock_irqrestore(&io_request_lock, flags);
+ return;
+ }
+
+ rp = blk_ring.sring->rsp_prod;
+ rmb(); /* Ensure we see queued responses up to 'rp'. */
+
+ for ( i = blk_ring.rsp_cons; i != rp; i++ )
+ {
+ unsigned long id;
+ blkif_response_t *bret;
+
+ bret = RING_GET_RESPONSE(&blk_ring, i);
+ id = bret->id;
+ bh = (struct buffer_head *)blk_shadow[id].request;
+
+ blkif_completion(&blk_shadow[id]);
+
+ ADD_ID_TO_FREELIST(id);
+
+ switch ( bret->operation )
+ {
+ case BLKIF_OP_READ:
+ case BLKIF_OP_WRITE:
+ if ( unlikely(bret->status != BLKIF_RSP_OKAY) )
+ DPRINTK("Bad return from blkdev data request: %lx\n",
+ bret->status);
+ for ( ; bh != NULL; bh = next_bh )
+ {
+ next_bh = bh->b_reqnext;
+ bh->b_reqnext = NULL;
+ bh->b_end_io(bh, bret->status == BLKIF_RSP_OKAY);
+ }
+
+ break;
+ case BLKIF_OP_PROBE:
+ memcpy(&blkif_control_rsp, bret, sizeof(*bret));
+ blkif_control_rsp_valid = 1;
+ break;
+ default:
+ BUG();
+ }
+
+ }
+ blk_ring.rsp_cons = i;
+
+ kick_pending_request_queues();
+
+ spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+#endif
+
+/***************************** COMMON CODE *******************************/
+
+#ifdef CONFIG_XEN_BLKDEV_GRANT
+void blkif_control_probe_send(blkif_request_t *req, blkif_response_t *rsp,
+ unsigned long address)
+{
+ int ref = gnttab_claim_grant_reference(&gref_head, gref_terminal);
+ ASSERT( ref != -ENOSPC );
+
+ gnttab_grant_foreign_access_ref( ref, rdomid, address >> PAGE_SHIFT, 0 );
+
+ req->frame_and_sects[0] = (((u32) ref) << 16) | 7;
+
+ blkif_control_send(req, rsp);
+}
+#endif
+
+void blkif_control_send(blkif_request_t *req, blkif_response_t *rsp)
+{
+ unsigned long flags, id;
+ blkif_request_t *req_d;
+
+ retry:
+ while ( RING_FULL(&blk_ring) )
+ {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(1);
+ }
+
+ spin_lock_irqsave(&blkif_io_lock, flags);
+ if ( RING_FULL(&blk_ring) )
+ {
+ spin_unlock_irqrestore(&blkif_io_lock, flags);
+ goto retry;
+ }
+
+ DISABLE_SCATTERGATHER();
+ req_d = RING_GET_REQUEST(&blk_ring, blk_ring.req_prod_pvt);
+ *req_d = *req;
+
+ id = GET_ID_FROM_FREELIST();
+ req_d->id = id;
+ blk_shadow[id].request = (unsigned long)req;
+
+ pickle_request(&blk_shadow[id], req);
+
+ blk_ring.req_prod_pvt++;
+ flush_requests();
+
+ spin_unlock_irqrestore(&blkif_io_lock, flags);
+
+ while ( !blkif_control_rsp_valid )
+ {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(1);
+ }
+
+ memcpy(rsp, &blkif_control_rsp, sizeof(*rsp));
+ blkif_control_rsp_valid = 0;
+}
+
+
+/* Send a driver status notification to the domain controller. */
+static void send_driver_status(int ok)
+{
+ ctrl_msg_t cmsg = {
+ .type = CMSG_BLKIF_FE,
+ .subtype = CMSG_BLKIF_FE_DRIVER_STATUS,
+ .length = sizeof(blkif_fe_driver_status_t),
+ };
+ blkif_fe_driver_status_t *msg = (void*)cmsg.msg;
+
+ msg->status = (ok ? BLKIF_DRIVER_STATUS_UP : BLKIF_DRIVER_STATUS_DOWN);
+
+ ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
+}
+
+/* Tell the controller to bring up the interface. */
+static void blkif_send_interface_connect(void)
+{
+ ctrl_msg_t cmsg = {
+ .type = CMSG_BLKIF_FE,
+ .subtype = CMSG_BLKIF_FE_INTERFACE_CONNECT,
+ .length = sizeof(blkif_fe_interface_connect_t),
+ };
+ blkif_fe_interface_connect_t *msg = (void*)cmsg.msg;
+
+ msg->handle = 0;
+ msg->shmem_frame = (virt_to_machine(blk_ring.sring) >> PAGE_SHIFT);
+
+ ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
+}
+
+static void blkif_free(void)
+{
+ /* Prevent new requests being issued until we fix things up. */
+ spin_lock_irq(&blkif_io_lock);
+ recovery = 1;
+ blkif_state = BLKIF_STATE_DISCONNECTED;
+ spin_unlock_irq(&blkif_io_lock);
+
+ /* Free resources associated with old device channel. */
+ if ( blk_ring.sring != NULL )
+ {
+ free_page((unsigned long)blk_ring.sring);
+ blk_ring.sring = NULL;
+ }
+ free_irq(blkif_irq, NULL);
+ blkif_irq = 0;
+
+ unbind_evtchn_from_irq(blkif_evtchn);
+ blkif_evtchn = 0;
+}
+
+static void blkif_close(void)
+{
+}
+
+/* Move from CLOSED to DISCONNECTED state. */
+static void blkif_disconnect(void)
+{
+ blkif_sring_t *sring;
+
+ if ( blk_ring.sring != NULL )
+ free_page((unsigned long)blk_ring.sring);
+
+ sring = (blkif_sring_t *)__get_free_page(GFP_KERNEL);
+ SHARED_RING_INIT(sring);
+ FRONT_RING_INIT(&blk_ring, sring, PAGE_SIZE);
+ blkif_state = BLKIF_STATE_DISCONNECTED;
+ blkif_send_interface_connect();
+}
+
+static void blkif_reset(void)
+{
+ blkif_free();
+ blkif_disconnect();
+}
+
+static void blkif_recover(void)
+{
+ int i;
+ blkif_request_t *req;
+ struct blk_shadow *copy;
+#ifdef CONFIG_XEN_BLKDEV_GRANT
+ int j;
+#endif
+
+ /* Stage 1: Make a safe copy of the shadow state. */
+ copy = (struct blk_shadow *)kmalloc(sizeof(blk_shadow), GFP_KERNEL);
+ BUG_ON(copy == NULL);
+ memcpy(copy, blk_shadow, sizeof(blk_shadow));
+
+ /* Stage 2: Set up free list. */
+ memset(&blk_shadow, 0, sizeof(blk_shadow));
+ for ( i = 0; i < BLK_RING_SIZE; i++ )
+ blk_shadow[i].req.id = i+1;
+ blk_shadow_free = blk_ring.req_prod_pvt;
+ blk_shadow[BLK_RING_SIZE-1].req.id = 0x0fffffff;
+
+ /* Stage 3: Find pending requests and requeue them. */
+ for ( i = 0; i < BLK_RING_SIZE; i++ )
+ {
+ /* Not in use? */
+ if ( copy[i].request == 0 )
+ continue;
+
+ /* Grab a request slot and unpickle shadow state into it. */
+ req = RING_GET_REQUEST(
+ &blk_ring, blk_ring.req_prod_pvt);
+ unpickle_request(req, ©[i]);
+
+ /* We get a new request id, and must reset the shadow state. */
+ req->id = GET_ID_FROM_FREELIST();
+ memcpy(&blk_shadow[req->id], ©[i], sizeof(copy[i]));
+
+#ifdef CONFIG_XEN_BLKDEV_GRANT
+ /* Rewrite any grant references invalidated by suspend/resume. */
+ for ( j = 0; j < req->nr_segments; j++ )
+ {
+ if ( req->frame_and_sects[j] & GRANTREF_INVALID )
+ gnttab_grant_foreign_access_ref(
+ blkif_gref_from_fas(req->frame_and_sects[j]),
+ rdomid,
+ blk_shadow[req->id].frame[j],
+ rq_data_dir((struct request *)
+ blk_shadow[req->id].request));
+ req->frame_and_sects[j] &= ~GRANTREF_INVALID;
+ }
+ blk_shadow[req->id].req = *req;
+#endif
+
+ blk_ring.req_prod_pvt++;
+ }
+
+ kfree(copy);
+
+ recovery = 0;
+
+ /* blk_ring->req_prod will be set when we flush_requests().*/
+ wmb();
+
+ /* Kicks things back into life. */
+ flush_requests();
+
+ /* Now safe to left other people use the interface. */
+ blkif_state = BLKIF_STATE_CONNECTED;
+}
+
+static void blkif_connect(blkif_fe_interface_status_t *status)
+{
+ int err = 0;
+
+ blkif_evtchn = status->evtchn;
+ blkif_irq = bind_evtchn_to_irq(blkif_evtchn);
+#ifdef CONFIG_XEN_BLKDEV_GRANT
+ rdomid = status->domid;
+#endif
+
+ err = request_irq(blkif_irq, blkif_int, SA_SAMPLE_RANDOM, "blkif", NULL);
+ if ( err )
+ {
+ printk(KERN_ALERT "xen_blk: request_irq failed (err=%d)\n", err);
+ return;
+ }
+
+ if ( recovery )
+ {
+ blkif_recover();
+ }
+ else
+ {
+ /* Transition to connected in case we need to do
+ * a partition probe on a whole disk. */
+ blkif_state = BLKIF_STATE_CONNECTED;
+
+ /* Probe for discs attached to the interface. */
+ xlvbd_init();
+ }
+
+ /* Kick pending requests. */
+ spin_lock_irq(&blkif_io_lock);
+ kick_pending_request_queues();
+ spin_unlock_irq(&blkif_io_lock);
+}
+
+static void unexpected(blkif_fe_interface_status_t *status)
+{
+ DPRINTK(" Unexpected blkif status %u in state %u\n",
+ status->status, blkif_state);
+}
+
+static void blkif_status(blkif_fe_interface_status_t *status)
+{
+ if ( status->handle != blkif_handle )
+ {
+ WPRINTK(" Invalid blkif: handle=%u\n", status->handle);
+ unexpected(status);
+ return;
+ }
+
+ switch ( status->status )
+ {
+ case BLKIF_INTERFACE_STATUS_CLOSED:
+ switch ( blkif_state )
+ {
+ case BLKIF_STATE_CLOSED:
+ unexpected(status);
+ break;
+ case BLKIF_STATE_DISCONNECTED:
+ case BLKIF_STATE_CONNECTED:
+ unexpected(status);
+ blkif_close();
+ break;
+ }
+ break;
+
+ case BLKIF_INTERFACE_STATUS_DISCONNECTED:
+ switch ( blkif_state )
+ {
+ case BLKIF_STATE_CLOSED:
+ blkif_disconnect();
+ break;
+ case BLKIF_STATE_DISCONNECTED:
+ case BLKIF_STATE_CONNECTED:
+ /* unexpected(status); */ /* occurs during suspend/resume */
+ blkif_reset();
+ break;
+ }
+ break;
+
+ case BLKIF_INTERFACE_STATUS_CONNECTED:
+ switch ( blkif_state )
+ {
+ case BLKIF_STATE_CLOSED:
+ unexpected(status);
+ blkif_disconnect();
+ blkif_connect(status);
+ break;
+ case BLKIF_STATE_DISCONNECTED:
+ blkif_connect(status);
+ break;
+ case BLKIF_STATE_CONNECTED:
+ unexpected(status);
+ blkif_connect(status);
+ break;
+ }
+ break;
+
+ case BLKIF_INTERFACE_STATUS_CHANGED:
+ switch ( blkif_state )
+ {
+ case BLKIF_STATE_CLOSED:
+ case BLKIF_STATE_DISCONNECTED:
+ unexpected(status);
+ break;
+ case BLKIF_STATE_CONNECTED:
+ vbd_update();
+ break;
+ }
+ break;
+
+ default:
+ WPRINTK(" Invalid blkif status: %d\n", status->status);
+ break;
+ }
+}
+
+
+static void blkif_ctrlif_rx(ctrl_msg_t *msg, unsigned long id)
+{
+ switch ( msg->subtype )
+ {
+ case CMSG_BLKIF_FE_INTERFACE_STATUS:
+ blkif_status((blkif_fe_interface_status_t *)
+ &msg->msg[0]);
+ break;
+ default:
+ msg->length = 0;
+ break;
+ }
+
+ ctrl_if_send_response(msg);
+}
+
+int wait_for_blkif(void)
+{
+ int err = 0;
+ int i;
+ send_driver_status(1);
+
+ /*
+ * We should read 'nr_interfaces' from response message and wait
+ * for notifications before proceeding. For now we assume that we
+ * will be notified of exactly one interface.
+ */
+ for ( i=0; (blkif_state != BLKIF_STATE_CONNECTED) && (i < 10*HZ); i++ )
+ {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(1);
+ }
+
+ if ( blkif_state != BLKIF_STATE_CONNECTED )
+ {
+ printk(KERN_INFO "xen_blk: Timeout connecting to device!\n");
+ err = -ENOSYS;
+ }
+ return err;
+}
+
+int __init xlblk_init(void)
+{
+ int i;
+
+#ifdef CONFIG_XEN_BLKDEV_GRANT
+ if ( 0 > gnttab_alloc_grant_references( MAXIMUM_OUTSTANDING_BLOCK_REQS,
+ &gref_head, &gref_terminal ))
+ return 1;
+ printk(KERN_ALERT "Blkif frontend is using grant tables.\n");
+#endif
+
+ if ( (xen_start_info.flags & SIF_INITDOMAIN) ||
+ (xen_start_info.flags & SIF_BLK_BE_DOMAIN) )
+ return 0;
+
+ printk(KERN_INFO "xen_blk: Initialising virtual block device driver\n");
+
+ blk_shadow_free = 0;
+ memset(blk_shadow, 0, sizeof(blk_shadow));
+ for ( i = 0; i < BLK_RING_SIZE; i++ )
+ blk_shadow[i].req.id = i+1;
+ blk_shadow[BLK_RING_SIZE-1].req.id = 0x0fffffff;
+
+ (void)ctrl_if_register_receiver(CMSG_BLKIF_FE, blkif_ctrlif_rx,
+ CALLBACK_IN_BLOCKING_CONTEXT);
+
+ wait_for_blkif();
+
+ return 0;
+}
+
+void blkdev_suspend(void)
+{
+}
+
+void blkdev_resume(void)
+{
+#ifdef CONFIG_XEN_BLKDEV_GRANT
+ int i, j;
+ for ( i = 0; i < BLK_RING_SIZE; i++ )
+ for ( j = 0; j < BLKIF_MAX_SEGMENTS_PER_REQUEST; j++ )
+ blk_shadow[i].req.frame_and_sects[j] |= GRANTREF_INVALID;
+#endif
+ send_driver_status(1);
+}
+
+static void blkif_completion(struct blk_shadow *s)
+{
+ int i;
+#ifdef CONFIG_XEN_BLKDEV_GRANT
+ for ( i = 0; i < s->req.nr_segments; i++ )
+ gnttab_release_grant_reference(
+ &gref_head, blkif_gref_from_fas(s->req.frame_and_sects[i]));
+#else
+ /* This is a hack to get the dirty logging bits set */
+ if ( s->req.operation == BLKIF_OP_READ )
+ {
+ for ( i = 0; i < s->req.nr_segments; i++ )
+ {
+ unsigned long pfn = s->req.frame_and_sects[i] >> PAGE_SHIFT;
+ unsigned long mfn = phys_to_machine_mapping[pfn];
+ xen_machphys_update(mfn, pfn);
+ }
+ }
+#endif
+}
--- /dev/null
+/******************************************************************************
+ * block.h
+ *
+ * Shared definitions between all levels of XenLinux Virtual block devices.
+ *
+ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
+ * Modifications by Mark A. Williamson are (c) Intel Research Cambridge
+ * Copyright (c) 2004-2005, Christian Limpach
+ *
+ * This file may be distributed separately from the Linux kernel, or
+ * incorporated into other software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (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 THE
+ * AUTHORS OR COPYRIGHT HOLDERS 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.
+ */
+
+#ifndef __XEN_DRIVERS_BLOCK_H__
+#define __XEN_DRIVERS_BLOCK_H__
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/hdreg.h>
+#include <linux/blkdev.h>
+#include <linux/major.h>
+#include <linux/devfs_fs_kernel.h>
+#include <asm-xen/xen-public/xen.h>
+#include <asm-xen/xen-public/io/blkif.h>
+#include <asm-xen/xen-public/io/ring.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+#include <asm/uaccess.h>
+
+#if 0
+#define DPRINTK(_f, _a...) printk ( KERN_ALERT _f , ## _a )
+#else
+#define DPRINTK(_f, _a...) ((void)0)
+#endif
+
+#if 0
+#define DPRINTK_IOCTL(_f, _a...) printk ( KERN_ALERT _f , ## _a )
+#else
+#define DPRINTK_IOCTL(_f, _a...) ((void)0)
+#endif
+
+struct xlbd_type_info {
+ int partn_shift;
+ int partn_per_major;
+ int devs_per_major;
+ char *devname;
+ char *diskname;
+};
+
+/*
+ * We have one of these per vbd, whether ide, scsi or 'other'. They
+ * hang in private_data off the gendisk structure. We may end up
+ * putting all kinds of interesting stuff here :-)
+ */
+struct xlbd_major_info {
+ int major;
+ int index;
+ int usage;
+ struct xlbd_type_info *type;
+};
+
+struct xlbd_disk_info {
+ int xd_device;
+ struct xlbd_major_info *mi;
+};
+
+typedef struct xen_block {
+ int usage;
+} xen_block_t;
+
+extern struct request_queue *xlbd_blk_queue;
+extern spinlock_t blkif_io_lock;
+
+extern int blkif_open(struct inode *inode, struct file *filep);
+extern int blkif_release(struct inode *inode, struct file *filep);
+extern int blkif_ioctl(struct inode *inode, struct file *filep,
+ unsigned command, unsigned long argument);
+extern int blkif_check(dev_t dev);
+extern int blkif_revalidate(dev_t dev);
+extern void blkif_control_send(blkif_request_t *req, blkif_response_t *rsp);
+#ifdef CONFIG_XEN_BLKDEV_GRANT
+extern void blkif_control_probe_send(
+ blkif_request_t *req, blkif_response_t *rsp, unsigned long address);
+#endif
+extern void do_blkif_request (request_queue_t *rq);
+
+extern void xlvbd_update_vbds(void);
+
+/* Virtual block-device subsystem. */
+extern int xlvbd_init(void);
+extern void xlvbd_cleanup(void);
+
+#endif /* __XEN_DRIVERS_BLOCK_H__ */
--- /dev/null
+/******************************************************************************
+ * vbd.c
+ *
+ * XenLinux virtual block-device driver (xvd).
+ *
+ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
+ * Modifications by Mark A. Williamson are (c) Intel Research Cambridge
+ * Copyright (c) 2004-2005, Christian Limpach
+ *
+ * This file may be distributed separately from the Linux kernel, or
+ * incorporated into other software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (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 THE
+ * AUTHORS OR COPYRIGHT HOLDERS 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 "block.h"
+#include <linux/blkdev.h>
+#include <linux/list.h>
+
+/*
+ * For convenience we distinguish between ide, scsi and 'other' (i.e.,
+ * potentially combinations of the two) in the naming scheme and in a few other
+ * places.
+ */
+
+#define NUM_IDE_MAJORS 10
+#define NUM_SCSI_MAJORS 9
+#define NUM_VBD_MAJORS 1
+
+struct lvdisk
+{
+ blkif_sector_t capacity; /* 0: Size in terms of 512-byte sectors. */
+ blkif_vdev_t device; /* 8: Device number (opaque 16 bit value). */
+ u16 info;
+ struct list_head list;
+};
+
+static struct xlbd_type_info xlbd_ide_type = {
+ .partn_shift = 6,
+ .partn_per_major = 2,
+ .devname = "ide",
+ .diskname = "hd",
+};
+
+static struct xlbd_type_info xlbd_scsi_type = {
+ .partn_shift = 4,
+ .partn_per_major = 16,
+ .devname = "sd",
+ .diskname = "sd",
+};
+
+static struct xlbd_type_info xlbd_vbd_type = {
+ .partn_shift = 4,
+ .partn_per_major = 16,
+ .devname = "xvd",
+ .diskname = "xvd",
+};
+
+static struct xlbd_major_info *major_info[NUM_IDE_MAJORS + NUM_SCSI_MAJORS +
+ NUM_VBD_MAJORS];
+
+#define XLBD_MAJOR_IDE_START 0
+#define XLBD_MAJOR_SCSI_START (NUM_IDE_MAJORS)
+#define XLBD_MAJOR_VBD_START (NUM_IDE_MAJORS + NUM_SCSI_MAJORS)
+
+#define XLBD_MAJOR_IDE_RANGE XLBD_MAJOR_IDE_START ... XLBD_MAJOR_SCSI_START - 1
+#define XLBD_MAJOR_SCSI_RANGE XLBD_MAJOR_SCSI_START ... XLBD_MAJOR_VBD_START - 1
+#define XLBD_MAJOR_VBD_RANGE XLBD_MAJOR_VBD_START ... XLBD_MAJOR_VBD_START + NUM_VBD_MAJORS - 1
+
+/* Information about our VBDs. */
+#define MAX_VBDS 64
+struct list_head vbds_list;
+
+struct request_queue *xlbd_blk_queue = NULL;
+
+#define MAJOR_XEN(dev) ((dev)>>8)
+#define MINOR_XEN(dev) ((dev) & 0xff)
+
+static struct block_device_operations xlvbd_block_fops =
+{
+ .owner = THIS_MODULE,
+ .open = blkif_open,
+ .release = blkif_release,
+ .ioctl = blkif_ioctl,
+};
+
+spinlock_t blkif_io_lock = SPIN_LOCK_UNLOCKED;
+
+static struct lvdisk * xlvbd_device_alloc(void)
+{
+ struct lvdisk *ret;
+
+ ret = kmalloc(sizeof(struct lvdisk), GFP_KERNEL);
+ if ( ret ) {
+ memset(ret, '\0', sizeof(struct lvdisk));
+ INIT_LIST_HEAD(&ret->list);
+ }
+ return ret;
+}
+
+static void xlvbd_device_free(struct lvdisk *disk)
+{
+ list_del(&disk->list);
+ kfree(disk);
+}
+
+static vdisk_t * xlvbd_probe(int *ret)
+{
+ blkif_response_t rsp;
+ blkif_request_t req;
+ vdisk_t *disk_info = NULL;
+ unsigned long buf;
+ int nr;
+
+ buf = __get_free_page(GFP_KERNEL);
+ if ( !buf )
+ goto out;
+
+ memset(&req, 0, sizeof(req));
+ req.operation = BLKIF_OP_PROBE;
+ req.nr_segments = 1;
+#ifdef CONFIG_XEN_BLKDEV_GRANT
+ blkif_control_probe_send(&req, &rsp,
+ (unsigned long)(virt_to_machine(buf)));
+#else
+ req.frame_and_sects[0] = virt_to_machine(buf) | 7;
+
+ blkif_control_send(&req, &rsp);
+#endif
+ if ( rsp.status <= 0 ) {
+ printk(KERN_ALERT "Could not probe disks (%d)\n", rsp.status);
+ goto out;
+ }
+ nr = rsp.status;
+ if ( nr > MAX_VBDS )
+ nr = MAX_VBDS;
+
+ disk_info = kmalloc(nr * sizeof(vdisk_t), GFP_KERNEL);
+ if ( disk_info )
+ memcpy(disk_info, (void *) buf, nr * sizeof(vdisk_t));
+ if ( ret )
+ *ret = nr;
+out:
+ free_page(buf);
+ return disk_info;
+}
+
+static struct xlbd_major_info *xlbd_alloc_major_info(int major, int minor, int index)
+{
+ struct xlbd_major_info *ptr;
+
+ ptr = kmalloc(sizeof(struct xlbd_major_info), GFP_KERNEL);
+ if ( !ptr )
+ return NULL;
+
+ memset(ptr, 0, sizeof(struct xlbd_major_info));
+
+ ptr->major = major;
+
+ switch (index) {
+ case XLBD_MAJOR_IDE_RANGE:
+ ptr->type = &xlbd_ide_type;
+ ptr->index = index - XLBD_MAJOR_IDE_START;
+ break;
+ case XLBD_MAJOR_SCSI_RANGE:
+ ptr->type = &xlbd_scsi_type;
+ ptr->index = index - XLBD_MAJOR_SCSI_START;
+ break;
+ case XLBD_MAJOR_VBD_RANGE:
+ ptr->type = &xlbd_vbd_type;
+ ptr->index = index - XLBD_MAJOR_VBD_START;
+ break;
+ }
+
+ if ( register_blkdev(ptr->major, ptr->type->devname) ) {
+ printk(KERN_ALERT "XL VBD: can't get major %d with name %s\n",
+ ptr->major, ptr->type->devname);
+ kfree(ptr);
+ return NULL;
+ }
+
+ devfs_mk_dir(ptr->type->devname);
+ major_info[index] = ptr;
+ return ptr;
+}
+
+static struct xlbd_major_info *xlbd_get_major_info(int device)
+{
+ int major, minor, index;
+
+ major = MAJOR_XEN(device);
+ minor = MINOR_XEN(device);
+
+ switch (major) {
+ case IDE0_MAJOR: index = 0; break;
+ case IDE1_MAJOR: index = 1; break;
+ case IDE2_MAJOR: index = 2; break;
+ case IDE3_MAJOR: index = 3; break;
+ case IDE4_MAJOR: index = 4; break;
+ case IDE5_MAJOR: index = 5; break;
+ case IDE6_MAJOR: index = 6; break;
+ case IDE7_MAJOR: index = 7; break;
+ case IDE8_MAJOR: index = 8; break;
+ case IDE9_MAJOR: index = 9; break;
+ case SCSI_DISK0_MAJOR: index = 10; break;
+ case SCSI_DISK1_MAJOR ... SCSI_DISK7_MAJOR:
+ index = 11 + major - SCSI_DISK1_MAJOR;
+ break;
+ case SCSI_CDROM_MAJOR: index = 18; break;
+ default: index = 19; break;
+ }
+
+ return major_info[index]
+ ? major_info[index]
+ : xlbd_alloc_major_info(major, minor, index);
+}
+
+static int xlvbd_blk_queue_alloc(struct xlbd_type_info *type)
+{
+ xlbd_blk_queue = blk_init_queue(do_blkif_request, &blkif_io_lock);
+ if ( !xlbd_blk_queue )
+ return -1;
+
+ elevator_init(xlbd_blk_queue, "noop");
+
+ /*
+ * Turn off barking 'headactive' mode. We dequeue
+ * buffer heads as soon as we pass them to back-end
+ * driver.
+ */
+ blk_queue_headactive(xlbd_blk_queue, 0);
+
+ /* Hard sector size and max sectors impersonate the equiv. hardware. */
+ blk_queue_hardsect_size(xlbd_blk_queue, 512);
+ blk_queue_max_sectors(xlbd_blk_queue, 512);
+
+ /* Each segment in a request is up to an aligned page in size. */
+ blk_queue_segment_boundary(xlbd_blk_queue, PAGE_SIZE - 1);
+ blk_queue_max_segment_size(xlbd_blk_queue, PAGE_SIZE);
+
+ /* Ensure a merged request will fit in a single I/O ring slot. */
+ blk_queue_max_phys_segments(xlbd_blk_queue, BLKIF_MAX_SEGMENTS_PER_REQUEST);
+ blk_queue_max_hw_segments(xlbd_blk_queue, BLKIF_MAX_SEGMENTS_PER_REQUEST);
+
+ /* Make sure buffer addresses are sector-aligned. */
+ blk_queue_dma_alignment(xlbd_blk_queue, 511);
+ return 0;
+}
+
+struct gendisk *xlvbd_alloc_gendisk(struct xlbd_major_info *mi, int minor,
+ vdisk_t *disk)
+{
+ struct gendisk *gd;
+ struct xlbd_disk_info *di;
+ int nb_minors;
+
+ di = kmalloc(sizeof(struct xlbd_disk_info), GFP_KERNEL);
+ if ( !di )
+ goto out;
+ di->mi = mi;
+ di->xd_device = disk->device;
+
+ nb_minors = ((minor & ((1 << mi->type->partn_shift) - 1)) == 0)
+ ? mi->type->partn_per_major
+ : 1;
+
+ gd = alloc_disk(nb_minors);
+ if ( !gd )
+ goto out;
+
+ if ( nb_minors > 1 )
+ sprintf(gd->disk_name, "%s%c", mi->type->diskname,
+ 'a' + mi->index * mi->type->partn_per_major +
+ (minor >> mi->type->partn_shift));
+ else
+ sprintf(gd->disk_name, "%s%c%d", mi->type->diskname,
+ 'a' + mi->index * mi->type->partn_per_major +
+ (minor >> mi->type->partn_shift),
+ minor & ((1 << mi->type->partn_shift) - 1));
+
+ gd->major = mi->major;
+ gd->first_minor = minor;
+ gd->fops = &xlvbd_block_fops;
+ gd->private_data = di;
+ set_capacity(gd, disk->capacity);
+
+ if ( !xlbd_blk_queue )
+ if ( xlvbd_blk_queue_alloc(mi->type) )
+ goto out_gendisk;
+
+ gd->queue = xlbd_blk_queue;
+ add_disk(gd);
+ return gd;
+out_gendisk:
+ printk(KERN_ALERT "error gendisk\n");
+ del_gendisk(gd);
+out:
+ printk(KERN_ALERT "error out\n");
+ kfree(di);
+ return NULL;
+}
+
+static int xlvbd_device_add(struct list_head *list, vdisk_t *disk)
+{
+ struct lvdisk *new;
+ int minor;
+ dev_t device;
+ struct block_device *bd;
+ struct gendisk *gd;
+ struct xlbd_major_info *mi;
+
+ mi = xlbd_get_major_info(disk->device);
+ if ( !mi )
+ return -EPERM;
+
+ new = xlvbd_device_alloc();
+ if ( !new )
+ return -1;
+ new->capacity = disk->capacity;
+ new->device = disk->device;
+ new->info = disk->info;
+
+ minor = MINOR_XEN(disk->device);
+ device = MKDEV(mi->major, minor);
+
+ bd = bdget(device);
+ if ( !bd )
+ goto out;
+
+ gd = xlvbd_alloc_gendisk(mi, minor, disk);
+ if ( !gd )
+ goto out_bd;
+
+ if ( VDISK_READONLY(disk->info) )
+ set_disk_ro(gd, 1);
+
+ switch (VDISK_TYPE(disk->info)) {
+ case VDISK_TYPE_CDROM:
+ gd->flags |= GENHD_FL_REMOVABLE | GENHD_FL_CD;
+ break;
+ case VDISK_TYPE_FLOPPY:
+ case VDISK_TYPE_TAPE:
+ gd->flags |= GENHD_FL_REMOVABLE;
+ break;
+ case VDISK_TYPE_DISK:
+ break;
+ default:
+ printk(KERN_ALERT "XenLinux: unknown device type %d\n",
+ VDISK_TYPE(disk->info));
+ break;
+ }
+
+ list_add(&new->list, list);
+out_bd:
+ bdput(bd);
+out:
+ return 0;
+}
+
+static int xlvbd_device_del(struct lvdisk *disk)
+{
+ dev_t device;
+ struct block_device *bd;
+ struct gendisk *gd;
+ struct xlbd_disk_info *di;
+ int ret = 0, unused;
+
+ device = MKDEV(MAJOR_XEN(disk->device), MINOR_XEN(disk->device));
+
+ bd = bdget(device);
+ if ( !bd )
+ return -1;
+
+ gd = get_gendisk(device, &unused);
+ di = gd->private_data;
+
+ if ( di->mi->usage != 0 ) {
+ printk(KERN_ALERT "VBD removal failed: used [dev=%x]\n", device);
+ ret = -1;
+ goto out;
+ }
+
+ del_gendisk(gd);
+
+ xlvbd_device_free(disk);
+out:
+ bdput(bd);
+ return ret;
+}
+
+static int xlvbd_device_update(struct lvdisk *ldisk, vdisk_t *disk)
+{
+ dev_t device;
+ struct block_device *bd;
+ struct gendisk *gd;
+ int unused;
+
+ if ( ldisk->capacity == disk->capacity && ldisk->info == disk->info )
+ return 0;
+
+ device = MKDEV(MAJOR_XEN(ldisk->device), MINOR_XEN(ldisk->device));
+
+ bd = bdget(device);
+ if ( !bd )
+ return -1;
+
+ gd = get_gendisk(device, &unused);
+ set_capacity(gd, disk->capacity);
+ ldisk->capacity = disk->capacity;
+
+ bdput(bd);
+
+ return 0;
+}
+
+void xlvbd_refresh(void)
+{
+ vdisk_t *newdisks;
+ struct list_head *tmp, *tmp2;
+ struct lvdisk *disk;
+ int i, nr;
+
+ newdisks = xlvbd_probe(&nr);
+ if ( !newdisks ) {
+ printk(KERN_ALERT "failed to probe\n");
+ return;
+ }
+
+ i = 0;
+ list_for_each_safe(tmp, tmp2, &vbds_list) {
+ disk = list_entry(tmp, struct lvdisk, list);
+
+ for (i = 0; i < nr; i++) {
+ if ( !newdisks[i].device )
+ continue;
+ if ( disk->device == newdisks[i].device ) {
+ xlvbd_device_update(disk, &newdisks[i]);
+ newdisks[i].device = 0;
+ break;
+ }
+ }
+ if ( i == nr ) {
+ xlvbd_device_del(disk);
+ newdisks[i].device = 0;
+ }
+ }
+ for (i = 0; i < nr; i++)
+ if ( newdisks[i].device )
+ xlvbd_device_add(&vbds_list, &newdisks[i]);
+ kfree(newdisks);
+}
+
+/*
+ * xlvbd_update_vbds - reprobes the VBD status and performs updates driver
+ * state. The VBDs need to be updated in this way when the domain is
+ * initialised and also each time we receive an XLBLK_UPDATE event.
+ */
+void xlvbd_update_vbds(void)
+{
+ xlvbd_refresh();
+}
+
+/*
+ * Set up all the linux device goop for the virtual block devices
+ * (vbd's) that we know about. Note that although from the backend
+ * driver's p.o.v. VBDs are addressed simply an opaque 16-bit device
+ * number, the domain creation tools conventionally allocate these
+ * numbers to correspond to those used by 'real' linux -- this is just
+ * for convenience as it means e.g. that the same /etc/fstab can be
+ * used when booting with or without Xen.
+ */
+int xlvbd_init(void)
+{
+ int i, nr;
+ vdisk_t *disks;
+
+ INIT_LIST_HEAD(&vbds_list);
+
+ memset(major_info, 0, sizeof(major_info));
+
+ disks = xlvbd_probe(&nr);
+ if ( !disks ) {
+ printk(KERN_ALERT "failed to probe\n");
+ return -1;
+ }
+
+ for (i = 0; i < nr; i++)
+ xlvbd_device_add(&vbds_list, &disks[i]);
+ kfree(disks);
+ return 0;
+}
--- /dev/null
+
+obj-y := blktap_userdev.o blktap_datapath.o blktap_controlmsg.o blktap.o
+
--- /dev/null
+/******************************************************************************
+ * blktap.c
+ *
+ * XenLinux virtual block-device tap.
+ *
+ * Copyright (c) 2004, Andrew Warfield
+ *
+ * Based on the original split block driver:
+ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
+ * Modifications by Mark A. Williamson are (c) Intel Research Cambridge
+ * Copyright (c) 2004, Christian Limpach
+ *
+ * Note that unlike the split block driver code, this driver has been developed
+ * strictly for Linux 2.6
+ */
+
+#include "blktap.h"
+
+int __init xlblktap_init(void)
+{
+ ctrl_msg_t cmsg;
+ blkif_fe_driver_status_t fe_st;
+ blkif_be_driver_status_t be_st;
+
+ printk(KERN_INFO "Initialising Xen block tap device\n");
+
+ DPRINTK(" tap - Backend connection init:\n");
+
+
+ (void)ctrl_if_register_receiver(CMSG_BLKIF_FE, blkif_ctrlif_rx,
+ CALLBACK_IN_BLOCKING_CONTEXT);
+
+ /* Send a driver-UP notification to the domain controller. */
+ cmsg.type = CMSG_BLKIF_FE;
+ cmsg.subtype = CMSG_BLKIF_FE_DRIVER_STATUS;
+ cmsg.length = sizeof(blkif_fe_driver_status_t);
+ fe_st.status = BLKIF_DRIVER_STATUS_UP;
+ memcpy(cmsg.msg, &fe_st, sizeof(fe_st));
+ ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
+
+ DPRINTK(" tap - Frontend connection init:\n");
+
+ active_reqs_init();
+ blkif_interface_init();
+ blkdev_schedule_init();
+
+ (void)ctrl_if_register_receiver(CMSG_BLKIF_BE, blkif_ctrlif_rx,
+ CALLBACK_IN_BLOCKING_CONTEXT);
+
+ /* Send a driver-UP notification to the domain controller. */
+ cmsg.type = CMSG_BLKIF_BE;
+ cmsg.subtype = CMSG_BLKIF_BE_DRIVER_STATUS;
+ cmsg.length = sizeof(blkif_be_driver_status_t);
+ be_st.status = BLKIF_DRIVER_STATUS_UP;
+ memcpy(cmsg.msg, &be_st, sizeof(be_st));
+ ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
+
+ DPRINTK(" tap - Userland channel init:\n");
+
+ blktap_init();
+
+ DPRINTK("Blkif tap device initialized.\n");
+
+ return 0;
+}
+
+#if 0 /* tap doesn't handle suspend/resume */
+void blkdev_suspend(void)
+{
+}
+
+void blkdev_resume(void)
+{
+ ctrl_msg_t cmsg;
+ blkif_fe_driver_status_t st;
+
+ /* Send a driver-UP notification to the domain controller. */
+ cmsg.type = CMSG_BLKIF_FE;
+ cmsg.subtype = CMSG_BLKIF_FE_DRIVER_STATUS;
+ cmsg.length = sizeof(blkif_fe_driver_status_t);
+ st.status = BLKIF_DRIVER_STATUS_UP;
+ memcpy(cmsg.msg, &st, sizeof(st));
+ ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
+}
+#endif
+
+__initcall(xlblktap_init);
--- /dev/null
+
+obj-y := console.o
--- /dev/null
+/******************************************************************************
+ * console.c
+ *
+ * Virtual console driver.
+ *
+ * Copyright (c) 2002-2004, K A Fraser.
+ *
+ * This file may be distributed separately from the Linux kernel, or
+ * incorporated into other software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (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 THE
+ * AUTHORS OR COPYRIGHT HOLDERS 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 <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/major.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/bootmem.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm-xen/xen-public/event_channel.h>
+#include <asm-xen/hypervisor.h>
+#include <asm-xen/evtchn.h>
+#include <asm-xen/ctrl_if.h>
+
+/*
+ * Modes:
+ * 'xencons=off' [XC_OFF]: Console is disabled.
+ * 'xencons=tty' [XC_TTY]: Console attached to '/dev/tty[0-9]+'.
+ * 'xencons=ttyS' [XC_SERIAL]: Console attached to '/dev/ttyS[0-9]+'.
+ * [XC_DEFAULT]: DOM0 -> XC_SERIAL ; all others -> XC_TTY.
+ *
+ * NB. In mode XC_TTY, we create dummy consoles for tty2-63. This suppresses
+ * warnings from standard distro startup scripts.
+ */
+static enum { XC_OFF, XC_DEFAULT, XC_TTY, XC_SERIAL } xc_mode = XC_DEFAULT;
+static int xc_num = -1;
+
+static int __init xencons_setup(char *str)
+{
+ char *q;
+ int n;
+
+ if ( !strncmp(str, "ttyS", 4) )
+ xc_mode = XC_SERIAL;
+ else if ( !strncmp(str, "tty", 3) )
+ xc_mode = XC_TTY;
+ else if ( !strncmp(str, "off", 3) )
+ xc_mode = XC_OFF;
+
+ switch ( xc_mode )
+ {
+ case XC_SERIAL:
+ n = simple_strtol( str+4, &q, 10 );
+ if ( q > (str + 4) ) xc_num = n;
+ break;
+ case XC_TTY:
+ n = simple_strtol( str+3, &q, 10 );
+ if ( q > (str + 3) ) xc_num = n;
+ break;
+ default:
+ break;
+ }
+
+ return 1;
+}
+__setup("xencons=", xencons_setup);
+
+/* The kernel and user-land drivers share a common transmit buffer. */
+static unsigned int wbuf_size = 4096;
+#define WBUF_MASK(_i) ((_i)&(wbuf_size-1))
+static char *wbuf;
+static unsigned int wc, wp; /* write_cons, write_prod */
+
+static int __init xencons_bufsz_setup(char *str)
+{
+ unsigned int goal;
+ goal = simple_strtoul(str, NULL, 0);
+ while ( wbuf_size < goal )
+ wbuf_size <<= 1;
+ return 1;
+}
+__setup("xencons_bufsz=", xencons_bufsz_setup);
+
+/* This lock protects accesses to the common transmit buffer. */
+static spinlock_t xencons_lock = SPIN_LOCK_UNLOCKED;
+
+/* Common transmit-kick routine. */
+static void __xencons_tx_flush(void);
+
+/* This task is used to defer sending console data until there is space. */
+static void xencons_tx_flush_task_routine(void *data);
+
+static DECLARE_TQUEUE(xencons_tx_flush_task,
+ xencons_tx_flush_task_routine,
+ NULL);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+static struct tty_driver *xencons_driver;
+#else
+static struct tty_driver xencons_driver;
+#endif
+
+
+/******************** Kernel console driver ********************************/
+
+static void kcons_write(
+ struct console *c, const char *s, unsigned int count)
+{
+ int i;
+ unsigned long flags;
+
+ spin_lock_irqsave(&xencons_lock, flags);
+
+ for ( i = 0; i < count; i++ )
+ {
+ if ( (wp - wc) >= (wbuf_size - 1) )
+ break;
+ if ( (wbuf[WBUF_MASK(wp++)] = s[i]) == '\n' )
+ wbuf[WBUF_MASK(wp++)] = '\r';
+ }
+
+ __xencons_tx_flush();
+
+ spin_unlock_irqrestore(&xencons_lock, flags);
+}
+
+static void kcons_write_dom0(
+ struct console *c, const char *s, unsigned int count)
+{
+ int rc;
+
+ while ( (count > 0) &&
+ ((rc = HYPERVISOR_console_io(
+ CONSOLEIO_write, count, (char *)s)) > 0) )
+ {
+ count -= rc;
+ s += rc;
+ }
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+static struct tty_driver *kcons_device(struct console *c, int *index)
+{
+ *index = c->index;
+ return xencons_driver;
+}
+#else
+static kdev_t kcons_device(struct console *c)
+{
+ return MKDEV(TTY_MAJOR, (xc_mode == XC_SERIAL) ? 64 : 1);
+}
+#endif
+
+static struct console kcons_info = {
+ device: kcons_device,
+ flags: CON_PRINTBUFFER,
+ index: -1
+};
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+#define __RETCODE 0
+static int __init xen_console_init(void)
+#else
+#define __RETCODE
+void xen_console_init(void)
+#endif
+{
+ if ( xen_start_info.flags & SIF_INITDOMAIN )
+ {
+ if ( xc_mode == XC_DEFAULT )
+ xc_mode = XC_SERIAL;
+ kcons_info.write = kcons_write_dom0;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+ if ( xc_mode == XC_SERIAL )
+ kcons_info.flags |= CON_ENABLED;
+#endif
+ }
+ else
+ {
+ if ( xc_mode == XC_DEFAULT )
+ xc_mode = XC_TTY;
+ kcons_info.write = kcons_write;
+ }
+
+ switch ( xc_mode )
+ {
+ case XC_SERIAL:
+ strcpy(kcons_info.name, "ttyS");
+ if ( xc_num == -1 ) xc_num = 0;
+ break;
+
+ case XC_TTY:
+ strcpy(kcons_info.name, "tty");
+ if ( xc_num == -1 ) xc_num = 1;
+ break;
+
+ default:
+ return __RETCODE;
+ }
+
+ wbuf = alloc_bootmem(wbuf_size);
+
+ register_console(&kcons_info);
+
+ return __RETCODE;
+}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+console_initcall(xen_console_init);
+#endif
+
+/*** Useful function for console debugging -- goes straight to Xen. ***/
+asmlinkage int xprintk(const char *fmt, ...)
+{
+ va_list args;
+ int printk_len;
+ static char printk_buf[1024];
+
+ /* Emit the output into the temporary buffer */
+ va_start(args, fmt);
+ printk_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args);
+ va_end(args);
+
+ /* Send the processed output directly to Xen. */
+ kcons_write_dom0(NULL, printk_buf, printk_len);
+
+ return 0;
+}
+
+/*** Forcibly flush console data before dying. ***/
+void xencons_force_flush(void)
+{
+ ctrl_msg_t msg;
+ int sz;
+
+ /* Emergency console is synchronous, so there's nothing to flush. */
+ if ( xen_start_info.flags & SIF_INITDOMAIN )
+ return;
+
+ /*
+ * We use dangerous control-interface functions that require a quiescent
+ * system and no interrupts. Try to ensure this with a global cli().
+ */
+ local_irq_disable(); /* XXXsmp */
+
+ /* Spin until console data is flushed through to the domain controller. */
+ while ( (wc != wp) && !ctrl_if_transmitter_empty() )
+ {
+ /* Interrupts are disabled -- we must manually reap responses. */
+ ctrl_if_discard_responses();
+
+ if ( (sz = wp - wc) == 0 )
+ continue;
+ if ( sz > sizeof(msg.msg) )
+ sz = sizeof(msg.msg);
+ if ( sz > (wbuf_size - WBUF_MASK(wc)) )
+ sz = wbuf_size - WBUF_MASK(wc);
+
+ msg.type = CMSG_CONSOLE;
+ msg.subtype = CMSG_CONSOLE_DATA;
+ msg.length = sz;
+ memcpy(msg.msg, &wbuf[WBUF_MASK(wc)], sz);
+
+ if ( ctrl_if_send_message_noblock(&msg, NULL, 0) == 0 )
+ wc += sz;
+ }
+}
+
+
+/******************** User-space console driver (/dev/console) ************/
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+#define DRV(_d) (_d)
+#define TTY_INDEX(_tty) ((_tty)->index)
+#else
+static int xencons_refcount;
+static struct tty_struct *xencons_table[MAX_NR_CONSOLES];
+#define DRV(_d) (&(_d))
+#define TTY_INDEX(_tty) (MINOR((_tty)->device) - xencons_driver.minor_start)
+#endif
+
+static struct termios *xencons_termios[MAX_NR_CONSOLES];
+static struct termios *xencons_termios_locked[MAX_NR_CONSOLES];
+static struct tty_struct *xencons_tty;
+static int xencons_priv_irq;
+static char x_char;
+
+/* Non-privileged receive callback. */
+static void xencons_rx(ctrl_msg_t *msg, unsigned long id)
+{
+ int i;
+ unsigned long flags;
+
+ spin_lock_irqsave(&xencons_lock, flags);
+ if ( xencons_tty != NULL )
+ {
+ for ( i = 0; i < msg->length; i++ )
+ tty_insert_flip_char(xencons_tty, msg->msg[i], 0);
+ tty_flip_buffer_push(xencons_tty);
+ }
+ spin_unlock_irqrestore(&xencons_lock, flags);
+
+ msg->length = 0;
+ ctrl_if_send_response(msg);
+}
+
+/* Privileged and non-privileged transmit worker. */
+static void __xencons_tx_flush(void)
+{
+ int sz, work_done = 0;
+ ctrl_msg_t msg;
+
+ if ( xen_start_info.flags & SIF_INITDOMAIN )
+ {
+ if ( x_char )
+ {
+ kcons_write_dom0(NULL, &x_char, 1);
+ x_char = 0;
+ work_done = 1;
+ }
+
+ while ( wc != wp )
+ {
+ sz = wp - wc;
+ if ( sz > (wbuf_size - WBUF_MASK(wc)) )
+ sz = wbuf_size - WBUF_MASK(wc);
+ kcons_write_dom0(NULL, &wbuf[WBUF_MASK(wc)], sz);
+ wc += sz;
+ work_done = 1;
+ }
+ }
+ else
+ {
+ while ( x_char )
+ {
+ msg.type = CMSG_CONSOLE;
+ msg.subtype = CMSG_CONSOLE_DATA;
+ msg.length = 1;
+ msg.msg[0] = x_char;
+
+ if ( ctrl_if_send_message_noblock(&msg, NULL, 0) == 0 )
+ x_char = 0;
+ else if ( ctrl_if_enqueue_space_callback(&xencons_tx_flush_task) )
+ break;
+
+ work_done = 1;
+ }
+
+ while ( wc != wp )
+ {
+ sz = wp - wc;
+ if ( sz > sizeof(msg.msg) )
+ sz = sizeof(msg.msg);
+ if ( sz > (wbuf_size - WBUF_MASK(wc)) )
+ sz = wbuf_size - WBUF_MASK(wc);
+
+ msg.type = CMSG_CONSOLE;
+ msg.subtype = CMSG_CONSOLE_DATA;
+ msg.length = sz;
+ memcpy(msg.msg, &wbuf[WBUF_MASK(wc)], sz);
+
+ if ( ctrl_if_send_message_noblock(&msg, NULL, 0) == 0 )
+ wc += sz;
+ else if ( ctrl_if_enqueue_space_callback(&xencons_tx_flush_task) )
+ break;
+
+ work_done = 1;
+ }
+ }
+
+ if ( work_done && (xencons_tty != NULL) )
+ {
+ wake_up_interruptible(&xencons_tty->write_wait);
+ if ( (xencons_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ (xencons_tty->ldisc.write_wakeup != NULL) )
+ (xencons_tty->ldisc.write_wakeup)(xencons_tty);
+ }
+}
+
+/* Non-privileged transmit kicker. */
+static void xencons_tx_flush_task_routine(void *data)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&xencons_lock, flags);
+ __xencons_tx_flush();
+ spin_unlock_irqrestore(&xencons_lock, flags);
+}
+
+/* Privileged receive callback and transmit kicker. */
+static irqreturn_t xencons_priv_interrupt(int irq, void *dev_id,
+ struct pt_regs *regs)
+{
+ static char rbuf[16];
+ int i, l;
+ unsigned long flags;
+
+ spin_lock_irqsave(&xencons_lock, flags);
+
+ if ( xencons_tty != NULL )
+ {
+ /* Receive work. */
+ while ( (l = HYPERVISOR_console_io(CONSOLEIO_read, 16, rbuf)) > 0 )
+ for ( i = 0; i < l; i++ )
+ tty_insert_flip_char(xencons_tty, rbuf[i], 0);
+ if ( xencons_tty->flip.count != 0 )
+ tty_flip_buffer_push(xencons_tty);
+ }
+
+ /* Transmit work. */
+ __xencons_tx_flush();
+
+ spin_unlock_irqrestore(&xencons_lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+static int xencons_write_room(struct tty_struct *tty)
+{
+ return wbuf_size - (wp - wc);
+}
+
+static int xencons_chars_in_buffer(struct tty_struct *tty)
+{
+ return wp - wc;
+}
+
+static void xencons_send_xchar(struct tty_struct *tty, char ch)
+{
+ unsigned long flags;
+
+ if ( TTY_INDEX(tty) != 0 )
+ return;
+
+ spin_lock_irqsave(&xencons_lock, flags);
+ x_char = ch;
+ __xencons_tx_flush();
+ spin_unlock_irqrestore(&xencons_lock, flags);
+}
+
+static void xencons_throttle(struct tty_struct *tty)
+{
+ if ( TTY_INDEX(tty) != 0 )
+ return;
+
+ if ( I_IXOFF(tty) )
+ xencons_send_xchar(tty, STOP_CHAR(tty));
+}
+
+static void xencons_unthrottle(struct tty_struct *tty)
+{
+ if ( TTY_INDEX(tty) != 0 )
+ return;
+
+ if ( I_IXOFF(tty) )
+ {
+ if ( x_char != 0 )
+ x_char = 0;
+ else
+ xencons_send_xchar(tty, START_CHAR(tty));
+ }
+}
+
+static void xencons_flush_buffer(struct tty_struct *tty)
+{
+ unsigned long flags;
+
+ if ( TTY_INDEX(tty) != 0 )
+ return;
+
+ spin_lock_irqsave(&xencons_lock, flags);
+ wc = wp = 0;
+ spin_unlock_irqrestore(&xencons_lock, flags);
+}
+
+static inline int __xencons_put_char(int ch)
+{
+ char _ch = (char)ch;
+ if ( (wp - wc) == wbuf_size )
+ return 0;
+ wbuf[WBUF_MASK(wp++)] = _ch;
+ return 1;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+static int xencons_write(
+ struct tty_struct *tty,
+ const unsigned char *buf,
+ int count)
+{
+ int i;
+ unsigned long flags;
+
+ if ( TTY_INDEX(tty) != 0 )
+ return count;
+
+ spin_lock_irqsave(&xencons_lock, flags);
+
+ for ( i = 0; i < count; i++ )
+ if ( !__xencons_put_char(buf[i]) )
+ break;
+
+ if ( i != 0 )
+ __xencons_tx_flush();
+
+ spin_unlock_irqrestore(&xencons_lock, flags);
+
+ return i;
+}
+#else
+static int xencons_write(
+ struct tty_struct *tty,
+ int from_user,
+ const u_char *buf,
+ int count)
+{
+ int i;
+ unsigned long flags;
+
+ if ( from_user && verify_area(VERIFY_READ, buf, count) )
+ return -EINVAL;
+
+ if ( TTY_INDEX(tty) != 0 )
+ return count;
+
+ spin_lock_irqsave(&xencons_lock, flags);
+
+ for ( i = 0; i < count; i++ )
+ {
+ char ch;
+ if ( from_user )
+ __get_user(ch, buf + i);
+ else
+ ch = buf[i];
+ if ( !__xencons_put_char(ch) )
+ break;
+ }
+
+ if ( i != 0 )
+ __xencons_tx_flush();
+
+ spin_unlock_irqrestore(&xencons_lock, flags);
+
+ return i;
+}
+#endif
+
+static void xencons_put_char(struct tty_struct *tty, u_char ch)
+{
+ unsigned long flags;
+
+ if ( TTY_INDEX(tty) != 0 )
+ return;
+
+ spin_lock_irqsave(&xencons_lock, flags);
+ (void)__xencons_put_char(ch);
+ spin_unlock_irqrestore(&xencons_lock, flags);
+}
+
+static void xencons_flush_chars(struct tty_struct *tty)
+{
+ unsigned long flags;
+
+ if ( TTY_INDEX(tty) != 0 )
+ return;
+
+ spin_lock_irqsave(&xencons_lock, flags);
+ __xencons_tx_flush();
+ spin_unlock_irqrestore(&xencons_lock, flags);
+}
+
+static void xencons_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+ unsigned long orig_jiffies = jiffies;
+
+ if ( TTY_INDEX(tty) != 0 )
+ return;
+
+ while ( DRV(tty->driver)->chars_in_buffer(tty) )
+ {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(1);
+ if ( signal_pending(current) )
+ break;
+ if ( (timeout != 0) && time_after(jiffies, orig_jiffies + timeout) )
+ break;
+ }
+
+ set_current_state(TASK_RUNNING);
+}
+
+static int xencons_open(struct tty_struct *tty, struct file *filp)
+{
+ unsigned long flags;
+
+ if ( TTY_INDEX(tty) != 0 )
+ return 0;
+
+ spin_lock_irqsave(&xencons_lock, flags);
+ tty->driver_data = NULL;
+ if ( xencons_tty == NULL )
+ xencons_tty = tty;
+ __xencons_tx_flush();
+ spin_unlock_irqrestore(&xencons_lock, flags);
+
+ return 0;
+}
+
+static void xencons_close(struct tty_struct *tty, struct file *filp)
+{
+ unsigned long flags;
+
+ if ( TTY_INDEX(tty) != 0 )
+ return;
+
+ if ( tty->count == 1 )
+ {
+ tty->closing = 1;
+ tty_wait_until_sent(tty, 0);
+ if ( DRV(tty->driver)->flush_buffer != NULL )
+ DRV(tty->driver)->flush_buffer(tty);
+ if ( tty->ldisc.flush_buffer != NULL )
+ tty->ldisc.flush_buffer(tty);
+ tty->closing = 0;
+ spin_lock_irqsave(&xencons_lock, flags);
+ xencons_tty = NULL;
+ spin_unlock_irqrestore(&xencons_lock, flags);
+ }
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+static struct tty_operations xencons_ops = {
+ .open = xencons_open,
+ .close = xencons_close,
+ .write = xencons_write,
+ .write_room = xencons_write_room,
+ .put_char = xencons_put_char,
+ .flush_chars = xencons_flush_chars,
+ .chars_in_buffer = xencons_chars_in_buffer,
+ .send_xchar = xencons_send_xchar,
+ .flush_buffer = xencons_flush_buffer,
+ .throttle = xencons_throttle,
+ .unthrottle = xencons_unthrottle,
+ .wait_until_sent = xencons_wait_until_sent,
+};
+
+#ifdef CONFIG_XEN_PRIVILEGED_GUEST
+static const char *xennullcon_startup(void)
+{
+ return NULL;
+}
+
+static int xennullcon_dummy(void)
+{
+ return 0;
+}
+
+#define DUMMY (void *)xennullcon_dummy
+
+/*
+ * The console `switch' structure for the dummy console
+ *
+ * Most of the operations are dummies.
+ */
+
+const struct consw xennull_con = {
+ .owner = THIS_MODULE,
+ .con_startup = xennullcon_startup,
+ .con_init = DUMMY,
+ .con_deinit = DUMMY,
+ .con_clear = DUMMY,
+ .con_putc = DUMMY,
+ .con_putcs = DUMMY,
+ .con_cursor = DUMMY,
+ .con_scroll = DUMMY,
+ .con_bmove = DUMMY,
+ .con_switch = DUMMY,
+ .con_blank = DUMMY,
+ .con_font_set = DUMMY,
+ .con_font_get = DUMMY,
+ .con_font_default = DUMMY,
+ .con_font_copy = DUMMY,
+ .con_set_palette = DUMMY,
+ .con_scrolldelta = DUMMY,
+};
+#endif
+#endif
+
+static int __init xencons_init(void)
+{
+ int rc;
+
+ if ( xc_mode == XC_OFF )
+ return 0;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+ xencons_driver = alloc_tty_driver((xc_mode == XC_SERIAL) ?
+ 1 : MAX_NR_CONSOLES);
+ if ( xencons_driver == NULL )
+ return -ENOMEM;
+#else
+ memset(&xencons_driver, 0, sizeof(struct tty_driver));
+ xencons_driver.magic = TTY_DRIVER_MAGIC;
+ xencons_driver.refcount = &xencons_refcount;
+ xencons_driver.table = xencons_table;
+ xencons_driver.num = (xc_mode == XC_SERIAL) ? 1 : MAX_NR_CONSOLES;
+#endif
+
+ DRV(xencons_driver)->major = TTY_MAJOR;
+ DRV(xencons_driver)->type = TTY_DRIVER_TYPE_SERIAL;
+ DRV(xencons_driver)->subtype = SERIAL_TYPE_NORMAL;
+ DRV(xencons_driver)->init_termios = tty_std_termios;
+ DRV(xencons_driver)->flags =
+ TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_NO_DEVFS;
+ DRV(xencons_driver)->termios = xencons_termios;
+ DRV(xencons_driver)->termios_locked = xencons_termios_locked;
+
+ if ( xc_mode == XC_SERIAL )
+ {
+ DRV(xencons_driver)->name = "ttyS";
+ DRV(xencons_driver)->minor_start = 64 + xc_num;
+ DRV(xencons_driver)->name_base = 0 + xc_num;
+ }
+ else
+ {
+ DRV(xencons_driver)->name = "tty";
+ DRV(xencons_driver)->minor_start = xc_num;
+ DRV(xencons_driver)->name_base = xc_num;
+ }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+ tty_set_operations(xencons_driver, &xencons_ops);
+#else
+ xencons_driver.open = xencons_open;
+ xencons_driver.close = xencons_close;
+ xencons_driver.write = xencons_write;
+ xencons_driver.write_room = xencons_write_room;
+ xencons_driver.put_char = xencons_put_char;
+ xencons_driver.flush_chars = xencons_flush_chars;
+ xencons_driver.chars_in_buffer = xencons_chars_in_buffer;
+ xencons_driver.send_xchar = xencons_send_xchar;
+ xencons_driver.flush_buffer = xencons_flush_buffer;
+ xencons_driver.throttle = xencons_throttle;
+ xencons_driver.unthrottle = xencons_unthrottle;
+ xencons_driver.wait_until_sent = xencons_wait_until_sent;
+#endif
+
+ if ( (rc = tty_register_driver(DRV(xencons_driver))) != 0 )
+ {
+ printk("WARNING: Failed to register Xen virtual "
+ "console driver as '%s%d'\n",
+ DRV(xencons_driver)->name, DRV(xencons_driver)->name_base);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+ put_tty_driver(xencons_driver);
+ xencons_driver = NULL;
+#endif
+ return rc;
+ }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+ tty_register_device(xencons_driver, 0, NULL);
+#endif
+
+ if ( xen_start_info.flags & SIF_INITDOMAIN )
+ {
+ xencons_priv_irq = bind_virq_to_irq(VIRQ_CONSOLE);
+ (void)request_irq(xencons_priv_irq,
+ xencons_priv_interrupt, 0, "console", NULL);
+ }
+ else
+ {
+ (void)ctrl_if_register_receiver(CMSG_CONSOLE, xencons_rx, 0);
+ }
+
+ printk("Xen virtual console successfully installed as %s%d\n",
+ DRV(xencons_driver)->name,
+ DRV(xencons_driver)->name_base );
+
+ return 0;
+}
+
+module_init(xencons_init);
--- /dev/null
+
+obj-y := evtchn.o
--- /dev/null
+/******************************************************************************
+ * evtchn.c
+ *
+ * Xenolinux driver for receiving and demuxing event-channel signals.
+ *
+ * Copyright (c) 2004, K A Fraser
+ * Multi-process extensions Copyright (c) 2004, Steven Smith
+ *
+ * This file may be distributed separately from the Linux kernel, or
+ * incorporated into other software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (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 THE
+ * AUTHORS OR COPYRIGHT HOLDERS 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 <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/major.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/poll.h>
+#include <linux/irq.h>
+#include <linux/init.h>
+#define XEN_EVTCHN_MASK_OPS
+#include <asm-xen/evtchn.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+#include <linux/devfs_fs_kernel.h>
+#define OLD_DEVFS
+#else
+#include <linux/gfp.h>
+#endif
+
+#ifdef OLD_DEVFS
+/* NB. This must be shared amongst drivers if more things go in /dev/xen */
+static devfs_handle_t xen_dev_dir;
+#endif
+
+struct per_user_data {
+ /* Notification ring, accessed via /dev/xen/evtchn. */
+# define EVTCHN_RING_SIZE 2048 /* 2048 16-bit entries */
+# define EVTCHN_RING_MASK(_i) ((_i)&(EVTCHN_RING_SIZE-1))
+ u16 *ring;
+ unsigned int ring_cons, ring_prod, ring_overflow;
+
+ /* Processes wait on this queue when ring is empty. */
+ wait_queue_head_t evtchn_wait;
+ struct fasync_struct *evtchn_async_queue;
+};
+
+/* Who's bound to each port? */
+static struct per_user_data *port_user[NR_EVENT_CHANNELS];
+static spinlock_t port_user_lock;
+
+void evtchn_device_upcall(int port)
+{
+ struct per_user_data *u;
+
+ spin_lock(&port_user_lock);
+
+ mask_evtchn(port);
+ clear_evtchn(port);
+
+ if ( (u = port_user[port]) != NULL )
+ {
+ if ( (u->ring_prod - u->ring_cons) < EVTCHN_RING_SIZE )
+ {
+ u->ring[EVTCHN_RING_MASK(u->ring_prod)] = (u16)port;
+ if ( u->ring_cons == u->ring_prod++ )
+ {
+ wake_up_interruptible(&u->evtchn_wait);
+ kill_fasync(&u->evtchn_async_queue, SIGIO, POLL_IN);
+ }
+ }
+ else
+ {
+ u->ring_overflow = 1;
+ }
+ }
+
+ spin_unlock(&port_user_lock);
+}
+
+static ssize_t evtchn_read(struct file *file, char *buf,
+ size_t count, loff_t *ppos)
+{
+ int rc;
+ unsigned int c, p, bytes1 = 0, bytes2 = 0;
+ DECLARE_WAITQUEUE(wait, current);
+ struct per_user_data *u = file->private_data;
+
+ add_wait_queue(&u->evtchn_wait, &wait);
+
+ count &= ~1; /* even number of bytes */
+
+ if ( count == 0 )
+ {
+ rc = 0;
+ goto out;
+ }
+
+ if ( count > PAGE_SIZE )
+ count = PAGE_SIZE;
+
+ for ( ; ; )
+ {
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ if ( (c = u->ring_cons) != (p = u->ring_prod) )
+ break;
+
+ if ( u->ring_overflow )
+ {
+ rc = -EFBIG;
+ goto out;
+ }
+
+ if ( file->f_flags & O_NONBLOCK )
+ {
+ rc = -EAGAIN;
+ goto out;
+ }
+
+ if ( signal_pending(current) )
+ {
+ rc = -ERESTARTSYS;
+ goto out;
+ }
+
+ schedule();
+ }
+
+ /* Byte lengths of two chunks. Chunk split (if any) is at ring wrap. */
+ if ( ((c ^ p) & EVTCHN_RING_SIZE) != 0 )
+ {
+ bytes1 = (EVTCHN_RING_SIZE - EVTCHN_RING_MASK(c)) * sizeof(u16);
+ bytes2 = EVTCHN_RING_MASK(p) * sizeof(u16);
+ }
+ else
+ {
+ bytes1 = (p - c) * sizeof(u16);
+ bytes2 = 0;
+ }
+
+ /* Truncate chunks according to caller's maximum byte count. */
+ if ( bytes1 > count )
+ {
+ bytes1 = count;
+ bytes2 = 0;
+ }
+ else if ( (bytes1 + bytes2) > count )
+ {
+ bytes2 = count - bytes1;
+ }
+
+ if ( copy_to_user(buf, &u->ring[EVTCHN_RING_MASK(c)], bytes1) ||
+ ((bytes2 != 0) && copy_to_user(&buf[bytes1], &u->ring[0], bytes2)) )
+ {
+ rc = -EFAULT;
+ goto out;
+ }
+
+ u->ring_cons += (bytes1 + bytes2) / sizeof(u16);
+
+ rc = bytes1 + bytes2;
+
+ out:
+ __set_current_state(TASK_RUNNING);
+ remove_wait_queue(&u->evtchn_wait, &wait);
+ return rc;
+}
+
+static ssize_t evtchn_write(struct file *file, const char *buf,
+ size_t count, loff_t *ppos)
+{
+ int rc, i;
+ u16 *kbuf = (u16 *)__get_free_page(GFP_KERNEL);
+ struct per_user_data *u = file->private_data;
+
+ if ( kbuf == NULL )
+ return -ENOMEM;
+
+ count &= ~1; /* even number of bytes */
+
+ if ( count == 0 )
+ {
+ rc = 0;
+ goto out;
+ }
+
+ if ( count > PAGE_SIZE )
+ count = PAGE_SIZE;
+
+ if ( copy_from_user(kbuf, buf, count) != 0 )
+ {
+ rc = -EFAULT;
+ goto out;
+ }
+
+ spin_lock_irq(&port_user_lock);
+ for ( i = 0; i < (count/2); i++ )
+ if ( (kbuf[i] < NR_EVENT_CHANNELS) && (port_user[kbuf[i]] == u) )
+ unmask_evtchn(kbuf[i]);
+ spin_unlock_irq(&port_user_lock);
+
+ rc = count;
+
+ out:
+ free_page((unsigned long)kbuf);
+ return rc;
+}
+
+static int evtchn_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int rc = 0;
+ struct per_user_data *u = file->private_data;
+
+ spin_lock_irq(&port_user_lock);
+
+ switch ( cmd )
+ {
+ case EVTCHN_RESET:
+ /* Initialise the ring to empty. Clear errors. */
+ u->ring_cons = u->ring_prod = u->ring_overflow = 0;
+ break;
+
+ case EVTCHN_BIND:
+ if ( arg >= NR_EVENT_CHANNELS )
+ {
+ rc = -EINVAL;
+ }
+ else if ( port_user[arg] != NULL )
+ {
+ rc = -EISCONN;
+ }
+ else
+ {
+ port_user[arg] = u;
+ unmask_evtchn(arg);
+ }
+ break;
+
+ case EVTCHN_UNBIND:
+ if ( arg >= NR_EVENT_CHANNELS )
+ {
+ rc = -EINVAL;
+ }
+ else if ( port_user[arg] != u )
+ {
+ rc = -ENOTCONN;
+ }
+ else
+ {
+ port_user[arg] = NULL;
+ mask_evtchn(arg);
+ }
+ break;
+
+ default:
+ rc = -ENOSYS;
+ break;
+ }
+
+ spin_unlock_irq(&port_user_lock);
+
+ return rc;
+}
+
+static unsigned int evtchn_poll(struct file *file, poll_table *wait)
+{
+ unsigned int mask = POLLOUT | POLLWRNORM;
+ struct per_user_data *u = file->private_data;
+
+ poll_wait(file, &u->evtchn_wait, wait);
+ if ( u->ring_cons != u->ring_prod )
+ mask |= POLLIN | POLLRDNORM;
+ if ( u->ring_overflow )
+ mask = POLLERR;
+ return mask;
+}
+
+static int evtchn_fasync(int fd, struct file *filp, int on)
+{
+ struct per_user_data *u = filp->private_data;
+ return fasync_helper(fd, filp, on, &u->evtchn_async_queue);
+}
+
+static int evtchn_open(struct inode *inode, struct file *filp)
+{
+ struct per_user_data *u;
+
+ if ( (u = kmalloc(sizeof(*u), GFP_KERNEL)) == NULL )
+ return -ENOMEM;
+
+ memset(u, 0, sizeof(*u));
+ init_waitqueue_head(&u->evtchn_wait);
+
+ if ( (u->ring = (u16 *)__get_free_page(GFP_KERNEL)) == NULL )
+ {
+ kfree(u);
+ return -ENOMEM;
+ }
+
+ filp->private_data = u;
+
+ return 0;
+}
+
+static int evtchn_release(struct inode *inode, struct file *filp)
+{
+ int i;
+ struct per_user_data *u = filp->private_data;
+
+ spin_lock_irq(&port_user_lock);
+
+ free_page((unsigned long)u->ring);
+
+ for ( i = 0; i < NR_EVENT_CHANNELS; i++ )
+ {
+ if ( port_user[i] == u )
+ {
+ port_user[i] = NULL;
+ mask_evtchn(i);
+ }
+ }
+
+ spin_unlock_irq(&port_user_lock);
+
+ return 0;
+}
+
+static struct file_operations evtchn_fops = {
+ owner: THIS_MODULE,
+ read: evtchn_read,
+ write: evtchn_write,
+ ioctl: evtchn_ioctl,
+ poll: evtchn_poll,
+ fasync: evtchn_fasync,
+ open: evtchn_open,
+ release: evtchn_release
+};
+
+static struct miscdevice evtchn_miscdev = {
+ .minor = EVTCHN_MINOR,
+ .name = "evtchn",
+ .fops = &evtchn_fops,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+ .devfs_name = "misc/evtchn",
+#endif
+};
+
+static int __init evtchn_init(void)
+{
+#ifdef OLD_DEVFS
+ devfs_handle_t symlink_handle;
+ int pos;
+ char link_dest[64];
+#endif
+ int err;
+
+ spin_lock_init(&port_user_lock);
+ memset(port_user, 0, sizeof(port_user));
+
+ /* (DEVFS) create '/dev/misc/evtchn'. */
+ err = misc_register(&evtchn_miscdev);
+ if ( err != 0 )
+ {
+ printk(KERN_ALERT "Could not register /dev/misc/evtchn\n");
+ return err;
+ }
+
+#ifdef OLD_DEVFS
+ /* (DEVFS) create directory '/dev/xen'. */
+ xen_dev_dir = devfs_mk_dir(NULL, "xen", NULL);
+
+ /* (DEVFS) &link_dest[pos] == '../misc/evtchn'. */
+ pos = devfs_generate_path(evtchn_miscdev.devfs_handle,
+ &link_dest[3],
+ sizeof(link_dest) - 3);
+ if ( pos >= 0 )
+ strncpy(&link_dest[pos], "../", 3);
+
+ /* (DEVFS) symlink '/dev/xen/evtchn' -> '../misc/evtchn'. */
+ (void)devfs_mk_symlink(xen_dev_dir,
+ "evtchn",
+ DEVFS_FL_DEFAULT,
+ &link_dest[pos],
+ &symlink_handle,
+ NULL);
+
+ /* (DEVFS) automatically destroy the symlink with its destination. */
+ devfs_auto_unregister(evtchn_miscdev.devfs_handle, symlink_handle);
+#endif
+
+ printk("Event-channel device installed.\n");
+
+ return 0;
+}
+
+static void evtchn_cleanup(void)
+{
+ misc_deregister(&evtchn_miscdev);
+}
+
+module_init(evtchn_init);
+module_exit(evtchn_cleanup);
--- /dev/null
+
+obj-y := netback.o control.o interface.o
--- /dev/null
+/******************************************************************************
+ * arch/xen/drivers/netif/backend/common.h
+ */
+
+#ifndef __NETIF__BACKEND__COMMON_H__
+#define __NETIF__BACKEND__COMMON_H__
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/ip.h>
+#include <linux/in.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <asm-xen/ctrl_if.h>
+#include <asm-xen/xen-public/io/netif.h>
+#include <asm/io.h>
+#include <asm/pgalloc.h>
+
+#if 0
+#define ASSERT(_p) \
+ if ( !(_p) ) { printk("Assertion '%s' failed, line %d, file %s", #_p , \
+ __LINE__, __FILE__); *(int*)0=0; }
+#define DPRINTK(_f, _a...) printk(KERN_ALERT "(file=%s, line=%d) " _f, \
+ __FILE__ , __LINE__ , ## _a )
+#else
+#define ASSERT(_p) ((void)0)
+#define DPRINTK(_f, _a...) ((void)0)
+#endif
+
+typedef struct netif_st {
+ /* Unique identifier for this interface. */
+ domid_t domid;
+ unsigned int handle;
+
+ u8 fe_dev_addr[6];
+
+ /* Physical parameters of the comms window. */
+ unsigned long tx_shmem_frame;
+ unsigned long rx_shmem_frame;
+ unsigned int evtchn;
+ int irq;
+
+ /* The shared rings and indexes. */
+ netif_tx_interface_t *tx;
+ netif_rx_interface_t *rx;
+
+ /* Private indexes into shared ring. */
+ NETIF_RING_IDX rx_req_cons;
+ NETIF_RING_IDX rx_resp_prod; /* private version of shared variable */
+ NETIF_RING_IDX tx_req_cons;
+ NETIF_RING_IDX tx_resp_prod; /* private version of shared variable */
+
+ /* Transmit shaping: allow 'credit_bytes' every 'credit_usec'. */
+ unsigned long credit_bytes;
+ unsigned long credit_usec;
+ unsigned long remaining_credit;
+ struct timer_list credit_timeout;
+
+ /* Miscellaneous private stuff. */
+ enum { DISCONNECTED, DISCONNECTING, CONNECTED } status;
+ int active;
+ /*
+ * DISCONNECT response is deferred until pending requests are ack'ed.
+ * We therefore need to store the id from the original request.
+ */
+ u8 disconnect_rspid;
+ struct netif_st *hash_next;
+ struct list_head list; /* scheduling list */
+ atomic_t refcnt;
+ struct net_device *dev;
+ struct net_device_stats stats;
+
+ struct work_struct work;
+} netif_t;
+
+void netif_create(netif_be_create_t *create);
+void netif_destroy(netif_be_destroy_t *destroy);
+void netif_creditlimit(netif_be_creditlimit_t *creditlimit);
+void netif_connect(netif_be_connect_t *connect);
+int netif_disconnect(netif_be_disconnect_t *disconnect, u8 rsp_id);
+void netif_disconnect_complete(netif_t *netif);
+netif_t *netif_find_by_handle(domid_t domid, unsigned int handle);
+#define netif_get(_b) (atomic_inc(&(_b)->refcnt))
+#define netif_put(_b) \
+ do { \
+ if ( atomic_dec_and_test(&(_b)->refcnt) ) \
+ netif_disconnect_complete(_b); \
+ } while (0)
+
+void netif_interface_init(void);
+void netif_ctrlif_init(void);
+
+void netif_schedule_work(netif_t *netif);
+void netif_deschedule_work(netif_t *netif);
+
+int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev);
+struct net_device_stats *netif_be_get_stats(struct net_device *dev);
+irqreturn_t netif_be_int(int irq, void *dev_id, struct pt_regs *regs);
+
+#endif /* __NETIF__BACKEND__COMMON_H__ */
--- /dev/null
+/******************************************************************************
+ * arch/xen/drivers/netif/backend/interface.c
+ *
+ * Network-device interface management.
+ *
+ * Copyright (c) 2004-2005, Keir Fraser
+ */
+
+#include "common.h"
+#include <linux/rtnetlink.h>
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+#endif
+
+#define NETIF_HASHSZ 1024
+#define NETIF_HASH(_d,_h) (((int)(_d)^(int)(_h))&(NETIF_HASHSZ-1))
+
+static netif_t *netif_hash[NETIF_HASHSZ];
+
+netif_t *netif_find_by_handle(domid_t domid, unsigned int handle)
+{
+ netif_t *netif = netif_hash[NETIF_HASH(domid, handle)];
+ while ( (netif != NULL) &&
+ ((netif->domid != domid) || (netif->handle != handle)) )
+ netif = netif->hash_next;
+ return netif;
+}
+
+static void __netif_up(netif_t *netif)
+{
+ struct net_device *dev = netif->dev;
+ spin_lock_bh(&dev->xmit_lock);
+ netif->active = 1;
+ spin_unlock_bh(&dev->xmit_lock);
+ (void)request_irq(netif->irq, netif_be_int, 0, dev->name, netif);
+ netif_schedule_work(netif);
+}
+
+static void __netif_down(netif_t *netif)
+{
+ struct net_device *dev = netif->dev;
+ spin_lock_bh(&dev->xmit_lock);
+ netif->active = 0;
+ spin_unlock_bh(&dev->xmit_lock);
+ free_irq(netif->irq, netif);
+ netif_deschedule_work(netif);
+}
+
+static int net_open(struct net_device *dev)
+{
+ netif_t *netif = netdev_priv(dev);
+ if ( netif->status == CONNECTED )
+ __netif_up(netif);
+ netif_start_queue(dev);
+ return 0;
+}
+
+static int net_close(struct net_device *dev)
+{
+ netif_t *netif = netdev_priv(dev);
+ netif_stop_queue(dev);
+ if ( netif->status == CONNECTED )
+ __netif_down(netif);
+ return 0;
+}
+
+static void __netif_disconnect_complete(void *arg)
+{
+ netif_t *netif = (netif_t *)arg;
+ ctrl_msg_t cmsg;
+ netif_be_disconnect_t disc;
+
+ /*
+ * These can't be done in netif_disconnect() because at that point there
+ * may be outstanding requests in the network stack whose asynchronous
+ * responses must still be notified to the remote driver.
+ */
+ unbind_evtchn_from_irq(netif->evtchn);
+ vfree(netif->tx); /* Frees netif->rx as well. */
+
+ /* Construct the deferred response message. */
+ cmsg.type = CMSG_NETIF_BE;
+ cmsg.subtype = CMSG_NETIF_BE_DISCONNECT;
+ cmsg.id = netif->disconnect_rspid;
+ cmsg.length = sizeof(netif_be_disconnect_t);
+ disc.domid = netif->domid;
+ disc.netif_handle = netif->handle;
+ disc.status = NETIF_BE_STATUS_OKAY;
+ memcpy(cmsg.msg, &disc, sizeof(disc));
+
+ /*
+ * Make sure message is constructed /before/ status change, because
+ * after the status change the 'netif' structure could be deallocated at
+ * any time. Also make sure we send the response /after/ status change,
+ * as otherwise a subsequent CONNECT request could spuriously fail if
+ * another CPU doesn't see the status change yet.
+ */
+ mb();
+ if ( netif->status != DISCONNECTING )
+ BUG();
+ netif->status = DISCONNECTED;
+ mb();
+
+ /* Send the successful response. */
+ ctrl_if_send_response(&cmsg);
+}
+
+void netif_disconnect_complete(netif_t *netif)
+{
+ INIT_WORK(&netif->work, __netif_disconnect_complete, (void *)netif);
+ schedule_work(&netif->work);
+}
+
+void netif_create(netif_be_create_t *create)
+{
+ int err = 0;
+ domid_t domid = create->domid;
+ unsigned int handle = create->netif_handle;
+ struct net_device *dev;
+ netif_t **pnetif, *netif;
+ char name[IFNAMSIZ] = {};
+
+ snprintf(name, IFNAMSIZ - 1, "vif%u.%u", domid, handle);
+ dev = alloc_netdev(sizeof(netif_t), name, ether_setup);
+ if ( dev == NULL )
+ {
+ DPRINTK("Could not create netif: out of memory\n");
+ create->status = NETIF_BE_STATUS_OUT_OF_MEMORY;
+ return;
+ }
+
+ netif = netdev_priv(dev);
+ memset(netif, 0, sizeof(*netif));
+ netif->domid = domid;
+ netif->handle = handle;
+ netif->status = DISCONNECTED;
+ atomic_set(&netif->refcnt, 0);
+ netif->dev = dev;
+
+ netif->credit_bytes = netif->remaining_credit = ~0UL;
+ netif->credit_usec = 0UL;
+ init_timer(&netif->credit_timeout);
+
+ pnetif = &netif_hash[NETIF_HASH(domid, handle)];
+ while ( *pnetif != NULL )
+ {
+ if ( ((*pnetif)->domid == domid) && ((*pnetif)->handle == handle) )
+ {
+ DPRINTK("Could not create netif: already exists\n");
+ create->status = NETIF_BE_STATUS_INTERFACE_EXISTS;
+ free_netdev(dev);
+ return;
+ }
+ pnetif = &(*pnetif)->hash_next;
+ }
+
+ dev->hard_start_xmit = netif_be_start_xmit;
+ dev->get_stats = netif_be_get_stats;
+ dev->open = net_open;
+ dev->stop = net_close;
+
+ /* Disable queuing. */
+ dev->tx_queue_len = 0;
+
+ if ( (create->be_mac[0] == 0) && (create->be_mac[1] == 0) &&
+ (create->be_mac[2] == 0) && (create->be_mac[3] == 0) &&
+ (create->be_mac[4] == 0) && (create->be_mac[5] == 0) )
+ {
+ /*
+ * Initialise a dummy MAC address. We choose the numerically largest
+ * non-broadcast address to prevent the address getting stolen by an
+ * Ethernet bridge for STP purposes. (FE:FF:FF:FF:FF:FF)
+ */
+ memset(dev->dev_addr, 0xFF, ETH_ALEN);
+ dev->dev_addr[0] &= ~0x01;
+ }
+ else
+ {
+ memcpy(dev->dev_addr, create->be_mac, ETH_ALEN);
+ }
+
+ memcpy(netif->fe_dev_addr, create->mac, ETH_ALEN);
+
+ rtnl_lock();
+ err = register_netdevice(dev);
+ rtnl_unlock();
+
+ if ( err != 0 )
+ {
+ DPRINTK("Could not register new net device %s: err=%d\n",
+ dev->name, err);
+ create->status = NETIF_BE_STATUS_OUT_OF_MEMORY;
+ free_netdev(dev);
+ return;
+ }
+
+ netif->hash_next = *pnetif;
+ *pnetif = netif;
+
+ DPRINTK("Successfully created netif\n");
+ create->status = NETIF_BE_STATUS_OKAY;
+}
+
+void netif_destroy(netif_be_destroy_t *destroy)
+{
+ domid_t domid = destroy->domid;
+ unsigned int handle = destroy->netif_handle;
+ netif_t **pnetif, *netif;
+
+ pnetif = &netif_hash[NETIF_HASH(domid, handle)];
+ while ( (netif = *pnetif) != NULL )
+ {
+ if ( (netif->domid == domid) && (netif->handle == handle) )
+ {
+ if ( netif->status != DISCONNECTED )
+ goto still_connected;
+ goto destroy;
+ }
+ pnetif = &netif->hash_next;
+ }
+
+ destroy->status = NETIF_BE_STATUS_INTERFACE_NOT_FOUND;
+ return;
+
+ still_connected:
+ destroy->status = NETIF_BE_STATUS_INTERFACE_CONNECTED;
+ return;
+
+ destroy:
+ *pnetif = netif->hash_next;
+ unregister_netdev(netif->dev);
+ free_netdev(netif->dev);
+ destroy->status = NETIF_BE_STATUS_OKAY;
+}
+
+void netif_creditlimit(netif_be_creditlimit_t *creditlimit)
+{
+ domid_t domid = creditlimit->domid;
+ unsigned int handle = creditlimit->netif_handle;
+ netif_t *netif;
+
+ netif = netif_find_by_handle(domid, handle);
+ if ( unlikely(netif == NULL) )
+ {
+ DPRINTK("netif_creditlimit attempted for non-existent netif"
+ " (%u,%u)\n", creditlimit->domid, creditlimit->netif_handle);
+ creditlimit->status = NETIF_BE_STATUS_INTERFACE_NOT_FOUND;
+ return;
+ }
+
+ /* Set the credit limit (reset remaining credit to new limit). */
+ netif->credit_bytes = netif->remaining_credit = creditlimit->credit_bytes;
+ netif->credit_usec = creditlimit->period_usec;
+
+ if ( netif->status == CONNECTED )
+ {
+ /*
+ * Schedule work so that any packets waiting under previous credit
+ * limit are dealt with (acts like a replenishment point).
+ */
+ netif->credit_timeout.expires = jiffies;
+ netif_schedule_work(netif);
+ }
+
+ creditlimit->status = NETIF_BE_STATUS_OKAY;
+}
+
+void netif_connect(netif_be_connect_t *connect)
+{
+ domid_t domid = connect->domid;
+ unsigned int handle = connect->netif_handle;
+ unsigned int evtchn = connect->evtchn;
+ unsigned long tx_shmem_frame = connect->tx_shmem_frame;
+ unsigned long rx_shmem_frame = connect->rx_shmem_frame;
+ struct vm_struct *vma;
+ pgprot_t prot;
+ int error;
+ netif_t *netif;
+
+ netif = netif_find_by_handle(domid, handle);
+ if ( unlikely(netif == NULL) )
+ {
+ DPRINTK("netif_connect attempted for non-existent netif (%u,%u)\n",
+ connect->domid, connect->netif_handle);
+ connect->status = NETIF_BE_STATUS_INTERFACE_NOT_FOUND;
+ return;
+ }
+
+ if ( netif->status != DISCONNECTED )
+ {
+ connect->status = NETIF_BE_STATUS_INTERFACE_CONNECTED;
+ return;
+ }
+
+ if ( (vma = get_vm_area(2*PAGE_SIZE, VM_IOREMAP)) == NULL )
+ {
+ connect->status = NETIF_BE_STATUS_OUT_OF_MEMORY;
+ return;
+ }
+
+ prot = __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED);
+ error = direct_remap_area_pages(&init_mm,
+ VMALLOC_VMADDR(vma->addr),
+ tx_shmem_frame<<PAGE_SHIFT, PAGE_SIZE,
+ prot, domid);
+ error |= direct_remap_area_pages(&init_mm,
+ VMALLOC_VMADDR(vma->addr) + PAGE_SIZE,
+ rx_shmem_frame<<PAGE_SHIFT, PAGE_SIZE,
+ prot, domid);
+ if ( error != 0 )
+ {
+ if ( error == -ENOMEM )
+ connect->status = NETIF_BE_STATUS_OUT_OF_MEMORY;
+ else if ( error == -EFAULT )
+ connect->status = NETIF_BE_STATUS_MAPPING_ERROR;
+ else
+ connect->status = NETIF_BE_STATUS_ERROR;
+ vfree(vma->addr);
+ return;
+ }
+
+ netif->evtchn = evtchn;
+ netif->irq = bind_evtchn_to_irq(evtchn);
+ netif->tx_shmem_frame = tx_shmem_frame;
+ netif->rx_shmem_frame = rx_shmem_frame;
+ netif->tx =
+ (netif_tx_interface_t *)vma->addr;
+ netif->rx =
+ (netif_rx_interface_t *)((char *)vma->addr + PAGE_SIZE);
+ netif->tx->resp_prod = netif->rx->resp_prod = 0;
+ netif_get(netif);
+ wmb(); /* Other CPUs see new state before interface is started. */
+
+ rtnl_lock();
+ netif->status = CONNECTED;
+ wmb();
+ if ( netif_running(netif->dev) )
+ __netif_up(netif);
+ rtnl_unlock();
+
+ connect->status = NETIF_BE_STATUS_OKAY;
+}
+
+int netif_disconnect(netif_be_disconnect_t *disconnect, u8 rsp_id)
+{
+ domid_t domid = disconnect->domid;
+ unsigned int handle = disconnect->netif_handle;
+ netif_t *netif;
+
+ netif = netif_find_by_handle(domid, handle);
+ if ( unlikely(netif == NULL) )
+ {
+ DPRINTK("netif_disconnect attempted for non-existent netif"
+ " (%u,%u)\n", disconnect->domid, disconnect->netif_handle);
+ disconnect->status = NETIF_BE_STATUS_INTERFACE_NOT_FOUND;
+ return 1; /* Caller will send response error message. */
+ }
+
+ if ( netif->status == CONNECTED )
+ {
+ rtnl_lock();
+ netif->status = DISCONNECTING;
+ netif->disconnect_rspid = rsp_id;
+ wmb();
+ if ( netif_running(netif->dev) )
+ __netif_down(netif);
+ rtnl_unlock();
+ netif_put(netif);
+ return 0; /* Caller should not send response message. */
+ }
+
+ disconnect->status = NETIF_BE_STATUS_OKAY;
+ return 1;
+}
+
+void netif_interface_init(void)
+{
+ memset(netif_hash, 0, sizeof(netif_hash));
+}
--- /dev/null
+/******************************************************************************
+ * drivers/xen/netback/netback.c
+ *
+ * Back-end of the driver for virtual network devices. This portion of the
+ * driver exports a 'unified' network-device interface that can be accessed
+ * by any operating system that implements a compatible front end. A
+ * reference front-end implementation can be found in:
+ * drivers/xen/netfront/netfront.c
+ *
+ * Copyright (c) 2002-2005, K A Fraser
+ */
+
+#include "common.h"
+#include <asm-xen/balloon.h>
+#include <asm-xen/evtchn.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+#include <linux/delay.h>
+#endif
+
+static void netif_idx_release(u16 pending_idx);
+static void netif_page_release(struct page *page);
+static void make_tx_response(netif_t *netif,
+ u16 id,
+ s8 st);
+static int make_rx_response(netif_t *netif,
+ u16 id,
+ s8 st,
+ memory_t addr,
+ u16 size);
+
+static void net_tx_action(unsigned long unused);
+static DECLARE_TASKLET(net_tx_tasklet, net_tx_action, 0);
+
+static void net_rx_action(unsigned long unused);
+static DECLARE_TASKLET(net_rx_tasklet, net_rx_action, 0);
+
+static struct timer_list net_timer;
+
+static struct sk_buff_head rx_queue;
+static multicall_entry_t rx_mcl[NETIF_RX_RING_SIZE*2+1];
+static mmu_update_t rx_mmu[NETIF_RX_RING_SIZE];
+static struct mmuext_op rx_mmuext[NETIF_RX_RING_SIZE];
+static unsigned char rx_notify[NR_EVENT_CHANNELS];
+
+/* Don't currently gate addition of an interface to the tx scheduling list. */
+#define tx_work_exists(_if) (1)
+
+#define MAX_PENDING_REQS 256
+static unsigned long mmap_vstart;
+#define MMAP_VADDR(_req) (mmap_vstart + ((_req) * PAGE_SIZE))
+
+#define PKT_PROT_LEN 64
+
+static struct {
+ netif_tx_request_t req;
+ netif_t *netif;
+} pending_tx_info[MAX_PENDING_REQS];
+static u16 pending_ring[MAX_PENDING_REQS];
+typedef unsigned int PEND_RING_IDX;
+#define MASK_PEND_IDX(_i) ((_i)&(MAX_PENDING_REQS-1))
+static PEND_RING_IDX pending_prod, pending_cons;
+#define NR_PENDING_REQS (MAX_PENDING_REQS - pending_prod + pending_cons)
+
+/* Freed TX SKBs get batched on this ring before return to pending_ring. */
+static u16 dealloc_ring[MAX_PENDING_REQS];
+static PEND_RING_IDX dealloc_prod, dealloc_cons;
+
+static struct sk_buff_head tx_queue;
+static multicall_entry_t tx_mcl[MAX_PENDING_REQS];
+
+static struct list_head net_schedule_list;
+static spinlock_t net_schedule_list_lock;
+
+#define MAX_MFN_ALLOC 64
+static unsigned long mfn_list[MAX_MFN_ALLOC];
+static unsigned int alloc_index = 0;
+static spinlock_t mfn_lock = SPIN_LOCK_UNLOCKED;
+
+static unsigned long alloc_mfn(void)
+{
+ unsigned long mfn = 0, flags;
+ spin_lock_irqsave(&mfn_lock, flags);
+ if ( unlikely(alloc_index == 0) )
+ alloc_index = HYPERVISOR_dom_mem_op(
+ MEMOP_increase_reservation, mfn_list, MAX_MFN_ALLOC, 0);
+ if ( alloc_index != 0 )
+ mfn = mfn_list[--alloc_index];
+ spin_unlock_irqrestore(&mfn_lock, flags);
+ return mfn;
+}
+
+static void free_mfn(unsigned long mfn)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&mfn_lock, flags);
+ if ( alloc_index != MAX_MFN_ALLOC )
+ mfn_list[alloc_index++] = mfn;
+ else if ( HYPERVISOR_dom_mem_op(MEMOP_decrease_reservation,
+ &mfn, 1, 0) != 1 )
+ BUG();
+ spin_unlock_irqrestore(&mfn_lock, flags);
+}
+
+static inline void maybe_schedule_tx_action(void)
+{
+ smp_mb();
+ if ( (NR_PENDING_REQS < (MAX_PENDING_REQS/2)) &&
+ !list_empty(&net_schedule_list) )
+ tasklet_schedule(&net_tx_tasklet);
+}
+
+/*
+ * A gross way of confirming the origin of an skb data page. The slab
+ * allocator abuses a field in the page struct to cache the kmem_cache_t ptr.
+ */
+static inline int is_xen_skb(struct sk_buff *skb)
+{
+ extern kmem_cache_t *skbuff_cachep;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+ kmem_cache_t *cp = (kmem_cache_t *)virt_to_page(skb->head)->lru.next;
+#else
+ kmem_cache_t *cp = (kmem_cache_t *)virt_to_page(skb->head)->list.next;
+#endif
+ return (cp == skbuff_cachep);
+}
+
+int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ netif_t *netif = netdev_priv(dev);
+
+ ASSERT(skb->dev == dev);
+
+ /* Drop the packet if the target domain has no receive buffers. */
+ if ( !netif->active ||
+ (netif->rx_req_cons == netif->rx->req_prod) ||
+ ((netif->rx_req_cons-netif->rx_resp_prod) == NETIF_RX_RING_SIZE) )
+ goto drop;
+
+ /*
+ * We do not copy the packet unless:
+ * 1. The data is shared; or
+ * 2. The data is not allocated from our special cache.
+ * NB. We also couldn't cope with fragmented packets, but we won't get
+ * any because we not advertise the NETIF_F_SG feature.
+ */
+ if ( skb_shared(skb) || skb_cloned(skb) || !is_xen_skb(skb) )
+ {
+ int hlen = skb->data - skb->head;
+ struct sk_buff *nskb = dev_alloc_skb(hlen + skb->len);
+ if ( unlikely(nskb == NULL) )
+ goto drop;
+ skb_reserve(nskb, hlen);
+ __skb_put(nskb, skb->len);
+ (void)skb_copy_bits(skb, -hlen, nskb->data - hlen, skb->len + hlen);
+ nskb->dev = skb->dev;
+ dev_kfree_skb(skb);
+ skb = nskb;
+ }
+
+ netif->rx_req_cons++;
+ netif_get(netif);
+
+ skb_queue_tail(&rx_queue, skb);
+ tasklet_schedule(&net_rx_tasklet);
+
+ return 0;
+
+ drop:
+ netif->stats.tx_dropped++;
+ dev_kfree_skb(skb);
+ return 0;
+}
+
+#if 0
+static void xen_network_done_notify(void)
+{
+ static struct net_device *eth0_dev = NULL;
+ if ( unlikely(eth0_dev == NULL) )
+ eth0_dev = __dev_get_by_name("eth0");
+ netif_rx_schedule(eth0_dev);
+}
+/*
+ * Add following to poll() function in NAPI driver (Tigon3 is example):
+ * if ( xen_network_done() )
+ * tg3_enable_ints(tp);
+ */
+int xen_network_done(void)
+{
+ return skb_queue_empty(&rx_queue);
+}
+#endif
+
+static void net_rx_action(unsigned long unused)
+{
+ netif_t *netif;
+ s8 status;
+ u16 size, id, evtchn;
+ multicall_entry_t *mcl;
+ mmu_update_t *mmu;
+ struct mmuext_op *mmuext;
+ unsigned long vdata, mdata, new_mfn;
+ struct sk_buff_head rxq;
+ struct sk_buff *skb;
+ u16 notify_list[NETIF_RX_RING_SIZE];
+ int notify_nr = 0;
+
+ skb_queue_head_init(&rxq);
+
+ mcl = rx_mcl;
+ mmu = rx_mmu;
+ mmuext = rx_mmuext;
+ while ( (skb = skb_dequeue(&rx_queue)) != NULL )
+ {
+ netif = netdev_priv(skb->dev);
+ vdata = (unsigned long)skb->data;
+ mdata = virt_to_machine(vdata);
+
+ /* Memory squeeze? Back off for an arbitrary while. */
+ if ( (new_mfn = alloc_mfn()) == 0 )
+ {
+ if ( net_ratelimit() )
+ printk(KERN_WARNING "Memory squeeze in netback driver.\n");
+ mod_timer(&net_timer, jiffies + HZ);
+ skb_queue_head(&rx_queue, skb);
+ break;
+ }
+
+ /*
+ * Set the new P2M table entry before reassigning the old data page.
+ * Heed the comment in pgtable-2level.h:pte_page(). :-)
+ */
+ phys_to_machine_mapping[__pa(skb->data) >> PAGE_SHIFT] = new_mfn;
+
+ mcl->op = __HYPERVISOR_update_va_mapping;
+ mcl->args[0] = vdata;
+ mcl->args[1] = (new_mfn << PAGE_SHIFT) | __PAGE_KERNEL;
+ mcl->args[2] = 0;
+ mcl++;
+
+ mcl->op = __HYPERVISOR_mmuext_op;
+ mcl->args[0] = (unsigned long)mmuext;
+ mcl->args[1] = 1;
+ mcl->args[2] = 0;
+ mcl->args[3] = netif->domid;
+ mcl++;
+
+ mmuext->cmd = MMUEXT_REASSIGN_PAGE;
+ mmuext->mfn = mdata >> PAGE_SHIFT;
+ mmuext++;
+
+ mmu->ptr = (new_mfn << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE;
+ mmu->val = __pa(vdata) >> PAGE_SHIFT;
+ mmu++;
+
+ __skb_queue_tail(&rxq, skb);
+
+ /* Filled the batch queue? */
+ if ( (mcl - rx_mcl) == ARRAY_SIZE(rx_mcl) )
+ break;
+ }
+
+ if ( mcl == rx_mcl )
+ return;
+
+ mcl->op = __HYPERVISOR_mmu_update;
+ mcl->args[0] = (unsigned long)rx_mmu;
+ mcl->args[1] = mmu - rx_mmu;
+ mcl->args[2] = 0;
+ mcl->args[3] = DOMID_SELF;
+ mcl++;
+
+ mcl[-3].args[2] = UVMF_TLB_FLUSH|UVMF_ALL;
+ if ( unlikely(HYPERVISOR_multicall(rx_mcl, mcl - rx_mcl) != 0) )
+ BUG();
+
+ mcl = rx_mcl;
+ mmuext = rx_mmuext;
+ while ( (skb = __skb_dequeue(&rxq)) != NULL )
+ {
+ netif = netdev_priv(skb->dev);
+ size = skb->tail - skb->data;
+
+ /* Rederive the machine addresses. */
+ new_mfn = mcl[0].args[1] >> PAGE_SHIFT;
+ mdata = ((mmuext[0].mfn << PAGE_SHIFT) |
+ ((unsigned long)skb->data & ~PAGE_MASK));
+
+ atomic_set(&(skb_shinfo(skb)->dataref), 1);
+ skb_shinfo(skb)->nr_frags = 0;
+ skb_shinfo(skb)->frag_list = NULL;
+
+ netif->stats.tx_bytes += size;
+ netif->stats.tx_packets++;
+
+ /* The update_va_mapping() must not fail. */
+ if ( unlikely(mcl[0].args[5] != 0) )
+ BUG();
+
+ /* Check the reassignment error code. */
+ status = NETIF_RSP_OKAY;
+ if ( unlikely(mcl[1].args[5] != 0) )
+ {
+ DPRINTK("Failed MMU update transferring to DOM%u\n", netif->domid);
+ free_mfn(mdata >> PAGE_SHIFT);
+ status = NETIF_RSP_ERROR;
+ }
+
+ evtchn = netif->evtchn;
+ id = netif->rx->ring[MASK_NETIF_RX_IDX(netif->rx_resp_prod)].req.id;
+ if ( make_rx_response(netif, id, status, mdata, size) &&
+ (rx_notify[evtchn] == 0) )
+ {
+ rx_notify[evtchn] = 1;
+ notify_list[notify_nr++] = evtchn;
+ }
+
+ netif_put(netif);
+ dev_kfree_skb(skb);
+
+ mcl += 2;
+ mmuext += 1;
+ }
+
+ while ( notify_nr != 0 )
+ {
+ evtchn = notify_list[--notify_nr];
+ rx_notify[evtchn] = 0;
+ notify_via_evtchn(evtchn);
+ }
+
+ /* More work to do? */
+ if ( !skb_queue_empty(&rx_queue) && !timer_pending(&net_timer) )
+ tasklet_schedule(&net_rx_tasklet);
+#if 0
+ else
+ xen_network_done_notify();
+#endif
+}
+
+static void net_alarm(unsigned long unused)
+{
+ tasklet_schedule(&net_rx_tasklet);
+}
+
+struct net_device_stats *netif_be_get_stats(struct net_device *dev)
+{
+ netif_t *netif = netdev_priv(dev);
+ return &netif->stats;
+}
+
+static int __on_net_schedule_list(netif_t *netif)
+{
+ return netif->list.next != NULL;
+}
+
+static void remove_from_net_schedule_list(netif_t *netif)
+{
+ spin_lock_irq(&net_schedule_list_lock);
+ if ( likely(__on_net_schedule_list(netif)) )
+ {
+ list_del(&netif->list);
+ netif->list.next = NULL;
+ netif_put(netif);
+ }
+ spin_unlock_irq(&net_schedule_list_lock);
+}
+
+static void add_to_net_schedule_list_tail(netif_t *netif)
+{
+ if ( __on_net_schedule_list(netif) )
+ return;
+
+ spin_lock_irq(&net_schedule_list_lock);
+ if ( !__on_net_schedule_list(netif) && netif->active )
+ {
+ list_add_tail(&netif->list, &net_schedule_list);
+ netif_get(netif);
+ }
+ spin_unlock_irq(&net_schedule_list_lock);
+}
+
+void netif_schedule_work(netif_t *netif)
+{
+ if ( (netif->tx_req_cons != netif->tx->req_prod) &&
+ ((netif->tx_req_cons-netif->tx_resp_prod) != NETIF_TX_RING_SIZE) )
+ {
+ add_to_net_schedule_list_tail(netif);
+ maybe_schedule_tx_action();
+ }
+}
+
+void netif_deschedule_work(netif_t *netif)
+{
+ remove_from_net_schedule_list(netif);
+}
+
+
+static void tx_credit_callback(unsigned long data)
+{
+ netif_t *netif = (netif_t *)data;
+ netif->remaining_credit = netif->credit_bytes;
+ netif_schedule_work(netif);
+}
+
+static void net_tx_action(unsigned long unused)
+{
+ struct list_head *ent;
+ struct sk_buff *skb;
+ netif_t *netif;
+ netif_tx_request_t txreq;
+ u16 pending_idx;
+ NETIF_RING_IDX i;
+ multicall_entry_t *mcl;
+ PEND_RING_IDX dc, dp;
+ unsigned int data_len;
+
+ if ( (dc = dealloc_cons) == (dp = dealloc_prod) )
+ goto skip_dealloc;
+
+ mcl = tx_mcl;
+ while ( dc != dp )
+ {
+ pending_idx = dealloc_ring[MASK_PEND_IDX(dc++)];
+ mcl[0].op = __HYPERVISOR_update_va_mapping;
+ mcl[0].args[0] = MMAP_VADDR(pending_idx);
+ mcl[0].args[1] = 0;
+ mcl[0].args[2] = 0;
+ mcl++;
+ }
+
+ mcl[-1].args[2] = UVMF_TLB_FLUSH|UVMF_ALL;
+ if ( unlikely(HYPERVISOR_multicall(tx_mcl, mcl - tx_mcl) != 0) )
+ BUG();
+
+ mcl = tx_mcl;
+ while ( dealloc_cons != dp )
+ {
+ /* The update_va_mapping() must not fail. */
+ if ( unlikely(mcl[0].args[5] != 0) )
+ BUG();
+
+ pending_idx = dealloc_ring[MASK_PEND_IDX(dealloc_cons++)];
+
+ netif = pending_tx_info[pending_idx].netif;
+
+ make_tx_response(netif, pending_tx_info[pending_idx].req.id,
+ NETIF_RSP_OKAY);
+
+ pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx;
+
+ /*
+ * Scheduling checks must happen after the above response is posted.
+ * This avoids a possible race with a guest OS on another CPU if that
+ * guest is testing against 'resp_prod' when deciding whether to notify
+ * us when it queues additional packets.
+ */
+ mb();
+ if ( (netif->tx_req_cons != netif->tx->req_prod) &&
+ ((netif->tx_req_cons-netif->tx_resp_prod) != NETIF_TX_RING_SIZE) )
+ add_to_net_schedule_list_tail(netif);
+
+ netif_put(netif);
+
+ mcl++;
+ }
+
+ skip_dealloc:
+ mcl = tx_mcl;
+ while ( (NR_PENDING_REQS < MAX_PENDING_REQS) &&
+ !list_empty(&net_schedule_list) )
+ {
+ /* Get a netif from the list with work to do. */
+ ent = net_schedule_list.next;
+ netif = list_entry(ent, netif_t, list);
+ netif_get(netif);
+ remove_from_net_schedule_list(netif);
+
+ /* Work to do? */
+ i = netif->tx_req_cons;
+ if ( (i == netif->tx->req_prod) ||
+ ((i-netif->tx_resp_prod) == NETIF_TX_RING_SIZE) )
+ {
+ netif_put(netif);
+ continue;
+ }
+
+ rmb(); /* Ensure that we see the request before we copy it. */
+ memcpy(&txreq, &netif->tx->ring[MASK_NETIF_TX_IDX(i)].req,
+ sizeof(txreq));
+
+ /* Credit-based scheduling. */
+ if ( txreq.size > netif->remaining_credit )
+ {
+ unsigned long now = jiffies;
+ unsigned long next_credit =
+ netif->credit_timeout.expires +
+ msecs_to_jiffies(netif->credit_usec / 1000);
+
+ /* Timer could already be pending in some rare cases. */
+ if ( timer_pending(&netif->credit_timeout) )
+ break;
+
+ /* Already passed the point at which we can replenish credit? */
+ if ( time_after_eq(now, next_credit) )
+ {
+ netif->credit_timeout.expires = now;
+ netif->remaining_credit = netif->credit_bytes;
+ }
+
+ /* Still too big to send right now? Then set a timer callback. */
+ if ( txreq.size > netif->remaining_credit )
+ {
+ netif->remaining_credit = 0;
+ netif->credit_timeout.expires = next_credit;
+ netif->credit_timeout.data = (unsigned long)netif;
+ netif->credit_timeout.function = tx_credit_callback;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+ add_timer_on(&netif->credit_timeout, smp_processor_id());
+#else
+ add_timer(&netif->credit_timeout);
+#endif
+ break;
+ }
+ }
+ netif->remaining_credit -= txreq.size;
+
+ /*
+ * Why the barrier? It ensures that the frontend sees updated req_cons
+ * before we check for more work to schedule.
+ */
+ netif->tx->req_cons = ++netif->tx_req_cons;
+ mb();
+
+ netif_schedule_work(netif);
+
+ if ( unlikely(txreq.size < ETH_HLEN) ||
+ unlikely(txreq.size > ETH_FRAME_LEN) )
+ {
+ DPRINTK("Bad packet size: %d\n", txreq.size);
+ make_tx_response(netif, txreq.id, NETIF_RSP_ERROR);
+ netif_put(netif);
+ continue;
+ }
+
+ /* No crossing a page boundary as the payload mustn't fragment. */
+ if ( unlikely(((txreq.addr & ~PAGE_MASK) + txreq.size) >= PAGE_SIZE) )
+ {
+ DPRINTK("txreq.addr: %lx, size: %u, end: %lu\n",
+ txreq.addr, txreq.size,
+ (txreq.addr &~PAGE_MASK) + txreq.size);
+ make_tx_response(netif, txreq.id, NETIF_RSP_ERROR);
+ netif_put(netif);
+ continue;
+ }
+
+ pending_idx = pending_ring[MASK_PEND_IDX(pending_cons)];
+
+ data_len = (txreq.size > PKT_PROT_LEN) ? PKT_PROT_LEN : txreq.size;
+
+ if ( unlikely((skb = alloc_skb(data_len+16, GFP_ATOMIC)) == NULL) )
+ {
+ DPRINTK("Can't allocate a skb in start_xmit.\n");
+ make_tx_response(netif, txreq.id, NETIF_RSP_ERROR);
+ netif_put(netif);
+ break;
+ }
+
+ /* Packets passed to netif_rx() must have some headroom. */
+ skb_reserve(skb, 16);
+
+ mcl[0].op = __HYPERVISOR_update_va_mapping_otherdomain;
+ mcl[0].args[0] = MMAP_VADDR(pending_idx);
+ mcl[0].args[1] = (txreq.addr & PAGE_MASK) | __PAGE_KERNEL;
+ mcl[0].args[2] = 0;
+ mcl[0].args[3] = netif->domid;
+ mcl++;
+
+ memcpy(&pending_tx_info[pending_idx].req, &txreq, sizeof(txreq));
+ pending_tx_info[pending_idx].netif = netif;
+ *((u16 *)skb->data) = pending_idx;
+
+ __skb_queue_tail(&tx_queue, skb);
+
+ pending_cons++;
+
+ /* Filled the batch queue? */
+ if ( (mcl - tx_mcl) == ARRAY_SIZE(tx_mcl) )
+ break;
+ }
+
+ if ( mcl == tx_mcl )
+ return;
+
+ if ( unlikely(HYPERVISOR_multicall(tx_mcl, mcl - tx_mcl) != 0) )
+ BUG();
+
+ mcl = tx_mcl;
+ while ( (skb = __skb_dequeue(&tx_queue)) != NULL )
+ {
+ pending_idx = *((u16 *)skb->data);
+ netif = pending_tx_info[pending_idx].netif;
+ memcpy(&txreq, &pending_tx_info[pending_idx].req, sizeof(txreq));
+
+ /* Check the remap error code. */
+ if ( unlikely(mcl[0].args[5] != 0) )
+ {
+ DPRINTK("Bad page frame\n");
+ make_tx_response(netif, txreq.id, NETIF_RSP_ERROR);
+ netif_put(netif);
+ kfree_skb(skb);
+ mcl++;
+ pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx;
+ continue;
+ }
+
+ phys_to_machine_mapping[__pa(MMAP_VADDR(pending_idx)) >> PAGE_SHIFT] =
+ FOREIGN_FRAME(txreq.addr >> PAGE_SHIFT);
+
+ data_len = (txreq.size > PKT_PROT_LEN) ? PKT_PROT_LEN : txreq.size;
+
+ __skb_put(skb, data_len);
+ memcpy(skb->data,
+ (void *)(MMAP_VADDR(pending_idx)|(txreq.addr&~PAGE_MASK)),
+ data_len);
+
+ if ( data_len < txreq.size )
+ {
+ /* Append the packet payload as a fragment. */
+ skb_shinfo(skb)->frags[0].page =
+ virt_to_page(MMAP_VADDR(pending_idx));
+ skb_shinfo(skb)->frags[0].size = txreq.size - data_len;
+ skb_shinfo(skb)->frags[0].page_offset =
+ (txreq.addr + data_len) & ~PAGE_MASK;
+ skb_shinfo(skb)->nr_frags = 1;
+ }
+ else
+ {
+ /* Schedule a response immediately. */
+ netif_idx_release(pending_idx);
+ }
+
+ skb->data_len = txreq.size - data_len;
+ skb->len += skb->data_len;
+
+ skb->dev = netif->dev;
+ skb->protocol = eth_type_trans(skb, skb->dev);
+
+ netif->stats.rx_bytes += txreq.size;
+ netif->stats.rx_packets++;
+
+ netif_rx(skb);
+ netif->dev->last_rx = jiffies;
+
+ mcl++;
+ }
+}
+
+static void netif_idx_release(u16 pending_idx)
+{
+ static spinlock_t _lock = SPIN_LOCK_UNLOCKED;
+ unsigned long flags;
+
+ spin_lock_irqsave(&_lock, flags);
+ dealloc_ring[MASK_PEND_IDX(dealloc_prod++)] = pending_idx;
+ spin_unlock_irqrestore(&_lock, flags);
+
+ tasklet_schedule(&net_tx_tasklet);
+}
+
+static void netif_page_release(struct page *page)
+{
+ u16 pending_idx = page - virt_to_page(mmap_vstart);
+
+ /* Ready for next use. */
+ set_page_count(page, 1);
+
+ netif_idx_release(pending_idx);
+}
+
+irqreturn_t netif_be_int(int irq, void *dev_id, struct pt_regs *regs)
+{
+ netif_t *netif = dev_id;
+ if ( tx_work_exists(netif) )
+ {
+ add_to_net_schedule_list_tail(netif);
+ maybe_schedule_tx_action();
+ }
+ return IRQ_HANDLED;
+}
+
+static void make_tx_response(netif_t *netif,
+ u16 id,
+ s8 st)
+{
+ NETIF_RING_IDX i = netif->tx_resp_prod;
+ netif_tx_response_t *resp;
+
+ resp = &netif->tx->ring[MASK_NETIF_TX_IDX(i)].resp;
+ resp->id = id;
+ resp->status = st;
+ wmb();
+ netif->tx->resp_prod = netif->tx_resp_prod = ++i;
+
+ mb(); /* Update producer before checking event threshold. */
+ if ( i == netif->tx->event )
+ notify_via_evtchn(netif->evtchn);
+}
+
+static int make_rx_response(netif_t *netif,
+ u16 id,
+ s8 st,
+ memory_t addr,
+ u16 size)
+{
+ NETIF_RING_IDX i = netif->rx_resp_prod;
+ netif_rx_response_t *resp;
+
+ resp = &netif->rx->ring[MASK_NETIF_RX_IDX(i)].resp;
+ resp->addr = addr;
+ resp->id = id;
+ resp->status = (s16)size;
+ if ( st < 0 )
+ resp->status = (s16)st;
+ wmb();
+ netif->rx->resp_prod = netif->rx_resp_prod = ++i;
+
+ mb(); /* Update producer before checking event threshold. */
+ return (i == netif->rx->event);
+}
+
+static irqreturn_t netif_be_dbg(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct list_head *ent;
+ netif_t *netif;
+ int i = 0;
+
+ printk(KERN_ALERT "netif_schedule_list:\n");
+ spin_lock_irq(&net_schedule_list_lock);
+
+ list_for_each ( ent, &net_schedule_list )
+ {
+ netif = list_entry(ent, netif_t, list);
+ printk(KERN_ALERT " %d: private(rx_req_cons=%08x rx_resp_prod=%08x\n",
+ i, netif->rx_req_cons, netif->rx_resp_prod);
+ printk(KERN_ALERT " tx_req_cons=%08x tx_resp_prod=%08x)\n",
+ netif->tx_req_cons, netif->tx_resp_prod);
+ printk(KERN_ALERT " shared(rx_req_prod=%08x rx_resp_prod=%08x\n",
+ netif->rx->req_prod, netif->rx->resp_prod);
+ printk(KERN_ALERT " rx_event=%08x tx_req_prod=%08x\n",
+ netif->rx->event, netif->tx->req_prod);
+ printk(KERN_ALERT " tx_resp_prod=%08x, tx_event=%08x)\n",
+ netif->tx->resp_prod, netif->tx->event);
+ i++;
+ }
+
+ spin_unlock_irq(&net_schedule_list_lock);
+ printk(KERN_ALERT " ** End of netif_schedule_list **\n");
+
+ return IRQ_HANDLED;
+}
+
+static int __init netback_init(void)
+{
+ int i;
+ struct page *page;
+
+ if ( !(xen_start_info.flags & SIF_NET_BE_DOMAIN) &&
+ !(xen_start_info.flags & SIF_INITDOMAIN) )
+ return 0;
+
+ printk("Initialising Xen netif backend\n");
+
+ /* We can increase reservation by this much in net_rx_action(). */
+ balloon_update_driver_allowance(NETIF_RX_RING_SIZE);
+
+ skb_queue_head_init(&rx_queue);
+ skb_queue_head_init(&tx_queue);
+
+ init_timer(&net_timer);
+ net_timer.data = 0;
+ net_timer.function = net_alarm;
+
+ netif_interface_init();
+
+ if ( (mmap_vstart = allocate_empty_lowmem_region(MAX_PENDING_REQS)) == 0 )
+ BUG();
+
+ for ( i = 0; i < MAX_PENDING_REQS; i++ )
+ {
+ page = virt_to_page(MMAP_VADDR(i));
+ set_page_count(page, 1);
+ SetPageForeign(page, netif_page_release);
+ }
+
+ pending_cons = 0;
+ pending_prod = MAX_PENDING_REQS;
+ for ( i = 0; i < MAX_PENDING_REQS; i++ )
+ pending_ring[i] = i;
+
+ spin_lock_init(&net_schedule_list_lock);
+ INIT_LIST_HEAD(&net_schedule_list);
+
+ netif_ctrlif_init();
+
+ (void)request_irq(bind_virq_to_irq(VIRQ_DEBUG),
+ netif_be_dbg, SA_SHIRQ,
+ "net-be-dbg", &netif_be_dbg);
+
+ return 0;
+}
+
+static void netback_cleanup(void)
+{
+ BUG();
+}
+
+module_init(netback_init);
+module_exit(netback_cleanup);
--- /dev/null
+
+config XENNET
+ tristate "Xen network driver"
+ depends on NETDEVICES && ARCH_XEN
+ help
+ Network driver for Xen
--- /dev/null
+
+obj-y := netfront.o
--- /dev/null
+/******************************************************************************
+ * Virtual network driver for conversing with remote driver backends.
+ *
+ * Copyright (c) 2002-2004, K A Fraser
+ *
+ * This file may be distributed separately from the Linux kernel, or
+ * incorporated into other software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (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 THE
+ * AUTHORS OR COPYRIGHT HOLDERS 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 <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <net/sock.h>
+#include <net/pkt_sched.h>
+#include <net/arp.h>
+#include <net/route.h>
+#include <asm/io.h>
+#include <asm-xen/evtchn.h>
+#include <asm-xen/ctrl_if.h>
+#include <asm-xen/xen-public/io/netif.h>
+#include <asm-xen/balloon.h>
+#include <asm/page.h>
+
+#ifndef __GFP_NOWARN
+#define __GFP_NOWARN 0
+#endif
+#define alloc_xen_skb(_l) __dev_alloc_skb((_l), GFP_ATOMIC|__GFP_NOWARN)
+
+#define init_skb_shinfo(_skb) \
+ do { \
+ atomic_set(&(skb_shinfo(_skb)->dataref), 1); \
+ skb_shinfo(_skb)->nr_frags = 0; \
+ skb_shinfo(_skb)->frag_list = NULL; \
+ } while (0)
+
+/* Allow headroom on each rx pkt for Ethernet header, alignment padding, ... */
+#define RX_HEADROOM 200
+
+/*
+ * If the backend driver is pipelining transmit requests then we can be very
+ * aggressive in avoiding new-packet notifications -- only need to send a
+ * notification if there are no outstanding unreceived responses.
+ * If the backend may be buffering our transmit buffers for any reason then we
+ * are rather more conservative.
+ */
+#ifdef CONFIG_XEN_NETDEV_FRONTEND_PIPELINED_TRANSMITTER
+#define TX_TEST_IDX resp_prod /* aggressive: any outstanding responses? */
+#else
+#define TX_TEST_IDX req_cons /* conservative: not seen all our requests? */
+#endif
+
+static void network_tx_buf_gc(struct net_device *dev);
+static void network_alloc_rx_buffers(struct net_device *dev);
+
+static unsigned long rx_pfn_array[NETIF_RX_RING_SIZE];
+static multicall_entry_t rx_mcl[NETIF_RX_RING_SIZE+1];
+static mmu_update_t rx_mmu[NETIF_RX_RING_SIZE];
+
+static struct list_head dev_list;
+
+struct net_private
+{
+ struct list_head list;
+ struct net_device *dev;
+
+ struct net_device_stats stats;
+ NETIF_RING_IDX rx_resp_cons, tx_resp_cons;
+ unsigned int tx_full;
+
+ netif_tx_interface_t *tx;
+ netif_rx_interface_t *rx;
+
+ spinlock_t tx_lock;
+ spinlock_t rx_lock;
+
+ unsigned int handle;
+ unsigned int evtchn;
+ unsigned int irq;
+
+ /* What is the status of our connection to the remote backend? */
+#define BEST_CLOSED 0
+#define BEST_DISCONNECTED 1
+#define BEST_CONNECTED 2
+ unsigned int backend_state;
+
+ /* Is this interface open or closed (down or up)? */
+#define UST_CLOSED 0
+#define UST_OPEN 1
+ unsigned int user_state;
+
+ /* Receive-ring batched refills. */
+#define RX_MIN_TARGET 8
+#define RX_MAX_TARGET NETIF_RX_RING_SIZE
+ int rx_target;
+ struct sk_buff_head rx_batch;
+
+ /*
+ * {tx,rx}_skbs store outstanding skbuffs. The first entry in each
+ * array is an index into a chain of free entries.
+ */
+ struct sk_buff *tx_skbs[NETIF_TX_RING_SIZE+1];
+ struct sk_buff *rx_skbs[NETIF_RX_RING_SIZE+1];
+};
+
+/* Access macros for acquiring freeing slots in {tx,rx}_skbs[]. */
+#define ADD_ID_TO_FREELIST(_list, _id) \
+ (_list)[(_id)] = (_list)[0]; \
+ (_list)[0] = (void *)(unsigned long)(_id);
+#define GET_ID_FROM_FREELIST(_list) \
+ ({ unsigned long _id = (unsigned long)(_list)[0]; \
+ (_list)[0] = (_list)[_id]; \
+ (unsigned short)_id; })
+
+static char *status_name[] = {
+ [NETIF_INTERFACE_STATUS_CLOSED] = "closed",
+ [NETIF_INTERFACE_STATUS_DISCONNECTED] = "disconnected",
+ [NETIF_INTERFACE_STATUS_CONNECTED] = "connected",
+ [NETIF_INTERFACE_STATUS_CHANGED] = "changed",
+};
+
+static char *be_state_name[] = {
+ [BEST_CLOSED] = "closed",
+ [BEST_DISCONNECTED] = "disconnected",
+ [BEST_CONNECTED] = "connected",
+};
+
+#if DEBUG
+#define DPRINTK(fmt, args...) \
+ printk(KERN_ALERT "xen_net (%s:%d) " fmt, __FUNCTION__, __LINE__, ##args)
+#else
+#define DPRINTK(fmt, args...) ((void)0)
+#endif
+#define IPRINTK(fmt, args...) \
+ printk(KERN_INFO "xen_net: " fmt, ##args)
+#define WPRINTK(fmt, args...) \
+ printk(KERN_WARNING "xen_net: " fmt, ##args)
+
+static struct net_device *find_dev_by_handle(unsigned int handle)
+{
+ struct list_head *ent;
+ struct net_private *np;
+ list_for_each (ent, &dev_list) {
+ np = list_entry(ent, struct net_private, list);
+ if (np->handle == handle)
+ return np->dev;
+ }
+ return NULL;
+}
+
+/** Network interface info. */
+struct netif_ctrl {
+ /** Number of interfaces. */
+ int interface_n;
+ /** Number of connected interfaces. */
+ int connected_n;
+ /** Error code. */
+ int err;
+ int up;
+};
+
+static struct netif_ctrl netctrl;
+
+static void netctrl_init(void)
+{
+ memset(&netctrl, 0, sizeof(netctrl));
+ netctrl.up = NETIF_DRIVER_STATUS_DOWN;
+}
+
+/** Get or set a network interface error.
+ */
+static int netctrl_err(int err)
+{
+ if ((err < 0) && !netctrl.err)
+ netctrl.err = err;
+ return netctrl.err;
+}
+
+/** Test if all network interfaces are connected.
+ *
+ * @return 1 if all connected, 0 if not, negative error code otherwise
+ */
+static int netctrl_connected(void)
+{
+ int ok;
+
+ if (netctrl.err)
+ ok = netctrl.err;
+ else if (netctrl.up == NETIF_DRIVER_STATUS_UP)
+ ok = (netctrl.connected_n == netctrl.interface_n);
+ else
+ ok = 0;
+
+ return ok;
+}
+
+/** Count the connected network interfaces.
+ *
+ * @return connected count
+ */
+static int netctrl_connected_count(void)
+{
+
+ struct list_head *ent;
+ struct net_private *np;
+ unsigned int connected;
+
+ connected = 0;
+
+ list_for_each(ent, &dev_list) {
+ np = list_entry(ent, struct net_private, list);
+ if (np->backend_state == BEST_CONNECTED)
+ connected++;
+ }
+
+ netctrl.connected_n = connected;
+ DPRINTK("> connected_n=%d interface_n=%d\n",
+ netctrl.connected_n, netctrl.interface_n);
+ return connected;
+}
+
+/** Send a packet on a net device to encourage switches to learn the
+ * MAC. We send a fake ARP request.
+ *
+ * @param dev device
+ * @return 0 on success, error code otherwise
+ */
+static int send_fake_arp(struct net_device *dev)
+{
+ struct sk_buff *skb;
+ u32 src_ip, dst_ip;
+
+ dst_ip = INADDR_BROADCAST;
+ src_ip = inet_select_addr(dev, dst_ip, RT_SCOPE_LINK);
+
+ /* No IP? Then nothing to do. */
+ if (src_ip == 0)
+ return 0;
+
+ skb = arp_create(ARPOP_REPLY, ETH_P_ARP,
+ dst_ip, dev, src_ip,
+ /*dst_hw*/ NULL, /*src_hw*/ NULL,
+ /*target_hw*/ dev->dev_addr);
+ if (skb == NULL)
+ return -ENOMEM;
+
+ return dev_queue_xmit(skb);
+}
+
+static int network_open(struct net_device *dev)
+{
+ struct net_private *np = netdev_priv(dev);
+
+ memset(&np->stats, 0, sizeof(np->stats));
+
+ np->user_state = UST_OPEN;
+
+ network_alloc_rx_buffers(dev);
+ np->rx->event = np->rx_resp_cons + 1;
+
+ netif_start_queue(dev);
+
+ return 0;
+}
+
+static void network_tx_buf_gc(struct net_device *dev)
+{
+ NETIF_RING_IDX i, prod;
+ unsigned short id;
+ struct net_private *np = netdev_priv(dev);
+ struct sk_buff *skb;
+
+ if (np->backend_state != BEST_CONNECTED)
+ return;
+
+ do {
+ prod = np->tx->resp_prod;
+ rmb(); /* Ensure we see responses up to 'rp'. */
+
+ for (i = np->tx_resp_cons; i != prod; i++) {
+ id = np->tx->ring[MASK_NETIF_TX_IDX(i)].resp.id;
+ skb = np->tx_skbs[id];
+ ADD_ID_TO_FREELIST(np->tx_skbs, id);
+ dev_kfree_skb_irq(skb);
+ }
+
+ np->tx_resp_cons = prod;
+
+ /*
+ * Set a new event, then check for race with update of tx_cons. Note
+ * that it is essential to schedule a callback, no matter how few
+ * buffers are pending. Even if there is space in the transmit ring,
+ * higher layers may be blocked because too much data is outstanding:
+ * in such cases notification from Xen is likely to be the only kick
+ * that we'll get.
+ */
+ np->tx->event =
+ prod + ((np->tx->req_prod - prod) >> 1) + 1;
+ mb();
+ } while (prod != np->tx->resp_prod);
+
+ if (np->tx_full && ((np->tx->req_prod - prod) < NETIF_TX_RING_SIZE)) {
+ np->tx_full = 0;
+ if (np->user_state == UST_OPEN)
+ netif_wake_queue(dev);
+ }
+}
+
+
+static void network_alloc_rx_buffers(struct net_device *dev)
+{
+ unsigned short id;
+ struct net_private *np = netdev_priv(dev);
+ struct sk_buff *skb;
+ int i, batch_target;
+ NETIF_RING_IDX req_prod = np->rx->req_prod;
+
+ if (unlikely(np->backend_state != BEST_CONNECTED))
+ return;
+
+ /*
+ * Allocate skbuffs greedily, even though we batch updates to the
+ * receive ring. This creates a less bursty demand on the memory allocator,
+ * so should reduce the chance of failed allocation requests both for
+ * ourself and for other kernel subsystems.
+ */
+ batch_target = np->rx_target - (req_prod - np->rx_resp_cons);
+ for (i = skb_queue_len(&np->rx_batch); i < batch_target; i++) {
+ if (unlikely((skb = alloc_xen_skb(dev->mtu + RX_HEADROOM)) == NULL))
+ break;
+ __skb_queue_tail(&np->rx_batch, skb);
+ }
+
+ /* Is the batch large enough to be worthwhile? */
+ if (i < (np->rx_target/2))
+ return;
+
+ for (i = 0; ; i++) {
+ if ((skb = __skb_dequeue(&np->rx_batch)) == NULL)
+ break;
+
+ skb->dev = dev;
+
+ id = GET_ID_FROM_FREELIST(np->rx_skbs);
+
+ np->rx_skbs[id] = skb;
+
+ np->rx->ring[MASK_NETIF_RX_IDX(req_prod + i)].req.id = id;
+
+ rx_pfn_array[i] = virt_to_machine(skb->head) >> PAGE_SHIFT;
+
+ /* Remove this page from pseudo phys map before passing back to Xen. */
+ phys_to_machine_mapping[__pa(skb->head) >> PAGE_SHIFT]
+ = INVALID_P2M_ENTRY;
+
+ rx_mcl[i].op = __HYPERVISOR_update_va_mapping;
+ rx_mcl[i].args[0] = (unsigned long)skb->head;
+ rx_mcl[i].args[1] = 0;
+ rx_mcl[i].args[2] = 0;
+ }
+
+ /* After all PTEs have been zapped we blow away stale TLB entries. */
+ rx_mcl[i-1].args[2] = UVMF_TLB_FLUSH|UVMF_ALL;
+
+ /* Give away a batch of pages. */
+ rx_mcl[i].op = __HYPERVISOR_dom_mem_op;
+ rx_mcl[i].args[0] = MEMOP_decrease_reservation;
+ rx_mcl[i].args[1] = (unsigned long)rx_pfn_array;
+ rx_mcl[i].args[2] = (unsigned long)i;
+ rx_mcl[i].args[3] = 0;
+ rx_mcl[i].args[4] = DOMID_SELF;
+
+ /* Tell the ballon driver what is going on. */
+ balloon_update_driver_allowance(i);
+
+ /* Zap PTEs and give away pages in one big multicall. */
+ (void)HYPERVISOR_multicall(rx_mcl, i+1);
+
+ /* Check return status of HYPERVISOR_dom_mem_op(). */
+ if (unlikely(rx_mcl[i].args[5] != i))
+ panic("Unable to reduce memory reservation\n");
+
+ /* Above is a suitable barrier to ensure backend will see requests. */
+ np->rx->req_prod = req_prod + i;
+
+ /* Adjust our floating fill target if we risked running out of buffers. */
+ if (((req_prod - np->rx->resp_prod) < (np->rx_target / 4)) &&
+ ((np->rx_target *= 2) > RX_MAX_TARGET))
+ np->rx_target = RX_MAX_TARGET;
+}
+
+
+static int network_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ unsigned short id;
+ struct net_private *np = netdev_priv(dev);
+ netif_tx_request_t *tx;
+ NETIF_RING_IDX i;
+
+ if (unlikely(np->tx_full)) {
+ printk(KERN_ALERT "%s: full queue wasn't stopped!\n", dev->name);
+ netif_stop_queue(dev);
+ goto drop;
+ }
+
+ if (unlikely((((unsigned long)skb->data & ~PAGE_MASK) + skb->len) >=
+ PAGE_SIZE)) {
+ struct sk_buff *nskb;
+ if (unlikely((nskb = alloc_xen_skb(skb->len)) == NULL))
+ goto drop;
+ skb_put(nskb, skb->len);
+ memcpy(nskb->data, skb->data, skb->len);
+ nskb->dev = skb->dev;
+ dev_kfree_skb(skb);
+ skb = nskb;
+ }
+
+ spin_lock_irq(&np->tx_lock);
+
+ if (np->backend_state != BEST_CONNECTED) {
+ spin_unlock_irq(&np->tx_lock);
+ goto drop;
+ }
+
+ i = np->tx->req_prod;
+
+ id = GET_ID_FROM_FREELIST(np->tx_skbs);
+ np->tx_skbs[id] = skb;
+
+ tx = &np->tx->ring[MASK_NETIF_TX_IDX(i)].req;
+
+ tx->id = id;
+ tx->addr = virt_to_machine(skb->data);
+ tx->size = skb->len;
+
+ wmb(); /* Ensure that backend will see the request. */
+ np->tx->req_prod = i + 1;
+
+ network_tx_buf_gc(dev);
+
+ if ((i - np->tx_resp_cons) == (NETIF_TX_RING_SIZE - 1)) {
+ np->tx_full = 1;
+ netif_stop_queue(dev);
+ }
+
+ spin_unlock_irq(&np->tx_lock);
+
+ np->stats.tx_bytes += skb->len;
+ np->stats.tx_packets++;
+
+ /* Only notify Xen if we really have to. */
+ mb();
+ if (np->tx->TX_TEST_IDX == i)
+ notify_via_evtchn(np->evtchn);
+
+ return 0;
+
+ drop:
+ np->stats.tx_dropped++;
+ dev_kfree_skb(skb);
+ return 0;
+}
+
+static irqreturn_t netif_int(int irq, void *dev_id, struct pt_regs *ptregs)
+{
+ struct net_device *dev = dev_id;
+ struct net_private *np = netdev_priv(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&np->tx_lock, flags);
+ network_tx_buf_gc(dev);
+ spin_unlock_irqrestore(&np->tx_lock, flags);
+
+ if ((np->rx_resp_cons != np->rx->resp_prod) && (np->user_state == UST_OPEN))
+ netif_rx_schedule(dev);
+
+ return IRQ_HANDLED;
+}
+
+
+static int netif_poll(struct net_device *dev, int *pbudget)
+{
+ struct net_private *np = netdev_priv(dev);
+ struct sk_buff *skb, *nskb;
+ netif_rx_response_t *rx;
+ NETIF_RING_IDX i, rp;
+ mmu_update_t *mmu = rx_mmu;
+ multicall_entry_t *mcl = rx_mcl;
+ int work_done, budget, more_to_do = 1;
+ struct sk_buff_head rxq;
+ unsigned long flags;
+
+ spin_lock(&np->rx_lock);
+
+ if (np->backend_state != BEST_CONNECTED) {
+ spin_unlock(&np->rx_lock);
+ return 0;
+ }
+
+ skb_queue_head_init(&rxq);
+
+ if ((budget = *pbudget) > dev->quota)
+ budget = dev->quota;
+
+ rp = np->rx->resp_prod;
+ rmb(); /* Ensure we see queued responses up to 'rp'. */
+
+ for (i = np->rx_resp_cons, work_done = 0;
+ (i != rp) && (work_done < budget);
+ i++, work_done++) {
+ rx = &np->rx->ring[MASK_NETIF_RX_IDX(i)].resp;
+
+ /*
+ * An error here is very odd. Usually indicates a backend bug,
+ * low-memory condition, or that we didn't have reservation headroom.
+ */
+ if (unlikely(rx->status <= 0)) {
+ if (net_ratelimit())
+ printk(KERN_WARNING "Bad rx buffer (memory squeeze?).\n");
+ np->rx->ring[MASK_NETIF_RX_IDX(np->rx->req_prod)].req.id = rx->id;
+ wmb();
+ np->rx->req_prod++;
+ work_done--;
+ continue;
+ }
+
+ skb = np->rx_skbs[rx->id];
+ ADD_ID_TO_FREELIST(np->rx_skbs, rx->id);
+
+ /* NB. We handle skb overflow later. */
+ skb->data = skb->head + (rx->addr & ~PAGE_MASK);
+ skb->len = rx->status;
+ skb->tail = skb->data + skb->len;
+
+ np->stats.rx_packets++;
+ np->stats.rx_bytes += rx->status;
+
+ /* Remap the page. */
+ mmu->ptr = (rx->addr & PAGE_MASK) | MMU_MACHPHYS_UPDATE;
+ mmu->val = __pa(skb->head) >> PAGE_SHIFT;
+ mmu++;
+ mcl->op = __HYPERVISOR_update_va_mapping;
+ mcl->args[0] = (unsigned long)skb->head;
+ mcl->args[1] = (rx->addr & PAGE_MASK) | __PAGE_KERNEL;
+ mcl->args[2] = 0;
+ mcl++;
+
+ phys_to_machine_mapping[__pa(skb->head) >> PAGE_SHIFT] =
+ rx->addr >> PAGE_SHIFT;
+
+ __skb_queue_tail(&rxq, skb);
+ }
+
+ /* Some pages are no longer absent... */
+ balloon_update_driver_allowance(-work_done);
+
+ /* Do all the remapping work, and M->P updates, in one big hypercall. */
+ if (likely((mcl - rx_mcl) != 0)) {
+ mcl->op = __HYPERVISOR_mmu_update;
+ mcl->args[0] = (unsigned long)rx_mmu;
+ mcl->args[1] = mmu - rx_mmu;
+ mcl->args[2] = 0;
+ mcl->args[3] = DOMID_SELF;
+ mcl++;
+ (void)HYPERVISOR_multicall(rx_mcl, mcl - rx_mcl);
+ }
+
+ while ((skb = __skb_dequeue(&rxq)) != NULL) {
+ /*
+ * Enough room in skbuff for the data we were passed? Also, Linux
+ * expects at least 16 bytes headroom in each receive buffer.
+ */
+ if (unlikely(skb->tail > skb->end) ||
+ unlikely((skb->data - skb->head) < 16)) {
+ nskb = NULL;
+
+ /* Only copy the packet if it fits in the current MTU. */
+ if (skb->len <= (dev->mtu + ETH_HLEN)) {
+ if ((skb->tail > skb->end) && net_ratelimit())
+ printk(KERN_INFO "Received packet needs %d bytes more "
+ "headroom.\n", skb->tail - skb->end);
+
+ if ((nskb = alloc_xen_skb(skb->len + 2)) != NULL) {
+ skb_reserve(nskb, 2);
+ skb_put(nskb, skb->len);
+ memcpy(nskb->data, skb->data, skb->len);
+ nskb->dev = skb->dev;
+ }
+ }
+ else if (net_ratelimit())
+ printk(KERN_INFO "Received packet too big for MTU "
+ "(%d > %d)\n", skb->len - ETH_HLEN, dev->mtu);
+
+ /* Reinitialise and then destroy the old skbuff. */
+ skb->len = 0;
+ skb->tail = skb->data;
+ init_skb_shinfo(skb);
+ dev_kfree_skb(skb);
+
+ /* Switch old for new, if we copied the buffer. */
+ if ((skb = nskb) == NULL)
+ continue;
+ }
+
+ /* Set the shared-info area, which is hidden behind the real data. */
+ init_skb_shinfo(skb);
+
+ /* Ethernet-specific work. Delayed to here as it peeks the header. */
+ skb->protocol = eth_type_trans(skb, dev);
+
+ /* Pass it up. */
+ netif_receive_skb(skb);
+ dev->last_rx = jiffies;
+ }
+
+ np->rx_resp_cons = i;
+
+ /* If we get a callback with very few responses, reduce fill target. */
+ /* NB. Note exponential increase, linear decrease. */
+ if (((np->rx->req_prod - np->rx->resp_prod) > ((3*np->rx_target) / 4)) &&
+ (--np->rx_target < RX_MIN_TARGET))
+ np->rx_target = RX_MIN_TARGET;
+
+ network_alloc_rx_buffers(dev);
+
+ *pbudget -= work_done;
+ dev->quota -= work_done;
+
+ if (work_done < budget) {
+ local_irq_save(flags);
+
+ np->rx->event = i + 1;
+
+ /* Deal with hypervisor racing our resetting of rx_event. */
+ mb();
+ if (np->rx->resp_prod == i) {
+ __netif_rx_complete(dev);
+ more_to_do = 0;
+ }
+
+ local_irq_restore(flags);
+ }
+
+ spin_unlock(&np->rx_lock);
+
+ return more_to_do;
+}
+
+
+static int network_close(struct net_device *dev)
+{
+ struct net_private *np = netdev_priv(dev);
+ np->user_state = UST_CLOSED;
+ netif_stop_queue(np->dev);
+ return 0;
+}
+
+
+static struct net_device_stats *network_get_stats(struct net_device *dev)
+{
+ struct net_private *np = netdev_priv(dev);
+ return &np->stats;
+}
+
+
+static void network_connect(struct net_device *dev,
+ netif_fe_interface_status_t *status)
+{
+ struct net_private *np;
+ int i, requeue_idx;
+ netif_tx_request_t *tx;
+
+ np = netdev_priv(dev);
+ spin_lock_irq(&np->tx_lock);
+ spin_lock(&np->rx_lock);
+
+ /* Recovery procedure: */
+
+ /* Step 1: Reinitialise variables. */
+ np->rx_resp_cons = np->tx_resp_cons = np->tx_full = 0;
+ np->rx->event = np->tx->event = 1;
+
+ /* Step 2: Rebuild the RX and TX ring contents.
+ * NB. We could just free the queued TX packets now but we hope
+ * that sending them out might do some good. We have to rebuild
+ * the RX ring because some of our pages are currently flipped out
+ * so we can't just free the RX skbs.
+ * NB2. Freelist index entries are always going to be less than
+ * __PAGE_OFFSET, whereas pointers to skbs will always be equal or
+ * greater than __PAGE_OFFSET: we use this property to distinguish
+ * them.
+ */
+
+ /* Rebuild the TX buffer freelist and the TX ring itself.
+ * NB. This reorders packets. We could keep more private state
+ * to avoid this but maybe it doesn't matter so much given the
+ * interface has been down.
+ */
+ for (requeue_idx = 0, i = 1; i <= NETIF_TX_RING_SIZE; i++) {
+ if ((unsigned long)np->tx_skbs[i] >= __PAGE_OFFSET) {
+ struct sk_buff *skb = np->tx_skbs[i];
+
+ tx = &np->tx->ring[requeue_idx++].req;
+
+ tx->id = i;
+ tx->addr = virt_to_machine(skb->data);
+ tx->size = skb->len;
+
+ np->stats.tx_bytes += skb->len;
+ np->stats.tx_packets++;
+ }
+ }
+ wmb();
+ np->tx->req_prod = requeue_idx;
+
+ /* Rebuild the RX buffer freelist and the RX ring itself. */
+ for (requeue_idx = 0, i = 1; i <= NETIF_RX_RING_SIZE; i++)
+ if ((unsigned long)np->rx_skbs[i] >= __PAGE_OFFSET)
+ np->rx->ring[requeue_idx++].req.id = i;
+ wmb();
+ np->rx->req_prod = requeue_idx;
+
+ /* Step 3: All public and private state should now be sane. Get
+ * ready to start sending and receiving packets and give the driver
+ * domain a kick because we've probably just requeued some
+ * packets.
+ */
+ np->backend_state = BEST_CONNECTED;
+ wmb();
+ notify_via_evtchn(status->evtchn);
+ network_tx_buf_gc(dev);
+
+ if (np->user_state == UST_OPEN)
+ netif_start_queue(dev);
+
+ spin_unlock(&np->rx_lock);
+ spin_unlock_irq(&np->tx_lock);
+}
+
+static void vif_show(struct net_private *np)
+{
+#if DEBUG
+ if (np) {
+ IPRINTK("<vif handle=%u %s(%s) evtchn=%u irq=%u tx=%p rx=%p>\n",
+ np->handle,
+ be_state_name[np->backend_state],
+ np->user_state ? "open" : "closed",
+ np->evtchn,
+ np->irq,
+ np->tx,
+ np->rx);
+ } else {
+ IPRINTK("<vif NULL>\n");
+ }
+#endif
+}
+
+/* Send a connect message to xend to tell it to bring up the interface. */
+static void send_interface_connect(struct net_private *np)
+{
+ ctrl_msg_t cmsg = {
+ .type = CMSG_NETIF_FE,
+ .subtype = CMSG_NETIF_FE_INTERFACE_CONNECT,
+ .length = sizeof(netif_fe_interface_connect_t),
+ };
+ netif_fe_interface_connect_t *msg = (void*)cmsg.msg;
+
+ msg->handle = np->handle;
+ msg->tx_shmem_frame = (virt_to_machine(np->tx) >> PAGE_SHIFT);
+ msg->rx_shmem_frame = (virt_to_machine(np->rx) >> PAGE_SHIFT);
+
+ ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
+}
+
+/* Send a driver status notification to the domain controller. */
+static int send_driver_status(int ok)
+{
+ int err = 0;
+ ctrl_msg_t cmsg = {
+ .type = CMSG_NETIF_FE,
+ .subtype = CMSG_NETIF_FE_DRIVER_STATUS,
+ .length = sizeof(netif_fe_driver_status_t),
+ };
+ netif_fe_driver_status_t *msg = (void*)cmsg.msg;
+
+ msg->status = (ok ? NETIF_DRIVER_STATUS_UP : NETIF_DRIVER_STATUS_DOWN);
+ err = ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
+ return err;
+}
+
+/* Stop network device and free tx/rx queues and irq.
+ */
+static void vif_release(struct net_private *np)
+{
+ /* Stop old i/f to prevent errors whilst we rebuild the state. */
+ spin_lock_irq(&np->tx_lock);
+ spin_lock(&np->rx_lock);
+ netif_stop_queue(np->dev);
+ /* np->backend_state = BEST_DISCONNECTED; */
+ spin_unlock(&np->rx_lock);
+ spin_unlock_irq(&np->tx_lock);
+
+ /* Free resources. */
+ if(np->tx != NULL){
+ free_irq(np->irq, np->dev);
+ unbind_evtchn_from_irq(np->evtchn);
+ free_page((unsigned long)np->tx);
+ free_page((unsigned long)np->rx);
+ np->irq = 0;
+ np->evtchn = 0;
+ np->tx = NULL;
+ np->rx = NULL;
+ }
+}
+
+/* Release vif resources and close it down completely.
+ */
+static void vif_close(struct net_private *np)
+{
+ WPRINTK("Unexpected netif-CLOSED message in state %s\n",
+ be_state_name[np->backend_state]);
+ vif_release(np);
+ np->backend_state = BEST_CLOSED;
+ /* todo: take dev down and free. */
+ vif_show(np);
+}
+
+/* Move the vif into disconnected state.
+ * Allocates tx/rx pages.
+ * Sends connect message to xend.
+ */
+static void vif_disconnect(struct net_private *np)
+{
+ if(np->tx) free_page((unsigned long)np->tx);
+ if(np->rx) free_page((unsigned long)np->rx);
+ // Before this np->tx and np->rx had better be null.
+ np->tx = (netif_tx_interface_t *)__get_free_page(GFP_KERNEL);
+ np->rx = (netif_rx_interface_t *)__get_free_page(GFP_KERNEL);
+ memset(np->tx, 0, PAGE_SIZE);
+ memset(np->rx, 0, PAGE_SIZE);
+ np->backend_state = BEST_DISCONNECTED;
+ send_interface_connect(np);
+ vif_show(np);
+}
+
+/* Begin interface recovery.
+ *
+ * NB. Whilst we're recovering, we turn the carrier state off. We
+ * take measures to ensure that this device isn't used for
+ * anything. We also stop the queue for this device. Various
+ * different approaches (e.g. continuing to buffer packets) have
+ * been tested but don't appear to improve the overall impact on
+ * TCP connections.
+ *
+ * TODO: (MAW) Change the Xend<->Guest protocol so that a recovery
+ * is initiated by a special "RESET" message - disconnect could
+ * just mean we're not allowed to use this interface any more.
+ */
+static void vif_reset(struct net_private *np)
+{
+ IPRINTK("Attempting to reconnect network interface: handle=%u\n",
+ np->handle);
+ vif_release(np);
+ vif_disconnect(np);
+ vif_show(np);
+}
+
+/* Move the vif into connected state.
+ * Sets the mac and event channel from the message.
+ * Binds the irq to the event channel.
+ */
+static void
+vif_connect(struct net_private *np, netif_fe_interface_status_t *status)
+{
+ struct net_device *dev = np->dev;
+ memcpy(dev->dev_addr, status->mac, ETH_ALEN);
+ network_connect(dev, status);
+ np->evtchn = status->evtchn;
+ np->irq = bind_evtchn_to_irq(np->evtchn);
+ (void)request_irq(np->irq, netif_int, SA_SAMPLE_RANDOM, dev->name, dev);
+ netctrl_connected_count();
+ (void)send_fake_arp(dev);
+ vif_show(np);
+}
+
+
+/** Create a network device.
+ * @param handle device handle
+ * @param val return parameter for created device
+ * @return 0 on success, error code otherwise
+ */
+static int create_netdev(int handle, struct net_device **val)
+{
+ int i, err = 0;
+ struct net_device *dev = NULL;
+ struct net_private *np = NULL;
+
+ if ((dev = alloc_etherdev(sizeof(struct net_private))) == NULL) {
+ printk(KERN_WARNING "%s> alloc_etherdev failed.\n", __FUNCTION__);
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ np = netdev_priv(dev);
+ np->backend_state = BEST_CLOSED;
+ np->user_state = UST_CLOSED;
+ np->handle = handle;
+
+ spin_lock_init(&np->tx_lock);
+ spin_lock_init(&np->rx_lock);
+
+ skb_queue_head_init(&np->rx_batch);
+ np->rx_target = RX_MIN_TARGET;
+
+ /* Initialise {tx,rx}_skbs to be a free chain containing every entry. */
+ for (i = 0; i <= NETIF_TX_RING_SIZE; i++)
+ np->tx_skbs[i] = (void *)(i+1);
+ for (i = 0; i <= NETIF_RX_RING_SIZE; i++)
+ np->rx_skbs[i] = (void *)(i+1);
+
+ dev->open = network_open;
+ dev->hard_start_xmit = network_start_xmit;
+ dev->stop = network_close;
+ dev->get_stats = network_get_stats;
+ dev->poll = netif_poll;
+ dev->weight = 64;
+
+ if ((err = register_netdev(dev)) != 0) {
+ printk(KERN_WARNING "%s> register_netdev err=%d\n", __FUNCTION__, err);
+ goto exit;
+ }
+ np->dev = dev;
+ list_add(&np->list, &dev_list);
+
+ exit:
+ if ((err != 0) && (dev != NULL ))
+ kfree(dev);
+ else if (val != NULL)
+ *val = dev;
+ return err;
+}
+
+/* Get the target interface for a status message.
+ * Creates the interface when it makes sense.
+ * The returned interface may be null when there is no error.
+ *
+ * @param status status message
+ * @param np return parameter for interface state
+ * @return 0 on success, error code otherwise
+ */
+static int
+target_vif(netif_fe_interface_status_t *status, struct net_private **np)
+{
+ int err = 0;
+ struct net_device *dev;
+
+ DPRINTK("> handle=%d\n", status->handle);
+ if (status->handle < 0) {
+ err = -EINVAL;
+ goto exit;
+ }
+
+ if ((dev = find_dev_by_handle(status->handle)) != NULL)
+ goto exit;
+
+ if (status->status == NETIF_INTERFACE_STATUS_CLOSED)
+ goto exit;
+ if (status->status == NETIF_INTERFACE_STATUS_CHANGED)
+ goto exit;
+
+ /* It's a new interface in a good state - create it. */
+ DPRINTK("> create device...\n");
+ if ((err = create_netdev(status->handle, &dev)) != 0)
+ goto exit;
+
+ netctrl.interface_n++;
+
+ exit:
+ if (np != NULL)
+ *np = ((dev && !err) ? netdev_priv(dev) : NULL);
+ DPRINTK("< err=%d\n", err);
+ return err;
+}
+
+/* Handle an interface status message. */
+static void netif_interface_status(netif_fe_interface_status_t *status)
+{
+ int err = 0;
+ struct net_private *np = NULL;
+
+ DPRINTK("> status=%s handle=%d\n",
+ status_name[status->status], status->handle);
+
+ if ((err = target_vif(status, &np)) != 0) {
+ WPRINTK("Invalid netif: handle=%u\n", status->handle);
+ return;
+ }
+
+ if (np == NULL) {
+ DPRINTK("> no vif\n");
+ return;
+ }
+
+ switch (status->status) {
+ case NETIF_INTERFACE_STATUS_CLOSED:
+ switch (np->backend_state) {
+ case BEST_CLOSED:
+ case BEST_DISCONNECTED:
+ case BEST_CONNECTED:
+ vif_close(np);
+ break;
+ }
+ break;
+
+ case NETIF_INTERFACE_STATUS_DISCONNECTED:
+ switch (np->backend_state) {
+ case BEST_CLOSED:
+ vif_disconnect(np);
+ break;
+ case BEST_DISCONNECTED:
+ case BEST_CONNECTED:
+ vif_reset(np);
+ break;
+ }
+ break;
+
+ case NETIF_INTERFACE_STATUS_CONNECTED:
+ switch (np->backend_state) {
+ case BEST_CLOSED:
+ WPRINTK("Unexpected netif status %s in state %s\n",
+ status_name[status->status],
+ be_state_name[np->backend_state]);
+ vif_disconnect(np);
+ vif_connect(np, status);
+ break;
+ case BEST_DISCONNECTED:
+ vif_connect(np, status);
+ break;
+ }
+ break;
+
+ case NETIF_INTERFACE_STATUS_CHANGED:
+ /*
+ * The domain controller is notifying us that a device has been
+ * added or removed.
+ */
+ break;
+
+ default:
+ WPRINTK("Invalid netif status code %d\n", status->status);
+ break;
+ }
+
+ vif_show(np);
+}
+
+/*
+ * Initialize the network control interface.
+ */
+static void netif_driver_status(netif_fe_driver_status_t *status)
+{
+ netctrl.up = status->status;
+ netctrl_connected_count();
+}
+
+/* Receive handler for control messages. */
+static void netif_ctrlif_rx(ctrl_msg_t *msg, unsigned long id)
+{
+
+ switch (msg->subtype) {
+ case CMSG_NETIF_FE_INTERFACE_STATUS:
+ netif_interface_status((netif_fe_interface_status_t *) &msg->msg[0]);
+ break;
+
+ case CMSG_NETIF_FE_DRIVER_STATUS:
+ netif_driver_status((netif_fe_driver_status_t *) &msg->msg[0]);
+ break;
+
+ default:
+ msg->length = 0;
+ break;
+ }
+
+ ctrl_if_send_response(msg);
+}
+
+
+#if 1
+/* Wait for all interfaces to be connected.
+ *
+ * This works OK, but we'd like to use the probing mode (see below).
+ */
+static int probe_interfaces(void)
+{
+ int err = 0, conn = 0;
+ int wait_i, wait_n = 100;
+
+ DPRINTK(">\n");
+
+ for (wait_i = 0; wait_i < wait_n; wait_i++) {
+ DPRINTK("> wait_i=%d\n", wait_i);
+ conn = netctrl_connected();
+ if(conn) break;
+ DPRINTK("> schedule_timeout...\n");
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(10);
+ }
+
+ DPRINTK("> wait finished...\n");
+ if (conn <= 0) {
+ err = netctrl_err(-ENETDOWN);
+ WPRINTK("Failed to connect all virtual interfaces: err=%d\n", err);
+ }
+
+ DPRINTK("< err=%d\n", err);
+
+ return err;
+}
+#else
+/* Probe for interfaces until no more are found.
+ *
+ * This is the mode we'd like to use, but at the moment it panics the kernel.
+*/
+static int probe_interfaces(void)
+{
+ int err = 0;
+ int wait_i, wait_n = 100;
+ ctrl_msg_t cmsg = {
+ .type = CMSG_NETIF_FE,
+ .subtype = CMSG_NETIF_FE_INTERFACE_STATUS,
+ .length = sizeof(netif_fe_interface_status_t),
+ };
+ netif_fe_interface_status_t msg = {};
+ ctrl_msg_t rmsg = {};
+ netif_fe_interface_status_t *reply = (void*)rmsg.msg;
+ int state = TASK_UNINTERRUPTIBLE;
+ u32 query = -1;
+
+ DPRINTK(">\n");
+
+ netctrl.interface_n = 0;
+ for (wait_i = 0; wait_i < wait_n; wait_i++) {
+ DPRINTK("> wait_i=%d query=%d\n", wait_i, query);
+ msg.handle = query;
+ memcpy(cmsg.msg, &msg, sizeof(msg));
+ DPRINTK("> set_current_state...\n");
+ set_current_state(state);
+ DPRINTK("> rmsg=%p msg=%p, reply=%p\n", &rmsg, rmsg.msg, reply);
+ DPRINTK("> sending...\n");
+ err = ctrl_if_send_message_and_get_response(&cmsg, &rmsg, state);
+ DPRINTK("> err=%d\n", err);
+ if(err) goto exit;
+ DPRINTK("> rmsg=%p msg=%p, reply=%p\n", &rmsg, rmsg.msg, reply);
+ if((int)reply->handle < 0) {
+ // No more interfaces.
+ break;
+ }
+ query = -reply->handle - 2;
+ DPRINTK(">netif_interface_status ...\n");
+ netif_interface_status(reply);
+ }
+
+ exit:
+ if (err) {
+ err = netctrl_err(-ENETDOWN);
+ WPRINTK("Connecting virtual network interfaces failed: err=%d\n", err);
+ }
+
+ DPRINTK("< err=%d\n", err);
+ return err;
+}
+
+#endif
+
+/*
+ * We use this notifier to send out a fake ARP reply to reset switches and
+ * router ARP caches when an IP interface is brought up on a VIF.
+ */
+static int
+inetdev_notify(struct notifier_block *this, unsigned long event, void *ptr)
+{
+ struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
+ struct net_device *dev = ifa->ifa_dev->dev;
+ struct list_head *ent;
+ struct net_private *np;
+
+ if (event != NETDEV_UP)
+ goto out;
+
+ list_for_each (ent, &dev_list) {
+ np = list_entry(ent, struct net_private, list);
+ if (np->dev == dev)
+ (void)send_fake_arp(dev);
+ }
+
+ out:
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block notifier_inetdev = {
+ .notifier_call = inetdev_notify,
+ .next = NULL,
+ .priority = 0
+};
+
+static int __init netif_init(void)
+{
+ int err = 0;
+
+ if (xen_start_info.flags & SIF_INITDOMAIN)
+ return 0;
+
+ IPRINTK("Initialising virtual ethernet driver.\n");
+ INIT_LIST_HEAD(&dev_list);
+ (void)register_inetaddr_notifier(¬ifier_inetdev);
+ netctrl_init();
+ (void)ctrl_if_register_receiver(CMSG_NETIF_FE, netif_ctrlif_rx,
+ CALLBACK_IN_BLOCKING_CONTEXT);
+ send_driver_status(1);
+ err = probe_interfaces();
+ if (err)
+ ctrl_if_unregister_receiver(CMSG_NETIF_FE, netif_ctrlif_rx);
+
+ DPRINTK("< err=%d\n", err);
+ return err;
+}
+
+static void vif_suspend(struct net_private *np)
+{
+ /* Avoid having tx/rx stuff happen until we're ready. */
+ free_irq(np->irq, np->dev);
+ unbind_evtchn_from_irq(np->evtchn);
+}
+
+static void vif_resume(struct net_private *np)
+{
+ /*
+ * Connect regardless of whether IFF_UP flag set.
+ * Stop bad things from happening until we're back up.
+ */
+ np->backend_state = BEST_DISCONNECTED;
+ memset(np->tx, 0, PAGE_SIZE);
+ memset(np->rx, 0, PAGE_SIZE);
+
+ send_interface_connect(np);
+}
+
+void netif_suspend(void)
+{
+ struct list_head *ent;
+ struct net_private *np;
+
+ list_for_each (ent, &dev_list) {
+ np = list_entry(ent, struct net_private, list);
+ vif_suspend(np);
+ }
+}
+
+void netif_resume(void)
+{
+ struct list_head *ent;
+ struct net_private *np;
+
+ list_for_each (ent, &dev_list) {
+ np = list_entry(ent, struct net_private, list);
+ vif_resume(np);
+ }
+}
+
+
+module_init(netif_init);
+
--- /dev/null
+
+obj-y := privcmd.o
--- /dev/null
+/******************************************************************************
+ * privcmd.c
+ *
+ * Interface to privileged domain-0 commands.
+ *
+ * Copyright (c) 2002-2004, K A Fraser, B Dragovic
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/swap.h>
+#include <linux/smp_lock.h>
+#include <linux/highmem.h>
+#include <linux/pagemap.h>
+#include <linux/seq_file.h>
+
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+#include <asm/tlb.h>
+#include <asm-xen/linux-public/privcmd.h>
+#include <asm-xen/xen-public/dom0_ops.h>
+#include <asm-xen/xen_proc.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+#define pud_t pgd_t
+#define pud_offset(d, va) d
+#endif
+
+static struct proc_dir_entry *privcmd_intf;
+
+static int privcmd_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long data)
+{
+ int ret = -ENOSYS;
+
+ switch ( cmd )
+ {
+ case IOCTL_PRIVCMD_HYPERCALL:
+ {
+ privcmd_hypercall_t hypercall;
+
+ if ( copy_from_user(&hypercall, (void *)data, sizeof(hypercall)) )
+ return -EFAULT;
+
+#if defined(__i386__)
+ __asm__ __volatile__ (
+ "pushl %%ebx; pushl %%ecx; pushl %%edx; pushl %%esi; pushl %%edi; "
+ "movl 4(%%eax),%%ebx ;"
+ "movl 8(%%eax),%%ecx ;"
+ "movl 12(%%eax),%%edx ;"
+ "movl 16(%%eax),%%esi ;"
+ "movl 20(%%eax),%%edi ;"
+ "movl (%%eax),%%eax ;"
+ TRAP_INSTR "; "
+ "popl %%edi; popl %%esi; popl %%edx; popl %%ecx; popl %%ebx"
+ : "=a" (ret) : "0" (&hypercall) : "memory" );
+#elif defined (__x86_64__)
+ __asm__ __volatile__ (
+ "movq %5,%%r10; movq %6,%%r8;" TRAP_INSTR
+ : "=a" (ret)
+ : "a" ((unsigned long)hypercall.op),
+ "D" ((unsigned long)hypercall.arg[0]),
+ "S" ((unsigned long)hypercall.arg[1]),
+ "d" ((unsigned long)hypercall.arg[2]),
+ "g" ((unsigned long)hypercall.arg[3]),
+ "g" ((unsigned long)hypercall.arg[4])
+ : "r11","rcx","r8","r10","memory");
+#endif
+ }
+ break;
+
+ case IOCTL_PRIVCMD_INITDOMAIN_EVTCHN:
+ {
+ extern int initdom_ctrlif_domcontroller_port;
+ ret = initdom_ctrlif_domcontroller_port;
+ }
+ break;
+
+#if defined(CONFIG_XEN_PRIVILEGED_GUEST)
+ case IOCTL_PRIVCMD_MMAP:
+ {
+#define PRIVCMD_MMAP_SZ 32
+ privcmd_mmap_t mmapcmd;
+ privcmd_mmap_entry_t msg[PRIVCMD_MMAP_SZ], *p;
+ int i, rc;
+
+ if ( copy_from_user(&mmapcmd, (void *)data, sizeof(mmapcmd)) )
+ return -EFAULT;
+
+ p = mmapcmd.entry;
+
+ for (i=0; i<mmapcmd.num; i+=PRIVCMD_MMAP_SZ, p+=PRIVCMD_MMAP_SZ)
+ {
+ int j, n = ((mmapcmd.num-i)>PRIVCMD_MMAP_SZ)?
+ PRIVCMD_MMAP_SZ:(mmapcmd.num-i);
+
+
+ if ( copy_from_user(&msg, p, n*sizeof(privcmd_mmap_entry_t)) )
+ return -EFAULT;
+
+ for ( j = 0; j < n; j++ )
+ {
+ struct vm_area_struct *vma =
+ find_vma( current->mm, msg[j].va );
+
+ if ( !vma )
+ return -EINVAL;
+
+ if ( msg[j].va > PAGE_OFFSET )
+ return -EINVAL;
+
+ if ( (msg[j].va + (msg[j].npages<<PAGE_SHIFT)) > vma->vm_end )
+ return -EINVAL;
+
+ if ( (rc = direct_remap_area_pages(vma->vm_mm,
+ msg[j].va&PAGE_MASK,
+ msg[j].mfn<<PAGE_SHIFT,
+ msg[j].npages<<PAGE_SHIFT,
+ vma->vm_page_prot,
+ mmapcmd.dom)) < 0 )
+ return rc;
+ }
+ }
+ ret = 0;
+ }
+ break;
+
+ case IOCTL_PRIVCMD_MMAPBATCH:
+ {
+ mmu_update_t u;
+ privcmd_mmapbatch_t m;
+ struct vm_area_struct *vma = NULL;
+ unsigned long *p, addr;
+ unsigned long mfn;
+ int i;
+
+ if ( copy_from_user(&m, (void *)data, sizeof(m)) )
+ { ret = -EFAULT; goto batch_err; }
+
+ vma = find_vma( current->mm, m.addr );
+
+ if ( !vma )
+ { ret = -EINVAL; goto batch_err; }
+
+ if ( m.addr > PAGE_OFFSET )
+ { ret = -EFAULT; goto batch_err; }
+
+ if ( (m.addr + (m.num<<PAGE_SHIFT)) > vma->vm_end )
+ { ret = -EFAULT; goto batch_err; }
+
+ p = m.arr;
+ addr = m.addr;
+ for ( i = 0; i < m.num; i++, addr += PAGE_SIZE, p++ )
+ {
+ if ( get_user(mfn, p) )
+ return -EFAULT;
+
+ u.val = (mfn << PAGE_SHIFT) | pgprot_val(vma->vm_page_prot);
+
+ __direct_remap_area_pages(vma->vm_mm,
+ addr,
+ PAGE_SIZE,
+ &u);
+
+ if ( unlikely(HYPERVISOR_mmu_update(&u, 1, NULL, m.dom) < 0) )
+ put_user(0xF0000000 | mfn, p);
+ }
+
+ ret = 0;
+ break;
+
+ batch_err:
+ printk("batch_err ret=%d vma=%p addr=%lx num=%d arr=%p %lx-%lx\n",
+ ret, vma, m.addr, m.num, m.arr,
+ vma ? vma->vm_start : 0, vma ? vma->vm_end : 0);
+ break;
+ }
+ break;
+#endif
+
+ case IOCTL_PRIVCMD_GET_MACH2PHYS_START_MFN:
+ {
+ unsigned long m2pv = (unsigned long)machine_to_phys_mapping;
+ pgd_t *pgd = pgd_offset_k(m2pv);
+ pud_t *pud = pud_offset(pgd, m2pv);
+ pmd_t *pmd = pmd_offset(pud, m2pv);
+ unsigned long m2p_start_mfn = (*(unsigned long *)pmd) >> PAGE_SHIFT;
+ ret = put_user(m2p_start_mfn, (unsigned long *)data) ? -EFAULT: 0;
+ }
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int privcmd_mmap(struct file * file, struct vm_area_struct * vma)
+{
+ /* DONTCOPY is essential for Xen as copy_page_range is broken. */
+ vma->vm_flags |= VM_RESERVED | VM_IO | VM_DONTCOPY;
+
+ return 0;
+}
+
+static struct file_operations privcmd_file_ops = {
+ ioctl : privcmd_ioctl,
+ mmap: privcmd_mmap
+};
+
+
+static int __init privcmd_init(void)
+{
+ if ( !(xen_start_info.flags & SIF_PRIVILEGED) )
+ return 0;
+
+ privcmd_intf = create_xen_proc_entry("privcmd", 0400);
+ if ( privcmd_intf != NULL )
+ privcmd_intf->proc_fops = &privcmd_file_ops;
+
+ return 0;
+}
+
+__initcall(privcmd_init);
--- /dev/null
+/*
+ * This structure describes the machine which we are running on.
+ */
+struct imxfb_mach_info {
+ u_long pixclock;
+
+ u_short xres;
+ u_short yres;
+
+ u_char bpp;
+ u_char hsync_len;
+ u_char left_margin;
+ u_char right_margin;
+
+ u_char vsync_len;
+ u_char upper_margin;
+ u_char lower_margin;
+ u_char sync;
+
+ u_int cmap_greyscale:1,
+ cmap_inverse:1,
+ cmap_static:1,
+ unused:29;
+
+ u_int pcr;
+ u_int pwmr;
+ u_int lscr1;
+
+ u_char * fixed_screen_cpu;
+ dma_addr_t fixed_screen_dma;
+
+ void (*lcd_power)(int);
+ void (*backlight_power)(int);
+};
+void set_imx_fb_info(struct imxfb_mach_info *hard_imx_fb_info);
--- /dev/null
+/*
+ * Copyright (C) 2004 2N Telekomunikace, Ladislav Michl <michl@2n.cz>
+ *
+ * Hardware definitions for OMAP5910 based VoiceBlue board.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_ARCH_VOICEBLUE_H
+#define __ASM_ARCH_VOICEBLUE_H
+
+#if (EXTERNAL_MAX_NR_PORTS < 4)
+#undef EXTERNAL_MAX_NR_PORTS
+#define EXTERNAL_MAX_NR_PORTS 4
+#endif
+
+extern void voiceblue_wdt_enable(void);
+extern void voiceblue_wdt_disable(void);
+extern void voiceblue_wdt_ping(void);
+extern void voiceblue_reset(void);
+
+#endif /* __ASM_ARCH_VOICEBLUE_H */
+
--- /dev/null
+/* linux/include/asm-arm/arch-s3c2410/otom-map.h
+ *
+ * (c) 2005 Guillaume GOURAT / NexVision
+ * guillaume.gourat@nexvision.fr
+ *
+ * NexVision OTOM board memory map definitions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+/* needs arch/map.h including with this */
+
+/* ok, we've used up to 0x01300000, now we need to find space for the
+ * peripherals that live in the nGCS[x] areas, which are quite numerous
+ * in their space.
+ */
+
+#ifndef __ASM_ARCH_OTOMMAP_H
+#define __ASM_ARCH_OTOMMAP_H
+
+#define OTOM_PA_CS8900A_BASE (S3C2410_CS3 + 0x01000000) /* nGCS3 +0x01000000 */
+#define OTOM_VA_CS8900A_BASE S3C2410_ADDR(0x04000000) /* 0xF4000000 */
+
+/* physical offset addresses for the peripherals */
+
+#define OTOM_PA_FLASH0_BASE (S3C2410_CS0) /* Bank 0 */
+
+#endif /* __ASM_ARCH_OTOMMAP_H */
--- /dev/null
+/*
+ * Hardware parameter area specific to Sharp SL series devices
+ *
+ * Copyright (c) 2005 Richard Purdie
+ *
+ * Based on Sharp's 2.4 kernel patches
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+struct sharpsl_param_info {
+ unsigned int comadj_keyword;
+ unsigned int comadj;
+
+ unsigned int uuid_keyword;
+ unsigned char uuid[16];
+
+ unsigned int touch_keyword;
+ unsigned int touch_xp;
+ unsigned int touch_yp;
+ unsigned int touch_xd;
+ unsigned int touch_yd;
+
+ unsigned int adadj_keyword;
+ unsigned int adadj;
+
+ unsigned int phad_keyword;
+ unsigned int phadadj;
+} __attribute__((packed));
+
+
+extern struct sharpsl_param_info sharpsl_param;
+extern void sharpsl_save_param(void);
+
--- /dev/null
+#ifndef _ASM_GENERIC_IPC_H
+#define _ASM_GENERIC_IPC_H
+/*
+ * These are used to wrap system calls.
+ *
+ * See architecture code for ugly details..
+ */
+struct ipc_kludge {
+ struct msgbuf __user *msgp;
+ long msgtyp;
+};
+
+#define SEMOP 1
+#define SEMGET 2
+#define SEMCTL 3
+#define SEMTIMEDOP 4
+#define MSGSND 11
+#define MSGRCV 12
+#define MSGGET 13
+#define MSGCTL 14
+#define SHMAT 21
+#define SHMDT 22
+#define SHMGET 23
+#define SHMCTL 24
+
+/* Used by the DIPC package, try and avoid reusing it */
+#define DIPC 25
+
+#define IPCCALL(version,op) ((version)<<16 | (op))
+
+#endif /* _ASM_GENERIC_IPC_H */
--- /dev/null
+#ifndef _ASM_SECCOMP_H
+
+#include <linux/thread_info.h>
+
+#ifdef TIF_32BIT
+#error "unexpected TIF_32BIT on i386"
+#endif
+
+#include <linux/unistd.h>
+
+#define __NR_seccomp_read __NR_read
+#define __NR_seccomp_write __NR_write
+#define __NR_seccomp_exit __NR_exit
+#define __NR_seccomp_sigreturn __NR_sigreturn
+
+#endif /* _ASM_SECCOMP_H */
--- /dev/null
+#ifndef _ASM_IA64_SN_TIO_TIOCA_H
+#define _ASM_IA64_SN_TIO_TIOCA_H
+
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (c) 2003-2005 Silicon Graphics, Inc. All rights reserved.
+ */
+
+
+#define TIOCA_PART_NUM 0xE020
+#define TIOCA_MFGR_NUM 0x24
+#define TIOCA_REV_A 0x1
+
+/*
+ * Register layout for TIO:CA. See below for bitmasks for each register.
+ */
+
+struct tioca {
+ uint64_t ca_id; /* 0x000000 */
+ uint64_t ca_control1; /* 0x000008 */
+ uint64_t ca_control2; /* 0x000010 */
+ uint64_t ca_status1; /* 0x000018 */
+ uint64_t ca_status2; /* 0x000020 */
+ uint64_t ca_gart_aperature; /* 0x000028 */
+ uint64_t ca_gfx_detach; /* 0x000030 */
+ uint64_t ca_inta_dest_addr; /* 0x000038 */
+ uint64_t ca_intb_dest_addr; /* 0x000040 */
+ uint64_t ca_err_int_dest_addr; /* 0x000048 */
+ uint64_t ca_int_status; /* 0x000050 */
+ uint64_t ca_int_status_alias; /* 0x000058 */
+ uint64_t ca_mult_error; /* 0x000060 */
+ uint64_t ca_mult_error_alias; /* 0x000068 */
+ uint64_t ca_first_error; /* 0x000070 */
+ uint64_t ca_int_mask; /* 0x000078 */
+ uint64_t ca_crm_pkterr_type; /* 0x000080 */
+ uint64_t ca_crm_pkterr_type_alias; /* 0x000088 */
+ uint64_t ca_crm_ct_error_detail_1; /* 0x000090 */
+ uint64_t ca_crm_ct_error_detail_2; /* 0x000098 */
+ uint64_t ca_crm_tnumto; /* 0x0000A0 */
+ uint64_t ca_gart_err; /* 0x0000A8 */
+ uint64_t ca_pcierr_type; /* 0x0000B0 */
+ uint64_t ca_pcierr_addr; /* 0x0000B8 */
+
+ uint64_t ca_pad_0000C0[3]; /* 0x0000{C0..D0} */
+
+ uint64_t ca_pci_rd_buf_flush; /* 0x0000D8 */
+ uint64_t ca_pci_dma_addr_extn; /* 0x0000E0 */
+ uint64_t ca_agp_dma_addr_extn; /* 0x0000E8 */
+ uint64_t ca_force_inta; /* 0x0000F0 */
+ uint64_t ca_force_intb; /* 0x0000F8 */
+ uint64_t ca_debug_vector_sel; /* 0x000100 */
+ uint64_t ca_debug_mux_core_sel; /* 0x000108 */
+ uint64_t ca_debug_mux_pci_sel; /* 0x000110 */
+ uint64_t ca_debug_domain_sel; /* 0x000118 */
+
+ uint64_t ca_pad_000120[28]; /* 0x0001{20..F8} */
+
+ uint64_t ca_gart_ptr_table; /* 0x200 */
+ uint64_t ca_gart_tlb_addr[8]; /* 0x2{08..40} */
+};
+
+/*
+ * Mask/shift definitions for TIO:CA registers. The convention here is
+ * to mainly use the names as they appear in the "TIO AEGIS Programmers'
+ * Reference" with a CA_ prefix added. Some exceptions were made to fix
+ * duplicate field names or to generalize fields that are common to
+ * different registers (ca_debug_mux_core_sel and ca_debug_mux_pci_sel for
+ * example).
+ *
+ * Fields consisting of a single bit have a single #define have a single
+ * macro declaration to mask the bit. Fields consisting of multiple bits
+ * have two declarations: one to mask the proper bits in a register, and
+ * a second with the suffix "_SHFT" to identify how far the mask needs to
+ * be shifted right to get its base value.
+ */
+
+/* ==== ca_control1 */
+#define CA_SYS_BIG_END (1ull << 0)
+#define CA_DMA_AGP_SWAP (1ull << 1)
+#define CA_DMA_PCI_SWAP (1ull << 2)
+#define CA_PIO_IO_SWAP (1ull << 3)
+#define CA_PIO_MEM_SWAP (1ull << 4)
+#define CA_GFX_WR_SWAP (1ull << 5)
+#define CA_AGP_FW_ENABLE (1ull << 6)
+#define CA_AGP_CAL_CYCLE (0x7ull << 7)
+#define CA_AGP_CAL_CYCLE_SHFT 7
+#define CA_AGP_CAL_PRSCL_BYP (1ull << 10)
+#define CA_AGP_INIT_CAL_ENB (1ull << 11)
+#define CA_INJ_ADDR_PERR (1ull << 12)
+#define CA_INJ_DATA_PERR (1ull << 13)
+ /* bits 15:14 unused */
+#define CA_PCIM_IO_NBE_AD (0x7ull << 16)
+#define CA_PCIM_IO_NBE_AD_SHFT 16
+#define CA_PCIM_FAST_BTB_ENB (1ull << 19)
+ /* bits 23:20 unused */
+#define CA_PIO_ADDR_OFFSET (0xffull << 24)
+#define CA_PIO_ADDR_OFFSET_SHFT 24
+ /* bits 35:32 unused */
+#define CA_AGPDMA_OP_COMBDELAY (0x1full << 36)
+#define CA_AGPDMA_OP_COMBDELAY_SHFT 36
+ /* bit 41 unused */
+#define CA_AGPDMA_OP_ENB_COMBDELAY (1ull << 42)
+#define CA_PCI_INT_LPCNT (0xffull << 44)
+#define CA_PCI_INT_LPCNT_SHFT 44
+ /* bits 63:52 unused */
+
+/* ==== ca_control2 */
+#define CA_AGP_LATENCY_TO (0xffull << 0)
+#define CA_AGP_LATENCY_TO_SHFT 0
+#define CA_PCI_LATENCY_TO (0xffull << 8)
+#define CA_PCI_LATENCY_TO_SHFT 8
+#define CA_PCI_MAX_RETRY (0x3ffull << 16)
+#define CA_PCI_MAX_RETRY_SHFT 16
+ /* bits 27:26 unused */
+#define CA_RT_INT_EN (0x3ull << 28)
+#define CA_RT_INT_EN_SHFT 28
+#define CA_MSI_INT_ENB (1ull << 30)
+#define CA_PCI_ARB_ERR_ENB (1ull << 31)
+#define CA_GART_MEM_PARAM (0x3ull << 32)
+#define CA_GART_MEM_PARAM_SHFT 32
+#define CA_GART_RD_PREFETCH_ENB (1ull << 34)
+#define CA_GART_WR_PREFETCH_ENB (1ull << 35)
+#define CA_GART_FLUSH_TLB (1ull << 36)
+ /* bits 39:37 unused */
+#define CA_CRM_TNUMTO_PERIOD (0x1fffull << 40)
+#define CA_CRM_TNUMTO_PERIOD_SHFT 40
+ /* bits 55:53 unused */
+#define CA_CRM_TNUMTO_ENB (1ull << 56)
+#define CA_CRM_PRESCALER_BYP (1ull << 57)
+ /* bits 59:58 unused */
+#define CA_CRM_MAX_CREDIT (0x7ull << 60)
+#define CA_CRM_MAX_CREDIT_SHFT 60
+ /* bit 63 unused */
+
+/* ==== ca_status1 */
+#define CA_CORELET_ID (0x3ull << 0)
+#define CA_CORELET_ID_SHFT 0
+#define CA_INTA_N (1ull << 2)
+#define CA_INTB_N (1ull << 3)
+#define CA_CRM_CREDIT_AVAIL (0x7ull << 4)
+#define CA_CRM_CREDIT_AVAIL_SHFT 4
+ /* bit 7 unused */
+#define CA_CRM_SPACE_AVAIL (0x7full << 8)
+#define CA_CRM_SPACE_AVAIL_SHFT 8
+ /* bit 15 unused */
+#define CA_GART_TLB_VAL (0xffull << 16)
+#define CA_GART_TLB_VAL_SHFT 16
+ /* bits 63:24 unused */
+
+/* ==== ca_status2 */
+#define CA_GFX_CREDIT_AVAIL (0xffull << 0)
+#define CA_GFX_CREDIT_AVAIL_SHFT 0
+#define CA_GFX_OPQ_AVAIL (0xffull << 8)
+#define CA_GFX_OPQ_AVAIL_SHFT 8
+#define CA_GFX_WRBUFF_AVAIL (0xffull << 16)
+#define CA_GFX_WRBUFF_AVAIL_SHFT 16
+#define CA_ADMA_OPQ_AVAIL (0xffull << 24)
+#define CA_ADMA_OPQ_AVAIL_SHFT 24
+#define CA_ADMA_WRBUFF_AVAIL (0xffull << 32)
+#define CA_ADMA_WRBUFF_AVAIL_SHFT 32
+#define CA_ADMA_RDBUFF_AVAIL (0x7full << 40)
+#define CA_ADMA_RDBUFF_AVAIL_SHFT 40
+#define CA_PCI_PIO_OP_STAT (1ull << 47)
+#define CA_PDMA_OPQ_AVAIL (0xfull << 48)
+#define CA_PDMA_OPQ_AVAIL_SHFT 48
+#define CA_PDMA_WRBUFF_AVAIL (0xfull << 52)
+#define CA_PDMA_WRBUFF_AVAIL_SHFT 52
+#define CA_PDMA_RDBUFF_AVAIL (0x3ull << 56)
+#define CA_PDMA_RDBUFF_AVAIL_SHFT 56
+ /* bits 63:58 unused */
+
+/* ==== ca_gart_aperature */
+#define CA_GART_AP_ENB_AGP (1ull << 0)
+#define CA_GART_PAGE_SIZE (1ull << 1)
+#define CA_GART_AP_ENB_PCI (1ull << 2)
+ /* bits 11:3 unused */
+#define CA_GART_AP_SIZE (0x3ffull << 12)
+#define CA_GART_AP_SIZE_SHFT 12
+#define CA_GART_AP_BASE (0x3ffffffffffull << 22)
+#define CA_GART_AP_BASE_SHFT 22
+
+/* ==== ca_inta_dest_addr
+ ==== ca_intb_dest_addr
+ ==== ca_err_int_dest_addr */
+ /* bits 2:0 unused */
+#define CA_INT_DEST_ADDR (0x7ffffffffffffull << 3)
+#define CA_INT_DEST_ADDR_SHFT 3
+ /* bits 55:54 unused */
+#define CA_INT_DEST_VECT (0xffull << 56)
+#define CA_INT_DEST_VECT_SHFT 56
+
+/* ==== ca_int_status */
+/* ==== ca_int_status_alias */
+/* ==== ca_mult_error */
+/* ==== ca_mult_error_alias */
+/* ==== ca_first_error */
+/* ==== ca_int_mask */
+#define CA_PCI_ERR (1ull << 0)
+ /* bits 3:1 unused */
+#define CA_GART_FETCH_ERR (1ull << 4)
+#define CA_GFX_WR_OVFLW (1ull << 5)
+#define CA_PIO_REQ_OVFLW (1ull << 6)
+#define CA_CRM_PKTERR (1ull << 7)
+#define CA_CRM_DVERR (1ull << 8)
+#define CA_TNUMTO (1ull << 9)
+#define CA_CXM_RSP_CRED_OVFLW (1ull << 10)
+#define CA_CXM_REQ_CRED_OVFLW (1ull << 11)
+#define CA_PIO_INVALID_ADDR (1ull << 12)
+#define CA_PCI_ARB_TO (1ull << 13)
+#define CA_AGP_REQ_OFLOW (1ull << 14)
+#define CA_SBA_TYPE1_ERR (1ull << 15)
+ /* bit 16 unused */
+#define CA_INTA (1ull << 17)
+#define CA_INTB (1ull << 18)
+#define CA_MULT_INTA (1ull << 19)
+#define CA_MULT_INTB (1ull << 20)
+#define CA_GFX_CREDIT_OVFLW (1ull << 21)
+ /* bits 63:22 unused */
+
+/* ==== ca_crm_pkterr_type */
+/* ==== ca_crm_pkterr_type_alias */
+#define CA_CRM_PKTERR_SBERR_HDR (1ull << 0)
+#define CA_CRM_PKTERR_DIDN (1ull << 1)
+#define CA_CRM_PKTERR_PACTYPE (1ull << 2)
+#define CA_CRM_PKTERR_INV_TNUM (1ull << 3)
+#define CA_CRM_PKTERR_ADDR_RNG (1ull << 4)
+#define CA_CRM_PKTERR_ADDR_ALGN (1ull << 5)
+#define CA_CRM_PKTERR_HDR_PARAM (1ull << 6)
+#define CA_CRM_PKTERR_CW_ERR (1ull << 7)
+#define CA_CRM_PKTERR_SBERR_NH (1ull << 8)
+#define CA_CRM_PKTERR_EARLY_TERM (1ull << 9)
+#define CA_CRM_PKTERR_EARLY_TAIL (1ull << 10)
+#define CA_CRM_PKTERR_MSSNG_TAIL (1ull << 11)
+#define CA_CRM_PKTERR_MSSNG_HDR (1ull << 12)
+ /* bits 15:13 unused */
+#define CA_FIRST_CRM_PKTERR_SBERR_HDR (1ull << 16)
+#define CA_FIRST_CRM_PKTERR_DIDN (1ull << 17)
+#define CA_FIRST_CRM_PKTERR_PACTYPE (1ull << 18)
+#define CA_FIRST_CRM_PKTERR_INV_TNUM (1ull << 19)
+#define CA_FIRST_CRM_PKTERR_ADDR_RNG (1ull << 20)
+#define CA_FIRST_CRM_PKTERR_ADDR_ALGN (1ull << 21)
+#define CA_FIRST_CRM_PKTERR_HDR_PARAM (1ull << 22)
+#define CA_FIRST_CRM_PKTERR_CW_ERR (1ull << 23)
+#define CA_FIRST_CRM_PKTERR_SBERR_NH (1ull << 24)
+#define CA_FIRST_CRM_PKTERR_EARLY_TERM (1ull << 25)
+#define CA_FIRST_CRM_PKTERR_EARLY_TAIL (1ull << 26)
+#define CA_FIRST_CRM_PKTERR_MSSNG_TAIL (1ull << 27)
+#define CA_FIRST_CRM_PKTERR_MSSNG_HDR (1ull << 28)
+ /* bits 63:29 unused */
+
+/* ==== ca_crm_ct_error_detail_1 */
+#define CA_PKT_TYPE (0xfull << 0)
+#define CA_PKT_TYPE_SHFT 0
+#define CA_SRC_ID (0x3ull << 4)
+#define CA_SRC_ID_SHFT 4
+#define CA_DATA_SZ (0x3ull << 6)
+#define CA_DATA_SZ_SHFT 6
+#define CA_TNUM (0xffull << 8)
+#define CA_TNUM_SHFT 8
+#define CA_DW_DATA_EN (0xffull << 16)
+#define CA_DW_DATA_EN_SHFT 16
+#define CA_GFX_CRED (0xffull << 24)
+#define CA_GFX_CRED_SHFT 24
+#define CA_MEM_RD_PARAM (0x3ull << 32)
+#define CA_MEM_RD_PARAM_SHFT 32
+#define CA_PIO_OP (1ull << 34)
+#define CA_CW_ERR (1ull << 35)
+ /* bits 62:36 unused */
+#define CA_VALID (1ull << 63)
+
+/* ==== ca_crm_ct_error_detail_2 */
+ /* bits 2:0 unused */
+#define CA_PKT_ADDR (0x1fffffffffffffull << 3)
+#define CA_PKT_ADDR_SHFT 3
+ /* bits 63:56 unused */
+
+/* ==== ca_crm_tnumto */
+#define CA_CRM_TNUMTO_VAL (0xffull << 0)
+#define CA_CRM_TNUMTO_VAL_SHFT 0
+#define CA_CRM_TNUMTO_WR (1ull << 8)
+ /* bits 63:9 unused */
+
+/* ==== ca_gart_err */
+#define CA_GART_ERR_SOURCE (0x3ull << 0)
+#define CA_GART_ERR_SOURCE_SHFT 0
+ /* bits 3:2 unused */
+#define CA_GART_ERR_ADDR (0xfffffffffull << 4)
+#define CA_GART_ERR_ADDR_SHFT 4
+ /* bits 63:40 unused */
+
+/* ==== ca_pcierr_type */
+#define CA_PCIERR_DATA (0xffffffffull << 0)
+#define CA_PCIERR_DATA_SHFT 0
+#define CA_PCIERR_ENB (0xfull << 32)
+#define CA_PCIERR_ENB_SHFT 32
+#define CA_PCIERR_CMD (0xfull << 36)
+#define CA_PCIERR_CMD_SHFT 36
+#define CA_PCIERR_A64 (1ull << 40)
+#define CA_PCIERR_SLV_SERR (1ull << 41)
+#define CA_PCIERR_SLV_WR_PERR (1ull << 42)
+#define CA_PCIERR_SLV_RD_PERR (1ull << 43)
+#define CA_PCIERR_MST_SERR (1ull << 44)
+#define CA_PCIERR_MST_WR_PERR (1ull << 45)
+#define CA_PCIERR_MST_RD_PERR (1ull << 46)
+#define CA_PCIERR_MST_MABT (1ull << 47)
+#define CA_PCIERR_MST_TABT (1ull << 48)
+#define CA_PCIERR_MST_RETRY_TOUT (1ull << 49)
+
+#define CA_PCIERR_TYPES \
+ (CA_PCIERR_A64|CA_PCIERR_SLV_SERR| \
+ CA_PCIERR_SLV_WR_PERR|CA_PCIERR_SLV_RD_PERR| \
+ CA_PCIERR_MST_SERR|CA_PCIERR_MST_WR_PERR|CA_PCIERR_MST_RD_PERR| \
+ CA_PCIERR_MST_MABT|CA_PCIERR_MST_TABT|CA_PCIERR_MST_RETRY_TOUT)
+
+ /* bits 63:50 unused */
+
+/* ==== ca_pci_dma_addr_extn */
+#define CA_UPPER_NODE_OFFSET (0x3full << 0)
+#define CA_UPPER_NODE_OFFSET_SHFT 0
+ /* bits 7:6 unused */
+#define CA_CHIPLET_ID (0x3ull << 8)
+#define CA_CHIPLET_ID_SHFT 8
+ /* bits 11:10 unused */
+#define CA_PCI_DMA_NODE_ID (0xffffull << 12)
+#define CA_PCI_DMA_NODE_ID_SHFT 12
+ /* bits 27:26 unused */
+#define CA_PCI_DMA_PIO_MEM_TYPE (1ull << 28)
+ /* bits 63:29 unused */
+
+
+/* ==== ca_agp_dma_addr_extn */
+ /* bits 19:0 unused */
+#define CA_AGP_DMA_NODE_ID (0xffffull << 20)
+#define CA_AGP_DMA_NODE_ID_SHFT 20
+ /* bits 27:26 unused */
+#define CA_AGP_DMA_PIO_MEM_TYPE (1ull << 28)
+ /* bits 63:29 unused */
+
+/* ==== ca_debug_vector_sel */
+#define CA_DEBUG_MN_VSEL (0xfull << 0)
+#define CA_DEBUG_MN_VSEL_SHFT 0
+#define CA_DEBUG_PP_VSEL (0xfull << 4)
+#define CA_DEBUG_PP_VSEL_SHFT 4
+#define CA_DEBUG_GW_VSEL (0xfull << 8)
+#define CA_DEBUG_GW_VSEL_SHFT 8
+#define CA_DEBUG_GT_VSEL (0xfull << 12)
+#define CA_DEBUG_GT_VSEL_SHFT 12
+#define CA_DEBUG_PD_VSEL (0xfull << 16)
+#define CA_DEBUG_PD_VSEL_SHFT 16
+#define CA_DEBUG_AD_VSEL (0xfull << 20)
+#define CA_DEBUG_AD_VSEL_SHFT 20
+#define CA_DEBUG_CX_VSEL (0xfull << 24)
+#define CA_DEBUG_CX_VSEL_SHFT 24
+#define CA_DEBUG_CR_VSEL (0xfull << 28)
+#define CA_DEBUG_CR_VSEL_SHFT 28
+#define CA_DEBUG_BA_VSEL (0xfull << 32)
+#define CA_DEBUG_BA_VSEL_SHFT 32
+#define CA_DEBUG_PE_VSEL (0xfull << 36)
+#define CA_DEBUG_PE_VSEL_SHFT 36
+#define CA_DEBUG_BO_VSEL (0xfull << 40)
+#define CA_DEBUG_BO_VSEL_SHFT 40
+#define CA_DEBUG_BI_VSEL (0xfull << 44)
+#define CA_DEBUG_BI_VSEL_SHFT 44
+#define CA_DEBUG_AS_VSEL (0xfull << 48)
+#define CA_DEBUG_AS_VSEL_SHFT 48
+#define CA_DEBUG_PS_VSEL (0xfull << 52)
+#define CA_DEBUG_PS_VSEL_SHFT 52
+#define CA_DEBUG_PM_VSEL (0xfull << 56)
+#define CA_DEBUG_PM_VSEL_SHFT 56
+ /* bits 63:60 unused */
+
+/* ==== ca_debug_mux_core_sel */
+/* ==== ca_debug_mux_pci_sel */
+#define CA_DEBUG_MSEL0 (0x7ull << 0)
+#define CA_DEBUG_MSEL0_SHFT 0
+ /* bit 3 unused */
+#define CA_DEBUG_NSEL0 (0x7ull << 4)
+#define CA_DEBUG_NSEL0_SHFT 4
+ /* bit 7 unused */
+#define CA_DEBUG_MSEL1 (0x7ull << 8)
+#define CA_DEBUG_MSEL1_SHFT 8
+ /* bit 11 unused */
+#define CA_DEBUG_NSEL1 (0x7ull << 12)
+#define CA_DEBUG_NSEL1_SHFT 12
+ /* bit 15 unused */
+#define CA_DEBUG_MSEL2 (0x7ull << 16)
+#define CA_DEBUG_MSEL2_SHFT 16
+ /* bit 19 unused */
+#define CA_DEBUG_NSEL2 (0x7ull << 20)
+#define CA_DEBUG_NSEL2_SHFT 20
+ /* bit 23 unused */
+#define CA_DEBUG_MSEL3 (0x7ull << 24)
+#define CA_DEBUG_MSEL3_SHFT 24
+ /* bit 27 unused */
+#define CA_DEBUG_NSEL3 (0x7ull << 28)
+#define CA_DEBUG_NSEL3_SHFT 28
+ /* bit 31 unused */
+#define CA_DEBUG_MSEL4 (0x7ull << 32)
+#define CA_DEBUG_MSEL4_SHFT 32
+ /* bit 35 unused */
+#define CA_DEBUG_NSEL4 (0x7ull << 36)
+#define CA_DEBUG_NSEL4_SHFT 36
+ /* bit 39 unused */
+#define CA_DEBUG_MSEL5 (0x7ull << 40)
+#define CA_DEBUG_MSEL5_SHFT 40
+ /* bit 43 unused */
+#define CA_DEBUG_NSEL5 (0x7ull << 44)
+#define CA_DEBUG_NSEL5_SHFT 44
+ /* bit 47 unused */
+#define CA_DEBUG_MSEL6 (0x7ull << 48)
+#define CA_DEBUG_MSEL6_SHFT 48
+ /* bit 51 unused */
+#define CA_DEBUG_NSEL6 (0x7ull << 52)
+#define CA_DEBUG_NSEL6_SHFT 52
+ /* bit 55 unused */
+#define CA_DEBUG_MSEL7 (0x7ull << 56)
+#define CA_DEBUG_MSEL7_SHFT 56
+ /* bit 59 unused */
+#define CA_DEBUG_NSEL7 (0x7ull << 60)
+#define CA_DEBUG_NSEL7_SHFT 60
+ /* bit 63 unused */
+
+
+/* ==== ca_debug_domain_sel */
+#define CA_DEBUG_DOMAIN_L (1ull << 0)
+#define CA_DEBUG_DOMAIN_H (1ull << 1)
+ /* bits 63:2 unused */
+
+/* ==== ca_gart_ptr_table */
+#define CA_GART_PTR_VAL (1ull << 0)
+ /* bits 11:1 unused */
+#define CA_GART_PTR_ADDR (0xfffffffffffull << 12)
+#define CA_GART_PTR_ADDR_SHFT 12
+ /* bits 63:56 unused */
+
+/* ==== ca_gart_tlb_addr[0-7] */
+#define CA_GART_TLB_ADDR (0xffffffffffffffull << 0)
+#define CA_GART_TLB_ADDR_SHFT 0
+ /* bits 62:56 unused */
+#define CA_GART_TLB_ENTRY_VAL (1ull << 63)
+
+/*
+ * PIO address space ranges for TIO:CA
+ */
+
+/* CA internal registers */
+#define CA_PIO_ADMIN 0x00000000
+#define CA_PIO_ADMIN_LEN 0x00010000
+
+/* GFX Write Buffer - Diagnostics */
+#define CA_PIO_GFX 0x00010000
+#define CA_PIO_GFX_LEN 0x00010000
+
+/* AGP DMA Write Buffer - Diagnostics */
+#define CA_PIO_AGP_DMAWRITE 0x00020000
+#define CA_PIO_AGP_DMAWRITE_LEN 0x00010000
+
+/* AGP DMA READ Buffer - Diagnostics */
+#define CA_PIO_AGP_DMAREAD 0x00030000
+#define CA_PIO_AGP_DMAREAD_LEN 0x00010000
+
+/* PCI Config Type 0 */
+#define CA_PIO_PCI_TYPE0_CONFIG 0x01000000
+#define CA_PIO_PCI_TYPE0_CONFIG_LEN 0x01000000
+
+/* PCI Config Type 1 */
+#define CA_PIO_PCI_TYPE1_CONFIG 0x02000000
+#define CA_PIO_PCI_TYPE1_CONFIG_LEN 0x01000000
+
+/* PCI I/O Cycles - mapped to PCI Address 0x00000000-0x04ffffff */
+#define CA_PIO_PCI_IO 0x03000000
+#define CA_PIO_PCI_IO_LEN 0x05000000
+
+/* PCI MEM Cycles - mapped to PCI with CA_PIO_ADDR_OFFSET of ca_control1 */
+/* use Fast Write if enabled and coretalk packet type is a GFX request */
+#define CA_PIO_PCI_MEM_OFFSET 0x08000000
+#define CA_PIO_PCI_MEM_OFFSET_LEN 0x08000000
+
+/* PCI MEM Cycles - mapped to PCI Address 0x00000000-0xbfffffff */
+/* use Fast Write if enabled and coretalk packet type is a GFX request */
+#define CA_PIO_PCI_MEM 0x40000000
+#define CA_PIO_PCI_MEM_LEN 0xc0000000
+
+/*
+ * DMA space
+ *
+ * The CA aperature (ie. bus address range) mapped by the GART is segmented into
+ * two parts. The lower portion of the aperature is used for mapping 32 bit
+ * PCI addresses which are managed by the dma interfaces in this file. The
+ * upper poprtion of the aperature is used for mapping 48 bit AGP addresses.
+ * The AGP portion of the aperature is managed by the agpgart_be.c driver
+ * in drivers/linux/agp. There are ca-specific hooks in that driver to
+ * manipulate the gart, but management of the AGP portion of the aperature
+ * is the responsibility of that driver.
+ *
+ * CA allows three main types of DMA mapping:
+ *
+ * PCI 64-bit Managed by this driver
+ * PCI 32-bit Managed by this driver
+ * AGP 48-bit Managed by hooks in the /dev/agpgart driver
+ *
+ * All of the above can optionally be remapped through the GART. The following
+ * table lists the combinations of addressing types and GART remapping that
+ * is currently supported by the driver (h/w supports all, s/w limits this):
+ *
+ * PCI64 PCI32 AGP48
+ * GART no yes yes
+ * Direct yes yes no
+ *
+ * GART remapping of PCI64 is not done because there is no need to. The
+ * 64 bit PCI address holds all of the information necessary to target any
+ * memory in the system.
+ *
+ * AGP48 is always mapped through the GART. Management of the AGP48 portion
+ * of the aperature is the responsibility of code in the agpgart_be driver.
+ *
+ * The non-64 bit bus address space will currently be partitioned like this:
+ *
+ * 0xffff_ffff_ffff +--------
+ * | AGP48 direct
+ * | Space managed by this driver
+ * CA_AGP_DIRECT_BASE +--------
+ * | AGP GART mapped (gfx aperature)
+ * | Space managed by /dev/agpgart driver
+ * | This range is exposed to the agpgart
+ * | driver as the "graphics aperature"
+ * CA_AGP_MAPPED_BASE +-----
+ * | PCI GART mapped
+ * | Space managed by this driver
+ * CA_PCI32_MAPPED_BASE +----
+ * | PCI32 direct
+ * | Space managed by this driver
+ * 0xC000_0000 +--------
+ * (CA_PCI32_DIRECT_BASE)
+ *
+ * The bus address range CA_PCI32_MAPPED_BASE through CA_AGP_DIRECT_BASE
+ * is what we call the CA aperature. Addresses falling in this range will
+ * be remapped using the GART.
+ *
+ * The bus address range CA_AGP_MAPPED_BASE through CA_AGP_DIRECT_BASE
+ * is what we call the graphics aperature. This is a subset of the CA
+ * aperature and is under the control of the agpgart_be driver.
+ *
+ * CA_PCI32_MAPPED_BASE, CA_AGP_MAPPED_BASE, and CA_AGP_DIRECT_BASE are
+ * somewhat arbitrary values. The known constraints on choosing these is:
+ *
+ * 1) CA_AGP_DIRECT_BASE-CA_PCI32_MAPPED_BASE+1 (the CA aperature size)
+ * must be one of the values supported by the ca_gart_aperature register.
+ * Currently valid values are: 4MB through 4096MB in powers of 2 increments
+ *
+ * 2) CA_AGP_DIRECT_BASE-CA_AGP_MAPPED_BASE+1 (the gfx aperature size)
+ * must be in MB units since that's what the agpgart driver assumes.
+ */
+
+/*
+ * Define Bus DMA ranges. These are configurable (see constraints above)
+ * and will probably need tuning based on experience.
+ */
+
+
+/*
+ * 11/24/03
+ * CA has an addressing glitch w.r.t. PCI direct 32 bit DMA that makes it
+ * generally unusable. The problem is that for PCI direct 32
+ * DMA's, all 32 bits of the bus address are used to form the lower 32 bits
+ * of the coretalk address, and coretalk bits 38:32 come from a register.
+ * Since only PCI bus addresses 0xC0000000-0xFFFFFFFF (1GB) are available
+ * for DMA (the rest is allocated to PIO), host node addresses need to be
+ * such that their lower 32 bits fall in the 0xC0000000-0xffffffff range
+ * as well. So there can be no PCI32 direct DMA below 3GB!! For this
+ * reason we set the CA_PCI32_DIRECT_SIZE to 0 which essentially makes
+ * tioca_dma_direct32() a noop but preserves the code flow should this issue
+ * be fixed in a respin.
+ *
+ * For now, all PCI32 DMA's must be mapped through the GART.
+ */
+
+#define CA_PCI32_DIRECT_BASE 0xC0000000UL /* BASE not configurable */
+#define CA_PCI32_DIRECT_SIZE 0x00000000UL /* 0 MB */
+
+#define CA_PCI32_MAPPED_BASE 0xC0000000UL
+#define CA_PCI32_MAPPED_SIZE 0x40000000UL /* 2GB */
+
+#define CA_AGP_MAPPED_BASE 0x80000000UL
+#define CA_AGP_MAPPED_SIZE 0x40000000UL /* 2GB */
+
+#define CA_AGP_DIRECT_BASE 0x40000000UL /* 2GB */
+#define CA_AGP_DIRECT_SIZE 0x40000000UL
+
+#define CA_APERATURE_BASE (CA_AGP_MAPPED_BASE)
+#define CA_APERATURE_SIZE (CA_AGP_MAPPED_SIZE+CA_PCI32_MAPPED_SIZE)
+
+#endif /* _ASM_IA64_SN_TIO_TIOCA_H */
--- /dev/null
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (c) 2005 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#ifndef _ASM_IA64_SN_TIO_TIOCX_H
+#define _ASM_IA64_SN_TIO_TIOCX_H
+
+#ifdef __KERNEL__
+
+struct cx_id_s {
+ unsigned int part_num;
+ unsigned int mfg_num;
+ int nasid;
+};
+
+struct cx_dev {
+ struct cx_id_s cx_id;
+ void *soft; /* driver specific */
+ struct hubdev_info *hubdev;
+ struct device dev;
+ struct cx_drv *driver;
+};
+
+struct cx_device_id {
+ unsigned int part_num;
+ unsigned int mfg_num;
+};
+
+struct cx_drv {
+ char *name;
+ const struct cx_device_id *id_table;
+ struct device_driver driver;
+ int (*probe) (struct cx_dev * dev, const struct cx_device_id * id);
+ int (*remove) (struct cx_dev * dev);
+};
+
+/* create DMA address by stripping AS bits */
+#define TIOCX_DMA_ADDR(a) (uint64_t)((uint64_t)(a) & 0xffffcfffffffffUL)
+
+#define TIOCX_TO_TIOCX_DMA_ADDR(a) (uint64_t)(((uint64_t)(a) & 0xfffffffff) | \
+ ((((uint64_t)(a)) & 0xffffc000000000UL) <<2))
+
+#define TIO_CE_ASIC_PARTNUM 0xce00
+#define TIOCX_CORELET 3
+
+/* These are taken from tio_mmr_as.h */
+#define TIO_ICE_FRZ_CFG TIO_MMR_ADDR_MOD(0x00000000b0008100UL)
+#define TIO_ICE_PMI_TX_CFG TIO_MMR_ADDR_MOD(0x00000000b000b100UL)
+#define TIO_ICE_PMI_TX_DYN_CREDIT_STAT_CB3 TIO_MMR_ADDR_MOD(0x00000000b000be18UL)
+#define TIO_ICE_PMI_TX_DYN_CREDIT_STAT_CB3_CREDIT_CNT_MASK 0x000000000000000fUL
+
+#define to_cx_dev(n) container_of(n, struct cx_dev, dev)
+#define to_cx_driver(drv) container_of(drv, struct cx_drv, driver)
+
+extern struct sn_irq_info *tiocx_irq_alloc(nasid_t, int, int, nasid_t, int);
+extern void tiocx_irq_free(struct sn_irq_info *);
+extern int cx_device_unregister(struct cx_dev *);
+extern int cx_device_register(nasid_t, int, int, struct hubdev_info *);
+extern int cx_driver_unregister(struct cx_drv *);
+extern int cx_driver_register(struct cx_drv *);
+extern uint64_t tiocx_dma_addr(uint64_t addr);
+extern uint64_t tiocx_swin_base(int nasid);
+extern void tiocx_mmr_store(int nasid, uint64_t offset, uint64_t value);
+extern uint64_t tiocx_mmr_load(int nasid, uint64_t offset);
+
+#endif // __KERNEL__
+#endif // _ASM_IA64_SN_TIO_TIOCX__
--- /dev/null
+/*
+ * Include file for NEC VR4100 series PCI Control Unit.
+ *
+ * Copyright (C) 2004-2005 Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
+ *
+ * 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
+ */
+#ifndef __NEC_VR41XX_PCI_H
+#define __NEC_VR41XX_PCI_H
+
+#define PCI_MASTER_ADDRESS_MASK 0x7fffffffU
+
+struct pci_master_address_conversion {
+ uint32_t bus_base_address;
+ uint32_t address_mask;
+ uint32_t pci_base_address;
+};
+
+struct pci_target_address_conversion {
+ uint32_t address_mask;
+ uint32_t bus_base_address;
+};
+
+typedef enum {
+ CANNOT_LOCK_FROM_DEVICE,
+ CAN_LOCK_FROM_DEVICE,
+} pci_exclusive_access_t;
+
+struct pci_mailbox_address {
+ uint32_t base_address;
+};
+
+struct pci_target_address_window {
+ uint32_t base_address;
+};
+
+typedef enum {
+ PCI_ARBITRATION_MODE_FAIR,
+ PCI_ARBITRATION_MODE_ALTERNATE_0,
+ PCI_ARBITRATION_MODE_ALTERNATE_B,
+} pci_arbiter_priority_control_t;
+
+typedef enum {
+ PCI_TAKE_AWAY_GNT_DISABLE,
+ PCI_TAKE_AWAY_GNT_ENABLE,
+} pci_take_away_gnt_mode_t;
+
+struct pci_controller_unit_setup {
+ struct pci_master_address_conversion *master_memory1;
+ struct pci_master_address_conversion *master_memory2;
+
+ struct pci_target_address_conversion *target_memory1;
+ struct pci_target_address_conversion *target_memory2;
+
+ struct pci_master_address_conversion *master_io;
+
+ pci_exclusive_access_t exclusive_access;
+
+ uint32_t pci_clock_max;
+ uint8_t wait_time_limit_from_irdy_to_trdy; /* Only VR4122 is supported */
+
+ struct pci_mailbox_address *mailbox;
+ struct pci_target_address_window *target_window1;
+ struct pci_target_address_window *target_window2;
+
+ uint8_t master_latency_timer;
+ uint8_t retry_limit;
+
+ pci_arbiter_priority_control_t arbiter_priority_control;
+ pci_take_away_gnt_mode_t take_away_gnt_mode;
+
+ struct resource *mem_resource;
+ struct resource *io_resource;
+};
+
+extern void vr41xx_pciu_setup(struct pci_controller_unit_setup *setup);
+
+#endif /* __NEC_VR41XX_PCI_H */
--- /dev/null
+/*
+ * Include file for NEC VR4100 series Serial Interface Unit.
+ *
+ * Copyright (C) 2005 Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
+ *
+ * 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
+ */
+#ifndef __NEC_VR41XX_SIU_H
+#define __NEC_VR41XX_SIU_H
+
+typedef enum {
+ SIU_INTERFACE_RS232C,
+ SIU_INTERFACE_IRDA,
+} siu_interface_t;
+
+extern void vr41xx_select_siu_interface(siu_interface_t interface);
+
+typedef enum {
+ SIU_USE_IRDA,
+ FIR_USE_IRDA,
+} irda_use_t;
+
+extern void vr41xx_use_irda(irda_use_t use);
+
+typedef enum {
+ SHARP_IRDA,
+ TEMIC_IRDA,
+ HP_IRDA,
+} irda_module_t;
+
+typedef enum {
+ IRDA_TX_1_5MBPS,
+ IRDA_TX_4MBPS,
+} irda_speed_t;
+
+extern void vr41xx_select_irda_module(irda_module_t module, irda_speed_t speed);
+
+#endif /* __NEC_VR41XX_SIU_H */
--- /dev/null
+static inline int arch_prepare_suspend(void)
+{
+ return 0;
+}
+
+static inline void save_processor_state(void)
+{
+}
+
+static inline void restore_processor_state(void)
+{
+}
--- /dev/null
+/*
+ * include/asm-sh/cpu-sh4/timer.h
+ *
+ * Copyright (C) 2004 Lineo Solutions, Inc.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#ifndef __ASM_CPU_SH4_TIMER_H
+#define __ASM_CPU_SH4_TIMER_H
+
+/*
+ * ---------------------------------------------------------------------------
+ * TMU Common definitions for SH4 processors
+ * SH7750S/SH7750R
+ * SH7751/SH7751R
+ * SH7760
+ * ---------------------------------------------------------------------------
+ */
+
+#if !defined(CONFIG_CPU_SUBTYPE_SH7760)
+#define TMU_TOCR 0xffd80000 /* Byte access */
+#endif
+#define TMU_TSTR 0xffd80004 /* Byte access */
+
+#define TMU0_TCOR 0xffd80008 /* Long access */
+#define TMU0_TCNT 0xffd8000c /* Long access */
+#define TMU0_TCR 0xffd80010 /* Word access */
+
+#define TMU1_TCOR 0xffd80014 /* Long access */
+#define TMU1_TCNT 0xffd80018 /* Long access */
+#define TMU1_TCR 0xffd8001c /* Word access */
+
+#define TMU2_TCOR 0xffd80020 /* Long access */
+#define TMU2_TCNT 0xffd80024 /* Long access */
+#define TMU2_TCR 0xffd80028 /* Word access */
+#define TMU2_TCPR 0xffd8002c /* Long access */
+
+#if !defined(CONFIG_CPU_SUBTYPE_SH7760)
+#define TMU3_TCOR 0xfe100008 /* Long access */
+#define TMU3_TCNT 0xfe10000c /* Long access */
+#define TMU3_TCR 0xfe100010 /* Word access */
+
+#define TMU4_TCOR 0xfe100014 /* Long access */
+#define TMU4_TCNT 0xfe100018 /* Long access */
+#define TMU4_TCR 0xfe10001c /* Word access */
+#endif
+
+#endif /* __ASM_CPU_SH4_TIMER_H */
+
--- /dev/null
+/* rwsem-const.h: RW semaphore counter constants. */
+#ifndef _SPARC64_RWSEM_CONST_H
+#define _SPARC64_RWSEM_CONST_H
+
+#define RWSEM_UNLOCKED_VALUE 0x00000000
+#define RWSEM_ACTIVE_BIAS 0x00000001
+#define RWSEM_ACTIVE_MASK 0x0000ffff
+#define RWSEM_WAITING_BIAS 0xffff0000
+#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS
+#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
+
+#endif /* _SPARC64_RWSEM_CONST_H */
--- /dev/null
+/*
+ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+#ifndef __UM_ELF_I386_H
+#define __UM_ELF_I386_H
+
+#include <asm/user.h>
+
+#define R_386_NONE 0
+#define R_386_32 1
+#define R_386_PC32 2
+#define R_386_GOT32 3
+#define R_386_PLT32 4
+#define R_386_COPY 5
+#define R_386_GLOB_DAT 6
+#define R_386_JMP_SLOT 7
+#define R_386_RELATIVE 8
+#define R_386_GOTOFF 9
+#define R_386_GOTPC 10
+#define R_386_NUM 11
+
+typedef unsigned long elf_greg_t;
+
+#define ELF_NGREG (sizeof (struct user_regs_struct) / sizeof(elf_greg_t))
+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+
+typedef struct user_i387_struct elf_fpregset_t;
+
+/*
+ * This is used to ensure we don't load something for the wrong architecture.
+ */
+#define elf_check_arch(x) \
+ (((x)->e_machine == EM_386) || ((x)->e_machine == EM_486))
+
+#define ELF_CLASS ELFCLASS32
+#define ELF_DATA ELFDATA2LSB
+#define ELF_ARCH EM_386
+
+#define ELF_PLAT_INIT(regs, load_addr) do { \
+ PT_REGS_EBX(regs) = 0; \
+ PT_REGS_ECX(regs) = 0; \
+ PT_REGS_EDX(regs) = 0; \
+ PT_REGS_ESI(regs) = 0; \
+ PT_REGS_EDI(regs) = 0; \
+ PT_REGS_EBP(regs) = 0; \
+ PT_REGS_EAX(regs) = 0; \
+} while(0)
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE 4096
+
+#define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3)
+
+/* Shamelessly stolen from include/asm-i386/elf.h */
+
+#define ELF_CORE_COPY_REGS(pr_reg, regs) do { \
+ pr_reg[0] = PT_REGS_EBX(regs); \
+ pr_reg[1] = PT_REGS_ECX(regs); \
+ pr_reg[2] = PT_REGS_EDX(regs); \
+ pr_reg[3] = PT_REGS_ESI(regs); \
+ pr_reg[4] = PT_REGS_EDI(regs); \
+ pr_reg[5] = PT_REGS_EBP(regs); \
+ pr_reg[6] = PT_REGS_EAX(regs); \
+ pr_reg[7] = PT_REGS_DS(regs); \
+ pr_reg[8] = PT_REGS_ES(regs); \
+ /* fake once used fs and gs selectors? */ \
+ pr_reg[9] = PT_REGS_DS(regs); \
+ pr_reg[10] = PT_REGS_DS(regs); \
+ pr_reg[11] = PT_REGS_SYSCALL_NR(regs); \
+ pr_reg[12] = PT_REGS_IP(regs); \
+ pr_reg[13] = PT_REGS_CS(regs); \
+ pr_reg[14] = PT_REGS_EFLAGS(regs); \
+ pr_reg[15] = PT_REGS_SP(regs); \
+ pr_reg[16] = PT_REGS_SS(regs); \
+} while(0);
+
+extern long elf_aux_hwcap;
+#define ELF_HWCAP (elf_aux_hwcap)
+
+extern char * elf_aux_platform;
+#define ELF_PLATFORM (elf_aux_platform)
+
+#define SET_PERSONALITY(ex, ibcs2) do ; while(0)
+
+extern unsigned long vsyscall_ehdr;
+extern unsigned long vsyscall_end;
+extern unsigned long __kernel_vsyscall;
+
+#define VSYSCALL_BASE vsyscall_ehdr
+#define VSYSCALL_END vsyscall_end
+
+/*
+ * This is the range that is readable by user mode, and things
+ * acting like user mode such as get_user_pages.
+ */
+#define FIXADDR_USER_START VSYSCALL_BASE
+#define FIXADDR_USER_END VSYSCALL_END
+
+/*
+ * Architecture-neutral AT_ values in 0-17, leave some room
+ * for more of them, start the x86-specific ones at 32.
+ */
+#define AT_SYSINFO 32
+#define AT_SYSINFO_EHDR 33
+
+#define ARCH_DLINFO \
+do { \
+ if ( vsyscall_ehdr ) { \
+ NEW_AUX_ENT(AT_SYSINFO, __kernel_vsyscall); \
+ NEW_AUX_ENT(AT_SYSINFO_EHDR, vsyscall_ehdr); \
+ } \
+} while (0)
+
+/*
+ * These macros parameterize elf_core_dump in fs/binfmt_elf.c to write out
+ * extra segments containing the vsyscall DSO contents. Dumping its
+ * contents makes post-mortem fully interpretable later without matching up
+ * the same kernel and hardware config to see what PC values meant.
+ * Dumping its extra ELF program headers includes all the other information
+ * a debugger needs to easily find how the vsyscall DSO was being used.
+ */
+#define ELF_CORE_EXTRA_PHDRS \
+ (vsyscall_ehdr ? (((struct elfhdr *)vsyscall_ehdr)->e_phnum) : 0 )
+
+#define ELF_CORE_WRITE_EXTRA_PHDRS \
+if ( vsyscall_ehdr ) { \
+ const struct elfhdr *const ehdrp = (struct elfhdr *)vsyscall_ehdr; \
+ const struct elf_phdr *const phdrp = \
+ (const struct elf_phdr *) (vsyscall_ehdr + ehdrp->e_phoff); \
+ int i; \
+ Elf32_Off ofs = 0; \
+ for (i = 0; i < ehdrp->e_phnum; ++i) { \
+ struct elf_phdr phdr = phdrp[i]; \
+ if (phdr.p_type == PT_LOAD) { \
+ ofs = phdr.p_offset = offset; \
+ offset += phdr.p_filesz; \
+ } \
+ else \
+ phdr.p_offset += ofs; \
+ phdr.p_paddr = 0; /* match other core phdrs */ \
+ DUMP_WRITE(&phdr, sizeof(phdr)); \
+ } \
+}
+#define ELF_CORE_WRITE_EXTRA_DATA \
+if ( vsyscall_ehdr ) { \
+ const struct elfhdr *const ehdrp = (struct elfhdr *)vsyscall_ehdr; \
+ const struct elf_phdr *const phdrp = \
+ (const struct elf_phdr *) (vsyscall_ehdr + ehdrp->e_phoff); \
+ int i; \
+ for (i = 0; i < ehdrp->e_phnum; ++i) { \
+ if (phdrp[i].p_type == PT_LOAD) \
+ DUMP_WRITE((void *) phdrp[i].p_vaddr, \
+ phdrp[i].p_filesz); \
+ } \
+}
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
--- /dev/null
+/*
+ * Copyright 2003 PathScale, Inc.
+ *
+ * Licensed under the GPL
+ */
+#ifndef __UM_ELF_X86_64_H
+#define __UM_ELF_X86_64_H
+
+#include <asm/user.h>
+
+/* x86-64 relocation types, taken from asm-x86_64/elf.h */
+#define R_X86_64_NONE 0 /* No reloc */
+#define R_X86_64_64 1 /* Direct 64 bit */
+#define R_X86_64_PC32 2 /* PC relative 32 bit signed */
+#define R_X86_64_GOT32 3 /* 32 bit GOT entry */
+#define R_X86_64_PLT32 4 /* 32 bit PLT address */
+#define R_X86_64_COPY 5 /* Copy symbol at runtime */
+#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */
+#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */
+#define R_X86_64_RELATIVE 8 /* Adjust by program base */
+#define R_X86_64_GOTPCREL 9 /* 32 bit signed pc relative
+ offset to GOT */
+#define R_X86_64_32 10 /* Direct 32 bit zero extended */
+#define R_X86_64_32S 11 /* Direct 32 bit sign extended */
+#define R_X86_64_16 12 /* Direct 16 bit zero extended */
+#define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */
+#define R_X86_64_8 14 /* Direct 8 bit sign extended */
+#define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */
+
+#define R_X86_64_NUM 16
+
+typedef unsigned long elf_greg_t;
+
+#define ELF_NGREG (sizeof (struct user_regs_struct) / sizeof(elf_greg_t))
+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+
+typedef struct { } elf_fpregset_t;
+
+/*
+ * This is used to ensure we don't load something for the wrong architecture.
+ */
+#define elf_check_arch(x) \
+ ((x)->e_machine == EM_X86_64)
+
+#define ELF_CLASS ELFCLASS64
+#define ELF_DATA ELFDATA2LSB
+#define ELF_ARCH EM_X86_64
+
+#define ELF_PLAT_INIT(regs, load_addr) do { \
+ PT_REGS_RBX(regs) = 0; \
+ PT_REGS_RCX(regs) = 0; \
+ PT_REGS_RDX(regs) = 0; \
+ PT_REGS_RSI(regs) = 0; \
+ PT_REGS_RDI(regs) = 0; \
+ PT_REGS_RBP(regs) = 0; \
+ PT_REGS_RAX(regs) = 0; \
+ PT_REGS_R8(regs) = 0; \
+ PT_REGS_R9(regs) = 0; \
+ PT_REGS_R10(regs) = 0; \
+ PT_REGS_R11(regs) = 0; \
+ PT_REGS_R12(regs) = 0; \
+ PT_REGS_R13(regs) = 0; \
+ PT_REGS_R14(regs) = 0; \
+ PT_REGS_R15(regs) = 0; \
+} while (0)
+
+#ifdef TIF_IA32 /* XXX */
+#error XXX, indeed
+ clear_thread_flag(TIF_IA32);
+#endif
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE 4096
+
+#define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3)
+
+extern long elf_aux_hwcap;
+#define ELF_HWCAP (elf_aux_hwcap)
+
+#define ELF_PLATFORM "x86_64"
+
+#define SET_PERSONALITY(ex, ibcs2) do ; while(0)
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
--- /dev/null
+#ifndef _ASM_SECCOMP_H
+
+#include <linux/thread_info.h>
+
+#ifdef TIF_32BIT
+#error "unexpected TIF_32BIT on x86_64"
+#else
+#define TIF_32BIT TIF_IA32
+#endif
+
+#include <linux/unistd.h>
+#include <asm/ia32_unistd.h>
+
+#define __NR_seccomp_read __NR_read
+#define __NR_seccomp_write __NR_write
+#define __NR_seccomp_exit __NR_exit
+#define __NR_seccomp_sigreturn __NR_rt_sigreturn
+
+#define __NR_seccomp_read_32 __NR_ia32_read
+#define __NR_seccomp_write_32 __NR_ia32_write
+#define __NR_seccomp_exit_32 __NR_ia32_exit
+#define __NR_seccomp_sigreturn_32 __NR_ia32_sigreturn
+
+#endif /* _ASM_SECCOMP_H */
--- /dev/null
+/* Never include this file directly. Include <linux/compiler.h> instead. */
+
+/* These definitions are for GCC v4.x. */
+#include <linux/compiler-gcc.h>
+
+#define inline inline __attribute__((always_inline))
+#define __inline__ __inline__ __attribute__((always_inline))
+#define __inline __inline __attribute__((always_inline))
+#define __deprecated __attribute__((deprecated))
+#define __attribute_used__ __attribute__((__used__))
+#define __attribute_pure__ __attribute__((pure))
+#define __attribute_const__ __attribute__((__const__))
+#define noinline __attribute__((noinline))
+#define __must_check __attribute__((warn_unused_result))
+#define __compiler_offsetof(a,b) __builtin_offsetof(a,b)
+
--- /dev/null
+#ifndef __CRYPTOHASH_H
+#define __CRYPTOHASH_H
+
+#define SHA_DIGEST_WORDS 5
+#define SHA_WORKSPACE_WORDS 80
+
+void sha_init(__u32 *buf);
+void sha_transform(__u32 *digest, const char *data, __u32 *W);
+
+__u32 half_md4_transform(__u32 buf[4], __u32 const in[8]);
+
+#endif
--- /dev/null
+#include <linux/spinlock.h>
+
+struct cpustate_t {
+ spinlock_t lock;
+ int excl;
+ int open_count;
+ unsigned char cached_val;
+ int inited;
+ unsigned long *set_addr;
+ unsigned long *clr_addr;
+};
+
+
+#define HDPU_CPUSTATE_NAME "hdpu cpustate"
+#define HDPU_NEXUS_NAME "hdpu nexus"
+
+#define CPUSTATE_KERNEL_MAJOR 0x10
+
+#define CPUSTATE_KERNEL_INIT_DRV 0 /* CPU State Driver Initialized */
+#define CPUSTATE_KERNEL_INIT_PCI 1 /* 64360 PCI Busses Init */
+#define CPUSTATE_KERNEL_INIT_REG 2 /* 64360 Bridge Init */
+#define CPUSTATE_KERNEL_CPU1_KICK 3 /* Boot cpu 1 */
+#define CPUSTATE_KERNEL_CPU1_OK 4 /* Cpu 1 has checked in */
+#define CPUSTATE_KERNEL_OK 5 /* Terminal state */
+#define CPUSTATE_KERNEL_RESET 14 /* Board reset via SW*/
+#define CPUSTATE_KERNEL_HALT 15 /* Board halted via SW*/
--- /dev/null
+/* ip_mp_alg.h: IPV4 multipath algorithm support, user-visible values.
+ *
+ * Copyright (C) 2004, 2005 Einar Lueck <elueck@de.ibm.com>
+ * Copyright (C) 2005 David S. Miller <davem@davemloft.net>
+ */
+
+#ifndef _LINUX_IP_MP_ALG_H
+#define _LINUX_IP_MP_ALG_H
+
+enum ip_mp_alg {
+ IP_MP_ALG_NONE,
+ IP_MP_ALG_RR,
+ IP_MP_ALG_DRR,
+ IP_MP_ALG_RANDOM,
+ IP_MP_ALG_WRANDOM,
+ __IP_MP_ALG_MAX
+};
+
+#define IP_MP_ALG_MAX (__IP_MP_ALG_MAX - 1)
+
+#endif /* _LINUX_IP_MP_ALG_H */
+
--- /dev/null
+/*
+ * <linux/patchkey.h> -- definition of _PATCHKEY macro
+ *
+ * Copyright (C) 2005 Stuart Brady
+ *
+ * This exists because awe_voice.h defined its own _PATCHKEY and it wasn't
+ * clear whether removing this would break anything in userspace.
+ *
+ * Do not include this file directly. Please use <sys/soundcard.h> instead.
+ * For kernel code, use <linux/soundcard.h>
+ */
+
+#ifndef _LINUX_PATCHKEY_H_INDIRECT
+#error "patchkey.h included directly"
+#endif
+
+#ifndef _LINUX_PATCHKEY_H
+#define _LINUX_PATCHKEY_H
+
+/* Endian macros. */
+#ifdef __KERNEL__
+# include <asm/byteorder.h>
+#else
+# include <endian.h>
+#endif
+
+#if defined(__KERNEL__)
+# if defined(__BIG_ENDIAN)
+# define _PATCHKEY(id) (0xfd00|id)
+# elif defined(__LITTLE_ENDIAN)
+# define _PATCHKEY(id) ((id<<8)|0x00fd)
+# else
+# error "could not determine byte order"
+# endif
+#elif defined(__BYTE_ORDER)
+# if __BYTE_ORDER == __BIG_ENDIAN
+# define _PATCHKEY(id) (0xfd00|id)
+# elif __BYTE_ORDER == __LITTLE_ENDIAN
+# define _PATCHKEY(id) ((id<<8)|0x00fd)
+# else
+# error "could not determine byte order"
+# endif
+#endif
+
+#endif /* _LINUX_PATCHKEY_H */
--- /dev/null
+#ifndef _LINUX_REBOOT_FIXUPS_H
+#define _LINUX_REBOOT_FIXUPS_H
+
+#ifdef CONFIG_X86_REBOOTFIXUPS
+extern void mach_reboot_fixups(void);
+#else
+#define mach_reboot_fixups() ((void)(0))
+#endif
+
+#endif /* _LINUX_REBOOT_FIXUPS_H */
--- /dev/null
+#ifndef _LINUX_SORT_H
+#define _LINUX_SORT_H
+
+#include <linux/types.h>
+
+void sort(void *base, size_t num, size_t size,
+ int (*cmp)(const void *, const void *),
+ void (*swap)(void *, void *, int));
+
+#endif
--- /dev/null
+/*
+ * include/linux/superhyway.h
+ *
+ * SuperHyway Bus definitions
+ *
+ * Copyright (C) 2004, 2005 Paul Mundt <lethal@linux-sh.org>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#ifndef __LINUX_SUPERHYWAY_H
+#define __LINUX_SUPERHYWAY_H
+
+#include <linux/device.h>
+
+/*
+ * SuperHyway IDs
+ */
+#define SUPERHYWAY_DEVICE_ID_SH5_DMAC 0x0183
+
+struct vcr_info {
+ u8 perr_flags; /* P-port Error flags */
+ u8 merr_flags; /* Module Error flags */
+ u16 mod_vers; /* Module Version */
+ u16 mod_id; /* Module ID */
+ u8 bot_mb; /* Bottom Memory block */
+ u8 top_mb; /* Top Memory block */
+};
+
+struct superhyway_device_id {
+ unsigned int id;
+ unsigned long driver_data;
+};
+
+struct superhyway_device;
+extern struct bus_type superhyway_bus_type;
+
+struct superhyway_driver {
+ char *name;
+
+ const struct superhyway_device_id *id_table;
+ struct device_driver drv;
+
+ int (*probe)(struct superhyway_device *dev, const struct superhyway_device_id *id);
+ void (*remove)(struct superhyway_device *dev);
+};
+
+#define to_superhyway_driver(d) container_of((d), struct superhyway_driver, drv)
+
+struct superhyway_device {
+ char name[32];
+
+ struct device dev;
+
+ struct superhyway_device_id id;
+ struct superhyway_driver *drv;
+
+ struct resource resource;
+ struct vcr_info vcr;
+};
+
+#define to_superhyway_device(d) container_of((d), struct superhyway_device, dev)
+
+#define superhyway_get_drvdata(d) dev_get_drvdata(&(d)->dev)
+#define superhyway_set_drvdata(d,p) dev_set_drvdata(&(d)->dev, (p))
+
+extern int superhyway_scan_bus(void);
+
+/* drivers/sh/superhyway/superhyway.c */
+int superhyway_register_driver(struct superhyway_driver *);
+void superhyway_unregister_driver(struct superhyway_driver *);
+int superhyway_add_device(unsigned int, unsigned long, unsigned long long);
+
+/* drivers/sh/superhyway/superhyway-sysfs.c */
+extern struct device_attribute superhyway_dev_attrs[];
+
+#endif /* __LINUX_SUPERHYWAY_H */
+
--- /dev/null
+#ifndef __LINUX_TC_DEF_H
+#define __LINUX_TC_DEF_H
+
+#include <linux/pkt_cls.h>
+
+struct tc_defact
+{
+ tc_gen;
+};
+
+enum
+{
+ TCA_DEF_UNSPEC,
+ TCA_DEF_TM,
+ TCA_DEF_PARMS,
+ TCA_DEF_DATA,
+ __TCA_DEF_MAX
+};
+#define TCA_DEF_MAX (__TCA_DEF_MAX - 1)
+
+#endif
--- /dev/null
+#ifndef __LINUX_TC_EM_CMP_H
+#define __LINUX_TC_EM_CMP_H
+
+#include <linux/pkt_cls.h>
+
+struct tcf_em_cmp
+{
+ __u32 val;
+ __u32 mask;
+ __u16 off;
+ __u8 align:4;
+ __u8 flags:4;
+ __u8 layer:4;
+ __u8 opnd:4;
+};
+
+enum
+{
+ TCF_EM_ALIGN_U8 = 1,
+ TCF_EM_ALIGN_U16 = 2,
+ TCF_EM_ALIGN_U32 = 4
+};
+
+#define TCF_EM_CMP_TRANS 1
+
+#endif
--- /dev/null
+#ifndef __LINUX_TC_EM_META_H
+#define __LINUX_TC_EM_META_H
+
+#include <linux/pkt_cls.h>
+
+enum
+{
+ TCA_EM_META_UNSPEC,
+ TCA_EM_META_HDR,
+ TCA_EM_META_LVALUE,
+ TCA_EM_META_RVALUE,
+ __TCA_EM_META_MAX
+};
+#define TCA_EM_META_MAX (__TCA_EM_META_MAX - 1)
+
+struct tcf_meta_val
+{
+ __u16 kind;
+ __u8 shift;
+ __u8 op;
+};
+
+#define TCF_META_TYPE_MASK (0xf << 12)
+#define TCF_META_TYPE(kind) (((kind) & TCF_META_TYPE_MASK) >> 12)
+#define TCF_META_ID_MASK 0x7ff
+#define TCF_META_ID(kind) ((kind) & TCF_META_ID_MASK)
+
+enum
+{
+ TCF_META_TYPE_VAR,
+ TCF_META_TYPE_INT,
+ __TCF_META_TYPE_MAX
+};
+#define TCF_META_TYPE_MAX (__TCF_META_TYPE_MAX - 1)
+
+enum
+{
+ TCF_META_ID_VALUE,
+ TCF_META_ID_RANDOM,
+ TCF_META_ID_LOADAVG_0,
+ TCF_META_ID_LOADAVG_1,
+ TCF_META_ID_LOADAVG_2,
+ TCF_META_ID_DEV,
+ TCF_META_ID_INDEV,
+ TCF_META_ID_REALDEV,
+ TCF_META_ID_PRIORITY,
+ TCF_META_ID_PROTOCOL,
+ TCF_META_ID_SECURITY,
+ TCF_META_ID_PKTTYPE,
+ TCF_META_ID_PKTLEN,
+ TCF_META_ID_DATALEN,
+ TCF_META_ID_MACLEN,
+ TCF_META_ID_NFMARK,
+ TCF_META_ID_TCINDEX,
+ TCF_META_ID_TCVERDICT,
+ TCF_META_ID_TCCLASSID,
+ TCF_META_ID_RTCLASSID,
+ TCF_META_ID_RTIIF,
+ TCF_META_ID_SK_FAMILY,
+ TCF_META_ID_SK_STATE,
+ TCF_META_ID_SK_REUSE,
+ TCF_META_ID_SK_BOUND_IF,
+ TCF_META_ID_SK_REFCNT,
+ TCF_META_ID_SK_SHUTDOWN,
+ TCF_META_ID_SK_PROTO,
+ TCF_META_ID_SK_TYPE,
+ TCF_META_ID_SK_RCVBUF,
+ TCF_META_ID_SK_RMEM_ALLOC,
+ TCF_META_ID_SK_WMEM_ALLOC,
+ TCF_META_ID_SK_OMEM_ALLOC,
+ TCF_META_ID_SK_WMEM_QUEUED,
+ TCF_META_ID_SK_RCV_QLEN,
+ TCF_META_ID_SK_SND_QLEN,
+ TCF_META_ID_SK_ERR_QLEN,
+ TCF_META_ID_SK_FORWARD_ALLOCS,
+ TCF_META_ID_SK_SNDBUF,
+ TCF_META_ID_SK_ALLOCS,
+ TCF_META_ID_SK_ROUTE_CAPS,
+ TCF_META_ID_SK_HASHENT,
+ TCF_META_ID_SK_LINGERTIME,
+ TCF_META_ID_SK_ACK_BACKLOG,
+ TCF_META_ID_SK_MAX_ACK_BACKLOG,
+ TCF_META_ID_SK_PRIO,
+ TCF_META_ID_SK_RCVLOWAT,
+ TCF_META_ID_SK_RCVTIMEO,
+ TCF_META_ID_SK_SNDTIMEO,
+ TCF_META_ID_SK_SENDMSG_OFF,
+ TCF_META_ID_SK_WRITE_PENDING,
+ __TCF_META_ID_MAX
+};
+#define TCF_META_ID_MAX (__TCF_META_ID_MAX - 1)
+
+struct tcf_meta_hdr
+{
+ struct tcf_meta_val left;
+ struct tcf_meta_val right;
+};
+
+#endif
--- /dev/null
+#ifndef __LINUX_TC_EM_NBYTE_H
+#define __LINUX_TC_EM_NBYTE_H
+
+#include <linux/pkt_cls.h>
+
+struct tcf_em_nbyte
+{
+ __u16 off;
+ __u16 len:12;
+ __u8 layer:4;
+};
+
+#endif
--- /dev/null
+/*
+ * Merged with mainline ieee80211.h in Aug 2004. Original ieee802_11
+ * remains copyright by the original authors
+ *
+ * Portions of the merged code are based on Host AP (software wireless
+ * LAN access point) driver for Intersil Prism2/2.5/3.
+ *
+ * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
+ * <jkmaline@cc.hut.fi>
+ * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * Adaption to a generic IEEE 802.11 stack by James Ketrenos
+ * <jketreno@linux.intel.com>
+ * Copyright (c) 2004, Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation. See README and COPYING for
+ * more details.
+ */
+#ifndef IEEE80211_H
+#define IEEE80211_H
+
+#include <linux/if_ether.h> /* ETH_ALEN */
+#include <linux/kernel.h> /* ARRAY_SIZE */
+
+#if WIRELESS_EXT < 17
+#define IW_QUAL_QUAL_INVALID 0x10
+#define IW_QUAL_LEVEL_INVALID 0x20
+#define IW_QUAL_NOISE_INVALID 0x40
+#define IW_QUAL_QUAL_UPDATED 0x1
+#define IW_QUAL_LEVEL_UPDATED 0x2
+#define IW_QUAL_NOISE_UPDATED 0x4
+#endif
+
+#define IEEE80211_DATA_LEN 2304
+/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section
+ 6.2.1.1.2.
+
+ The figure in section 7.1.2 suggests a body size of up to 2312
+ bytes is allowed, which is a bit confusing, I suspect this
+ represents the 2304 bytes of real data, plus a possible 8 bytes of
+ WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */
+
+
+#define IEEE80211_HLEN 30
+#define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN)
+
+struct ieee80211_hdr {
+ u16 frame_ctl;
+ u16 duration_id;
+ u8 addr1[ETH_ALEN];
+ u8 addr2[ETH_ALEN];
+ u8 addr3[ETH_ALEN];
+ u16 seq_ctl;
+ u8 addr4[ETH_ALEN];
+} __attribute__ ((packed));
+
+struct ieee80211_hdr_3addr {
+ u16 frame_ctl;
+ u16 duration_id;
+ u8 addr1[ETH_ALEN];
+ u8 addr2[ETH_ALEN];
+ u8 addr3[ETH_ALEN];
+ u16 seq_ctl;
+} __attribute__ ((packed));
+
+enum eap_type {
+ EAP_PACKET = 0,
+ EAPOL_START,
+ EAPOL_LOGOFF,
+ EAPOL_KEY,
+ EAPOL_ENCAP_ASF_ALERT
+};
+
+static const char *eap_types[] = {
+ [EAP_PACKET] = "EAP-Packet",
+ [EAPOL_START] = "EAPOL-Start",
+ [EAPOL_LOGOFF] = "EAPOL-Logoff",
+ [EAPOL_KEY] = "EAPOL-Key",
+ [EAPOL_ENCAP_ASF_ALERT] = "EAPOL-Encap-ASF-Alert"
+};
+
+static inline const char *eap_get_type(int type)
+{
+ return (type >= ARRAY_SIZE(eap_types)) ? "Unknown" : eap_types[type];
+}
+
+struct eapol {
+ u8 snap[6];
+ u16 ethertype;
+ u8 version;
+ u8 type;
+ u16 length;
+} __attribute__ ((packed));
+
+#define IEEE80211_3ADDR_LEN 24
+#define IEEE80211_4ADDR_LEN 30
+#define IEEE80211_FCS_LEN 4
+
+#define MIN_FRAG_THRESHOLD 256U
+#define MAX_FRAG_THRESHOLD 2346U
+
+/* Frame control field constants */
+#define IEEE80211_FCTL_VERS 0x0002
+#define IEEE80211_FCTL_FTYPE 0x000c
+#define IEEE80211_FCTL_STYPE 0x00f0
+#define IEEE80211_FCTL_TODS 0x0100
+#define IEEE80211_FCTL_FROMDS 0x0200
+#define IEEE80211_FCTL_MOREFRAGS 0x0400
+#define IEEE80211_FCTL_RETRY 0x0800
+#define IEEE80211_FCTL_PM 0x1000
+#define IEEE80211_FCTL_MOREDATA 0x2000
+#define IEEE80211_FCTL_WEP 0x4000
+#define IEEE80211_FCTL_ORDER 0x8000
+
+#define IEEE80211_FTYPE_MGMT 0x0000
+#define IEEE80211_FTYPE_CTL 0x0004
+#define IEEE80211_FTYPE_DATA 0x0008
+
+/* management */
+#define IEEE80211_STYPE_ASSOC_REQ 0x0000
+#define IEEE80211_STYPE_ASSOC_RESP 0x0010
+#define IEEE80211_STYPE_REASSOC_REQ 0x0020
+#define IEEE80211_STYPE_REASSOC_RESP 0x0030
+#define IEEE80211_STYPE_PROBE_REQ 0x0040
+#define IEEE80211_STYPE_PROBE_RESP 0x0050
+#define IEEE80211_STYPE_BEACON 0x0080
+#define IEEE80211_STYPE_ATIM 0x0090
+#define IEEE80211_STYPE_DISASSOC 0x00A0
+#define IEEE80211_STYPE_AUTH 0x00B0
+#define IEEE80211_STYPE_DEAUTH 0x00C0
+
+/* control */
+#define IEEE80211_STYPE_PSPOLL 0x00A0
+#define IEEE80211_STYPE_RTS 0x00B0
+#define IEEE80211_STYPE_CTS 0x00C0
+#define IEEE80211_STYPE_ACK 0x00D0
+#define IEEE80211_STYPE_CFEND 0x00E0
+#define IEEE80211_STYPE_CFENDACK 0x00F0
+
+/* data */
+#define IEEE80211_STYPE_DATA 0x0000
+#define IEEE80211_STYPE_DATA_CFACK 0x0010
+#define IEEE80211_STYPE_DATA_CFPOLL 0x0020
+#define IEEE80211_STYPE_DATA_CFACKPOLL 0x0030
+#define IEEE80211_STYPE_NULLFUNC 0x0040
+#define IEEE80211_STYPE_CFACK 0x0050
+#define IEEE80211_STYPE_CFPOLL 0x0060
+#define IEEE80211_STYPE_CFACKPOLL 0x0070
+
+#define IEEE80211_SCTL_FRAG 0x000F
+#define IEEE80211_SCTL_SEQ 0xFFF0
+
+
+/* debug macros */
+
+#ifdef CONFIG_IEEE80211_DEBUG
+extern u32 ieee80211_debug_level;
+#define IEEE80211_DEBUG(level, fmt, args...) \
+do { if (ieee80211_debug_level & (level)) \
+ printk(KERN_DEBUG "ieee80211: %c %s " fmt, \
+ in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
+#else
+#define IEEE80211_DEBUG(level, fmt, args...) do {} while (0)
+#endif /* CONFIG_IEEE80211_DEBUG */
+
+/*
+ * To use the debug system;
+ *
+ * If you are defining a new debug classification, simply add it to the #define
+ * list here in the form of:
+ *
+ * #define IEEE80211_DL_xxxx VALUE
+ *
+ * shifting value to the left one bit from the previous entry. xxxx should be
+ * the name of the classification (for example, WEP)
+ *
+ * You then need to either add a IEEE80211_xxxx_DEBUG() macro definition for your
+ * classification, or use IEEE80211_DEBUG(IEEE80211_DL_xxxx, ...) whenever you want
+ * to send output to that classification.
+ *
+ * To add your debug level to the list of levels seen when you perform
+ *
+ * % cat /proc/net/ipw/debug_level
+ *
+ * you simply need to add your entry to the ipw_debug_levels array.
+ *
+ * If you do not see debug_level in /proc/net/ipw then you do not have
+ * CONFIG_IEEE80211_DEBUG defined in your kernel configuration
+ *
+ */
+
+#define IEEE80211_DL_INFO (1<<0)
+#define IEEE80211_DL_WX (1<<1)
+#define IEEE80211_DL_SCAN (1<<2)
+#define IEEE80211_DL_STATE (1<<3)
+#define IEEE80211_DL_MGMT (1<<4)
+#define IEEE80211_DL_FRAG (1<<5)
+#define IEEE80211_DL_EAP (1<<6)
+#define IEEE80211_DL_DROP (1<<7)
+
+#define IEEE80211_DL_TX (1<<8)
+#define IEEE80211_DL_RX (1<<9)
+
+#define IEEE80211_ERROR(f, a...) printk(KERN_ERR "ieee80211: " f, ## a)
+#define IEEE80211_WARNING(f, a...) printk(KERN_WARNING "ieee80211: " f, ## a)
+#define IEEE80211_DEBUG_INFO(f, a...) IEEE80211_DEBUG(IEEE80211_DL_INFO, f, ## a)
+
+#define IEEE80211_DEBUG_WX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_WX, f, ## a)
+#define IEEE80211_DEBUG_SCAN(f, a...) IEEE80211_DEBUG(IEEE80211_DL_SCAN, f, ## a)
+#define IEEE80211_DEBUG_STATE(f, a...) IEEE80211_DEBUG(IEEE80211_DL_STATE, f, ## a)
+#define IEEE80211_DEBUG_MGMT(f, a...) IEEE80211_DEBUG(IEEE80211_DL_MGMT, f, ## a)
+#define IEEE80211_DEBUG_FRAG(f, a...) IEEE80211_DEBUG(IEEE80211_DL_FRAG, f, ## a)
+#define IEEE80211_DEBUG_EAP(f, a...) IEEE80211_DEBUG(IEEE80211_DL_EAP, f, ## a)
+#define IEEE80211_DEBUG_DROP(f, a...) IEEE80211_DEBUG(IEEE80211_DL_DROP, f, ## a)
+#define IEEE80211_DEBUG_TX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_TX, f, ## a)
+#define IEEE80211_DEBUG_RX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_RX, f, ## a)
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+#include <linux/if_arp.h> /* ARPHRD_ETHER */
+
+#ifndef WIRELESS_SPY
+#define WIRELESS_SPY // enable iwspy support
+#endif
+#include <net/iw_handler.h> // new driver API
+
+#ifndef ETH_P_PAE
+#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */
+#endif /* ETH_P_PAE */
+
+#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */
+
+#ifndef ETH_P_80211_RAW
+#define ETH_P_80211_RAW (ETH_P_ECONET + 1)
+#endif
+
+/* IEEE 802.11 defines */
+
+#define P80211_OUI_LEN 3
+
+struct ieee80211_snap_hdr {
+
+ u8 dsap; /* always 0xAA */
+ u8 ssap; /* always 0xAA */
+ u8 ctrl; /* always 0x03 */
+ u8 oui[P80211_OUI_LEN]; /* organizational universal id */
+
+} __attribute__ ((packed));
+
+#define SNAP_SIZE sizeof(struct ieee80211_snap_hdr)
+
+#define WLAN_FC_GET_TYPE(fc) ((fc) & IEEE80211_FCTL_FTYPE)
+#define WLAN_FC_GET_STYPE(fc) ((fc) & IEEE80211_FCTL_STYPE)
+
+#define WLAN_GET_SEQ_FRAG(seq) ((seq) & IEEE80211_SCTL_FRAG)
+#define WLAN_GET_SEQ_SEQ(seq) ((seq) & IEEE80211_SCTL_SEQ)
+
+/* Authentication algorithms */
+#define WLAN_AUTH_OPEN 0
+#define WLAN_AUTH_SHARED_KEY 1
+
+#define WLAN_AUTH_CHALLENGE_LEN 128
+
+#define WLAN_CAPABILITY_BSS (1<<0)
+#define WLAN_CAPABILITY_IBSS (1<<1)
+#define WLAN_CAPABILITY_CF_POLLABLE (1<<2)
+#define WLAN_CAPABILITY_CF_POLL_REQUEST (1<<3)
+#define WLAN_CAPABILITY_PRIVACY (1<<4)
+#define WLAN_CAPABILITY_SHORT_PREAMBLE (1<<5)
+#define WLAN_CAPABILITY_PBCC (1<<6)
+#define WLAN_CAPABILITY_CHANNEL_AGILITY (1<<7)
+
+/* Status codes */
+#define WLAN_STATUS_SUCCESS 0
+#define WLAN_STATUS_UNSPECIFIED_FAILURE 1
+#define WLAN_STATUS_CAPS_UNSUPPORTED 10
+#define WLAN_STATUS_REASSOC_NO_ASSOC 11
+#define WLAN_STATUS_ASSOC_DENIED_UNSPEC 12
+#define WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG 13
+#define WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION 14
+#define WLAN_STATUS_CHALLENGE_FAIL 15
+#define WLAN_STATUS_AUTH_TIMEOUT 16
+#define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17
+#define WLAN_STATUS_ASSOC_DENIED_RATES 18
+/* 802.11b */
+#define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19
+#define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20
+#define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21
+
+/* Reason codes */
+#define WLAN_REASON_UNSPECIFIED 1
+#define WLAN_REASON_PREV_AUTH_NOT_VALID 2
+#define WLAN_REASON_DEAUTH_LEAVING 3
+#define WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY 4
+#define WLAN_REASON_DISASSOC_AP_BUSY 5
+#define WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6
+#define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7
+#define WLAN_REASON_DISASSOC_STA_HAS_LEFT 8
+#define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9
+
+
+/* Information Element IDs */
+#define WLAN_EID_SSID 0
+#define WLAN_EID_SUPP_RATES 1
+#define WLAN_EID_FH_PARAMS 2
+#define WLAN_EID_DS_PARAMS 3
+#define WLAN_EID_CF_PARAMS 4
+#define WLAN_EID_TIM 5
+#define WLAN_EID_IBSS_PARAMS 6
+#define WLAN_EID_CHALLENGE 16
+#define WLAN_EID_RSN 48
+#define WLAN_EID_GENERIC 221
+
+#define IEEE80211_MGMT_HDR_LEN 24
+#define IEEE80211_DATA_HDR3_LEN 24
+#define IEEE80211_DATA_HDR4_LEN 30
+
+
+#define IEEE80211_STATMASK_SIGNAL (1<<0)
+#define IEEE80211_STATMASK_RSSI (1<<1)
+#define IEEE80211_STATMASK_NOISE (1<<2)
+#define IEEE80211_STATMASK_RATE (1<<3)
+#define IEEE80211_STATMASK_WEMASK 0x7
+
+
+#define IEEE80211_CCK_MODULATION (1<<0)
+#define IEEE80211_OFDM_MODULATION (1<<1)
+
+#define IEEE80211_24GHZ_BAND (1<<0)
+#define IEEE80211_52GHZ_BAND (1<<1)
+
+#define IEEE80211_CCK_RATE_1MB 0x02
+#define IEEE80211_CCK_RATE_2MB 0x04
+#define IEEE80211_CCK_RATE_5MB 0x0B
+#define IEEE80211_CCK_RATE_11MB 0x16
+#define IEEE80211_OFDM_RATE_6MB 0x0C
+#define IEEE80211_OFDM_RATE_9MB 0x12
+#define IEEE80211_OFDM_RATE_12MB 0x18
+#define IEEE80211_OFDM_RATE_18MB 0x24
+#define IEEE80211_OFDM_RATE_24MB 0x30
+#define IEEE80211_OFDM_RATE_36MB 0x48
+#define IEEE80211_OFDM_RATE_48MB 0x60
+#define IEEE80211_OFDM_RATE_54MB 0x6C
+#define IEEE80211_BASIC_RATE_MASK 0x80
+
+#define IEEE80211_CCK_RATE_1MB_MASK (1<<0)
+#define IEEE80211_CCK_RATE_2MB_MASK (1<<1)
+#define IEEE80211_CCK_RATE_5MB_MASK (1<<2)
+#define IEEE80211_CCK_RATE_11MB_MASK (1<<3)
+#define IEEE80211_OFDM_RATE_6MB_MASK (1<<4)
+#define IEEE80211_OFDM_RATE_9MB_MASK (1<<5)
+#define IEEE80211_OFDM_RATE_12MB_MASK (1<<6)
+#define IEEE80211_OFDM_RATE_18MB_MASK (1<<7)
+#define IEEE80211_OFDM_RATE_24MB_MASK (1<<8)
+#define IEEE80211_OFDM_RATE_36MB_MASK (1<<9)
+#define IEEE80211_OFDM_RATE_48MB_MASK (1<<10)
+#define IEEE80211_OFDM_RATE_54MB_MASK (1<<11)
+
+#define IEEE80211_CCK_RATES_MASK 0x0000000F
+#define IEEE80211_CCK_BASIC_RATES_MASK (IEEE80211_CCK_RATE_1MB_MASK | \
+ IEEE80211_CCK_RATE_2MB_MASK)
+#define IEEE80211_CCK_DEFAULT_RATES_MASK (IEEE80211_CCK_BASIC_RATES_MASK | \
+ IEEE80211_CCK_RATE_5MB_MASK | \
+ IEEE80211_CCK_RATE_11MB_MASK)
+
+#define IEEE80211_OFDM_RATES_MASK 0x00000FF0
+#define IEEE80211_OFDM_BASIC_RATES_MASK (IEEE80211_OFDM_RATE_6MB_MASK | \
+ IEEE80211_OFDM_RATE_12MB_MASK | \
+ IEEE80211_OFDM_RATE_24MB_MASK)
+#define IEEE80211_OFDM_DEFAULT_RATES_MASK (IEEE80211_OFDM_BASIC_RATES_MASK | \
+ IEEE80211_OFDM_RATE_9MB_MASK | \
+ IEEE80211_OFDM_RATE_18MB_MASK | \
+ IEEE80211_OFDM_RATE_36MB_MASK | \
+ IEEE80211_OFDM_RATE_48MB_MASK | \
+ IEEE80211_OFDM_RATE_54MB_MASK)
+#define IEEE80211_DEFAULT_RATES_MASK (IEEE80211_OFDM_DEFAULT_RATES_MASK | \
+ IEEE80211_CCK_DEFAULT_RATES_MASK)
+
+#define IEEE80211_NUM_OFDM_RATES 8
+#define IEEE80211_NUM_CCK_RATES 4
+#define IEEE80211_OFDM_SHIFT_MASK_A 4
+
+
+
+
+/* NOTE: This data is for statistical purposes; not all hardware provides this
+ * information for frames received. Not setting these will not cause
+ * any adverse affects. */
+struct ieee80211_rx_stats {
+ u32 mac_time;
+ s8 rssi;
+ u8 signal;
+ u8 noise;
+ u16 rate; /* in 100 kbps */
+ u8 received_channel;
+ u8 control;
+ u8 mask;
+ u8 freq;
+ u16 len;
+};
+
+/* IEEE 802.11 requires that STA supports concurrent reception of at least
+ * three fragmented frames. This define can be increased to support more
+ * concurrent frames, but it should be noted that each entry can consume about
+ * 2 kB of RAM and increasing cache size will slow down frame reassembly. */
+#define IEEE80211_FRAG_CACHE_LEN 4
+
+struct ieee80211_frag_entry {
+ unsigned long first_frag_time;
+ unsigned int seq;
+ unsigned int last_frag;
+ struct sk_buff *skb;
+ u8 src_addr[ETH_ALEN];
+ u8 dst_addr[ETH_ALEN];
+};
+
+struct ieee80211_stats {
+ unsigned int tx_unicast_frames;
+ unsigned int tx_multicast_frames;
+ unsigned int tx_fragments;
+ unsigned int tx_unicast_octets;
+ unsigned int tx_multicast_octets;
+ unsigned int tx_deferred_transmissions;
+ unsigned int tx_single_retry_frames;
+ unsigned int tx_multiple_retry_frames;
+ unsigned int tx_retry_limit_exceeded;
+ unsigned int tx_discards;
+ unsigned int rx_unicast_frames;
+ unsigned int rx_multicast_frames;
+ unsigned int rx_fragments;
+ unsigned int rx_unicast_octets;
+ unsigned int rx_multicast_octets;
+ unsigned int rx_fcs_errors;
+ unsigned int rx_discards_no_buffer;
+ unsigned int tx_discards_wrong_sa;
+ unsigned int rx_discards_undecryptable;
+ unsigned int rx_message_in_msg_fragments;
+ unsigned int rx_message_in_bad_msg_fragments;
+};
+
+struct ieee80211_device;
+
+#define SEC_KEY_1 (1<<0)
+#define SEC_KEY_2 (1<<1)
+#define SEC_KEY_3 (1<<2)
+#define SEC_KEY_4 (1<<3)
+#define SEC_ACTIVE_KEY (1<<4)
+#define SEC_AUTH_MODE (1<<5)
+#define SEC_UNICAST_GROUP (1<<6)
+#define SEC_LEVEL (1<<7)
+#define SEC_ENABLED (1<<8)
+
+#define SEC_LEVEL_0 0 /* None */
+#define SEC_LEVEL_1 1 /* WEP 40 and 104 bit */
+#define SEC_LEVEL_2 2 /* Level 1 + TKIP */
+#define SEC_LEVEL_2_CKIP 3 /* Level 1 + CKIP */
+#define SEC_LEVEL_3 4 /* Level 2 + CCMP */
+
+#define WEP_KEYS 4
+#define WEP_KEY_LEN 13
+
+struct ieee80211_security {
+ u16 active_key:2,
+ enabled:1,
+ auth_mode:2,
+ auth_algo:4,
+ unicast_uses_group:1;
+ u8 key_sizes[WEP_KEYS];
+ u8 keys[WEP_KEYS][WEP_KEY_LEN];
+ u8 level;
+ u16 flags;
+} __attribute__ ((packed));
+
+
+/*
+
+ 802.11 data frame from AP
+
+ ,-------------------------------------------------------------------.
+Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 |
+ |------|------|---------|---------|---------|------|---------|------|
+Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | frame | fcs |
+ | | tion | (BSSID) | | | ence | data | |
+ `-------------------------------------------------------------------'
+
+Total: 28-2340 bytes
+
+*/
+
+struct ieee80211_header_data {
+ u16 frame_ctl;
+ u16 duration_id;
+ u8 addr1[6];
+ u8 addr2[6];
+ u8 addr3[6];
+ u16 seq_ctrl;
+};
+
+#define BEACON_PROBE_SSID_ID_POSITION 12
+
+/* Management Frame Information Element Types */
+#define MFIE_TYPE_SSID 0
+#define MFIE_TYPE_RATES 1
+#define MFIE_TYPE_FH_SET 2
+#define MFIE_TYPE_DS_SET 3
+#define MFIE_TYPE_CF_SET 4
+#define MFIE_TYPE_TIM 5
+#define MFIE_TYPE_IBSS_SET 6
+#define MFIE_TYPE_CHALLENGE 16
+#define MFIE_TYPE_RSN 48
+#define MFIE_TYPE_RATES_EX 50
+#define MFIE_TYPE_GENERIC 221
+
+struct ieee80211_info_element_hdr {
+ u8 id;
+ u8 len;
+} __attribute__ ((packed));
+
+struct ieee80211_info_element {
+ u8 id;
+ u8 len;
+ u8 data[0];
+} __attribute__ ((packed));
+
+/*
+ * These are the data types that can make up management packets
+ *
+ u16 auth_algorithm;
+ u16 auth_sequence;
+ u16 beacon_interval;
+ u16 capability;
+ u8 current_ap[ETH_ALEN];
+ u16 listen_interval;
+ struct {
+ u16 association_id:14, reserved:2;
+ } __attribute__ ((packed));
+ u32 time_stamp[2];
+ u16 reason;
+ u16 status;
+*/
+
+struct ieee80211_authentication {
+ struct ieee80211_header_data header;
+ u16 algorithm;
+ u16 transaction;
+ u16 status;
+ struct ieee80211_info_element info_element;
+} __attribute__ ((packed));
+
+
+struct ieee80211_probe_response {
+ struct ieee80211_header_data header;
+ u32 time_stamp[2];
+ u16 beacon_interval;
+ u16 capability;
+ struct ieee80211_info_element info_element;
+} __attribute__ ((packed));
+
+struct ieee80211_assoc_request_frame {
+ u16 capability;
+ u16 listen_interval;
+ u8 current_ap[ETH_ALEN];
+ struct ieee80211_info_element info_element;
+} __attribute__ ((packed));
+
+struct ieee80211_assoc_response_frame {
+ struct ieee80211_hdr_3addr header;
+ u16 capability;
+ u16 status;
+ u16 aid;
+ struct ieee80211_info_element info_element; /* supported rates */
+} __attribute__ ((packed));
+
+
+struct ieee80211_txb {
+ u8 nr_frags;
+ u8 encrypted;
+ u16 reserved;
+ u16 frag_size;
+ u16 payload_size;
+ struct sk_buff *fragments[0];
+};
+
+
+/* SWEEP TABLE ENTRIES NUMBER*/
+#define MAX_SWEEP_TAB_ENTRIES 42
+#define MAX_SWEEP_TAB_ENTRIES_PER_PACKET 7
+/* MAX_RATES_LENGTH needs to be 12. The spec says 8, and many APs
+ * only use 8, and then use extended rates for the remaining supported
+ * rates. Other APs, however, stick all of their supported rates on the
+ * main rates information element... */
+#define MAX_RATES_LENGTH ((u8)12)
+#define MAX_RATES_EX_LENGTH ((u8)16)
+#define MAX_NETWORK_COUNT 128
+
+#define CRC_LENGTH 4U
+
+#define MAX_WPA_IE_LEN 64
+
+#define NETWORK_EMPTY_ESSID (1<<0)
+#define NETWORK_HAS_OFDM (1<<1)
+#define NETWORK_HAS_CCK (1<<2)
+
+struct ieee80211_network {
+ /* These entries are used to identify a unique network */
+ u8 bssid[ETH_ALEN];
+ u8 channel;
+ /* Ensure null-terminated for any debug msgs */
+ u8 ssid[IW_ESSID_MAX_SIZE + 1];
+ u8 ssid_len;
+
+ /* These are network statistics */
+ struct ieee80211_rx_stats stats;
+ u16 capability;
+ u8 rates[MAX_RATES_LENGTH];
+ u8 rates_len;
+ u8 rates_ex[MAX_RATES_EX_LENGTH];
+ u8 rates_ex_len;
+ unsigned long last_scanned;
+ u8 mode;
+ u8 flags;
+ u32 last_associate;
+ u32 time_stamp[2];
+ u16 beacon_interval;
+ u16 listen_interval;
+ u16 atim_window;
+ u8 wpa_ie[MAX_WPA_IE_LEN];
+ size_t wpa_ie_len;
+ u8 rsn_ie[MAX_WPA_IE_LEN];
+ size_t rsn_ie_len;
+ struct list_head list;
+};
+
+enum ieee80211_state {
+ IEEE80211_UNINITIALIZED = 0,
+ IEEE80211_INITIALIZED,
+ IEEE80211_ASSOCIATING,
+ IEEE80211_ASSOCIATED,
+ IEEE80211_AUTHENTICATING,
+ IEEE80211_AUTHENTICATED,
+ IEEE80211_SHUTDOWN
+};
+
+#define DEFAULT_MAX_SCAN_AGE (15 * HZ)
+#define DEFAULT_FTS 2346
+#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
+#define MAC_ARG(x) ((u8*)(x))[0],((u8*)(x))[1],((u8*)(x))[2],((u8*)(x))[3],((u8*)(x))[4],((u8*)(x))[5]
+
+
+extern inline int is_broadcast_ether_addr(const u8 *addr)
+{
+ return ((addr[0] == 0xff) && (addr[1] == 0xff) && (addr[2] == 0xff) && \
+ (addr[3] == 0xff) && (addr[4] == 0xff) && (addr[5] == 0xff));
+}
+
+#define CFG_IEEE80211_RESERVE_FCS (1<<0)
+#define CFG_IEEE80211_COMPUTE_FCS (1<<1)
+
+struct ieee80211_device {
+ struct net_device *dev;
+
+ /* Bookkeeping structures */
+ struct net_device_stats stats;
+ struct ieee80211_stats ieee_stats;
+
+ /* Probe / Beacon management */
+ struct list_head network_free_list;
+ struct list_head network_list;
+ struct ieee80211_network *networks;
+ int scans;
+ int scan_age;
+
+ int iw_mode; /* operating mode (IW_MODE_*) */
+
+ spinlock_t lock;
+
+ int tx_headroom; /* Set to size of any additional room needed at front
+ * of allocated Tx SKBs */
+ u32 config;
+
+ /* WEP and other encryption related settings at the device level */
+ int open_wep; /* Set to 1 to allow unencrypted frames */
+
+ int reset_on_keychange; /* Set to 1 if the HW needs to be reset on
+ * WEP key changes */
+
+ /* If the host performs {en,de}cryption, then set to 1 */
+ int host_encrypt;
+ int host_decrypt;
+ int ieee802_1x; /* is IEEE 802.1X used */
+
+ /* WPA data */
+ int wpa_enabled;
+ int drop_unencrypted;
+ int tkip_countermeasures;
+ int privacy_invoked;
+ size_t wpa_ie_len;
+ u8 *wpa_ie;
+
+ struct list_head crypt_deinit_list;
+ struct ieee80211_crypt_data *crypt[WEP_KEYS];
+ int tx_keyidx; /* default TX key index (crypt[tx_keyidx]) */
+ struct timer_list crypt_deinit_timer;
+
+ int bcrx_sta_key; /* use individual keys to override default keys even
+ * with RX of broad/multicast frames */
+
+ /* Fragmentation structures */
+ struct ieee80211_frag_entry frag_cache[IEEE80211_FRAG_CACHE_LEN];
+ unsigned int frag_next_idx;
+ u16 fts; /* Fragmentation Threshold */
+
+ /* Association info */
+ u8 bssid[ETH_ALEN];
+
+ enum ieee80211_state state;
+
+ int mode; /* A, B, G */
+ int modulation; /* CCK, OFDM */
+ int freq_band; /* 2.4Ghz, 5.2Ghz, Mixed */
+ int abg_ture; /* ABG flag */
+
+ /* Callback functions */
+ void (*set_security)(struct net_device *dev,
+ struct ieee80211_security *sec);
+ int (*hard_start_xmit)(struct ieee80211_txb *txb,
+ struct net_device *dev);
+ int (*reset_port)(struct net_device *dev);
+
+ /* This must be the last item so that it points to the data
+ * allocated beyond this structure by alloc_ieee80211 */
+ u8 priv[0];
+};
+
+#define IEEE_A (1<<0)
+#define IEEE_B (1<<1)
+#define IEEE_G (1<<2)
+#define IEEE_MODE_MASK (IEEE_A|IEEE_B|IEEE_G)
+
+extern inline void *ieee80211_priv(struct net_device *dev)
+{
+ return ((struct ieee80211_device *)netdev_priv(dev))->priv;
+}
+
+extern inline int ieee80211_is_empty_essid(const char *essid, int essid_len)
+{
+ /* Single white space is for Linksys APs */
+ if (essid_len == 1 && essid[0] == ' ')
+ return 1;
+
+ /* Otherwise, if the entire essid is 0, we assume it is hidden */
+ while (essid_len) {
+ essid_len--;
+ if (essid[essid_len] != '\0')
+ return 0;
+ }
+
+ return 1;
+}
+
+extern inline int ieee80211_is_valid_mode(struct ieee80211_device *ieee, int mode)
+{
+ /*
+ * It is possible for both access points and our device to support
+ * combinations of modes, so as long as there is one valid combination
+ * of ap/device supported modes, then return success
+ *
+ */
+ if ((mode & IEEE_A) &&
+ (ieee->modulation & IEEE80211_OFDM_MODULATION) &&
+ (ieee->freq_band & IEEE80211_52GHZ_BAND))
+ return 1;
+
+ if ((mode & IEEE_G) &&
+ (ieee->modulation & IEEE80211_OFDM_MODULATION) &&
+ (ieee->freq_band & IEEE80211_24GHZ_BAND))
+ return 1;
+
+ if ((mode & IEEE_B) &&
+ (ieee->modulation & IEEE80211_CCK_MODULATION) &&
+ (ieee->freq_band & IEEE80211_24GHZ_BAND))
+ return 1;
+
+ return 0;
+}
+
+extern inline int ieee80211_get_hdrlen(u16 fc)
+{
+ int hdrlen = 24;
+
+ switch (WLAN_FC_GET_TYPE(fc)) {
+ case IEEE80211_FTYPE_DATA:
+ if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS))
+ hdrlen = 30; /* Addr4 */
+ break;
+ case IEEE80211_FTYPE_CTL:
+ switch (WLAN_FC_GET_STYPE(fc)) {
+ case IEEE80211_STYPE_CTS:
+ case IEEE80211_STYPE_ACK:
+ hdrlen = 10;
+ break;
+ default:
+ hdrlen = 16;
+ break;
+ }
+ break;
+ }
+
+ return hdrlen;
+}
+
+
+
+/* ieee80211.c */
+extern void free_ieee80211(struct net_device *dev);
+extern struct net_device *alloc_ieee80211(int sizeof_priv);
+
+extern int ieee80211_set_encryption(struct ieee80211_device *ieee);
+
+/* ieee80211_tx.c */
+
+
+extern int ieee80211_xmit(struct sk_buff *skb,
+ struct net_device *dev);
+extern void ieee80211_txb_free(struct ieee80211_txb *);
+
+
+/* ieee80211_rx.c */
+extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
+ struct ieee80211_rx_stats *rx_stats);
+extern void ieee80211_rx_mgt(struct ieee80211_device *ieee,
+ struct ieee80211_hdr *header,
+ struct ieee80211_rx_stats *stats);
+
+/* iee80211_wx.c */
+extern int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *key);
+extern int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *key);
+extern int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *key);
+
+
+extern inline void ieee80211_increment_scans(struct ieee80211_device *ieee)
+{
+ ieee->scans++;
+}
+
+extern inline int ieee80211_get_scans(struct ieee80211_device *ieee)
+{
+ return ieee->scans;
+}
+
+static inline const char *escape_essid(const char *essid, u8 essid_len) {
+ static char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
+ const char *s = essid;
+ char *d = escaped;
+
+ if (ieee80211_is_empty_essid(essid, essid_len)) {
+ memcpy(escaped, "<hidden>", sizeof("<hidden>"));
+ return escaped;
+ }
+
+ essid_len = min(essid_len, (u8)IW_ESSID_MAX_SIZE);
+ while (essid_len--) {
+ if (*s == '\0') {
+ *d++ = '\\';
+ *d++ = '0';
+ s++;
+ } else {
+ *d++ = *s++;
+ }
+ }
+ *d = '\0';
+ return escaped;
+}
+
+#endif /* IEEE80211_H */
--- /dev/null
+/*
+ * linux/kernel/seccomp.c
+ *
+ * Copyright 2004-2005 Andrea Arcangeli <andrea@cpushare.com>
+ *
+ * This defines a simple but solid secure-computing mode.
+ */
+
+#include <linux/seccomp.h>
+#include <linux/sched.h>
+
+/* #define SECCOMP_DEBUG 1 */
+
+/*
+ * Secure computing mode 1 allows only read/write/exit/sigreturn.
+ * To be fully secure this must be combined with rlimit
+ * to limit the stack allocations too.
+ */
+static int mode1_syscalls[] = {
+ __NR_seccomp_read, __NR_seccomp_write, __NR_seccomp_exit, __NR_seccomp_sigreturn,
+ 0, /* null terminated */
+};
+
+#ifdef TIF_32BIT
+static int mode1_syscalls_32[] = {
+ __NR_seccomp_read_32, __NR_seccomp_write_32, __NR_seccomp_exit_32, __NR_seccomp_sigreturn_32,
+ 0, /* null terminated */
+};
+#endif
+
+void __secure_computing(int this_syscall)
+{
+ int mode = current->seccomp.mode;
+ int * syscall;
+
+ switch (mode) {
+ case 1:
+ syscall = mode1_syscalls;
+#ifdef TIF_32BIT
+ if (test_thread_flag(TIF_32BIT))
+ syscall = mode1_syscalls_32;
+#endif
+ do {
+ if (*syscall == this_syscall)
+ return;
+ } while (*++syscall);
+ break;
+ default:
+ BUG();
+ }
+
+#ifdef SECCOMP_DEBUG
+ dump_stack();
+#endif
+ do_exit(SIGKILL);
+}
--- /dev/null
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/cryptohash.h>
+
+/* F, G and H are basic MD4 functions: selection, majority, parity */
+#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
+#define G(x, y, z) (((x) & (y)) + (((x) ^ (y)) & (z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+
+/*
+ * The generic round function. The application is so specific that
+ * we don't bother protecting all the arguments with parens, as is generally
+ * good macro practice, in favor of extra legibility.
+ * Rotation is separate from addition to prevent recomputation
+ */
+#define ROUND(f, a, b, c, d, x, s) \
+ (a += f(b, c, d) + x, a = (a << s) | (a >> (32 - s)))
+#define K1 0
+#define K2 013240474631UL
+#define K3 015666365641UL
+
+/*
+ * Basic cut-down MD4 transform. Returns only 32 bits of result.
+ */
+__u32 half_md4_transform(__u32 buf[4], __u32 const in[8])
+{
+ __u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
+
+ /* Round 1 */
+ ROUND(F, a, b, c, d, in[0] + K1, 3);
+ ROUND(F, d, a, b, c, in[1] + K1, 7);
+ ROUND(F, c, d, a, b, in[2] + K1, 11);
+ ROUND(F, b, c, d, a, in[3] + K1, 19);
+ ROUND(F, a, b, c, d, in[4] + K1, 3);
+ ROUND(F, d, a, b, c, in[5] + K1, 7);
+ ROUND(F, c, d, a, b, in[6] + K1, 11);
+ ROUND(F, b, c, d, a, in[7] + K1, 19);
+
+ /* Round 2 */
+ ROUND(G, a, b, c, d, in[1] + K2, 3);
+ ROUND(G, d, a, b, c, in[3] + K2, 5);
+ ROUND(G, c, d, a, b, in[5] + K2, 9);
+ ROUND(G, b, c, d, a, in[7] + K2, 13);
+ ROUND(G, a, b, c, d, in[0] + K2, 3);
+ ROUND(G, d, a, b, c, in[2] + K2, 5);
+ ROUND(G, c, d, a, b, in[4] + K2, 9);
+ ROUND(G, b, c, d, a, in[6] + K2, 13);
+
+ /* Round 3 */
+ ROUND(H, a, b, c, d, in[3] + K3, 3);
+ ROUND(H, d, a, b, c, in[7] + K3, 9);
+ ROUND(H, c, d, a, b, in[2] + K3, 11);
+ ROUND(H, b, c, d, a, in[6] + K3, 15);
+ ROUND(H, a, b, c, d, in[1] + K3, 3);
+ ROUND(H, d, a, b, c, in[5] + K3, 9);
+ ROUND(H, c, d, a, b, in[0] + K3, 11);
+ ROUND(H, b, c, d, a, in[4] + K3, 15);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+
+ return buf[1]; /* "most hashed" word */
+}
+EXPORT_SYMBOL(half_md4_transform);
--- /dev/null
+/* multipath.c: IPV4 multipath algorithm support.
+ *
+ * Copyright (C) 2004, 2005 Einar Lueck <elueck@de.ibm.com>
+ * Copyright (C) 2005 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/spinlock.h>
+
+#include <net/ip_mp_alg.h>
+
+static DEFINE_SPINLOCK(alg_table_lock);
+struct ip_mp_alg_ops *ip_mp_alg_table[IP_MP_ALG_MAX + 1];
+
+int multipath_alg_register(struct ip_mp_alg_ops *ops, enum ip_mp_alg n)
+{
+ struct ip_mp_alg_ops **slot;
+ int err;
+
+ if (n < IP_MP_ALG_NONE || n > IP_MP_ALG_MAX ||
+ !ops->mp_alg_select_route)
+ return -EINVAL;
+
+ spin_lock(&alg_table_lock);
+ slot = &ip_mp_alg_table[n];
+ if (*slot != NULL) {
+ err = -EBUSY;
+ } else {
+ *slot = ops;
+ err = 0;
+ }
+ spin_unlock(&alg_table_lock);
+
+ return err;
+}
+EXPORT_SYMBOL(multipath_alg_register);
+
+void multipath_alg_unregister(struct ip_mp_alg_ops *ops, enum ip_mp_alg n)
+{
+ struct ip_mp_alg_ops **slot;
+
+ if (n < IP_MP_ALG_NONE || n > IP_MP_ALG_MAX)
+ return;
+
+ spin_lock(&alg_table_lock);
+ slot = &ip_mp_alg_table[n];
+ if (*slot == ops)
+ *slot = NULL;
+ spin_unlock(&alg_table_lock);
+
+ synchronize_net();
+}
+EXPORT_SYMBOL(multipath_alg_unregister);
--- /dev/null
+cmd_scripts/kconfig/kxgettext.o := gcc -Wp,-MD,scripts/kconfig/.kxgettext.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -c -o scripts/kconfig/kxgettext.o scripts/kconfig/kxgettext.c
+
+deps_scripts/kconfig/kxgettext.o := \
+ scripts/kconfig/kxgettext.c \
+ /usr/include/stdlib.h \
+ /usr/include/features.h \
+ /usr/include/sys/cdefs.h \
+ /usr/include/gnu/stubs.h \
+ /usr/lib/gcc/i386-redhat-linux/3.4.2/include/stddef.h \
+ /usr/include/sys/types.h \
+ /usr/include/bits/types.h \
+ /usr/include/bits/wordsize.h \
+ /usr/include/bits/typesizes.h \
+ /usr/include/time.h \
+ /usr/include/endian.h \
+ /usr/include/bits/endian.h \
+ /usr/include/sys/select.h \
+ /usr/include/bits/select.h \
+ /usr/include/bits/sigset.h \
+ /usr/include/bits/time.h \
+ /usr/include/sys/sysmacros.h \
+ /usr/include/bits/pthreadtypes.h \
+ /usr/include/bits/sched.h \
+ /usr/include/alloca.h \
+ /usr/include/string.h \
+ /usr/include/bits/string.h \
+ /usr/include/bits/string2.h \
+ scripts/kconfig/lkc.h \
+ scripts/kconfig/expr.h \
+ /usr/include/stdio.h \
+ /usr/include/libio.h \
+ /usr/include/_G_config.h \
+ /usr/include/wchar.h \
+ /usr/include/bits/wchar.h \
+ /usr/include/gconv.h \
+ /usr/lib/gcc/i386-redhat-linux/3.4.2/include/stdarg.h \
+ /usr/include/bits/stdio_lim.h \
+ /usr/include/bits/sys_errlist.h \
+ /usr/include/bits/stdio.h \
+ /usr/lib/gcc/i386-redhat-linux/3.4.2/include/stdbool.h \
+ /usr/include/libintl.h \
+ /usr/include/locale.h \
+ /usr/include/bits/locale.h \
+ scripts/kconfig/lkc_proto.h \
+
+scripts/kconfig/kxgettext.o: $(deps_scripts/kconfig/kxgettext.o)
+
+$(deps_scripts/kconfig/kxgettext.o):
--- /dev/null
+scripts/kconfig/mconf.c
+scripts/kconfig/conf.c
+scripts/kconfig/confdata.c
+scripts/kconfig/gconf.c
+scripts/kconfig/qconf.cc
--- /dev/null
+/*
+ * Arnaldo Carvalho de Melo <acme@conectiva.com.br>, 2005
+ *
+ * Released under the terms of the GNU GPL v2.0
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+static char *escape(const char* text, char *bf, int len)
+{
+ char *bfp = bf;
+ int multiline = strchr(text, '\n') != NULL;
+
+ *bfp++ = '"';
+ --len;
+
+ if (multiline) {
+ *bfp++ = '"';
+ *bfp++ = '\n';
+ *bfp++ = '"';
+ len -= 3;
+ }
+
+ while (*text != '\0' && len > 1) {
+ if (*text == '"')
+ *bfp++ = '\\';
+ else if (*text == '\n') {
+ *bfp++ = '\\';
+ *bfp++ = 'n';
+ *bfp++ = '"';
+ *bfp++ = '\n';
+ *bfp++ = '"';
+ len -= 5;
+ ++text;
+ goto next;
+ }
+ *bfp++ = *text++;
+next:
+ --len;
+ }
+
+ if (multiline)
+ bfp -= 3;
+
+ *bfp++ = '"';
+ *bfp = '\0';
+
+ return bf;
+}
+
+struct file_line {
+ struct file_line *next;
+ char* file;
+ int lineno;
+};
+
+static struct file_line *file_line__new(char *file, int lineno)
+{
+ struct file_line *self = malloc(sizeof(*self));
+
+ if (self == NULL)
+ goto out;
+
+ self->file = file;
+ self->lineno = lineno;
+ self->next = NULL;
+out:
+ return self;
+}
+
+struct message {
+ const char *msg;
+ const char *option;
+ struct message *next;
+ struct file_line *files;
+};
+
+static struct message *message__list;
+
+static struct message *message__new(const char *msg, char *option, char *file, int lineno)
+{
+ struct message *self = malloc(sizeof(*self));
+
+ if (self == NULL)
+ goto out;
+
+ self->files = file_line__new(file, lineno);
+ if (self->files == NULL)
+ goto out_fail;
+
+ self->msg = strdup(msg);
+ if (self->msg == NULL)
+ goto out_fail_msg;
+
+ self->option = option;
+ self->next = NULL;
+out:
+ return self;
+out_fail_msg:
+ free(self->files);
+out_fail:
+ free(self);
+ self = NULL;
+ goto out;
+}
+
+static struct message *mesage__find(const char *msg)
+{
+ struct message *m = message__list;
+
+ while (m != NULL) {
+ if (strcmp(m->msg, msg) == 0)
+ break;
+ m = m->next;
+ }
+
+ return m;
+}
+
+static int message__add_file_line(struct message *self, char *file, int lineno)
+{
+ int rc = -1;
+ struct file_line *fl = file_line__new(file, lineno);
+
+ if (fl == NULL)
+ goto out;
+
+ fl->next = self->files;
+ self->files = fl;
+ rc = 0;
+out:
+ return rc;
+}
+
+static int message__add(const char *msg, char *option, char *file, int lineno)
+{
+ int rc = 0;
+ char bf[16384];
+ char *escaped = escape(msg, bf, sizeof(bf));
+ struct message *m = mesage__find(escaped);
+
+ if (m != NULL)
+ rc = message__add_file_line(m, file, lineno);
+ else {
+ m = message__new(escaped, option, file, lineno);
+
+ if (m != NULL) {
+ m->next = message__list;
+ message__list = m;
+ } else
+ rc = -1;
+ }
+ return rc;
+}
+
+void menu_build_message_list(struct menu *menu)
+{
+ struct menu *child;
+
+ message__add(menu_get_prompt(menu), NULL,
+ menu->file == NULL ? "Root Menu" : menu->file->name,
+ menu->lineno);
+
+ if (menu->sym != NULL && menu->sym->help != NULL)
+ message__add(menu->sym->help, menu->sym->name,
+ menu->file == NULL ? "Root Menu" : menu->file->name,
+ menu->lineno);
+
+ for (child = menu->list; child != NULL; child = child->next)
+ if (child->prompt != NULL)
+ menu_build_message_list(child);
+}
+
+static void message__print_file_lineno(struct message *self)
+{
+ struct file_line *fl = self->files;
+
+ printf("\n#: %s:%d", fl->file, fl->lineno);
+ fl = fl->next;
+
+ while (fl != NULL) {
+ printf(", %s:%d", fl->file, fl->lineno);
+ fl = fl->next;
+ }
+
+ if (self->option != NULL)
+ printf(", %s:00000", self->option);
+
+ putchar('\n');
+}
+
+static void message__print_gettext_msgid_msgstr(struct message *self)
+{
+ message__print_file_lineno(self);
+
+ printf("msgid %s\n"
+ "msgstr \"\"\n", self->msg);
+}
+
+void menu__xgettext(void)
+{
+ struct message *m = message__list;
+
+ while (m != NULL) {
+ message__print_gettext_msgid_msgstr(m);
+ m = m->next;
+ }
+}
+
+int main(int ac, char **av)
+{
+ conf_parse(av[1]);
+
+ menu_build_message_list(menu_get_root_menu(NULL));
+ menu__xgettext();
+ return 0;
+}
--- /dev/null
+#!/usr/bin/env python
+#
+# show_deltas: Read list of printk messages instrumented with
+# time data, and format with time deltas.
+#
+# Also, you can show the times relative to a fixed point.
+#
+# Copyright 2003 Sony Corporation
+#
+# GPL 2.0 applies.
+
+import sys
+import string
+
+def usage():
+ print """usage: show_delta [<options>] <filename>
+
+This program parses the output from a set of printk message lines which
+have time data prefixed because the CONFIG_PRINTK_TIME option is set, or
+the kernel command line option "time" is specified. When run with no
+options, the time information is converted to show the time delta between
+each printk line and the next. When run with the '-b' option, all times
+are relative to a single (base) point in time.
+
+Options:
+ -h Show this usage help.
+ -b <base> Specify a base for time references.
+ <base> can be a number or a string.
+ If it is a string, the first message line
+ which matches (at the beginning of the
+ line) is used as the time reference.
+
+ex: $ dmesg >timefile
+ $ show_delta -b NET4 timefile
+
+will show times relative to the line in the kernel output
+starting with "NET4".
+"""
+ sys.exit(1)
+
+# returns a tuple containing the seconds and text for each message line
+# seconds is returned as a float
+# raise an exception if no timing data was found
+def get_time(line):
+ if line[0]!="[":
+ raise ValueError
+
+ # split on closing bracket
+ (time_str, rest) = string.split(line[1:],']',1)
+ time = string.atof(time_str)
+
+ #print "time=", time
+ return (time, rest)
+
+
+# average line looks like:
+# [ 0.084282] VFS: Mounted root (romfs filesystem) readonly
+# time data is expressed in seconds.useconds,
+# convert_line adds a delta for each line
+last_time = 0.0
+def convert_line(line, base_time):
+ global last_time
+
+ try:
+ (time, rest) = get_time(line)
+ except:
+ # if any problem parsing time, don't convert anything
+ return line
+
+ if base_time:
+ # show time from base
+ delta = time - base_time
+ else:
+ # just show time from last line
+ delta = time - last_time
+ last_time = time
+
+ return ("[%5.6f < %5.6f >]" % (time, delta)) + rest
+
+def main():
+ base_str = ""
+ filein = ""
+ for arg in sys.argv[1:]:
+ if arg=="-b":
+ base_str = sys.argv[sys.argv.index("-b")+1]
+ elif arg=="-h":
+ usage()
+ else:
+ filein = arg
+
+ if not filein:
+ usage()
+
+ try:
+ lines = open(filein,"r").readlines()
+ except:
+ print "Problem opening file: %s" % filein
+ sys.exit(1)
+
+ if base_str:
+ print 'base= "%s"' % base_str
+ # assume a numeric base. If that fails, try searching
+ # for a matching line.
+ try:
+ base_time = float(base_str)
+ except:
+ # search for line matching <base> string
+ found = 0
+ for line in lines:
+ try:
+ (time, rest) = get_time(line)
+ except:
+ continue
+ if string.find(rest, base_str)==1:
+ base_time = time
+ found = 1
+ # stop at first match
+ break
+ if not found:
+ print 'Couldn\'t find line matching base pattern "%s"' % base_str
+ sys.exit(1)
+ else:
+ base_time = 0.0
+
+ for line in lines:
+ print convert_line(line, base_time),
+
+main()
+
--- /dev/null
+/*
+ * 32bit -> 64bit ioctl wrapper for raw MIDI API
+ * Copyright (c) by Takashi Iwai <tiwai@suse.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/* This file included from rawmidi.c */
+
+#include <linux/compat.h>
+
+struct sndrv_rawmidi_params32 {
+ s32 stream;
+ u32 buffer_size;
+ u32 avail_min;
+ unsigned int no_active_sensing; /* avoid bit-field */
+ unsigned char reserved[16];
+} __attribute__((packed));
+
+static int snd_rawmidi_ioctl_params_compat(snd_rawmidi_file_t *rfile,
+ struct sndrv_rawmidi_params32 __user *src)
+{
+ snd_rawmidi_params_t params;
+ unsigned int val;
+
+ if (rfile->output == NULL)
+ return -EINVAL;
+ if (get_user(params.stream, &src->stream) ||
+ get_user(params.buffer_size, &src->buffer_size) ||
+ get_user(params.avail_min, &src->avail_min) ||
+ get_user(val, &src->no_active_sensing))
+ return -EFAULT;
+ params.no_active_sensing = val;
+ switch (params.stream) {
+ case SNDRV_RAWMIDI_STREAM_OUTPUT:
+ return snd_rawmidi_output_params(rfile->output, ¶ms);
+ case SNDRV_RAWMIDI_STREAM_INPUT:
+ return snd_rawmidi_input_params(rfile->input, ¶ms);
+ }
+ return -EINVAL;
+}
+
+struct sndrv_rawmidi_status32 {
+ s32 stream;
+ struct compat_timespec tstamp;
+ u32 avail;
+ u32 xruns;
+ unsigned char reserved[16];
+} __attribute__((packed));
+
+static int snd_rawmidi_ioctl_status_compat(snd_rawmidi_file_t *rfile,
+ struct sndrv_rawmidi_status32 __user *src)
+{
+ int err;
+ snd_rawmidi_status_t status;
+
+ if (rfile->output == NULL)
+ return -EINVAL;
+ if (get_user(status.stream, &src->stream))
+ return -EFAULT;
+
+ switch (status.stream) {
+ case SNDRV_RAWMIDI_STREAM_OUTPUT:
+ err = snd_rawmidi_output_status(rfile->output, &status);
+ break;
+ case SNDRV_RAWMIDI_STREAM_INPUT:
+ err = snd_rawmidi_input_status(rfile->input, &status);
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (err < 0)
+ return err;
+
+ if (put_user(status.tstamp.tv_sec, &src->tstamp.tv_sec) ||
+ put_user(status.tstamp.tv_nsec, &src->tstamp.tv_nsec) ||
+ put_user(status.avail, &src->avail) ||
+ put_user(status.xruns, &src->xruns))
+ return -EFAULT;
+
+ return 0;
+}
+
+enum {
+ SNDRV_RAWMIDI_IOCTL_PARAMS32 = _IOWR('W', 0x10, struct sndrv_rawmidi_params32),
+ SNDRV_RAWMIDI_IOCTL_STATUS32 = _IOWR('W', 0x20, struct sndrv_rawmidi_status32),
+};
+
+static long snd_rawmidi_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ snd_rawmidi_file_t *rfile;
+ void __user *argp = compat_ptr(arg);
+
+ rfile = file->private_data;
+ switch (cmd) {
+ case SNDRV_RAWMIDI_IOCTL_PVERSION:
+ case SNDRV_RAWMIDI_IOCTL_INFO:
+ case SNDRV_RAWMIDI_IOCTL_DROP:
+ case SNDRV_RAWMIDI_IOCTL_DRAIN:
+ return snd_rawmidi_ioctl(file, cmd, (unsigned long)argp);
+ case SNDRV_RAWMIDI_IOCTL_PARAMS32:
+ return snd_rawmidi_ioctl_params_compat(rfile, argp);
+ case SNDRV_RAWMIDI_IOCTL_STATUS32:
+ return snd_rawmidi_ioctl_status_compat(rfile, argp);
+ }
+ return -ENOIOCTLCMD;
+}
--- /dev/null
+/*
+ * 32bit -> 64bit ioctl wrapper for sequencer API
+ * Copyright (c) by Takashi Iwai <tiwai@suse.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/* This file included from seq.c */
+
+#include <linux/compat.h>
+
+struct sndrv_seq_port_info32 {
+ struct sndrv_seq_addr addr; /* client/port numbers */
+ char name[64]; /* port name */
+
+ u32 capability; /* port capability bits */
+ u32 type; /* port type bits */
+ s32 midi_channels; /* channels per MIDI port */
+ s32 midi_voices; /* voices per MIDI port */
+ s32 synth_voices; /* voices per SYNTH port */
+
+ s32 read_use; /* R/O: subscribers for output (from this port) */
+ s32 write_use; /* R/O: subscribers for input (to this port) */
+
+ u32 kernel; /* reserved for kernel use (must be NULL) */
+ u32 flags; /* misc. conditioning */
+ unsigned char time_queue; /* queue # for timestamping */
+ char reserved[59]; /* for future use */
+};
+
+static int snd_seq_call_port_info_ioctl(client_t *client, unsigned int cmd,
+ struct sndrv_seq_port_info32 __user *data32)
+{
+ int err = -EFAULT;
+ snd_seq_port_info_t *data;
+ mm_segment_t fs;
+
+ data = kmalloc(sizeof(*data), GFP_KERNEL);
+ if (! data)
+ return -ENOMEM;
+
+ if (copy_from_user(data, data32, sizeof(*data32)) ||
+ get_user(data->flags, &data32->flags) ||
+ get_user(data->time_queue, &data32->time_queue))
+ goto error;
+ data->kernel = NULL;
+
+ fs = snd_enter_user();
+ err = snd_seq_do_ioctl(client, cmd, data);
+ snd_leave_user(fs);
+ if (err < 0)
+ goto error;
+
+ if (copy_to_user(data32, data, sizeof(*data32)) ||
+ put_user(data->flags, &data32->flags) ||
+ put_user(data->time_queue, &data32->time_queue))
+ err = -EFAULT;
+
+ error:
+ kfree(data);
+ return err;
+}
+
+
+
+/*
+ */
+
+enum {
+ SNDRV_SEQ_IOCTL_CREATE_PORT32 = _IOWR('S', 0x20, struct sndrv_seq_port_info32),
+ SNDRV_SEQ_IOCTL_DELETE_PORT32 = _IOW ('S', 0x21, struct sndrv_seq_port_info32),
+ SNDRV_SEQ_IOCTL_GET_PORT_INFO32 = _IOWR('S', 0x22, struct sndrv_seq_port_info32),
+ SNDRV_SEQ_IOCTL_SET_PORT_INFO32 = _IOW ('S', 0x23, struct sndrv_seq_port_info32),
+ SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT32 = _IOWR('S', 0x52, struct sndrv_seq_port_info32),
+};
+
+static long snd_seq_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ client_t *client = (client_t *) file->private_data;
+ void __user *argp = compat_ptr(arg);
+
+ snd_assert(client != NULL, return -ENXIO);
+
+ switch (cmd) {
+ case SNDRV_SEQ_IOCTL_PVERSION:
+ case SNDRV_SEQ_IOCTL_CLIENT_ID:
+ case SNDRV_SEQ_IOCTL_SYSTEM_INFO:
+ case SNDRV_SEQ_IOCTL_GET_CLIENT_INFO:
+ case SNDRV_SEQ_IOCTL_SET_CLIENT_INFO:
+ case SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT:
+ case SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT:
+ case SNDRV_SEQ_IOCTL_CREATE_QUEUE:
+ case SNDRV_SEQ_IOCTL_DELETE_QUEUE:
+ case SNDRV_SEQ_IOCTL_GET_QUEUE_INFO:
+ case SNDRV_SEQ_IOCTL_SET_QUEUE_INFO:
+ case SNDRV_SEQ_IOCTL_GET_NAMED_QUEUE:
+ case SNDRV_SEQ_IOCTL_GET_QUEUE_STATUS:
+ case SNDRV_SEQ_IOCTL_GET_QUEUE_TEMPO:
+ case SNDRV_SEQ_IOCTL_SET_QUEUE_TEMPO:
+ case SNDRV_SEQ_IOCTL_GET_QUEUE_TIMER:
+ case SNDRV_SEQ_IOCTL_SET_QUEUE_TIMER:
+ case SNDRV_SEQ_IOCTL_GET_QUEUE_CLIENT:
+ case SNDRV_SEQ_IOCTL_SET_QUEUE_CLIENT:
+ case SNDRV_SEQ_IOCTL_GET_CLIENT_POOL:
+ case SNDRV_SEQ_IOCTL_SET_CLIENT_POOL:
+ case SNDRV_SEQ_IOCTL_REMOVE_EVENTS:
+ case SNDRV_SEQ_IOCTL_QUERY_SUBS:
+ case SNDRV_SEQ_IOCTL_GET_SUBSCRIPTION:
+ case SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT:
+ case SNDRV_SEQ_IOCTL_RUNNING_MODE:
+ return snd_seq_do_ioctl(client, cmd, argp);
+ case SNDRV_SEQ_IOCTL_CREATE_PORT32:
+ return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_CREATE_PORT, argp);
+ case SNDRV_SEQ_IOCTL_DELETE_PORT32:
+ return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_DELETE_PORT, argp);
+ case SNDRV_SEQ_IOCTL_GET_PORT_INFO32:
+ return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_GET_PORT_INFO, argp);
+ case SNDRV_SEQ_IOCTL_SET_PORT_INFO32:
+ return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_SET_PORT_INFO, argp);
+ case SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT32:
+ return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT, argp);
+ }
+ return -ENOIOCTLCMD;
+}
--- /dev/null
+/*
+ * 32bit -> 64bit ioctl wrapper for timer API
+ * Copyright (c) by Takashi Iwai <tiwai@suse.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/* This file included from timer.c */
+
+#include <linux/compat.h>
+
+struct sndrv_timer_info32 {
+ u32 flags;
+ s32 card;
+ unsigned char id[64];
+ unsigned char name[80];
+ u32 reserved0;
+ u32 resolution;
+ unsigned char reserved[64];
+};
+
+static int snd_timer_user_info_compat(struct file *file,
+ struct sndrv_timer_info32 __user *_info)
+{
+ snd_timer_user_t *tu;
+ struct sndrv_timer_info32 info;
+ snd_timer_t *t;
+
+ tu = file->private_data;
+ snd_assert(tu->timeri != NULL, return -ENXIO);
+ t = tu->timeri->timer;
+ snd_assert(t != NULL, return -ENXIO);
+ memset(&info, 0, sizeof(info));
+ info.card = t->card ? t->card->number : -1;
+ if (t->hw.flags & SNDRV_TIMER_HW_SLAVE)
+ info.flags |= SNDRV_TIMER_FLG_SLAVE;
+ strlcpy(info.id, t->id, sizeof(info.id));
+ strlcpy(info.name, t->name, sizeof(info.name));
+ info.resolution = t->hw.resolution;
+ if (copy_to_user(_info, &info, sizeof(*_info)))
+ return -EFAULT;
+ return 0;
+}
+
+struct sndrv_timer_status32 {
+ struct compat_timespec tstamp;
+ u32 resolution;
+ u32 lost;
+ u32 overrun;
+ u32 queue;
+ unsigned char reserved[64];
+};
+
+static int snd_timer_user_status_compat(struct file *file,
+ struct sndrv_timer_status32 __user *_status)
+{
+ snd_timer_user_t *tu;
+ snd_timer_status_t status;
+
+ tu = file->private_data;
+ snd_assert(tu->timeri != NULL, return -ENXIO);
+ memset(&status, 0, sizeof(status));
+ status.tstamp = tu->tstamp;
+ status.resolution = snd_timer_resolution(tu->timeri);
+ status.lost = tu->timeri->lost;
+ status.overrun = tu->overrun;
+ spin_lock_irq(&tu->qlock);
+ status.queue = tu->qused;
+ spin_unlock_irq(&tu->qlock);
+ if (copy_to_user(_status, &status, sizeof(status)))
+ return -EFAULT;
+ return 0;
+}
+
+/*
+ */
+
+enum {
+ SNDRV_TIMER_IOCTL_INFO32 = _IOR('T', 0x11, struct sndrv_timer_info32),
+ SNDRV_TIMER_IOCTL_STATUS32 = _IOW('T', 0x14, struct sndrv_timer_status32),
+};
+
+static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ void __user *argp = compat_ptr(arg);
+
+ switch (cmd) {
+ case SNDRV_TIMER_IOCTL_PVERSION:
+ case SNDRV_TIMER_IOCTL_TREAD:
+ case SNDRV_TIMER_IOCTL_GINFO:
+ case SNDRV_TIMER_IOCTL_GPARAMS:
+ case SNDRV_TIMER_IOCTL_GSTATUS:
+ case SNDRV_TIMER_IOCTL_SELECT:
+ case SNDRV_TIMER_IOCTL_PARAMS:
+ case SNDRV_TIMER_IOCTL_START:
+ case SNDRV_TIMER_IOCTL_STOP:
+ case SNDRV_TIMER_IOCTL_CONTINUE:
+ case SNDRV_TIMER_IOCTL_NEXT_DEVICE:
+ return snd_timer_user_ioctl(file, cmd, (unsigned long)argp);
+ case SNDRV_TIMER_IOCTL_INFO32:
+ return snd_timer_user_info_compat(file, argp);
+ case SNDRV_TIMER_IOCTL_STATUS32:
+ return snd_timer_user_status_compat(file, argp);
+ }
+ return -ENOIOCTLCMD;
+}
--- /dev/null
+/* Hewlett-Packard Harmony audio driver
+ * Copyright (C) 2004, Kyle McMartin <kyle@parisc-linux.org>
+ */
+
+#ifndef __HARMONY_H__
+#define __HARMONY_H__
+
+struct harmony_buffer {
+ unsigned long addr;
+ int buf;
+ int count;
+ int size;
+ int coherent;
+};
+
+typedef struct snd_card_harmony {
+ int irq;
+
+ unsigned long hpa; /* hard physical address */
+ void __iomem *iobase; /* remapped io address */
+
+ struct parisc_device *dev;
+
+ struct {
+ u32 gain;
+ u32 rate;
+ u32 format;
+ u32 stereo;
+ int playing;
+ int capturing;
+ } st;
+
+ struct snd_dma_device dma; /* playback/capture */
+ struct harmony_buffer pbuf;
+ struct harmony_buffer cbuf;
+
+ struct snd_dma_buffer gdma; /* graveyard */
+ struct snd_dma_buffer sdma; /* silence */
+
+ struct {
+ unsigned long play_intr;
+ unsigned long rec_intr;
+ unsigned long graveyard_intr;
+ unsigned long silence_intr;
+ } stats;
+
+ snd_pcm_t *pcm;
+ snd_card_t *card;
+ snd_pcm_substream_t *psubs;
+ snd_pcm_substream_t *csubs;
+ snd_info_entry_t *proc;
+
+ spinlock_t lock;
+ spinlock_t mixer_lock;
+} harmony_t;
+
+#define MAX_PCM_DEVICES 1
+#define MAX_PCM_SUBSTREAMS 4
+#define MAX_MIDI_DEVICES 0
+
+#define HARMONY_SIZE 64
+
+#define BUF_SIZE PAGE_SIZE
+#define MAX_BUFS 10
+#define MAX_BUF_SIZE (MAX_BUFS * BUF_SIZE)
+
+#define PLAYBACK_BUFS MAX_BUFS
+#define RECORD_BUFS MAX_BUFS
+#define GRAVEYARD_BUFS 1
+#define GRAVEYARD_BUFSZ (GRAVEYARD_BUFS*BUF_SIZE)
+#define SILENCE_BUFS 1
+#define SILENCE_BUFSZ (SILENCE_BUFS*BUF_SIZE)
+
+#define HARMONY_ID 0x000
+#define HARMONY_RESET 0x004
+#define HARMONY_CNTL 0x008
+#define HARMONY_GAINCTL 0x00c
+#define HARMONY_PNXTADD 0x010
+#define HARMONY_PCURADD 0x014
+#define HARMONY_RNXTADD 0x018
+#define HARMONY_RCURADD 0x01c
+#define HARMONY_DSTATUS 0x020
+#define HARMONY_OV 0x024
+#define HARMONY_PIO 0x028
+#define HARMONY_DIAG 0x03c
+
+#define HARMONY_CNTL_C 0x80000000
+#define HARMONY_CNTL_ST 0x00000020
+#define HARMONY_CNTL_44100 0x00000015 /* HARMONY_SR_44KHZ */
+#define HARMONY_CNTL_8000 0x00000008 /* HARMONY_SR_8KHZ */
+
+#define HARMONY_DSTATUS_ID 0x00000000 /* interrupts off */
+#define HARMONY_DSTATUS_PN 0x00000200 /* playback fill */
+#define HARMONY_DSTATUS_RN 0x00000002 /* record fill */
+#define HARMONY_DSTATUS_IE 0x80000000 /* interrupts on */
+
+#define HARMONY_DF_16BIT_LINEAR 0x00000000
+#define HARMONY_DF_8BIT_ULAW 0x00000001
+#define HARMONY_DF_8BIT_ALAW 0x00000002
+
+#define HARMONY_SS_MONO 0x00000000
+#define HARMONY_SS_STEREO 0x00000001
+
+#define HARMONY_GAIN_SILENCE 0x00F00FFF
+#define HARMONY_GAIN_DEFAULT 0x0FF00000
+
+#define HARMONY_GAIN_HE_SHIFT 27
+#define HARMONY_GAIN_HE_MASK (1 << HARMONY_GAIN_HE_SHIFT)
+#define HARMONY_GAIN_LE_SHIFT 26
+#define HARMONY_GAIN_LE_MASK (1 << HARMONY_GAIN_LE_SHIFT)
+#define HARMONY_GAIN_SE_SHIFT 25
+#define HARMONY_GAIN_SE_MASK (1 << HARMONY_GAIN_SE_SHIFT)
+#define HARMONY_GAIN_IS_SHIFT 24
+#define HARMONY_GAIN_IS_MASK (1 << HARMONY_GAIN_IS_SHIFT)
+
+#define HARMONY_GAIN_MA 0x0f
+#define HARMONY_GAIN_MA_SHIFT 20
+#define HARMONY_GAIN_MA_MASK (HARMONY_GAIN_MA << HARMONY_GAIN_MA_SHIFT)
+
+#define HARMONY_GAIN_IN 0x0f
+#define HARMONY_GAIN_LI_SHIFT 16
+#define HARMONY_GAIN_LI_MASK (HARMONY_GAIN_IN << HARMONY_GAIN_LI_SHIFT)
+#define HARMONY_GAIN_RI_SHIFT 12
+#define HARMONY_GAIN_RI_MASK (HARMONY_GAIN_IN << HARMONY_GAIN_RI_SHIFT)
+
+#define HARMONY_GAIN_OUT 0x3f
+#define HARMONY_GAIN_LO_SHIFT 6
+#define HARMONY_GAIN_LO_MASK (HARMONY_GAIN_OUT << HARMONY_GAIN_LO_SHIFT)
+#define HARMONY_GAIN_RO_SHIFT 0
+#define HARMONY_GAIN_RO_MASK (HARMONY_GAIN_OUT << HARMONY_GAIN_RO_SHIFT)
+
+#define HARMONY_MAX_OUT (HARMONY_GAIN_RO_MASK >> HARMONY_GAIN_RO_SHIFT)
+#define HARMONY_MAX_IN (HARMONY_GAIN_RI_MASK >> HARMONY_GAIN_RI_SHIFT)
+#define HARMONY_MAX_MON (HARMONY_GAIN_MA_MASK >> HARMONY_GAIN_MA_SHIFT)
+
+#define HARMONY_SR_8KHZ 0x08
+#define HARMONY_SR_16KHZ 0x09
+#define HARMONY_SR_27KHZ 0x0A
+#define HARMONY_SR_32KHZ 0x0B
+#define HARMONY_SR_48KHZ 0x0E
+#define HARMONY_SR_9KHZ 0x0F
+#define HARMONY_SR_5KHZ 0x10
+#define HARMONY_SR_11KHZ 0x11
+#define HARMONY_SR_18KHZ 0x12
+#define HARMONY_SR_22KHZ 0x13
+#define HARMONY_SR_37KHZ 0x14
+#define HARMONY_SR_44KHZ 0x15
+#define HARMONY_SR_33KHZ 0x16
+#define HARMONY_SR_6KHZ 0x17
+
+#endif /* __HARMONY_H__ */
--- /dev/null
+/*
+ * Copyright (c) by James Courtier-Dutton <James@superbug.demon.co.uk>
+ * Driver p16v chips
+ * Version: 0.21
+ *
+ * FEATURES currently supported:
+ * Output fixed at S32_LE, 2 channel to hw:0,0
+ * Rates: 44.1, 48, 96, 192.
+ *
+ * Changelog:
+ * 0.8
+ * Use separate card based buffer for periods table.
+ * 0.9
+ * Use 2 channel output streams instead of 8 channel.
+ * (8 channel output streams might be good for ASIO type output)
+ * Corrected speaker output, so Front -> Front etc.
+ * 0.10
+ * Fixed missed interrupts.
+ * 0.11
+ * Add Sound card model number and names.
+ * Add Analog volume controls.
+ * 0.12
+ * Corrected playback interrupts. Now interrupt per period, instead of half period.
+ * 0.13
+ * Use single trigger for multichannel.
+ * 0.14
+ * Mic capture now works at fixed: S32_LE, 96000Hz, Stereo.
+ * 0.15
+ * Force buffer_size / period_size == INTEGER.
+ * 0.16
+ * Update p16v.c to work with changed alsa api.
+ * 0.17
+ * Update p16v.c to work with changed alsa api. Removed boot_devs.
+ * 0.18
+ * Merging with snd-emu10k1 driver.
+ * 0.19
+ * One stereo channel at 24bit now works.
+ * 0.20
+ * Added better register defines.
+ * 0.21
+ * Split from p16v.c
+ *
+ *
+ * BUGS:
+ * Some stability problems when unloading the snd-p16v kernel module.
+ * --
+ *
+ * TODO:
+ * SPDIF out.
+ * Find out how to change capture sample rates. E.g. To record SPDIF at 48000Hz.
+ * Currently capture fixed at 48000Hz.
+ *
+ * --
+ * GENERAL INFO:
+ * Model: SB0240
+ * P16V Chip: CA0151-DBS
+ * Audigy 2 Chip: CA0102-IAT
+ * AC97 Codec: STAC 9721
+ * ADC: Philips 1361T (Stereo 24bit)
+ * DAC: CS4382-K (8-channel, 24bit, 192Khz)
+ *
+ * This code was initally based on code from ALSA's emu10k1x.c which is:
+ * Copyright (c) by Francisco Moraes <fmoraes@nc.rr.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/********************************************************************************************************/
+/* Audigy2 P16V pointer-offset register set, accessed through the PTR2 and DATA2 registers */
+/********************************************************************************************************/
+
+/* The sample rate of the SPDIF outputs is set by modifying a register in the EMU10K2 PTR register A_SPDIF_SAMPLERATE.
+ * The sample rate is also controlled by the same registers that control the rate of the EMU10K2 sample rate converters.
+ */
+
+/* Initally all registers from 0x00 to 0x3f have zero contents. */
+#define PLAYBACK_LIST_ADDR 0x00 /* Base DMA address of a list of pointers to each period/size */
+ /* One list entry: 4 bytes for DMA address,
+ * 4 bytes for period_size << 16.
+ * One list entry is 8 bytes long.
+ * One list entry for each period in the buffer.
+ */
+#define PLAYBACK_LIST_SIZE 0x01 /* Size of list in bytes << 16. E.g. 8 periods -> 0x00380000 */
+#define PLAYBACK_LIST_PTR 0x02 /* Pointer to the current period being played */
+#define PLAYBACK_UNKNOWN3 0x03 /* Not used */
+#define PLAYBACK_DMA_ADDR 0x04 /* Playback DMA addresss */
+#define PLAYBACK_PERIOD_SIZE 0x05 /* Playback period size. win2000 uses 0x04000000 */
+#define PLAYBACK_POINTER 0x06 /* Playback period pointer. Used with PLAYBACK_LIST_PTR to determine buffer position currently in DAC */
+#define PLAYBACK_FIFO_END_ADDRESS 0x07 /* Playback FIFO end address */
+#define PLAYBACK_FIFO_POINTER 0x08 /* Playback FIFO pointer and number of valid sound samples in cache */
+#define PLAYBACK_UNKNOWN9 0x09 /* Not used */
+#define CAPTURE_DMA_ADDR 0x10 /* Capture DMA address */
+#define CAPTURE_BUFFER_SIZE 0x11 /* Capture buffer size */
+#define CAPTURE_POINTER 0x12 /* Capture buffer pointer. Sample currently in ADC */
+#define CAPTURE_FIFO_POINTER 0x13 /* Capture FIFO pointer and number of valid sound samples in cache */
+#define CAPTURE_P16V_VOLUME1 0x14 /* Low: Capture volume 0xXXXX3030 */
+#define CAPTURE_P16V_VOLUME2 0x15 /* High:Has no effect on capture volume */
+#define CAPTURE_P16V_SOURCE 0x16 /* P16V source select. Set to 0x0700E4E5 for AC97 CAPTURE */
+ /* [0:1] Capture input 0 channel select. 0 = Capture output 0.
+ * 1 = Capture output 1.
+ * 2 = Capture output 2.
+ * 3 = Capture output 3.
+ * [3:2] Capture input 1 channel select. 0 = Capture output 0.
+ * 1 = Capture output 1.
+ * 2 = Capture output 2.
+ * 3 = Capture output 3.
+ * [5:4] Capture input 2 channel select. 0 = Capture output 0.
+ * 1 = Capture output 1.
+ * 2 = Capture output 2.
+ * 3 = Capture output 3.
+ * [7:6] Capture input 3 channel select. 0 = Capture output 0.
+ * 1 = Capture output 1.
+ * 2 = Capture output 2.
+ * 3 = Capture output 3.
+ * [9:8] Playback input 0 channel select. 0 = Play output 0.
+ * 1 = Play output 1.
+ * 2 = Play output 2.
+ * 3 = Play output 3.
+ * [11:10] Playback input 1 channel select. 0 = Play output 0.
+ * 1 = Play output 1.
+ * 2 = Play output 2.
+ * 3 = Play output 3.
+ * [13:12] Playback input 2 channel select. 0 = Play output 0.
+ * 1 = Play output 1.
+ * 2 = Play output 2.
+ * 3 = Play output 3.
+ * [15:14] Playback input 3 channel select. 0 = Play output 0.
+ * 1 = Play output 1.
+ * 2 = Play output 2.
+ * 3 = Play output 3.
+ * [19:16] Playback mixer output enable. 1 bit per channel.
+ * [23:20] Capture mixer output enable. 1 bit per channel.
+ * [26:24] FX engine channel capture 0 = 0x60-0x67.
+ * 1 = 0x68-0x6f.
+ * 2 = 0x70-0x77.
+ * 3 = 0x78-0x7f.
+ * 4 = 0x80-0x87.
+ * 5 = 0x88-0x8f.
+ * 6 = 0x90-0x97.
+ * 7 = 0x98-0x9f.
+ * [31:27] Not used.
+ */
+
+ /* 0x1 = capture on.
+ * 0x100 = capture off.
+ * 0x200 = capture off.
+ * 0x1000 = capture off.
+ */
+#define CAPTURE_RATE_STATUS 0x17 /* Capture sample rate. Read only */
+ /* [15:0] Not used.
+ * [18:16] Channel 0 Detected sample rate. 0 - 44.1khz
+ * 1 - 48 khz
+ * 2 - 96 khz
+ * 3 - 192 khz
+ * 7 - undefined rate.
+ * [19] Channel 0. 1 - Valid, 0 - Not Valid.
+ * [22:20] Channel 1 Detected sample rate.
+ * [23] Channel 1. 1 - Valid, 0 - Not Valid.
+ * [26:24] Channel 2 Detected sample rate.
+ * [27] Channel 2. 1 - Valid, 0 - Not Valid.
+ * [30:28] Channel 3 Detected sample rate.
+ * [31] Channel 3. 1 - Valid, 0 - Not Valid.
+ */
+/* 0x18 - 0x1f unused */
+#define PLAYBACK_LAST_SAMPLE 0x20 /* The sample currently being played. Read only */
+/* 0x21 - 0x3f unused */
+#define BASIC_INTERRUPT 0x40 /* Used by both playback and capture interrupt handler */
+ /* Playback (0x1<<channel_id) Don't touch high 16bits. */
+ /* Capture (0x100<<channel_id). not tested */
+ /* Start Playback [3:0] (one bit per channel)
+ * Start Capture [11:8] (one bit per channel)
+ * Record source select for channel 0 [18:16]
+ * Record source select for channel 1 [22:20]
+ * Record source select for channel 2 [26:24]
+ * Record source select for channel 3 [30:28]
+ * 0 - SPDIF channel.
+ * 1 - I2S channel.
+ * 2 - SRC48 channel.
+ * 3 - SRCMulti_SPDIF channel.
+ * 4 - SRCMulti_I2S channel.
+ * 5 - SPDIF channel.
+ * 6 - fxengine capture.
+ * 7 - AC97 capture.
+ */
+ /* Default 41110000.
+ * Writing 0xffffffff hangs the PC.
+ * Writing 0xffff0000 -> 77770000 so it must be some sort of route.
+ * bit 0x1 starts DMA playback on channel_id 0
+ */
+/* 0x41,42 take values from 0 - 0xffffffff, but have no effect on playback */
+/* 0x43,0x48 do not remember settings */
+/* 0x41-45 unused */
+#define WATERMARK 0x46 /* Test bit to indicate cache level usage */
+ /* Values it can have while playing on channel 0.
+ * 0000f000, 0000f004, 0000f008, 0000f00c.
+ * Readonly.
+ */
+/* 0x47-0x4f unused */
+/* 0x50-0x5f Capture cache data */
+#define SRCSel 0x60 /* SRCSel. Default 0x4. Bypass P16V 0x14 */
+ /* [0] 0 = 10K2 audio, 1 = SRC48 mixer output.
+ * [2] 0 = 10K2 audio, 1 = SRCMulti SPDIF mixer output.
+ * [4] 0 = 10K2 audio, 1 = SRCMulti I2S mixer output.
+ */
+ /* SRC48 converts samples rates 44.1, 48, 96, 192 to 48 khz. */
+ /* SRCMulti converts 48khz samples rates to 44.1, 48, 96, 192 to 48. */
+ /* SRC48 and SRCMULTI sample rate select and output select. */
+ /* 0xffffffff -> 0xC0000015
+ * 0xXXXXXXX4 = Enable Front Left/Right
+ * Enable PCMs
+ */
+
+/* 0x61 -> 0x6c are Volume controls */
+#define PLAYBACK_VOLUME_MIXER1 0x61 /* SRC48 Low to mixer input volume control. */
+#define PLAYBACK_VOLUME_MIXER2 0x62 /* SRC48 High to mixer input volume control. */
+#define PLAYBACK_VOLUME_MIXER3 0x63 /* SRCMULTI SPDIF Low to mixer input volume control. */
+#define PLAYBACK_VOLUME_MIXER4 0x64 /* SRCMULTI SPDIF High to mixer input volume control. */
+#define PLAYBACK_VOLUME_MIXER5 0x65 /* SRCMULTI I2S Low to mixer input volume control. */
+#define PLAYBACK_VOLUME_MIXER6 0x66 /* SRCMULTI I2S High to mixer input volume control. */
+#define PLAYBACK_VOLUME_MIXER7 0x67 /* P16V Low to SRCMULTI SPDIF mixer input volume control. */
+#define PLAYBACK_VOLUME_MIXER8 0x68 /* P16V High to SRCMULTI SPDIF mixer input volume control. */
+#define PLAYBACK_VOLUME_MIXER9 0x69 /* P16V Low to SRCMULTI I2S mixer input volume control. */
+ /* 0xXXXX3030 = PCM0 Volume (Front).
+ * 0x3030XXXX = PCM1 Volume (Center)
+ */
+#define PLAYBACK_VOLUME_MIXER10 0x6a /* P16V High to SRCMULTI I2S mixer input volume control. */
+ /* 0x3030XXXX = PCM3 Volume (Rear). */
+#define PLAYBACK_VOLUME_MIXER11 0x6b /* E10K2 Low to SRC48 mixer input volume control. */
+#define PLAYBACK_VOLUME_MIXER12 0x6c /* E10K2 High to SRC48 mixer input volume control. */
+
+#define SRC48_ENABLE 0x6d /* SRC48 input audio enable */
+ /* SRC48 converts samples rates 44.1, 48, 96, 192 to 48 khz. */
+ /* [23:16] The corresponding P16V channel to SRC48 enabled if == 1.
+ * [31:24] The corresponding E10K2 channel to SRC48 enabled.
+ */
+#define SRCMULTI_ENABLE 0x6e /* SRCMulti input audio enable. Default 0xffffffff */
+ /* SRCMulti converts 48khz samples rates to 44.1, 48, 96, 192 to 48. */
+ /* [7:0] The corresponding P16V channel to SRCMulti_I2S enabled if == 1.
+ * [15:8] The corresponding E10K2 channel to SRCMulti I2S enabled.
+ * [23:16] The corresponding P16V channel to SRCMulti SPDIF enabled.
+ * [31:24] The corresponding E10K2 channel to SRCMulti SPDIF enabled.
+ */
+ /* Bypass P16V 0xff00ff00
+ * Bitmap. 0 = Off, 1 = On.
+ * P16V playback outputs:
+ * 0xXXXXXXX1 = PCM0 Left. (Front)
+ * 0xXXXXXXX2 = PCM0 Right.
+ * 0xXXXXXXX4 = PCM1 Left. (Center/LFE)
+ * 0xXXXXXXX8 = PCM1 Right.
+ * 0xXXXXXX1X = PCM2 Left. (Unknown)
+ * 0xXXXXXX2X = PCM2 Right.
+ * 0xXXXXXX4X = PCM3 Left. (Rear)
+ * 0xXXXXXX8X = PCM3 Right.
+ */
+#define AUDIO_OUT_ENABLE 0x6f /* Default: 000100FF */
+ /* [3:0] Does something, but not documented. Probably capture enable.
+ * [7:4] Playback channels enable. not documented.
+ * [16] AC97 output enable if == 1
+ * [30] 0 = SRCMulti_I2S input from fxengine 0x68-0x6f.
+ * 1 = SRCMulti_I2S input from SRC48 output.
+ * [31] 0 = SRCMulti_SPDIF input from fxengine 0x60-0x67.
+ * 1 = SRCMulti_SPDIF input from SRC48 output.
+ */
+ /* 0xffffffff -> C00100FF */
+ /* 0 -> Not playback sound, irq still running */
+ /* 0xXXXXXX10 = PCM0 Left/Right On. (Front)
+ * 0xXXXXXX20 = PCM1 Left/Right On. (Center/LFE)
+ * 0xXXXXXX40 = PCM2 Left/Right On. (Unknown)
+ * 0xXXXXXX80 = PCM3 Left/Right On. (Rear)
+ */
+#define PLAYBACK_SPDIF_SELECT 0x70 /* Default: 12030F00 */
+ /* 0xffffffff -> 3FF30FFF */
+ /* 0x00000001 pauses stream/irq fail. */
+ /* All other bits do not effect playback */
+#define PLAYBACK_SPDIF_SRC_SELECT 0x71 /* Default: 0000E4E4 */
+ /* 0xffffffff -> F33FFFFF */
+ /* All bits do not effect playback */
+#define PLAYBACK_SPDIF_USER_DATA0 0x72 /* SPDIF out user data 0 */
+#define PLAYBACK_SPDIF_USER_DATA1 0x73 /* SPDIF out user data 1 */
+/* 0x74-0x75 unknown */
+#define CAPTURE_SPDIF_CONTROL 0x76 /* SPDIF in control setting */
+#define CAPTURE_SPDIF_STATUS 0x77 /* SPDIF in status */
+#define CAPURE_SPDIF_USER_DATA0 0x78 /* SPDIF in user data 0 */
+#define CAPURE_SPDIF_USER_DATA1 0x79 /* SPDIF in user data 1 */
+#define CAPURE_SPDIF_USER_DATA2 0x7a /* SPDIF in user data 2 */
+
--- /dev/null
+/*
+ * Universal Interface for Intel High Definition Audio Codec
+ *
+ * HD audio interface patch for C-Media CMI9880
+ *
+ * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
+ *
+ *
+ * This driver 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 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 <sound/driver.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <sound/core.h>
+#include "hda_codec.h"
+#include "hda_local.h"
+
+
+/* board config type */
+enum {
+ CMI_MINIMAL, /* back 3-jack */
+ CMI_MIN_FP, /* back 3-jack + front-panel 2-jack */
+ CMI_FULL, /* back 6-jack + front-panel 2-jack */
+ CMI_FULL_DIG, /* back 6-jack + front-panel 2-jack + digital I/O */
+ CMI_ALLOUT, /* back 5-jack + front-panel 2-jack + digital out */
+};
+
+struct cmi_spec {
+ int board_config;
+ unsigned int surr_switch: 1; /* switchable line,mic */
+ unsigned int no_line_in: 1; /* no line-in (5-jack) */
+ unsigned int front_panel: 1; /* has front-panel 2-jack */
+
+ /* playback */
+ struct hda_multi_out multiout;
+
+ /* capture */
+ hda_nid_t *adc_nids;
+ hda_nid_t dig_in_nid;
+
+ /* capture source */
+ const struct hda_input_mux *input_mux;
+ unsigned int cur_mux[2];
+
+ /* channel mode */
+ unsigned int num_ch_modes;
+ unsigned int cur_ch_mode;
+ const struct cmi_channel_mode *channel_modes;
+
+ struct hda_pcm pcm_rec[2]; /* PCM information */
+};
+
+/*
+ * input MUX
+ */
+static int cmi_mux_enum_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct cmi_spec *spec = codec->spec;
+ return snd_hda_input_mux_info(spec->input_mux, uinfo);
+}
+
+static int cmi_mux_enum_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct cmi_spec *spec = codec->spec;
+ unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+
+ ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
+ return 0;
+}
+
+static int cmi_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct cmi_spec *spec = codec->spec;
+ unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+
+ return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
+ spec->adc_nids[adc_idx], &spec->cur_mux[adc_idx]);
+}
+
+/*
+ * shared line-in, mic for surrounds
+ */
+
+/* 3-stack / 2 channel */
+static struct hda_verb cmi9880_ch2_init[] = {
+ /* set line-in PIN for input */
+ { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
+ /* set mic PIN for input, also enable vref */
+ { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+ /* route front PCM (DAC1) to HP */
+ { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
+ {}
+};
+
+/* 3-stack / 6 channel */
+static struct hda_verb cmi9880_ch6_init[] = {
+ /* set line-in PIN for output */
+ { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+ /* set mic PIN for output */
+ { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+ /* route front PCM (DAC1) to HP */
+ { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
+ {}
+};
+
+/* 3-stack+front / 8 channel */
+static struct hda_verb cmi9880_ch8_init[] = {
+ /* set line-in PIN for output */
+ { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+ /* set mic PIN for output */
+ { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+ /* route rear-surround PCM (DAC4) to HP */
+ { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x03 },
+ {}
+};
+
+struct cmi_channel_mode {
+ unsigned int channels;
+ const struct hda_verb *sequence;
+};
+
+static struct cmi_channel_mode cmi9880_channel_modes[3] = {
+ { 2, cmi9880_ch2_init },
+ { 6, cmi9880_ch6_init },
+ { 8, cmi9880_ch8_init },
+};
+
+static int cmi_ch_mode_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct cmi_spec *spec = codec->spec;
+
+ snd_assert(spec->channel_modes, return -EINVAL);
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = spec->num_ch_modes;
+ if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+ uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
+ sprintf(uinfo->value.enumerated.name, "%dch",
+ spec->channel_modes[uinfo->value.enumerated.item].channels);
+ return 0;
+}
+
+static int cmi_ch_mode_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct cmi_spec *spec = codec->spec;
+
+ ucontrol->value.enumerated.item[0] = spec->cur_ch_mode;
+ return 0;
+}
+
+static int cmi_ch_mode_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct cmi_spec *spec = codec->spec;
+
+ snd_assert(spec->channel_modes, return -EINVAL);
+ if (ucontrol->value.enumerated.item[0] >= spec->num_ch_modes)
+ ucontrol->value.enumerated.item[0] = spec->num_ch_modes;
+ if (ucontrol->value.enumerated.item[0] == spec->cur_ch_mode &&
+ ! codec->in_resume)
+ return 0;
+
+ spec->cur_ch_mode = ucontrol->value.enumerated.item[0];
+ snd_hda_sequence_write(codec, spec->channel_modes[spec->cur_ch_mode].sequence);
+ spec->multiout.max_channels = spec->channel_modes[spec->cur_ch_mode].channels;
+ return 1;
+}
+
+/*
+ */
+static snd_kcontrol_new_t cmi9880_basic_mixer[] = {
+ /* CMI9880 has no playback volumes! */
+ HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), /* front */
+ HDA_CODEC_MUTE("Surround Playback Switch", 0x04, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Side Playback Switch", 0x06, 0x0, HDA_OUTPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ /* The multiple "Capture Source" controls confuse alsamixer
+ * So call somewhat different..
+ * FIXME: the controls appear in the "playback" view!
+ */
+ /* .name = "Capture Source", */
+ .name = "Input Source",
+ .count = 2,
+ .info = cmi_mux_enum_info,
+ .get = cmi_mux_enum_get,
+ .put = cmi_mux_enum_put,
+ },
+ HDA_CODEC_VOLUME("Capture Volume", 0x08, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0, HDA_INPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x08, 0, HDA_INPUT),
+ HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x23, 0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x23, 0, HDA_OUTPUT),
+ { } /* end */
+};
+
+/*
+ * shared I/O pins
+ */
+static snd_kcontrol_new_t cmi9880_ch_mode_mixer[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Channel Mode",
+ .info = cmi_ch_mode_info,
+ .get = cmi_ch_mode_get,
+ .put = cmi_ch_mode_put,
+ },
+ { } /* end */
+};
+
+/* AUD-in selections:
+ * 0x0b 0x0c 0x0d 0x0e 0x0f 0x10 0x11 0x1f 0x20
+ */
+static struct hda_input_mux cmi9880_basic_mux = {
+ .num_items = 4,
+ .items = {
+ { "Front Mic", 0x5 },
+ { "Rear Mic", 0x2 },
+ { "Line", 0x1 },
+ { "CD", 0x7 },
+ }
+};
+
+static struct hda_input_mux cmi9880_no_line_mux = {
+ .num_items = 3,
+ .items = {
+ { "Front Mic", 0x5 },
+ { "Rear Mic", 0x2 },
+ { "CD", 0x7 },
+ }
+};
+
+/* front, rear, clfe, rear_surr */
+static hda_nid_t cmi9880_dac_nids[4] = {
+ 0x03, 0x04, 0x05, 0x06
+};
+/* ADC0, ADC1 */
+static hda_nid_t cmi9880_adc_nids[2] = {
+ 0x08, 0x09
+};
+
+#define CMI_DIG_OUT_NID 0x07
+#define CMI_DIG_IN_NID 0x0a
+
+/*
+ */
+static struct hda_verb cmi9880_basic_init[] = {
+ /* port-D for line out (rear panel) */
+ { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
+ /* port-E for HP out (front panel) */
+ { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
+ /* route front PCM to HP */
+ { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
+ /* port-A for surround (rear panel) */
+ { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
+ /* port-G for CLFE (rear panel) */
+ { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
+ /* port-H for side (rear panel) */
+ { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
+ /* port-C for line-in (rear panel) */
+ { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
+ /* port-B for mic-in (rear panel) with vref */
+ { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+ /* port-F for mic-in (front panel) with vref */
+ { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+ /* CD-in */
+ { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
+ /* route front mic to ADC1/2 */
+ { 0x08, AC_VERB_SET_CONNECT_SEL, 0x05 },
+ { 0x09, AC_VERB_SET_CONNECT_SEL, 0x05 },
+ {} /* terminator */
+};
+
+static struct hda_verb cmi9880_allout_init[] = {
+ /* port-D for line out (rear panel) */
+ { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
+ /* port-E for HP out (front panel) */
+ { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
+ /* route front PCM to HP */
+ { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
+ /* port-A for side (rear panel) */
+ { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
+ /* port-G for CLFE (rear panel) */
+ { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
+ /* port-C for surround (rear panel) */
+ { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
+ /* port-B for mic-in (rear panel) with vref */
+ { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+ /* port-F for mic-in (front panel) with vref */
+ { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+ /* CD-in */
+ { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
+ /* route front mic to ADC1/2 */
+ { 0x08, AC_VERB_SET_CONNECT_SEL, 0x05 },
+ { 0x09, AC_VERB_SET_CONNECT_SEL, 0x05 },
+ {} /* terminator */
+};
+
+/*
+ */
+static int cmi9880_build_controls(struct hda_codec *codec)
+{
+ struct cmi_spec *spec = codec->spec;
+ int err;
+
+ err = snd_hda_add_new_ctls(codec, cmi9880_basic_mixer);
+ if (err < 0)
+ return err;
+ if (spec->surr_switch) {
+ err = snd_hda_add_new_ctls(codec, cmi9880_ch_mode_mixer);
+ if (err < 0)
+ return err;
+ }
+ if (spec->multiout.dig_out_nid) {
+ err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
+ if (err < 0)
+ return err;
+ }
+ if (spec->dig_in_nid) {
+ err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
+ if (err < 0)
+ return err;
+ }
+ return 0;
+}
+
+static int cmi9880_init(struct hda_codec *codec)
+{
+ struct cmi_spec *spec = codec->spec;
+ if (spec->board_config == CMI_ALLOUT)
+ snd_hda_sequence_write(codec, cmi9880_allout_init);
+ else
+ snd_hda_sequence_write(codec, cmi9880_basic_init);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+/*
+ * resume
+ */
+static int cmi9880_resume(struct hda_codec *codec)
+{
+ struct cmi_spec *spec = codec->spec;
+
+ cmi9880_init(codec);
+ snd_hda_resume_ctls(codec, cmi9880_basic_mixer);
+ if (spec->surr_switch)
+ snd_hda_resume_ctls(codec, cmi9880_ch_mode_mixer);
+ if (spec->multiout.dig_out_nid)
+ snd_hda_resume_spdif_out(codec);
+ if (spec->dig_in_nid)
+ snd_hda_resume_spdif_in(codec);
+
+ return 0;
+}
+#endif
+
+/*
+ * Analog playback callbacks
+ */
+static int cmi9880_playback_pcm_open(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ snd_pcm_substream_t *substream)
+{
+ struct cmi_spec *spec = codec->spec;
+ return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
+}
+
+static int cmi9880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ unsigned int stream_tag,
+ unsigned int format,
+ snd_pcm_substream_t *substream)
+{
+ struct cmi_spec *spec = codec->spec;
+ return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag,
+ format, substream);
+}
+
+static int cmi9880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ snd_pcm_substream_t *substream)
+{
+ struct cmi_spec *spec = codec->spec;
+ return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
+}
+
+/*
+ * Digital out
+ */
+static int cmi9880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ snd_pcm_substream_t *substream)
+{
+ struct cmi_spec *spec = codec->spec;
+ return snd_hda_multi_out_dig_open(codec, &spec->multiout);
+}
+
+static int cmi9880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ snd_pcm_substream_t *substream)
+{
+ struct cmi_spec *spec = codec->spec;
+ return snd_hda_multi_out_dig_close(codec, &spec->multiout);
+}
+
+/*
+ * Analog capture
+ */
+static int cmi9880_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ unsigned int stream_tag,
+ unsigned int format,
+ snd_pcm_substream_t *substream)
+{
+ struct cmi_spec *spec = codec->spec;
+
+ snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
+ stream_tag, 0, format);
+ return 0;
+}
+
+static int cmi9880_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ snd_pcm_substream_t *substream)
+{
+ struct cmi_spec *spec = codec->spec;
+
+ snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 0, 0, 0);
+ return 0;
+}
+
+
+/*
+ */
+static struct hda_pcm_stream cmi9880_pcm_analog_playback = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 8,
+ .nid = 0x03, /* NID to query formats and rates */
+ .ops = {
+ .open = cmi9880_playback_pcm_open,
+ .prepare = cmi9880_playback_pcm_prepare,
+ .cleanup = cmi9880_playback_pcm_cleanup
+ },
+};
+
+static struct hda_pcm_stream cmi9880_pcm_analog_capture = {
+ .substreams = 2,
+ .channels_min = 2,
+ .channels_max = 2,
+ .nid = 0x08, /* NID to query formats and rates */
+ .ops = {
+ .prepare = cmi9880_capture_pcm_prepare,
+ .cleanup = cmi9880_capture_pcm_cleanup
+ },
+};
+
+static struct hda_pcm_stream cmi9880_pcm_digital_playback = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 2,
+ /* NID is set in cmi9880_build_pcms */
+ .ops = {
+ .open = cmi9880_dig_playback_pcm_open,
+ .close = cmi9880_dig_playback_pcm_close
+ },
+};
+
+static struct hda_pcm_stream cmi9880_pcm_digital_capture = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 2,
+ /* NID is set in cmi9880_build_pcms */
+};
+
+static int cmi9880_build_pcms(struct hda_codec *codec)
+{
+ struct cmi_spec *spec = codec->spec;
+ struct hda_pcm *info = spec->pcm_rec;
+
+ codec->num_pcms = 1;
+ codec->pcm_info = info;
+
+ info->name = "CMI9880";
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK] = cmi9880_pcm_analog_playback;
+ info->stream[SNDRV_PCM_STREAM_CAPTURE] = cmi9880_pcm_analog_capture;
+
+ if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
+ codec->num_pcms++;
+ info++;
+ info->name = "CMI9880 Digital";
+ if (spec->multiout.dig_out_nid) {
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK] = cmi9880_pcm_digital_playback;
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
+ }
+ if (spec->dig_in_nid) {
+ info->stream[SNDRV_PCM_STREAM_CAPTURE] = cmi9880_pcm_digital_capture;
+ info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
+ }
+ }
+
+ return 0;
+}
+
+static void cmi9880_free(struct hda_codec *codec)
+{
+ kfree(codec->spec);
+}
+
+/*
+ */
+
+static struct hda_board_config cmi9880_cfg_tbl[] = {
+ { .modelname = "minimal", .config = CMI_MINIMAL },
+ { .modelname = "min_fp", .config = CMI_MIN_FP },
+ { .modelname = "full", .config = CMI_FULL },
+ { .modelname = "full_dig", .config = CMI_FULL_DIG },
+ { .modelname = "allout", .config = CMI_ALLOUT },
+ {} /* terminator */
+};
+
+static struct hda_codec_ops cmi9880_patch_ops = {
+ .build_controls = cmi9880_build_controls,
+ .build_pcms = cmi9880_build_pcms,
+ .init = cmi9880_init,
+ .free = cmi9880_free,
+#ifdef CONFIG_PM
+ .resume = cmi9880_resume,
+#endif
+};
+
+static int patch_cmi9880(struct hda_codec *codec)
+{
+ struct cmi_spec *spec;
+
+ spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+ if (spec == NULL)
+ return -ENOMEM;
+
+ codec->spec = spec;
+ spec->board_config = snd_hda_check_board_config(codec, cmi9880_cfg_tbl);
+ if (spec->board_config < 0) {
+ snd_printd(KERN_INFO "hda_codec: Unknown model for CMI9880\n");
+ spec->board_config = CMI_FULL_DIG; /* try everything */
+ }
+
+ switch (spec->board_config) {
+ case CMI_MINIMAL:
+ case CMI_MIN_FP:
+ spec->surr_switch = 1;
+ if (spec->board_config == CMI_MINIMAL)
+ spec->num_ch_modes = 2;
+ else {
+ spec->front_panel = 1;
+ spec->num_ch_modes = 3;
+ }
+ spec->channel_modes = cmi9880_channel_modes;
+ spec->multiout.max_channels = cmi9880_channel_modes[0].channels;
+ spec->input_mux = &cmi9880_basic_mux;
+ break;
+ case CMI_FULL:
+ case CMI_FULL_DIG:
+ spec->front_panel = 1;
+ spec->multiout.max_channels = 8;
+ spec->input_mux = &cmi9880_basic_mux;
+ if (spec->board_config == CMI_FULL_DIG) {
+ spec->multiout.dig_out_nid = CMI_DIG_OUT_NID;
+ spec->dig_in_nid = CMI_DIG_IN_NID;
+ }
+ break;
+ case CMI_ALLOUT:
+ spec->front_panel = 1;
+ spec->multiout.max_channels = 8;
+ spec->no_line_in = 1;
+ spec->input_mux = &cmi9880_no_line_mux;
+ spec->multiout.dig_out_nid = CMI_DIG_OUT_NID;
+ break;
+ }
+
+ spec->multiout.num_dacs = 4;
+ spec->multiout.dac_nids = cmi9880_dac_nids;
+
+ spec->adc_nids = cmi9880_adc_nids;
+
+ codec->patch_ops = cmi9880_patch_ops;
+
+ return 0;
+}
+
+/*
+ * patch entries
+ */
+struct hda_codec_preset snd_hda_preset_cmedia[] = {
+ { .id = 0x13f69880, .name = "CMI9880", .patch = patch_cmi9880 },
+ { .id = 0x434d4980, .name = "CMI9880", .patch = patch_cmi9880 },
+ {} /* terminator */
+};
--- /dev/null
+/*
+ * ALSA driver for ICEnsemble VT1724 (Envy24HT)
+ *
+ * Lowlevel functions for ESI Juli@ cards
+ *
+ * Copyright (c) 2004 Jaroslav Kysela <perex@suse.cz>
+ *
+ * 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 <sound/driver.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+
+#include "ice1712.h"
+#include "envy24ht.h"
+#include "juli.h"
+
+/*
+ * chip addresses on I2C bus
+ */
+#define AK4114_ADDR 0x20 /* S/PDIF receiver */
+#define AK4358_ADDR 0x22 /* DAC */
+
+/*
+ * GPIO pins
+ */
+#define GPIO_FREQ_MASK (3<<0)
+#define GPIO_FREQ_32KHZ (0<<0)
+#define GPIO_FREQ_44KHZ (1<<0)
+#define GPIO_FREQ_48KHZ (2<<0)
+#define GPIO_MULTI_MASK (3<<2)
+#define GPIO_MULTI_4X (0<<2)
+#define GPIO_MULTI_2X (1<<2)
+#define GPIO_MULTI_1X (2<<2) /* also external */
+#define GPIO_MULTI_HALF (3<<2)
+#define GPIO_INTERNAL_CLOCK (1<<4)
+#define GPIO_ANALOG_PRESENT (1<<5) /* RO only: 0 = present */
+#define GPIO_RXMCLK_SEL (1<<7) /* must be 0 */
+#define GPIO_AK5385A_CKS0 (1<<8)
+#define GPIO_AK5385A_DFS0 (1<<9) /* swapped with DFS1 according doc? */
+#define GPIO_AK5385A_DFS1 (1<<10)
+#define GPIO_DIGOUT_MONITOR (1<<11) /* 1 = active */
+#define GPIO_DIGIN_MONITOR (1<<12) /* 1 = active */
+#define GPIO_ANAIN_MONITOR (1<<13) /* 1 = active */
+#define GPIO_AK5385A_MCLK (1<<14) /* must be 0 */
+#define GPIO_MUTE_CONTROL (1<<15) /* 0 = off, 1 = on */
+
+static void juli_ak4114_write(void *private_data, unsigned char reg, unsigned char val)
+{
+ snd_vt1724_write_i2c((ice1712_t *)private_data, AK4114_ADDR, reg, val);
+}
+
+static unsigned char juli_ak4114_read(void *private_data, unsigned char reg)
+{
+ return snd_vt1724_read_i2c((ice1712_t *)private_data, AK4114_ADDR, reg);
+}
+
+/*
+ * AK4358 section
+ */
+
+static void juli_akm_lock(akm4xxx_t *ak, int chip)
+{
+}
+
+static void juli_akm_unlock(akm4xxx_t *ak, int chip)
+{
+}
+
+static void juli_akm_write(akm4xxx_t *ak, int chip,
+ unsigned char addr, unsigned char data)
+{
+ ice1712_t *ice = ak->private_data[0];
+
+ snd_assert(chip == 0, return);
+ snd_vt1724_write_i2c(ice, AK4358_ADDR, addr, data);
+}
+
+/*
+ * change the rate of envy24HT, AK4358
+ */
+static void juli_akm_set_rate_val(akm4xxx_t *ak, unsigned int rate)
+{
+ unsigned char old, tmp, dfs;
+
+ if (rate == 0) /* no hint - S/PDIF input is master, simply return */
+ return;
+
+ /* adjust DFS on codecs */
+ if (rate > 96000)
+ dfs = 2;
+ else if (rate > 48000)
+ dfs = 1;
+ else
+ dfs = 0;
+
+ tmp = snd_akm4xxx_get(ak, 0, 2);
+ old = (tmp >> 4) & 0x03;
+ if (old == dfs)
+ return;
+ /* reset DFS */
+ snd_akm4xxx_reset(ak, 1);
+ tmp = snd_akm4xxx_get(ak, 0, 2);
+ tmp &= ~(0x03 << 4);
+ tmp |= dfs << 4;
+ snd_akm4xxx_set(ak, 0, 2, tmp);
+ snd_akm4xxx_reset(ak, 0);
+}
+
+static akm4xxx_t akm_juli_dac __devinitdata = {
+ .type = SND_AK4358,
+ .num_dacs = 2,
+ .ops = {
+ .lock = juli_akm_lock,
+ .unlock = juli_akm_unlock,
+ .write = juli_akm_write,
+ .set_rate_val = juli_akm_set_rate_val
+ }
+};
+
+static int __devinit juli_add_controls(ice1712_t *ice)
+{
+ return snd_ice1712_akm4xxx_build_controls(ice);
+}
+
+/*
+ * initialize the chip
+ */
+static int __devinit juli_init(ice1712_t *ice)
+{
+ static unsigned char ak4114_init_vals[] = {
+ /* AK4117_REG_PWRDN */ AK4114_RST | AK4114_PWN | AK4114_OCKS0 | AK4114_OCKS1,
+ /* AK4114_REQ_FORMAT */ AK4114_DIF_I24I2S,
+ /* AK4114_REG_IO0 */ AK4114_TX1E,
+ /* AK4114_REG_IO1 */ AK4114_EFH_1024 | AK4114_DIT | AK4114_IPS(1),
+ /* AK4114_REG_INT0_MASK */ 0,
+ /* AK4114_REG_INT1_MASK */ 0
+ };
+ static unsigned char ak4114_init_txcsb[] = {
+ 0x41, 0x02, 0x2c, 0x00, 0x00
+ };
+ int err;
+ akm4xxx_t *ak;
+
+#if 0
+ for (err = 0; err < 0x20; err++)
+ juli_ak4114_read(ice, err);
+ juli_ak4114_write(ice, 0, 0x0f);
+ juli_ak4114_read(ice, 0);
+ juli_ak4114_read(ice, 1);
+#endif
+ err = snd_ak4114_create(ice->card,
+ juli_ak4114_read,
+ juli_ak4114_write,
+ ak4114_init_vals, ak4114_init_txcsb,
+ ice, &ice->spec.juli.ak4114);
+ if (err < 0)
+ return err;
+
+ ice->spec.juli.analog = ice->gpio.get_data(ice) & GPIO_ANALOG_PRESENT;
+
+ if (ice->spec.juli.analog) {
+ printk(KERN_INFO "juli@: analog I/O detected\n");
+ ice->num_total_dacs = 2;
+ ice->num_total_adcs = 2;
+
+ ak = ice->akm = kcalloc(1, sizeof(akm4xxx_t), GFP_KERNEL);
+ if (! ak)
+ return -ENOMEM;
+ ice->akm_codecs = 1;
+ if ((err = snd_ice1712_akm4xxx_init(ak, &akm_juli_dac, NULL, ice)) < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Juli@ boards don't provide the EEPROM data except for the vendor IDs.
+ * hence the driver needs to sets up it properly.
+ */
+
+static unsigned char juli_eeprom[] __devinitdata = {
+ 0x20, /* SYSCONF: clock 512, mpu401, 1xADC, 1xDACs */
+ 0x80, /* ACLINK: I2S */
+ 0xf8, /* I2S: vol, 96k, 24bit, 192k */
+ 0xc3, /* SPDIF: out-en, out-int, spdif-in */
+ 0x9f, /* GPIO_DIR */
+ 0xff, /* GPIO_DIR1 */
+ 0x7f, /* GPIO_DIR2 */
+ 0x9f, /* GPIO_MASK */
+ 0xff, /* GPIO_MASK1 */
+ 0x7f, /* GPIO_MASK2 */
+ 0x16, /* GPIO_STATE: internal clock, multiple 1x, 48kHz */
+ 0x80, /* GPIO_STATE1: mute */
+ 0x00, /* GPIO_STATE2 */
+};
+
+/* entry point */
+struct snd_ice1712_card_info snd_vt1724_juli_cards[] __devinitdata = {
+ {
+ .subvendor = VT1724_SUBDEVICE_JULI,
+ .name = "ESI Juli@",
+ .model = "juli",
+ .chip_init = juli_init,
+ .build_controls = juli_add_controls,
+ .eeprom_size = sizeof(juli_eeprom),
+ .eeprom_data = juli_eeprom,
+ },
+ { } /* terminator */
+};
--- /dev/null
+#ifndef __SOUND_JULI_H
+#define __SOUND_JULI_H
+
+#define JULI_DEVICE_DESC "{ESI,Juli@},"
+
+#define VT1724_SUBDEVICE_JULI 0x31305345 /* Juli@ */
+
+extern struct snd_ice1712_card_info snd_vt1724_juli_cards[];
+
+#endif /* __SOUND_JULI_H */
--- /dev/null
+#ifndef __SOUND_PHASE_H
+#define __SOUND_PHASE_H
+
+/*
+ * ALSA driver for ICEnsemble ICE1712 (Envy24)
+ *
+ * Lowlevel functions for Terratec PHASE 22
+ *
+ * Copyright (c) 2005 Misha Zhilin <misha@epiphan.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#define PHASE_DEVICE_DESC "{Terratec,Phase 22},"
+
+#define VT1724_SUBDEVICE_PHASE22 0x3b155011
+
+/* entry point */
+extern struct snd_ice1712_card_info snd_vt1724_phase_cards[];
+
+#endif /* __SOUND_PHASE */