Do arch/ia64/defconfig by hand.
S: D-91080 Uttenreuth
S: Germany
+N: Jaya Kumar
+E: jayalk@intworks.biz
+W: http://www.intworks.biz
+D: Arc monochrome LCD framebuffer driver, x86 reboot fixups
+S: Gurgaon, India
+S: Kuala Lumpur, Malaysia
+
N: Gabor Kuti
M: seasons@falcon.sch.bme.hu
M: seasons@makosteszta.sote.hu
D: bug fixes, documentation, minor hackery
N: James Morris
-E: jmorris@intercode.com.au
+E: jmorris@redhat.com
W: http://www.intercode.com.au/jmorris/
-D: Netfilter, Linux Security Modules (LSM).
+D: Netfilter, Linux Security Modules (LSM), SELinux, IPSec,
+D: Crypto API, general networking, miscellaneous.
S: PO Box 707
S: Spit Junction NSW 2088
S: Australia
--- /dev/null
+Intel 830M/845G/852GM/855GM/865G/915G Framebuffer driver
+================================================================
+
+A. Introduction
+ This is a framebuffer driver for various Intel 810/815 compatible
+graphics devices. These would include:
+
+ Intel 830M
+ Intel 810E845G
+ Intel 852GM
+ Intel 855GM
+ Intel 865G
+ Intel 915G
+
+B. List of available options
+
+ a. "video=intelfb"
+ enables the intelfb driver
+
+ Recommendation: required
+
+ b. "mode=<xres>x<yres>[-<bpp>][@<refresh>]"
+ select mode
+
+ Recommendation: user preference
+ (default = 1024x768-32@70)
+
+ c. "vram=<value>"
+ select amount of system RAM in MB to allocate for the video memory
+ if not enough RAM was already allocated by the BIOS.
+
+ Recommendation: 1 - 4 MB.
+ (default = 4 MB)
+
+ d. "voffset=<value>"
+ select at what offset in MB of the logical memory to allocate the
+ framebuffer memory. The intent is to avoid the memory blocks
+ used by standard graphics applications (XFree86). Depending on your
+ usage, adjust the value up or down, (0 for maximum usage, 63/127 MB
+ for the least amount). Note, an arbitrary setting may conflict
+ with XFree86.
+
+ Recommendation: do not set
+ (default = 48 MB)
+
+ e. "accel"
+ enable text acceleration. This can be enabled/reenabled anytime
+ by using 'fbset -accel true/false'.
+
+ Recommendation: enable
+ (default = set)
+
+ f. "hwcursor"
+ enable cursor acceleration.
+
+ Recommendation: enable
+ (default = set)
+
+ g. "mtrr"
+ enable MTRR. This allows data transfers to the framebuffer memory
+ to occur in bursts which can significantly increase performance.
+ Not very helpful with the intel chips because of 'shared memory'.
+
+ Recommendation: set
+ (default = set)
+
+ h. "fixed"
+ disable mode switching.
+
+ Recommendation: do not set
+ (default = not set)
+
+ The binary parameters can be unset with a "no" prefix, example "noaccel".
+ The default parameter (not named) is the mode.
+
+C. Kernel booting
+
+Separate each option/option-pair by commas (,) and the option from its value
+with an equals sign (=) as in the following:
+
+video=i810fb:option1,option2=value2
+
+Sample Usage
+------------
+
+In /etc/lilo.conf, add the line:
+
+append="video=intelfb:800x600-32@75,accel,hwcursor,vram=8"
+
+This will initialize the framebuffer to 800x600 at 32bpp and 75Hz. The
+framebuffer will use 8 MB of System RAM. hw acceleration of text and cursor
+will be enabled.
+
+D. Module options
+
+ The module parameters are essentially similar to the kernel
+parameters. The main difference is that you need to include a Boolean value
+(1 for TRUE, and 0 for FALSE) for those options which don't need a value.
+
+Example, to enable MTRR, include "mtrr=1".
+
+Sample Usage
+------------
+
+Using the same setup as described above, load the module like this:
+
+ modprobe intelfb mode=800x600-32@75 vram=8 accel=1 hwcursor=1
+
+Or just add the following to /etc/modprobe.conf
+
+ options intelfb mode=800x600-32@75 vram=8 accel=1 hwcursor=1
+
+and just do a
+
+ modprobe intelfb
+
+
+E. Acknowledgment:
+
+ 1. Geert Uytterhoeven - his excellent howto and the virtual
+ framebuffer driver code made this possible.
+
+ 2. Jeff Hartmann for his agpgart code.
+
+ 3. David Dawes for his original kernel 2.4 code.
+
+ 4. The X developers. Insights were provided just by reading the
+ XFree86 source code.
+
+ 5. Antonino A. Daplas for his inspiring i810fb driver.
+
+ 6. Andrew Morton for his kernel patches maintenance.
+
+###########################
+Sylvain
more efficient. You should really be using libraw1394 for raw1394
access anyway.
Who: Jody McIntyre <scjody@steamballoon.com>
+
+---------------------------
+
+What: i2c sysfs name change: in1_ref, vid deprecated in favour of cpu0_vid
+When: November 2005
+Files: drivers/i2c/chips/adm1025.c, drivers/i2c/chips/adm1026.c
+Why: Match the other drivers' name for the same function, duplicate names
+ will be available until removal of old names.
+Who: Grant Coady <gcoady@gmail.com>
+
mode=xxx Sets the permissions on files to xxx
nojoliet Ignore Joliet extensions if they are present.
norock Ignore Rock Ridge extensions if they are present.
- unhide Show hidden files.
+ hide Completely strip hidden files from the file system.
+ showassoc Show files marked with the 'associated' bit
+ unhide Deprecated; showing hidden files is now default;
+ If given, it is a synonym for 'showassoc' which will
+ recreate previous unhide behavior
session=x Select number of session on multisession CD
sbsector=xxx Session begins from sector xxx
to limit this tmpfs instance to that percentage of your physical RAM:
the default, when neither size nor nr_blocks is specified, is size=50%
-If both nr_blocks (or size) and nr_inodes are set to 0, neither blocks
-nor inodes will be limited in that instance. It is generally unwise to
+If nr_blocks=0 (or size=0), blocks will not be limited in that instance;
+if nr_inodes=0, inodes will not be limited. It is generally unwise to
mount with such options, since it allows any user with write access to
use up all the memory on the machine; but enhances the scalability of
that instance in a system with many cpus making intensive use of it.
Author:
Christoph Rohland <cr@sap.com>, 1.12.01
Updated:
- Hugh Dickins <hugh@veritas.com>, 01 September 2004
+ Hugh Dickins <hugh@veritas.com>, 13 March 2005
chipsets as well: 635, and 635T. If anyone owns a board with those chips
AND is willing to risk crashing & burning an otherwise well-behaved kernel
in the name of progress... please contact me at <mhoffman@lightlink.com> or
-via the project's mailing list: <sensors@stimpy.netroedge.com>. Please
+via the project's mailing list: <lm-sensors@lm-sensors.org>. Please
send bug reports and/or success stories as well.
--- /dev/null
+Kernel driver adm1021
+=====================
+
+Supported chips:
+ * Analog Devices ADM1021
+ Prefix: 'adm1021'
+ Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
+ Datasheet: Publicly available at the Analog Devices website
+ * Analog Devices ADM1021A/ADM1023
+ Prefix: 'adm1023'
+ Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
+ Datasheet: Publicly available at the Analog Devices website
+ * Genesys Logic GL523SM
+ Prefix: 'gl523sm'
+ Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
+ Datasheet:
+ * Intel Xeon Processor
+ Prefix: - any other - may require 'force_adm1021' parameter
+ Addresses scanned: none
+ Datasheet: Publicly available at Intel website
+ * Maxim MAX1617
+ Prefix: 'max1617'
+ Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
+ Datasheet: Publicly available at the Maxim website
+ * Maxim MAX1617A
+ Prefix: 'max1617a'
+ Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
+ Datasheet: Publicly available at the Maxim website
+ * National Semiconductor LM84
+ Prefix: 'lm84'
+ Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
+ Datasheet: Publicly available at the National Semiconductor website
+ * Philips NE1617
+ Prefix: 'max1617' (probably detected as a max1617)
+ Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
+ Datasheet: Publicly available at the Philips website
+ * Philips NE1617A
+ Prefix: 'max1617' (probably detected as a max1617)
+ Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
+ Datasheet: Publicly available at the Philips website
+ * TI THMC10
+ Prefix: 'thmc10'
+ Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
+ Datasheet: Publicly available at the TI website
+ * Onsemi MC1066
+ Prefix: 'mc1066'
+ Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
+ Datasheet: Publicly available at the Onsemi website
+
+
+Authors:
+ Frodo Looijaard <frodol@dds.nl>,
+ Philip Edelbrock <phil@netroedge.com>
+
+Module Parameters
+-----------------
+
+* read_only: int
+ Don't set any values, read only mode
+
+
+Description
+-----------
+
+The chips supported by this driver are very similar. The Maxim MAX1617 is
+the oldest; it has the problem that it is not very well detectable. The
+MAX1617A solves that. The ADM1021 is a straight clone of the MAX1617A.
+Ditto for the THMC10. From here on, we will refer to all these chips as
+ADM1021-clones.
+
+The ADM1021 and MAX1617A reports a die code, which is a sort of revision
+code. This can help us pinpoint problems; it is not very useful
+otherwise.
+
+ADM1021-clones implement two temperature sensors. One of them is internal,
+and measures the temperature of the chip itself; the other is external and
+is realised in the form of a transistor-like device. A special alarm
+indicates whether the remote sensor is connected.
+
+Each sensor has its own low and high limits. When they are crossed, the
+corresponding alarm is set and remains on as long as the temperature stays
+out of range. Temperatures are measured in degrees Celsius. Measurements
+are possible between -65 and +127 degrees, with a resolution of one degree.
+
+If an alarm triggers, it will remain triggered until the hardware register
+is read at least once. This means that the cause for the alarm may already
+have disappeared!
+
+This driver only updates its values each 1.5 seconds; reading it more often
+will do no harm, but will return 'old' values. It is possible to make
+ADM1021-clones do faster measurements, but there is really no good reason
+for that.
+
+Xeon support
+------------
+
+Some Xeon processors have real max1617, adm1021, or compatible chips
+within them, with two temperature sensors.
+
+Other Xeons have chips with only one sensor.
+
+If you have a Xeon, and the adm1021 module loads, and both temperatures
+appear valid, then things are good.
+
+If the adm1021 module doesn't load, you should try this:
+ modprobe adm1021 force_adm1021=BUS,ADDRESS
+ ADDRESS can only be 0x18, 0x1a, 0x29, 0x2b, 0x4c, or 0x4e.
+
+If you have dual Xeons you may have appear to have two separate
+adm1021-compatible chips, or two single-temperature sensors, at distinct
+addresses.
--- /dev/null
+Kernel driver adm1025
+=====================
+
+Supported chips:
+ * Analog Devices ADM1025, ADM1025A
+ Prefix: 'adm1025'
+ Addresses scanned: I2C 0x2c - 0x2e
+ Datasheet: Publicly available at the Analog Devices website
+ * Philips NE1619
+ Prefix: 'ne1619'
+ Addresses scanned: I2C 0x2c - 0x2d
+ Datasheet: Publicly available at the Philips website
+
+The NE1619 presents some differences with the original ADM1025:
+ * Only two possible addresses (0x2c - 0x2d).
+ * No temperature offset register, but we don't use it anyway.
+ * No INT mode for pin 16. We don't play with it anyway.
+
+Authors:
+ Chen-Yuan Wu <gwu@esoft.com>,
+ Jean Delvare <khali@linux-fr.org>
+
+Description
+-----------
+
+(This is from Analog Devices.) The ADM1025 is a complete system hardware
+monitor for microprocessor-based systems, providing measurement and limit
+comparison of various system parameters. Five voltage measurement inputs
+are provided, for monitoring +2.5V, +3.3V, +5V and +12V power supplies and
+the processor core voltage. The ADM1025 can monitor a sixth power-supply
+voltage by measuring its own VCC. One input (two pins) is dedicated to a
+remote temperature-sensing diode and an on-chip temperature sensor allows
+ambient temperature to be monitored.
+
+One specificity of this chip is that the pin 11 can be hardwired in two
+different manners. It can act as the +12V power-supply voltage analog
+input, or as the a fifth digital entry for the VID reading (bit 4). It's
+kind of strange since both are useful, and the reason for designing the
+chip that way is obscure at least to me. The bit 5 of the configuration
+register can be used to define how the chip is hardwired. Please note that
+it is not a choice you have to make as the user. The choice was already
+made by your motherboard's maker. If the configuration bit isn't set
+properly, you'll have a wrong +12V reading or a wrong VID reading. The way
+the driver handles that is to preserve this bit through the initialization
+process, assuming that the BIOS set it up properly beforehand. If it turns
+out not to be true in some cases, we'll provide a module parameter to force
+modes.
+
+This driver also supports the ADM1025A, which differs from the ADM1025
+only in that it has "open-drain VID inputs while the ADM1025 has on-chip
+100k pull-ups on the VID inputs". It doesn't make any difference for us.
--- /dev/null
+Kernel driver adm1026
+=====================
+
+Supported chips:
+ * Analog Devices ADM1026
+ Prefix: 'adm1026'
+ Addresses scanned: I2C 0x2c, 0x2d, 0x2e
+ Datasheet: Publicly available at the Analog Devices website
+ http://www.analog.com/en/prod/0,,766_825_ADM1026,00.html
+
+Authors:
+ Philip Pokorny <ppokorny@penguincomputing.com> for Penguin Computing
+ Justin Thiessen <jthiessen@penguincomputing.com>
+
+Module Parameters
+-----------------
+
+* gpio_input: int array (min = 1, max = 17)
+ List of GPIO pins (0-16) to program as inputs
+* gpio_output: int array (min = 1, max = 17)
+ List of GPIO pins (0-16) to program as outputs
+* gpio_inverted: int array (min = 1, max = 17)
+ List of GPIO pins (0-16) to program as inverted
+* gpio_normal: int array (min = 1, max = 17)
+ List of GPIO pins (0-16) to program as normal/non-inverted
+* gpio_fan: int array (min = 1, max = 8)
+ List of GPIO pins (0-7) to program as fan tachs
+
+
+Description
+-----------
+
+This driver implements support for the Analog Devices ADM1026. Analog
+Devices calls it a "complete thermal system management controller."
+
+The ADM1026 implements three (3) temperature sensors, 17 voltage sensors,
+16 general purpose digital I/O lines, eight (8) fan speed sensors (8-bit),
+an analog output and a PWM output along with limit, alarm and mask bits for
+all of the above. There is even 8k bytes of EEPROM memory on chip.
+
+Temperatures are measured in degrees Celsius. There are two external
+sensor inputs and one internal sensor. Each sensor has a high and low
+limit. If the limit is exceeded, an interrupt (#SMBALERT) can be
+generated. The interrupts can be masked. In addition, there are over-temp
+limits for each sensor. If this limit is exceeded, the #THERM output will
+be asserted. The current temperature and limits have a resolution of 1
+degree.
+
+Fan rotation speeds are reported in RPM (rotations per minute) but measured
+in counts of a 22.5kHz internal clock. Each fan has a high limit which
+corresponds to a minimum fan speed. If the limit is exceeded, an interrupt
+can be generated. Each fan can be programmed to divide the reference clock
+by 1, 2, 4 or 8. Not all RPM values can accurately be represented, so some
+rounding is done. With a divider of 8, the slowest measurable speed of a
+two pulse per revolution fan is 661 RPM.
+
+There are 17 voltage sensors. An alarm is triggered if the voltage has
+crossed a programmable minimum or maximum limit. Note that minimum in this
+case always means 'closest to zero'; this is important for negative voltage
+measurements. Several inputs have integrated attenuators so they can measure
+higher voltages directly. 3.3V, 5V, 12V, -12V and battery voltage all have
+dedicated inputs. There are several inputs scaled to 0-3V full-scale range
+for SCSI terminator power. The remaining inputs are not scaled and have
+a 0-2.5V full-scale range. A 2.5V or 1.82V reference voltage is provided
+for negative voltage measurements.
+
+If an alarm triggers, it will remain triggered until the hardware register
+is read at least once. This means that the cause for the alarm may already
+have disappeared! Note that in the current implementation, all hardware
+registers are read whenever any data is read (unless it is less than 2.0
+seconds since the last update). This means that you can easily miss
+once-only alarms.
+
+The ADM1026 measures continuously. Analog inputs are measured about 4
+times a second. Fan speed measurement time depends on fan speed and
+divisor. It can take as long as 1.5 seconds to measure all fan speeds.
+
+The ADM1026 has the ability to automatically control fan speed based on the
+temperature sensor inputs. Both the PWM output and the DAC output can be
+used to control fan speed. Usually only one of these two outputs will be
+used. Write the minimum PWM or DAC value to the appropriate control
+register. Then set the low temperature limit in the tmin values for each
+temperature sensor. The range of control is fixed at 20 °C, and the
+largest difference between current and tmin of the temperature sensors sets
+the control output. See the datasheet for several example circuits for
+controlling fan speed with the PWM and DAC outputs. The fan speed sensors
+do not have PWM compensation, so it is probably best to control the fan
+voltage from the power lead rather than on the ground lead.
+
+The datasheet shows an example application with VID signals attached to
+GPIO lines. Unfortunately, the chip may not be connected to the VID lines
+in this way. The driver assumes that the chips *is* connected this way to
+get a VID voltage.
--- /dev/null
+Kernel driver adm1031
+=====================
+
+Supported chips:
+ * Analog Devices ADM1030
+ Prefix: 'adm1030'
+ Addresses scanned: I2C 0x2c to 0x2e
+ Datasheet: Publicly available at the Analog Devices website
+ http://products.analog.com/products/info.asp?product=ADM1030
+
+ * Analog Devices ADM1031
+ Prefix: 'adm1031'
+ Addresses scanned: I2C 0x2c to 0x2e
+ Datasheet: Publicly available at the Analog Devices website
+ http://products.analog.com/products/info.asp?product=ADM1031
+
+Authors:
+ Alexandre d'Alton <alex@alexdalton.org>
+ Jean Delvare <khali@linux-fr.org>
+
+Description
+-----------
+
+The ADM1030 and ADM1031 are digital temperature sensors and fan controllers.
+They sense their own temperature as well as the temperature of up to one
+(ADM1030) or two (ADM1031) external diodes.
+
+All temperature values are given in degrees Celsius. Resolution is 0.5
+degree for the local temperature, 0.125 degree for the remote temperatures.
+
+Each temperature channel has its own high and low limits, plus a critical
+limit.
+
+The ADM1030 monitors a single fan speed, while the ADM1031 monitors up to
+two. Each fan channel has its own low speed limit.
--- /dev/null
+Kernel driver adm9240
+=====================
+
+Supported chips:
+ * Analog Devices ADM9240
+ Prefix: 'adm9240'
+ Addresses scanned: I2C 0x2c - 0x2f
+ Datasheet: Publicly available at the Analog Devices website
+ http://www.analog.com/UploadedFiles/Data_Sheets/79857778ADM9240_0.pdf
+
+ * Dallas Semiconductor DS1780
+ Prefix: 'ds1780'
+ Addresses scanned: I2C 0x2c - 0x2f
+ Datasheet: Publicly available at the Dallas Semiconductor (Maxim) website
+ http://pdfserv.maxim-ic.com/en/ds/DS1780.pdf
+
+ * National Semiconductor LM81
+ Prefix: 'lm81'
+ Addresses scanned: I2C 0x2c - 0x2f
+ Datasheet: Publicly available at the National Semiconductor website
+ http://www.national.com/ds.cgi/LM/LM81.pdf
+
+Authors:
+ Frodo Looijaard <frodol@dds.nl>,
+ Philip Edelbrock <phil@netroedge.com>,
+ Michiel Rook <michiel@grendelproject.nl>,
+ Grant Coady <gcoady@gmail.com> with guidance
+ from Jean Delvare <khali@linux-fr.org>
+
+Interface
+---------
+The I2C addresses listed above assume BIOS has not changed the
+chip MSB 5-bit address. Each chip reports a unique manufacturer
+identification code as well as the chip revision/stepping level.
+
+Description
+-----------
+[From ADM9240] The ADM9240 is a complete system hardware monitor for
+microprocessor-based systems, providing measurement and limit comparison
+of up to four power supplies and two processor core voltages, plus
+temperature, two fan speeds and chassis intrusion. Measured values can
+be read out via an I2C-compatible serial System Management Bus, and values
+for limit comparisons can be programmed in over the same serial bus. The
+high speed successive approximation ADC allows frequent sampling of all
+analog channels to ensure a fast interrupt response to any out-of-limit
+measurement.
+
+The ADM9240, DS1780 and LM81 are register compatible, the following
+details are common to the three chips. Chip differences are described
+after this section.
+
+
+Measurements
+------------
+The measurement cycle
+
+The adm9240 driver will take a measurement reading no faster than once
+each two seconds. User-space may read sysfs interface faster than the
+measurement update rate and will receive cached data from the most
+recent measurement.
+
+ADM9240 has a very fast 320us temperature and voltage measurement cycle
+with independent fan speed measurement cycles counting alternating rising
+edges of the fan tacho inputs.
+
+DS1780 measurement cycle is about once per second including fan speed.
+
+LM81 measurement cycle is about once per 400ms including fan speed.
+The LM81 12-bit extended temperature measurement mode is not supported.
+
+Temperature
+-----------
+On chip temperature is reported as degrees Celsius as 9-bit signed data
+with resolution of 0.5 degrees Celsius. High and low temperature limits
+are 8-bit signed data with resolution of one degree Celsius.
+
+Temperature alarm is asserted once the temperature exceeds the high limit,
+and is cleared when the temperature falls below the temp1_max_hyst value.
+
+Fan Speed
+---------
+Two fan tacho inputs are provided, the ADM9240 gates an internal 22.5kHz
+clock via a divider to an 8-bit counter. Fan speed (rpm) is calculated by:
+
+rpm = (22500 * 60) / (count * divider)
+
+Automatic fan clock divider
+
+ * User sets 0 to fan_min limit
+ - low speed alarm is disabled
+ - fan clock divider not changed
+ - auto fan clock adjuster enabled for valid fan speed reading
+
+ * User sets fan_min limit too low
+ - low speed alarm is enabled
+ - fan clock divider set to max
+ - fan_min set to register value 254 which corresponds
+ to 664 rpm on adm9240
+ - low speed alarm will be asserted if fan speed is
+ less than minimum measurable speed
+ - auto fan clock adjuster disabled
+
+ * User sets reasonable fan speed
+ - low speed alarm is enabled
+ - fan clock divider set to suit fan_min
+ - auto fan clock adjuster enabled: adjusts fan_min
+
+ * User sets unreasonably high low fan speed limit
+ - resolution of the low speed limit may be reduced
+ - alarm will be asserted
+ - auto fan clock adjuster enabled: adjusts fan_min
+
+ * fan speed may be displayed as zero until the auto fan clock divider
+ adjuster brings fan speed clock divider back into chip measurement
+ range, this will occur within a few measurement cycles.
+
+Analog Output
+-------------
+An analog output provides a 0 to 1.25 volt signal intended for an external
+fan speed amplifier circuit. The analog output is set to maximum value on
+power up or reset. This doesn't do much on the test Intel SE440BX-2.
+
+Voltage Monitor
+
+Voltage (IN) measurement is internally scaled:
+
+ nr label nominal maximum resolution
+ mV mV mV
+ 0 +2.5V 2500 3320 13.0
+ 1 Vccp1 2700 3600 14.1
+ 2 +3.3V 3300 4380 17.2
+ 3 +5V 5000 6640 26.0
+ 4 +12V 12000 15940 62.5
+ 5 Vccp2 2700 3600 14.1
+
+The reading is an unsigned 8-bit value, nominal voltage measurement is
+represented by a reading of 192, being 3/4 of the measurement range.
+
+An alarm is asserted for any voltage going below or above the set limits.
+
+The driver reports and accepts voltage limits scaled to the above table.
+
+VID Monitor
+-----------
+The chip has five inputs to read the 5-bit VID and reports the mV value
+based on detected CPU type.
+
+Chassis Intrusion
+-----------------
+An alarm is asserted when the CI pin goes active high. The ADM9240
+Datasheet has an example of an external temperature sensor driving
+this pin. On an Intel SE440BX-2 the Chassis Intrusion header is
+connected to a normally open switch.
+
+The ADM9240 provides an internal open drain on this line, and may output
+a 20 ms active low pulse to reset an external Chassis Intrusion latch.
+
+Clear the CI latch by writing value 1 to the sysfs chassis_clear file.
+
+Alarm flags reported as 16-bit word
+
+ bit label comment
+ --- ------------- --------------------------
+ 0 +2.5 V_Error high or low limit exceeded
+ 1 VCCP_Error high or low limit exceeded
+ 2 +3.3 V_Error high or low limit exceeded
+ 3 +5 V_Error high or low limit exceeded
+ 4 Temp_Error temperature error
+ 6 FAN1_Error fan low limit exceeded
+ 7 FAN2_Error fan low limit exceeded
+ 8 +12 V_Error high or low limit exceeded
+ 9 VCCP2_Error high or low limit exceeded
+ 12 Chassis_Error CI pin went high
+
+Remaining bits are reserved and thus undefined. It is important to note
+that alarm bits may be cleared on read, user-space may latch alarms and
+provide the end-user with a method to clear alarm memory.
--- /dev/null
+Kernel driver asb100
+====================
+
+Supported Chips:
+ * Asus ASB100 and ASB100-A "Bach"
+ Prefix: 'asb100'
+ Addresses scanned: I2C 0x2d
+ Datasheet: none released
+
+Author: Mark M. Hoffman <mhoffman@lightlink.com>
+
+Description
+-----------
+
+This driver implements support for the Asus ASB100 and ASB100-A "Bach".
+These are custom ASICs available only on Asus mainboards. Asus refuses to
+supply a datasheet for these chips. Thanks go to many people who helped
+investigate their hardware, including:
+
+Vitaly V. Bursov
+Alexander van Kaam (author of MBM for Windows)
+Bertrik Sikken
+
+The ASB100 implements seven voltage sensors, three fan rotation speed
+sensors, four temperature sensors, VID lines and alarms. In addition to
+these, the ASB100-A also implements a single PWM controller for fans 2 and
+3 (i.e. one setting controls both.) If you have a plain ASB100, the PWM
+controller will simply not work (or maybe it will for you... it doesn't for
+me).
+
+Temperatures are measured and reported in degrees Celsius.
+
+Fan speeds are reported in RPM (rotations per minute). An alarm is
+triggered if the rotation speed has dropped below a programmable limit.
+
+Voltage sensors (also known as IN sensors) report values in volts.
+
+The VID lines encode the core voltage value: the voltage level your
+processor should work with. This is hardcoded by the mainboard and/or
+processor itself. It is a value in volts.
+
+Alarms: (TODO question marks indicate may or may not work)
+
+0x0001 => in0 (?)
+0x0002 => in1 (?)
+0x0004 => in2
+0x0008 => in3
+0x0010 => temp1 (1)
+0x0020 => temp2
+0x0040 => fan1
+0x0080 => fan2
+0x0100 => in4
+0x0200 => in5 (?) (2)
+0x0400 => in6 (?) (2)
+0x0800 => fan3
+0x1000 => chassis switch
+0x2000 => temp3
+
+Alarm Notes:
+
+(1) This alarm will only trigger if the hysteresis value is 127C.
+I.e. it behaves the same as w83781d.
+
+(2) The min and max registers for these values appear to
+be read-only or otherwise stuck at 0x00.
+
+TODO:
+* Experiment with fan divisors > 8.
+* Experiment with temp. sensor types.
+* Are there really 13 voltage inputs? Probably not...
+* Cleanups, no doubt...
+
--- /dev/null
+Kernel driver ds1621
+====================
+
+Supported chips:
+ * Dallas Semiconductor DS1621
+ Prefix: 'ds1621'
+ Addresses scanned: I2C 0x48 - 0x4f
+ Datasheet: Publicly available at the Dallas Semiconductor website
+ http://www.dalsemi.com/
+ * Dallas Semiconductor DS1625
+ Prefix: 'ds1621'
+ Addresses scanned: I2C 0x48 - 0x4f
+ Datasheet: Publicly available at the Dallas Semiconductor website
+ http://www.dalsemi.com/
+
+Authors:
+ Christian W. Zuckschwerdt <zany@triq.net>
+ valuable contributions by Jan M. Sendler <sendler@sendler.de>
+ ported to 2.6 by Aurelien Jarno <aurelien@aurel32.net>
+ with the help of Jean Delvare <khali@linux-fr.org>
+
+Module Parameters
+------------------
+
+* polarity int
+ Output's polarity: 0 = active high, 1 = active low
+
+Description
+-----------
+
+The DS1621 is a (one instance) digital thermometer and thermostat. It has
+both high and low temperature limits which can be user defined (i.e.
+programmed into non-volatile on-chip registers). Temperature range is -55
+degree Celsius to +125 in 0.5 increments. You may convert this into a
+Fahrenheit range of -67 to +257 degrees with 0.9 steps. If polarity
+parameter is not provided, original value is used.
+
+As for the thermostat, behavior can also be programmed using the polarity
+toggle. On the one hand ("heater"), the thermostat output of the chip,
+Tout, will trigger when the low limit temperature is met or underrun and
+stays high until the high limit is met or exceeded. On the other hand
+("cooler"), vice versa. That way "heater" equals "active low", whereas
+"conditioner" equals "active high". Please note that the DS1621 data sheet
+is somewhat misleading in this point since setting the polarity bit does
+not simply invert Tout.
+
+A second thing is that, during extensive testing, Tout showed a tolerance
+of up to +/- 0.5 degrees even when compared against precise temperature
+readings. Be sure to have a high vs. low temperature limit gap of al least
+1.0 degree Celsius to avoid Tout "bouncing", though!
+
+As for alarms, you can read the alarm status of the DS1621 via the 'alarms'
+/sys file interface. The result consists mainly of bit 6 and 5 of the
+configuration register of the chip; bit 6 (0x40 or 64) is the high alarm
+bit and bit 5 (0x20 or 32) the low one. These bits are set when the high or
+low limits are met or exceeded and are reset by the module as soon as the
+respective temperature ranges are left.
+
+The alarm registers are in no way suitable to find out about the actual
+status of Tout. They will only tell you about its history, whether or not
+any of the limits have ever been met or exceeded since last power-up or
+reset. Be aware: When testing, it showed that the status of Tout can change
+with neither of the alarms set.
+
+Temperature conversion of the DS1621 takes up to 1000ms; internal access to
+non-volatile registers may last for 10ms or below.
+
+High Accuracy Temperature Reading
+---------------------------------
+
+As said before, the temperature issued via the 9-bit i2c-bus data is
+somewhat arbitrary. Internally, the temperature conversion is of a
+different kind that is explained (not so...) well in the DS1621 data sheet.
+To cut the long story short: Inside the DS1621 there are two oscillators,
+both of them biassed by a temperature coefficient.
+
+Higher resolution of the temperature reading can be achieved using the
+internal projection, which means taking account of REG_COUNT and REG_SLOPE
+(the driver manages them):
+
+Taken from Dallas Semiconductors App Note 068: 'Increasing Temperature
+Resolution on the DS1620' and App Note 105: 'High Resolution Temperature
+Measurement with Dallas Direct-to-Digital Temperature Sensors'
+
+- Read the 9-bit temperature and strip the LSB (Truncate the .5 degs)
+- The resulting value is TEMP_READ.
+- Then, read REG_COUNT.
+- And then, REG_SLOPE.
+
+ TEMP = TEMP_READ - 0.25 + ((REG_SLOPE - REG_COUNT) / REG_SLOPE)
+
+Note that this is what the DONE bit in the DS1621 configuration register is
+good for: Internally, one temperature conversion takes up to 1000ms. Before
+that conversion is complete you will not be able to read valid things out
+of REG_COUNT and REG_SLOPE. The DONE bit, as you may have guessed by now,
+tells you whether the conversion is complete ("done", in plain English) and
+thus, whether the values you read are good or not.
+
+The DS1621 has two modes of operation: "Continuous" conversion, which can
+be understood as the default stand-alone mode where the chip gets the
+temperature and controls external devices via its Tout pin or tells other
+i2c's about it if they care. The other mode is called "1SHOT", that means
+that it only figures out about the temperature when it is explicitly told
+to do so; this can be seen as power saving mode.
+
+Now if you want to read REG_COUNT and REG_SLOPE, you have to either stop
+the continuous conversions until the contents of these registers are valid,
+or, in 1SHOT mode, you have to have one conversion made.
--- /dev/null
+Kernel driver eeprom
+====================
+
+Supported chips:
+ * Any EEPROM chip in the designated address range
+ Prefix: 'eeprom'
+ Addresses scanned: I2C 0x50 - 0x57
+ Datasheets: Publicly available from:
+ Atmel (www.atmel.com),
+ Catalyst (www.catsemi.com),
+ Fairchild (www.fairchildsemi.com),
+ Microchip (www.microchip.com),
+ Philips (www.semiconductor.philips.com),
+ Rohm (www.rohm.com),
+ ST (www.st.com),
+ Xicor (www.xicor.com),
+ and others.
+
+ Chip Size (bits) Address
+ 24C01 1K 0x50 (shadows at 0x51 - 0x57)
+ 24C01A 1K 0x50 - 0x57 (Typical device on DIMMs)
+ 24C02 2K 0x50 - 0x57
+ 24C04 4K 0x50, 0x52, 0x54, 0x56
+ (additional data at 0x51, 0x53, 0x55, 0x57)
+ 24C08 8K 0x50, 0x54 (additional data at 0x51, 0x52,
+ 0x53, 0x55, 0x56, 0x57)
+ 24C16 16K 0x50 (additional data at 0x51 - 0x57)
+ Sony 2K 0x57
+
+ Atmel 34C02B 2K 0x50 - 0x57, SW write protect at 0x30-37
+ Catalyst 34FC02 2K 0x50 - 0x57, SW write protect at 0x30-37
+ Catalyst 34RC02 2K 0x50 - 0x57, SW write protect at 0x30-37
+ Fairchild 34W02 2K 0x50 - 0x57, SW write protect at 0x30-37
+ Microchip 24AA52 2K 0x50 - 0x57, SW write protect at 0x30-37
+ ST M34C02 2K 0x50 - 0x57, SW write protect at 0x30-37
+
+
+Authors:
+ Frodo Looijaard <frodol@dds.nl>,
+ Philip Edelbrock <phil@netroedge.com>,
+ Jean Delvare <khali@linux-fr.org>,
+ Greg Kroah-Hartman <greg@kroah.com>,
+ IBM Corp.
+
+Description
+-----------
+
+This is a simple EEPROM module meant to enable reading the first 256 bytes
+of an EEPROM (on a SDRAM DIMM for example). However, it will access serial
+EEPROMs on any I2C adapter. The supported devices are generically called
+24Cxx, and are listed above; however the numbering for these
+industry-standard devices may vary by manufacturer.
+
+This module was a programming exercise to get used to the new project
+organization laid out by Frodo, but it should be at least completely
+effective for decoding the contents of EEPROMs on DIMMs.
+
+DIMMS will typically contain a 24C01A or 24C02, or the 34C02 variants.
+The other devices will not be found on a DIMM because they respond to more
+than one address.
+
+DDC Monitors may contain any device. Often a 24C01, which responds to all 8
+addresses, is found.
+
+Recent Sony Vaio laptops have an EEPROM at 0x57. We couldn't get the
+specification, so it is guess work and far from being complete.
+
+The Microchip 24AA52/24LCS52, ST M34C02, and others support an additional
+software write protect register at 0x30 - 0x37 (0x20 less than the memory
+location). The chip responds to "write quick" detection at this address but
+does not respond to byte reads. If this register is present, the lower 128
+bytes of the memory array are not write protected. Any byte data write to
+this address will write protect the memory array permanently, and the
+device will no longer respond at the 0x30-37 address. The eeprom driver
+does not support this register.
+
+Lacking functionality:
+
+* Full support for larger devices (24C04, 24C08, 24C16). These are not
+typically found on a PC. These devices will appear as separate devices at
+multiple addresses.
+
+* Support for really large devices (24C32, 24C64, 24C128, 24C256, 24C512).
+These devices require two-byte address fields and are not supported.
+
+* Enable Writing. Again, no technical reason why not, but making it easy
+to change the contents of the EEPROMs (on DIMMs anyway) also makes it easy
+to disable the DIMMs (potentially preventing the computer from booting)
+until the values are restored somehow.
+
+Use:
+
+After inserting the module (and any other required SMBus/i2c modules), you
+should have some EEPROM directories in /sys/bus/i2c/devices/* of names such
+as "0-0050". Inside each of these is a series of files, the eeprom file
+contains the binary data from EEPROM.
--- /dev/null
+Kernel driver fscher
+====================
+
+Supported chips:
+ * Fujitsu-Siemens Hermes chip
+ Prefix: 'fscher'
+ Addresses scanned: I2C 0x73
+
+Authors:
+ Reinhard Nissl <rnissl@gmx.de> based on work
+ from Hermann Jung <hej@odn.de>,
+ Frodo Looijaard <frodol@dds.nl>,
+ Philip Edelbrock <phil@netroedge.com>
+
+Description
+-----------
+
+This driver implements support for the Fujitsu-Siemens Hermes chip. It is
+described in the 'Register Set Specification BMC Hermes based Systemboard'
+from Fujitsu-Siemens.
+
+The Hermes chip implements a hardware-based system management, e.g. for
+controlling fan speed and core voltage. There is also a watchdog counter on
+the chip which can trigger an alarm and even shut the system down.
+
+The chip provides three temperature values (CPU, motherboard and
+auxiliary), three voltage values (+12V, +5V and battery) and three fans
+(power supply, CPU and auxiliary).
+
+Temperatures are measured in degrees Celsius. The resolution is 1 degree.
+
+Fan rotation speeds are reported in RPM (rotations per minute). The value
+can be divided by a programmable divider (1, 2 or 4) which is stored on
+the chip.
+
+Voltage sensors (also known as "in" sensors) report their values in volts.
+
+All values are reported as final values from the driver. There is no need
+for further calculations.
+
+
+Detailed description
+--------------------
+
+Below you'll find a single line description of all the bit values. With
+this information, you're able to decode e. g. alarms, wdog, etc. To make
+use of the watchdog, you'll need to set the watchdog time and enable the
+watchdog. After that it is necessary to restart the watchdog time within
+the specified period of time, or a system reset will occur.
+
+* revision
+ READING & 0xff = 0x??: HERMES revision identification
+
+* alarms
+ READING & 0x80 = 0x80: CPU throttling active
+ READING & 0x80 = 0x00: CPU running at full speed
+
+ READING & 0x10 = 0x10: software event (see control:1)
+ READING & 0x10 = 0x00: no software event
+
+ READING & 0x08 = 0x08: watchdog event (see wdog:2)
+ READING & 0x08 = 0x00: no watchdog event
+
+ READING & 0x02 = 0x02: thermal event (see temp*:1)
+ READING & 0x02 = 0x00: no thermal event
+
+ READING & 0x01 = 0x01: fan event (see fan*:1)
+ READING & 0x01 = 0x00: no fan event
+
+ READING & 0x13 ! 0x00: ALERT LED is flashing
+
+* control
+ READING & 0x01 = 0x01: software event
+ READING & 0x01 = 0x00: no software event
+
+ WRITING & 0x01 = 0x01: set software event
+ WRITING & 0x01 = 0x00: clear software event
+
+* watchdog_control
+ READING & 0x80 = 0x80: power off on watchdog event while thermal event
+ READING & 0x80 = 0x00: watchdog power off disabled (just system reset enabled)
+
+ READING & 0x40 = 0x40: watchdog timebase 60 seconds (see also wdog:1)
+ READING & 0x40 = 0x00: watchdog timebase 2 seconds
+
+ READING & 0x10 = 0x10: watchdog enabled
+ READING & 0x10 = 0x00: watchdog disabled
+
+ WRITING & 0x80 = 0x80: enable "power off on watchdog event while thermal event"
+ WRITING & 0x80 = 0x00: disable "power off on watchdog event while thermal event"
+
+ WRITING & 0x40 = 0x40: set watchdog timebase to 60 seconds
+ WRITING & 0x40 = 0x00: set watchdog timebase to 2 seconds
+
+ WRITING & 0x20 = 0x20: disable watchdog
+
+ WRITING & 0x10 = 0x10: enable watchdog / restart watchdog time
+
+* watchdog_state
+ READING & 0x02 = 0x02: watchdog system reset occurred
+ READING & 0x02 = 0x00: no watchdog system reset occurred
+
+ WRITING & 0x02 = 0x02: clear watchdog event
+
+* watchdog_preset
+ READING & 0xff = 0x??: configured watch dog time in units (see wdog:3 0x40)
+
+ WRITING & 0xff = 0x??: configure watch dog time in units
+
+* in* (0: +5V, 1: +12V, 2: onboard 3V battery)
+ READING: actual voltage value
+
+* temp*_status (1: CPU sensor, 2: onboard sensor, 3: auxiliary sensor)
+ READING & 0x02 = 0x02: thermal event (overtemperature)
+ READING & 0x02 = 0x00: no thermal event
+
+ READING & 0x01 = 0x01: sensor is working
+ READING & 0x01 = 0x00: sensor is faulty
+
+ WRITING & 0x02 = 0x02: clear thermal event
+
+* temp*_input (1: CPU sensor, 2: onboard sensor, 3: auxiliary sensor)
+ READING: actual temperature value
+
+* fan*_status (1: power supply fan, 2: CPU fan, 3: auxiliary fan)
+ READING & 0x04 = 0x04: fan event (fan fault)
+ READING & 0x04 = 0x00: no fan event
+
+ WRITING & 0x04 = 0x04: clear fan event
+
+* fan*_div (1: power supply fan, 2: CPU fan, 3: auxiliary fan)
+ Divisors 2,4 and 8 are supported, both for reading and writing
+
+* fan*_pwm (1: power supply fan, 2: CPU fan, 3: auxiliary fan)
+ READING & 0xff = 0x00: fan may be switched off
+ READING & 0xff = 0x01: fan must run at least at minimum speed (supply: 6V)
+ READING & 0xff = 0xff: fan must run at maximum speed (supply: 12V)
+ READING & 0xff = 0x??: fan must run at least at given speed (supply: 6V..12V)
+
+ WRITING & 0xff = 0x00: fan may be switched off
+ WRITING & 0xff = 0x01: fan must run at least at minimum speed (supply: 6V)
+ WRITING & 0xff = 0xff: fan must run at maximum speed (supply: 12V)
+ WRITING & 0xff = 0x??: fan must run at least at given speed (supply: 6V..12V)
+
+* fan*_input (1: power supply fan, 2: CPU fan, 3: auxiliary fan)
+ READING: actual RPM value
+
+
+Limitations
+-----------
+
+* Measuring fan speed
+It seems that the chip counts "ripples" (typical fans produce 2 ripples per
+rotation while VERAX fans produce 18) in a 9-bit register. This register is
+read out every second, then the ripple prescaler (2, 4 or 8) is applied and
+the result is stored in the 8 bit output register. Due to the limitation of
+the counting register to 9 bits, it is impossible to measure a VERAX fan
+properly (even with a prescaler of 8). At its maximum speed of 3500 RPM the
+fan produces 1080 ripples per second which causes the counting register to
+overflow twice, leading to only 186 RPM.
+
+* Measuring input voltages
+in2 ("battery") reports the voltage of the onboard lithium battery and not
++3.3V from the power supply.
+
+* Undocumented features
+Fujitsu-Siemens Computers has not documented all features of the chip so
+far. Their software, System Guard, shows that there are a still some
+features which cannot be controlled by this implementation.
--- /dev/null
+Kernel driver gl518sm
+=====================
+
+Supported chips:
+ * Genesys Logic GL518SM release 0x00
+ Prefix: 'gl518sm'
+ Addresses scanned: I2C 0x2c and 0x2d
+ Datasheet: http://www.genesyslogic.com/pdf
+ * Genesys Logic GL518SM release 0x80
+ Prefix: 'gl518sm'
+ Addresses scanned: I2C 0x2c and 0x2d
+ Datasheet: http://www.genesyslogic.com/pdf
+
+Authors:
+ Frodo Looijaard <frodol@dds.nl>,
+ Kyösti Mälkki <kmalkki@cc.hut.fi>
+ Hong-Gunn Chew <hglinux@gunnet.org>
+ Jean Delvare <khali@linux-fr.org>
+
+Description
+-----------
+
+IMPORTANT:
+
+For the revision 0x00 chip, the in0, in1, and in2 values (+5V, +3V,
+and +12V) CANNOT be read. This is a limitation of the chip, not the driver.
+
+This driver supports the Genesys Logic GL518SM chip. There are at least
+two revision of this chip, which we call revision 0x00 and 0x80. Revision
+0x80 chips support the reading of all voltages and revision 0x00 only
+for VIN3.
+
+The GL518SM implements one temperature sensor, two fan rotation speed
+sensors, and four voltage sensors. It can report alarms through the
+computer speakers.
+
+Temperatures are measured in degrees Celsius. An alarm goes off while the
+temperature is above the over temperature limit, and has not yet dropped
+below the hysteresis limit. The alarm always reflects the current
+situation. Measurements are guaranteed between -10 degrees and +110
+degrees, with a accuracy of +/-3 degrees.
+
+Rotation speeds are reported in RPM (rotations per minute). An alarm is
+triggered if the rotation speed has dropped below a programmable limit. In
+case when you have selected to turn fan1 off, no fan1 alarm is triggered.
+
+Fan readings can be divided by a programmable divider (1, 2, 4 or 8) to
+give the readings more range or accuracy. Not all RPM values can
+accurately be represented, so some rounding is done. With a divider
+of 2, the lowest representable value is around 1900 RPM.
+
+Voltage sensors (also known as VIN sensors) report their values in volts.
+An alarm is triggered if the voltage has crossed a programmable minimum or
+maximum limit. Note that minimum in this case always means 'closest to
+zero'; this is important for negative voltage measurements. The VDD input
+measures voltages between 0.000 and 5.865 volt, with a resolution of 0.023
+volt. The other inputs measure voltages between 0.000 and 4.845 volt, with
+a resolution of 0.019 volt. Note that revision 0x00 chips do not support
+reading the current voltage of any input except for VIN3; limit setting and
+alarms work fine, though.
+
+When an alarm is triggered, you can be warned by a beeping signal through your
+computer speaker. It is possible to enable all beeping globally, or only the
+beeping for some alarms.
+
+If an alarm triggers, it will remain triggered until the hardware register
+is read at least once (except for temperature alarms). This means that the
+cause for the alarm may already have disappeared! Note that in the current
+implementation, all hardware registers are read whenever any data is read
+(unless it is less than 1.5 seconds since the last update). This means that
+you can easily miss once-only alarms.
+
+The GL518SM only updates its values each 1.5 seconds; reading it more often
+will do no harm, but will return 'old' values.
--- /dev/null
+Kernel driver it87
+==================
+
+Supported chips:
+ * IT8705F
+ Prefix: 'it87'
+ Addresses scanned: from Super I/O config space, or default ISA 0x290 (8 I/O ports)
+ Datasheet: Publicly available at the ITE website
+ http://www.ite.com.tw/
+ * IT8712F
+ Prefix: 'it8712'
+ Addresses scanned: I2C 0x28 - 0x2f
+ from Super I/O config space, or default ISA 0x290 (8 I/O ports)
+ Datasheet: Publicly available at the ITE website
+ http://www.ite.com.tw/
+ * SiS950 [clone of IT8705F]
+ Prefix: 'sis950'
+ Addresses scanned: from Super I/O config space, or default ISA 0x290 (8 I/O ports)
+ Datasheet: No longer be available
+
+Author: Christophe Gauthron <chrisg@0-in.com>
+
+
+Module Parameters
+-----------------
+
+* update_vbat: int
+
+ 0 if vbat should report power on value, 1 if vbat should be updated after
+ each read. Default is 0. On some boards the battery voltage is provided
+ by either the battery or the onboard power supply. Only the first reading
+ at power on will be the actual battery voltage (which the chip does
+ automatically). On other boards the battery voltage is always fed to
+ the chip so can be read at any time. Excessive reading may decrease
+ battery life but no information is given in the datasheet.
+
+* fix_pwm_polarity int
+
+ Force PWM polarity to active high (DANGEROUS). Some chips are
+ misconfigured by BIOS - PWM values would be inverted. This option tries
+ to fix this. Please contact your BIOS manufacturer and ask him for fix.
+
+Description
+-----------
+
+This driver implements support for the IT8705F, IT8712F and SiS950 chips.
+
+This driver also supports IT8712F, which adds SMBus access, and a VID
+input, used to report the Vcore voltage of the Pentium processor.
+The IT8712F additionally features VID inputs.
+
+These chips are 'Super I/O chips', supporting floppy disks, infrared ports,
+joysticks and other miscellaneous stuff. For hardware monitoring, they
+include an 'environment controller' with 3 temperature sensors, 3 fan
+rotation speed sensors, 8 voltage sensors, and associated alarms.
+
+Temperatures are measured in degrees Celsius. An alarm is triggered once
+when the Overtemperature Shutdown limit is crossed.
+
+Fan rotation speeds are reported in RPM (rotations per minute). An alarm is
+triggered if the rotation speed has dropped below a programmable limit. Fan
+readings can be divided by a programmable divider (1, 2, 4 or 8) to give the
+readings more range or accuracy. Not all RPM values can accurately be
+represented, so some rounding is done. With a divider of 2, the lowest
+representable value is around 2600 RPM.
+
+Voltage sensors (also known as IN sensors) report their values in volts. An
+alarm is triggered if the voltage has crossed a programmable minimum or
+maximum limit. Note that minimum in this case always means 'closest to
+zero'; this is important for negative voltage measurements. All voltage
+inputs can measure voltages between 0 and 4.08 volts, with a resolution of
+0.016 volt. The battery voltage in8 does not have limit registers.
+
+The VID lines (IT8712F only) encode the core voltage value: the voltage
+level your processor should work with. This is hardcoded by the mainboard
+and/or processor itself. It is a value in volts.
+
+If an alarm triggers, it will remain triggered until the hardware register
+is read at least once. This means that the cause for the alarm may already
+have disappeared! Note that in the current implementation, all hardware
+registers are read whenever any data is read (unless it is less than 1.5
+seconds since the last update). This means that you can easily miss
+once-only alarms.
+
+The IT87xx only updates its values each 1.5 seconds; reading it more often
+will do no harm, but will return 'old' values.
+
+To change sensor N to a thermistor, 'echo 2 > tempN_type' where N is 1, 2,
+or 3. To change sensor N to a thermal diode, 'echo 3 > tempN_type'.
+Give 0 for unused sensor. Any other value is invalid. To configure this at
+startup, consult lm_sensors's /etc/sensors.conf. (2 = thermistor;
+3 = thermal diode)
+
+The fan speed control features are limited to manual PWM mode. Automatic
+"Smart Guardian" mode control handling is not implemented. However
+if you want to go for "manual mode" just write 1 to pwmN_enable.
--- /dev/null
+Kernel driver lm63
+==================
+
+Supported chips:
+ * National Semiconductor LM63
+ Prefix: 'lm63'
+ Addresses scanned: I2C 0x4c
+ Datasheet: Publicly available at the National Semiconductor website
+ http://www.national.com/pf/LM/LM63.html
+
+Author: Jean Delvare <khali@linux-fr.org>
+
+Thanks go to Tyan and especially Alex Buckingham for setting up a remote
+access to their S4882 test platform for this driver.
+ http://www.tyan.com/
+
+Description
+-----------
+
+The LM63 is a digital temperature sensor with integrated fan monitoring
+and control.
+
+The LM63 is basically an LM86 with fan speed monitoring and control
+capabilities added. It misses some of the LM86 features though:
+ - No low limit for local temperature.
+ - No critical limit for local temperature.
+ - Critical limit for remote temperature can be changed only once. We
+ will consider that the critical limit is read-only.
+
+The datasheet isn't very clear about what the tachometer reading is.
+
+An explanation from National Semiconductor: The two lower bits of the read
+value have to be masked out. The value is still 16 bit in width.
+
+All temperature values are given in degrees Celsius. Resolution is 1.0
+degree for the local temperature, 0.125 degree for the remote temperature.
+
+The fan speed is measured using a tachometer. Contrary to most chips which
+store the value in an 8-bit register and have a selectable clock divider
+to make sure that the result will fit in the register, the LM63 uses 16-bit
+value for measuring the speed of the fan. It can measure fan speeds down to
+83 RPM, at least in theory.
+
+Note that the pin used for fan monitoring is shared with an alert out
+function. Depending on how the board designer wanted to use the chip, fan
+speed monitoring will or will not be possible. The proper chip configuration
+is left to the BIOS, and the driver will blindly trust it.
+
+A PWM output can be used to control the speed of the fan. The LM63 has two
+PWM modes: manual and automatic. Automatic mode is not fully implemented yet
+(you cannot define your custom PWM/temperature curve), and mode change isn't
+supported either.
+
+The lm63 driver will not update its values more frequently than every
+second; reading them more often will do no harm, but will return 'old'
+values.
+
--- /dev/null
+Kernel driver lm75
+==================
+
+Supported chips:
+ * National Semiconductor LM75
+ Prefix: 'lm75'
+ Addresses scanned: I2C 0x48 - 0x4f
+ Datasheet: Publicly available at the National Semiconductor website
+ http://www.national.com/
+ * Dallas Semiconductor DS75
+ Prefix: 'lm75'
+ Addresses scanned: I2C 0x48 - 0x4f
+ Datasheet: Publicly available at the Dallas Semiconductor website
+ http://www.maxim-ic.com/
+ * Dallas Semiconductor DS1775
+ Prefix: 'lm75'
+ Addresses scanned: I2C 0x48 - 0x4f
+ Datasheet: Publicly available at the Dallas Semiconductor website
+ http://www.maxim-ic.com/
+ * Maxim MAX6625, MAX6626
+ Prefix: 'lm75'
+ Addresses scanned: I2C 0x48 - 0x4b
+ Datasheet: Publicly available at the Maxim website
+ http://www.maxim-ic.com/
+ * Microchip (TelCom) TCN75
+ Prefix: 'lm75'
+ Addresses scanned: I2C 0x48 - 0x4f
+ Datasheet: Publicly available at the Microchip website
+ http://www.microchip.com/
+
+Author: Frodo Looijaard <frodol@dds.nl>
+
+Description
+-----------
+
+The LM75 implements one temperature sensor. Limits can be set through the
+Overtemperature Shutdown register and Hysteresis register. Each value can be
+set and read to half-degree accuracy.
+An alarm is issued (usually to a connected LM78) when the temperature
+gets higher then the Overtemperature Shutdown value; it stays on until
+the temperature falls below the Hysteresis value.
+All temperatures are in degrees Celsius, and are guaranteed within a
+range of -55 to +125 degrees.
+
+The LM75 only updates its values each 1.5 seconds; reading it more often
+will do no harm, but will return 'old' values.
+
+The LM75 is usually used in combination with LM78-like chips, to measure
+the temperature of the processor(s).
+
+The DS75, DS1775, MAX6625, and MAX6626 are supported as well.
+They are not distinguished from an LM75. While most of these chips
+have three additional bits of accuracy (12 vs. 9 for the LM75),
+the additional bits are not supported. Not only that, but these chips will
+not be detected if not in 9-bit precision mode (use the force parameter if
+needed).
+
+The TCN75 is supported as well, and is not distinguished from an LM75.
+
+The LM75 is essentially an industry standard; there may be other
+LM75 clones not listed here, with or without various enhancements,
+that are supported.
+
+The LM77 is not supported, contrary to what we pretended for a long time.
+Both chips are simply not compatible, value encoding differs.
--- /dev/null
+Kernel driver lm77
+==================
+
+Supported chips:
+ * National Semiconductor LM77
+ Prefix: 'lm77'
+ Addresses scanned: I2C 0x48 - 0x4b
+ Datasheet: Publicly available at the National Semiconductor website
+ http://www.national.com/
+
+Author: Andras BALI <drewie@freemail.hu>
+
+Description
+-----------
+
+The LM77 implements one temperature sensor. The temperature
+sensor incorporates a band-gap type temperature sensor,
+10-bit ADC, and a digital comparator with user-programmable upper
+and lower limit values.
+
+Limits can be set through the Overtemperature Shutdown register and
+Hysteresis register.
--- /dev/null
+Kernel driver lm78
+==================
+
+Supported chips:
+ * National Semiconductor LM78
+ Prefix: 'lm78'
+ Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports)
+ Datasheet: Publicly available at the National Semiconductor website
+ http://www.national.com/
+ * National Semiconductor LM78-J
+ Prefix: 'lm78-j'
+ Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports)
+ Datasheet: Publicly available at the National Semiconductor website
+ http://www.national.com/
+ * National Semiconductor LM79
+ Prefix: 'lm79'
+ Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports)
+ Datasheet: Publicly available at the National Semiconductor website
+ http://www.national.com/
+
+Author: Frodo Looijaard <frodol@dds.nl>
+
+Description
+-----------
+
+This driver implements support for the National Semiconductor LM78, LM78-J
+and LM79. They are described as 'Microprocessor System Hardware Monitors'.
+
+There is almost no difference between the three supported chips. Functionally,
+the LM78 and LM78-J are exactly identical. The LM79 has one more VID line,
+which is used to report the lower voltages newer Pentium processors use.
+From here on, LM7* means either of these three types.
+
+The LM7* implements one temperature sensor, three fan rotation speed sensors,
+seven voltage sensors, VID lines, alarms, and some miscellaneous stuff.
+
+Temperatures are measured in degrees Celsius. An alarm is triggered once
+when the Overtemperature Shutdown limit is crossed; it is triggered again
+as soon as it drops below the Hysteresis value. A more useful behavior
+can be found by setting the Hysteresis value to +127 degrees Celsius; in
+this case, alarms are issued during all the time when the actual temperature
+is above the Overtemperature Shutdown value. Measurements are guaranteed
+between -55 and +125 degrees, with a resolution of 1 degree.
+
+Fan rotation speeds are reported in RPM (rotations per minute). An alarm is
+triggered if the rotation speed has dropped below a programmable limit. Fan
+readings can be divided by a programmable divider (1, 2, 4 or 8) to give
+the readings more range or accuracy. Not all RPM values can accurately be
+represented, so some rounding is done. With a divider of 2, the lowest
+representable value is around 2600 RPM.
+
+Voltage sensors (also known as IN sensors) report their values in volts.
+An alarm is triggered if the voltage has crossed a programmable minimum
+or maximum limit. Note that minimum in this case always means 'closest to
+zero'; this is important for negative voltage measurements. All voltage
+inputs can measure voltages between 0 and 4.08 volts, with a resolution
+of 0.016 volt.
+
+The VID lines encode the core voltage value: the voltage level your processor
+should work with. This is hardcoded by the mainboard and/or processor itself.
+It is a value in volts. When it is unconnected, you will often find the
+value 3.50 V here.
+
+In addition to the alarms described above, there are a couple of additional
+ones. There is a BTI alarm, which gets triggered when an external chip has
+crossed its limits. Usually, this is connected to all LM75 chips; if at
+least one crosses its limits, this bit gets set. The CHAS alarm triggers
+if your computer case is open. The FIFO alarms should never trigger; it
+indicates an internal error. The SMI_IN alarm indicates some other chip
+has triggered an SMI interrupt. As we do not use SMI interrupts at all,
+this condition usually indicates there is a problem with some other
+device.
+
+If an alarm triggers, it will remain triggered until the hardware register
+is read at least once. This means that the cause for the alarm may
+already have disappeared! Note that in the current implementation, all
+hardware registers are read whenever any data is read (unless it is less
+than 1.5 seconds since the last update). This means that you can easily
+miss once-only alarms.
+
+The LM7* only updates its values each 1.5 seconds; reading it more often
+will do no harm, but will return 'old' values.
--- /dev/null
+Kernel driver lm80
+==================
+
+Supported chips:
+ * National Semiconductor LM80
+ Prefix: 'lm80'
+ Addresses scanned: I2C 0x28 - 0x2f
+ Datasheet: Publicly available at the National Semiconductor website
+ http://www.national.com/
+
+Authors:
+ Frodo Looijaard <frodol@dds.nl>,
+ Philip Edelbrock <phil@netroedge.com>
+
+Description
+-----------
+
+This driver implements support for the National Semiconductor LM80.
+It is described as a 'Serial Interface ACPI-Compatible Microprocessor
+System Hardware Monitor'.
+
+The LM80 implements one temperature sensor, two fan rotation speed sensors,
+seven voltage sensors, alarms, and some miscellaneous stuff.
+
+Temperatures are measured in degrees Celsius. There are two sets of limits
+which operate independently. When the HOT Temperature Limit is crossed,
+this will cause an alarm that will be reasserted until the temperature
+drops below the HOT Hysteresis. The Overtemperature Shutdown (OS) limits
+should work in the same way (but this must be checked; the datasheet
+is unclear about this). Measurements are guaranteed between -55 and
++125 degrees. The current temperature measurement has a resolution of
+0.0625 degrees; the limits have a resolution of 1 degree.
+
+Fan rotation speeds are reported in RPM (rotations per minute). An alarm is
+triggered if the rotation speed has dropped below a programmable limit. Fan
+readings can be divided by a programmable divider (1, 2, 4 or 8) to give
+the readings more range or accuracy. Not all RPM values can accurately be
+represented, so some rounding is done. With a divider of 2, the lowest
+representable value is around 2600 RPM.
+
+Voltage sensors (also known as IN sensors) report their values in volts.
+An alarm is triggered if the voltage has crossed a programmable minimum
+or maximum limit. Note that minimum in this case always means 'closest to
+zero'; this is important for negative voltage measurements. All voltage
+inputs can measure voltages between 0 and 2.55 volts, with a resolution
+of 0.01 volt.
+
+If an alarm triggers, it will remain triggered until the hardware register
+is read at least once. This means that the cause for the alarm may
+already have disappeared! Note that in the current implementation, all
+hardware registers are read whenever any data is read (unless it is less
+than 2.0 seconds since the last update). This means that you can easily
+miss once-only alarms.
+
+The LM80 only updates its values each 1.5 seconds; reading it more often
+will do no harm, but will return 'old' values.
--- /dev/null
+Kernel driver lm83
+==================
+
+Supported chips:
+ * National Semiconductor LM83
+ Prefix: 'lm83'
+ Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
+ Datasheet: Publicly available at the National Semiconductor website
+ http://www.national.com/pf/LM/LM83.html
+
+
+Author: Jean Delvare <khali@linux-fr.org>
+
+Description
+-----------
+
+The LM83 is a digital temperature sensor. It senses its own temperature as
+well as the temperature of up to three external diodes. It is compatible
+with many other devices such as the LM84 and all other ADM1021 clones.
+The main difference between the LM83 and the LM84 in that the later can
+only sense the temperature of one external diode.
+
+Using the adm1021 driver for a LM83 should work, but only two temperatures
+will be reported instead of four.
+
+The LM83 is only found on a handful of motherboards. Both a confirmed
+list and an unconfirmed list follow. If you can confirm or infirm the
+fact that any of these motherboards do actually have an LM83, please
+contact us. Note that the LM90 can easily be misdetected as a LM83.
+
+Confirmed motherboards:
+ SBS P014
+
+Unconfirmed motherboards:
+ Gigabyte GA-8IK1100
+ Iwill MPX2
+ Soltek SL-75DRV5
+
+The driver has been successfully tested by Magnus Forsström, who I'd
+like to thank here. More testers will be of course welcome.
+
+The fact that the LM83 is only scarcely used can be easily explained.
+Most motherboards come with more than just temperature sensors for
+health monitoring. They also have voltage and fan rotation speed
+sensors. This means that temperature-only chips are usually used as
+secondary chips coupled with another chip such as an IT8705F or similar
+chip, which provides more features. Since systems usually need three
+temperature sensors (motherboard, processor, power supply) and primary
+chips provide some temperature sensors, the secondary chip, if needed,
+won't have to handle more than two temperatures. Thus, ADM1021 clones
+are sufficient, and there is no need for a four temperatures sensor
+chip such as the LM83. The only case where using an LM83 would make
+sense is on SMP systems, such as the above-mentioned Iwill MPX2,
+because you want an additional temperature sensor for each additional
+CPU.
+
+On the SBS P014, this is different, since the LM83 is the only hardware
+monitoring chipset. One temperature sensor is used for the motherboard
+(actually measuring the LM83's own temperature), one is used for the
+CPU. The two other sensors must be used to measure the temperature of
+two other points of the motherboard. We suspect these points to be the
+north and south bridges, but this couldn't be confirmed.
+
+All temperature values are given in degrees Celsius. Local temperature
+is given within a range of 0 to +85 degrees. Remote temperatures are
+given within a range of 0 to +125 degrees. Resolution is 1.0 degree,
+accuracy is guaranteed to 3.0 degrees (see the datasheet for more
+details).
+
+Each sensor has its own high limit, but the critical limit is common to
+all four sensors. There is no hysteresis mechanism as found on most
+recent temperature sensors.
+
+The lm83 driver will not update its values more frequently than every
+other second; reading them more often will do no harm, but will return
+'old' values.
--- /dev/null
+Kernel driver lm85
+==================
+
+Supported chips:
+ * National Semiconductor LM85 (B and C versions)
+ Prefix: 'lm85'
+ Addresses scanned: I2C 0x2c, 0x2d, 0x2e
+ Datasheet: http://www.national.com/pf/LM/LM85.html
+ * Analog Devices ADM1027
+ Prefix: 'adm1027'
+ Addresses scanned: I2C 0x2c, 0x2d, 0x2e
+ Datasheet: http://www.analog.com/en/prod/0,,766_825_ADM1027,00.html
+ * Analog Devices ADT7463
+ Prefix: 'adt7463'
+ Addresses scanned: I2C 0x2c, 0x2d, 0x2e
+ Datasheet: http://www.analog.com/en/prod/0,,766_825_ADT7463,00.html
+ * SMSC EMC6D100, SMSC EMC6D101
+ Prefix: 'emc6d100'
+ Addresses scanned: I2C 0x2c, 0x2d, 0x2e
+ Datasheet: http://www.smsc.com/main/tools/discontinued/6d100.pdf
+ * SMSC EMC6D102
+ Prefix: 'emc6d102'
+ Addresses scanned: I2C 0x2c, 0x2d, 0x2e
+ Datasheet: http://www.smsc.com/main/catalog/emc6d102.html
+
+Authors:
+ Philip Pokorny <ppokorny@penguincomputing.com>,
+ Frodo Looijaard <frodol@dds.nl>,
+ Richard Barrington <rich_b_nz@clear.net.nz>,
+ Margit Schubert-While <margitsw@t-online.de>,
+ Justin Thiessen <jthiessen@penguincomputing.com>
+
+Description
+-----------
+
+This driver implements support for the National Semiconductor LM85 and
+compatible chips including the Analog Devices ADM1027, ADT7463 and
+SMSC EMC6D10x chips family.
+
+The LM85 uses the 2-wire interface compatible with the SMBUS 2.0
+specification. Using an analog to digital converter it measures three (3)
+temperatures and five (5) voltages. It has four (4) 16-bit counters for
+measuring fan speed. Five (5) digital inputs are provided for sampling the
+VID signals from the processor to the VRM. Lastly, there are three (3) PWM
+outputs that can be used to control fan speed.
+
+The voltage inputs have internal scaling resistors so that the following
+voltage can be measured without external resistors:
+
+ 2.5V, 3.3V, 5V, 12V, and CPU core voltage (2.25V)
+
+The temperatures measured are one internal diode, and two remote diodes.
+Remote 1 is generally the CPU temperature. These inputs are designed to
+measure a thermal diode like the one in a Pentium 4 processor in a socket
+423 or socket 478 package. They can also measure temperature using a
+transistor like the 2N3904.
+
+A sophisticated control system for the PWM outputs is designed into the
+LM85 that allows fan speed to be adjusted automatically based on any of the
+three temperature sensors. Each PWM output is individually adjustable and
+programmable. Once configured, the LM85 will adjust the PWM outputs in
+response to the measured temperatures without further host intervention.
+This feature can also be disabled for manual control of the PWM's.
+
+Each of the measured inputs (voltage, temperature, fan speed) has
+corresponding high/low limit values. The LM85 will signal an ALARM if any
+measured value exceeds either limit.
+
+The LM85 samples all inputs continuously. The lm85 driver will not read
+the registers more often than once a second. Further, configuration data is
+only read once each 5 minutes. There is twice as much config data as
+measurements, so this would seem to be a worthwhile optimization.
+
+Special Features
+----------------
+
+The LM85 has four fan speed monitoring modes. The ADM1027 has only two.
+Both have special circuitry to compensate for PWM interactions with the
+TACH signal from the fans. The ADM1027 can be configured to measure the
+speed of a two wire fan, but the input conditioning circuitry is different
+for 3-wire and 2-wire mode. For this reason, the 2-wire fan modes are not
+exposed to user control. The BIOS should initialize them to the correct
+mode. If you've designed your own ADM1027, you'll have to modify the
+init_client function and add an insmod parameter to set this up.
+
+To smooth the response of fans to changes in temperature, the LM85 has an
+optional filter for smoothing temperatures. The ADM1027 has the same
+config option but uses it to rate limit the changes to fan speed instead.
+
+The ADM1027 and ADT7463 have a 10-bit ADC and can therefore measure
+temperatures with 0.25 degC resolution. They also provide an offset to the
+temperature readings that is automatically applied during measurement.
+This offset can be used to zero out any errors due to traces and placement.
+The documentation says that the offset is in 0.25 degC steps, but in
+initial testing of the ADM1027 it was 1.00 degC steps. Analog Devices has
+confirmed this "bug". The ADT7463 is reported to work as described in the
+documentation. The current lm85 driver does not show the offset register.
+
+The ADT7463 has a THERM asserted counter. This counter has a 22.76ms
+resolution and a range of 5.8 seconds. The driver implements a 32-bit
+accumulator of the counter value to extend the range to over a year. The
+counter will stay at it's max value until read.
+
+See the vendor datasheets for more information. There is application note
+from National (AN-1260) with some additional information about the LM85.
+The Analog Devices datasheet is very detailed and describes a procedure for
+determining an optimal configuration for the automatic PWM control.
+
+The SMSC EMC6D100 & EMC6D101 monitor external voltages, temperatures, and
+fan speeds. They use this monitoring capability to alert the system to out
+of limit conditions and can automatically control the speeds of multiple
+fans in a PC or embedded system. The EMC6D101, available in a 24-pin SSOP
+package, and the EMC6D100, available in a 28-pin SSOP package, are designed
+to be register compatible. The EMC6D100 offers all the features of the
+EMC6D101 plus additional voltage monitoring and system control features.
+Unfortunately it is not possible to distinguish between the package
+versions on register level so these additional voltage inputs may read
+zero. The EMC6D102 features addtional ADC bits thus extending precision
+of voltage and temperature channels.
+
+
+Hardware Configurations
+-----------------------
+
+The LM85 can be jumpered for 3 different SMBus addresses. There are
+no other hardware configuration options for the LM85.
+
+The lm85 driver detects both LM85B and LM85C revisions of the chip. See the
+datasheet for a complete description of the differences. Other than
+identifying the chip, the driver behaves no differently with regard to
+these two chips. The LM85B is recommended for new designs.
+
+The ADM1027 and ADT7463 chips have an optional SMBALERT output that can be
+used to signal the chipset in case a limit is exceeded or the temperature
+sensors fail. Individual sensor interrupts can be masked so they won't
+trigger SMBALERT. The SMBALERT output if configured replaces one of the other
+functions (PWM2 or IN0). This functionality is not implemented in current
+driver.
+
+The ADT7463 also has an optional THERM output/input which can be connected
+to the processor PROC_HOT output. If available, the autofan control
+dynamic Tmin feature can be enabled to keep the system temperature within
+spec (just?!) with the least possible fan noise.
+
+Configuration Notes
+-------------------
+
+Besides standard interfaces driver adds following:
+
+* Temperatures and Zones
+
+Each temperature sensor is associated with a Zone. There are three
+sensors and therefore three zones (# 1, 2 and 3). Each zone has the following
+temperature configuration points:
+
+* temp#_auto_temp_off - temperature below which fans should be off or spinning very low.
+* temp#_auto_temp_min - temperature over which fans start to spin.
+* temp#_auto_temp_max - temperature when fans spin at full speed.
+* temp#_auto_temp_crit - temperature when all fans will run full speed.
+
+* PWM Control
+
+There are three PWM outputs. The LM85 datasheet suggests that the
+pwm3 output control both fan3 and fan4. Each PWM can be individually
+configured and assigned to a zone for it's control value. Each PWM can be
+configured individually according to the following options.
+
+* pwm#_auto_pwm_min - this specifies the PWM value for temp#_auto_temp_off
+ temperature. (PWM value from 0 to 255)
+
+* pwm#_auto_pwm_freq - select base frequency of PWM output. You can select
+ in range of 10.0 to 94.0 Hz in .1 Hz units.
+ (Values 100 to 940).
+
+The pwm#_auto_pwm_freq can be set to one of the following 8 values. Setting the
+frequency to a value not on this list, will result in the next higher frequency
+being selected. The actual device frequency may vary slightly from this
+specification as designed by the manufacturer. Consult the datasheet for more
+details. (PWM Frequency values: 100, 150, 230, 300, 380, 470, 620, 940)
+
+* pwm#_auto_pwm_minctl - this flags selects for temp#_auto_temp_off temperature
+ the bahaviour of fans. Write 1 to let fans spinning at
+ pwm#_auto_pwm_min or write 0 to let them off.
+
+NOTE: It has been reported that there is a bug in the LM85 that causes the flag
+to be associated with the zones not the PWMs. This contradicts all the
+published documentation. Setting pwm#_min_ctl in this case actually affects all
+PWMs controlled by zone '#'.
+
+* PWM Controlling Zone selection
+
+* pwm#_auto_channels - controls zone that is associated with PWM
+
+Configuration choices:
+
+ Value Meaning
+ ------ ------------------------------------------------
+ 1 Controlled by Zone 1
+ 2 Controlled by Zone 2
+ 3 Controlled by Zone 3
+ 23 Controlled by higher temp of Zone 2 or 3
+ 123 Controlled by highest temp of Zone 1, 2 or 3
+ 0 PWM always 0% (off)
+ -1 PWM always 100% (full on)
+ -2 Manual control (write to 'pwm#' to set)
+
+The National LM85's have two vendor specific configuration
+features. Tach. mode and Spinup Control. For more details on these,
+see the LM85 datasheet or Application Note AN-1260.
+
+The Analog Devices ADM1027 has several vendor specific enhancements.
+The number of pulses-per-rev of the fans can be set, Tach monitoring
+can be optimized for PWM operation, and an offset can be applied to
+the temperatures to compensate for systemic errors in the
+measurements.
+
+In addition to the ADM1027 features, the ADT7463 also has Tmin control
+and THERM asserted counts. Automatic Tmin control acts to adjust the
+Tmin value to maintain the measured temperature sensor at a specified
+temperature. There isn't much documentation on this feature in the
+ADT7463 data sheet. This is not supported by current driver.
--- /dev/null
+Kernel driver lm87
+==================
+
+Supported chips:
+ * National Semiconductor LM87
+ Prefix: 'lm87'
+ Addresses scanned: I2C 0x2c - 0x2f
+ Datasheet: http://www.national.com/pf/LM/LM87.html
+
+Authors:
+ Frodo Looijaard <frodol@dds.nl>,
+ Philip Edelbrock <phil@netroedge.com>,
+ Mark Studebaker <mdsxyz123@yahoo.com>,
+ Stephen Rousset <stephen.rousset@rocketlogix.com>,
+ Dan Eaton <dan.eaton@rocketlogix.com>,
+ Jean Delvare <khali@linux-fr.org>,
+ Original 2.6 port Jeff Oliver
+
+Description
+-----------
+
+This driver implements support for the National Semiconductor LM87.
+
+The LM87 implements up to three temperature sensors, up to two fan
+rotation speed sensors, up to seven voltage sensors, alarms, and some
+miscellaneous stuff.
+
+Temperatures are measured in degrees Celsius. Each input has a high
+and low alarm settings. A high limit produces an alarm when the value
+goes above it, and an alarm is also produced when the value goes below
+the low limit.
+
+Fan rotation speeds are reported in RPM (rotations per minute). An alarm is
+triggered if the rotation speed has dropped below a programmable limit. Fan
+readings can be divided by a programmable divider (1, 2, 4 or 8) to give
+the readings more range or accuracy. Not all RPM values can accurately be
+represented, so some rounding is done. With a divider of 2, the lowest
+representable value is around 2600 RPM.
+
+Voltage sensors (also known as IN sensors) report their values in
+volts. An alarm is triggered if the voltage has crossed a programmable
+minimum or maximum limit. Note that minimum in this case always means
+'closest to zero'; this is important for negative voltage measurements.
+
+If an alarm triggers, it will remain triggered until the hardware register
+is read at least once. This means that the cause for the alarm may
+already have disappeared! Note that in the current implementation, all
+hardware registers are read whenever any data is read (unless it is less
+than 1.0 seconds since the last update). This means that you can easily
+miss once-only alarms.
+
+The lm87 driver only updates its values each 1.0 seconds; reading it more
+often will do no harm, but will return 'old' values.
+
+
+Hardware Configurations
+-----------------------
+
+The LM87 has four pins which can serve one of two possible functions,
+depending on the hardware configuration.
+
+Some functions share pins, so not all functions are available at the same
+time. Which are depends on the hardware setup. This driver assumes that
+the BIOS configured the chip correctly. In that respect, it differs from
+the original driver (from lm_sensors for Linux 2.4), which would force the
+LM87 to an arbitrary, compile-time chosen mode, regardless of the actual
+chipset wiring.
+
+For reference, here is the list of exclusive functions:
+ - in0+in5 (default) or temp3
+ - fan1 (default) or in6
+ - fan2 (default) or in7
+ - VID lines (default) or IRQ lines (not handled by this driver)
--- /dev/null
+Kernel driver lm90
+==================
+
+Supported chips:
+ * National Semiconductor LM90
+ Prefix: 'lm90'
+ Addresses scanned: I2C 0x4c
+ Datasheet: Publicly available at the National Semiconductor website
+ http://www.national.com/pf/LM/LM90.html
+ * National Semiconductor LM89
+ Prefix: 'lm99'
+ Addresses scanned: I2C 0x4c and 0x4d
+ Datasheet: Publicly available at the National Semiconductor website
+ http://www.national.com/pf/LM/LM89.html
+ * National Semiconductor LM99
+ Prefix: 'lm99'
+ Addresses scanned: I2C 0x4c and 0x4d
+ Datasheet: Publicly available at the National Semiconductor website
+ http://www.national.com/pf/LM/LM99.html
+ * National Semiconductor LM86
+ Prefix: 'lm86'
+ Addresses scanned: I2C 0x4c
+ Datasheet: Publicly available at the National Semiconductor website
+ http://www.national.com/pf/LM/LM86.html
+ * Analog Devices ADM1032
+ Prefix: 'adm1032'
+ Addresses scanned: I2C 0x4c
+ Datasheet: Publicly available at the Analog Devices website
+ http://products.analog.com/products/info.asp?product=ADM1032
+ * Analog Devices ADT7461
+ Prefix: 'adt7461'
+ Addresses scanned: I2C 0x4c
+ Datasheet: Publicly available at the Analog Devices website
+ http://products.analog.com/products/info.asp?product=ADT7461
+ Note: Only if in ADM1032 compatibility mode
+ * Maxim MAX6657
+ Prefix: 'max6657'
+ Addresses scanned: I2C 0x4c
+ Datasheet: Publicly available at the Maxim website
+ http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2578
+ * Maxim MAX6658
+ Prefix: 'max6657'
+ Addresses scanned: I2C 0x4c
+ Datasheet: Publicly available at the Maxim website
+ http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2578
+ * Maxim MAX6659
+ Prefix: 'max6657'
+ Addresses scanned: I2C 0x4c, 0x4d (unsupported 0x4e)
+ Datasheet: Publicly available at the Maxim website
+ http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2578
+
+
+Author: Jean Delvare <khali@linux-fr.org>
+
+
+Description
+-----------
+
+The LM90 is a digital temperature sensor. It senses its own temperature as
+well as the temperature of up to one external diode. It is compatible
+with many other devices such as the LM86, the LM89, the LM99, the ADM1032,
+the MAX6657, MAX6658 and the MAX6659 all of which are supported by this driver.
+Note that there is no easy way to differentiate between the last three
+variants. The extra address and features of the MAX6659 are not supported by
+this driver. Additionally, the ADT7461 is supported if found in ADM1032
+compatibility mode.
+
+The specificity of this family of chipsets over the ADM1021/LM84
+family is that it features critical limits with hysteresis, and an
+increased resolution of the remote temperature measurement.
+
+The different chipsets of the family are not strictly identical, although
+very similar. This driver doesn't handle any specific feature for now,
+but could if there ever was a need for it. For reference, here comes a
+non-exhaustive list of specific features:
+
+LM90:
+ * Filter and alert configuration register at 0xBF.
+ * ALERT is triggered by temperatures over critical limits.
+
+LM86 and LM89:
+ * Same as LM90
+ * Better external channel accuracy
+
+LM99:
+ * Same as LM89
+ * External temperature shifted by 16 degrees down
+
+ADM1032:
+ * Consecutive alert register at 0x22.
+ * Conversion averaging.
+ * Up to 64 conversions/s.
+ * ALERT is triggered by open remote sensor.
+
+ADT7461
+ * Extended temperature range (breaks compatibility)
+ * Lower resolution for remote temperature
+
+MAX6657 and MAX6658:
+ * Remote sensor type selection
+
+MAX6659
+ * Selectable address
+ * Second critical temperature limit
+ * Remote sensor type selection
+
+All temperature values are given in degrees Celsius. Resolution
+is 1.0 degree for the local temperature, 0.125 degree for the remote
+temperature.
+
+Each sensor has its own high and low limits, plus a critical limit.
+Additionally, there is a relative hysteresis value common to both critical
+values. To make life easier to user-space applications, two absolute values
+are exported, one for each channel, but these values are of course linked.
+Only the local hysteresis can be set from user-space, and the same delta
+applies to the remote hysteresis.
+
+The lm90 driver will not update its values more frequently than every
+other second; reading them more often will do no harm, but will return
+'old' values.
+
--- /dev/null
+Kernel driver lm92
+==================
+
+Supported chips:
+ * National Semiconductor LM92
+ Prefix: 'lm92'
+ Addresses scanned: I2C 0x48 - 0x4b
+ Datasheet: http://www.national.com/pf/LM/LM92.html
+ * National Semiconductor LM76
+ Prefix: 'lm92'
+ Addresses scanned: none, force parameter needed
+ Datasheet: http://www.national.com/pf/LM/LM76.html
+ * Maxim MAX6633/MAX6634/MAX6635
+ Prefix: 'lm92'
+ Addresses scanned: I2C 0x48 - 0x4b
+ MAX6633 with address in 0x40 - 0x47, 0x4c - 0x4f needs force parameter
+ and MAX6634 with address in 0x4c - 0x4f needs force parameter
+ Datasheet: http://www.maxim-ic.com/quick_view2.cfm/qv_pk/3074
+
+Authors:
+ Abraham van der Merwe <abraham@2d3d.co.za>
+ Jean Delvare <khali@linux-fr.org>
+
+
+Description
+-----------
+
+This driver implements support for the National Semiconductor LM92
+temperature sensor.
+
+Each LM92 temperature sensor supports a single temperature sensor. There are
+alarms for high, low, and critical thresholds. There's also an hysteresis to
+control the thresholds for resetting alarms.
+
+Support was added later for the LM76 and Maxim MAX6633/MAX6634/MAX6635,
+which are mostly compatible. They have not all been tested, so you
+may need to use the force parameter.
--- /dev/null
+Kernel driver max1619
+=====================
+
+Supported chips:
+ * Maxim MAX1619
+ Prefix: 'max1619'
+ Addresses scanned: I2C 0x18-0x1a, 0x29-0x2b, 0x4c-0x4e
+ Datasheet: Publicly available at the Maxim website
+ http://pdfserv.maxim-ic.com/en/ds/MAX1619.pdf
+
+Authors:
+ Alexey Fisher <fishor@mail.ru>,
+ Jean Delvare <khali@linux-fr.org>
+
+Description
+-----------
+
+The MAX1619 is a digital temperature sensor. It senses its own temperature as
+well as the temperature of up to one external diode.
+
+All temperature values are given in degrees Celsius. Resolution
+is 1.0 degree for the local temperature and for the remote temperature.
+
+Only the external sensor has high and low limits.
+
+The max1619 driver will not update its values more frequently than every
+other second; reading them more often will do no harm, but will return
+'old' values.
+
--- /dev/null
+Kernel driver max6875
+=====================
+
+Supported chips:
+ * Maxim max6874, max6875
+ Prefixes: 'max6875'
+ Addresses scanned: 0x50, 0x52
+ Datasheets:
+ http://pdfserv.maxim-ic.com/en/ds/MAX6874-MAX6875.pdf
+
+Author: Ben Gardner <bgardner@wabtec.com>
+
+
+Module Parameters
+-----------------
+
+* allow_write int
+ Set to non-zero to enable write permission:
+ *0: Read only
+ 1: Read and write
+
+
+Description
+-----------
+
+The MAXIM max6875 is a EEPROM-programmable power-supply sequencer/supervisor.
+It provides timed outputs that can be used as a watchdog, if properly wired.
+It also provides 512 bytes of user EEPROM.
+
+At reset, the max6875 reads the configuration eeprom into its configuration
+registers. The chip then begins to operate according to the values in the
+registers.
+
+See the datasheet for details on how to program the EEPROM.
+
+
+Sysfs entries
+-------------
+
+eeprom_user - 512 bytes of user-defined EEPROM space. Only writable if
+ allow_write was set and register 0x43 is 0.
+
+eeprom_config - 70 bytes of config EEPROM. Note that changes will not get
+ loaded into register space until a power cycle or device reset.
+
+reg_config - 70 bytes of register space. Any changes take affect immediately.
+
+
+General Remarks
+---------------
+
+A typical application will require that the EEPROMs be programmed once and
+never altered afterwards.
+
--- /dev/null
+Kernel driver pc87360
+=====================
+
+Supported chips:
+ * National Semiconductor PC87360, PC87363, PC87364, PC87365 and PC87366
+ Prefixes: 'pc87360', 'pc87363', 'pc87364', 'pc87365', 'pc87366'
+ Addresses scanned: none, address read from Super I/O config space
+ Datasheets:
+ http://www.national.com/pf/PC/PC87360.html
+ http://www.national.com/pf/PC/PC87363.html
+ http://www.national.com/pf/PC/PC87364.html
+ http://www.national.com/pf/PC/PC87365.html
+ http://www.national.com/pf/PC/PC87366.html
+
+Authors: Jean Delvare <khali@linux-fr.org>
+
+Thanks to Sandeep Mehta, Tonko de Rooy and Daniel Ceregatti for testing.
+Thanks to Rudolf Marek for helping me investigate conversion issues.
+
+
+Module Parameters
+-----------------
+
+* init int
+ Chip initialization level:
+ 0: None
+ *1: Forcibly enable internal voltage and temperature channels, except in9
+ 2: Forcibly enable all voltage and temperature channels, except in9
+ 3: Forcibly enable all voltage and temperature channels, including in9
+
+Note that this parameter has no effect for the PC87360, PC87363 and PC87364
+chips.
+
+Also note that for the PC87366, initialization levels 2 and 3 don't enable
+all temperature channels, because some of them share pins with each other,
+so they can't be used at the same time.
+
+
+Description
+-----------
+
+The National Semiconductor PC87360 Super I/O chip contains monitoring and
+PWM control circuitry for two fans. The PC87363 chip is similar, and the
+PC87364 chip has monitoring and PWM control for a third fan.
+
+The National Semiconductor PC87365 and PC87366 Super I/O chips are complete
+hardware monitoring chipsets, not only controlling and monitoring three fans,
+but also monitoring eleven voltage inputs and two (PC87365) or up to four
+(PC87366) temperatures.
+
+ Chip #vin #fan #pwm #temp devid
+
+ PC87360 - 2 2 - 0xE1
+ PC87363 - 2 2 - 0xE8
+ PC87364 - 3 3 - 0xE4
+ PC87365 11 3 3 2 0xE5
+ PC87366 11 3 3 3-4 0xE9
+
+The driver assumes that no more than one chip is present, and one of the
+standard Super I/O addresses is used (0x2E/0x2F or 0x4E/0x4F)
+
+Fan Monitoring
+--------------
+
+Fan rotation speeds are reported in RPM (revolutions per minute). An alarm
+is triggered if the rotation speed has dropped below a programmable limit.
+A different alarm is triggered if the fan speed is too low to be measured.
+
+Fan readings are affected by a programmable clock divider, giving the
+readings more range or accuracy. Usually, users have to learn how it works,
+but this driver implements dynamic clock divider selection, so you don't
+have to care no more.
+
+For reference, here are a few values about clock dividers:
+
+ slowest accuracy highest
+ measurable around 3000 accurate
+ divider speed (RPM) RPM (RPM) speed (RPM)
+ 1 1882 18 6928
+ 2 941 37 4898
+ 4 470 74 3464
+ 8 235 150 2449
+
+For the curious, here is how the values above were computed:
+ * slowest measurable speed: clock/(255*divider)
+ * accuracy around 3000 RPM: 3000^2/clock
+ * highest accurate speed: sqrt(clock*100)
+The clock speed for the PC87360 family is 480 kHz. I arbitrarily chose 100
+RPM as the lowest acceptable accuracy.
+
+As mentioned above, you don't have to care about this no more.
+
+Note that not all RPM values can be represented, even when the best clock
+divider is selected. This is not only true for the measured speeds, but
+also for the programmable low limits, so don't be surprised if you try to
+set, say, fan1_min to 2900 and it finally reads 2909.
+
+
+Fan Control
+-----------
+
+PWM (pulse width modulation) values range from 0 to 255, with 0 meaning
+that the fan is stopped, and 255 meaning that the fan goes at full speed.
+
+Be extremely careful when changing PWM values. Low PWM values, even
+non-zero, can stop the fan, which may cause irreversible damage to your
+hardware if temperature increases too much. When changing PWM values, go
+step by step and keep an eye on temperatures.
+
+One user reported problems with PWM. Changing PWM values would break fan
+speed readings. No explanation nor fix could be found.
+
+
+Temperature Monitoring
+----------------------
+
+Temperatures are reported in degrees Celsius. Each temperature measured has
+associated low, high and overtemperature limits, each of which triggers an
+alarm when crossed.
+
+The first two temperature channels are external. The third one (PC87366
+only) is internal.
+
+The PC87366 has three additional temperature channels, based on
+thermistors (as opposed to thermal diodes for the first three temperature
+channels). For technical reasons, these channels are held by the VLM
+(voltage level monitor) logical device, not the TMS (temperature
+measurement) one. As a consequence, these temperatures are exported as
+voltages, and converted into temperatures in user-space.
+
+Note that these three additional channels share their pins with the
+external thermal diode channels, so you (physically) can't use them all at
+the same time. Although it should be possible to mix the two sensor types,
+the documents from National Semiconductor suggest that motherboard
+manufacturers should choose one type and stick to it. So you will more
+likely have either channels 1 to 3 (thermal diodes) or 3 to 6 (internal
+thermal diode, and thermistors).
+
+
+Voltage Monitoring
+------------------
+
+Voltages are reported relatively to a reference voltage, either internal or
+external. Some of them (in7:Vsb, in8:Vdd and in10:AVdd) are divided by two
+internally, you will have to compensate in sensors.conf. Others (in0 to in6)
+are likely to be divided externally. The meaning of each of these inputs as
+well as the values of the resistors used for division is left to the
+motherboard manufacturers, so you will have to document yourself and edit
+sensors.conf accordingly. National Semiconductor has a document with
+recommended resistor values for some voltages, but this still leaves much
+room for per motherboard specificities, unfortunately. Even worse,
+motherboard manufacturers don't seem to care about National Semiconductor's
+recommendations.
+
+Each voltage measured has associated low and high limits, each of which
+triggers an alarm when crossed.
+
+When available, VID inputs are used to provide the nominal CPU Core voltage.
+The driver will default to VRM 9.0, but this can be changed from user-space.
+The chipsets can handle two sets of VID inputs (on dual-CPU systems), but
+the driver will only export one for now. This may change later if there is
+a need.
+
+
+General Remarks
+---------------
+
+If an alarm triggers, it will remain triggered until the hardware register
+is read at least once. This means that the cause for the alarm may already
+have disappeared! Note that all hardware registers are read whenever any
+data is read (unless it is less than 2 seconds since the last update, in
+which case cached values are returned instead). As a consequence, when
+a once-only alarm triggers, it may take 2 seconds for it to show, and 2
+more seconds for it to disappear.
+
+Monitoring of in9 isn't enabled at lower init levels (<3) because that
+channel measures the battery voltage (Vbat). It is a known fact that
+repeatedly sampling the battery voltage reduces its lifetime. National
+Semiconductor smartly designed their chipset so that in9 is sampled only
+once every 1024 sampling cycles (that is every 34 minutes at the default
+sampling rate), so the effect is attenuated, but still present.
+
+
+Limitations
+-----------
+
+The datasheets suggests that some values (fan mins, fan dividers)
+shouldn't be changed once the monitoring has started, but we ignore that
+recommendation. We'll reconsider if it actually causes trouble.
--- /dev/null
+Kernel driver pca9539
+=====================
+
+Supported chips:
+ * Philips PCA9539
+ Prefix: 'pca9539'
+ Addresses scanned: 0x74 - 0x77
+ Datasheet:
+ http://www.semiconductors.philips.com/acrobat/datasheets/PCA9539_2.pdf
+
+Author: Ben Gardner <bgardner@wabtec.com>
+
+
+Description
+-----------
+
+The Philips PCA9539 is a 16 bit low power I/O device.
+All 16 lines can be individually configured as an input or output.
+The input sense can also be inverted.
+The 16 lines are split between two bytes.
+
+
+Sysfs entries
+-------------
+
+Each is a byte that maps to the 8 I/O bits.
+A '0' suffix is for bits 0-7, while '1' is for bits 8-15.
+
+input[01] - read the current value
+output[01] - sets the output value
+direction[01] - direction of each bit: 1=input, 0=output
+invert[01] - toggle the input bit sense
+
+input reads the actual state of the line and is always available.
+The direction defaults to input for all channels.
+
+
+General Remarks
+---------------
+
+Note that each output, direction, and invert entry controls 8 lines.
+You should use the read, modify, write sequence.
+For example. to set output bit 0 of 1.
+ val=$(cat output0)
+ val=$(( $val | 1 ))
+ echo $val > output0
+
--- /dev/null
+Kernel driver pcf8574
+=====================
+
+Supported chips:
+ * Philips PCF8574
+ Prefix: 'pcf8574'
+ Addresses scanned: I2C 0x20 - 0x27
+ Datasheet: Publicly available at the Philips Semiconductors website
+ http://www.semiconductors.philips.com/pip/PCF8574P.html
+
+ * Philips PCF8574A
+ Prefix: 'pcf8574a'
+ Addresses scanned: I2C 0x38 - 0x3f
+ Datasheet: Publicly available at the Philips Semiconductors website
+ http://www.semiconductors.philips.com/pip/PCF8574P.html
+
+Authors:
+ Frodo Looijaard <frodol@dds.nl>,
+ Philip Edelbrock <phil@netroedge.com>,
+ Dan Eaton <dan.eaton@rocketlogix.com>,
+ Aurelien Jarno <aurelien@aurel32.net>,
+ Jean Delvare <khali@linux-fr.org>,
+
+
+Description
+-----------
+The PCF8574(A) is an 8-bit I/O expander for the I2C bus produced by Philips
+Semiconductors. It is designed to provide a byte I2C interface to up to 16
+separate devices (8 x PCF8574 and 8 x PCF8574A).
+
+This device consists of a quasi-bidirectional port. Each of the eight I/Os
+can be independently used as an input or output. To setup an I/O as an
+input, you have to write a 1 to the corresponding output.
+
+For more informations see the datasheet.
+
+
+Accessing PCF8574(A) via /sys interface
+-------------------------------------
+
+! Be careful !
+The PCF8574(A) is plainly impossible to detect ! Stupid chip.
+So every chip with address in the interval [20..27] and [38..3f] are
+detected as PCF8574(A). If you have other chips in this address
+range, the workaround is to load this module after the one
+for your others chips.
+
+On detection (i.e. insmod, modprobe et al.), directories are being
+created for each detected PCF8574(A):
+
+/sys/bus/i2c/devices/<0>-<1>/
+where <0> is the bus the chip was detected on (e. g. i2c-0)
+and <1> the chip address ([20..27] or [38..3f]):
+
+(example: /sys/bus/i2c/devices/1-0020/)
+
+Inside these directories, there are two files each:
+read and write (and one file with chip name).
+
+The read file is read-only. Reading gives you the current I/O input
+if the corresponding output is set as 1, otherwise the current output
+value, that is to say 0.
+
+The write file is read/write. Writing a value outputs it on the I/O
+port. Reading returns the last written value.
+
+On module initialization the chip is configured as eight inputs (all
+outputs to 1), so you can connect any circuit to the PCF8574(A) without
+being afraid of short-circuit.
--- /dev/null
+Kernel driver pcf8591
+=====================
+
+Supported chips:
+ * Philips PCF8591
+ Prefix: 'pcf8591'
+ Addresses scanned: I2C 0x48 - 0x4f
+ Datasheet: Publicly available at the Philips Semiconductor website
+ http://www.semiconductors.philips.com/pip/PCF8591P.html
+
+Authors:
+ Aurelien Jarno <aurelien@aurel32.net>
+ valuable contributions by Jan M. Sendler <sendler@sendler.de>,
+ Jean Delvare <khali@linux-fr.org>
+
+
+Description
+-----------
+The PCF8591 is an 8-bit A/D and D/A converter (4 analog inputs and one
+analog output) for the I2C bus produced by Philips Semiconductors. It
+is designed to provide a byte I2C interface to up to 4 separate devices.
+
+The PCF8591 has 4 analog inputs programmable as single-ended or
+differential inputs :
+- mode 0 : four single ended inputs
+ Pins AIN0 to AIN3 are single ended inputs for channels 0 to 3
+
+- mode 1 : three differential inputs
+ Pins AIN3 is the common negative differential input
+ Pins AIN0 to AIN2 are positive differential inputs for channels 0 to 2
+
+- mode 2 : single ended and differential mixed
+ Pins AIN0 and AIN1 are single ended inputs for channels 0 and 1
+ Pins AIN2 is the positive differential input for channel 3
+ Pins AIN3 is the negative differential input for channel 3
+
+- mode 3 : two differential inputs
+ Pins AIN0 is the positive differential input for channel 0
+ Pins AIN1 is the negative differential input for channel 0
+ Pins AIN2 is the positive differential input for channel 1
+ Pins AIN3 is the negative differential input for channel 1
+
+See the datasheet for details.
+
+Module parameters
+-----------------
+
+* input_mode int
+
+ Analog input mode:
+ 0 = four single ended inputs
+ 1 = three differential inputs
+ 2 = single ended and differential mixed
+ 3 = two differential inputs
+
+
+Accessing PCF8591 via /sys interface
+-------------------------------------
+
+! Be careful !
+The PCF8591 is plainly impossible to detect ! Stupid chip.
+So every chip with address in the interval [48..4f] is
+detected as PCF8591. If you have other chips in this address
+range, the workaround is to load this module after the one
+for your others chips.
+
+On detection (i.e. insmod, modprobe et al.), directories are being
+created for each detected PCF8591:
+
+/sys/bus/devices/<0>-<1>/
+where <0> is the bus the chip was detected on (e. g. i2c-0)
+and <1> the chip address ([48..4f])
+
+Inside these directories, there are such files:
+in0, in1, in2, in3, out0_enable, out0_output, name
+
+Name contains chip name.
+
+The in0, in1, in2 and in3 files are RO. Reading gives the value of the
+corresponding channel. Depending on the current analog inputs configuration,
+files in2 and/or in3 do not exist. Values range are from 0 to 255 for single
+ended inputs and -128 to +127 for differential inputs (8-bit ADC).
+
+The out0_enable file is RW. Reading gives "1" for analog output enabled and
+"0" for analog output disabled. Writing accepts "0" and "1" accordingly.
+
+The out0_output file is RW. Writing a number between 0 and 255 (8-bit DAC), send
+the value to the digital-to-analog converter. Note that a voltage will
+only appears on AOUT pin if aout0_enable equals 1. Reading returns the last
+value written.
--- /dev/null
+Kernel driver sis5595
+=====================
+
+Supported chips:
+ * Silicon Integrated Systems Corp. SiS5595 Southbridge Hardware Monitor
+ Prefix: 'sis5595'
+ Addresses scanned: ISA in PCI-space encoded address
+ Datasheet: Publicly available at the Silicon Integrated Systems Corp. site.
+
+Authors:
+ Kyösti Mälkki <kmalkki@cc.hut.fi>,
+ Mark D. Studebaker <mdsxyz123@yahoo.com>,
+ Aurelien Jarno <aurelien@aurel32.net> 2.6 port
+
+ SiS southbridge has a LM78-like chip integrated on the same IC.
+ This driver is a customized copy of lm78.c
+
+ Supports following revisions:
+ Version PCI ID PCI Revision
+ 1 1039/0008 AF or less
+ 2 1039/0008 B0 or greater
+
+ 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
+ 630 0008 0630
+ 645 0008 0645
+ 730 0008 0730
+ 735 0008 0735
+
+
+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.
+ Example: 'modprobe sis5595 force_addr=0x290'
+
+
+Description
+-----------
+
+The SiS5595 southbridge has integrated hardware monitor functions. It also
+has an I2C bus, but this driver only supports the hardware monitor. For the
+I2C bus driver see i2c-sis5595.
+
+The SiS5595 implements zero or one temperature sensor, two fan speed
+sensors, four or five voltage sensors, and alarms.
+
+On the first version of the chip, there are four voltage sensors and one
+temperature sensor.
+
+On the second version of the chip, the temperature sensor (temp) and the
+fifth voltage sensor (in4) share a pin which is configurable, but not
+through the driver. Sorry. The driver senses the configuration of the pin,
+which was hopefully set by the BIOS.
+
+Temperatures are measured in degrees Celsius. An alarm is triggered once
+when the max is crossed; it is also triggered when it drops below the min
+value. Measurements are guaranteed between -55 and +125 degrees, with a
+resolution of 1 degree.
+
+Fan rotation speeds are reported in RPM (rotations per minute). An alarm is
+triggered if the rotation speed has dropped below a programmable limit. Fan
+readings can be divided by a programmable divider (1, 2, 4 or 8) to give
+the readings more range or accuracy. Not all RPM values can accurately be
+represented, so some rounding is done. With a divider of 2, the lowest
+representable value is around 2600 RPM.
+
+Voltage sensors (also known as IN sensors) report their values in volts. An
+alarm is triggered if the voltage has crossed a programmable minimum or
+maximum limit. Note that minimum in this case always means 'closest to
+zero'; this is important for negative voltage measurements. All voltage
+inputs can measure voltages between 0 and 4.08 volts, with a resolution of
+0.016 volt.
+
+In addition to the alarms described above, there is a BTI alarm, which gets
+triggered when an external chip has crossed its limits. Usually, this is
+connected to some LM75-like chip; if at least one crosses its limits, this
+bit gets set.
+
+If an alarm triggers, it will remain triggered until the hardware register
+is read at least once. This means that the cause for the alarm may already
+have disappeared! Note that in the current implementation, all hardware
+registers are read whenever any data is read (unless it is less than 1.5
+seconds since the last update). This means that you can easily miss
+once-only alarms.
+
+The SiS5595 only updates its values each 1.5 seconds; reading it more often
+will do no harm, but will return 'old' values.
+
+Problems
+--------
+Some chips refuse to be enabled. We don't know why.
+The driver will recognize this and print a message in dmesg.
+
--- /dev/null
+Kernel driver smsc47b397
+========================
+
+Supported chips:
+ * SMSC LPC47B397-NC
+ Prefix: 'smsc47b397'
+ Addresses scanned: none, address read from Super I/O config space
+ Datasheet: In this file
+
+Authors: Mark M. Hoffman <mhoffman@lightlink.com>
+ Utilitek Systems, Inc.
+
+November 23, 2004
+
+The following specification describes the SMSC LPC47B397-NC sensor chip
+(for which there is no public datasheet available). This document was
+provided by Craig Kelly (In-Store Broadcast Network) and edited/corrected
+by Mark M. Hoffman <mhoffman@lightlink.com>.
+
+* * * * *
+
+Methods for detecting the HP SIO and reading the thermal data on a dc7100.
+
+The thermal information on the dc7100 is contained in the SIO Hardware Monitor
+(HWM). The information is accessed through an index/data pair. The index/data
+pair is located at the HWM Base Address + 0 and the HWM Base Address + 1. The
+HWM Base address can be obtained from Logical Device 8, registers 0x60 (MSB)
+and 0x61 (LSB). Currently we are using 0x480 for the HWM Base Address and
+0x480 and 0x481 for the index/data pair.
+
+Reading temperature information.
+The temperature information is located in the following registers:
+Temp1 0x25 (Currently, this reflects the CPU temp on all systems).
+Temp2 0x26
+Temp3 0x27
+Temp4 0x80
+
+Programming Example
+The following is an example of how to read the HWM temperature registers:
+MOV DX,480H
+MOV AX,25H
+OUT DX,AL
+MOV DX,481H
+IN AL,DX
+
+AL contains the data in hex, the temperature in Celsius is the decimal
+equivalent.
+
+Ex: If AL contains 0x2A, the temperature is 42 degrees C.
+
+Reading tach information.
+The fan speed information is located in the following registers:
+ LSB MSB
+Tach1 0x28 0x29 (Currently, this reflects the CPU
+ fan speed on all systems).
+Tach2 0x2A 0x2B
+Tach3 0x2C 0x2D
+Tach4 0x2E 0x2F
+
+Important!!!
+Reading the tach LSB locks the tach MSB.
+The LSB Must be read first.
+
+How to convert the tach reading to RPM.
+The tach reading (TCount) is given by: (Tach MSB * 256) + (Tach LSB)
+The SIO counts the number of 90kHz (11.111us) pulses per revolution.
+RPM = 60/(TCount * 11.111us)
+
+Example:
+Reg 0x28 = 0x9B
+Reg 0x29 = 0x08
+
+TCount = 0x89B = 2203
+
+RPM = 60 / (2203 * 11.11111 E-6) = 2451 RPM
+
+Obtaining the SIO version.
+
+CONFIGURATION SEQUENCE
+To program the configuration registers, the following sequence must be followed:
+1. Enter Configuration Mode
+2. Configure the Configuration Registers
+3. Exit Configuration Mode.
+
+Enter Configuration Mode
+To place the chip into the Configuration State The config key (0x55) is written
+to the CONFIG PORT (0x2E).
+
+Configuration Mode
+In configuration mode, the INDEX PORT is located at the CONFIG PORT address and
+the DATA PORT is at INDEX PORT address + 1.
+
+The desired configuration registers are accessed in two steps:
+a. Write the index of the Logical Device Number Configuration Register
+ (i.e., 0x07) to the INDEX PORT and then write the number of the
+ desired logical device to the DATA PORT.
+
+b. Write the address of the desired configuration register within the
+ logical device to the INDEX PORT and then write or read the config-
+ uration register through the DATA PORT.
+
+Note: If accessing the Global Configuration Registers, step (a) is not required.
+
+Exit Configuration Mode
+To exit the Configuration State the write 0xAA to the CONFIG PORT (0x2E).
+The chip returns to the RUN State. (This is important).
+
+Programming Example
+The following is an example of how to read the SIO Device ID located at 0x20
+
+; ENTER CONFIGURATION MODE
+MOV DX,02EH
+MOV AX,055H
+OUT DX,AL
+; GLOBAL CONFIGURATION REGISTER
+MOV DX,02EH
+MOV AL,20H
+OUT DX,AL
+; READ THE DATA
+MOV DX,02FH
+IN AL,DX
+; EXIT CONFIGURATION MODE
+MOV DX,02EH
+MOV AX,0AAH
+OUT DX,AL
+
+The registers of interest for identifying the SIO on the dc7100 are Device ID
+(0x20) and Device Rev (0x21).
+
+The Device ID will read 0X6F
+The Device Rev currently reads 0x01
+
+Obtaining the HWM Base Address.
+The following is an example of how to read the HWM Base Address located in
+Logical Device 8.
+
+; ENTER CONFIGURATION MODE
+MOV DX,02EH
+MOV AX,055H
+OUT DX,AL
+; CONFIGURE REGISTER CRE0,
+; LOGICAL DEVICE 8
+MOV DX,02EH
+MOV AL,07H
+OUT DX,AL ;Point to LD# Config Reg
+MOV DX,02FH
+MOV AL, 08H
+OUT DX,AL;Point to Logical Device 8
+;
+MOV DX,02EH
+MOV AL,60H
+OUT DX,AL ; Point to HWM Base Addr MSB
+MOV DX,02FH
+IN AL,DX ; Get MSB of HWM Base Addr
+; EXIT CONFIGURATION MODE
+MOV DX,02EH
+MOV AX,0AAH
+OUT DX,AL
+++ /dev/null
-November 23, 2004
-
-The following specification describes the SMSC LPC47B397-NC sensor chip
-(for which there is no public datasheet available). This document was
-provided by Craig Kelly (In-Store Broadcast Network) and edited/corrected
-by Mark M. Hoffman <mhoffman@lightlink.com>.
-
-* * * * *
-
-Methods for detecting the HP SIO and reading the thermal data on a dc7100.
-
-The thermal information on the dc7100 is contained in the SIO Hardware Monitor
-(HWM). The information is accessed through an index/data pair. The index/data
-pair is located at the HWM Base Address + 0 and the HWM Base Address + 1. The
-HWM Base address can be obtained from Logical Device 8, registers 0x60 (MSB)
-and 0x61 (LSB). Currently we are using 0x480 for the HWM Base Address and
-0x480 and 0x481 for the index/data pair.
-
-Reading temperature information.
-The temperature information is located in the following registers:
-Temp1 0x25 (Currently, this reflects the CPU temp on all systems).
-Temp2 0x26
-Temp3 0x27
-Temp4 0x80
-
-Programming Example
-The following is an example of how to read the HWM temperature registers:
-MOV DX,480H
-MOV AX,25H
-OUT DX,AL
-MOV DX,481H
-IN AL,DX
-
-AL contains the data in hex, the temperature in Celsius is the decimal
-equivalent.
-
-Ex: If AL contains 0x2A, the temperature is 42 degrees C.
-
-Reading tach information.
-The fan speed information is located in the following registers:
- LSB MSB
-Tach1 0x28 0x29 (Currently, this reflects the CPU
- fan speed on all systems).
-Tach2 0x2A 0x2B
-Tach3 0x2C 0x2D
-Tach4 0x2E 0x2F
-
-Important!!!
-Reading the tach LSB locks the tach MSB.
-The LSB Must be read first.
-
-How to convert the tach reading to RPM.
-The tach reading (TCount) is given by: (Tach MSB * 256) + (Tach LSB)
-The SIO counts the number of 90kHz (11.111us) pulses per revolution.
-RPM = 60/(TCount * 11.111us)
-
-Example:
-Reg 0x28 = 0x9B
-Reg 0x29 = 0x08
-
-TCount = 0x89B = 2203
-
-RPM = 60 / (2203 * 11.11111 E-6) = 2451 RPM
-
-Obtaining the SIO version.
-
-CONFIGURATION SEQUENCE
-To program the configuration registers, the following sequence must be followed:
-1. Enter Configuration Mode
-2. Configure the Configuration Registers
-3. Exit Configuration Mode.
-
-Enter Configuration Mode
-To place the chip into the Configuration State The config key (0x55) is written
-to the CONFIG PORT (0x2E).
-
-Configuration Mode
-In configuration mode, the INDEX PORT is located at the CONFIG PORT address and
-the DATA PORT is at INDEX PORT address + 1.
-
-The desired configuration registers are accessed in two steps:
-a. Write the index of the Logical Device Number Configuration Register
- (i.e., 0x07) to the INDEX PORT and then write the number of the
- desired logical device to the DATA PORT.
-
-b. Write the address of the desired configuration register within the
- logical device to the INDEX PORT and then write or read the config-
- uration register through the DATA PORT.
-
-Note: If accessing the Global Configuration Registers, step (a) is not required.
-
-Exit Configuration Mode
-To exit the Configuration State the write 0xAA to the CONFIG PORT (0x2E).
-The chip returns to the RUN State. (This is important).
-
-Programming Example
-The following is an example of how to read the SIO Device ID located at 0x20
-
-; ENTER CONFIGURATION MODE
-MOV DX,02EH
-MOV AX,055H
-OUT DX,AL
-; GLOBAL CONFIGURATION REGISTER
-MOV DX,02EH
-MOV AL,20H
-OUT DX,AL
-; READ THE DATA
-MOV DX,02FH
-IN AL,DX
-; EXIT CONFIGURATION MODE
-MOV DX,02EH
-MOV AX,0AAH
-OUT DX,AL
-
-The registers of interest for identifying the SIO on the dc7100 are Device ID
-(0x20) and Device Rev (0x21).
-
-The Device ID will read 0X6F
-The Device Rev currently reads 0x01
-
-Obtaining the HWM Base Address.
-The following is an example of how to read the HWM Base Address located in
-Logical Device 8.
-
-; ENTER CONFIGURATION MODE
-MOV DX,02EH
-MOV AX,055H
-OUT DX,AL
-; CONFIGURE REGISTER CRE0,
-; LOGICAL DEVICE 8
-MOV DX,02EH
-MOV AL,07H
-OUT DX,AL ;Point to LD# Config Reg
-MOV DX,02FH
-MOV AL, 08H
-OUT DX,AL;Point to Logical Device 8
-;
-MOV DX,02EH
-MOV AL,60H
-OUT DX,AL ; Point to HWM Base Addr MSB
-MOV DX,02FH
-IN AL,DX ; Get MSB of HWM Base Addr
-; EXIT CONFIGURATION MODE
-MOV DX,02EH
-MOV AX,0AAH
-OUT DX,AL
--- /dev/null
+Kernel driver smsc47m1
+======================
+
+Supported chips:
+ * SMSC LPC47B27x, LPC47M10x, LPC47M13x, LPC47M14x, LPC47M15x and LPC47M192
+ Addresses scanned: none, address read from Super I/O config space
+ Prefix: 'smsc47m1'
+ Datasheets:
+ http://www.smsc.com/main/datasheets/47b27x.pdf
+ http://www.smsc.com/main/datasheets/47m10x.pdf
+ http://www.smsc.com/main/tools/discontinued/47m13x.pdf
+ http://www.smsc.com/main/datasheets/47m14x.pdf
+ http://www.smsc.com/main/tools/discontinued/47m15x.pdf
+ http://www.smsc.com/main/datasheets/47m192.pdf
+
+Authors:
+ Mark D. Studebaker <mdsxyz123@yahoo.com>,
+ With assistance from Bruce Allen <ballen@uwm.edu>, and his
+ fan.c program: http://www.lsc-group.phys.uwm.edu/%7Eballen/driver/
+ Gabriele Gorla <gorlik@yahoo.com>,
+ Jean Delvare <khali@linux-fr.org>
+
+Description
+-----------
+
+The Standard Microsystems Corporation (SMSC) 47M1xx Super I/O chips
+contain monitoring and PWM control circuitry for two fans.
+
+The 47M15x and 47M192 chips contain a full 'hardware monitoring block'
+in addition to the fan monitoring and control. The hardware monitoring
+block is not supported by the driver.
+
+Fan rotation speeds are reported in RPM (rotations per minute). An alarm is
+triggered if the rotation speed has dropped below a programmable limit. Fan
+readings can be divided by a programmable divider (1, 2, 4 or 8) to give
+the readings more range or accuracy. Not all RPM values can accurately be
+represented, so some rounding is done. With a divider of 2, the lowest
+representable value is around 2600 RPM.
+
+PWM values are from 0 to 255.
+
+If an alarm triggers, it will remain triggered until the hardware register
+is read at least once. This means that the cause for the alarm may
+already have disappeared! Note that in the current implementation, all
+hardware registers are read whenever any data is read (unless it is less
+than 1.5 seconds since the last update). This means that you can easily
+miss once-only alarms.
+
+
+**********************
+The lm_sensors project gratefully acknowledges the support of
+Intel in the development of this driver.
--- /dev/null
+Kernel driver via686a
+=====================
+
+Supported chips:
+ * Via VT82C686A, VT82C686B Southbridge Integrated Hardware Monitor
+ Prefix: 'via686a'
+ Addresses scanned: ISA in PCI-space encoded address
+ Datasheet: On request through web form (http://www.via.com.tw/en/support/datasheets/)
+
+Authors:
+ Kyösti Mälkki <kmalkki@cc.hut.fi>,
+ Mark D. Studebaker <mdsxyz123@yahoo.com>
+ Bob Dougherty <bobd@stanford.edu>
+ (Some conversion-factor data were contributed by
+ Jonathan Teh Soon Yew <j.teh@iname.com>
+ and Alex van Kaam <darkside@chello.nl>.)
+
+Module Parameters
+-----------------
+
+force_addr=0xaddr Set the I/O base address. Useful for Asus A7V boards
+ that don't set the address in the BIOS. Does not do a
+ PCI force; the via686a must still be present in lspci.
+ Don't use this unless the driver complains that the
+ base address is not set.
+ Example: 'modprobe via686a force_addr=0x6000'
+
+Description
+-----------
+
+The driver does not distinguish between the chips and reports
+all as a 686A.
+
+The Via 686a southbridge has integrated hardware monitor functionality.
+It also has an I2C bus, but this driver only supports the hardware monitor.
+For the I2C bus driver, see <file:Documentation/i2c/busses/i2c-viapro>
+
+The Via 686a implements three temperature sensors, two fan rotation speed
+sensors, five voltage sensors and alarms.
+
+Temperatures are measured in degrees Celsius. An alarm is triggered once
+when the Overtemperature Shutdown limit is crossed; it is triggered again
+as soon as it drops below the hysteresis value.
+
+Fan rotation speeds are reported in RPM (rotations per minute). An alarm is
+triggered if the rotation speed has dropped below a programmable limit. Fan
+readings can be divided by a programmable divider (1, 2, 4 or 8) to give
+the readings more range or accuracy. Not all RPM values can accurately be
+represented, so some rounding is done. With a divider of 2, the lowest
+representable value is around 2600 RPM.
+
+Voltage sensors (also known as IN sensors) report their values in volts.
+An alarm is triggered if the voltage has crossed a programmable minimum
+or maximum limit. Voltages are internally scalled, so each voltage channel
+has a different resolution and range.
+
+If an alarm triggers, it will remain triggered until the hardware register
+is read at least once. This means that the cause for the alarm may
+already have disappeared! Note that in the current implementation, all
+hardware registers are read whenever any data is read (unless it is less
+than 1.5 seconds since the last update). This means that you can easily
+miss once-only alarms.
+
+The driver only updates its values each 1.5 seconds; reading it more often
+will do no harm, but will return 'old' values.
--- /dev/null
+Kernel driver w83627hf
+======================
+
+Supported chips:
+ * Winbond W83627HF (ISA accesses ONLY)
+ Prefix: 'w83627hf'
+ Addresses scanned: ISA address retrieved from Super I/O registers
+ Datasheet: http://www.winbond.com/PDF/sheet/w83627hf.pdf
+ * Winbond W83627THF
+ Prefix: 'w83627thf'
+ Addresses scanned: ISA address retrieved from Super I/O registers
+ Datasheet: http://www.winbond.com/PDF/sheet/w83627thf.pdf
+ * Winbond W83697HF
+ Prefix: 'w83697hf'
+ Addresses scanned: ISA address retrieved from Super I/O registers
+ Datasheet: http://www.winbond.com/PDF/sheet/697hf.pdf
+ * Winbond W83637HF
+ Prefix: 'w83637hf'
+ Addresses scanned: ISA address retrieved from Super I/O registers
+ Datasheet: http://www.winbond.com/PDF/sheet/w83637hf.pdf
+
+Authors:
+ Frodo Looijaard <frodol@dds.nl>,
+ Philip Edelbrock <phil@netroedge.com>,
+ Mark Studebaker <mdsxyz123@yahoo.com>,
+ Bernhard C. Schrenk <clemy@clemy.org>
+
+Module Parameters
+-----------------
+
+* force_addr: int
+ Initialize the ISA address of the sensors
+* force_i2c: int
+ Initialize the I2C address of the sensors
+* init: int
+ (default is 1)
+ Use 'init=0' to bypass initializing the chip.
+ Try this if your computer crashes when you load the module.
+
+Description
+-----------
+
+This driver implements support for ISA accesses *only* for
+the Winbond W83627HF, W83627THF, W83697HF and W83637HF Super I/O chips.
+We will refer to them collectively as Winbond chips.
+
+This driver supports ISA accesses, which should be more reliable
+than i2c accesses. Also, for Tyan boards which contain both a
+Super I/O chip and a second i2c-only Winbond chip (often a W83782D),
+using this driver will avoid i2c address conflicts and complex
+initialization that were required in the w83781d driver.
+
+If you really want i2c accesses for these Super I/O chips,
+use the w83781d driver. However this is not the preferred method
+now that this ISA driver has been developed.
+
+Technically, the w83627thf does not support a VID reading. However, it's
+possible or even likely that your mainboard maker has routed these signals
+to a specific set of general purpose IO pins (the Asus P4C800-E is one such
+board). The w83627thf driver now interprets these as VID. If the VID on
+your board doesn't work, first see doc/vid in the lm_sensors package. If
+that still doesn't help, email us at lm-sensors@lm-sensors.org.
+
+For further information on this driver see the w83781d driver
+documentation.
+
--- /dev/null
+Kernel driver w83781d
+=====================
+
+Supported chips:
+ * Winbond W83781D
+ Prefix: 'w83781d'
+ Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports)
+ Datasheet: http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/w83781d.pdf
+ * Winbond W83782D
+ Prefix: 'w83782d'
+ Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports)
+ Datasheet: http://www.winbond.com/PDF/sheet/w83782d.pdf
+ * Winbond W83783S
+ Prefix: 'w83783s'
+ Addresses scanned: I2C 0x2d
+ Datasheet: http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/w83783s.pdf
+ * Winbond W83627HF
+ Prefix: 'w83627hf'
+ Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports)
+ Datasheet: http://www.winbond.com/PDF/sheet/w83627hf.pdf
+ * Asus AS99127F
+ Prefix: 'as99127f'
+ Addresses scanned: I2C 0x28 - 0x2f
+ Datasheet: Unavailable from Asus
+
+Authors:
+ Frodo Looijaard <frodol@dds.nl>,
+ Philip Edelbrock <phil@netroedge.com>,
+ Mark Studebaker <mdsxyz123@yahoo.com>
+
+Module parameters
+-----------------
+
+* init int
+ (default 1)
+ Use 'init=0' to bypass initializing the chip.
+ Try this if your computer crashes when you load the module.
+
+force_subclients=bus,caddr,saddr,saddr
+ This is used to force the i2c addresses for subclients of
+ a certain chip. Typical usage is `force_subclients=0,0x2d,0x4a,0x4b'
+ to force the subclients of chip 0x2d on bus 0 to i2c addresses
+ 0x4a and 0x4b. This parameter is useful for certain Tyan boards.
+
+Description
+-----------
+
+This driver implements support for the Winbond W83781D, W83782D, W83783S,
+W83627HF chips, and the Asus AS99127F chips. We will refer to them
+collectively as W8378* chips.
+
+There is quite some difference between these chips, but they are similar
+enough that it was sensible to put them together in one driver.
+The W83627HF chip is assumed to be identical to the ISA W83782D.
+The Asus chips are similar to an I2C-only W83782D.
+
+Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA
+as99127f 7 3 0 3 0x31 0x12c3 yes no
+as99127f rev.2 (type_name = as99127f) 0x31 0x5ca3 yes no
+w83781d 7 3 0 3 0x10-1 0x5ca3 yes yes
+w83627hf 9 3 2 3 0x21 0x5ca3 yes yes(LPC)
+w83782d 9 3 2-4 3 0x30 0x5ca3 yes yes
+w83783s 5-6 3 2 1-2 0x40 0x5ca3 yes no
+
+Detection of these chips can sometimes be foiled because they can be in
+an internal state that allows no clean access. If you know the address
+of the chip, use a 'force' parameter; this will put them into a more
+well-behaved state first.
+
+The W8378* implements temperature sensors (three on the W83781D and W83782D,
+two on the W83783S), three fan rotation speed sensors, voltage sensors
+(seven on the W83781D, nine on the W83782D and six on the W83783S), VID
+lines, alarms with beep warnings, and some miscellaneous stuff.
+
+Temperatures are measured in degrees Celsius. There is always one main
+temperature sensor, and one (W83783S) or two (W83781D and W83782D) other
+sensors. An alarm is triggered for the main sensor once when the
+Overtemperature Shutdown limit is crossed; it is triggered again as soon as
+it drops below the Hysteresis value. A more useful behavior
+can be found by setting the Hysteresis value to +127 degrees Celsius; in
+this case, alarms are issued during all the time when the actual temperature
+is above the Overtemperature Shutdown value. The driver sets the
+hysteresis value for temp1 to 127 at initialization.
+
+For the other temperature sensor(s), an alarm is triggered when the
+temperature gets higher then the Overtemperature Shutdown value; it stays
+on until the temperature falls below the Hysteresis value. But on the
+W83781D, there is only one alarm that functions for both other sensors!
+Temperatures are guaranteed within a range of -55 to +125 degrees. The
+main temperature sensors has a resolution of 1 degree; the other sensor(s)
+of 0.5 degree.
+
+Fan rotation speeds are reported in RPM (rotations per minute). An alarm is
+triggered if the rotation speed has dropped below a programmable limit. Fan
+readings can be divided by a programmable divider (1, 2, 4 or 8 for the
+W83781D; 1, 2, 4, 8, 16, 32, 64 or 128 for the others) to give
+the readings more range or accuracy. Not all RPM values can accurately
+be represented, so some rounding is done. With a divider of 2, the lowest
+representable value is around 2600 RPM.
+
+Voltage sensors (also known as IN sensors) report their values in volts.
+An alarm is triggered if the voltage has crossed a programmable minimum
+or maximum limit. Note that minimum in this case always means 'closest to
+zero'; this is important for negative voltage measurements. All voltage
+inputs can measure voltages between 0 and 4.08 volts, with a resolution
+of 0.016 volt.
+
+The VID lines encode the core voltage value: the voltage level your processor
+should work with. This is hardcoded by the mainboard and/or processor itself.
+It is a value in volts. When it is unconnected, you will often find the
+value 3.50 V here.
+
+The W83782D and W83783S temperature conversion machine understands about
+several kinds of temperature probes. You can program the so-called
+beta value in the sensor files. '1' is the PII/Celeron diode, '2' is the
+TN3904 transistor, and 3435 the default thermistor value. Other values
+are (not yet) supported.
+
+In addition to the alarms described above, there is a CHAS alarm on the
+chips which triggers if your computer case is open.
+
+When an alarm goes off, you can be warned by a beeping signal through
+your computer speaker. It is possible to enable all beeping globally,
+or only the beeping for some alarms.
+
+If an alarm triggers, it will remain triggered until the hardware register
+is read at least once. This means that the cause for the alarm may
+already have disappeared! Note that in the current implementation, all
+hardware registers are read whenever any data is read (unless it is less
+than 1.5 seconds since the last update). This means that you can easily
+miss once-only alarms.
+
+The chips only update values each 1.5 seconds; reading them more often
+will do no harm, but will return 'old' values.
+
+AS99127F PROBLEMS
+-----------------
+The as99127f support was developed without the benefit of a datasheet.
+In most cases it is treated as a w83781d (although revision 2 of the
+AS99127F looks more like a w83782d).
+This support will be BETA until a datasheet is released.
+One user has reported problems with fans stopping
+occasionally.
+
+Note that the individual beep bits are inverted from the other chips.
+The driver now takes care of this so that user-space applications
+don't have to know about it.
+
+Known problems:
+ - Problems with diode/thermistor settings (supported?)
+ - One user reports fans stopping under high server load.
+ - Revision 2 seems to have 2 PWM registers but we don't know
+ how to handle them. More details below.
+
+These will not be fixed unless we get a datasheet.
+If you have problems, please lobby Asus to release a datasheet.
+Unfortunately several others have without success.
+Please do not send mail to us asking for better as99127f support.
+We have done the best we can without a datasheet.
+Please do not send mail to the author or the sensors group asking for
+a datasheet or ideas on how to convince Asus. We can't help.
+
+
+NOTES:
+-----
+ 783s has no in1 so that in[2-6] are compatible with the 781d/782d.
+
+ 783s pin is programmable for -5V or temp1; defaults to -5V,
+ no control in driver so temp1 doesn't work.
+
+ 782d and 783s datasheets differ on which is pwm1 and which is pwm2.
+ We chose to follow 782d.
+
+ 782d and 783s pin is programmable for fan3 input or pwm2 output;
+ defaults to fan3 input.
+ If pwm2 is enabled (with echo 255 1 > pwm2), then
+ fan3 will report 0.
+
+ 782d has pwm1-2 for ISA, pwm1-4 for i2c. (pwm3-4 share pins with
+ the ISA pins)
+
+Data sheet updates:
+------------------
+ - PWM clock registers:
+
+ 000: master / 512
+ 001: master / 1024
+ 010: master / 2048
+ 011: master / 4096
+ 100: master / 8192
+
+
+Answers from Winbond tech support
+---------------------------------
+>
+> 1) In the W83781D data sheet section 7.2 last paragraph, it talks about
+> reprogramming the R-T table if the Beta of the thermistor is not
+> 3435K. The R-T table is described briefly in section 8.20.
+> What formulas do I use to program a new R-T table for a given Beta?
+>
+ We are sorry that the calculation for R-T table value is
+confidential. If you have another Beta value of thermistor, we can help
+to calculate the R-T table for you. But you should give us real R-T
+Table which can be gotten by thermistor vendor. Therefore we will calculate
+them and obtain 32-byte data, and you can fill the 32-byte data to the
+register in Bank0.CR51 of W83781D.
+
+
+> 2) In the W83782D data sheet, it mentions that pins 38, 39, and 40 are
+> programmable to be either thermistor or Pentium II diode inputs.
+> How do I program them for diode inputs? I can't find any register
+> to program these to be diode inputs.
+ --> You may program Bank0 CR[5Dh] and CR[59h] registers.
+
+ CR[5Dh] bit 1(VTIN1) bit 2(VTIN2) bit 3(VTIN3)
+
+ thermistor 0 0 0
+ diode 1 1 1
+
+
+(error) CR[59h] bit 4(VTIN1) bit 2(VTIN2) bit 3(VTIN3)
+(right) CR[59h] bit 4(VTIN1) bit 5(VTIN2) bit 6(VTIN3)
+
+ PII thermal diode 1 1 1
+ 2N3904 diode 0 0 0
+
+
+Asus Clones
+-----------
+
+We have no datasheets for the Asus clones (AS99127F and ASB100 Bach).
+Here are some very useful information that were given to us by Alex Van
+Kaam about how to detect these chips, and how to read their values. He
+also gives advice for another Asus chipset, the Mozart-2 (which we
+don't support yet). Thanks Alex!
+I reworded some parts and added personal comments.
+
+# Detection:
+
+AS99127F rev.1, AS99127F rev.2 and ASB100:
+- I2C address range: 0x29 - 0x2F
+- If register 0x58 holds 0x31 then we have an Asus (either ASB100 or
+ AS99127F)
+- Which one depends on register 0x4F (manufacturer ID):
+ 0x06 or 0x94: ASB100
+ 0x12 or 0xC3: AS99127F rev.1
+ 0x5C or 0xA3: AS99127F rev.2
+ Note that 0x5CA3 is Winbond's ID (WEC), which let us think Asus get their
+ AS99127F rev.2 direct from Winbond. The other codes mean ATT and DVC,
+ respectively. ATT could stand for Asustek something (although it would be
+ very badly chosen IMHO), I don't know what DVC could stand for. Maybe
+ these codes simply aren't meant to be decoded that way.
+
+Mozart-2:
+- I2C address: 0x77
+- If register 0x58 holds 0x56 or 0x10 then we have a Mozart-2
+- Of the Mozart there are 3 types:
+ 0x58=0x56, 0x4E=0x94, 0x4F=0x36: Asus ASM58 Mozart-2
+ 0x58=0x56, 0x4E=0x94, 0x4F=0x06: Asus AS2K129R Mozart-2
+ 0x58=0x10, 0x4E=0x5C, 0x4F=0xA3: Asus ??? Mozart-2
+ You can handle all 3 the exact same way :)
+
+# Temperature sensors:
+
+ASB100:
+- sensor 1: register 0x27
+- sensor 2 & 3 are the 2 LM75's on the SMBus
+- sensor 4: register 0x17
+Remark: I noticed that on Intel boards sensor 2 is used for the CPU
+ and 4 is ignored/stuck, on AMD boards sensor 4 is the CPU and sensor 2 is
+ either ignored or a socket temperature.
+
+AS99127F (rev.1 and 2 alike):
+- sensor 1: register 0x27
+- sensor 2 & 3 are the 2 LM75's on the SMBus
+Remark: Register 0x5b is suspected to be temperature type selector. Bit 1
+ would control temp1, bit 3 temp2 and bit 5 temp3.
+
+Mozart-2:
+- sensor 1: register 0x27
+- sensor 2: register 0x13
+
+# Fan sensors:
+
+ASB100, AS99127F (rev.1 and 2 alike):
+- 3 fans, identical to the W83781D
+
+Mozart-2:
+- 2 fans only, 1350000/RPM/div
+- fan 1: register 0x28, divisor on register 0xA1 (bits 4-5)
+- fan 2: register 0x29, divisor on register 0xA1 (bits 6-7)
+
+# Voltages:
+
+This is where there is a difference between AS99127F rev.1 and 2.
+Remark: The difference is similar to the difference between
+ W83781D and W83782D.
+
+ASB100:
+in0=r(0x20)*0.016
+in1=r(0x21)*0.016
+in2=r(0x22)*0.016
+in3=r(0x23)*0.016*1.68
+in4=r(0x24)*0.016*3.8
+in5=r(0x25)*(-0.016)*3.97
+in6=r(0x26)*(-0.016)*1.666
+
+AS99127F rev.1:
+in0=r(0x20)*0.016
+in1=r(0x21)*0.016
+in2=r(0x22)*0.016
+in3=r(0x23)*0.016*1.68
+in4=r(0x24)*0.016*3.8
+in5=r(0x25)*(-0.016)*3.97
+in6=r(0x26)*(-0.016)*1.503
+
+AS99127F rev.2:
+in0=r(0x20)*0.016
+in1=r(0x21)*0.016
+in2=r(0x22)*0.016
+in3=r(0x23)*0.016*1.68
+in4=r(0x24)*0.016*3.8
+in5=(r(0x25)*0.016-3.6)*5.14+3.6
+in6=(r(0x26)*0.016-3.6)*3.14+3.6
+
+Mozart-2:
+in0=r(0x20)*0.016
+in1=255
+in2=r(0x22)*0.016
+in3=r(0x23)*0.016*1.68
+in4=r(0x24)*0.016*4
+in5=255
+in6=255
+
+
+# PWM
+
+Additional info about PWM on the AS99127F (may apply to other Asus
+chips as well) by Jean Delvare as of 2004-04-09:
+
+AS99127F revision 2 seems to have two PWM registers at 0x59 and 0x5A,
+and a temperature sensor type selector at 0x5B (which basically means
+that they swapped registers 0x59 and 0x5B when you compare with Winbond
+chips).
+Revision 1 of the chip also has the temperature sensor type selector at
+0x5B, but PWM registers have no effect.
+
+We don't know exactly how the temperature sensor type selection works.
+Looks like bits 1-0 are for temp1, bits 3-2 for temp2 and bits 5-4 for
+temp3, although it is possible that only the most significant bit matters
+each time. So far, values other than 0 always broke the readings.
+
+PWM registers seem to be split in two parts: bit 7 is a mode selector,
+while the other bits seem to define a value or threshold.
+
+When bit 7 is clear, bits 6-0 seem to hold a threshold value. If the value
+is below a given limit, the fan runs at low speed. If the value is above
+the limit, the fan runs at full speed. We have no clue as to what the limit
+represents. Note that there seem to be some inertia in this mode, speed
+changes may need some time to trigger. Also, an hysteresis mechanism is
+suspected since walking through all the values increasingly and then
+decreasingly led to slightly different limits.
+
+When bit 7 is set, bits 3-0 seem to hold a threshold value, while bits 6-4
+would not be significant. If the value is below a given limit, the fan runs
+at full speed, while if it is above the limit it runs at low speed (so this
+is the contrary of the other mode, in a way). Here again, we don't know
+what the limit is supposed to represent.
+
+One remarkable thing is that the fans would only have two or three
+different speeds (transitional states left apart), not a whole range as
+you usually get with PWM.
+
+As a conclusion, you can write 0x00 or 0x8F to the PWM registers to make
+fans run at low speed, and 0x7F or 0x80 to make them run at full speed.
+
+Please contact us if you can figure out how it is supposed to work. As
+long as we don't know more, the w83781d driver doesn't handle PWM on
+AS99127F chips at all.
+
+Additional info about PWM on the AS99127F rev.1 by Hector Martin:
+
+I've been fiddling around with the (in)famous 0x59 register and
+found out the following values do work as a form of coarse pwm:
+
+0x80 - seems to turn fans off after some time(1-2 minutes)... might be
+some form of auto-fan-control based on temp? hmm (Qfan? this mobo is an
+old ASUS, it isn't marketed as Qfan. Maybe some beta pre-attemp at Qfan
+that was dropped at the BIOS)
+0x81 - off
+0x82 - slightly "on-ner" than off, but my fans do not get to move. I can
+hear the high-pitched PWM sound that motors give off at too-low-pwm.
+0x83 - now they do move. Estimate about 70% speed or so.
+0x84-0x8f - full on
+
+Changing the high nibble doesn't seem to do much except the high bit
+(0x80) must be set for PWM to work, else the current pwm doesn't seem to
+change.
+
+My mobo is an ASUS A7V266-E. This behavior is similar to what I got
+with speedfan under Windows, where 0-15% would be off, 15-2x% (can't
+remember the exact value) would be 70% and higher would be full on.
--- /dev/null
+Kernel driver w83l785ts
+=======================
+
+Supported chips:
+ * Winbond W83L785TS-S
+ Prefix: 'w83l785ts'
+ Addresses scanned: I2C 0x2e
+ Datasheet: Publicly available at the Winbond USA website
+ http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83L785TS-S.pdf
+
+Authors:
+ Jean Delvare <khali@linux-fr.org>
+
+Description
+-----------
+
+The W83L785TS-S is a digital temperature sensor. It senses the
+temperature of a single external diode. The high limit is
+theoretically defined as 85 or 100 degrees C through a combination
+of external resistors, so the user cannot change it. Values seen so
+far suggest that the two possible limits are actually 95 and 110
+degrees C. The datasheet is rather poor and obviously inaccurate
+on several points including this one.
+
+All temperature values are given in degrees Celsius. Resolution
+is 1.0 degree. See the datasheet for details.
+
+The w83l785ts driver will not update its values more frequently than
+every other second; reading them more often will do no harm, but will
+return 'old' values.
+
+Known Issues
+------------
+
+On some systems (Asus), the BIOS is known to interfere with the driver
+and cause read errors. The driver will retry a given number of times
+(5 by default) and then give up, returning the old value (or 0 if
+there is no old value). It seems to work well enough so that you should
+not notice anything. Thanks to James Bolt for helping test this feature.
Documentation/i2c/sysfs-interface for the individual files. Also
convert the units these files read and write to the specified ones.
If you need to add a new type of file, please discuss it on the
- sensors mailing list <sensors@stimpy.netroedge.com> by providing a
+ sensors mailing list <lm-sensors@lm-sensors.org> by providing a
patch to the Documentation/i2c/sysfs-interface file.
* [Attach] For I2C drivers, the attach function should make sure
--- /dev/null
+Introduction
+------------
+
+Most mainboards have sensor chips to monitor system health (like temperatures,
+voltages, fans speed). They are often connected through an I2C bus, but some
+are also connected directly through the ISA bus.
+
+The kernel drivers make the data from the sensor chips available in the /sys
+virtual filesystem. Userspace tools are then used to display or set or the
+data in a more friendly manner.
+
+Lm-sensors
+----------
+
+Core set of utilites that will allow you to obtain health information,
+setup monitoring limits etc. You can get them on their homepage
+http://www.lm-sensors.nu/ or as a package from your Linux distribution.
+
+If from website:
+Get lmsensors from project web site. Please note, you need only userspace
+part, so compile with "make user_install" target.
+
+General hints to get things working:
+
+0) get lm-sensors userspace utils
+1) compile all drivers in I2C section as modules in your kernel
+2) run sensors-detect script, it will tell you what modules you need to load.
+3) load them and run "sensors" command, you should see some results.
+4) fix sensors.conf, labels, limits, fan divisors
+5) if any more problems consult FAQ, or documentation
+
+Other utilites
+--------------
+
+If you want some graphical indicators of system health look for applications
+like: gkrellm, ksensors, xsensors, wmtemp, wmsensors, wmgtemp, ksysguardd,
+hardware-monitor
+
+If you are server administrator you can try snmpd or mrtgutils.
normal_i2c: filled in by the module writer.
A list of I2C addresses which should normally be examined.
- normal_i2c_range: filled in by the module writer.
- A list of pairs of I2C addresses, each pair being an inclusive range of
- addresses which should normally be examined.
probe: insmod parameter.
A list of pairs. The first value is a bus number (-1 for any I2C bus),
the second is the address. These addresses are also probed, as if they
were in the 'normal' list.
- probe_range: insmod parameter.
- A list of triples. The first value is a bus number (-1 for any I2C bus),
- the second and third are addresses. These form an inclusive range of
- addresses that are also probed, as if they were in the 'normal' list.
ignore: insmod parameter.
A list of pairs. The first value is a bus number (-1 for any I2C bus),
the second is the I2C address. These addresses are never probed.
This parameter overrules 'normal' and 'probe', but not the 'force' lists.
- ignore_range: insmod parameter.
- A list of triples. The first value is a bus number (-1 for any I2C bus),
- the second and third are addresses. These form an inclusive range of
- I2C addresses that are never probed.
- This parameter overrules 'normal' and 'probe', but not the 'force' lists.
force: insmod parameter.
A list of pairs. The first value is a bus number (-1 for any I2C bus),
the second is the I2C address. A device is blindly assumed to be on
the given address, no probing is done.
-Fortunately, as a module writer, you just have to define the `normal'
-and/or `normal_range' parameters. The complete declaration could look
-like this:
+Fortunately, as a module writer, you just have to define the `normal_i2c'
+parameter. The complete declaration could look like this:
- /* Scan 0x20 to 0x2f, 0x37, and 0x40 to 0x4f */
- static unsigned short normal_i2c[] = { 0x37,I2C_CLIENT_END };
- static unsigned short normal_i2c_range[] = { 0x20, 0x2f, 0x40, 0x4f,
- I2C_CLIENT_END };
+ /* Scan 0x37, and 0x48 to 0x4f */
+ static unsigned short normal_i2c[] = { 0x37, 0x48, 0x49, 0x4a, 0x4b, 0x4c,
+ 0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
/* Magic definition of all other variables and things */
I2C_CLIENT_INSMOD;
-Note that you *have* to call the two defined variables `normal_i2c' and
-`normal_i2c_range', without any prefix!
+Note that you *have* to call the defined variable `normal_i2c',
+without any prefix!
Probing classes (sensors)
normal_i2c: filled in by the module writer. Terminated by SENSORS_I2C_END.
A list of I2C addresses which should normally be examined.
- normal_i2c_range: filled in by the module writer. Terminated by
- SENSORS_I2C_END
- A list of pairs of I2C addresses, each pair being an inclusive range of
- addresses which should normally be examined.
normal_isa: filled in by the module writer. Terminated by SENSORS_ISA_END.
A list of ISA addresses which should normally be examined.
- normal_isa_range: filled in by the module writer. Terminated by
- SENSORS_ISA_END
- A list of triples. The first two elements are ISA addresses, being an
- range of addresses which should normally be examined. The third is the
- modulo parameter: only addresses which are 0 module this value relative
- to the first address of the range are actually considered.
probe: insmod parameter. Initialize this list with SENSORS_I2C_END values.
A list of pairs. The first value is a bus number (SENSORS_ISA_BUS for
the ISA bus, -1 for any I2C bus), the second is the address. These
addresses are also probed, as if they were in the 'normal' list.
- probe_range: insmod parameter. Initialize this list with SENSORS_I2C_END
- values.
- A list of triples. The first value is a bus number (SENSORS_ISA_BUS for
- the ISA bus, -1 for any I2C bus), the second and third are addresses.
- These form an inclusive range of addresses that are also probed, as
- if they were in the 'normal' list.
ignore: insmod parameter. Initialize this list with SENSORS_I2C_END values.
A list of pairs. The first value is a bus number (SENSORS_ISA_BUS for
the ISA bus, -1 for any I2C bus), the second is the I2C address. These
addresses are never probed. This parameter overrules 'normal' and
'probe', but not the 'force' lists.
- ignore_range: insmod parameter. Initialize this list with SENSORS_I2C_END
- values.
- A list of triples. The first value is a bus number (SENSORS_ISA_BUS for
- the ISA bus, -1 for any I2C bus), the second and third are addresses.
- These form an inclusive range of I2C addresses that are never probed.
- This parameter overrules 'normal' and 'probe', but not the 'force' lists.
Also used is a list of pointers to sensors_force_data structures:
force_data: insmod parameters. A list, ending with an element of which
So we have a generic insmod variabled `force', and chip-specific variables
`force_CHIPNAME'.
-Fortunately, as a module writer, you just have to define the `normal'
-and/or `normal_range' parameters, and define what chip names are used.
+Fortunately, as a module writer, you just have to define the `normal_i2c'
+and `normal_isa' parameters, and define what chip names are used.
The complete declaration could look like this:
- /* Scan i2c addresses 0x20 to 0x2f, 0x37, and 0x40 to 0x4f
- static unsigned short normal_i2c[] = {0x37,SENSORS_I2C_END};
- static unsigned short normal_i2c_range[] = {0x20,0x2f,0x40,0x4f,
- SENSORS_I2C_END};
+ /* Scan i2c addresses 0x37, and 0x48 to 0x4f */
+ static unsigned short normal_i2c[] = { 0x37, 0x48, 0x49, 0x4a, 0x4b, 0x4c,
+ 0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
/* Scan ISA address 0x290 */
static unsigned int normal_isa[] = {0x0290,SENSORS_ISA_END};
- static unsigned int normal_isa_range[] = {SENSORS_ISA_END};
/* Define chips foo and bar, as well as all module parameters and things */
SENSORS_INSMOD_2(foo,bar);
device numbers (0xabcd or abcd, for 2.4 backward compatibility).
You can use the 'all' keyword to ignore all devices.
The '!' operator will cause the I/O-layer to _not_ ignore a device.
- The order on the command line is not important.
+ The command line is parsed from left to right.
For example,
cio_ignore=0.0.0023-0.0.0042,0.0.4711
/proc/cio_ignore; "add <device range>, <device range>, ..." will ignore the
specified devices.
- Note: Already known devices cannot be ignored.
+ Note: While already known devices can be added to the list of devices to be
+ ignored, there will be no effect on then. However, if such a device
+ disappears and then reappeares, it will then be ignored.
- For example, if device 0.0.abcd is already known and all other devices
- 0.0.a000-0.0.afff are not known,
+ For example,
"echo add 0.0.a000-0.0.accc, 0.0.af00-0.0.afff > /proc/cio_ignore"
- will add 0.0.a000-0.0.abcc, 0.0.abce-0.0.accc and 0.0.af00-0.0.afff to the
- list of ignored devices and skip 0.0.abcd.
+ will add 0.0.a000-0.0.accc and 0.0.af00-0.0.afff to the list of ignored
+ devices.
The devices can be specified either by bus id (0.0.abcd) or, for 2.4 backward
compatibilty, by the device number in hexadecimal (0xabcd or abcd).
- /proc/s390dbf/cio_trace/hex_ascii
Logs the calling of functions in the common I/O-layer and, if applicable,
- which subchannel they were called for.
+ which subchannel they were called for, as well as dumps of some data
+ structures (like irb in an error case).
The level of logging can be changed to be more or less verbose by piping to
/proc/s390dbf/cio_*/level a number between 0 and 6; see the documentation on
--- /dev/null
+The SGI IOC4 PCI device is a bit of a strange beast, so some notes on
+it are in order.
+
+First, even though the IOC4 performs multiple functions, such as an
+IDE controller, a serial controller, a PS/2 keyboard/mouse controller,
+and an external interrupt mechanism, it's not implemented as a
+multifunction device. The consequence of this from a software
+standpoint is that all these functions share a single IRQ, and
+they can't all register to own the same PCI device ID. To make
+matters a bit worse, some of the register blocks (and even registers
+themselves) present in IOC4 are mixed-purpose between these several
+functions, meaning that there's no clear "owning" device driver.
+
+The solution is to organize the IOC4 driver into several independent
+drivers, "ioc4", "sgiioc4", and "ioc4_serial". Note that there is no
+PS/2 controller driver as this functionality has never been wired up
+on a shipping IO card.
+
+ioc4
+====
+This is the core (or shim) driver for IOC4. It is responsible for
+initializing the basic functionality of the chip, and allocating
+the PCI resources that are shared between the IOC4 functions.
+
+This driver also provides registration functions that the other
+IOC4 drivers can call to make their presence known. Each driver
+needs to provide a probe and remove function, which are invoked
+by the core driver at appropriate times. The interface of these
+IOC4 function probe and remove operations isn't precisely the same
+as PCI device probe and remove operations, but is logically the
+same operation.
+
+sgiioc4
+=======
+This is the IDE driver for IOC4. Its name isn't very descriptive
+simply for historical reasons (it used to be the only IOC4 driver
+component). There's not much to say about it other than it hooks
+up to the ioc4 driver via the appropriate registration, probe, and
+remove functions.
+
+ioc4_serial
+===========
+This is the serial driver for IOC4. There's not much to say about it
+other than it hooks up to the ioc4 driver via the appropriate registration,
+probe, and remove functions.
Module snd-hda-intel
--------------------
- Module for Intel HD Audio (ICH6, ICH6M, ICH7)
+ Module for Intel HD Audio (ICH6, ICH6M, ICH7), ATI SB450,
+ VIA VT8251/VT8237A
model - force the model name
+ position_fix - Fix DMA pointer (0 = FIFO size, 1 = none, 2 = POSBUF)
Module supports up to 8 cards.
5stack 5-jack in back, 2-jack in front
5stack-digout 5-jack in back, 2-jack in front, a SPDIF out
w810 3-jack
+ z71v 3-jack (HP shared SPDIF)
+ asus 3-jack
+ uniwill 3-jack
+ F1734 2-jack
CMI9880
minimal 3-jack in back
full 6-jack in back, 2-jack in front
full_dig 6-jack in back, 2-jack in front, SPDIF I/O
allout 5-jack in back, 2-jack in front, SPDIF out
+ auto auto-config reading BIOS (default)
+
+ Note 2: If you get click noises on output, try the module option
+ position_fix=1 or 2. position_fix=1 will use the SD_LPIB
+ register value without FIFO size correction as the current
+ DMA pointer. position_fix=2 will make the driver to use
+ the position buffer instead of reading SD_LPIB register.
+ (Usually SD_LPLIB register is more accurate than the
+ position buffer.)
Module snd-hdsp
---------------
module did formerly. It will allocate the buffers in advance
when any HDSP cards are found. To make the buffer
allocation sure, load snd-page-alloc module in the early
- stage of boot sequence.
+ stage of boot sequence. See "Early Buffer Allocation"
+ section.
+
+ Module snd-hdspm
+ ----------------
+
+ Module for RME HDSP MADI board.
+
+ precise_ptr - Enable precise pointer, or disable.
+ line_outs_monitor - Send playback streams to analog outs by default.
+ enable_monitor - Enable Analog Out on Channel 63/64 by default.
+
+ See hdspm.txt for details.
Module snd-ice1712
------------------
* TerraTec EWS 88D
* TerraTec EWX 24/96
* TerraTec DMX 6Fire
+ * TerraTec Phase 88
* Hoontech SoundTrack DSP 24
* Hoontech SoundTrack DSP 24 Value
* Hoontech SoundTrack DSP 24 Media 7.1
+ * Event Electronics, EZ8
* Digigram VX442
+ * Lionstracs, Mediastaton
model - Use the given board model, one of the following:
delta1010, dio2496, delta66, delta44, audiophile, delta410,
delta1010lt, vx442, ewx2496, ews88mt, ews88mt_new, ews88d,
- dmx6fire, dsp24, dsp24_value, dsp24_71, ez8
+ dmx6fire, dsp24, dsp24_value, dsp24_71, ez8,
+ phase88, mediastation
omni - Omni I/O support for MidiMan M-Audio Delta44/66
cs8427_timeout - reset timeout for the CS8427 chip (S/PDIF transciever)
in msec resolution, default value is 500 (0.5 sec)
is not used with all Envy24 based cards (for example in the MidiMan Delta
serie).
+ Note: The supported board is detected by reading EEPROM or PCI
+ SSID (if EEPROM isn't available). You can override the
+ model by passing "model" module option in case that the
+ driver isn't configured properly or you want to try another
+ type for testing.
+
Module snd-ice1724
------------------
- Module for Envy24HT (VT/ICE1724) based PCI sound cards.
+ Module for Envy24HT (VT/ICE1724), Envy24PT (VT1720) based PCI sound cards.
* MidiMan M Audio Revolution 7.1
* AMP Ltd AUDIO2000
- * TerraTec Aureon Sky-5.1, Space-7.1
+ * TerraTec Aureon 5.1 Sky
+ * TerraTec Aureon 7.1 Space
+ * TerraTec Aureon 7.1 Universe
+ * TerraTec Phase 22
+ * TerraTec Phase 28
+ * AudioTrak Prodigy 7.1
+ * AudioTrak Prodigy 192
+ * Pontis MS300
+ * Albatron K8X800 Pro II
+ * Chaintech ZNF3-150
+ * Chaintech ZNF3-250
+ * Chaintech 9CJS
+ * Chaintech AV-710
+ * Shuttle SN25P
model - Use the given board model, one of the following:
- revo71, amp2000, prodigy71, aureon51, aureon71,
- k8x800
+ revo71, amp2000, prodigy71, prodigy192, aureon51,
+ aureon71, universe, k8x800, phase22, phase28, ms300,
+ av710
Module supports up to 8 cards and autoprobe.
+ Note: The supported board is detected by reading EEPROM or PCI
+ SSID (if EEPROM isn't available). You can override the
+ model by passing "model" module option in case that the
+ driver isn't configured properly or you want to try another
+ type for testing.
+
Module snd-intel8x0
-------------------
module did formerly. It will allocate the buffers in advance
when any RME9652 cards are found. To make the buffer
allocation sure, load snd-page-alloc module in the early
- stage of boot sequence.
+ stage of boot sequence. See "Early Buffer Allocation"
+ section.
Module snd-sa11xx-uda1341 (on arm only)
---------------------------------------
------------------
Module for AC'97 motherboards based on VIA 82C686A/686B, 8233,
- 8233A, 8233C, 8235 (south) bridge.
+ 8233A, 8233C, 8235, 8237 (south) bridge.
mpu_port - 0x300,0x310,0x320,0x330, otherwise obtain BIOS setup
[VIA686A/686B only]
joystick - Enable joystick (default off) [VIA686A/686B only]
ac97_clock - AC'97 codec clock base (default 48000Hz)
dxs_support - support DXS channels,
- 0 = auto (defalut), 1 = enable, 2 = disable,
- 3 = 48k only, 4 = no VRA
- [VIA8233/C,8235 only]
+ 0 = auto (default), 1 = enable, 2 = disable,
+ 3 = 48k only, 4 = no VRA, 5 = enable any sample
+ rate and different sample rates on different
+ channels
+ [VIA8233/C, 8235, 8237 only]
ac97_quirk - AC'97 workaround for strange hardware
See the description of intel8x0 module for details.
default value 1.4. Then the interrupt number will be
assigned under 15. You might also upgrade your BIOS.
- Note: VIA8233/5 (not VIA8233A) can support DXS (direct sound)
+ Note: VIA8233/5/7 (not VIA8233A) can support DXS (direct sound)
channels as the first PCM. On these channels, up to 4
- streams can be played at the same time.
+ streams can be played at the same time, and the controller
+ can perform sample rate conversion with separate rates for
+ each channel.
As default (dxs_support = 0), 48k fixed rate is chosen
except for the known devices since the output is often
noisy except for 48k on some mother boards due to the
bug of BIOS.
- Please try once dxs_support=1 and if it works on other
+ Please try once dxs_support=5 and if it works on other
sample rates (e.g. 44.1kHz of mp3 playback), please let us
know the PCI subsystem vendor/device id's (output of
"lspci -nv").
- If it doesn't work, try dxs_support=4. If it still doesn't
+ If dxs_support=5 does not work, try dxs_support=4; if it
+ doesn't work too, try dxs_support=1. (dxs_support=1 is
+ usually for old motherboards. The correct implementated
+ board should work with 4 or 5.) If it still doesn't
work and the default setting is ok, dxs_support=3 is the
right choice. If the default setting doesn't work at all,
try dxs_support=2 to disable the DXS channels.
echo "rvplayer 0 0 block" > /proc/asound/card0/pcm0p/oss
+Early Buffer Allocation
+=======================
+
+Some drivers (e.g. hdsp) require the large contiguous buffers, and
+sometimes it's too late to find such spaces when the driver module is
+actually loaded due to memory fragmentation. You can pre-allocate the
+PCM buffers by loading snd-page-alloc module and write commands to its
+proc file in prior, for example, in the early boot stage like
+/etc/init.d/*.local scripts.
+
+Reading the proc file /proc/drivers/snd-page-alloc shows the current
+usage of page allocation. In writing, you can send the following
+commands to the snd-page-alloc driver:
+
+ - add VENDOR DEVICE MASK SIZE BUFFERS
+
+ VENDOR and DEVICE are PCI vendor and device IDs. They take
+ integer numbers (0x prefix is needed for the hex).
+ MASK is the PCI DMA mask. Pass 0 if not restricted.
+ SIZE is the size of each buffer to allocate. You can pass
+ k and m suffix for KB and MB. The max number is 16MB.
+ BUFFERS is the number of buffers to allocate. It must be greater
+ than 0. The max number is 4.
+
+ - erase
+
+ This will erase the all pre-allocated buffers which are not in
+ use.
+
+
Links
=====
There are some control switchs affecting to the speaker connections:
-"Line-In As Rear" - As mentioned above, the line-in jack is used
- for the rear (3th and 4th channels) output.
-"Line-In As Bass" - The line-in jack is used for the bass (5th
- and 6th channels) output.
-"Mic As Center/LFE" - The mic jack is used for the bass output.
- If this switch is on, you cannot use a microphone as a capture
- source, of course.
-
+"Line-In Mode" - an enum control to change the behavior of line-in
+ jack. Either "Line-In", "Rear Output" or "Bass Output" can
+ be selected. The last item is available only with model 039
+ or newer.
+ When "Rear Output" is chosen, the surround channels 3 and 4
+ are output to line-in jack.
+"Mic-In Mode" - an enum control to change the behavior of mic-in
+ jack. Either "Mic-In" or "Center/LFE Output" can be
+ selected.
+ When "Center/LFE Output" is chosen, the center and bass
+ channels (channels 5 and 6) are output to mic-in jack.
Digital I/O
-----------
-The CM8x38 provides the excellent SPDIF capability with very chip
+The CM8x38 provides the excellent SPDIF capability with very cheap
price (yes, that's the reason I bought the card :)
The SPDIF playback and capture are done via the third PCM device
simultaneously.
To enable SPDIF output, you need to turn on "IEC958 Output Switch"
-control via mixer or alsactl. Then you'll see the red light on from
-the card so you know that's working obviously :)
+control via mixer or alsactl ("IEC958" is the official name of
+so-called S/PDIF). Then you'll see the red light on from the card so
+you know that's working obviously :)
The SPDIF input is always enabled, so you can hear SPDIF input data
from line-out with "IEC958 In Monitor" switch at any time (see
below).
MIDI CONTROLLER
---------------
-The MPU401-UART interface is enabled as default only for the first
-(CMIPCI) card. You need to set module option "midi_port" properly
-for the 2nd (CMIPCI) card.
+The MPU401-UART interface is disabled as default. You need to set
+module option "mpu_port" with a valid I/O port address to enable the
+MIDI support. The valid I/O ports are 0x300, 0x310, 0x320 and 0x330.
+Choose the value which doesn't conflict with other cards.
There is _no_ hardware wavetable function on this chip (except for
OPL3 synth below).
Joystick and Modem
------------------
-The joystick and modem should be available by enabling the control
-switch "Joystick" and "Modem" respectively. But I myself have never
-tested them yet.
+The legacy joystick is supported. To enable the joystick support, pass
+joystick_port=1 module option. The value 1 means the auto-detection.
+If the auto-detection fails, try to pass the exact I/O address.
+
+The modem is enabled dynamically via a card control switch "Modem".
Debugging Information
<listitem><para>create <function>probe()</function> callback.</para></listitem>
<listitem><para>create <function>remove()</function> callback.</para></listitem>
<listitem><para>create pci_driver table which contains the three pointers above.</para></listitem>
- <listitem><para>create <function>init()</function> function just calling <function>pci_module_init()</function> to register the pci_driver table defined above.</para></listitem>
+ <listitem><para>create <function>init()</function> function just calling <function>pci_register_driver()</function> to register the pci_driver table defined above.</para></listitem>
<listitem><para>create <function>exit()</function> function to call <function>pci_unregister_driver()</function> function.</para></listitem>
</itemizedlist>
</para>
/* initialization of the module */
static int __init alsa_card_mychip_init(void)
{
- return pci_module_init(&driver);
+ return pci_register_driver(&driver);
}
/* clean up the module */
<![CDATA[
static int __init alsa_card_mychip_init(void)
{
- return pci_module_init(&driver);
+ return pci_register_driver(&driver);
}
static void __exit alsa_card_mychip_exit(void)
--- /dev/null
+This document is a guide to using the emu10k1 based devices with JACK for low
+latency, multichannel recording functionality. All of my recent work to allow
+Linux users to use the full capabilities of their hardware has been inspired
+by the kX Project. Without their work I never would have discovered the true
+power of this hardware.
+
+ http://www.kxproject.com
+ - Lee Revell, 2005.03.30
+
+Low latency, multichannel audio with JACK and the emu10k1/emu10k2
+-----------------------------------------------------------------
+
+Until recently, emu10k1 users on Linux did not have access to the same low
+latency, multichannel features offered by the "kX ASIO" feature of their
+Windows driver. As of ALSA 1.0.9 this is no more!
+
+For those unfamiliar with kX ASIO, this consists of 16 capture and 16 playback
+channels. With a post 2.6.9 Linux kernel, latencies down to 64 (1.33 ms) or
+even 32 (0.66ms) frames should work well.
+
+The configuration is slightly more involved than on Windows, as you have to
+select the correct device for JACK to use. Actually, for qjackctl users it's
+fairly self explanatory - select Duplex, then for capture and playback select
+the multichannel devices, set the in and out channels to 16, and the sample
+rate to 48000Hz. The command line looks like this:
+
+/usr/local/bin/jackd -R -dalsa -r48000 -p64 -n2 -D -Chw:0,2 -Phw:0,3 -S
+
+This will give you 16 input ports and 16 output ports.
+
+The 16 output ports map onto the 16 FX buses (or the first 16 of 64, for the
+Audigy). The mapping from FX bus to physical output is described in
+SB-Live-mixer.txt (or Audigy-mixer.txt).
+
+The 16 input ports are connected to the 16 physical inputs. Contrary to
+popular belief, all emu10k1 cards are multichannel cards. Which of these
+input channels have physical inputs connected to them depends on the card
+model. Trial and error is highly recommended; the pinout diagrams
+for the card have been reverse engineered by some enterprising kX users and are
+available on the internet. Meterbridge is helpful here, and the kX forums are
+packed with useful information.
+
+Each input port will either correspond to a digital (SPDIF) input, an analog
+input, or nothing. The one exception is the SBLive! 5.1. On these devices,
+the second and third input ports are wired to the center/LFE output. You will
+still see 16 capture channels, but only 14 are available for recording inputs.
+
+This chart, borrowed from kxfxlib/da_asio51.cpp, describes the mapping of JACK
+ports to FXBUS2 (multitrack recording input) and EXTOUT (physical output)
+channels.
+
+/*JACK (& ASIO) mappings on 10k1 5.1 SBLive cards:
+--------------------------------------------
+JACK Epilog FXBUS2(nr)
+--------------------------------------------
+capture_1 asio14 FXBUS2(0xe)
+capture_2 asio15 FXBUS2(0xf)
+capture_3 asio0 FXBUS2(0x0)
+~capture_4 Center EXTOUT(0x11) // mapped to by Center
+~capture_5 LFE EXTOUT(0x12) // mapped to by LFE
+capture_6 asio3 FXBUS2(0x3)
+capture_7 asio4 FXBUS2(0x4)
+capture_8 asio5 FXBUS2(0x5)
+capture_9 asio6 FXBUS2(0x6)
+capture_10 asio7 FXBUS2(0x7)
+capture_11 asio8 FXBUS2(0x8)
+capture_12 asio9 FXBUS2(0x9)
+capture_13 asio10 FXBUS2(0xa)
+capture_14 asio11 FXBUS2(0xb)
+capture_15 asio12 FXBUS2(0xc)
+capture_16 asio13 FXBUS2(0xd)
+*/
+
+TODO: describe use of ld10k1/qlo10k1 in conjunction with JACK
--- /dev/null
+Software Interface ALSA-DSP MADI Driver
+
+(translated from German, so no good English ;-),
+2004 - winfried ritsch
+
+
+
+ Full functionality has been added to the driver. Since some of
+ the Controls and startup-options are ALSA-Standard and only the
+ special Controls are described and discussed below.
+
+
+ hardware functionality:
+
+
+ Audio transmission:
+
+ number of channels -- depends on transmission mode
+
+ The number of channels chosen is from 1..Nmax. The reason to
+ use for a lower number of channels is only resource allocation,
+ since unused DMA channels are disabled and less memory is
+ allocated. So also the throughput of the PCI system can be
+ scaled. (Only important for low performance boards).
+
+ Single Speed -- 1..64 channels
+
+ (Note: Choosing the 56channel mode for transmission or as
+ receiver, only 56 are transmitted/received over the MADI, but
+ all 64 channels are available for the mixer, so channel count
+ for the driver)
+
+ Double Speed -- 1..32 channels
+
+ Note: Choosing the 56-channel mode for
+ transmission/receive-mode , only 28 are transmitted/received
+ over the MADI, but all 32 channels are available for the mixer,
+ so channel count for the driver
+
+
+ Quad Speed -- 1..16 channels
+
+ Note: Choosing the 56-channel mode for
+ transmission/receive-mode , only 14 are transmitted/received
+ over the MADI, but all 16 channels are available for the mixer,
+ so channel count for the driver
+
+ Format -- signed 32 Bit Little Endian (SNDRV_PCM_FMTBIT_S32_LE)
+
+ Sample Rates --
+
+ Single Speed -- 32000, 44100, 48000
+
+ Double Speed -- 64000, 88200, 96000 (untested)
+
+ Quad Speed -- 128000, 176400, 192000 (untested)
+
+ access-mode -- MMAP (memory mapped), Not interleaved
+ (PCM_NON-INTERLEAVED)
+
+ buffer-sizes -- 64,128,256,512,1024,2048,8192 Samples
+
+ fragments -- 2
+
+ Hardware-pointer -- 2 Modi
+
+
+ The Card supports the readout of the actual Buffer-pointer,
+ where DMA reads/writes. Since of the bulk mode of PCI it is only
+ 64 Byte accurate. SO it is not really usable for the
+ ALSA-mid-level functions (here the buffer-ID gives a better
+ result), but if MMAP is used by the application. Therefore it
+ can be configured at load-time with the parameter
+ precise-pointer.
+
+
+ (Hint: Experimenting I found that the pointer is maximum 64 to
+ large never to small. So if you subtract 64 you always have a
+ safe pointer for writing, which is used on this mode inside
+ ALSA. In theory now you can get now a latency as low as 16
+ Samples, which is a quarter of the interrupt possibilities.)
+
+ Precise Pointer -- off
+ interrupt used for pointer-calculation
+
+ Precise Pointer -- on
+ hardware pointer used.
+
+ Controller:
+
+
+ Since DSP-MADI-Mixer has 8152 Fader, it does not make sense to
+ use the standard mixer-controls, since this would break most of
+ (especially graphic) ALSA-Mixer GUIs. So Mixer control has be
+ provided by a 2-dimensional controller using the
+ hwdep-interface.
+
+ Also all 128+256 Peak and RMS-Meter can be accessed via the
+ hwdep-interface. Since it could be a performance problem always
+ copying and converting Peak and RMS-Levels even if you just need
+ one, I decided to export the hardware structure, so that of
+ needed some driver-guru can implement a memory-mapping of mixer
+ or peak-meters over ioctl, or also to do only copying and no
+ conversion. A test-application shows the usage of the controller.
+
+ Latency Controls --- not implemented !!!
+
+
+ Note: Within the windows-driver the latency is accessible of a
+ control-panel, but buffer-sizes are controlled with ALSA from
+ hwparams-calls and should not be changed in run-state, I did not
+ implement it here.
+
+
+ System Clock -- suspended !!!!
+
+ Name -- "System Clock Mode"
+
+ Access -- Read Write
+
+ Values -- "Master" "Slave"
+
+
+ !!!! This is a hardware-function but is in conflict with the
+ Clock-source controller, which is a kind of ALSA-standard. I
+ makes sense to set the card to a special mode (master at some
+ frequency or slave), since even not using an Audio-application
+ a studio should have working synchronisations setup. So use
+ Clock-source-controller instead !!!!
+
+ Clock Source
+
+ Name -- "Sample Clock Source"
+
+ Access -- Read Write
+
+ Values -- "AutoSync", "Internal 32.0 kHz", "Internal 44.1 kHz",
+ "Internal 48.0 kHz", "Internal 64.0 kHz", "Internal 88.2 kHz",
+ "Internal 96.0 kHz"
+
+ Choose between Master at a specific Frequency and so also the
+ Speed-mode or Slave (Autosync). Also see "Preferred Sync Ref"
+
+
+ !!!! This is no pure hardware function but was implemented by
+ ALSA by some ALSA-drivers before, so I use it also. !!!
+
+
+ Preferred Sync Ref
+
+ Name -- "Preferred Sync Reference"
+
+ Access -- Read Write
+
+ Values -- "Word" "MADI"
+
+
+ Within the Auto-sync-Mode the preferred Sync Source can be
+ chosen. If it is not available another is used if possible.
+
+ Note: Since MADI has a much higher bit-rate than word-clock, the
+ card should synchronise better in MADI Mode. But since the
+ RME-PLL is very good, there are almost no problems with
+ word-clock too. I never found a difference.
+
+
+ TX 64 channel ---
+
+ Name -- "TX 64 channels mode"
+
+ Access -- Read Write
+
+ Values -- 0 1
+
+ Using 64-channel-modus (1) or 56-channel-modus for
+ MADI-transmission (0).
+
+
+ Note: This control is for output only. Input-mode is detected
+ automatically from hardware sending MADI.
+
+
+ Clear TMS ---
+
+ Name -- "Clear Track Marker"
+
+ Access -- Read Write
+
+ Values -- 0 1
+
+
+ Don't use to lower 5 Audio-bits on AES as additional Bits.
+
+
+ Safe Mode oder Auto Input ---
+
+ Name -- "Safe Mode"
+
+ Access -- Read Write
+
+ Values -- 0 1
+
+ (default on)
+
+ If on (1), then if either the optical or coaxial connection
+ has a failure, there is a takeover to the working one, with no
+ sample failure. Its only useful if you use the second as a
+ backup connection.
+
+ Input ---
+
+ Name -- "Input Select"
+
+ Access -- Read Write
+
+ Values -- optical coaxial
+
+
+ Choosing the Input, optical or coaxial. If Safe-mode is active,
+ this is the preferred Input.
+
+-------------- Mixer ----------------------
+
+ Mixer
+
+ Name -- "Mixer"
+
+ Access -- Read Write
+
+ Values - <channel-number 0-127> <Value 0-65535>
+
+
+ Here as a first value the channel-index is taken to get/set the
+ corresponding mixer channel, where 0-63 are the input to output
+ fader and 64-127 the playback to outputs fader. Value 0
+ is channel muted 0 and 32768 an amplification of 1.
+
+ Chn 1-64
+
+ fast mixer for the ALSA-mixer utils. The diagonal of the
+ mixer-matrix is implemented from playback to output.
+
+
+ Line Out
+
+ Name -- "Line Out"
+
+ Access -- Read Write
+
+ Values -- 0 1
+
+ Switching on and off the analog out, which has nothing to do
+ with mixing or routing. the analog outs reflects channel 63,64.
+
+
+--- information (only read access):
+
+ Sample Rate
+
+ Name -- "System Sample Rate"
+
+ Access -- Read-only
+
+ getting the sample rate.
+
+
+ External Rate measured
+
+ Name -- "External Rate"
+
+ Access -- Read only
+
+
+ Should be "Autosync Rate", but Name used is
+ ALSA-Scheme. External Sample frequency liked used on Autosync is
+ reported.
+
+
+ MADI Sync Status
+
+ Name -- "MADI Sync Lock Status"
+
+ Access -- Read
+
+ Values -- 0,1,2
+
+ MADI-Input is 0=Unlocked, 1=Locked, or 2=Synced.
+
+
+ Word Clock Sync Status
+
+ Name -- "Word Clock Lock Status"
+
+ Access -- Read
+
+ Values -- 0,1,2
+
+ Word Clock Input is 0=Unlocked, 1=Locked, or 2=Synced.
+
+ AutoSync
+
+ Name -- "AutoSync Reference"
+
+ Access -- Read
+
+ Values -- "WordClock", "MADI", "None"
+
+ Sync-Reference is either "WordClock", "MADI" or none.
+
+ RX 64ch --- noch nicht implementiert
+
+ MADI-Receiver is in 64 channel mode oder 56 channel mode.
+
+
+ AB_inp --- not tested
+
+ Used input for Auto-Input.
+
+
+ actual Buffer Position --- not implemented
+
+ !!! this is a ALSA internal function, so no control is used !!!
+
+
+
+Calling Parameter:
+
+ index int array (min = 1, max = 8),
+ "Index value for RME HDSPM interface." card-index within ALSA
+
+ note: ALSA-standard
+
+ id string array (min = 1, max = 8),
+ "ID string for RME HDSPM interface."
+
+ note: ALSA-standard
+
+ enable int array (min = 1, max = 8),
+ "Enable/disable specific HDSPM sound-cards."
+
+ note: ALSA-standard
+
+ precise_ptr int array (min = 1, max = 8),
+ "Enable precise pointer, or disable."
+
+ note: Use only when the application supports this (which is a special case).
+
+ line_outs_monitor int array (min = 1, max = 8),
+ "Send playback streams to analog outs by default."
+
+
+ note: each playback channel is mixed to the same numbered output
+ channel (routed). This is against the ALSA-convention, where all
+ channels have to be muted on after loading the driver, but was
+ used before on other cards, so i historically use it again)
+
+
+
+ enable_monitor int array (min = 1, max = 8),
+ "Enable Analog Out on Channel 63/64 by default."
+
+ note: here the analog output is enabled (but not routed).
\ No newline at end of file
-Any w1 device must be connected to w1 bus master device - for example
-ds9490 usb device or w1-over-GPIO or RS232 converter.
-Driver for w1 bus master must provide several functions(you can find
-them in struct w1_bus_master definition in w1.h) which then will be
-called by w1 core to send various commands over w1 bus(by default it is
-reset and search commands). When some device is found on the bus, w1 core
-checks if driver for it's family is loaded.
-If driver is loaded w1 core creates new w1_slave object and registers it
-in the system(creates some generic sysfs files(struct w1_family_ops in
-w1_family.h), notifies any registered listener and so on...).
-It is device driver's business to provide any communication method
-upstream.
-For example w1_therm driver(ds18?20 thermal sensor family driver)
-provides temperature reading function which is bound to ->rbin() method
-of the above w1_family_ops structure.
-w1_smem - driver for simple 64bit memory cell provides ID reading
-method.
+The 1-wire (w1) subsystem
+------------------------------------------------------------------
+The 1-wire bus is a simple master-slave bus that communicates via a single
+signal wire (plus ground, so two wires).
+
+Devices communicate on the bus by pulling the signal to ground via an open
+drain output and by sampling the logic level of the signal line.
+
+The w1 subsystem provides the framework for managing w1 masters and
+communication with slaves.
+
+All w1 slave devices must be connected to a w1 bus master device.
+
+Example w1 master devices:
+ DS9490 usb device
+ W1-over-GPIO
+ DS2482 (i2c to w1 bridge)
+ Emulated devices, such as a RS232 converter, parallel port adapter, etc
+
+
+What does the w1 subsystem do?
+------------------------------------------------------------------
+When a w1 master driver registers with the w1 subsystem, the following occurs:
+
+ - sysfs entries for that w1 master are created
+ - the w1 bus is periodically searched for new slave devices
+
+When a device is found on the bus, w1 core checks if driver for it's family is
+loaded. If so, the family driver is attached to the slave.
+If there is no driver for the family, a simple sysfs entry is created
+for the slave device.
+
+
+W1 device families
+------------------------------------------------------------------
+Slave devices are handled by a driver written for a family of w1 devices.
+
+A family driver populates a struct w1_family_ops (see w1_family.h) and
+registers with the w1 subsystem.
+
+Current family drivers:
+w1_therm - (ds18?20 thermal sensor family driver)
+ provides temperature reading function which is bound to ->rbin() method
+ of the above w1_family_ops structure.
+
+w1_smem - driver for simple 64bit memory cell provides ID reading method.
You can call above methods by reading appropriate sysfs files.
+
+
+What does a w1 master driver need to implement?
+------------------------------------------------------------------
+
+The driver for w1 bus master must provide at minimum two functions.
+
+Emulated devices must provide the ability to set the output signal level
+(write_bit) and sample the signal level (read_bit).
+
+Devices that support the 1-wire natively must provide the ability to write and
+sample a bit (touch_bit) and reset the bus (reset_bus).
+
+Most hardware provides higher-level functions that offload w1 handling.
+See struct w1_bus_master definition in w1.h for details.
+
+
+w1 master sysfs interface
+------------------------------------------------------------------
+<xx-xxxxxxxxxxxxx> - a directory for a found device. The format is family-serial
+bus - (standard) symlink to the w1 bus
+driver - (standard) symlink to the w1 driver
+w1_master_attempts - the number of times a search was attempted
+w1_master_max_slave_count
+ - the maximum slaves that may be attached to a master
+w1_master_name - the name of the device (w1_bus_masterX)
+w1_master_search - the number of searches left to do, -1=continual (default)
+w1_master_slave_count
+ - the number of slaves found
+w1_master_slaves - the names of the slaves, one per line
+w1_master_timeout - the delay in seconds between searches
+
+If you have a w1 bus that never changes (you don't add or remove devices),
+you can set w1_master_search to a positive value to disable searches.
+
+
+w1 slave sysfs interface
+------------------------------------------------------------------
+bus - (standard) symlink to the w1 bus
+driver - (standard) symlink to the w1 driver
+name - the device name, usually the same as the directory name
+w1_slave - (optional) a binary file whose meaning depends on the
+ family driver
+
ADM1025 HARDWARE MONITOR DRIVER
P: Jean Delvare
M: khali@linux-fr.org
-L: sensors@stimpy.netroedge.com
+L: lm-sensors@lm-sensors.org
S: Maintained
ADT746X FAN DRIVER
ALI1563 I2C DRIVER
P: Rudolf Marek
M: r.marek@sh.cvut.cz
-L: sensors@stimpy.netroedge.com
+L: lm-sensors@lm-sensors.org
S: Maintained
ALPHA PORT
M: acme@conectiva.com.br
S: Maintained
+ARC FRAMEBUFFER DRIVER
+P: Jaya Kumar
+M: jayalk@intworks.biz
+S: Maintained
+
ARM26 ARCHITECTURE
P: Ian Molton
M: spyro@f2s.com
M: greg@kroah.com
P: Jean Delvare
M: khali@linux-fr.org
-L: sensors@stimpy.netroedge.com
+L: lm-sensors@lm-sensors.org
W: http://www.lm-sensors.nu/
S: Maintained
LM83 HARDWARE MONITOR DRIVER
P: Jean Delvare
M: khali@linux-fr.org
-L: sensors@stimpy.netroedge.com
+L: lm-sensors@lm-sensors.org
S: Maintained
LM90 HARDWARE MONITOR DRIVER
P: Jean Delvare
M: khali@linux-fr.org
-L: sensors@stimpy.netroedge.com
+L: lm-sensors@lm-sensors.org
S: Maintained
LOGICAL DISK MANAGER SUPPORT (LDM, Windows 2000/XP Dynamic Disks)
SMSC47M1 HARDWARE MONITOR DRIVER
P: Jean Delvare
M: khali@linux-fr.org
-L: sensors@stimpy.netroedge.com
+L: lm-sensors@lm-sensors.org
S: Odd Fixes
SMB FILESYSTEM
W1 DALLAS'S 1-WIRE BUS
P: Evgeniy Polyakov
M: johnpol@2ka.mipt.ru
-L: sensors@stimpy.netroedge.com
+L: lm-sensors@lm-sensors.org
S: Maintained
W83L51xD SD/MMC CARD INTERFACE DRIVER
W83L785TS HARDWARE MONITOR DRIVER
P: Jean Delvare
M: khali@linux-fr.org
-L: sensors@stimpy.netroedge.com
+L: lm-sensors@lm-sensors.org
S: Odd Fixes
WAN ROUTER & SANGOMA WANPIPE DRIVERS & API (X.25, FRAME RELAY, PPP, CISCO HDLC)
(!vma || addr + len <= vma->vm_start))
return addr;
}
- start_addr = addr = mm->free_area_cache;
+ if (len > mm->cached_hole_size) {
+ start_addr = addr = mm->free_area_cache;
+ } else {
+ start_addr = addr = TASK_UNMAPPED_BASE;
+ mm->cached_hole_size = 0;
+ }
full_search:
if (do_align)
*/
if (start_addr != TASK_UNMAPPED_BASE) {
start_addr = addr = TASK_UNMAPPED_BASE;
+ mm->cached_hole_size = 0;
goto full_search;
}
return -ENOMEM;
mm->free_area_cache = addr + len;
return addr;
}
+ if (addr + mm->cached_hole_size < vma->vm_start)
+ mm->cached_hole_size = vma->vm_start - addr;
addr = vma->vm_end;
if (do_align)
addr = COLOUR_ALIGN(addr, pgoff);
struct page *page = &mem_map[pfn];
ClearPageReserved(page);
- set_bit(PG_highmem, &page->flags);
set_page_count(page, 1);
__free_page(page);
totalram_pages++;
$(obj)/zImage $(obj)/bzImage: $(obj)/bootsect $(obj)/setup \
$(obj)/vmlinux.bin $(obj)/tools/build FORCE
$(call if_changed,image)
- @echo 'Kernel: $@ is ready'
+ @echo 'Kernel: $@ is ready' ' (#'`cat .version`')'
$(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE
$(call if_changed,objcopy)
.long sys_io_submit
.long sys_io_cancel
.long sys_fadvise64 /* 250 */
- .long sys_ni_syscall
+ .long sys_set_zone_reclaim
.long sys_exit_group
.long sys_lookup_dcookie
.long sys_epoll_create
};
static int die_counter;
- if (die.lock_owner != _smp_processor_id()) {
+ if (die.lock_owner != raw_smp_processor_id()) {
console_verbose();
spin_lock_irq(&die.lock);
die.lock_owner = smp_processor_id();
xloops *= 4;
__asm__("mull %0"
:"=d" (xloops), "=&a" (d0)
- :"1" (xloops),"0" (cpu_data[_smp_processor_id()].loops_per_jiffy * (HZ/4)));
+ :"1" (xloops),"0" (cpu_data[raw_smp_processor_id()].loops_per_jiffy * (HZ/4)));
__delay(++xloops);
}
#include <asm/tlb.h>
#include <asm/tlbflush.h>
-static pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr)
+pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr)
{
pgd_t *pgd;
pud_t *pud;
return (pte_t *) pmd;
}
-static pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
+pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
{
pgd_t *pgd;
pud_t *pud;
return (pte_t *) pmd;
}
-static void set_huge_pte(struct mm_struct *mm, struct vm_area_struct *vma, struct page *page, pte_t * page_table, int write_access)
-{
- pte_t entry;
-
- add_mm_counter(mm, rss, HPAGE_SIZE / PAGE_SIZE);
- if (write_access) {
- entry =
- pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
- } else
- entry = pte_wrprotect(mk_pte(page, vma->vm_page_prot));
- entry = pte_mkyoung(entry);
- mk_pte_huge(entry);
- set_pte(page_table, entry);
-}
-
/*
* This function checks for proper alignment of input addr and len parameters.
*/
return 0;
}
-int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
- struct vm_area_struct *vma)
-{
- pte_t *src_pte, *dst_pte, entry;
- struct page *ptepage;
- unsigned long addr = vma->vm_start;
- unsigned long end = vma->vm_end;
-
- while (addr < end) {
- dst_pte = huge_pte_alloc(dst, addr);
- if (!dst_pte)
- goto nomem;
- src_pte = huge_pte_offset(src, addr);
- entry = *src_pte;
- ptepage = pte_page(entry);
- get_page(ptepage);
- set_pte(dst_pte, entry);
- add_mm_counter(dst, rss, HPAGE_SIZE / PAGE_SIZE);
- addr += HPAGE_SIZE;
- }
- return 0;
-
-nomem:
- return -ENOMEM;
-}
-
-int
-follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma,
- struct page **pages, struct vm_area_struct **vmas,
- unsigned long *position, int *length, int i)
-{
- unsigned long vpfn, vaddr = *position;
- int remainder = *length;
-
- WARN_ON(!is_vm_hugetlb_page(vma));
-
- vpfn = vaddr/PAGE_SIZE;
- while (vaddr < vma->vm_end && remainder) {
-
- if (pages) {
- pte_t *pte;
- struct page *page;
-
- pte = huge_pte_offset(mm, vaddr);
-
- /* hugetlb should be locked, and hence, prefaulted */
- WARN_ON(!pte || pte_none(*pte));
-
- page = &pte_page(*pte)[vpfn % (HPAGE_SIZE/PAGE_SIZE)];
-
- WARN_ON(!PageCompound(page));
-
- get_page(page);
- pages[i] = page;
- }
-
- if (vmas)
- vmas[i] = vma;
-
- vaddr += PAGE_SIZE;
- ++vpfn;
- --remainder;
- ++i;
- }
-
- *length = remainder;
- *position = vaddr;
-
- return i;
-}
-
#if 0 /* This is just for testing */
struct page *
follow_huge_addr(struct mm_struct *mm, unsigned long address, int write)
}
#endif
-void unmap_hugepage_range(struct vm_area_struct *vma,
- unsigned long start, unsigned long end)
+void hugetlb_clean_stale_pgtable(pte_t *pte)
{
- struct mm_struct *mm = vma->vm_mm;
- unsigned long address;
- pte_t pte, *ptep;
+ pmd_t *pmd = (pmd_t *) pte;
struct page *page;
- BUG_ON(start & (HPAGE_SIZE - 1));
- BUG_ON(end & (HPAGE_SIZE - 1));
-
- for (address = start; address < end; address += HPAGE_SIZE) {
- ptep = huge_pte_offset(mm, address);
- if (!ptep)
- continue;
- pte = ptep_get_and_clear(mm, address, ptep);
- if (pte_none(pte))
- continue;
- page = pte_page(pte);
- put_page(page);
- }
- add_mm_counter(mm ,rss, -((end - start) >> PAGE_SHIFT));
- flush_tlb_range(vma, start, end);
-}
-
-int hugetlb_prefault(struct address_space *mapping, struct vm_area_struct *vma)
-{
- struct mm_struct *mm = current->mm;
- unsigned long addr;
- int ret = 0;
-
- BUG_ON(vma->vm_start & ~HPAGE_MASK);
- BUG_ON(vma->vm_end & ~HPAGE_MASK);
-
- spin_lock(&mm->page_table_lock);
- for (addr = vma->vm_start; addr < vma->vm_end; addr += HPAGE_SIZE) {
- unsigned long idx;
- pte_t *pte = huge_pte_alloc(mm, addr);
- struct page *page;
-
- if (!pte) {
- ret = -ENOMEM;
- goto out;
- }
-
- if (!pte_none(*pte))
- continue;
-
- idx = ((addr - vma->vm_start) >> HPAGE_SHIFT)
- + (vma->vm_pgoff >> (HPAGE_SHIFT - PAGE_SHIFT));
- page = find_get_page(mapping, idx);
- if (!page) {
- /* charge the fs quota first */
- if (hugetlb_get_quota(mapping)) {
- ret = -ENOMEM;
- goto out;
- }
- page = alloc_huge_page();
- if (!page) {
- hugetlb_put_quota(mapping);
- ret = -ENOMEM;
- goto out;
- }
- ret = add_to_page_cache(page, mapping, idx, GFP_ATOMIC);
- if (! ret) {
- unlock_page(page);
- } else {
- hugetlb_put_quota(mapping);
- free_huge_page(page);
- goto out;
- }
- }
- set_huge_pte(mm, vma, page, pte, vma->vm_flags & VM_WRITE);
- }
-out:
- spin_unlock(&mm->page_table_lock);
- return ret;
+ page = pmd_page(*pmd);
+ pmd_clear(pmd);
+ dec_page_state(nr_page_table_pages);
+ page_cache_release(page);
}
/* x86_64 also uses this file */
struct vm_area_struct *vma;
unsigned long start_addr;
- start_addr = mm->free_area_cache;
+ if (len > mm->cached_hole_size) {
+ start_addr = mm->free_area_cache;
+ } else {
+ start_addr = TASK_UNMAPPED_BASE;
+ mm->cached_hole_size = 0;
+ }
full_search:
addr = ALIGN(start_addr, HPAGE_SIZE);
*/
if (start_addr != TASK_UNMAPPED_BASE) {
start_addr = TASK_UNMAPPED_BASE;
+ mm->cached_hole_size = 0;
goto full_search;
}
return -ENOMEM;
mm->free_area_cache = addr + len;
return addr;
}
+ if (addr + mm->cached_hole_size < vma->vm_start)
+ mm->cached_hole_size = vma->vm_start - addr;
addr = ALIGN(vma->vm_end, HPAGE_SIZE);
}
}
struct mm_struct *mm = current->mm;
struct vm_area_struct *vma, *prev_vma;
unsigned long base = mm->mmap_base, addr = addr0;
+ unsigned long largest_hole = mm->cached_hole_size;
int first_time = 1;
/* don't allow allocations above current base */
if (mm->free_area_cache > base)
mm->free_area_cache = base;
+ if (len <= largest_hole) {
+ largest_hole = 0;
+ mm->free_area_cache = base;
+ }
try_again:
/* make sure it can fit in the remaining address space */
if (mm->free_area_cache < len)
* vma->vm_start, use it:
*/
if (addr + len <= vma->vm_start &&
- (!prev_vma || (addr >= prev_vma->vm_end)))
+ (!prev_vma || (addr >= prev_vma->vm_end))) {
/* remember the address as a hint for next time */
- return (mm->free_area_cache = addr);
- else
+ mm->cached_hole_size = largest_hole;
+ return (mm->free_area_cache = addr);
+ } else {
/* pull free_area_cache down to the first hole */
- if (mm->free_area_cache == vma->vm_end)
+ if (mm->free_area_cache == vma->vm_end) {
mm->free_area_cache = vma->vm_start;
+ mm->cached_hole_size = largest_hole;
+ }
+ }
+
+ /* remember the largest hole we saw so far */
+ if (addr + largest_hole < vma->vm_start)
+ largest_hole = vma->vm_start - addr;
/* try just below the current vma->vm_start */
addr = (vma->vm_start - len) & HPAGE_MASK;
*/
if (first_time) {
mm->free_area_cache = base;
+ largest_hole = 0;
first_time = 0;
goto try_again;
}
* allocations.
*/
mm->free_area_cache = TASK_UNMAPPED_BASE;
+ mm->cached_hole_size = ~0UL;
addr = hugetlb_get_unmapped_area_bottomup(file, addr0,
len, pgoff, flags);
* Restore the topdown base:
*/
mm->free_area_cache = base;
+ mm->cached_hole_size = ~0UL;
return addr;
}
{
if (page_is_ram(pfn) && !(bad_ppro && page_kills_ppro(pfn))) {
ClearPageReserved(page);
- set_bit(PG_highmem, &page->flags);
set_page_count(page, 1);
__free_page(page);
totalhigh_pages++;
bool
default y
+config IA64_UNCACHED_ALLOCATOR
+ bool
+ select GENERIC_ALLOCATOR
+
choice
prompt "System type"
default IA64_GENERIC
config IA64_SGI_SN_XP
tristate "Support communication between SGI SSIs"
- depends on MSPEC
+ select IA64_UNCACHED_ALLOCATOR
help
An SGI machine can be divided into multiple Single System
Images which act independently of each other and have
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_SERIAL_SGI_L1_CONSOLE=y
+CONFIG_SERIAL_SGI_IOC4=y
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
CONFIG_INFINIBAND_IPOIB=m
# CONFIG_INFINIBAND_IPOIB_DEBUG is not set
+#
+# SN Devices
+#
+CONFIG_SGI_IOC4=y
+
#
# File systems
#
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_SERIAL_SGI_L1_CONSOLE=y
+CONFIG_SERIAL_SGI_IOC4=y
# CONFIG_SERIAL_JSM is not set
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_INFINIBAND_IPOIB=m
# CONFIG_INFINIBAND_IPOIB_DEBUG is not set
+#
+# SN Devices
+#
+CONFIG_SGI_IOC4=y
+
#
# File systems
#
obj-$(CONFIG_PERFMON) += perfmon_default_smpl.o
obj-$(CONFIG_IA64_CYCLONE) += cyclone.o
obj-$(CONFIG_IA64_MCA_RECOVERY) += mca_recovery.o
+obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR) += uncached.o
mca_recovery-y += mca_drv.o mca_drv_asm.o
# The gate DSO image is built using a special linker script.
}
}
+/*
+ * Walk the EFI memory map to pull out leftover pages in the lower
+ * memory regions which do not end up in the regular memory map and
+ * stick them into the uncached allocator
+ *
+ * The regular walk function is significantly more complex than the
+ * uncached walk which means it really doesn't make sense to try and
+ * marge the two.
+ */
+void __init
+efi_memmap_walk_uc (efi_freemem_callback_t callback)
+{
+ void *efi_map_start, *efi_map_end, *p;
+ efi_memory_desc_t *md;
+ u64 efi_desc_size, start, end;
+
+ efi_map_start = __va(ia64_boot_param->efi_memmap);
+ efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size;
+ efi_desc_size = ia64_boot_param->efi_memdesc_size;
+
+ for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
+ md = p;
+ if (md->attribute == EFI_MEMORY_UC) {
+ start = PAGE_ALIGN(md->phys_addr);
+ end = PAGE_ALIGN((md->phys_addr+(md->num_pages << EFI_PAGE_SHIFT)) & PAGE_MASK);
+ if ((*callback)(start, end, NULL) < 0)
+ return;
+ }
+ }
+}
+
+
/*
* Look for the PAL_CODE region reported by EFI and maps it using an
* ITR to enable safe PAL calls in virtual mode. See IA-64 Processor
data8 sys_keyctl
data8 sys_ni_syscall
data8 sys_ni_syscall // 1275
- data8 sys_ni_syscall
+ data8 sys_set_zone_reclaim
data8 sys_ni_syscall
data8 sys_ni_syscall
data8 sys_ni_syscall
--- /dev/null
+/*
+ * Copyright (C) 2001-2005 Silicon Graphics, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * A simple uncached page allocator using the generic allocator. This
+ * allocator first utilizes the spare (spill) pages found in the EFI
+ * memmap and will then start converting cached pages to uncached ones
+ * at a granule at a time. Node awareness is implemented by having a
+ * pool of pages per node.
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/efi.h>
+#include <linux/genalloc.h>
+#include <asm/page.h>
+#include <asm/pal.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/atomic.h>
+#include <asm/tlbflush.h>
+#include <asm/sn/arch.h>
+
+#define DEBUG 0
+
+#if DEBUG
+#define dprintk printk
+#else
+#define dprintk(x...) do { } while (0)
+#endif
+
+void __init efi_memmap_walk_uc (efi_freemem_callback_t callback);
+
+#define MAX_UNCACHED_GRANULES 5
+static int allocated_granules;
+
+struct gen_pool *uncached_pool[MAX_NUMNODES];
+
+
+static void uncached_ipi_visibility(void *data)
+{
+ int status;
+
+ status = ia64_pal_prefetch_visibility(PAL_VISIBILITY_PHYSICAL);
+ if ((status != PAL_VISIBILITY_OK) &&
+ (status != PAL_VISIBILITY_OK_REMOTE_NEEDED))
+ printk(KERN_DEBUG "pal_prefetch_visibility() returns %i on "
+ "CPU %i\n", status, get_cpu());
+}
+
+
+static void uncached_ipi_mc_drain(void *data)
+{
+ int status;
+ status = ia64_pal_mc_drain();
+ if (status)
+ printk(KERN_WARNING "ia64_pal_mc_drain() failed with %i on "
+ "CPU %i\n", status, get_cpu());
+}
+
+
+static unsigned long
+uncached_get_new_chunk(struct gen_pool *poolp)
+{
+ struct page *page;
+ void *tmp;
+ int status, i;
+ unsigned long addr, node;
+
+ if (allocated_granules >= MAX_UNCACHED_GRANULES)
+ return 0;
+
+ node = poolp->private;
+ page = alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO,
+ IA64_GRANULE_SHIFT-PAGE_SHIFT);
+
+ dprintk(KERN_INFO "get_new_chunk page %p, addr %lx\n",
+ page, (unsigned long)(page-vmem_map) << PAGE_SHIFT);
+
+ /*
+ * Do magic if no mem on local node! XXX
+ */
+ if (!page)
+ return 0;
+ tmp = page_address(page);
+
+ /*
+ * There's a small race here where it's possible for someone to
+ * access the page through /dev/mem halfway through the conversion
+ * to uncached - not sure it's really worth bothering about
+ */
+ for (i = 0; i < (IA64_GRANULE_SIZE / PAGE_SIZE); i++)
+ SetPageUncached(&page[i]);
+
+ flush_tlb_kernel_range(tmp, tmp + IA64_GRANULE_SIZE);
+
+ status = ia64_pal_prefetch_visibility(PAL_VISIBILITY_PHYSICAL);
+
+ dprintk(KERN_INFO "pal_prefetch_visibility() returns %i on cpu %i\n",
+ status, get_cpu());
+
+ if (!status) {
+ status = smp_call_function(uncached_ipi_visibility, NULL, 0, 1);
+ if (status)
+ printk(KERN_WARNING "smp_call_function failed for "
+ "uncached_ipi_visibility! (%i)\n", status);
+ }
+
+ if (ia64_platform_is("sn2"))
+ sn_flush_all_caches((unsigned long)tmp, IA64_GRANULE_SIZE);
+ else
+ flush_icache_range((unsigned long)tmp,
+ (unsigned long)tmp+IA64_GRANULE_SIZE);
+
+ ia64_pal_mc_drain();
+ status = smp_call_function(uncached_ipi_mc_drain, NULL, 0, 1);
+ if (status)
+ printk(KERN_WARNING "smp_call_function failed for "
+ "uncached_ipi_mc_drain! (%i)\n", status);
+
+ addr = (unsigned long)tmp - PAGE_OFFSET + __IA64_UNCACHED_OFFSET;
+
+ allocated_granules++;
+ return addr;
+}
+
+
+/*
+ * uncached_alloc_page
+ *
+ * Allocate 1 uncached page. Allocates on the requested node. If no
+ * uncached pages are available on the requested node, roundrobin starting
+ * with higher nodes.
+ */
+unsigned long
+uncached_alloc_page(int nid)
+{
+ unsigned long maddr;
+
+ maddr = gen_pool_alloc(uncached_pool[nid], PAGE_SIZE);
+
+ dprintk(KERN_DEBUG "uncached_alloc_page returns %lx on node %i\n",
+ maddr, nid);
+
+ /*
+ * If no memory is availble on our local node, try the
+ * remaining nodes in the system.
+ */
+ if (!maddr) {
+ int i;
+
+ for (i = MAX_NUMNODES - 1; i >= 0; i--) {
+ if (i == nid || !node_online(i))
+ continue;
+ maddr = gen_pool_alloc(uncached_pool[i], PAGE_SIZE);
+ dprintk(KERN_DEBUG "uncached_alloc_page alternate search "
+ "returns %lx on node %i\n", maddr, i);
+ if (maddr) {
+ break;
+ }
+ }
+ }
+
+ return maddr;
+}
+EXPORT_SYMBOL(uncached_alloc_page);
+
+
+/*
+ * uncached_free_page
+ *
+ * Free a single uncached page.
+ */
+void
+uncached_free_page(unsigned long maddr)
+{
+ int node;
+
+ node = nasid_to_cnodeid(NASID_GET(maddr));
+
+ dprintk(KERN_DEBUG "uncached_free_page(%lx) on node %i\n", maddr, node);
+
+ if ((maddr & (0XFUL << 60)) != __IA64_UNCACHED_OFFSET)
+ panic("uncached_free_page invalid address %lx\n", maddr);
+
+ gen_pool_free(uncached_pool[node], maddr, PAGE_SIZE);
+}
+EXPORT_SYMBOL(uncached_free_page);
+
+
+/*
+ * uncached_build_memmap,
+ *
+ * Called at boot time to build a map of pages that can be used for
+ * memory special operations.
+ */
+static int __init
+uncached_build_memmap(unsigned long start, unsigned long end, void *arg)
+{
+ long length;
+ unsigned long vstart, vend;
+ int node;
+
+ length = end - start;
+ vstart = start + __IA64_UNCACHED_OFFSET;
+ vend = end + __IA64_UNCACHED_OFFSET;
+
+ dprintk(KERN_ERR "uncached_build_memmap(%lx %lx)\n", start, end);
+
+ memset((char *)vstart, 0, length);
+
+ node = nasid_to_cnodeid(NASID_GET(start));
+
+ for (; vstart < vend ; vstart += PAGE_SIZE) {
+ dprintk(KERN_INFO "sticking %lx into the pool!\n", vstart);
+ gen_pool_free(uncached_pool[node], vstart, PAGE_SIZE);
+ }
+
+ return 0;
+}
+
+
+static int __init uncached_init(void) {
+ int i;
+
+ for (i = 0; i < MAX_NUMNODES; i++) {
+ if (!node_online(i))
+ continue;
+ uncached_pool[i] = gen_pool_create(0, IA64_GRANULE_SHIFT,
+ &uncached_get_new_chunk, i);
+ }
+
+ efi_memmap_walk_uc(uncached_build_memmap);
+
+ return 0;
+}
+
+__initcall(uncached_init);
unsigned int hpage_shift=HPAGE_SHIFT_DEFAULT;
-static pte_t *
+pte_t *
huge_pte_alloc (struct mm_struct *mm, unsigned long addr)
{
unsigned long taddr = htlbpage_to_page(addr);
return pte;
}
-static pte_t *
+pte_t *
huge_pte_offset (struct mm_struct *mm, unsigned long addr)
{
unsigned long taddr = htlbpage_to_page(addr);
#define mk_pte_huge(entry) { pte_val(entry) |= _PAGE_P; }
-static void
-set_huge_pte (struct mm_struct *mm, struct vm_area_struct *vma,
- struct page *page, pte_t * page_table, int write_access)
-{
- pte_t entry;
-
- add_mm_counter(mm, rss, HPAGE_SIZE / PAGE_SIZE);
- if (write_access) {
- entry =
- pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
- } else
- entry = pte_wrprotect(mk_pte(page, vma->vm_page_prot));
- entry = pte_mkyoung(entry);
- mk_pte_huge(entry);
- set_pte(page_table, entry);
- return;
-}
/*
* This function checks for proper alignment of input addr and len parameters.
*/
return 0;
}
-int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
- struct vm_area_struct *vma)
-{
- pte_t *src_pte, *dst_pte, entry;
- struct page *ptepage;
- unsigned long addr = vma->vm_start;
- unsigned long end = vma->vm_end;
-
- while (addr < end) {
- dst_pte = huge_pte_alloc(dst, addr);
- if (!dst_pte)
- goto nomem;
- src_pte = huge_pte_offset(src, addr);
- entry = *src_pte;
- ptepage = pte_page(entry);
- get_page(ptepage);
- set_pte(dst_pte, entry);
- add_mm_counter(dst, rss, HPAGE_SIZE / PAGE_SIZE);
- addr += HPAGE_SIZE;
- }
- return 0;
-nomem:
- return -ENOMEM;
-}
-
-int
-follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma,
- struct page **pages, struct vm_area_struct **vmas,
- unsigned long *st, int *length, int i)
-{
- pte_t *ptep, pte;
- unsigned long start = *st;
- unsigned long pstart;
- int len = *length;
- struct page *page;
-
- do {
- pstart = start & HPAGE_MASK;
- ptep = huge_pte_offset(mm, start);
- pte = *ptep;
-
-back1:
- page = pte_page(pte);
- if (pages) {
- page += ((start & ~HPAGE_MASK) >> PAGE_SHIFT);
- get_page(page);
- pages[i] = page;
- }
- if (vmas)
- vmas[i] = vma;
- i++;
- len--;
- start += PAGE_SIZE;
- if (((start & HPAGE_MASK) == pstart) && len &&
- (start < vma->vm_end))
- goto back1;
- } while (len && start < vma->vm_end);
- *length = len;
- *st = start;
- return i;
-}
-
struct page *follow_huge_addr(struct mm_struct *mm, unsigned long addr, int write)
{
struct page *page;
free_pgd_range(tlb, addr, end, floor, ceiling);
}
-void unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
-{
- struct mm_struct *mm = vma->vm_mm;
- unsigned long address;
- pte_t *pte;
- struct page *page;
-
- BUG_ON(start & (HPAGE_SIZE - 1));
- BUG_ON(end & (HPAGE_SIZE - 1));
-
- for (address = start; address < end; address += HPAGE_SIZE) {
- pte = huge_pte_offset(mm, address);
- if (pte_none(*pte))
- continue;
- page = pte_page(*pte);
- put_page(page);
- pte_clear(mm, address, pte);
- }
- add_mm_counter(mm, rss, - ((end - start) >> PAGE_SHIFT));
- flush_tlb_range(vma, start, end);
-}
-
-int hugetlb_prefault(struct address_space *mapping, struct vm_area_struct *vma)
-{
- struct mm_struct *mm = current->mm;
- unsigned long addr;
- int ret = 0;
-
- BUG_ON(vma->vm_start & ~HPAGE_MASK);
- BUG_ON(vma->vm_end & ~HPAGE_MASK);
-
- spin_lock(&mm->page_table_lock);
- for (addr = vma->vm_start; addr < vma->vm_end; addr += HPAGE_SIZE) {
- unsigned long idx;
- pte_t *pte = huge_pte_alloc(mm, addr);
- struct page *page;
-
- if (!pte) {
- ret = -ENOMEM;
- goto out;
- }
- if (!pte_none(*pte))
- continue;
-
- idx = ((addr - vma->vm_start) >> HPAGE_SHIFT)
- + (vma->vm_pgoff >> (HPAGE_SHIFT - PAGE_SHIFT));
- page = find_get_page(mapping, idx);
- if (!page) {
- /* charge the fs quota first */
- if (hugetlb_get_quota(mapping)) {
- ret = -ENOMEM;
- goto out;
- }
- page = alloc_huge_page();
- if (!page) {
- hugetlb_put_quota(mapping);
- ret = -ENOMEM;
- goto out;
- }
- ret = add_to_page_cache(page, mapping, idx, GFP_ATOMIC);
- if (! ret) {
- unlock_page(page);
- } else {
- hugetlb_put_quota(mapping);
- page_cache_release(page);
- goto out;
- }
- }
- set_huge_pte(mm, vma, page, pte, vma->vm_flags & VM_WRITE);
- }
-out:
- spin_unlock(&mm->page_table_lock);
- return ret;
-}
-
unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, unsigned long len,
unsigned long pgoff, unsigned long flags)
{
#include <linux/cache.h>
#include <linux/mmzone.h>
#include <linux/nodemask.h>
+#include <asm/uncached.h>
#include <asm/sn/bte.h>
#include <asm/sn/intr.h>
#include <asm/sn/sn_sal.h>
* memory protections are never restricted.
*/
if ((amos_page = xpc_vars->amos_page) == NULL) {
- amos_page = (AMO_t *) mspec_kalloc_page(0);
+ amos_page = (AMO_t *) TO_AMO(uncached_alloc_page(0));
if (amos_page == NULL) {
dev_err(xpc_part, "can't allocate page of AMOs\n");
return NULL;
if (ret != 0) {
dev_err(xpc_part, "can't change memory "
"protections\n");
- mspec_kfree_page((unsigned long) amos_page);
+ uncached_free_page(__IA64_UNCACHED_OFFSET |
+ TO_PHYS((u64) amos_page));
return NULL;
}
}
config PLAT_MAPPI2
bool "Mappi-II(M3A-ZA36/M3A-ZA52)"
+config PLAT_MAPPI3
+ bool "Mappi-III(M3A-2170)"
+
endchoice
choice
int "Bus Clock [Hz] (integer)"
default "70000000" if PLAT_MAPPI
default "25000000" if PLAT_USRV
+ default "50000000" if PLAT_MAPPI3
default "50000000" if PLAT_M32700UT
default "50000000" if PLAT_OPSPUT
default "33333333" if PLAT_OAKS32R
config MEMORY_START
hex "Physical memory start address (hex)"
- default "08000000" if PLAT_MAPPI || PLAT_MAPPI2
+ default "08000000" if PLAT_MAPPI || PLAT_MAPPI2 || PLAT_MAPPI3
default "08000000" if PLAT_USRV
default "08000000" if PLAT_M32700UT
default "08000000" if PLAT_OPSPUT
config MEMORY_SIZE
hex "Physical memory size (hex)"
+ default "08000000" if PLAT_MAPPI3
default "04000000" if PLAT_MAPPI || PLAT_MAPPI2
default "02000000" if PLAT_USRV
default "01000000" if PLAT_M32700UT
*/
#include <linux/config.h>
+#include <asm/processor.h>
static void putc(char c);
static void putc(char c)
{
-
- while ((*BOOT_SIO0STS & 0x3) != 0x3) ;
+ while ((*BOOT_SIO0STS & 0x3) != 0x3)
+ cpu_relax();
if (c == '\n') {
*BOOT_SIO0TXB = '\r';
- while ((*BOOT_SIO0STS & 0x3) != 0x3) ;
+ while ((*BOOT_SIO0STS & 0x3) != 0x3)
+ cpu_relax();
}
*BOOT_SIO0TXB = c;
}
-#else /* defined(CONFIG_PLAT_M32700UT_Alpha) || defined(CONFIG_PLAT_M32700UT) */
-#ifdef CONFIG_MMU
+#else /* !(CONFIG_PLAT_M32700UT_Alpha) && !(CONFIG_PLAT_M32700UT) */
+#if defined(CONFIG_PLAT_MAPPI2)
#define SIO0STS (volatile unsigned short *)(0xa0efd000 + 14)
#define SIO0TXB (volatile unsigned short *)(0xa0efd000 + 30)
#else
static void putc(char c)
{
-
- while ((*SIO0STS & 0x1) == 0) ;
+ while ((*SIO0STS & 0x1) == 0)
+ cpu_relax();
if (c == '\n') {
*SIO0TXB = '\r';
- while ((*SIO0STS & 0x1) == 0) ;
+ while ((*SIO0STS & 0x1) == 0)
+ cpu_relax();
}
*SIO0TXB = c;
}
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.11-rc4
-# Wed Feb 16 21:10:44 2005
+# Linux kernel version: 2.6.12-rc5
+# Fri Jun 3 16:20:11 2005
#
CONFIG_M32R=y
# CONFIG_UID16 is not set
CONFIG_CLEAN_COMPILE=y
CONFIG_BROKEN_ON_SMP=y
CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
#
# General setup
# CONFIG_BSD_PROCESS_ACCT_V3 is not set
CONFIG_SYSCTL=y
# CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
CONFIG_HOTPLUG=y
CONFIG_KOBJECT_UEVENT=y
CONFIG_IKCONFIG=y
# CONFIG_IKCONFIG_PROC is not set
CONFIG_EMBEDDED=y
# CONFIG_KALLSYMS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
# CONFIG_FUTEX is not set
# CONFIG_EPOLL is not set
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_CC_ALIGN_LOOPS=0
CONFIG_CC_ALIGN_JUMPS=0
# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
#
# Loadable module support
# CONFIG_PLAT_OPSPUT is not set
# CONFIG_PLAT_OAKS32R is not set
# CONFIG_PLAT_MAPPI2 is not set
+# CONFIG_PLAT_MAPPI3 is not set
CONFIG_CHIP_M32700=y
# CONFIG_CHIP_M32102 is not set
# CONFIG_CHIP_VDEC2 is not set
#
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_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=y
-# CONFIG_SERIO_I8042 is not set
-CONFIG_SERIO_SERPORT=y
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_LIBPS2 is not set
-# CONFIG_SERIO_RAW is not set
-
#
# Input Device Drivers
#
# CONFIG_INPUT_TOUCHSCREEN is not set
# CONFIG_INPUT_MISC is not set
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_LIBPS2 is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
#
# Character devices
#
# CONFIG_SYNCLINK_CS is not set
# CONFIG_RAW_DRIVER is not set
+#
+# TPM devices
+#
+
#
# I2C support
#
# Graphics support
#
CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_SOFT_CURSOR is not set
+# CONFIG_FB_MACMODES is not set
# CONFIG_FB_MODE_HELPERS is not set
# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
# CONFIG_FB_VIRTUAL is not set
#
# 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
#
#
# Kernel hacking
#
+# CONFIG_PRINTK_TIME is not set
# CONFIG_DEBUG_KERNEL is not set
-CONFIG_DEBUG_PREEMPT=y
+CONFIG_LOG_BUF_SHIFT=14
# CONFIG_DEBUG_BUGVERBOSE is not set
# CONFIG_FRAME_POINTER is not set
obj-$(CONFIG_SMP) += smp.o smpboot.o
obj-$(CONFIG_PLAT_MAPPI) += setup_mappi.o io_mappi.o
obj-$(CONFIG_PLAT_MAPPI2) += setup_mappi2.o io_mappi2.o
+obj-$(CONFIG_PLAT_MAPPI3) += setup_mappi3.o io_mappi3.o
obj-$(CONFIG_PLAT_USRV) += setup_usrv.o io_usrv.o
obj-$(CONFIG_PLAT_M32700UT) += setup_m32700ut.o io_m32700ut.o
obj-$(CONFIG_PLAT_OPSPUT) += setup_opsput.o io_opsput.o
obj-$(CONFIG_PLAT_OAKS32R) += setup_oaks32r.o io_oaks32r.o
EXTRA_AFLAGS := -traditional
-
*
* Typical I/O routines for M32700UT board.
*
- * Copyright (c) 2001, 2002 Hiroyuki Kondo, Hirokazu Takata,
- * Hitoshi Yamamoto, Takeo Takahashi
+ * Copyright (c) 2001-2005 Hiroyuki Kondo, Hirokazu Takata,
+ * Hitoshi Yamamoto, Takeo Takahashi
*
* 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
unsigned char _inb_p(unsigned long port)
{
- unsigned char v;
-
- if (port >= LAN_IOSTART && port < LAN_IOEND)
- v = _ne_inb(PORT2ADDR_NE(port));
- else
-#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
- if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
- return *(volatile unsigned char *)__port2addr_ata(port);
- } else
-#endif
-#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
- if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
- unsigned char b;
- pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0);
- return b;
- } else
-#endif
- v = *(volatile unsigned char *)PORT2ADDR(port);
-
+ unsigned char v = _inb(port);
delay();
return (v);
}
unsigned short _inw_p(unsigned long port)
{
- unsigned short v;
-
- if (port >= LAN_IOSTART && port < LAN_IOEND)
- v = _ne_inw(PORT2ADDR_NE(port));
- else
-#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
- if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
- return *(volatile unsigned short *)__port2addr_ata(port);
- } else
-#endif
-#if defined(CONFIG_USB)
- if(port >= 0x340 && port < 0x3a0)
- return *(volatile unsigned short *)PORT2ADDR_USB(port);
- else
-#endif
-#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
- if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
- unsigned short w;
- pcc_ioread_word(0, port, &w, sizeof(w), 1, 0);
- return w;
- } else
-#endif
- v = *(volatile unsigned short *)PORT2ADDR(port);
-
+ unsigned short v = _inw(port);
delay();
return (v);
}
unsigned long _inl_p(unsigned long port)
{
- unsigned long v;
-
- v = *(volatile unsigned long *)PORT2ADDR(port);
+ unsigned long v = _inl(port);
delay();
return (v);
}
void _outb_p(unsigned char b, unsigned long port)
{
- if (port >= LAN_IOSTART && port < LAN_IOEND)
- _ne_outb(b, PORT2ADDR_NE(port));
- else
-#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
- if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
- *(volatile unsigned char *)__port2addr_ata(port) = b;
- } else
-#endif
-#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
- if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
- pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0);
- } else
-#endif
- *(volatile unsigned char *)PORT2ADDR(port) = b;
-
+ _outb(b, port);
delay();
}
void _outw_p(unsigned short w, unsigned long port)
{
- if (port >= LAN_IOSTART && port < LAN_IOEND)
- _ne_outw(w, PORT2ADDR_NE(port));
- else
-#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
- if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
- *(volatile unsigned short *)__port2addr_ata(port) = w;
- } else
-#endif
-#if defined(CONFIG_USB)
- if(port >= 0x340 && port < 0x3a0)
- *(volatile unsigned short *)PORT2ADDR_USB(port) = w;
- else
-#endif
-#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
- if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
- pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0);
- } else
-#endif
- *(volatile unsigned short *)PORT2ADDR(port) = w;
-
+ _outw(w, port);
delay();
}
void _outl_p(unsigned long l, unsigned long port)
{
- *(volatile unsigned long *)PORT2ADDR(port) = l;
+ _outl(l, port);
delay();
}
*
* Typical I/O routines for Mappi board.
*
- * Copyright (c) 2001, 2002 Hiroyuki Kondo, Hirokazu Takata,
- * Hitoshi Yamamoto
+ * Copyright (c) 2001-2005 Hiroyuki Kondo, Hirokazu Takata,
+ * Hitoshi Yamamoto
*/
#include <linux/config.h>
unsigned char _inb_p(unsigned long port)
{
- unsigned char v;
-
- if (port >= 0x300 && port < 0x320)
- v = _ne_inb(PORT2ADDR_NE(port));
- else
-#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC)
- if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
- unsigned char b;
- pcc_ioread(0, port, &b, sizeof(b), 1, 0);
- return b;
- } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
- unsigned char b;
- pcc_ioread(1, port, &b, sizeof(b), 1, 0);
- return b;
- } else
-#endif
- v = *(volatile unsigned char *)PORT2ADDR(port);
-
+ unsigned char v = _inb(port);
delay();
return (v);
}
unsigned short _inw_p(unsigned long port)
{
- unsigned short v;
-
- if (port >= 0x300 && port < 0x320)
- v = _ne_inw(PORT2ADDR_NE(port));
- else
-#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC)
- if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
- unsigned short w;
- pcc_ioread(0, port, &w, sizeof(w), 1, 0);
- return w;
- } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
- unsigned short w;
- pcc_ioread(1, port, &w, sizeof(w), 1, 0);
- return w;
- } else
-#endif
- v = *(volatile unsigned short *)PORT2ADDR(port);
-
+ unsigned short v = _inw(port);
delay();
return (v);
}
unsigned long _inl_p(unsigned long port)
{
- unsigned long v;
-
- v = *(volatile unsigned long *)PORT2ADDR(port);
+ unsigned long v = _inl(port);
delay();
return (v);
}
void _outb_p(unsigned char b, unsigned long port)
{
- if (port >= 0x300 && port < 0x320)
- _ne_outb(b, PORT2ADDR_NE(port));
- else
-#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC)
- if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
- pcc_iowrite(0, port, &b, sizeof(b), 1, 0);
- } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
- pcc_iowrite(1, port, &b, sizeof(b), 1, 0);
- } else
-#endif
- *(volatile unsigned char *)PORT2ADDR(port) = b;
-
+ _outb(b, port);
delay();
}
void _outw_p(unsigned short w, unsigned long port)
{
- if (port >= 0x300 && port < 0x320)
- _ne_outw(w, PORT2ADDR_NE(port));
- else
-#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC)
- if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
- pcc_iowrite(0, port, &w, sizeof(w), 1, 0);
- } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
- pcc_iowrite(1, port, &w, sizeof(w), 1, 0);
- } else
-#endif
- *(volatile unsigned short *)PORT2ADDR(port) = w;
-
+ _outw(w, port);
delay();
}
void _outl_p(unsigned long l, unsigned long port)
{
- *(volatile unsigned long *)PORT2ADDR(port) = l;
+ _outl(l, port);
delay();
}
*
* Typical I/O routines for Mappi2 board.
*
- * Copyright (c) 2001-2003 Hiroyuki Kondo, Hirokazu Takata,
+ * Copyright (c) 2001-2005 Hiroyuki Kondo, Hirokazu Takata,
* Hitoshi Yamamoto, Mamoru Sakugawa
*/
extern void pcc_ioread_word(int, unsigned long, void *, size_t, size_t, int);
extern void pcc_iowrite_byte(int, unsigned long, void *, size_t, size_t, int);
extern void pcc_iowrite_word(int, unsigned long, void *, size_t, size_t, int);
-#endif /* CONFIG_PCMCIA && CONFIG_MAPPI2_CFC */
+#endif /* CONFIG_PCMCIA && CONFIG_M32R_CFC */
#define PORT2ADDR(port) _port2addr(port)
#define PORT2ADDR_NE(port) _port2addr_ne(port)
unsigned char _inb_p(unsigned long port)
{
- unsigned char v;
-
- if (port >= LAN_IOSTART && port < LAN_IOEND)
- v = _ne_inb(PORT2ADDR_NE(port));
- else
-#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
- if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
- return *(volatile unsigned char *)__port2addr_ata(port);
- } else
-#endif
-#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
- if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
- unsigned char b;
- pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0);
- return b;
- } else
-#endif
- v = *(volatile unsigned char *)PORT2ADDR(port);
-
+ unsigned char v = _inb(port);
delay();
return (v);
}
unsigned short _inw_p(unsigned long port)
{
- unsigned short v;
-
- if (port >= LAN_IOSTART && port < LAN_IOEND)
- v = _ne_inw(PORT2ADDR_NE(port));
- else
-#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
- if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
- return *(volatile unsigned short *)__port2addr_ata(port);
- } else
-#endif
-#if defined(CONFIG_USB)
- if (port >= 0x340 && port < 0x3a0)
- v = *(volatile unsigned short *)PORT2ADDR_USB(port);
- else
-#endif
-#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
- if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
- unsigned short w;
- pcc_ioread_word(0, port, &w, sizeof(w), 1, 0);
- return w;
- } else
-#endif
- v = *(volatile unsigned short *)PORT2ADDR(port);
-
+ unsigned short v = _inw(port);
delay();
return (v);
}
unsigned long _inl_p(unsigned long port)
{
- unsigned long v;
-
- v = *(volatile unsigned long *)PORT2ADDR(port);
+ unsigned long v = _inl(port);
delay();
return (v);
}
void _outb_p(unsigned char b, unsigned long port)
{
- if (port >= LAN_IOSTART && port < LAN_IOEND)
- _ne_outb(b, PORT2ADDR_NE(port));
- else
-#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
- if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
- *(volatile unsigned char *)__port2addr_ata(port) = b;
- } else
-#endif
-#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
- if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
- pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0);
- } else
-#endif
- *(volatile unsigned char *)PORT2ADDR(port) = b;
-
+ _outb(b, port);
delay();
}
void _outw_p(unsigned short w, unsigned long port)
{
- if (port >= LAN_IOSTART && port < LAN_IOEND)
- _ne_outw(w, PORT2ADDR_NE(port));
- else
-#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
- if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
- *(volatile unsigned short *)__port2addr_ata(port) = w;
- } else
-#endif
-#if defined(CONFIG_USB)
- if (port >= 0x340 && port < 0x3a0)
- *(volatile unsigned short *)PORT2ADDR_USB(port) = w;
- else
-#endif
-#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
- if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
- pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0);
- } else
-#endif
- *(volatile unsigned short *)PORT2ADDR(port) = w;
-
+ _outw(w, port);
delay();
}
void _outl_p(unsigned long l, unsigned long port)
{
- *(volatile unsigned long *)PORT2ADDR(port) = l;
+ _outl(l, port);
delay();
}
--- /dev/null
+/*
+ * linux/arch/m32r/kernel/io_mappi3.c
+ *
+ * Typical I/O routines for Mappi3 board.
+ *
+ * Copyright (c) 2001-2005 Hiroyuki Kondo, Hirokazu Takata,
+ * Hitoshi Yamamoto, Mamoru Sakugawa
+ */
+
+#include <linux/config.h>
+#include <asm/m32r.h>
+#include <asm/page.h>
+#include <asm/io.h>
+#include <asm/byteorder.h>
+
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+#include <linux/types.h>
+
+#define M32R_PCC_IOMAP_SIZE 0x1000
+
+#define M32R_PCC_IOSTART0 0x1000
+#define M32R_PCC_IOEND0 (M32R_PCC_IOSTART0 + M32R_PCC_IOMAP_SIZE - 1)
+
+extern void pcc_ioread_byte(int, unsigned long, void *, size_t, size_t, int);
+extern void pcc_ioread_word(int, unsigned long, void *, size_t, size_t, int);
+extern void pcc_iowrite_byte(int, unsigned long, void *, size_t, size_t, int);
+extern void pcc_iowrite_word(int, unsigned long, void *, size_t, size_t, int);
+#endif /* CONFIG_PCMCIA && CONFIG_M32R_CFC */
+
+#define PORT2ADDR(port) _port2addr(port)
+#define PORT2ADDR_NE(port) _port2addr_ne(port)
+#define PORT2ADDR_USB(port) _port2addr_usb(port)
+
+static inline void *_port2addr(unsigned long port)
+{
+ return (void *)(port + NONCACHE_OFFSET);
+}
+
+#define LAN_IOSTART 0x300
+#define LAN_IOEND 0x320
+
+#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
+static inline void *__port2addr_ata(unsigned long port)
+{
+ static int dummy_reg;
+
+ switch (port) {
+ case 0x1f0: return (void *)0xb4002000;
+ case 0x1f1: return (void *)0xb4012800;
+ case 0x1f2: return (void *)0xb4012002;
+ case 0x1f3: return (void *)0xb4012802;
+ case 0x1f4: return (void *)0xb4012004;
+ case 0x1f5: return (void *)0xb4012804;
+ case 0x1f6: return (void *)0xb4012006;
+ case 0x1f7: return (void *)0xb4012806;
+ case 0x3f6: return (void *)0xb401200e;
+ default: return (void *)&dummy_reg;
+ }
+}
+#endif
+
+static inline void *_port2addr_ne(unsigned long port)
+{
+ return (void *)(port + NONCACHE_OFFSET + 0x10000000);
+}
+
+static inline void *_port2addr_usb(unsigned long port)
+{
+ return (void *)(port + NONCACHE_OFFSET + 0x12000000);
+}
+static inline void delay(void)
+{
+ __asm__ __volatile__ ("push r0; \n\t pop r0;" : : :"memory");
+}
+
+/*
+ * NIC I/O function
+ */
+
+static inline unsigned char _ne_inb(void *portp)
+{
+ return (unsigned char) *(volatile unsigned char *)portp;
+}
+
+static inline unsigned short _ne_inw(void *portp)
+{
+ return (unsigned short)le16_to_cpu(*(volatile unsigned short *)portp);
+}
+
+static inline void _ne_insb(void *portp, void * addr, unsigned long count)
+{
+ unsigned char *buf = addr;
+
+ while (count--)
+ *buf++ = *(volatile unsigned char *)portp;
+}
+
+static inline void _ne_outb(unsigned char b, void *portp)
+{
+ *(volatile unsigned char *)portp = (unsigned char)b;
+}
+
+static inline void _ne_outw(unsigned short w, void *portp)
+{
+ *(volatile unsigned short *)portp = cpu_to_le16(w);
+}
+
+unsigned char _inb(unsigned long port)
+{
+ if (port >= LAN_IOSTART && port < LAN_IOEND)
+ return _ne_inb(PORT2ADDR_NE(port));
+#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
+ else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+ return *(volatile unsigned char *)__port2addr_ata(port);
+ }
+#endif
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+ else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+ unsigned char b;
+ pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0);
+ return b;
+ } else
+#endif
+ return *(volatile unsigned char *)PORT2ADDR(port);
+}
+
+unsigned short _inw(unsigned long port)
+{
+ if (port >= LAN_IOSTART && port < LAN_IOEND)
+ return _ne_inw(PORT2ADDR_NE(port));
+#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
+ else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+ return *(volatile unsigned short *)__port2addr_ata(port);
+ }
+#endif
+#if defined(CONFIG_USB)
+ else if (port >= 0x340 && port < 0x3a0)
+ return *(volatile unsigned short *)PORT2ADDR_USB(port);
+#endif
+
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+ else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+ unsigned short w;
+ pcc_ioread_word(0, port, &w, sizeof(w), 1, 0);
+ return w;
+ } else
+#endif
+ return *(volatile unsigned short *)PORT2ADDR(port);
+}
+
+unsigned long _inl(unsigned long port)
+{
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+ if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+ unsigned long l;
+ pcc_ioread_word(0, port, &l, sizeof(l), 1, 0);
+ return l;
+ } else
+#endif
+ return *(volatile unsigned long *)PORT2ADDR(port);
+}
+
+unsigned char _inb_p(unsigned long port)
+{
+ unsigned char v = _inb(port);
+ delay();
+ return (v);
+}
+
+unsigned short _inw_p(unsigned long port)
+{
+ unsigned short v = _inw(port);
+ delay();
+ return (v);
+}
+
+unsigned long _inl_p(unsigned long port)
+{
+ unsigned long v = _inl(port);
+ delay();
+ return (v);
+}
+
+void _outb(unsigned char b, unsigned long port)
+{
+ if (port >= LAN_IOSTART && port < LAN_IOEND)
+ _ne_outb(b, PORT2ADDR_NE(port));
+ else
+#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
+ if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+ *(volatile unsigned char *)__port2addr_ata(port) = b;
+ } else
+#endif
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+ if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+ pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0);
+ } else
+#endif
+ *(volatile unsigned char *)PORT2ADDR(port) = b;
+}
+
+void _outw(unsigned short w, unsigned long port)
+{
+ if (port >= LAN_IOSTART && port < LAN_IOEND)
+ _ne_outw(w, PORT2ADDR_NE(port));
+ else
+#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
+ if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+ *(volatile unsigned short *)__port2addr_ata(port) = w;
+ } else
+#endif
+#if defined(CONFIG_USB)
+ if (port >= 0x340 && port < 0x3a0)
+ *(volatile unsigned short *)PORT2ADDR_USB(port) = w;
+ else
+#endif
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+ if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+ pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0);
+ } else
+#endif
+ *(volatile unsigned short *)PORT2ADDR(port) = w;
+}
+
+void _outl(unsigned long l, unsigned long port)
+{
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+ if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+ pcc_iowrite_word(0, port, &l, sizeof(l), 1, 0);
+ } else
+#endif
+ *(volatile unsigned long *)PORT2ADDR(port) = l;
+}
+
+void _outb_p(unsigned char b, unsigned long port)
+{
+ _outb(b, port);
+ delay();
+}
+
+void _outw_p(unsigned short w, unsigned long port)
+{
+ _outw(w, port);
+ delay();
+}
+
+void _outl_p(unsigned long l, unsigned long port)
+{
+ _outl(l, port);
+ delay();
+}
+
+void _insb(unsigned int port, void * addr, unsigned long count)
+{
+ if (port >= LAN_IOSTART && port < LAN_IOEND)
+ _ne_insb(PORT2ADDR_NE(port), addr, count);
+#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
+ else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+ unsigned char *buf = addr;
+ unsigned char *portp = __port2addr_ata(port);
+ while (count--)
+ *buf++ = *(volatile unsigned char *)portp;
+ }
+#endif
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+ else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+ pcc_ioread_byte(0, port, (void *)addr, sizeof(unsigned char),
+ count, 1);
+ }
+#endif
+ else {
+ unsigned char *buf = addr;
+ unsigned char *portp = PORT2ADDR(port);
+ while (count--)
+ *buf++ = *(volatile unsigned char *)portp;
+ }
+}
+
+void _insw(unsigned int port, void * addr, unsigned long count)
+{
+ unsigned short *buf = addr;
+ unsigned short *portp;
+
+ if (port >= LAN_IOSTART && port < LAN_IOEND) {
+ portp = PORT2ADDR_NE(port);
+ while (count--)
+ *buf++ = *(volatile unsigned short *)portp;
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+ } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+ pcc_ioread_word(9, port, (void *)addr, sizeof(unsigned short),
+ count, 1);
+#endif
+#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
+ } else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+ portp = __port2addr_ata(port);
+ while (count--)
+ *buf++ = *(volatile unsigned short *)portp;
+#endif
+ } else {
+ portp = PORT2ADDR(port);
+ while (count--)
+ *buf++ = *(volatile unsigned short *)portp;
+ }
+}
+
+void _insl(unsigned int port, void * addr, unsigned long count)
+{
+ unsigned long *buf = addr;
+ unsigned long *portp;
+
+ portp = PORT2ADDR(port);
+ while (count--)
+ *buf++ = *(volatile unsigned long *)portp;
+}
+
+void _outsb(unsigned int port, const void * addr, unsigned long count)
+{
+ const unsigned char *buf = addr;
+ unsigned char *portp;
+
+ if (port >= LAN_IOSTART && port < LAN_IOEND) {
+ portp = PORT2ADDR_NE(port);
+ while (count--)
+ _ne_outb(*buf++, portp);
+#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
+ } else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+ portp = __port2addr_ata(port);
+ while (count--)
+ *(volatile unsigned char *)portp = *buf++;
+#endif
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+ } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+ pcc_iowrite_byte(0, port, (void *)addr, sizeof(unsigned char),
+ count, 1);
+#endif
+ } else {
+ portp = PORT2ADDR(port);
+ while (count--)
+ *(volatile unsigned char *)portp = *buf++;
+ }
+}
+
+void _outsw(unsigned int port, const void * addr, unsigned long count)
+{
+ const unsigned short *buf = addr;
+ unsigned short *portp;
+
+ if (port >= LAN_IOSTART && port < LAN_IOEND) {
+ portp = PORT2ADDR_NE(port);
+ while (count--)
+ *(volatile unsigned short *)portp = *buf++;
+#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
+ } else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+ portp = __port2addr_ata(port);
+ while (count--)
+ *(volatile unsigned short *)portp = *buf++;
+#endif
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+ } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+ pcc_iowrite_word(9, port, (void *)addr, sizeof(unsigned short),
+ count, 1);
+#endif
+ } else {
+ portp = PORT2ADDR(port);
+ while (count--)
+ *(volatile unsigned short *)portp = *buf++;
+ }
+}
+
+void _outsl(unsigned int port, const void * addr, unsigned long count)
+{
+ const unsigned long *buf = addr;
+ unsigned char *portp;
+
+ portp = PORT2ADDR(port);
+ while (count--)
+ *(volatile unsigned long *)portp = *buf++;
+}
*
* Typical I/O routines for OAKS32R board.
*
- * Copyright (c) 2001-2004 Hiroyuki Kondo, Hirokazu Takata,
+ * Copyright (c) 2001-2005 Hiroyuki Kondo, Hirokazu Takata,
* Hitoshi Yamamoto, Mamoru Sakugawa
*/
unsigned char _inb_p(unsigned long port)
{
- unsigned char v;
-
- if (port >= 0x300 && port < 0x320)
- v = _ne_inb(PORT2ADDR_NE(port));
- else
- v = *(volatile unsigned char *)PORT2ADDR(port);
-
+ unsigned char v = _inb(port);
delay();
return (v);
}
unsigned short _inw_p(unsigned long port)
{
- unsigned short v;
-
- if (port >= 0x300 && port < 0x320)
- v = _ne_inw(PORT2ADDR_NE(port));
- else
- v = *(volatile unsigned short *)PORT2ADDR(port);
-
+ unsigned short v = _inw(port);
delay();
return (v);
}
unsigned long _inl_p(unsigned long port)
{
- unsigned long v;
-
- v = *(volatile unsigned long *)PORT2ADDR(port);
+ unsigned long v = _inl(port);
delay();
return (v);
}
void _outb_p(unsigned char b, unsigned long port)
{
- if (port >= 0x300 && port < 0x320)
- _ne_outb(b, PORT2ADDR_NE(port));
- else
- *(volatile unsigned char *)PORT2ADDR(port) = b;
-
+ _outb(b, port);
delay();
}
void _outw_p(unsigned short w, unsigned long port)
{
- if (port >= 0x300 && port < 0x320)
- _ne_outw(w, PORT2ADDR_NE(port));
- else
- *(volatile unsigned short *)PORT2ADDR(port) = w;
-
+ _outw(w, port);
delay();
}
void _outl_p(unsigned long l, unsigned long port)
{
- *(volatile unsigned long *)PORT2ADDR(port) = l;
+ _outl(l, port);
delay();
}
/*
- * linux/arch/m32r/kernel/io_mappi.c
+ * linux/arch/m32r/kernel/io_opsput.c
*
* Typical I/O routines for OPSPUT board.
*
- * Copyright (c) 2001, 2002 Hiroyuki Kondo, Hirokazu Takata,
- * Hitoshi Yamamoto, Takeo Takahashi
+ * Copyright (c) 2001-2005 Hiroyuki Kondo, Hirokazu Takata,
+ * Hitoshi Yamamoto, Takeo Takahashi
*
* 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
{
if (port >= LAN_IOSTART && port < LAN_IOEND)
return _ne_inb(PORT2ADDR_NE(port));
-
#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
unsigned char b;
else if(port >= 0x340 && port < 0x3a0)
return *(volatile unsigned short *)PORT2ADDR_USB(port);
#endif
-
#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
unsigned short w;
unsigned char _inb_p(unsigned long port)
{
- unsigned char v;
-
- if (port >= LAN_IOSTART && port < LAN_IOEND)
- v = _ne_inb(PORT2ADDR_NE(port));
- else
-#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
- if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
- unsigned char b;
- pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0);
- return b;
- } else
-#endif
- v = *(volatile unsigned char *)PORT2ADDR(port);
-
+ unsigned char v = _inb(port);
delay();
return (v);
}
unsigned short _inw_p(unsigned long port)
{
- unsigned short v;
-
- if (port >= LAN_IOSTART && port < LAN_IOEND)
- v = _ne_inw(PORT2ADDR_NE(port));
- else
-#if defined(CONFIG_USB)
- if(port >= 0x340 && port < 0x3a0)
- return *(volatile unsigned short *)PORT2ADDR_USB(port);
- else
-#endif
-
-#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
- if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
- unsigned short w;
- pcc_ioread_word(0, port, &w, sizeof(w), 1, 0);
- return w;
- } else
-#endif
- v = *(volatile unsigned short *)PORT2ADDR(port);
-
+ unsigned short v = _inw(port);
delay();
return (v);
}
unsigned long _inl_p(unsigned long port)
{
- unsigned long v;
-
- v = *(volatile unsigned long *)PORT2ADDR(port);
+ unsigned long v = _inl(port);
delay();
return (v);
}
*(volatile unsigned short *)PORT2ADDR_USB(port) = w;
else
#endif
-
#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0);
void _outb_p(unsigned char b, unsigned long port)
{
- if (port >= LAN_IOSTART && port < LAN_IOEND)
- _ne_outb(b, PORT2ADDR_NE(port));
- else
-#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
- if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
- pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0);
- } else
-#endif
- *(volatile unsigned char *)PORT2ADDR(port) = b;
-
+ _outb(b, port);
delay();
}
void _outw_p(unsigned short w, unsigned long port)
{
- if (port >= LAN_IOSTART && port < LAN_IOEND)
- _ne_outw(w, PORT2ADDR_NE(port));
- else
-#if defined(CONFIG_USB)
- if(port >= 0x340 && port < 0x3a0)
- *(volatile unsigned short *)PORT2ADDR_USB(port) = w;
- else
-#endif
-
-#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
- if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
- pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0);
- } else
-#endif
- *(volatile unsigned short *)PORT2ADDR(port) = w;
-
+ _outw(w, port);
delay();
}
void _outl_p(unsigned long l, unsigned long port)
{
- *(volatile unsigned long *)PORT2ADDR(port) = l;
+ _outl(l, port);
delay();
}
*
* Typical I/O routines for uServer board.
*
- * Copyright (c) 2001 - 2003 Hiroyuki Kondo, Hirokazu Takata,
- * Hitoshi Yamamoto, Takeo Takahashi
+ * Copyright (c) 2001-2005 Hiroyuki Kondo, Hirokazu Takata,
+ * Hitoshi Yamamoto, Takeo Takahashi
*
* 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
#define PORT2ADDR(port) _port2addr(port)
-static __inline__ void *_port2addr(unsigned long port)
+static inline void *_port2addr(unsigned long port)
{
#if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE)
if (port >= UART0_IOSTART && port <= UART0_IOEND)
return (void *)(port + NONCACHE_OFFSET);
}
-static __inline__ void delay(void)
+static inline void delay(void)
{
__asm__ __volatile__ ("push r0; \n\t pop r0;" : : :"memory");
}
unsigned char _inb_p(unsigned long port)
{
- unsigned char b;
-
- if (port >= CFC_IOSTART && port <= CFC_IOEND) {
- pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0);
- return b;
- } else {
- b = *(volatile unsigned char *)PORT2ADDR(port);
- delay();
- return b;
- }
+ unsigned char v = _inb(port);
+ delay();
+ return v;
}
unsigned short _inw_p(unsigned long port)
{
- unsigned short w;
-
- if (port >= CFC_IOSTART && port <= CFC_IOEND) {
- pcc_ioread_word(0, port, &w, sizeof(w), 1, 0);
- return w;
- } else {
- w = *(volatile unsigned short *)PORT2ADDR(port);
- delay();
- return w;
- }
+ unsigned short v = _inw(port);
+ delay();
+ return v;
}
unsigned long _inl_p(unsigned long port)
{
- unsigned long v;
-
- v = *(volatile unsigned long *)PORT2ADDR(port);
+ unsigned long v = _inl(port);
delay();
-
return v;
}
void _outb_p(unsigned char b, unsigned long port)
{
- if (port >= CFC_IOSTART && port <= CFC_IOEND)
- pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0);
- else
- *(volatile unsigned char *)PORT2ADDR(port) = b;
+ _outb(b, port);
delay();
}
void _outw_p(unsigned short w, unsigned long port)
{
- if (port >= CFC_IOSTART && port <= CFC_IOEND)
- pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0);
- else
- *(volatile unsigned short *)PORT2ADDR(port) = w;
+ _outw(w, port);
delay();
}
void _outl_p(unsigned long l, unsigned long port)
{
- *(volatile unsigned long *)PORT2ADDR(port) = l;
+ _outl(l, port);
delay();
}
seq_printf(m, "Machine\t\t: Mappi Evaluation board\n");
#elif CONFIG_PLAT_MAPPI2
seq_printf(m, "Machine\t\t: Mappi-II Evaluation board\n");
+#elif CONFIG_PLAT_MAPPI3
+ seq_printf(m, "Machine\t\t: Mappi-III Evaluation board\n");
#elif CONFIG_PLAT_M32700UT
seq_printf(m, "Machine\t\t: M32700UT Evaluation board\n");
#elif CONFIG_PLAT_OPSPUT
static struct hw_interrupt_type m32700ut_irq_type =
{
- "M32700UT-IRQ",
- startup_m32700ut_irq,
- shutdown_m32700ut_irq,
- enable_m32700ut_irq,
- disable_m32700ut_irq,
- mask_and_ack_m32700ut,
- end_m32700ut_irq
+ .typename = "M32700UT-IRQ",
+ .startup = startup_m32700ut_irq,
+ .shutdown = shutdown_m32700ut_irq,
+ .enable = enable_m32700ut_irq,
+ .disable = disable_m32700ut_irq,
+ .ack = mask_and_ack_m32700ut,
+ .end = end_m32700ut_irq
};
/*
static struct hw_interrupt_type m32700ut_pld_irq_type =
{
- "M32700UT-PLD-IRQ",
- startup_m32700ut_pld_irq,
- shutdown_m32700ut_pld_irq,
- enable_m32700ut_pld_irq,
- disable_m32700ut_pld_irq,
- mask_and_ack_m32700ut_pld,
- end_m32700ut_pld_irq
+ .typename = "M32700UT-PLD-IRQ",
+ .startup = startup_m32700ut_pld_irq,
+ .shutdown = shutdown_m32700ut_pld_irq,
+ .enable = enable_m32700ut_pld_irq,
+ .disable = disable_m32700ut_pld_irq,
+ .ack = mask_and_ack_m32700ut_pld,
+ .end = end_m32700ut_pld_irq
};
/*
static struct hw_interrupt_type m32700ut_lanpld_irq_type =
{
- "M32700UT-PLD-LAN-IRQ",
- startup_m32700ut_lanpld_irq,
- shutdown_m32700ut_lanpld_irq,
- enable_m32700ut_lanpld_irq,
- disable_m32700ut_lanpld_irq,
- mask_and_ack_m32700ut_lanpld,
- end_m32700ut_lanpld_irq
+ .typename = "M32700UT-PLD-LAN-IRQ",
+ .startup = startup_m32700ut_lanpld_irq,
+ .shutdown = shutdown_m32700ut_lanpld_irq,
+ .enable = enable_m32700ut_lanpld_irq,
+ .disable = disable_m32700ut_lanpld_irq,
+ .ack = mask_and_ack_m32700ut_lanpld,
+ .end = end_m32700ut_lanpld_irq
};
/*
static struct hw_interrupt_type m32700ut_lcdpld_irq_type =
{
- "M32700UT-PLD-LCD-IRQ",
- startup_m32700ut_lcdpld_irq,
- shutdown_m32700ut_lcdpld_irq,
- enable_m32700ut_lcdpld_irq,
- disable_m32700ut_lcdpld_irq,
- mask_and_ack_m32700ut_lcdpld,
- end_m32700ut_lcdpld_irq
+ .typename = "M32700UT-PLD-LCD-IRQ",
+ .startup = startup_m32700ut_lcdpld_irq,
+ .shutdown = shutdown_m32700ut_lcdpld_irq,
+ .enable = enable_m32700ut_lcdpld_irq,
+ .disable = disable_m32700ut_lcdpld_irq,
+ .ack = mask_and_ack_m32700ut_lcdpld,
+ .end = end_m32700ut_lcdpld_irq
};
void __init init_IRQ(void)
static struct hw_interrupt_type mappi_irq_type =
{
- "MAPPI-IRQ",
- startup_mappi_irq,
- shutdown_mappi_irq,
- enable_mappi_irq,
- disable_mappi_irq,
- mask_and_ack_mappi,
- end_mappi_irq
+ .typename = "MAPPI-IRQ",
+ .startup = startup_mappi_irq,
+ .shutdown = shutdown_mappi_irq,
+ .enable = enable_mappi_irq,
+ .disable = disable_mappi_irq,
+ .ack = mask_and_ack_mappi,
+ .end = end_mappi_irq
};
void __init init_IRQ(void)
/*
- * linux/arch/m32r/kernel/setup_mappi.c
+ * linux/arch/m32r/kernel/setup_mappi2.c
*
* Setup routines for Renesas MAPPI-II(M3A-ZA36) Board
*
static struct hw_interrupt_type mappi2_irq_type =
{
- "MAPPI2-IRQ",
- startup_mappi2_irq,
- shutdown_mappi2_irq,
- enable_mappi2_irq,
- disable_mappi2_irq,
- mask_and_ack_mappi2,
- end_mappi2_irq
+ .typename = "MAPPI2-IRQ",
+ .startup = startup_mappi2_irq,
+ .shutdown = shutdown_mappi2_irq,
+ .enable = enable_mappi2_irq,
+ .disable = disable_mappi2_irq,
+ .ack = mask_and_ack_mappi2,
+ .end = end_mappi2_irq
};
void __init init_IRQ(void)
irq_desc[PLD_IRQ_CFIREQ].handler = &mappi2_irq_type;
irq_desc[PLD_IRQ_CFIREQ].action = 0;
irq_desc[PLD_IRQ_CFIREQ].depth = 1; /* disable nested irq */
-// icu_data[PLD_IRQ_CFIREQ].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD00;
icu_data[PLD_IRQ_CFIREQ].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD01;
disable_mappi2_irq(PLD_IRQ_CFIREQ);
irq_desc[PLD_IRQ_CFC_INSERT].action = 0;
irq_desc[PLD_IRQ_CFC_INSERT].depth = 1; /* disable nested irq */
icu_data[PLD_IRQ_CFC_INSERT].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD00;
-// icu_data[PLD_IRQ_CFC_INSERT].icucr = 0;
disable_mappi2_irq(PLD_IRQ_CFC_INSERT);
/* ICUCR42: CFC Eject */
irq_desc[PLD_IRQ_CFC_EJECT].action = 0;
irq_desc[PLD_IRQ_CFC_EJECT].depth = 1; /* disable nested irq */
icu_data[PLD_IRQ_CFC_EJECT].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
-// icu_data[PLD_IRQ_CFC_EJECT].icucr = 0;
disable_mappi2_irq(PLD_IRQ_CFC_EJECT);
-
#endif /* CONFIG_MAPPI2_CFC */
}
--- /dev/null
+/*
+ * linux/arch/m32r/kernel/setup_mappi3.c
+ *
+ * Setup routines for Renesas MAPPI-III(M3A-2170) Board
+ *
+ * Copyright (c) 2001-2005 Hiroyuki Kondo, Hirokazu Takata,
+ * Hitoshi Yamamoto, Mamoru Sakugawa
+ */
+
+#include <linux/config.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+
+#include <asm/system.h>
+#include <asm/m32r.h>
+#include <asm/io.h>
+
+#define irq2port(x) (M32R_ICU_CR1_PORTL + ((x - 1) * sizeof(unsigned long)))
+
+#ifndef CONFIG_SMP
+typedef struct {
+ unsigned long icucr; /* ICU Control Register */
+} icu_data_t;
+#endif /* CONFIG_SMP */
+
+icu_data_t icu_data[NR_IRQS];
+
+static void disable_mappi3_irq(unsigned int irq)
+{
+ unsigned long port, data;
+
+ if ((irq == 0) ||(irq >= NR_IRQS)) {
+ printk("bad irq 0x%08x\n", irq);
+ return;
+ }
+ port = irq2port(irq);
+ data = icu_data[irq].icucr|M32R_ICUCR_ILEVEL7;
+ outl(data, port);
+}
+
+static void enable_mappi3_irq(unsigned int irq)
+{
+ unsigned long port, data;
+
+ if ((irq == 0) ||(irq >= NR_IRQS)) {
+ printk("bad irq 0x%08x\n", irq);
+ return;
+ }
+ port = irq2port(irq);
+ data = icu_data[irq].icucr|M32R_ICUCR_IEN|M32R_ICUCR_ILEVEL6;
+ outl(data, port);
+}
+
+static void mask_and_ack_mappi3(unsigned int irq)
+{
+ disable_mappi3_irq(irq);
+}
+
+static void end_mappi3_irq(unsigned int irq)
+{
+ enable_mappi3_irq(irq);
+}
+
+static unsigned int startup_mappi3_irq(unsigned int irq)
+{
+ enable_mappi3_irq(irq);
+ return (0);
+}
+
+static void shutdown_mappi3_irq(unsigned int irq)
+{
+ unsigned long port;
+
+ port = irq2port(irq);
+ outl(M32R_ICUCR_ILEVEL7, port);
+}
+
+static struct hw_interrupt_type mappi3_irq_type =
+{
+ .typename = "MAPPI3-IRQ",
+ .startup = startup_mappi3_irq,
+ .shutdown = shutdown_mappi3_irq,
+ .enable = enable_mappi3_irq,
+ .disable = disable_mappi3_irq,
+ .ack = mask_and_ack_mappi3,
+ .end = end_mappi3_irq
+};
+
+void __init init_IRQ(void)
+{
+#if defined(CONFIG_SMC91X)
+ /* INT0 : LAN controller (SMC91111) */
+ irq_desc[M32R_IRQ_INT0].status = IRQ_DISABLED;
+ irq_desc[M32R_IRQ_INT0].handler = &mappi3_irq_type;
+ irq_desc[M32R_IRQ_INT0].action = 0;
+ irq_desc[M32R_IRQ_INT0].depth = 1;
+ icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
+ disable_mappi3_irq(M32R_IRQ_INT0);
+#endif /* CONFIG_SMC91X */
+
+ /* MFT2 : system timer */
+ irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED;
+ irq_desc[M32R_IRQ_MFT2].handler = &mappi3_irq_type;
+ irq_desc[M32R_IRQ_MFT2].action = 0;
+ irq_desc[M32R_IRQ_MFT2].depth = 1;
+ icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
+ disable_mappi3_irq(M32R_IRQ_MFT2);
+
+#ifdef CONFIG_SERIAL_M32R_SIO
+ /* SIO0_R : uart receive data */
+ irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED;
+ irq_desc[M32R_IRQ_SIO0_R].handler = &mappi3_irq_type;
+ irq_desc[M32R_IRQ_SIO0_R].action = 0;
+ irq_desc[M32R_IRQ_SIO0_R].depth = 1;
+ icu_data[M32R_IRQ_SIO0_R].icucr = 0;
+ disable_mappi3_irq(M32R_IRQ_SIO0_R);
+
+ /* SIO0_S : uart send data */
+ irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED;
+ irq_desc[M32R_IRQ_SIO0_S].handler = &mappi3_irq_type;
+ irq_desc[M32R_IRQ_SIO0_S].action = 0;
+ irq_desc[M32R_IRQ_SIO0_S].depth = 1;
+ icu_data[M32R_IRQ_SIO0_S].icucr = 0;
+ disable_mappi3_irq(M32R_IRQ_SIO0_S);
+ /* SIO1_R : uart receive data */
+ irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED;
+ irq_desc[M32R_IRQ_SIO1_R].handler = &mappi3_irq_type;
+ irq_desc[M32R_IRQ_SIO1_R].action = 0;
+ irq_desc[M32R_IRQ_SIO1_R].depth = 1;
+ icu_data[M32R_IRQ_SIO1_R].icucr = 0;
+ disable_mappi3_irq(M32R_IRQ_SIO1_R);
+
+ /* SIO1_S : uart send data */
+ irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED;
+ irq_desc[M32R_IRQ_SIO1_S].handler = &mappi3_irq_type;
+ irq_desc[M32R_IRQ_SIO1_S].action = 0;
+ irq_desc[M32R_IRQ_SIO1_S].depth = 1;
+ icu_data[M32R_IRQ_SIO1_S].icucr = 0;
+ disable_mappi3_irq(M32R_IRQ_SIO1_S);
+#endif /* CONFIG_M32R_USE_DBG_CONSOLE */
+
+#if defined(CONFIG_USB)
+ /* INT1 : USB Host controller interrupt */
+ irq_desc[M32R_IRQ_INT1].status = IRQ_DISABLED;
+ irq_desc[M32R_IRQ_INT1].handler = &mappi3_irq_type;
+ irq_desc[M32R_IRQ_INT1].action = 0;
+ irq_desc[M32R_IRQ_INT1].depth = 1;
+ icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_ISMOD01;
+ disable_mappi3_irq(M32R_IRQ_INT1);
+#endif /* CONFIG_USB */
+
+ /* ICUCR40: CFC IREQ */
+ irq_desc[PLD_IRQ_CFIREQ].status = IRQ_DISABLED;
+ irq_desc[PLD_IRQ_CFIREQ].handler = &mappi3_irq_type;
+ irq_desc[PLD_IRQ_CFIREQ].action = 0;
+ irq_desc[PLD_IRQ_CFIREQ].depth = 1; /* disable nested irq */
+ icu_data[PLD_IRQ_CFIREQ].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD01;
+ disable_mappi3_irq(PLD_IRQ_CFIREQ);
+
+#if defined(CONFIG_M32R_CFC)
+ /* ICUCR41: CFC Insert */
+ irq_desc[PLD_IRQ_CFC_INSERT].status = IRQ_DISABLED;
+ irq_desc[PLD_IRQ_CFC_INSERT].handler = &mappi3_irq_type;
+ irq_desc[PLD_IRQ_CFC_INSERT].action = 0;
+ irq_desc[PLD_IRQ_CFC_INSERT].depth = 1; /* disable nested irq */
+ icu_data[PLD_IRQ_CFC_INSERT].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD00;
+ disable_mappi3_irq(PLD_IRQ_CFC_INSERT);
+
+ /* ICUCR42: CFC Eject */
+ irq_desc[PLD_IRQ_CFC_EJECT].status = IRQ_DISABLED;
+ irq_desc[PLD_IRQ_CFC_EJECT].handler = &mappi3_irq_type;
+ irq_desc[PLD_IRQ_CFC_EJECT].action = 0;
+ irq_desc[PLD_IRQ_CFC_EJECT].depth = 1; /* disable nested irq */
+ icu_data[PLD_IRQ_CFC_EJECT].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
+ disable_mappi3_irq(PLD_IRQ_CFC_EJECT);
+#endif /* CONFIG_M32R_CFC */
+}
+
+#define LAN_IOSTART 0x300
+#define LAN_IOEND 0x320
+static struct resource smc91x_resources[] = {
+ [0] = {
+ .start = (LAN_IOSTART),
+ .end = (LAN_IOEND),
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = M32R_IRQ_INT0,
+ .end = M32R_IRQ_INT0,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static struct platform_device smc91x_device = {
+ .name = "smc91x",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(smc91x_resources),
+ .resource = smc91x_resources,
+};
+
+static int __init platform_init(void)
+{
+ platform_device_register(&smc91x_device);
+ return 0;
+}
+arch_initcall(platform_init);
static struct hw_interrupt_type oaks32r_irq_type =
{
- "OAKS32R-IRQ",
- startup_oaks32r_irq,
- shutdown_oaks32r_irq,
- enable_oaks32r_irq,
- disable_oaks32r_irq,
- mask_and_ack_mappi,
- end_oaks32r_irq
+ .typename = "OAKS32R-IRQ",
+ .startup = startup_oaks32r_irq,
+ .shutdown = shutdown_oaks32r_irq,
+ .enable = enable_oaks32r_irq,
+ .disable = disable_oaks32r_irq,
+ .ack = mask_and_ack_mappi,
+ .end = end_oaks32r_irq
};
void __init init_IRQ(void)
static struct hw_interrupt_type opsput_irq_type =
{
- "OPSPUT-IRQ",
- startup_opsput_irq,
- shutdown_opsput_irq,
- enable_opsput_irq,
- disable_opsput_irq,
- mask_and_ack_opsput,
- end_opsput_irq
+ .typename = "OPSPUT-IRQ",
+ .startup = startup_opsput_irq,
+ .shutdown = shutdown_opsput_irq,
+ .enable = enable_opsput_irq,
+ .disable = disable_opsput_irq,
+ .ack = mask_and_ack_opsput,
+ .end = end_opsput_irq
};
/*
static struct hw_interrupt_type opsput_pld_irq_type =
{
- "OPSPUT-PLD-IRQ",
- startup_opsput_pld_irq,
- shutdown_opsput_pld_irq,
- enable_opsput_pld_irq,
- disable_opsput_pld_irq,
- mask_and_ack_opsput_pld,
- end_opsput_pld_irq
+ .typename = "OPSPUT-PLD-IRQ",
+ .startup = startup_opsput_pld_irq,
+ .shutdown = shutdown_opsput_pld_irq,
+ .enable = enable_opsput_pld_irq,
+ .disable = disable_opsput_pld_irq,
+ .ack = mask_and_ack_opsput_pld,
+ .end = end_opsput_pld_irq
};
/*
static struct hw_interrupt_type mappi_irq_type =
{
- "M32700-IRQ",
- startup_mappi_irq,
- shutdown_mappi_irq,
- enable_mappi_irq,
- disable_mappi_irq,
- mask_and_ack_mappi,
- end_mappi_irq
+ .typename = "M32700-IRQ",
+ .startup = startup_mappi_irq,
+ .shutdown = shutdown_mappi_irq,
+ .enable = enable_mappi_irq,
+ .disable = disable_mappi_irq,
+ .ack = mask_and_ack_mappi,
+ .end = end_mappi_irq
};
/*
static struct hw_interrupt_type m32700ut_pld_irq_type =
{
- "USRV-PLD-IRQ",
- startup_m32700ut_pld_irq,
- shutdown_m32700ut_pld_irq,
- enable_m32700ut_pld_irq,
- disable_m32700ut_pld_irq,
- mask_and_ack_m32700ut_pld,
- end_m32700ut_pld_irq
+ .typename = "USRV-PLD-IRQ",
+ .startup = startup_m32700ut_pld_irq,
+ .shutdown = shutdown_m32700ut_pld_irq,
+ .enable = enable_m32700ut_pld_irq,
+ .disable = disable_m32700ut_pld_irq,
+ .ack = mask_and_ack_m32700ut_pld,
+ .end = end_m32700ut_pld_irq
};
void __init init_IRQ(void)
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.11-rc4
-# Wed Feb 16 21:10:50 2005
+# Linux kernel version: 2.6.12-rc5
+# Fri Jun 3 16:20:58 2005
#
CONFIG_M32R=y
# CONFIG_UID16 is not set
CONFIG_EXPERIMENTAL=y
CONFIG_CLEAN_COMPILE=y
CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
#
# General setup
# CONFIG_BSD_PROCESS_ACCT_V3 is not set
CONFIG_SYSCTL=y
# CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=15
CONFIG_HOTPLUG=y
CONFIG_KOBJECT_UEVENT=y
CONFIG_IKCONFIG=y
# CONFIG_IKCONFIG_PROC is not set
+# CONFIG_CPUSETS is not set
CONFIG_EMBEDDED=y
# CONFIG_KALLSYMS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
# CONFIG_FUTEX is not set
# CONFIG_EPOLL is not set
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_CC_ALIGN_LOOPS=0
CONFIG_CC_ALIGN_JUMPS=0
# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
#
# Loadable module support
# CONFIG_PLAT_OPSPUT is not set
# CONFIG_PLAT_OAKS32R is not set
# CONFIG_PLAT_MAPPI2 is not set
+# CONFIG_PLAT_MAPPI3 is not set
CONFIG_CHIP_M32700=y
# CONFIG_CHIP_M32102 is not set
# CONFIG_CHIP_VDEC2 is not set
#
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_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=y
-# CONFIG_SERIO_I8042 is not set
-CONFIG_SERIO_SERPORT=y
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_LIBPS2 is not set
-# CONFIG_SERIO_RAW is not set
-
#
# Input Device Drivers
#
# CONFIG_INPUT_TOUCHSCREEN is not set
# CONFIG_INPUT_MISC is not set
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_LIBPS2 is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
#
# Character devices
#
# CONFIG_SYNCLINK_CS is not set
# CONFIG_RAW_DRIVER is not set
+#
+# TPM devices
+#
+
#
# I2C support
#
# Graphics support
#
CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_SOFT_CURSOR is not set
+# CONFIG_FB_MACMODES is not set
# CONFIG_FB_MODE_HELPERS is not set
# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
# CONFIG_FB_VIRTUAL is not set
#
# 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
#
#
# Kernel hacking
#
+# CONFIG_PRINTK_TIME is not set
# CONFIG_DEBUG_KERNEL is not set
-CONFIG_DEBUG_PREEMPT=y
+CONFIG_LOG_BUF_SHIFT=15
# CONFIG_DEBUG_BUGVERBOSE is not set
# CONFIG_FRAME_POINTER is not set
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.11-rc4
-# Wed Feb 16 21:10:54 2005
+# Linux kernel version: 2.6.12-rc5
+# Fri Jun 3 16:21:34 2005
#
CONFIG_M32R=y
# CONFIG_UID16 is not set
CONFIG_CLEAN_COMPILE=y
CONFIG_BROKEN_ON_SMP=y
CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
#
# General setup
# CONFIG_BSD_PROCESS_ACCT_V3 is not set
CONFIG_SYSCTL=y
# CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
CONFIG_HOTPLUG=y
CONFIG_KOBJECT_UEVENT=y
CONFIG_IKCONFIG=y
# CONFIG_IKCONFIG_PROC is not set
CONFIG_EMBEDDED=y
# CONFIG_KALLSYMS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
# CONFIG_FUTEX is not set
# CONFIG_EPOLL is not set
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_CC_ALIGN_LOOPS=0
CONFIG_CC_ALIGN_JUMPS=0
# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
#
# Loadable module support
# CONFIG_PLAT_OPSPUT is not set
# CONFIG_PLAT_OAKS32R is not set
# CONFIG_PLAT_MAPPI2 is not set
+# CONFIG_PLAT_MAPPI3 is not set
CONFIG_CHIP_M32700=y
# CONFIG_CHIP_M32102 is not set
# CONFIG_CHIP_VDEC2 is not set
#
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_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=y
-# CONFIG_SERIO_I8042 is not set
-CONFIG_SERIO_SERPORT=y
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_LIBPS2 is not set
-# CONFIG_SERIO_RAW is not set
-
#
# Input Device Drivers
#
# CONFIG_INPUT_TOUCHSCREEN is not set
# CONFIG_INPUT_MISC is not set
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_LIBPS2 is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
#
# Character devices
#
# CONFIG_SYNCLINK_CS is not set
# CONFIG_RAW_DRIVER is not set
+#
+# TPM devices
+#
+
#
# I2C support
#
# Graphics support
#
CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_SOFT_CURSOR is not set
+# CONFIG_FB_MACMODES is not set
# CONFIG_FB_MODE_HELPERS is not set
# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
# CONFIG_FB_VIRTUAL is not set
#
# 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
#
#
# Kernel hacking
#
+# CONFIG_PRINTK_TIME is not set
# CONFIG_DEBUG_KERNEL is not set
-CONFIG_DEBUG_PREEMPT=y
+CONFIG_LOG_BUF_SHIFT=14
# CONFIG_DEBUG_BUGVERBOSE is not set
# CONFIG_FRAME_POINTER is not set
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.11-rc4
-# Wed Feb 16 21:10:57 2005
+# Linux kernel version: 2.6.12-rc5
+# Fri Jun 3 16:21:46 2005
#
CONFIG_M32R=y
# CONFIG_UID16 is not set
CONFIG_CLEAN_COMPILE=y
CONFIG_BROKEN_ON_SMP=y
CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
#
# General setup
# CONFIG_BSD_PROCESS_ACCT_V3 is not set
CONFIG_SYSCTL=y
# CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
CONFIG_HOTPLUG=y
CONFIG_KOBJECT_UEVENT=y
CONFIG_IKCONFIG=y
# CONFIG_IKCONFIG_PROC is not set
CONFIG_EMBEDDED=y
# CONFIG_KALLSYMS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
# CONFIG_FUTEX is not set
# CONFIG_EPOLL is not set
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_CC_ALIGN_LOOPS=0
CONFIG_CC_ALIGN_JUMPS=0
CONFIG_TINY_SHMEM=y
+CONFIG_BASE_SMALL=0
#
# Loadable module support
# CONFIG_PLAT_OPSPUT is not set
# CONFIG_PLAT_OAKS32R is not set
# CONFIG_PLAT_MAPPI2 is not set
+# CONFIG_PLAT_MAPPI3 is not set
CONFIG_CHIP_M32700=y
# CONFIG_CHIP_M32102 is not set
# CONFIG_CHIP_VDEC2 is not set
#
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_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=y
-# CONFIG_SERIO_I8042 is not set
-CONFIG_SERIO_SERPORT=y
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_LIBPS2 is not set
-# CONFIG_SERIO_RAW is not set
-
#
# Input Device Drivers
#
# CONFIG_INPUT_TOUCHSCREEN is not set
# CONFIG_INPUT_MISC is not set
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_LIBPS2 is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
#
# Character devices
#
# CONFIG_SYNCLINK_CS is not set
# CONFIG_RAW_DRIVER is not set
+#
+# TPM devices
+#
+
#
# I2C 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
#
#
# Kernel hacking
#
+# CONFIG_PRINTK_TIME is not set
# CONFIG_DEBUG_KERNEL is not set
-CONFIG_DEBUG_PREEMPT=y
+CONFIG_LOG_BUF_SHIFT=14
# CONFIG_DEBUG_BUGVERBOSE is not set
# CONFIG_FRAME_POINTER is not set
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.11-rc4
-# Wed Feb 16 21:11:02 2005
+# Linux kernel version: 2.6.12-rc5
+# Fri Jun 3 16:21:52 2005
#
CONFIG_M32R=y
# CONFIG_UID16 is not set
CONFIG_BROKEN=y
CONFIG_BROKEN_ON_SMP=y
CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
#
# General setup
# CONFIG_BSD_PROCESS_ACCT is not set
CONFIG_SYSCTL=y
# CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=15
CONFIG_HOTPLUG=y
CONFIG_KOBJECT_UEVENT=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
+# CONFIG_CPUSETS is not set
CONFIG_EMBEDDED=y
# CONFIG_KALLSYMS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
# CONFIG_FUTEX is not set
# CONFIG_EPOLL is not set
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_CC_ALIGN_LOOPS=0
CONFIG_CC_ALIGN_JUMPS=0
# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
#
# Loadable module support
# CONFIG_PLAT_OPSPUT is not set
# CONFIG_PLAT_OAKS32R is not set
# CONFIG_PLAT_MAPPI2 is not set
+# CONFIG_PLAT_MAPPI3 is not set
CONFIG_CHIP_M32700=y
# CONFIG_CHIP_M32102 is not set
# CONFIG_CHIP_VDEC2 is not set
#
CONFIG_MTD=y
# CONFIG_MTD_DEBUG is not set
-CONFIG_MTD_PARTITIONS=y
# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_REDBOOT_PARTS=y
CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
# Networking options
#
# CONFIG_PACKET is not set
-# CONFIG_NETLINK_DEV is not set
CONFIG_UNIX=y
# CONFIG_NET_KEY is not set
CONFIG_INET=y
# 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=y
-# CONFIG_SERIO_I8042 is not set
-# CONFIG_SERIO_SERPORT is not set
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_LIBPS2 is not set
-# CONFIG_SERIO_RAW is not set
-
#
# Input Device Drivers
#
# CONFIG_INPUT_TOUCHSCREEN is not set
# CONFIG_INPUT_MISC is not set
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_LIBPS2 is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
#
# Character devices
#
# CONFIG_SYNCLINK_CS is not set
# CONFIG_RAW_DRIVER is not set
+#
+# TPM devices
+#
+
#
# I2C 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
#
#
# Kernel hacking
#
+# CONFIG_PRINTK_TIME is not set
# CONFIG_DEBUG_KERNEL is not set
-CONFIG_DEBUG_PREEMPT=y
+CONFIG_LOG_BUF_SHIFT=15
# CONFIG_DEBUG_BUGVERBOSE is not set
# CONFIG_FRAME_POINTER is not set
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.11-rc4
-# Wed Feb 16 21:11:07 2005
+# Linux kernel version: 2.6.12-rc5
+# Fri Jun 3 16:21:59 2005
#
CONFIG_M32R=y
# CONFIG_UID16 is not set
CONFIG_BROKEN=y
CONFIG_BROKEN_ON_SMP=y
CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
#
# General setup
# CONFIG_BSD_PROCESS_ACCT is not set
CONFIG_SYSCTL=y
# CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
CONFIG_HOTPLUG=y
CONFIG_KOBJECT_UEVENT=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_EMBEDDED=y
# CONFIG_KALLSYMS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
# CONFIG_FUTEX is not set
# CONFIG_EPOLL is not set
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_CC_ALIGN_LOOPS=0
CONFIG_CC_ALIGN_JUMPS=0
# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
#
# Loadable module support
# CONFIG_PLAT_OPSPUT is not set
# CONFIG_PLAT_OAKS32R is not set
# CONFIG_PLAT_MAPPI2 is not set
+# CONFIG_PLAT_MAPPI3 is not set
CONFIG_CHIP_M32700=y
# CONFIG_CHIP_M32102 is not set
# CONFIG_CHIP_VDEC2 is not set
#
CONFIG_MTD=y
# CONFIG_MTD_DEBUG is not set
-CONFIG_MTD_PARTITIONS=y
# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_REDBOOT_PARTS=y
CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
# Networking options
#
# CONFIG_PACKET is not set
-# CONFIG_NETLINK_DEV is not set
CONFIG_UNIX=y
# CONFIG_NET_KEY is not set
CONFIG_INET=y
# 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=y
-# CONFIG_SERIO_I8042 is not set
-# CONFIG_SERIO_SERPORT is not set
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_LIBPS2 is not set
-# CONFIG_SERIO_RAW is not set
-
#
# Input Device Drivers
#
# CONFIG_INPUT_TOUCHSCREEN is not set
# CONFIG_INPUT_MISC is not set
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_LIBPS2 is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
#
# Character devices
#
# CONFIG_SYNCLINK_CS is not set
# CONFIG_RAW_DRIVER is not set
+#
+# TPM devices
+#
+
#
# I2C 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
#
#
# Kernel hacking
#
+# CONFIG_PRINTK_TIME is not set
# CONFIG_DEBUG_KERNEL is not set
-CONFIG_DEBUG_PREEMPT=y
+CONFIG_LOG_BUF_SHIFT=14
# CONFIG_DEBUG_BUGVERBOSE is not set
# CONFIG_FRAME_POINTER is not set
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.11-rc4
-# Wed Feb 16 21:11:10 2005
+# Linux kernel version: 2.6.12-rc5
+# Fri Jun 3 16:22:02 2005
#
CONFIG_M32R=y
# CONFIG_UID16 is not set
CONFIG_CLEAN_COMPILE=y
CONFIG_BROKEN_ON_SMP=y
CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
#
# General setup
# CONFIG_BSD_PROCESS_ACCT_V3 is not set
CONFIG_SYSCTL=y
# CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
CONFIG_HOTPLUG=y
CONFIG_KOBJECT_UEVENT=y
CONFIG_IKCONFIG=y
# CONFIG_IKCONFIG_PROC is not set
CONFIG_EMBEDDED=y
# CONFIG_KALLSYMS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
# CONFIG_FUTEX is not set
# CONFIG_EPOLL is not set
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_CC_ALIGN_LOOPS=0
CONFIG_CC_ALIGN_JUMPS=0
# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
#
# Loadable module support
# CONFIG_PLAT_OPSPUT is not set
# CONFIG_PLAT_OAKS32R is not set
CONFIG_PLAT_MAPPI2=y
+# CONFIG_PLAT_MAPPI3 is not set
# CONFIG_CHIP_M32700 is not set
# CONFIG_CHIP_M32102 is not set
CONFIG_CHIP_VDEC2=y
#
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_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=y
-# CONFIG_SERIO_I8042 is not set
-CONFIG_SERIO_SERPORT=y
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_LIBPS2 is not set
-# CONFIG_SERIO_RAW is not set
-
#
# Input Device Drivers
#
# CONFIG_INPUT_TOUCHSCREEN is not set
# CONFIG_INPUT_MISC is not set
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_LIBPS2 is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
#
# Character devices
#
# CONFIG_SYNCLINK_CS is not set
# CONFIG_RAW_DRIVER is not set
+#
+# TPM devices
+#
+
#
# I2C 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
#
#
# Kernel hacking
#
+# CONFIG_PRINTK_TIME is not set
# CONFIG_DEBUG_KERNEL is not set
-CONFIG_DEBUG_PREEMPT=y
+CONFIG_LOG_BUF_SHIFT=14
# CONFIG_DEBUG_BUGVERBOSE is not set
# CONFIG_FRAME_POINTER is not set
--- /dev/null
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.12-rc5
+# Tue May 31 17:55:34 2005
+#
+CONFIG_M32R=y
+# CONFIG_UID16 is not set
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+# CONFIG_CLEAN_COMPILE is not set
+CONFIG_BROKEN=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# 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=y
+CONFIG_IKCONFIG_PROC=y
+# CONFIG_CPUSETS is not set
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
+# CONFIG_FUTEX is not set
+# 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
+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 type and features
+#
+# CONFIG_PLAT_MAPPI is not set
+# CONFIG_PLAT_USRV is not set
+# CONFIG_PLAT_M32700UT is not set
+# CONFIG_PLAT_OPSPUT is not set
+# CONFIG_PLAT_OAKS32R is not set
+# CONFIG_PLAT_MAPPI2 is not set
+CONFIG_PLAT_MAPPI3=y
+CONFIG_CHIP_M32700=y
+# CONFIG_CHIP_M32102 is not set
+# CONFIG_CHIP_VDEC2 is not set
+# CONFIG_CHIP_OPSP is not set
+CONFIG_MMU=y
+CONFIG_TLB_ENTRIES=32
+CONFIG_ISA_M32R2=y
+CONFIG_ISA_DSP_LEVEL2=y
+CONFIG_ISA_DUAL_ISSUE=y
+CONFIG_BUS_CLOCK=10000000
+CONFIG_TIMER_DIVIDE=128
+# CONFIG_CPU_LITTLE_ENDIAN is not set
+CONFIG_MEMORY_START=0x08000000
+CONFIG_MEMORY_SIZE=0x08000000
+CONFIG_NOHIGHMEM=y
+CONFIG_DISCONTIGMEM=y
+CONFIG_IRAM_START=0x00f00000
+CONFIG_IRAM_SIZE=0x00080000
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_PREEMPT=y
+# CONFIG_HAVE_DEC_LOCK is not set
+CONFIG_SMP=y
+# CONFIG_CHIP_M32700_TS1 is not set
+CONFIG_NR_CPUS=2
+# CONFIG_NUMA is not set
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+# CONFIG_PCI is not set
+# CONFIG_ISA is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+CONFIG_PCCARD=y
+# CONFIG_PCMCIA_DEBUG is not set
+CONFIG_PCMCIA=y
+
+#
+# PC-card bridges
+#
+# CONFIG_TCIC is not set
+# CONFIG_M32R_PCC is not set
+# CONFIG_M32R_CFC is not set
+
+#
+# PCI Hotplug Support
+#
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+
+#
+# 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=y
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
+# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
+# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE 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_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+
+#
+# Self-contained MTD device drivers
+#
+# 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_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_BLK_DEV_IDECS=y
+CONFIG_BLK_DEV_IDECD=m
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+# CONFIG_IDE_ARM is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD 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
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_PACKET is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE 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=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
+CONFIG_SMC91X=y
+# CONFIG_NE2000 is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# PCMCIA network device support
+#
+# CONFIG_NET_PCMCIA 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=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=y
+# CONFIG_SERIO_I8042 is not set
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_LIBPS2 is not set
+# CONFIG_SERIO_RAW 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_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_M32R_SIO=y
+CONFIG_SERIAL_M32R_SIO_CONSOLE=y
+# CONFIG_SERIAL_M32R_PLDSIO is not set
+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_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_DRM is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_SYNCLINK_CS is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+
+#
+# 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 is not set
+# CONFIG_USB_ARCH_HAS_OHCI 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=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=y
+# 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_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
+# CONFIG_HUGETLBFS 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=y
+CONFIG_JFFS_FS_VERBOSE=0
+CONFIG_JFFS_PROC_FS=y
+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=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
+
+#
+# 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_DEBUG_BUGVERBOSE is not set
+# CONFIG_FRAME_POINTER 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
+#
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
--- /dev/null
+# .gdbinit file
+# $Id: dot.gdbinit,v 1.1 2005/04/11 02:21:08 sakugawa Exp $
+
+# setting
+set width 0d70
+set radix 0d16
+use_debug_dma
+
+# Initialize SDRAM controller for Mappi
+define sdram_init
+ # SDIR0
+ set *(unsigned long *)0x00ef6008 = 0x00000182
+ # SDIR1
+ set *(unsigned long *)0x00ef600c = 0x00000001
+ # Initialize wait
+ shell sleep 0.1
+ # MOD
+ set *(unsigned long *)0x00ef602c = 0x00000020
+ set *(unsigned long *)0x00ef604c = 0x00000020
+ # TR
+ set *(unsigned long *)0x00ef6028 = 0x00051502
+ set *(unsigned long *)0x00ef6048 = 0x00051502
+ # ADR
+ set *(unsigned long *)0x00ef6020 = 0x08000004
+ set *(unsigned long *)0x00ef6040 = 0x0c000004
+ # AutoRef On
+ set *(unsigned long *)0x00ef6004 = 0x00010517
+ # Access enable
+ set *(unsigned long *)0x00ef6024 = 0x00000001
+ set *(unsigned long *)0x00ef6044 = 0x00000001
+end
+
+# Initialize LAN controller for Mappi
+define lanc_init
+ # Set BSEL4
+ #set *(unsigned long *)0x00ef5004 = 0x0fff330f
+ #set *(unsigned long *)0x00ef5004 = 0x01113301
+
+# set *(unsigned long *)0x00ef5004 = 0x02011101
+# set *(unsigned long *)0x00ef5004 = 0x04441104
+end
+
+define clock_init
+ set *(unsigned long *)0x00ef4010 = 2
+ set *(unsigned long *)0x00ef4014 = 2
+ set *(unsigned long *)0x00ef4020 = 3
+ set *(unsigned long *)0x00ef4024 = 3
+ set *(unsigned long *)0x00ef4004 = 0x7
+# shell sleep 0.1
+# set *(unsigned long *)0x00ef4004 = 0x5
+ shell sleep 0.1
+ set *(unsigned long *)0x00ef4008 = 0x0200
+end
+
+define port_init
+ set $sfrbase = 0x00ef0000
+ set *(unsigned short *)0x00ef1060 = 0x5555
+ set *(unsigned short *)0x00ef1062 = 0x5555
+ set *(unsigned short *)0x00ef1064 = 0x5555
+ set *(unsigned short *)0x00ef1066 = 0x5555
+ set *(unsigned short *)0x00ef1068 = 0x5555
+ set *(unsigned short *)0x00ef106a = 0x0000
+ set *(unsigned short *)0x00ef106e = 0x5555
+ set *(unsigned short *)0x00ef1070 = 0x5555
+end
+
+# MMU enable
+define mmu_enable
+ set $evb=0x88000000
+ set *(unsigned long *)0xffff0024=1
+end
+
+# MMU disable
+define mmu_disable
+ set $evb=0
+ set *(unsigned long *)0xffff0024=0
+end
+
+# Show TLB entries
+define show_tlb_entries
+ set $i = 0
+ set $addr = $arg0
+ while ($i < 0d16 )
+ set $tlb_tag = *(unsigned long*)$addr
+ set $tlb_data = *(unsigned long*)($addr + 4)
+ printf " [%2d] 0x%08lx : 0x%08lx - 0x%08lx\n", $i, $addr, $tlb_tag, $tlb_data
+ set $i = $i + 1
+ set $addr = $addr + 8
+ end
+end
+define itlb
+ set $itlb=0xfe000000
+ show_tlb_entries $itlb
+end
+define dtlb
+ set $dtlb=0xfe000800
+ show_tlb_entries $dtlb
+end
+
+# Cache ON
+define set_cache_type
+ set $mctype = (void*)0xfffffff8
+# chaos
+# set *(unsigned long *)($mctype) = 0x0000c000
+# m32102 i-cache only
+ set *(unsigned long *)($mctype) = 0x00008000
+# m32102 d-cache only
+# set *(unsigned long *)($mctype) = 0x00004000
+end
+define cache_on
+ set $param = (void*)0x08001000
+ set *(unsigned long *)($param) = 0x60ff6102
+end
+
+
+# Show current task structure
+define show_current
+ set $current = $spi & 0xffffe000
+ printf "$current=0x%08lX\n",$current
+ print *(struct task_struct *)$current
+end
+
+# Show user assigned task structure
+define show_task
+ set $task = $arg0 & 0xffffe000
+ printf "$task=0x%08lX\n",$task
+ print *(struct task_struct *)$task
+end
+document show_task
+ Show user assigned task structure
+ arg0 : task structure address
+end
+
+# Show M32R registers
+define show_regs
+ printf " R0[0x%08lX] R1[0x%08lX] R2[0x%08lX] R3[0x%08lX]\n",$r0,$r1,$r2,$r3
+ printf " R4[0x%08lX] R5[0x%08lX] R6[0x%08lX] R7[0x%08lX]\n",$r4,$r5,$r6,$r7
+ printf " R8[0x%08lX] R9[0x%08lX] R10[0x%08lX] R11[0x%08lX]\n",$r8,$r9,$r10,$r11
+ printf "R12[0x%08lX] FP[0x%08lX] LR[0x%08lX] SP[0x%08lX]\n",$r12,$fp,$lr,$sp
+ printf "PSW[0x%08lX] CBR[0x%08lX] SPI[0x%08lX] SPU[0x%08lX]\n",$psw,$cbr,$spi,$spu
+ printf "BPC[0x%08lX] PC[0x%08lX] ACCL[0x%08lX] ACCH[0x%08lX]\n",$bpc,$pc,$accl,$acch
+ printf "EVB[0x%08lX]\n",$evb
+
+ set $mests = *(unsigned long *)0xffff000c
+ set $mdeva = *(unsigned long *)0xffff0010
+ printf "MESTS[0x%08lX] MDEVA[0x%08lX]\n",$mests,$mdeva
+end
+
+
+# Setup all
+define setup
+ clock_init
+ shell sleep 0.1
+ port_init
+ sdram_init
+# lanc_init
+# dispc_init
+# set $evb=0x08000000
+end
+
+# Load modules
+define load_modules
+ use_debug_dma
+ load
+# load busybox.mot
+end
+
+# Set kernel parameters
+define set_kernel_parameters
+ set $param = (void*)0x08001000
+
+ ## MOUNT_ROOT_RDONLY
+ set {long}($param+0x00)=0
+ ## RAMDISK_FLAGS
+ #set {long}($param+0x04)=0
+ ## ORIG_ROOT_DEV
+ #set {long}($param+0x08)=0x00000100
+ ## LOADER_TYPE
+ #set {long}($param+0x0C)=0
+ ## INITRD_START
+ set {long}($param+0x10)=0x082a0000
+ ## INITRD_SIZE
+ set {long}($param+0x14)=0d6200000
+
+ # M32R_CPUCLK
+ set *(unsigned long *)($param + 0x0018) = 0d100000000
+ # M32R_BUSCLK
+ set *(unsigned long *)($param + 0x001c) = 0d50000000
+ # M32R_TIMER_DIVIDE
+ set *(unsigned long *)($param + 0x0020) = 0d128
+
+
+ set {char[0x200]}($param + 0x100) = "console=ttyS0,115200n8x root=/dev/nfsroot nfsroot=192.168.0.1:/project/m32r-linux/export/root.2.6_04 nfsaddrs=192.168.0.102:192.168.0.1:192.168.0.1:255.255.255.0:mappi: \0"
+
+
+end
+
+# Boot
+define boot
+ set_kernel_parameters
+ debug_chaos
+ set *(unsigned long *)0x00f00000=0x08002000
+ set $pc=0x08002000
+ set $fp=0
+ del b
+ si
+end
+
+# Restart
+define restart
+ sdireset
+ sdireset
+ setup
+ load_modules
+ boot
+end
+
+sdireset
+sdireset
+file vmlinux
+target m32rsdi
+
+restart
+boot
/*
- * linux/arch/i386/mm/extable.c
+ * linux/arch/m32r/mm/extable.c
*/
-#include <linux/config.h>
#include <linux/module.h>
-#include <linux/spinlock.h>
#include <asm/uaccess.h>
int fixup_exception(struct pt_regs *regs)
return 0;
}
-
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.11-rc4
-# Wed Feb 16 21:11:13 2005
+# Linux kernel version: 2.6.12-rc5
+# Fri Jun 3 16:22:04 2005
#
CONFIG_M32R=y
# CONFIG_UID16 is not set
CONFIG_CLEAN_COMPILE=y
CONFIG_BROKEN_ON_SMP=y
CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
#
# General setup
# CONFIG_BSD_PROCESS_ACCT_V3 is not set
CONFIG_SYSCTL=y
# CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
CONFIG_HOTPLUG=y
CONFIG_KOBJECT_UEVENT=y
# CONFIG_IKCONFIG is not set
CONFIG_EMBEDDED=y
# CONFIG_KALLSYMS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
# CONFIG_FUTEX is not set
# CONFIG_EPOLL is not set
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_CC_ALIGN_LOOPS=0
CONFIG_CC_ALIGN_JUMPS=0
CONFIG_TINY_SHMEM=y
+CONFIG_BASE_SMALL=0
#
# Loadable module support
# CONFIG_PLAT_OPSPUT is not set
CONFIG_PLAT_OAKS32R=y
# CONFIG_PLAT_MAPPI2 is not set
+# CONFIG_PLAT_MAPPI3 is not set
# CONFIG_CHIP_M32700 is not set
CONFIG_CHIP_M32102=y
# CONFIG_CHIP_VDEC2 is not set
#
# CONFIG_PCCARD is not set
-#
-# PC-card bridges
-#
-
#
# PCI Hotplug Support
#
#
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_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=y
-# CONFIG_SERIO_I8042 is not set
-CONFIG_SERIO_SERPORT=y
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_LIBPS2 is not set
-# CONFIG_SERIO_RAW is not set
-
#
# Input Device Drivers
#
# CONFIG_INPUT_TOUCHSCREEN is not set
# CONFIG_INPUT_MISC is not set
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_LIBPS2 is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
#
# Character devices
#
# CONFIG_DRM is not set
# CONFIG_RAW_DRIVER is not set
+#
+# TPM devices
+#
+
#
# I2C 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
#
#
# Kernel hacking
#
+# CONFIG_PRINTK_TIME is not set
# CONFIG_DEBUG_KERNEL is not set
-CONFIG_DEBUG_PREEMPT=y
+CONFIG_LOG_BUF_SHIFT=14
# CONFIG_DEBUG_BUGVERBOSE is not set
# CONFIG_FRAME_POINTER is not set
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.11-rc4
-# Wed Feb 16 21:11:41 2005
+# Linux kernel version: 2.6.12-rc5
+# Fri Jun 3 16:22:06 2005
#
CONFIG_M32R=y
# CONFIG_UID16 is not set
CONFIG_EXPERIMENTAL=y
CONFIG_CLEAN_COMPILE=y
CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
#
# General setup
# CONFIG_BSD_PROCESS_ACCT_V3 is not set
CONFIG_SYSCTL=y
# CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
CONFIG_HOTPLUG=y
CONFIG_KOBJECT_UEVENT=y
CONFIG_IKCONFIG=y
# CONFIG_IKCONFIG_PROC is not set
CONFIG_EMBEDDED=y
# CONFIG_KALLSYMS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
# CONFIG_FUTEX is not set
# CONFIG_EPOLL is not set
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_CC_ALIGN_LOOPS=0
CONFIG_CC_ALIGN_JUMPS=0
# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
#
# Loadable module support
CONFIG_PLAT_OPSPUT=y
# CONFIG_PLAT_OAKS32R is not set
# CONFIG_PLAT_MAPPI2 is not set
+# CONFIG_PLAT_MAPPI3 is not set
# CONFIG_CHIP_M32700 is not set
# CONFIG_CHIP_M32102 is not set
# CONFIG_CHIP_VDEC2 is not set
#
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_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=y
-# CONFIG_SERIO_I8042 is not set
-CONFIG_SERIO_SERPORT=y
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_LIBPS2 is not set
-# CONFIG_SERIO_RAW is not set
-
#
# Input Device Drivers
#
# CONFIG_INPUT_TOUCHSCREEN is not set
# CONFIG_INPUT_MISC is not set
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_LIBPS2 is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
#
# Character devices
#
# CONFIG_SYNCLINK_CS is not set
# CONFIG_RAW_DRIVER is not set
+#
+# TPM devices
+#
+
#
# I2C 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
#
#
# Kernel hacking
#
+# CONFIG_PRINTK_TIME is not set
CONFIG_DEBUG_KERNEL=y
# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_LOG_BUF_SHIFT=14
# CONFIG_SCHEDSTATS is not set
# CONFIG_DEBUG_SLAB is not set
# CONFIG_DEBUG_SPINLOCK is not set
#ifdef CONFIG_LIMITED_DMA
set_page_address(page, lowmem_page_address(page));
#endif
- set_bit(PG_highmem, &page->flags);
set_page_count(page, 1);
__free_page(page);
totalhigh_pages++;
depends on PCORE || POWERPMC250 || LOPEC || SANDPOINT
default y
-config FSL_OCP
- bool
- depends on MPC10X_BRIDGE
- default y
-
config MPC10X_OPENPIC
bool
depends on POWERPMC250 || LOPEC || SANDPOINT
*(.ramdisk)
__ramdisk_end = .;
. = ALIGN(4096);
- __sysmap_begin = .;
- *(.sysmap)
- __sysmap_end = .;
CONSTRUCTORS
}
_edata = .;
@echo ' RAM disk image must be provided separately'
@/bin/false
-objcpxmon-$(CONFIG_XMON) := --add-section=.sysmap=System.map \
- --set-section-flags=.sysmap=contents,alloc,load,readonly,data
quiet_cmd_genimage = GEN $@
cmd_genimage = $(OBJCOPY) -R .comment \
--add-section=.image=$(images)/vmlinux.gz \
- --set-section-flags=.image=contents,alloc,load,readonly,data \
- $(objcpxmon-y) $< $@
+ --set-section-flags=.image=contents,alloc,load,readonly,data $< $@
targets += image.o
$(obj)/image.o: $(obj)/dummy.o $(images)/vmlinux.gz FORCE
#include <asm/page.h>
/* Information from the linker */
-extern char __sysmap_begin, __sysmap_end;
extern int strcmp(const char *s1, const char *s2);
extern char *avail_ram, *avail_high;
void make_bi_recs(unsigned long addr, char *name, unsigned int mach,
unsigned long progend)
{
- unsigned long sysmap_size;
struct bi_record *rec;
- /* Figure out the size of a possible System.map we're going to
- * pass along.
- * */
- sysmap_size = (unsigned long)(&__sysmap_end) -
- (unsigned long)(&__sysmap_begin);
/* leave a 1MB gap then align to the next 1MB boundary */
addr = _ALIGN(addr+ (1<<20) - 1, (1<<20));
rec->size = sizeof(struct bi_record) + 2 * sizeof(unsigned long);
rec = (struct bi_record *)((unsigned long)rec + rec->size);
- if (sysmap_size) {
- rec->tag = BI_SYSMAP;
- rec->data[0] = (unsigned long)(&__sysmap_begin);
- rec->data[1] = sysmap_size;
- rec->size = sizeof(struct bi_record) + 2 *
- sizeof(unsigned long);
- rec = (struct bi_record *)((unsigned long)rec + rec->size);
- }
-
rec->tag = BI_LAST;
rec->size = sizeof(struct bi_record);
rec = (struct bi_record *)((unsigned long)rec + rec->size);
$(obj)/dummy.o $(obj)/image.o
$(LD) $(LD_ARGS) -o $@ $(OBJS) $(obj)/image.o $(LIBS)
$(OBJCOPY) $(OBJCOPY_ARGS) $@ $@ -R .comment -R .stab \
- -R .stabstr -R .ramdisk -R .sysmap
+ -R .stabstr -R .ramdisk
$(obj)/zvmlinux.initrd: $(OBJS) $(LIBS) $(srctree)/$(boot)/ld.script \
$(images)/vmlinux.gz $(obj)/dummy.o
$(obj)/dummy.o $(obj)/image.o
$(LD) $(LD_ARGS) -o $@ $(OBJS) $(obj)/image.o $(LIBS)
$(OBJCOPY) $(OBJCOPY_ARGS) $@ $@ -R .comment -R .stab \
- -R .stabstr -R .sysmap
+ -R .stabstr
# Sort-of dummy rules, that let us format the image we want.
zImage: $(images)/$(zimage-y) $(obj)/zvmlinux
+++ /dev/null
-#include <stdio.h>
-#include <stdlib.h>
-#include <byteswap.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-void xlate( char * inb, char * trb, unsigned len )
-{
- unsigned i;
- for ( i=0; i<len; ++i ) {
- char c = *inb++;
- char c1 = c >> 4;
- char c2 = c & 0xf;
- if ( c1 > 9 )
- c1 = c1 + 'A' - 10;
- else
- c1 = c1 + '0';
- if ( c2 > 9 )
- c2 = c2 + 'A' - 10;
- else
- c2 = c2 + '0';
- *trb++ = c1;
- *trb++ = c2;
- }
- *trb = 0;
-}
-
-#define ElfHeaderSize (64 * 1024)
-#define ElfPages (ElfHeaderSize / 4096)
-#define KERNELBASE (0xc0000000)
-
-void get4k( /*istream *inf*/FILE *file, char *buf )
-{
- unsigned j;
- unsigned num = fread(buf, 1, 4096, file);
- for ( j=num; j<4096; ++j )
- buf[j] = 0;
-}
-
-void put4k( /*ostream *outf*/FILE *file, char *buf )
-{
- fwrite(buf, 1, 4096, file);
-}
-
-int main(int argc, char **argv)
-{
- char inbuf[4096];
- FILE *ramDisk = NULL;
- FILE *inputVmlinux = NULL;
- FILE *outputVmlinux = NULL;
- unsigned i = 0;
- unsigned long ramFileLen = 0;
- unsigned long ramLen = 0;
- unsigned long roundR = 0;
- unsigned long kernelLen = 0;
- unsigned long actualKernelLen = 0;
- unsigned long round = 0;
- unsigned long roundedKernelLen = 0;
- unsigned long ramStartOffs = 0;
- unsigned long ramPages = 0;
- unsigned long roundedKernelPages = 0;
- if ( argc < 2 ) {
- printf("Name of System Map file missing.\n");
- exit(1);
- }
-
- if ( argc < 3 ) {
- printf("Name of vmlinux file missing.\n");
- exit(1);
- }
-
- if ( argc < 4 ) {
- printf("Name of vmlinux output file missing.\n");
- exit(1);
- }
-
- ramDisk = fopen(argv[1], "r");
- if ( ! ramDisk ) {
- printf("System Map file \"%s\" failed to open.\n", argv[1]);
- exit(1);
- }
- inputVmlinux = fopen(argv[2], "r");
- if ( ! inputVmlinux ) {
- printf("vmlinux file \"%s\" failed to open.\n", argv[2]);
- exit(1);
- }
- outputVmlinux = fopen(argv[3], "w");
- if ( ! outputVmlinux ) {
- printf("output vmlinux file \"%s\" failed to open.\n", argv[3]);
- exit(1);
- }
- fseek(ramDisk, 0, SEEK_END);
- ramFileLen = ftell(ramDisk);
- fseek(ramDisk, 0, SEEK_SET);
- printf("%s file size = %ld\n", argv[1], ramFileLen);
-
- ramLen = ramFileLen;
-
- roundR = 4096 - (ramLen % 4096);
- if ( roundR ) {
- printf("Rounding System Map file up to a multiple of 4096, adding %ld\n", roundR);
- ramLen += roundR;
- }
-
- printf("Rounded System Map size is %ld\n", ramLen);
- fseek(inputVmlinux, 0, SEEK_END);
- kernelLen = ftell(inputVmlinux);
- fseek(inputVmlinux, 0, SEEK_SET);
- printf("kernel file size = %ld\n", kernelLen);
- if ( kernelLen == 0 ) {
- printf("You must have a linux kernel specified as argv[2]\n");
- exit(1);
- }
-
- actualKernelLen = kernelLen - ElfHeaderSize;
-
- printf("actual kernel length (minus ELF header) = %ld\n", actualKernelLen);
-
- round = actualKernelLen % 4096;
- roundedKernelLen = actualKernelLen;
- if ( round )
- roundedKernelLen += (4096 - round);
-
- printf("actual kernel length rounded up to a 4k multiple = %ld\n", roundedKernelLen);
-
- ramStartOffs = roundedKernelLen;
- ramPages = ramLen / 4096;
-
- printf("System map pages to copy = %ld\n", ramPages);
-
- // Copy 64K ELF header
- for (i=0; i<(ElfPages); ++i) {
- get4k( inputVmlinux, inbuf );
- put4k( outputVmlinux, inbuf );
- }
-
-
-
- roundedKernelPages = roundedKernelLen / 4096;
-
- fseek(inputVmlinux, ElfHeaderSize, SEEK_SET);
-
- {
- for ( i=0; i<roundedKernelPages; ++i ) {
- get4k( inputVmlinux, inbuf );
- if ( i == 0 ) {
- unsigned long * p;
- printf("Storing embedded_sysmap_start at 0x3c\n");
- p = (unsigned long *)(inbuf + 0x3c);
-
-#if (BYTE_ORDER == __BIG_ENDIAN)
- *p = ramStartOffs;
-#else
- *p = bswap_32(ramStartOffs);
-#endif
-
- printf("Storing embedded_sysmap_end at 0x44\n");
- p = (unsigned long *)(inbuf + 0x44);
-#if (BYTE_ORDER == __BIG_ENDIAN)
- *p = ramStartOffs + ramFileLen;
-#else
- *p = bswap_32(ramStartOffs + ramFileLen);
-#endif
- }
- put4k( outputVmlinux, inbuf );
- }
- }
-
- {
- for ( i=0; i<ramPages; ++i ) {
- get4k( ramDisk, inbuf );
- put4k( outputVmlinux, inbuf );
- }
- }
-
-
- fclose(ramDisk);
- fclose(inputVmlinux);
- fclose(outputVmlinux);
- /* Set permission to executable */
- chmod(argv[3], S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
-
- return 0;
-
-}
-
--- /dev/null
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.12-rc4
+# Tue May 24 22:36:27 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
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# 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 is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
+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
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# Processor
+#
+# CONFIG_6xx is not set
+# 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=y
+CONFIG_BOOKE=y
+CONFIG_FSL_BOOKE=y
+# CONFIG_PHYS_64BIT is not set
+CONFIG_SPE=y
+CONFIG_MATH_EMULATION=y
+# CONFIG_CPU_FREQ is not set
+# CONFIG_PM is not set
+CONFIG_85xx=y
+CONFIG_PPC_INDIRECT_PCI_BE=y
+
+#
+# Freescale 85xx options
+#
+# CONFIG_MPC8540_ADS is not set
+CONFIG_MPC8548_CDS=y
+# CONFIG_MPC8555_CDS is not set
+# CONFIG_MPC8560_ADS is not set
+# CONFIG_SBC8560 is not set
+# CONFIG_STX_GP3 is not set
+CONFIG_MPC8548=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
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+# CONFIG_PCI is not set
+# CONFIG_PCI_DOMAINS is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# 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_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=y
+
+#
+# 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 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=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
+
+#
+# TPM devices
+#
+
+#
+# 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_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 is not set
+# CONFIG_SENSORS_LM92 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_DS1337 is not set
+# 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
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI 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=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_PRINTK_TIME is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
.dcache_bsize = 32,
.num_pmcs = 4,
},
+ { /* e500v2 */
+ .pvr_mask = 0xffff0000,
+ .pvr_value = 0x80210000,
+ .cpu_name = "e500v2",
+ /* xxx - galak: add CPU_FTR_MAYBE_CAN_DOZE */
+ .cpu_features = CPU_FTR_SPLIT_ID_CACHE |
+ CPU_FTR_USE_TB | CPU_FTR_BIG_PHYS,
+ .cpu_user_features = PPC_FEATURE_32 |
+ PPC_FEATURE_HAS_MMU | PPC_FEATURE_SPE_COMP |
+ PPC_FEATURE_HAS_EFP_SINGLE | PPC_FEATURE_HAS_EFP_DOUBLE,
+ .icache_bsize = 32,
+ .dcache_bsize = 32,
+ .num_pmcs = 4,
+ },
#endif
#if !CLASSIC_PPC
{ /* default match */
#ifdef CONFIG_BOOKE
#include "head_booke.h"
+#define TRANSFER_TO_HANDLER_EXC_LEVEL(exc_level) \
+ mtspr exc_level##_SPRG,r8; \
+ BOOKE_LOAD_EXC_LEVEL_STACK(exc_level); \
+ lwz r0,GPR10-INT_FRAME_SIZE(r8); \
+ stw r0,GPR10(r11); \
+ lwz r0,GPR11-INT_FRAME_SIZE(r8); \
+ stw r0,GPR11(r11); \
+ mfspr r8,exc_level##_SPRG
+
.globl mcheck_transfer_to_handler
mcheck_transfer_to_handler:
- mtspr MCHECK_SPRG,r8
- BOOKE_LOAD_MCHECK_STACK
- lwz r0,GPR10-INT_FRAME_SIZE(r8)
- stw r0,GPR10(r11)
- lwz r0,GPR11-INT_FRAME_SIZE(r8)
- stw r0,GPR11(r11)
- mfspr r8,MCHECK_SPRG
+ TRANSFER_TO_HANDLER_EXC_LEVEL(MCHECK)
b transfer_to_handler_full
.globl crit_transfer_to_handler
crit_transfer_to_handler:
- mtspr CRIT_SPRG,r8
- BOOKE_LOAD_CRIT_STACK
- lwz r0,GPR10-INT_FRAME_SIZE(r8)
- stw r0,GPR10(r11)
- lwz r0,GPR11-INT_FRAME_SIZE(r8)
- stw r0,GPR11(r11)
- mfspr r8,CRIT_SPRG
+ TRANSFER_TO_HANDLER_EXC_LEVEL(CRIT)
/* fall through */
#endif
* time of the critical interrupt.
*
*/
- .globl ret_from_crit_exc
-ret_from_crit_exc:
- REST_NVGPRS(r1)
- lwz r3,_MSR(r1)
- andi. r3,r3,MSR_PR
- LOAD_MSR_KERNEL(r10,MSR_KERNEL)
- bne user_exc_return
-
- lwz r0,GPR0(r1)
- lwz r2,GPR2(r1)
- REST_4GPRS(3, r1)
- REST_2GPRS(7, r1)
-
- lwz r10,_XER(r1)
- lwz r11,_CTR(r1)
- mtspr SPRN_XER,r10
- mtctr r11
-
- PPC405_ERR77(0,r1)
- stwcx. r0,0,r1 /* to clear the reservation */
-
- lwz r11,_LINK(r1)
- mtlr r11
- lwz r10,_CCR(r1)
- mtcrf 0xff,r10
#ifdef CONFIG_40x
- /* avoid any possible TLB misses here by turning off MSR.DR, we
- * assume the instructions here are mapped by a pinned TLB entry */
- li r10,MSR_IR
- mtmsr r10
- isync
- tophys(r1, r1)
+#define PPC_40x_TURN_OFF_MSR_DR \
+ /* avoid any possible TLB misses here by turning off MSR.DR, we \
+ * assume the instructions here are mapped by a pinned TLB entry */ \
+ li r10,MSR_IR; \
+ mtmsr r10; \
+ isync; \
+ tophys(r1, r1);
+#else
+#define PPC_40x_TURN_OFF_MSR_DR
#endif
- lwz r9,_DEAR(r1)
- lwz r10,_ESR(r1)
- mtspr SPRN_DEAR,r9
- mtspr SPRN_ESR,r10
- lwz r11,_NIP(r1)
- lwz r12,_MSR(r1)
- mtspr SPRN_CSRR0,r11
- mtspr SPRN_CSRR1,r12
- lwz r9,GPR9(r1)
- lwz r12,GPR12(r1)
- lwz r10,GPR10(r1)
- lwz r11,GPR11(r1)
- lwz r1,GPR1(r1)
- PPC405_ERR77_SYNC
- rfci
- b . /* prevent prefetch past rfci */
+
+#define RET_FROM_EXC_LEVEL(exc_lvl_srr0, exc_lvl_srr1, exc_lvl_rfi) \
+ REST_NVGPRS(r1); \
+ lwz r3,_MSR(r1); \
+ andi. r3,r3,MSR_PR; \
+ LOAD_MSR_KERNEL(r10,MSR_KERNEL); \
+ bne user_exc_return; \
+ lwz r0,GPR0(r1); \
+ lwz r2,GPR2(r1); \
+ REST_4GPRS(3, r1); \
+ REST_2GPRS(7, r1); \
+ lwz r10,_XER(r1); \
+ lwz r11,_CTR(r1); \
+ mtspr SPRN_XER,r10; \
+ mtctr r11; \
+ PPC405_ERR77(0,r1); \
+ stwcx. r0,0,r1; /* to clear the reservation */ \
+ lwz r11,_LINK(r1); \
+ mtlr r11; \
+ lwz r10,_CCR(r1); \
+ mtcrf 0xff,r10; \
+ PPC_40x_TURN_OFF_MSR_DR; \
+ lwz r9,_DEAR(r1); \
+ lwz r10,_ESR(r1); \
+ mtspr SPRN_DEAR,r9; \
+ mtspr SPRN_ESR,r10; \
+ lwz r11,_NIP(r1); \
+ lwz r12,_MSR(r1); \
+ mtspr exc_lvl_srr0,r11; \
+ mtspr exc_lvl_srr1,r12; \
+ lwz r9,GPR9(r1); \
+ lwz r12,GPR12(r1); \
+ lwz r10,GPR10(r1); \
+ lwz r11,GPR11(r1); \
+ lwz r1,GPR1(r1); \
+ PPC405_ERR77_SYNC; \
+ exc_lvl_rfi; \
+ b .; /* prevent prefetch past exc_lvl_rfi */
+
+ .globl ret_from_crit_exc
+ret_from_crit_exc:
+ RET_FROM_EXC_LEVEL(SPRN_CSRR0, SPRN_CSRR1, RFCI)
#ifdef CONFIG_BOOKE
-/*
- * Return from a machine check interrupt, similar to a critical
- * interrupt.
- */
.globl ret_from_mcheck_exc
ret_from_mcheck_exc:
- REST_NVGPRS(r1)
- lwz r3,_MSR(r1)
- andi. r3,r3,MSR_PR
- LOAD_MSR_KERNEL(r10,MSR_KERNEL)
- bne user_exc_return
-
- lwz r0,GPR0(r1)
- lwz r2,GPR2(r1)
- REST_4GPRS(3, r1)
- REST_2GPRS(7, r1)
-
- lwz r10,_XER(r1)
- lwz r11,_CTR(r1)
- mtspr SPRN_XER,r10
- mtctr r11
-
- stwcx. r0,0,r1 /* to clear the reservation */
-
- lwz r11,_LINK(r1)
- mtlr r11
- lwz r10,_CCR(r1)
- mtcrf 0xff,r10
- lwz r9,_DEAR(r1)
- lwz r10,_ESR(r1)
- mtspr SPRN_DEAR,r9
- mtspr SPRN_ESR,r10
- lwz r11,_NIP(r1)
- lwz r12,_MSR(r1)
- mtspr SPRN_MCSRR0,r11
- mtspr SPRN_MCSRR1,r12
- lwz r9,GPR9(r1)
- lwz r12,GPR12(r1)
- lwz r10,GPR10(r1)
- lwz r11,GPR11(r1)
- lwz r1,GPR1(r1)
- RFMCI
+ RET_FROM_EXC_LEVEL(SPRN_MCSRR0, SPRN_MCSRR1, RFMCI)
#endif /* CONFIG_BOOKE */
/*
/* If we are faulting a kernel address, we have to use the
* kernel page tables.
*/
- andis. r11, r10, 0x8000
- beq 3f
+ lis r11, TASK_SIZE@h
+ cmplw r10, r11
+ blt+ 3f
lis r11, swapper_pg_dir@h
ori r11, r11, swapper_pg_dir@l
li r9, 0
/* If we are faulting a kernel address, we have to use the
* kernel page tables.
*/
- andis. r11, r10, 0x8000
- beq 3f
+ lis r11, TASK_SIZE@h
+ cmplw r10, r11
+ blt+ 3f
lis r11, swapper_pg_dir@h
ori r11, r11, swapper_pg_dir@l
li r9, 0
/* If we are faulting a kernel address, we have to use the
* kernel page tables.
*/
- andis. r11, r10, 0x8000
- beq 3f
+ lis r11, TASK_SIZE@h
+ cmplw r10, r11
+ blt+ 3f
lis r11, swapper_pg_dir@h
ori r11, r11, swapper_pg_dir@l
li r9, 0
#define CRIT_STACK_TOP (exception_stack_top)
#ifdef CONFIG_SMP
-#define BOOKE_LOAD_CRIT_STACK \
+#define BOOKE_LOAD_EXC_LEVEL_STACK(level) \
mfspr r8,SPRN_PIR; \
mulli r8,r8,BOOKE_EXCEPTION_STACK_SIZE; \
neg r8,r8; \
- addis r8,r8,CRIT_STACK_TOP@ha; \
- addi r8,r8,CRIT_STACK_TOP@l
-#define BOOKE_LOAD_MCHECK_STACK \
- mfspr r8,SPRN_PIR; \
- mulli r8,r8,BOOKE_EXCEPTION_STACK_SIZE; \
- neg r8,r8; \
- addis r8,r8,MCHECK_STACK_TOP@ha; \
- addi r8,r8,MCHECK_STACK_TOP@l
+ addis r8,r8,level##_STACK_TOP@ha; \
+ addi r8,r8,level##_STACK_TOP@l
#else
-#define BOOKE_LOAD_CRIT_STACK \
- lis r8,CRIT_STACK_TOP@h; \
- ori r8,r8,CRIT_STACK_TOP@l
-#define BOOKE_LOAD_MCHECK_STACK \
- lis r8,MCHECK_STACK_TOP@h; \
- ori r8,r8,MCHECK_STACK_TOP@l
+#define BOOKE_LOAD_EXC_LEVEL_STACK(level) \
+ lis r8,level##_STACK_TOP@h; \
+ ori r8,r8,level##_STACK_TOP@l
#endif
/*
- * Exception prolog for critical exceptions. This is a little different
- * from the normal exception prolog above since a critical exception
- * can potentially occur at any point during normal exception processing.
- * Thus we cannot use the same SPRG registers as the normal prolog above.
- * Instead we use a portion of the critical exception stack at low physical
- * addresses.
+ * Exception prolog for critical/machine check exceptions. This is a
+ * little different from the normal exception prolog above since a
+ * critical/machine check exception can potentially occur at any point
+ * during normal exception processing. Thus we cannot use the same SPRG
+ * registers as the normal prolog above. Instead we use a portion of the
+ * critical/machine check exception stack at low physical addresses.
*/
-
-#define CRITICAL_EXCEPTION_PROLOG \
- mtspr CRIT_SPRG,r8; \
- BOOKE_LOAD_CRIT_STACK; /* r8 points to the crit stack */ \
+#define EXC_LEVEL_EXCEPTION_PROLOG(exc_level, exc_level_srr0, exc_level_srr1) \
+ mtspr exc_level##_SPRG,r8; \
+ BOOKE_LOAD_EXC_LEVEL_STACK(exc_level);/* r8 points to the exc_level stack*/ \
stw r10,GPR10-INT_FRAME_SIZE(r8); \
stw r11,GPR11-INT_FRAME_SIZE(r8); \
mfcr r10; /* save CR in r10 for now */\
- mfspr r11,SPRN_CSRR1; /* check whether user or kernel */\
+ mfspr r11,exc_level_srr1; /* check whether user or kernel */\
andi. r11,r11,MSR_PR; \
mr r11,r8; \
- mfspr r8,CRIT_SPRG; \
+ mfspr r8,exc_level##_SPRG; \
beq 1f; \
/* COMING FROM USER MODE */ \
mfspr r11,SPRN_SPRG3; /* if from user, start at top of */\
stw r12,_DEAR(r11); /* since they may have had stuff */\
mfspr r9,SPRN_ESR; /* in them at the point where the */\
stw r9,_ESR(r11); /* exception was taken */\
- mfspr r12,SPRN_CSRR0; \
+ mfspr r12,exc_level_srr0; \
stw r1,GPR1(r11); \
- mfspr r9,SPRN_CSRR1; \
+ mfspr r9,exc_level_srr1; \
stw r1,0(r11); \
mr r1,r11; \
rlwinm r9,r9,0,14,12; /* clear MSR_WE (necessary?) */\
SAVE_4GPRS(3, r11); \
SAVE_2GPRS(7, r11)
-/*
- * Exception prolog for machine check exceptions. This is similar to
- * the critical exception prolog, except that machine check exceptions
- * have their stack.
- */
-#define MCHECK_EXCEPTION_PROLOG \
- mtspr MCHECK_SPRG,r8; \
- BOOKE_LOAD_MCHECK_STACK; /* r8 points to the mcheck stack */\
- stw r10,GPR10-INT_FRAME_SIZE(r8); \
- stw r11,GPR11-INT_FRAME_SIZE(r8); \
- mfcr r10; /* save CR in r10 for now */\
- mfspr r11,SPRN_MCSRR1; /* check whether user or kernel */\
- andi. r11,r11,MSR_PR; \
- mr r11,r8; \
- mfspr r8,MCHECK_SPRG; \
- beq 1f; \
- /* COMING FROM USER MODE */ \
- mfspr r11,SPRN_SPRG3; /* if from user, start at top of */\
- lwz r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\
- addi r11,r11,THREAD_SIZE; \
-1: subi r11,r11,INT_FRAME_SIZE; /* Allocate an exception frame */\
- stw r10,_CCR(r11); /* save various registers */\
- stw r12,GPR12(r11); \
- stw r9,GPR9(r11); \
- mflr r10; \
- stw r10,_LINK(r11); \
- mfspr r12,SPRN_DEAR; /* save DEAR and ESR in the frame */\
- stw r12,_DEAR(r11); /* since they may have had stuff */\
- mfspr r9,SPRN_ESR; /* in them at the point where the */\
- stw r9,_ESR(r11); /* exception was taken */\
- mfspr r12,SPRN_MCSRR0; \
- stw r1,GPR1(r11); \
- mfspr r9,SPRN_MCSRR1; \
- stw r1,0(r11); \
- mr r1,r11; \
- rlwinm r9,r9,0,14,12; /* clear MSR_WE (necessary?) */\
- stw r0,GPR0(r11); \
- SAVE_4GPRS(3, r11); \
- SAVE_2GPRS(7, r11)
+#define CRITICAL_EXCEPTION_PROLOG \
+ EXC_LEVEL_EXCEPTION_PROLOG(CRIT, SPRN_CSRR0, SPRN_CSRR1)
+#define MCHECK_EXCEPTION_PROLOG \
+ EXC_LEVEL_EXCEPTION_PROLOG(MCHECK, SPRN_MCSRR0, SPRN_MCSRR1)
/*
* Exception vectors.
EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, COPY_EE, transfer_to_handler, \
ret_from_except)
-
/* Check for a single step debug exception while in an exception
* handler before state has been saved. This is to catch the case
* where an instruction that we are trying to single step causes
lwz r9,GPR9(r11); \
lwz r12,GPR12(r11); \
mtspr CRIT_SPRG,r8; \
- BOOKE_LOAD_CRIT_STACK; /* r8 points to the crit stack */ \
+ BOOKE_LOAD_EXC_LEVEL_STACK(CRIT); /* r8 points to the debug stack */ \
lwz r10,GPR10-INT_FRAME_SIZE(r8); \
lwz r11,GPR11-INT_FRAME_SIZE(r8); \
mfspr r8,CRIT_SPRG; \
#include <asm/xmon.h>
#include <asm/ocp.h>
-#if defined(CONFIG_85xx) || defined(CONFIG_83xx)
+#if defined(CONFIG_85xx) || defined(CONFIG_83xx) || defined(CONFIG_MPC10X_BRIDGE)
#include <asm/ppc_sys.h>
#endif
extern boot_infos_t *boot_infos;
struct ide_machdep_calls ppc_ide_md;
-char *sysmap;
-unsigned long sysmap_size;
/* Used with the BI_MEMSIZE bootinfo parameter to store the memory
size value reported by the boot loader. */
seq_printf(m, "bogomips\t: %lu.%02lu\n",
lpj / (500000/HZ), (lpj / (5000/HZ)) % 100);
-#if defined(CONFIG_85xx) || defined(CONFIG_83xx)
+#if defined(CONFIG_85xx) || defined(CONFIG_83xx) || defined(CONFIG_MPC10X_BRIDGE)
if (cur_ppc_sys_spec->ppc_sys_name)
seq_printf(m, "chipset\t\t: %s\n",
cur_ppc_sys_spec->ppc_sys_name);
case BI_CMD_LINE:
strlcpy(cmd_line, (void *)data, sizeof(cmd_line));
break;
- case BI_SYSMAP:
- sysmap = (char *)((data[0] >= (KERNELBASE)) ? data[0] :
- (data[0]+KERNELBASE));
- sysmap_size = data[1];
- break;
#ifdef CONFIG_BLK_DEV_INITRD
case BI_INITRD:
initrd_start = data[0] + KERNELBASE;
console_verbose();
spin_lock_irq(&die_lock);
#ifdef CONFIG_PMAC_BACKLIGHT
- set_backlight_enable(1);
- set_backlight_level(BACKLIGHT_MAX);
+ if (_machine == _MACH_Pmac) {
+ set_backlight_enable(1);
+ set_backlight_level(BACKLIGHT_MAX);
+ }
#endif
printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter);
#ifdef CONFIG_PREEMPT
while (!read_can_lock(rw)) {
if (--stuck == 0) {
printk("_read_lock(%p) CPU#%d lock %d\n",
- rw, _smp_processor_id(), rw->lock);
+ rw, raw_smp_processor_id(), rw->lock);
stuck = INIT_STUCK;
}
}
while (!write_can_lock(rw)) {
if (--stuck == 0) {
printk("write_lock(%p) CPU#%d lock %d)\n",
- rw, _smp_processor_id(), rw->lock);
+ rw, raw_smp_processor_id(), rw->lock);
stuck = INIT_STUCK;
}
}
extern unsigned long __max_low_memory;
#define MAX_LOW_MEM CONFIG_LOWMEM_SIZE
+#define NUM_TLBCAMS (16)
+
struct tlbcam {
u32 MAS0;
u32 MAS1;
char *klimit = _end;
struct mem_pieces phys_avail;
-extern char *sysmap;
-extern unsigned long sysmap_size;
-
/*
* this tells the system to map all of ram with the segregs
* (i.e. page tables) instead of the bats.
if (agp_special_page)
SetPageReserved(virt_to_page(agp_special_page));
#endif
- if ( sysmap )
- for (addr = (unsigned long)sysmap;
- addr < PAGE_ALIGN((unsigned long)sysmap+sysmap_size) ;
- addr += PAGE_SIZE)
- SetPageReserved(virt_to_page(addr));
-
for (addr = PAGE_OFFSET; addr < (unsigned long)high_memory;
addr += PAGE_SIZE) {
if (!PageReserved(virt_to_page(addr)))
struct page *page = mem_map + pfn;
ClearPageReserved(page);
- set_bit(PG_highmem, &page->flags);
set_page_count(page, 1);
__free_page(page);
totalhigh_pages++;
codepages<< (PAGE_SHIFT-10), datapages<< (PAGE_SHIFT-10),
initpages<< (PAGE_SHIFT-10),
(unsigned long) (totalhigh_pages << (PAGE_SHIFT-10)));
- if (sysmap)
- printk("System.map loaded at 0x%08x for debugger, size: %ld bytes\n",
- (unsigned int)sysmap, sysmap_size);
+
#ifdef CONFIG_PPC_PMAC
if (agp_special_page)
printk(KERN_INFO "AGP special page: 0x%08lx\n", agp_special_page);
if (rtas_data)
mem_pieces_remove(&phys_avail, rtas_data, rtas_size, 1);
#endif
- /* remove the sysmap pages from the available memory */
- if (sysmap)
- mem_pieces_remove(&phys_avail, __pa(sysmap), sysmap_size, 1);
#ifdef CONFIG_PPC_PMAC
/* Because of some uninorth weirdness, we need a page of
* memory as high as possible (it must be outside of the
extern PTE *Hash, *Hash_end;
extern unsigned long Hash_size, Hash_mask;
+extern unsigned int num_tlbcam_entries;
+
/* ...and now those things that may be slightly different between processor
* architectures. -- Dan
*/
#ifdef HAVE_TLBCAM
extern unsigned int tlbcam_index;
-extern unsigned int num_tlbcam_entries;
extern unsigned long v_mapped_by_tlbcam(unsigned long va);
extern unsigned long p_mapped_by_tlbcam(unsigned long pa);
#else /* !HAVE_TLBCAM */
#include <asm/time.h>
#include <asm/io.h>
#include <asm/machdep.h>
-#include <asm/prom.h>
#include <asm/ipic.h>
#include <asm/bootinfo.h>
#include <asm/pci-bridge.h>
ipic_set_default_priority();
}
+#if defined(CONFIG_I2C_MPC) && defined(CONFIG_SENSORS_DS1374)
+extern ulong ds1374_get_rtc_time(void);
+extern int ds1374_set_rtc_time(ulong);
+
+static int __init
+mpc834x_rtc_hookup(void)
+{
+ struct timespec tv;
+
+ ppc_md.get_rtc_time = ds1374_get_rtc_time;
+ ppc_md.set_rtc_time = ds1374_set_rtc_time;
+
+ tv.tv_nsec = 0;
+ tv.tv_sec = (ppc_md.get_rtc_time)();
+ do_settimeofday(&tv);
+
+ return 0;
+}
+late_initcall(mpc834x_rtc_hookup);
+#endif
static __inline__ void
mpc834x_sys_set_bat(void)
{
help
This option enables support for the MPC 8540 ADS evaluation board.
+config MPC8548_CDS
+ bool "Freescale MPC8548 CDS"
+ help
+ This option enablese support for the MPC8548 CDS evaluation board.
+
config MPC8555_CDS
bool "Freescale MPC8555 CDS"
help
depends on MPC8540_ADS
default y
+config MPC8548
+ bool
+ depends on MPC8548_CDS
+ default y
+
config MPC8555
bool
depends on MPC8555_CDS
# Makefile for the PowerPC 85xx linux kernel.
#
obj-$(CONFIG_MPC8540_ADS) += mpc85xx_ads_common.o mpc8540_ads.o
+obj-$(CONFIG_MPC8548_CDS) += mpc85xx_cds_common.o
obj-$(CONFIG_MPC8555_CDS) += mpc85xx_cds_common.o
obj-$(CONFIG_MPC8560_ADS) += mpc85xx_ads_common.o mpc8560_ads.o
obj-$(CONFIG_SBC8560) += sbc85xx.o sbc8560.o
#include <asm/time.h>
#include <asm/io.h>
#include <asm/machdep.h>
-#include <asm/prom.h>
#include <asm/open_pic.h>
#include <asm/bootinfo.h>
#include <asm/pci-bridge.h>
#ifdef CONFIG_SERIAL_TEXT_DEBUG
/* Invalidate the entry we stole earlier the serial ports
* should be properly mapped */
- invalidate_tlbcam_entry(NUM_TLBCAMS - 1);
+ invalidate_tlbcam_entry(num_tlbcam_entries - 1);
#endif
/* setup the board related information for the enet controllers */
struct uart_port p;
/* Use the last TLB entry to map CCSRBAR to allow access to DUART regs */
- settlbcam(NUM_TLBCAMS - 1, binfo->bi_immr_base,
+ settlbcam(num_tlbcam_entries - 1, binfo->bi_immr_base,
binfo->bi_immr_base, MPC85xx_CCSRBAR_SIZE, _PAGE_IO, 0);
memset(&p, 0, sizeof (p));
#include <asm/time.h>
#include <asm/io.h>
#include <asm/machdep.h>
-#include <asm/prom.h>
#include <asm/open_pic.h>
#include <asm/bootinfo.h>
#include <asm/pci-bridge.h>
#include <asm/time.h>
#include <asm/io.h>
#include <asm/machdep.h>
-#include <asm/prom.h>
#include <asm/open_pic.h>
#include <asm/bootinfo.h>
#include <asm/pci-bridge.h>
unsigned char __res[sizeof (bd_t)];
/* Internal interrupts are all Level Sensitive, and Positive Polarity */
-
static u_char mpc85xx_ads_openpic_initsenses[] __initdata = {
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 0: L2 Cache */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 1: ECM */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 2: DDR DRAM */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 3: LBIU */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 4: DMA 0 */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 5: DMA 1 */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 6: DMA 2 */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 7: DMA 3 */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 8: PCI/PCI-X */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 9: RIO Inbound Port Write Error */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 10: RIO Doorbell Inbound */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 11: RIO Outbound Message */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 12: RIO Inbound Message */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 13: TSEC 0 Transmit */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 14: TSEC 0 Receive */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 15: Unused */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 16: Unused */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 17: Unused */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 18: TSEC 0 Receive/Transmit Error */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 19: TSEC 1 Transmit */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 20: TSEC 1 Receive */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 21: Unused */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 22: Unused */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 23: Unused */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 24: TSEC 1 Receive/Transmit Error */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 25: Fast Ethernet */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 26: DUART */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 27: I2C */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 28: Performance Monitor */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 29: Unused */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 30: CPM */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 31: Unused */
+ MPC85XX_INTERNAL_IRQ_SENSES,
0x0, /* External 0: */
#if defined(CONFIG_PCI)
(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 1: PCI slot 0 */
/* Skip reserved space and internal sources */
openpic_set_sources(0, 32, OpenPIC_Addr + 0x10200);
/* Map PIC IRQs 0-11 */
- openpic_set_sources(32, 12, OpenPIC_Addr + 0x10000);
+ openpic_set_sources(48, 12, OpenPIC_Addr + 0x10000);
/* we let openpic interrupts starting from an offset, to
* leave space for cascading interrupts underneath.
#include <asm/todc.h>
#include <asm/io.h>
#include <asm/machdep.h>
-#include <asm/prom.h>
#include <asm/open_pic.h>
#include <asm/i8259.h>
#include <asm/bootinfo.h>
static volatile u8 * cadmus;
/* Internal interrupts are all Level Sensitive, and Positive Polarity */
-
static u_char mpc85xx_cds_openpic_initsenses[] __initdata = {
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 0: L2 Cache */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 1: ECM */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 2: DDR DRAM */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 3: LBIU */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 4: DMA 0 */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 5: DMA 1 */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 6: DMA 2 */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 7: DMA 3 */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 8: PCI/PCI-X */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 9: RIO Inbound Port Write Error */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 10: RIO Doorbell Inbound */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 11: RIO Outbound Message */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 12: RIO Inbound Message */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 13: TSEC 0 Transmit */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 14: TSEC 0 Receive */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 15: Unused */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 16: Unused */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 17: Unused */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 18: TSEC 0 Receive/Transmit Error */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 19: TSEC 1 Transmit */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 20: TSEC 1 Receive */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 21: Unused */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 22: Unused */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 23: Unused */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 24: TSEC 1 Receive/Transmit Error */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 25: Fast Ethernet */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 26: DUART */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 27: I2C */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 28: Performance Monitor */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 29: Unused */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 30: CPM */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 31: Unused */
+ MPC85XX_INTERNAL_IRQ_SENSES,
#if defined(CONFIG_PCI)
(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 0: PCI1 slot */
(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 1: PCI1 slot */
mpc85xx_cds_init_IRQ(void)
{
bd_t *binfo = (bd_t *) __res;
- int i;
/* Determine the Physical Address of the OpenPIC regs */
phys_addr_t OpenPIC_PAddr = binfo->bi_immr_base + MPC85xx_OPENPIC_OFFSET;
OpenPIC_NumInitSenses = sizeof (mpc85xx_cds_openpic_initsenses);
/* Skip reserved space and internal sources */
+#ifdef CONFIG_MPC8548
+ openpic_set_sources(0, 48, OpenPIC_Addr + 0x10200);
+#else
openpic_set_sources(0, 32, OpenPIC_Addr + 0x10200);
+#endif
/* Map PIC IRQs 0-11 */
- openpic_set_sources(32, 12, OpenPIC_Addr + 0x10000);
+ openpic_set_sources(48, 12, OpenPIC_Addr + 0x10000);
/* we let openpic interrupts starting from an offset, to
* leave space for cascading interrupts underneath.
#ifdef CONFIG_SERIAL_TEXT_DEBUG
/* Invalidate the entry we stole earlier the serial ports
* should be properly mapped */
- invalidate_tlbcam_entry(NUM_TLBCAMS - 1);
+ invalidate_tlbcam_entry(num_tlbcam_entries - 1);
#endif
/* setup the board related information for the enet controllers */
pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1);
- pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
- pdata->interruptPHY = MPC85xx_IRQ_EXT5;
- pdata->phyid = 0;
- /* fixup phy address */
- pdata->phy_reg_addr += binfo->bi_immr_base;
- memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
+ if (pdata) {
+ pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
+ pdata->interruptPHY = MPC85xx_IRQ_EXT5;
+ pdata->phyid = 0;
+ /* fixup phy address */
+ pdata->phy_reg_addr += binfo->bi_immr_base;
+ memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
+ }
pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC2);
- pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
- pdata->interruptPHY = MPC85xx_IRQ_EXT5;
- pdata->phyid = 1;
- /* fixup phy address */
- pdata->phy_reg_addr += binfo->bi_immr_base;
- memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
+ if (pdata) {
+ pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
+ pdata->interruptPHY = MPC85xx_IRQ_EXT5;
+ pdata->phyid = 1;
+ /* fixup phy address */
+ pdata->phy_reg_addr += binfo->bi_immr_base;
+ memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
+ }
+
+ pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_eTSEC1);
+ if (pdata) {
+ pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
+ pdata->interruptPHY = MPC85xx_IRQ_EXT5;
+ pdata->phyid = 0;
+ /* fixup phy address */
+ pdata->phy_reg_addr += binfo->bi_immr_base;
+ memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
+ }
+
+ pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_eTSEC2);
+ if (pdata) {
+ pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
+ pdata->interruptPHY = MPC85xx_IRQ_EXT5;
+ pdata->phyid = 1;
+ /* fixup phy address */
+ pdata->phy_reg_addr += binfo->bi_immr_base;
+ memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
+ }
+ ppc_sys_device_remove(MPC85xx_eTSEC3);
+ ppc_sys_device_remove(MPC85xx_eTSEC4);
#ifdef CONFIG_BLK_DEV_INITRD
if (initrd_start)
struct uart_port p;
/* Use the last TLB entry to map CCSRBAR to allow access to DUART regs */
- settlbcam(NUM_TLBCAMS - 1, binfo->bi_immr_base,
+ settlbcam(num_tlbcam_entries - 1, binfo->bi_immr_base,
binfo->bi_immr_base, MPC85xx_CCSRBAR_SIZE, _PAGE_IO, 0);
memset(&p, 0, sizeof (p));
#include <asm/time.h>
#include <asm/io.h>
#include <asm/machdep.h>
-#include <asm/prom.h>
#include <asm/open_pic.h>
#include <asm/bootinfo.h>
#include <asm/pci-bridge.h>
#ifdef CONFIG_SERIAL_TEXT_DEBUG
/* Invalidate the entry we stole earlier the serial ports
* should be properly mapped */
- invalidate_tlbcam_entry(NUM_TLBCAMS - 1);
+ invalidate_tlbcam_entry(num_tlbcam_entries - 1);
#endif
/* setup the board related information for the enet controllers */
#ifdef CONFIG_SERIAL_TEXT_DEBUG
/* Use the last TLB entry to map CCSRBAR to allow access to DUART regs */
- settlbcam(NUM_TLBCAMS - 1, UARTA_ADDR,
+ settlbcam(num_tlbcam_entries - 1, UARTA_ADDR,
UARTA_ADDR, 0x1000, _PAGE_IO, 0);
#endif
#include <asm/time.h>
#include <asm/io.h>
#include <asm/machdep.h>
-#include <asm/prom.h>
#include <asm/open_pic.h>
#include <asm/bootinfo.h>
#include <asm/pci-bridge.h>
extern unsigned long total_memory; /* in mm/init */
/* Internal interrupts are all Level Sensitive, and Positive Polarity */
-
static u_char sbc8560_openpic_initsenses[] __initdata = {
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 0: L2 Cache */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 1: ECM */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 2: DDR DRAM */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 3: LBIU */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 4: DMA 0 */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 5: DMA 1 */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 6: DMA 2 */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 7: DMA 3 */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 8: PCI/PCI-X */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 9: RIO Inbound Port Write Error */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 10: RIO Doorbell Inbound */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 11: RIO Outbound Message */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 12: RIO Inbound Message */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 13: TSEC 0 Transmit */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 14: TSEC 0 Receive */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 15: Unused */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 16: Unused */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 17: Unused */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 18: TSEC 0 Receive/Transmit Error */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 19: TSEC 1 Transmit */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 20: TSEC 1 Receive */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 21: Unused */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 22: Unused */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 23: Unused */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 24: TSEC 1 Receive/Transmit Error */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 25: Fast Ethernet */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 26: DUART */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 27: I2C */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 28: Performance Monitor */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 29: Unused */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 30: CPM */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 31: Unused */
+ MPC85XX_INTERNAL_IRQ_SENSES,
0x0, /* External 0: */
0x0, /* External 1: */
#if defined(CONFIG_PCI)
/* Skip reserved space and internal sources */
openpic_set_sources(0, 32, OpenPIC_Addr + 0x10200);
/* Map PIC IRQs 0-11 */
- openpic_set_sources(32, 12, OpenPIC_Addr + 0x10000);
+ openpic_set_sources(48, 12, OpenPIC_Addr + 0x10000);
/* we let openpic interrupts starting from an offset, to
* leave space for cascading interrupts underneath.
#include <asm/time.h>
#include <asm/io.h>
#include <asm/machdep.h>
-#include <asm/prom.h>
#include <asm/open_pic.h>
#include <asm/bootinfo.h>
#include <asm/pci-bridge.h>
/* Internal interrupts are all Level Sensitive, and Positive Polarity */
static u8 gp3_openpic_initsenses[] __initdata = {
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 0: L2 Cache */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 1: ECM */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 2: DDR DRAM */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 3: LBIU */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 4: DMA 0 */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 5: DMA 1 */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 6: DMA 2 */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 7: DMA 3 */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 8: PCI/PCI-X */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 9: RIO Inbound Port Write Error */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 10: RIO Doorbell Inbound */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 11: RIO Outbound Message */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 12: RIO Inbound Message */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 13: TSEC 0 Transmit */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 14: TSEC 0 Receive */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 15: Unused */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 16: Unused */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 17: Unused */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 18: TSEC 0 Receive/Transmit Error */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 19: TSEC 1 Transmit */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 20: TSEC 1 Receive */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 21: Unused */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 22: Unused */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 23: Unused */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 24: TSEC 1 Receive/Transmit Error */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 25: Fast Ethernet */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 26: DUART */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 27: I2C */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 28: Performance Monitor */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 29: Unused */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 30: CPM */
- (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 31: Unused */
+ MPC85XX_INTERNAL_IRQ_SENSES,
0x0, /* External 0: */
#if defined(CONFIG_PCI)
(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 1: PCI slot 0 */
static void __init
gp3_init_IRQ(void)
{
- int i;
bd_t *binfo = (bd_t *) __res;
/*
openpic_set_sources(0, 32, OpenPIC_Addr + 0x10200);
/* Map PIC IRQs 0-11 */
- openpic_set_sources(32, 12, OpenPIC_Addr + 0x10000);
+ openpic_set_sources(48, 12, OpenPIC_Addr + 0x10000);
/*
* Let openpic interrupts starting from an offset, to
#include <linux/serial.h>
#include <linux/tty.h> /* for linux/serial_core.h */
#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
#include <asm/system.h>
#include <asm/pgtable.h>
#include <asm/mpc10x.h>
#include <asm/pci-bridge.h>
#include <asm/kgdb.h>
+#include <asm/ppc_sys.h>
#include "sandpoint.h"
/* Lookup PCI host bridges */
sandpoint_find_bridges();
+ if (strncmp (cur_ppc_sys_spec->ppc_sys_name, "8245", 4) == 0)
+ {
+ bd_t *bp = (bd_t *)__res;
+ struct plat_serial8250_port *pdata;
+ pdata = (struct plat_serial8250_port *) ppc_sys_get_pdata(MPC10X_DUART);
+
+ if (pdata)
+ {
+ pdata[0].uartclk = bp->bi_busfreq;
+ pdata[0].membase = ioremap(pdata[0].mapbase, 0x100);
+
+ /* this disables the 2nd serial port on the DUART
+ * since the sandpoint does not have it connected */
+ pdata[1].uartclk = 0;
+ pdata[1].irq = 0;
+ pdata[1].mapbase = 0;
+ }
+
printk(KERN_INFO "Motorola SPS Sandpoint Test Platform\n");
printk(KERN_INFO "Port by MontaVista Software, Inc. (source@mvista.com)\n");
obj-$(CONFIG_SERIAL_TEXT_DEBUG) += mv64x60_dbg.o
endif
obj-$(CONFIG_BOOTX_TEXT) += btext.o
-obj-$(CONFIG_MPC10X_BRIDGE) += mpc10x_common.o indirect_pci.o
+obj-$(CONFIG_MPC10X_BRIDGE) += mpc10x_common.o indirect_pci.o ppc_sys.o
obj-$(CONFIG_MPC10X_OPENPIC) += open_pic.o
obj-$(CONFIG_40x) += dcr.o
obj-$(CONFIG_BOOKE) += dcr.o
ifeq ($(CONFIG_83xx),y)
obj-$(CONFIG_PCI) += indirect_pci.o pci_auto.o
endif
+obj-$(CONFIG_MPC8548_CDS) += todc_time.o
obj-$(CONFIG_MPC8555_CDS) += todc_time.o
obj-$(CONFIG_PPC_MPC52xx) += mpc52xx_setup.o mpc52xx_pic.o \
mpc52xx_sys.o mpc52xx_devices.o ppc_sys.o
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/slab.h>
+#include <linux/serial_8250.h>
+#include <linux/fsl_devices.h>
+#include <linux/device.h>
#include <asm/byteorder.h>
#include <asm/io.h>
#include <asm/pci-bridge.h>
#include <asm/open_pic.h>
#include <asm/mpc10x.h>
-#include <asm/ocp.h>
-
-/* The OCP structure is fixed by code below, before OCP initialises.
- paddr depends on where the board places the EUMB.
- - fixed in mpc10x_bridge_init().
- irq depends on two things:
- > does the board use the EPIC at all? (PCORE does not).
- > is the EPIC in serial or parallel mode?
- - fixed in mpc10x_set_openpic().
-*/
+#include <asm/ppc_sys.h>
#ifdef CONFIG_MPC10X_OPENPIC
#ifdef CONFIG_EPIC_SERIAL_MODE
#define MPC10X_I2C_IRQ (EPIC_IRQ_BASE + NUM_8259_INTERRUPTS)
#define MPC10X_DMA0_IRQ (EPIC_IRQ_BASE + 1 + NUM_8259_INTERRUPTS)
#define MPC10X_DMA1_IRQ (EPIC_IRQ_BASE + 2 + NUM_8259_INTERRUPTS)
+#define MPC10X_UART0_IRQ (EPIC_IRQ_BASE + 4 + NUM_8259_INTERRUPTS)
#else
-#define MPC10X_I2C_IRQ OCP_IRQ_NA
-#define MPC10X_DMA0_IRQ OCP_IRQ_NA
-#define MPC10X_DMA1_IRQ OCP_IRQ_NA
+#define MPC10X_I2C_IRQ -1
+#define MPC10X_DMA0_IRQ -1
+#define MPC10X_DMA1_IRQ -1
+#define MPC10X_UART0_IRQ -1
#endif
-
-struct ocp_def core_ocp[] = {
- { .vendor = OCP_VENDOR_INVALID
- }
+static struct fsl_i2c_platform_data mpc10x_i2c_pdata = {
+ .device_flags = 0,
};
-static struct ocp_fs_i2c_data mpc10x_i2c_data = {
- .flags = 0
+static struct plat_serial8250_port serial_platform_data[] = {
+ [0] = {
+ .mapbase = 0x4500,
+ .iotype = UPIO_MEM,
+ .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
+ },
+ [1] = {
+ .mapbase = 0x4600,
+ .iotype = UPIO_MEM,
+ .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
+ },
+ { },
};
-static struct ocp_def mpc10x_i2c_ocp = {
- .vendor = OCP_VENDOR_MOTOROLA,
- .function = OCP_FUNC_IIC,
- .index = 0,
- .additions = &mpc10x_i2c_data
+
+struct platform_device ppc_sys_platform_devices[] = {
+ [MPC10X_IIC1] = {
+ .name = "fsl-i2c",
+ .id = 1,
+ .dev.platform_data = &mpc10x_i2c_pdata,
+ .num_resources = 2,
+ .resource = (struct resource[]) {
+ {
+ .start = MPC10X_EUMB_I2C_OFFSET,
+ .end = MPC10X_EUMB_I2C_OFFSET +
+ MPC10X_EUMB_I2C_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .flags = IORESOURCE_IRQ
+ },
+ },
+ },
+ [MPC10X_DMA0] = {
+ .name = "fsl-dma",
+ .id = 0,
+ .num_resources = 2,
+ .resource = (struct resource[]) {
+ {
+ .start = MPC10X_EUMB_DMA_OFFSET + 0x10,
+ .end = MPC10X_EUMB_DMA_OFFSET + 0x1f,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .flags = IORESOURCE_IRQ,
+ },
+ },
+ },
+ [MPC10X_DMA1] = {
+ .name = "fsl-dma",
+ .id = 1,
+ .num_resources = 2,
+ .resource = (struct resource[]) {
+ {
+ .start = MPC10X_EUMB_DMA_OFFSET + 0x20,
+ .end = MPC10X_EUMB_DMA_OFFSET + 0x2f,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .flags = IORESOURCE_IRQ,
+ },
+ },
+ },
+ [MPC10X_DMA1] = {
+ .name = "fsl-dma",
+ .id = 1,
+ .num_resources = 2,
+ .resource = (struct resource[]) {
+ {
+ .start = MPC10X_EUMB_DMA_OFFSET + 0x20,
+ .end = MPC10X_EUMB_DMA_OFFSET + 0x2f,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .flags = IORESOURCE_IRQ,
+ },
+ },
+ },
+ [MPC10X_DUART] = {
+ .name = "serial8250",
+ .id = 0,
+ .dev.platform_data = serial_platform_data,
+ },
};
-static struct ocp_def mpc10x_dma_ocp[2] = {
-{ .vendor = OCP_VENDOR_MOTOROLA,
- .function = OCP_FUNC_DMA,
- .index = 0 },
-{ .vendor = OCP_VENDOR_MOTOROLA,
- .function = OCP_FUNC_DMA,
- .index = 1 }
+/* We use the PCI ID to match on */
+struct ppc_sys_spec *cur_ppc_sys_spec;
+struct ppc_sys_spec ppc_sys_specs[] = {
+ {
+ .ppc_sys_name = "8245",
+ .mask = 0xFFFFFFFF,
+ .value = MPC10X_BRIDGE_8245,
+ .num_devices = 4,
+ .device_list = (enum ppc_sys_devices[])
+ {
+ MPC10X_IIC1, MPC10X_DMA0, MPC10X_DMA1, MPC10X_DUART,
+ },
+ },
+ {
+ .ppc_sys_name = "8240",
+ .mask = 0xFFFFFFFF,
+ .value = MPC10X_BRIDGE_8240,
+ .num_devices = 3,
+ .device_list = (enum ppc_sys_devices[])
+ {
+ MPC10X_IIC1, MPC10X_DMA0, MPC10X_DMA1,
+ },
+ },
+ {
+ .ppc_sys_name = "107",
+ .mask = 0xFFFFFFFF,
+ .value = MPC10X_BRIDGE_107,
+ .num_devices = 3,
+ .device_list = (enum ppc_sys_devices[])
+ {
+ MPC10X_IIC1, MPC10X_DMA0, MPC10X_DMA1,
+ },
+ },
+ { /* default match */
+ .ppc_sys_name = "",
+ .mask = 0x00000000,
+ .value = 0x00000000,
+ },
};
/* Set resources to match bridge memory map */
uint new_map,
uint phys_eumb_base)
{
- int host_bridge, picr1, picr1_bit;
+ int host_bridge, picr1, picr1_bit, i;
ulong pci_config_addr, pci_config_data;
u_char pir, byte;
printk("Host bridge in Agent mode\n");
/* Read or Set LMBAR & PCSRBAR? */
}
-
+
/* Set base addr of the 8240/107 EUMB. */
early_write_config_dword(hose,
0,
ioremap(phys_eumb_base + MPC10X_EUMB_EPIC_OFFSET,
MPC10X_EUMB_EPIC_SIZE);
#endif
- mpc10x_i2c_ocp.paddr = phys_eumb_base + MPC10X_EUMB_I2C_OFFSET;
- mpc10x_i2c_ocp.irq = MPC10X_I2C_IRQ;
- ocp_add_one_device(&mpc10x_i2c_ocp);
- mpc10x_dma_ocp[0].paddr = phys_eumb_base +
- MPC10X_EUMB_DMA_OFFSET + 0x100;
- mpc10x_dma_ocp[0].irq = MPC10X_DMA0_IRQ;
- ocp_add_one_device(&mpc10x_dma_ocp[0]);
- mpc10x_dma_ocp[1].paddr = phys_eumb_base +
- MPC10X_EUMB_DMA_OFFSET + 0x200;
- mpc10x_dma_ocp[1].irq = MPC10X_DMA1_IRQ;
- ocp_add_one_device(&mpc10x_dma_ocp[1]);
}
#ifdef CONFIG_MPC10X_STORE_GATHERING
mpc10x_disable_store_gathering(hose);
#endif
+ /* setup platform devices for MPC10x bridges */
+ identify_ppc_sys_by_id (host_bridge);
+
+ for (i = 0; i < cur_ppc_sys_spec->num_devices; i++) {
+ unsigned int dev_id = cur_ppc_sys_spec->device_list[i];
+ ppc_sys_fixup_mem_resource(&ppc_sys_platform_devices[dev_id],
+ phys_eumb_base);
+ }
+
+ /* IRQ's are determined at runtime */
+ ppc_sys_platform_devices[MPC10X_IIC1].resource[1].start = MPC10X_I2C_IRQ;
+ ppc_sys_platform_devices[MPC10X_IIC1].resource[1].end = MPC10X_I2C_IRQ;
+ ppc_sys_platform_devices[MPC10X_DMA0].resource[1].start = MPC10X_DMA0_IRQ;
+ ppc_sys_platform_devices[MPC10X_DMA0].resource[1].end = MPC10X_DMA0_IRQ;
+ ppc_sys_platform_devices[MPC10X_DMA1].resource[1].start = MPC10X_DMA1_IRQ;
+ ppc_sys_platform_devices[MPC10X_DMA1].resource[1].end = MPC10X_DMA1_IRQ;
+
+ serial_platform_data[0].mapbase += phys_eumb_base;
+ serial_platform_data[0].irq = MPC10X_UART0_IRQ;
+
+ serial_platform_data[1].mapbase += phys_eumb_base;
+ serial_platform_data[1].irq = MPC10X_UART0_IRQ + 1;
+
/*
* 8240 erratum 26, 8241/8245 erratum 29, 107 erratum 23: speculative
* PCI reads may return stale data so turn off.
* 8245 (Rev 2., dated 10/2003) says PICR2[0] is reserverd.
*/
if (host_bridge == MPC10X_BRIDGE_8245) {
- ulong picr2;
+ u32 picr2;
early_read_config_dword(hose, 0, PCI_DEVFN(0,0),
MPC10X_CFG_PICR2_REG, &picr2);
openpic_set_sources(EPIC_IRQ_BASE, 3, OpenPIC_Addr + 0x11020);
/* Skip reserved space and map Message Unit Interrupt (I2O) */
openpic_set_sources(EPIC_IRQ_BASE + 3, 1, OpenPIC_Addr + 0x110C0);
+ /* Skip reserved space and map Serial Interupts */
+ openpic_set_sources(EPIC_IRQ_BASE + 4, 2, OpenPIC_Addr + 0x11120);
openpic_init(NUM_8259_INTERRUPTS);
}
.phy_reg_addr = MPC85xx_ENET1_OFFSET,
};
+static struct gianfar_platform_data mpc85xx_etsec1_pdata = {
+ .device_flags = FSL_GIANFAR_DEV_HAS_GIGABIT |
+ FSL_GIANFAR_DEV_HAS_COALESCE | FSL_GIANFAR_DEV_HAS_RMON |
+ FSL_GIANFAR_DEV_HAS_MULTI_INTR |
+ FSL_GIANFAR_DEV_HAS_CSUM | FSL_GIANFAR_DEV_HAS_VLAN |
+ FSL_GIANFAR_DEV_HAS_EXTENDED_HASH,
+ .phy_reg_addr = MPC85xx_ENET1_OFFSET,
+};
+
+static struct gianfar_platform_data mpc85xx_etsec2_pdata = {
+ .device_flags = FSL_GIANFAR_DEV_HAS_GIGABIT |
+ FSL_GIANFAR_DEV_HAS_COALESCE | FSL_GIANFAR_DEV_HAS_RMON |
+ FSL_GIANFAR_DEV_HAS_MULTI_INTR |
+ FSL_GIANFAR_DEV_HAS_CSUM | FSL_GIANFAR_DEV_HAS_VLAN |
+ FSL_GIANFAR_DEV_HAS_EXTENDED_HASH,
+ .phy_reg_addr = MPC85xx_ENET1_OFFSET,
+};
+
+static struct gianfar_platform_data mpc85xx_etsec3_pdata = {
+ .device_flags = FSL_GIANFAR_DEV_HAS_GIGABIT |
+ FSL_GIANFAR_DEV_HAS_COALESCE | FSL_GIANFAR_DEV_HAS_RMON |
+ FSL_GIANFAR_DEV_HAS_MULTI_INTR |
+ FSL_GIANFAR_DEV_HAS_CSUM | FSL_GIANFAR_DEV_HAS_VLAN |
+ FSL_GIANFAR_DEV_HAS_EXTENDED_HASH,
+ .phy_reg_addr = MPC85xx_ENET1_OFFSET,
+};
+
+static struct gianfar_platform_data mpc85xx_etsec4_pdata = {
+ .device_flags = FSL_GIANFAR_DEV_HAS_GIGABIT |
+ FSL_GIANFAR_DEV_HAS_COALESCE | FSL_GIANFAR_DEV_HAS_RMON |
+ FSL_GIANFAR_DEV_HAS_MULTI_INTR |
+ FSL_GIANFAR_DEV_HAS_CSUM | FSL_GIANFAR_DEV_HAS_VLAN |
+ FSL_GIANFAR_DEV_HAS_EXTENDED_HASH,
+ .phy_reg_addr = MPC85xx_ENET1_OFFSET,
+};
+
static struct gianfar_platform_data mpc85xx_fec_pdata = {
.phy_reg_addr = MPC85xx_ENET1_OFFSET,
};
.device_flags = FSL_I2C_DEV_SEPARATE_DFSRR,
};
+static struct fsl_i2c_platform_data mpc85xx_fsl_i2c2_pdata = {
+ .device_flags = FSL_I2C_DEV_SEPARATE_DFSRR,
+};
+
static struct plat_serial8250_port serial_platform_data[] = {
[0] = {
.mapbase = 0x4500,
},
},
},
-#ifdef CONFIG_CPM2
[MPC85xx_CPM_FCC1] = {
.name = "fsl-cpm-fcc",
.id = 1,
},
},
},
-#endif /* CONFIG_CPM2 */
+ [MPC85xx_eTSEC1] = {
+ .name = "fsl-gianfar",
+ .id = 1,
+ .dev.platform_data = &mpc85xx_etsec1_pdata,
+ .num_resources = 4,
+ .resource = (struct resource[]) {
+ {
+ .start = MPC85xx_ENET1_OFFSET,
+ .end = MPC85xx_ENET1_OFFSET +
+ MPC85xx_ENET1_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "tx",
+ .start = MPC85xx_IRQ_TSEC1_TX,
+ .end = MPC85xx_IRQ_TSEC1_TX,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "rx",
+ .start = MPC85xx_IRQ_TSEC1_RX,
+ .end = MPC85xx_IRQ_TSEC1_RX,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "error",
+ .start = MPC85xx_IRQ_TSEC1_ERROR,
+ .end = MPC85xx_IRQ_TSEC1_ERROR,
+ .flags = IORESOURCE_IRQ,
+ },
+ },
+ },
+ [MPC85xx_eTSEC2] = {
+ .name = "fsl-gianfar",
+ .id = 2,
+ .dev.platform_data = &mpc85xx_etsec2_pdata,
+ .num_resources = 4,
+ .resource = (struct resource[]) {
+ {
+ .start = MPC85xx_ENET2_OFFSET,
+ .end = MPC85xx_ENET2_OFFSET +
+ MPC85xx_ENET2_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "tx",
+ .start = MPC85xx_IRQ_TSEC2_TX,
+ .end = MPC85xx_IRQ_TSEC2_TX,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "rx",
+ .start = MPC85xx_IRQ_TSEC2_RX,
+ .end = MPC85xx_IRQ_TSEC2_RX,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "error",
+ .start = MPC85xx_IRQ_TSEC2_ERROR,
+ .end = MPC85xx_IRQ_TSEC2_ERROR,
+ .flags = IORESOURCE_IRQ,
+ },
+ },
+ },
+ [MPC85xx_eTSEC3] = {
+ .name = "fsl-gianfar",
+ .id = 3,
+ .dev.platform_data = &mpc85xx_etsec3_pdata,
+ .num_resources = 4,
+ .resource = (struct resource[]) {
+ {
+ .start = MPC85xx_ENET3_OFFSET,
+ .end = MPC85xx_ENET3_OFFSET +
+ MPC85xx_ENET3_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "tx",
+ .start = MPC85xx_IRQ_TSEC3_TX,
+ .end = MPC85xx_IRQ_TSEC3_TX,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "rx",
+ .start = MPC85xx_IRQ_TSEC3_RX,
+ .end = MPC85xx_IRQ_TSEC3_RX,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "error",
+ .start = MPC85xx_IRQ_TSEC3_ERROR,
+ .end = MPC85xx_IRQ_TSEC3_ERROR,
+ .flags = IORESOURCE_IRQ,
+ },
+ },
+ },
+ [MPC85xx_eTSEC4] = {
+ .name = "fsl-gianfar",
+ .id = 4,
+ .dev.platform_data = &mpc85xx_etsec4_pdata,
+ .num_resources = 4,
+ .resource = (struct resource[]) {
+ {
+ .start = 0x27000,
+ .end = 0x27fff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "tx",
+ .start = MPC85xx_IRQ_TSEC4_TX,
+ .end = MPC85xx_IRQ_TSEC4_TX,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "rx",
+ .start = MPC85xx_IRQ_TSEC4_RX,
+ .end = MPC85xx_IRQ_TSEC4_RX,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "error",
+ .start = MPC85xx_IRQ_TSEC4_ERROR,
+ .end = MPC85xx_IRQ_TSEC4_ERROR,
+ .flags = IORESOURCE_IRQ,
+ },
+ },
+ },
+ [MPC85xx_IIC2] = {
+ .name = "fsl-i2c",
+ .id = 2,
+ .dev.platform_data = &mpc85xx_fsl_i2c2_pdata,
+ .num_resources = 2,
+ .resource = (struct resource[]) {
+ {
+ .start = 0x03100,
+ .end = 0x031ff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MPC85xx_IRQ_IIC1,
+ .end = MPC85xx_IRQ_IIC1,
+ .flags = IORESOURCE_IRQ,
+ },
+ },
+ },
};
static int __init mach_mpc85xx_fixup(struct platform_device *pdev)
MPC85xx_CPM_USB,
},
},
+ /* SVRs on 8548 rev1.0 matches for 8548/8547/8545 */
+ {
+ .ppc_sys_name = "8548E",
+ .mask = 0xFFFF00F0,
+ .value = 0x80390010,
+ .num_devices = 13,
+ .device_list = (enum ppc_sys_devices[])
+ {
+ MPC85xx_eTSEC1, MPC85xx_eTSEC2, MPC85xx_eTSEC3,
+ MPC85xx_eTSEC4, MPC85xx_IIC1, MPC85xx_IIC2,
+ MPC85xx_DMA0, MPC85xx_DMA1, MPC85xx_DMA2, MPC85xx_DMA3,
+ MPC85xx_PERFMON, MPC85xx_DUART, MPC85xx_SEC2,
+ },
+ },
+ {
+ .ppc_sys_name = "8548",
+ .mask = 0xFFFF00F0,
+ .value = 0x80310010,
+ .num_devices = 12,
+ .device_list = (enum ppc_sys_devices[])
+ {
+ MPC85xx_eTSEC1, MPC85xx_eTSEC2, MPC85xx_eTSEC3,
+ MPC85xx_eTSEC4, MPC85xx_IIC1, MPC85xx_IIC2,
+ MPC85xx_DMA0, MPC85xx_DMA1, MPC85xx_DMA2, MPC85xx_DMA3,
+ MPC85xx_PERFMON, MPC85xx_DUART,
+ },
+ },
+ {
+ .ppc_sys_name = "8547E",
+ .mask = 0xFFFF00F0,
+ .value = 0x80390010,
+ .num_devices = 13,
+ .device_list = (enum ppc_sys_devices[])
+ {
+ MPC85xx_eTSEC1, MPC85xx_eTSEC2, MPC85xx_eTSEC3,
+ MPC85xx_eTSEC4, MPC85xx_IIC1, MPC85xx_IIC2,
+ MPC85xx_DMA0, MPC85xx_DMA1, MPC85xx_DMA2, MPC85xx_DMA3,
+ MPC85xx_PERFMON, MPC85xx_DUART, MPC85xx_SEC2,
+ },
+ },
+ {
+ .ppc_sys_name = "8547",
+ .mask = 0xFFFF00F0,
+ .value = 0x80310010,
+ .num_devices = 12,
+ .device_list = (enum ppc_sys_devices[])
+ {
+ MPC85xx_eTSEC1, MPC85xx_eTSEC2, MPC85xx_eTSEC3,
+ MPC85xx_eTSEC4, MPC85xx_IIC1, MPC85xx_IIC2,
+ MPC85xx_DMA0, MPC85xx_DMA1, MPC85xx_DMA2, MPC85xx_DMA3,
+ MPC85xx_PERFMON, MPC85xx_DUART,
+ },
+ },
+ {
+ .ppc_sys_name = "8545E",
+ .mask = 0xFFFF00F0,
+ .value = 0x80390010,
+ .num_devices = 11,
+ .device_list = (enum ppc_sys_devices[])
+ {
+ MPC85xx_eTSEC1, MPC85xx_eTSEC2,
+ MPC85xx_IIC1, MPC85xx_IIC2,
+ MPC85xx_DMA0, MPC85xx_DMA1, MPC85xx_DMA2, MPC85xx_DMA3,
+ MPC85xx_PERFMON, MPC85xx_DUART, MPC85xx_SEC2,
+ },
+ },
+ {
+ .ppc_sys_name = "8545",
+ .mask = 0xFFFF00F0,
+ .value = 0x80310010,
+ .num_devices = 10,
+ .device_list = (enum ppc_sys_devices[])
+ {
+ MPC85xx_eTSEC1, MPC85xx_eTSEC2,
+ MPC85xx_IIC1, MPC85xx_IIC2,
+ MPC85xx_DMA0, MPC85xx_DMA1, MPC85xx_DMA2, MPC85xx_DMA3,
+ MPC85xx_PERFMON, MPC85xx_DUART,
+ },
+ },
+ {
+ .ppc_sys_name = "8543E",
+ .mask = 0xFFFF00F0,
+ .value = 0x803A0010,
+ .num_devices = 11,
+ .device_list = (enum ppc_sys_devices[])
+ {
+ MPC85xx_eTSEC1, MPC85xx_eTSEC2,
+ MPC85xx_IIC1, MPC85xx_IIC2,
+ MPC85xx_DMA0, MPC85xx_DMA1, MPC85xx_DMA2, MPC85xx_DMA3,
+ MPC85xx_PERFMON, MPC85xx_DUART, MPC85xx_SEC2,
+ },
+ },
+ {
+ .ppc_sys_name = "8543",
+ .mask = 0xFFFF00F0,
+ .value = 0x80320010,
+ .num_devices = 10,
+ .device_list = (enum ppc_sys_devices[])
+ {
+ MPC85xx_eTSEC1, MPC85xx_eTSEC2,
+ MPC85xx_IIC1, MPC85xx_IIC2,
+ MPC85xx_DMA0, MPC85xx_DMA1, MPC85xx_DMA2, MPC85xx_DMA3,
+ MPC85xx_PERFMON, MPC85xx_DUART,
+ },
+ },
{ /* default match */
.ppc_sys_name = "",
.mask = 0x00000000,
#include <asm/signal.h>
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/prom.h>
#include <asm/sections.h>
#include <asm/open_pic.h>
#include <asm/i8259.h>
#include <asm/signal.h>
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/prom.h>
#include <asm/sections.h>
#include <asm/open_pic.h>
#include <asm/i8259.h>
+++ /dev/null
-#include <linux/config.h>
-#include <linux/types.h>
-#include <asm/ibm4xx.h>
-#include <linux/kernel.h>
-
-
-
-#define LSR_DR 0x01 /* Data ready */
-#define LSR_OE 0x02 /* Overrun */
-#define LSR_PE 0x04 /* Parity error */
-#define LSR_FE 0x08 /* Framing error */
-#define LSR_BI 0x10 /* Break */
-#define LSR_THRE 0x20 /* Xmit holding register empty */
-#define LSR_TEMT 0x40 /* Xmitter empty */
-#define LSR_ERR 0x80 /* Error */
-
-#include <platforms/4xx/ibm_ocp.h>
-
-extern struct NS16550* COM_PORTS[];
-#ifndef NULL
-#define NULL 0x00
-#endif
-
-static volatile struct NS16550 *kgdb_debugport = NULL;
-
-volatile struct NS16550 *
-NS16550_init(int chan)
-{
- volatile struct NS16550 *com_port;
- int quot;
-#ifdef BASE_BAUD
- quot = BASE_BAUD / 9600;
-#else
- quot = 0x000c; /* 0xc = 9600 baud (on a pc) */
-#endif
-
- com_port = (struct NS16550 *) COM_PORTS[chan];
-
- com_port->lcr = 0x00;
- com_port->ier = 0xFF;
- com_port->ier = 0x00;
- com_port->lcr = com_port->lcr | 0x80; /* Access baud rate */
- com_port->dll = ( quot & 0x00ff ); /* 0xc = 9600 baud */
- com_port->dlm = ( quot & 0xff00 ) >> 8;
- com_port->lcr = 0x03; /* 8 data, 1 stop, no parity */
- com_port->mcr = 0x00; /* RTS/DTR */
- com_port->fcr = 0x07; /* Clear & enable FIFOs */
-
- return( com_port );
-}
-
-
-void
-NS16550_putc(volatile struct NS16550 *com_port, unsigned char c)
-{
- while ((com_port->lsr & LSR_THRE) == 0)
- ;
- com_port->thr = c;
- return;
-}
-
-unsigned char
-NS16550_getc(volatile struct NS16550 *com_port)
-{
- while ((com_port->lsr & LSR_DR) == 0)
- ;
- return (com_port->rbr);
-}
-
-unsigned char
-NS16550_tstc(volatile struct NS16550 *com_port)
-{
- return ((com_port->lsr & LSR_DR) != 0);
-}
-
-
-#if defined(CONFIG_KGDB_TTYS0)
-#define KGDB_PORT 0
-#elif defined(CONFIG_KGDB_TTYS1)
-#define KGDB_PORT 1
-#elif defined(CONFIG_KGDB_TTYS2)
-#define KGDB_PORT 2
-#elif defined(CONFIG_KGDB_TTYS3)
-#define KGDB_PORT 3
-#else
-#error "invalid kgdb_tty port"
-#endif
-
-void putDebugChar( unsigned char c )
-{
- if ( kgdb_debugport == NULL )
- kgdb_debugport = NS16550_init(KGDB_PORT);
- NS16550_putc( kgdb_debugport, c );
-}
-
-int getDebugChar( void )
-{
- if (kgdb_debugport == NULL)
- kgdb_debugport = NS16550_init(KGDB_PORT);
-
- return(NS16550_getc(kgdb_debugport));
-}
-
-void kgdb_interruptible(int enable)
-{
- return;
-}
-
-void putDebugString(char* str)
-{
- while (*str != '\0') {
- putDebugChar(*str);
- str++;
- }
- putDebugChar('\r');
- return;
-}
-
-void
-kgdb_map_scc(void)
-{
- printk("kgdb init \n");
- kgdb_debugport = NS16550_init(KGDB_PORT);
-}
#include <linux/serial_core.h>
#include <linux/serial_8250.h>
-#include <asm/prom.h>
#include <asm/time.h>
#include <asm/mpc83xx.h>
#include <asm/mmu.h>
#include <linux/serial_core.h>
#include <linux/serial_8250.h>
-#include <asm/prom.h>
#include <asm/time.h>
#include <asm/mpc85xx.h>
#include <asm/immap_85xx.h>
#include <syslib/ppc85xx_setup.h>
+extern void abort(void);
+
/* Return the amount of memory */
unsigned long __init
mpc85xx_find_end_of_memory(void)
#ifdef CONFIG_PCI
-#if defined(CONFIG_MPC8555_CDS)
+#if defined(CONFIG_MPC8555_CDS) || defined(CONFIG_MPC8548_CDS)
extern void mpc85xx_cds_enable_via(struct pci_controller *hose);
extern void mpc85xx_cds_fixup_via(struct pci_controller *hose);
#endif
ppc_md.pci_exclude_device = mpc85xx_exclude_device;
-#if defined(CONFIG_MPC8555_CDS)
+#if defined(CONFIG_MPC8555_CDS) || defined(CONFIG_MPC8548_CDS)
/* Pre pciauto_bus_scan VIA init */
mpc85xx_cds_enable_via(hose_a);
#endif
hose_a->last_busno = pciauto_bus_scan(hose_a, hose_a->first_busno);
-#if defined(CONFIG_MPC8555_CDS)
+#if defined(CONFIG_MPC8555_CDS) || defined(CONFIG_MPC8548_CDS)
/* Post pciauto_bus_scan VIA fixup */
mpc85xx_cds_fixup_via(hose_a);
#endif
#include <linux/smp.h>
#include <linux/interrupt.h>
#include <linux/bitops.h>
+#include <linux/kallsyms.h>
#include <asm/ptrace.h>
#include <asm/string.h>
#include <asm/prom.h>
static unsigned read_spr(int);
static void write_spr(int, unsigned);
static void super_regs(void);
-static void print_sysmap(void);
-static void sysmap_lookup(void);
+static void symbol_lookup(void);
static void remove_bpts(void);
static void insert_bpts(void);
static struct bpt *at_breakpoint(unsigned pc);
#ifdef CONFIG_SMP
static void cpu_cmd(void);
#endif /* CONFIG_SMP */
-static int pretty_print_addr(unsigned long addr);
static void csum(void);
#ifdef CONFIG_BOOTX_TEXT
static void vidcmds(void);
extern void xmon_enter(void);
extern void xmon_leave(void);
-extern char* xmon_find_symbol(unsigned long addr, unsigned long* saddr);
-extern unsigned long xmon_symbol_to_addr(char* symbol);
static unsigned start_tb[NR_CPUS][2];
static unsigned stop_tb[NR_CPUS][2];
mm move a block of memory\n\
ms set a block of memory\n\
md compare two blocks of memory\n\
- M print System.map\n\
r print registers\n\
S print special registers\n\
t print backtrace\n\
"r" (loops) : "ctr");
}
+/* Print an address in numeric and symbolic form (if possible) */
+static void xmon_print_symbol(unsigned long address, const char *mid,
+ const char *after)
+{
+ char *modname;
+ const char *name = NULL;
+ unsigned long offset, size;
+ static char tmpstr[128];
+
+ printf("%.8lx", address);
+ if (setjmp(bus_error_jmp) == 0) {
+ debugger_fault_handler = handle_fault;
+ sync();
+ name = kallsyms_lookup(address, &size, &offset, &modname,
+ tmpstr);
+ sync();
+ /* wait a little while to see if we get a machine check */
+ __delay(200);
+ }
+ debugger_fault_handler = NULL;
+
+ if (name) {
+ printf("%s%s+%#lx/%#lx", mid, name, offset, size);
+ if (modname)
+ printf(" [%s]", modname);
+ }
+ printf("%s", after);
+}
+
static void get_tb(unsigned *p)
{
unsigned hi, lo, hiagain;
dump();
break;
case 'l':
- sysmap_lookup();
+ symbol_lookup();
break;
case 'r':
if (excp != NULL)
else
excprint(excp);
break;
- case 'M':
- print_sysmap();
- break;
case 'S':
super_regs();
break;
for (; sp != 0; sp = stack[0]) {
if (mread(sp, stack, sizeof(stack)) != sizeof(stack))
break;
- pretty_print_addr(stack[1]);
- printf(" ");
+ printf("[%.8lx] ", stack);
+ xmon_print_symbol(stack[1], " ", "\n");
if (stack[1] == (unsigned) &ret_from_except
|| stack[1] == (unsigned) &ret_from_except_full
|| stack[1] == (unsigned) &ret_from_syscall) {
if (mread(sp+16, ®s, sizeof(regs)) != sizeof(regs))
break;
- printf("\nexception:%x [%x] %x ", regs.trap, sp+16,
+ printf("exception:%x [%x] %x\n", regs.trap, sp+16,
regs.nip);
sp = regs.gpr[1];
if (mread(sp, stack, sizeof(stack)) != sizeof(stack))
break;
}
- printf("\n");
}
}
#ifdef CONFIG_SMP
printf("cpu %d: ", smp_processor_id());
#endif /* CONFIG_SMP */
- printf("vector: %x at pc = ", fp->trap);
- pretty_print_addr(fp->nip);
- printf(", lr = ");
- pretty_print_addr(fp->link);
- printf("\nmsr = %x, sp = %x [%x]\n", fp->msr, fp->gpr[1], fp);
+ printf("vector: %x at pc=", fp->trap);
+ xmon_print_symbol(fp->nip, ": ", ", lr=");
+ xmon_print_symbol(fp->link, ": ", "\n");
+ printf("msr = %x, sp = %x [%x]\n", fp->msr, fp->gpr[1], fp);
trap = TRAP(fp);
if (trap == 0x300 || trap == 0x600)
printf("dar = %x, dsisr = %x\n", fp->dar, fp->dsisr);
extern char exc_prolog;
extern char dec_exc;
-void
-print_sysmap(void)
-{
- extern char *sysmap;
- if ( sysmap ) {
- printf("System.map: \n");
- if( setjmp(bus_error_jmp) == 0 ) {
- debugger_fault_handler = handle_fault;
- sync();
- xmon_puts(sysmap);
- sync();
- }
- debugger_fault_handler = NULL;
- }
- else
- printf("No System.map\n");
-}
-
void
super_regs(void)
{
printf("invalid register name '%%%s'\n", regname);
return 0;
} else if (c == '$') {
- static char symname[64];
+ static char symname[128];
int i;
for (i=0; i<63; i++) {
c = inchar();
symname[i] = c;
}
symname[i++] = 0;
- *vp = xmon_symbol_to_addr(symname);
+ *vp = 0;
+ if (setjmp(bus_error_jmp) == 0) {
+ debugger_fault_handler = handle_fault;
+ sync();
+ *vp = kallsyms_lookup_name(symname);
+ sync();
+ }
+ debugger_fault_handler = NULL;
if (!(*vp)) {
printf("unknown symbol\n");
return 0;
lineptr = str;
}
-void
-sysmap_lookup(void)
+static void
+symbol_lookup(void)
{
int type = inchar();
unsigned addr;
- static char tmp[64];
- char* cur;
-
- extern char *sysmap;
- extern unsigned long sysmap_size;
- if ( !sysmap || !sysmap_size )
- return;
-
- switch(type) {
- case 'a':
- if (scanhex(&addr)) {
- pretty_print_addr(addr);
- printf("\n");
- }
- termch = 0;
- break;
- case 's':
- getstring(tmp, 64);
- if( setjmp(bus_error_jmp) == 0 ) {
- debugger_fault_handler = handle_fault;
- sync();
- cur = sysmap;
- do {
- cur = strstr(cur, tmp);
- if (cur) {
- static char res[64];
- char *p, *d;
- p = cur;
- while(p > sysmap && *p != 10)
- p--;
- if (*p == 10) p++;
- d = res;
- while(*p && p < (sysmap + sysmap_size) && *p != 10)
- *(d++) = *(p++);
- *(d++) = 0;
- printf("%s\n", res);
- cur++;
- }
- } while (cur);
- sync();
- }
- debugger_fault_handler = NULL;
- termch = 0;
- break;
- }
-}
+ static char tmp[128];
-static int
-pretty_print_addr(unsigned long addr)
-{
- char *sym;
- unsigned long saddr;
-
- printf("%08x", addr);
- sym = xmon_find_symbol(addr, &saddr);
- if (sym)
- printf(" (%s+0x%x)", sym, addr-saddr);
- return (sym != 0);
-}
-
-char*
-xmon_find_symbol(unsigned long addr, unsigned long* saddr)
-{
- static char rbuffer[64];
- char *p, *ep, *limit;
- unsigned long prev, next;
- char* psym;
-
- extern char *sysmap;
- extern unsigned long sysmap_size;
- if ( !sysmap || !sysmap_size )
- return NULL;
-
- prev = 0;
- psym = NULL;
- p = sysmap;
- limit = p + sysmap_size;
- if( setjmp(bus_error_jmp) == 0 ) {
- debugger_fault_handler = handle_fault;
- sync();
- do {
- next = simple_strtoul(p, &p, 16);
- if (next > addr && prev <= addr) {
- if (!psym)
- goto bail;
- ep = rbuffer;
- p = psym;
- while(*p && p < limit && *p == 32)
- p++;
- while(*p && p < limit && *p != 10 && (ep - rbuffer) < 63)
- *(ep++) = *(p++);
- *(ep++) = 0;
- if (saddr)
- *saddr = prev;
- debugger_fault_handler = NULL;
- return rbuffer;
- }
- prev = next;
- psym = p;
- while(*p && p < limit && *p != 10)
- p++;
- if (*p) p++;
- } while(*p && p < limit && next);
-bail:
- sync();
+ switch (type) {
+ case 'a':
+ if (scanhex(&addr))
+ xmon_print_symbol(addr, ": ", "\n");
+ termch = 0;
+ break;
+ case 's':
+ getstring(tmp, 64);
+ if (setjmp(bus_error_jmp) == 0) {
+ debugger_fault_handler = handle_fault;
+ sync();
+ addr = kallsyms_lookup_name(tmp);
+ if (addr)
+ printf("%s: %lx\n", tmp, addr);
+ else
+ printf("Symbol '%s' not found.\n", tmp);
+ sync();
+ }
+ debugger_fault_handler = NULL;
+ termch = 0;
+ break;
}
- debugger_fault_handler = NULL;
- return NULL;
}
-unsigned long
-xmon_symbol_to_addr(char* symbol)
-{
- char *p, *cur;
- char *match = NULL;
- int goodness = 0;
- int result = 0;
-
- extern char *sysmap;
- extern unsigned long sysmap_size;
- if ( !sysmap || !sysmap_size )
- return 0;
-
- if( setjmp(bus_error_jmp) == 0 ) {
- debugger_fault_handler = handle_fault;
- sync();
- cur = sysmap;
- while(cur) {
- cur = strstr(cur, symbol);
- if (cur) {
- int gd = 1;
-
- /* best match if equal, better match if
- * begins with
- */
- if (cur == sysmap || *(cur-1) == ' ') {
- gd++;
- if (cur[strlen(symbol)] == 10)
- gd++;
- }
- if (gd > goodness) {
- match = cur;
- goodness = gd;
- if (gd == 3)
- break;
- }
- cur++;
- }
- }
- if (goodness) {
- p = match;
- while(p > sysmap && *p != 10)
- p--;
- if (*p == 10) p++;
- result = simple_strtoul(p, &p, 16);
- }
- sync();
- }
- debugger_fault_handler = NULL;
- return result;
-}
bool
config PCI
- bool
+ bool "support for PCI devices" if (EMBEDDED && PPC_ISERIES)
default y
help
Find out whether your system includes a PCI bus. PCI is the name of
CROSS32LD := $(LD) -m elf32ppc
CROSS32OBJCOPY := $(OBJCOPY)
endif
-AS := $(AS) -a64
-LD := $(LD) -m elf64ppc
-CC := $(CC) -m64
+override AS += -a64
+override LD += -m elf64ppc
+override CC += -m64
endif
export CROSS32CC CROSS32AS CROSS32LD CROSS32OBJCOPY
#include <asm/system.h>
#include <asm/iSeries/HvLpEvent.h>
#include <asm/iSeries/HvCallEvent.h>
-#include <asm/iSeries/LparData.h>
+#include <asm/iSeries/ItLpNaca.h>
/* Array of LpEvent handler functions */
LpEventHandler lpEventHandler[HvLpEvent_Type_NumTypes];
#include <asm/iSeries/ItLpQueue.h>
#include <asm/iSeries/HvLpEvent.h>
#include <asm/iSeries/HvCallEvent.h>
-#include <asm/iSeries/LparData.h>
static __inline__ int set_inUse( struct ItLpQueue * lpQueue )
{
obj-$(CONFIG_PPC_OF) += of_device.o
-pci-obj-$(CONFIG_PPC_ISERIES) += iSeries_pci.o iSeries_pci_reset.o
+pci-obj-$(CONFIG_PPC_ISERIES) += iSeries_pci.o iSeries_irq.o \
+ iSeries_VpdInfo.o
pci-obj-$(CONFIG_PPC_MULTIPLATFORM) += pci_dn.o pci_direct_iommu.o
obj-$(CONFIG_PCI) += pci.o pci_iommu.o iomap.o $(pci-obj-y)
-obj-$(CONFIG_PPC_ISERIES) += iSeries_irq.o \
- iSeries_VpdInfo.o XmPciLpEvent.o \
- HvCall.o HvLpConfig.o LparData.o \
+obj-$(CONFIG_PPC_ISERIES) += HvCall.o HvLpConfig.o LparData.o \
iSeries_setup.o ItLpQueue.o hvCall.o \
mf.o HvLpEvent.o iSeries_proc.o iSeries_htab.o \
iSeries_iommu.o
+++ /dev/null
-/*
- * File XmPciLpEvent.h created by Wayne Holm on Mon Jan 15 2001.
- *
- * This module handles PCI interrupt events sent by the iSeries Hypervisor.
-*/
-
-#include <linux/config.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/threads.h>
-#include <linux/smp.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/bootmem.h>
-#include <linux/ide.h>
-
-#include <asm/iSeries/HvTypes.h>
-#include <asm/iSeries/HvLpEvent.h>
-#include <asm/iSeries/HvCallPci.h>
-#include <asm/iSeries/XmPciLpEvent.h>
-#include <asm/ppcdebug.h>
-
-static long Pci_Interrupt_Count;
-static long Pci_Event_Count;
-
-enum XmPciLpEvent_Subtype {
- XmPciLpEvent_BusCreated = 0, // PHB has been created
- XmPciLpEvent_BusError = 1, // PHB has failed
- XmPciLpEvent_BusFailed = 2, // Msg to Secondary, Primary failed bus
- XmPciLpEvent_NodeFailed = 4, // Multi-adapter bridge has failed
- XmPciLpEvent_NodeRecovered = 5, // Multi-adapter bridge has recovered
- XmPciLpEvent_BusRecovered = 12, // PHB has been recovered
- XmPciLpEvent_UnQuiesceBus = 18, // Secondary bus unqiescing
- XmPciLpEvent_BridgeError = 21, // Bridge Error
- XmPciLpEvent_SlotInterrupt = 22 // Slot interrupt
-};
-
-struct XmPciLpEvent_BusInterrupt {
- HvBusNumber busNumber;
- HvSubBusNumber subBusNumber;
-};
-
-struct XmPciLpEvent_NodeInterrupt {
- HvBusNumber busNumber;
- HvSubBusNumber subBusNumber;
- HvAgentId deviceId;
-};
-
-struct XmPciLpEvent {
- struct HvLpEvent hvLpEvent;
-
- union {
- u64 alignData; // Align on an 8-byte boundary
-
- struct {
- u32 fisr;
- HvBusNumber busNumber;
- HvSubBusNumber subBusNumber;
- HvAgentId deviceId;
- } slotInterrupt;
-
- struct XmPciLpEvent_BusInterrupt busFailed;
- struct XmPciLpEvent_BusInterrupt busRecovered;
- struct XmPciLpEvent_BusInterrupt busCreated;
-
- struct XmPciLpEvent_NodeInterrupt nodeFailed;
- struct XmPciLpEvent_NodeInterrupt nodeRecovered;
-
- } eventData;
-
-};
-
-static void intReceived(struct XmPciLpEvent *eventParm,
- struct pt_regs *regsParm);
-
-static void XmPciLpEvent_handler(struct HvLpEvent *eventParm,
- struct pt_regs *regsParm)
-{
-#ifdef CONFIG_PCI
-#if 0
- PPCDBG(PPCDBG_BUSWALK, "XmPciLpEvent_handler, type 0x%x\n",
- eventParm->xType);
-#endif
- ++Pci_Event_Count;
-
- if (eventParm && (eventParm->xType == HvLpEvent_Type_PciIo)) {
- switch (eventParm->xFlags.xFunction) {
- case HvLpEvent_Function_Int:
- intReceived((struct XmPciLpEvent *)eventParm, regsParm);
- break;
- case HvLpEvent_Function_Ack:
- printk(KERN_ERR
- "XmPciLpEvent.c: unexpected ack received\n");
- break;
- default:
- printk(KERN_ERR
- "XmPciLpEvent.c: unexpected event function %d\n",
- (int)eventParm->xFlags.xFunction);
- break;
- }
- } else if (eventParm)
- printk(KERN_ERR
- "XmPciLpEvent.c: Unrecognized PCI event type 0x%x\n",
- (int)eventParm->xType);
- else
- printk(KERN_ERR "XmPciLpEvent.c: NULL event received\n");
-#endif
-}
-
-static void intReceived(struct XmPciLpEvent *eventParm,
- struct pt_regs *regsParm)
-{
- int irq;
-
- ++Pci_Interrupt_Count;
-#if 0
- PPCDBG(PPCDBG_BUSWALK, "PCI: XmPciLpEvent.c: intReceived\n");
-#endif
-
- switch (eventParm->hvLpEvent.xSubtype) {
- case XmPciLpEvent_SlotInterrupt:
- irq = eventParm->hvLpEvent.xCorrelationToken;
- /* Dispatch the interrupt handlers for this irq */
- ppc_irq_dispatch_handler(regsParm, irq);
- HvCallPci_eoi(eventParm->eventData.slotInterrupt.busNumber,
- eventParm->eventData.slotInterrupt.subBusNumber,
- eventParm->eventData.slotInterrupt.deviceId);
- break;
- /* Ignore error recovery events for now */
- case XmPciLpEvent_BusCreated:
- printk(KERN_INFO "XmPciLpEvent.c: system bus %d created\n",
- eventParm->eventData.busCreated.busNumber);
- break;
- case XmPciLpEvent_BusError:
- case XmPciLpEvent_BusFailed:
- printk(KERN_INFO "XmPciLpEvent.c: system bus %d failed\n",
- eventParm->eventData.busFailed.busNumber);
- break;
- case XmPciLpEvent_BusRecovered:
- case XmPciLpEvent_UnQuiesceBus:
- printk(KERN_INFO "XmPciLpEvent.c: system bus %d recovered\n",
- eventParm->eventData.busRecovered.busNumber);
- break;
- case XmPciLpEvent_NodeFailed:
- case XmPciLpEvent_BridgeError:
- printk(KERN_INFO
- "XmPciLpEvent.c: multi-adapter bridge %d/%d/%d failed\n",
- eventParm->eventData.nodeFailed.busNumber,
- eventParm->eventData.nodeFailed.subBusNumber,
- eventParm->eventData.nodeFailed.deviceId);
- break;
- case XmPciLpEvent_NodeRecovered:
- printk(KERN_INFO
- "XmPciLpEvent.c: multi-adapter bridge %d/%d/%d recovered\n",
- eventParm->eventData.nodeRecovered.busNumber,
- eventParm->eventData.nodeRecovered.subBusNumber,
- eventParm->eventData.nodeRecovered.deviceId);
- break;
- default:
- printk(KERN_ERR
- "XmPciLpEvent.c: unrecognized event subtype 0x%x\n",
- eventParm->hvLpEvent.xSubtype);
- break;
- }
-}
-
-
-/* This should be called sometime prior to buswalk (init_IRQ would be good) */
-int XmPciLpEvent_init()
-{
- int xRc;
-
- PPCDBG(PPCDBG_BUSWALK,
- "XmPciLpEvent_init, Register Event type 0x%04X\n",
- HvLpEvent_Type_PciIo);
-
- xRc = HvLpEvent_registerHandler(HvLpEvent_Type_PciIo,
- &XmPciLpEvent_handler);
- if (xRc == 0) {
- xRc = HvLpEvent_openPath(HvLpEvent_Type_PciIo, 0);
- if (xRc != 0)
- printk(KERN_ERR
- "XmPciLpEvent.c: open event path failed with rc 0x%x\n",
- xRc);
- } else
- printk(KERN_ERR
- "XmPciLpEvent.c: register handler failed with rc 0x%x\n",
- xRc);
- return xRc;
-}
#include <asm/paca.h>
#include <asm/lppaca.h>
-#include <asm/iSeries/ItLpQueue.h>
#include <asm/iSeries/HvLpEvent.h>
#include <asm/rtas.h>
#include <asm/cputable.h>
static struct dma_mapping_ops *get_dma_ops(struct device *dev)
{
+#ifdef CONFIG_PCI
if (dev->bus == &pci_bus_type)
return &pci_dma_ops;
+#endif
#ifdef CONFIG_IBMVIO
if (dev->bus == &vio_bus_type)
return &vio_dma_ops;
int dma_set_mask(struct device *dev, u64 dma_mask)
{
+#ifdef CONFIG_PCI
if (dev->bus == &pci_bus_type)
return pci_set_dma_mask(to_pci_dev(dev), dma_mask);
+#endif
#ifdef CONFIG_IBMVIO
if (dev->bus == &vio_bus_type)
return -EIO;
pte_t *ptep;
unsigned long pa;
- ptep = find_linux_pte(ioremap_mm.pgd, token);
+ ptep = find_linux_pte(init_mm.pgd, token);
if (!ptep)
return token;
pa = pte_pfn(*ptep) << PAGE_SHIFT;
swapper_pg_dir:
.space 4096
- .globl ioremap_dir
-ioremap_dir:
- .space 4096
-
#ifdef CONFIG_SMP
/* 1 page segment table per cpu (max 48, cpu0 allocated at STAB0_PHYS_ADDR) */
.globl stab_array
-/************************************************************************/
-/* File iSeries_vpdInfo.c created by Allan Trautman on Fri Feb 2 2001. */
-/************************************************************************/
-/* This code gets the card location of the hardware */
-/* Copyright (C) 20yy <Allan H Trautman> <IBM Corp> */
-/* */
-/* 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 */
-/************************************************************************/
-/* Change Activity: */
-/* Created, Feb 2, 2001 */
-/* Ported to ppc64, August 20, 2001 */
-/* End Change Activity */
-/************************************************************************/
-#include <linux/config.h>
+/*
+ * File iSeries_vpdInfo.c created by Allan Trautman on Fri Feb 2 2001.
+ *
+ * This code gets the card location of the hardware
+ * Copyright (C) 2001 <Allan H Trautman> <IBM Corp>
+ * Copyright (C) 2005 Stephen Rothwel, IBM Corp
+ *
+ * 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
+ *
+ * Change Activity:
+ * Created, Feb 2, 2001
+ * Ported to ppc64, August 20, 2001
+ * End Change Activity
+ */
#include <linux/init.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <asm/iSeries/HvCallPci.h>
#include <asm/iSeries/HvTypes.h>
-#include <asm/iSeries/mf.h>
-#include <asm/iSeries/LparData.h>
#include <asm/iSeries/iSeries_pci.h>
-#include "pci.h"
/*
* Size of Bus VPD data
*/
#define BUS_VPDSIZE 1024
+
/*
* Bus Vpd Tags
*/
-#define VpdEndOfDataTag 0x78
#define VpdEndOfAreaTag 0x79
#define VpdIdStringTag 0x82
#define VpdVendorAreaTag 0x84
+
/*
* Mfg Area Tags
*/
-#define VpdFruFlag 0x4647 // "FG"
#define VpdFruFrameId 0x4649 // "FI"
#define VpdSlotMapFormat 0x4D46 // "MF"
-#define VpdAsmPartNumber 0x504E // "PN"
-#define VpdFruSerial 0x534E // "SN"
#define VpdSlotMap 0x534D // "SM"
/*
char CardLocation[3];
char Parms[8];
char Reserved[2];
-};
+};
typedef struct SlotMapStruct SlotMap;
#define SLOT_ENTRY_SIZE 16
-/*
- * Formats the device information.
- * - Pass in pci_dev* pointer to the device.
- * - Pass in buffer to place the data. Danger here is the buffer must
- * be as big as the client says it is. Should be at least 128 bytes.
- * Return will the length of the string data put in the buffer.
- * Format:
- * PCI: Bus 0, Device 26, Vendor 0x12AE Frame 1, Card C10 Ethernet
- * controller
- */
-int iSeries_Device_Information(struct pci_dev *PciDev, char *buffer,
- int BufferSize)
-{
- struct iSeries_Device_Node *DevNode =
- (struct iSeries_Device_Node *)PciDev->sysdata;
- int len;
-
- if (DevNode == NULL)
- return sprintf(buffer,
- "PCI: iSeries_Device_Information DevNode is NULL");
-
- if (BufferSize < 128)
- return 0;
-
- len = sprintf(buffer, "PCI: Bus%3d, Device%3d, Vendor %04X ",
- ISERIES_BUS(DevNode), PCI_SLOT(PciDev->devfn),
- PciDev->vendor);
- len += sprintf(buffer + len, "Frame%3d, Card %4s ",
- DevNode->FrameId, DevNode->CardLocation);
-#ifdef CONFIG_PCI
- if (pci_class_name(PciDev->class >> 8) == 0)
- len += sprintf(buffer + len, "0x%04X ",
- (int)(PciDev->class >> 8));
- else
- len += sprintf(buffer + len, "%s",
- pci_class_name(PciDev->class >> 8));
-#endif
- return len;
-}
-
/*
* Parse the Slot Area
*/
-void iSeries_Parse_SlotArea(SlotMap *MapPtr, int MapLen,
- struct iSeries_Device_Node *DevNode)
+static void __init iSeries_Parse_SlotArea(SlotMap *MapPtr, int MapLen,
+ HvAgentId agent, u8 *PhbId, char card[4])
{
int SlotMapLen = MapLen;
SlotMap *SlotMapPtr = MapPtr;
/*
- * Parse Slot label until we find the one requrested
+ * Parse Slot label until we find the one requested
*/
while (SlotMapLen > 0) {
- if (SlotMapPtr->AgentId == DevNode->AgentId ) {
+ if (SlotMapPtr->AgentId == agent) {
/*
* If Phb wasn't found, grab the entry first one found.
*/
- if (DevNode->PhbId == 0xff)
- DevNode->PhbId = SlotMapPtr->PhbId;
+ if (*PhbId == 0xff)
+ *PhbId = SlotMapPtr->PhbId;
/* Found it, extract the data. */
- if (SlotMapPtr->PhbId == DevNode->PhbId ) {
- memcpy(&DevNode->CardLocation,
- &SlotMapPtr->CardLocation, 3);
- DevNode->CardLocation[3] = 0;
+ if (SlotMapPtr->PhbId == *PhbId) {
+ memcpy(card, &SlotMapPtr->CardLocation, 3);
+ card[3] = 0;
break;
}
}
/*
* Parse the Mfg Area
*/
-static void iSeries_Parse_MfgArea(u8 *AreaData, int AreaLen,
- struct iSeries_Device_Node *DevNode)
+static void __init iSeries_Parse_MfgArea(u8 *AreaData, int AreaLen,
+ HvAgentId agent, u8 *PhbId,
+ u8 *frame, char card[4])
{
MfgArea *MfgAreaPtr = (MfgArea *)AreaData;
int MfgAreaLen = AreaLen;
int MfgTagLen = MfgAreaPtr->TagLength;
/* Frame ID (FI 4649020310 ) */
if (MfgAreaPtr->Tag == VpdFruFrameId) /* FI */
- DevNode->FrameId = MfgAreaPtr->AreaData1;
+ *frame = MfgAreaPtr->AreaData1;
/* Slot Map Format (MF 4D46020004 ) */
else if (MfgAreaPtr->Tag == VpdSlotMapFormat) /* MF */
SlotMapFmt = (MfgAreaPtr->AreaData1 * 256)
if (SlotMapFmt == 0x1004)
SlotMapPtr = (SlotMap *)((char *)MfgAreaPtr
+ MFG_ENTRY_SIZE + 1);
- else
+ else
SlotMapPtr = (SlotMap *)((char *)MfgAreaPtr
+ MFG_ENTRY_SIZE);
- iSeries_Parse_SlotArea(SlotMapPtr, MfgTagLen, DevNode);
+ iSeries_Parse_SlotArea(SlotMapPtr, MfgTagLen,
+ agent, PhbId, card);
}
/*
* Point to the next Mfg Area
*/
MfgAreaPtr = (MfgArea *)((char *)MfgAreaPtr + MfgTagLen
+ MFG_ENTRY_SIZE);
- MfgAreaLen -= (MfgTagLen + MFG_ENTRY_SIZE);
- }
+ MfgAreaLen -= (MfgTagLen + MFG_ENTRY_SIZE);
+ }
}
/*
* Look for "BUS".. Data is not Null terminated.
* PHBID of 0xFF indicates PHB was not found in VPD Data.
*/
-static int iSeries_Parse_PhbId(u8 *AreaPtr, int AreaLength)
+static int __init iSeries_Parse_PhbId(u8 *AreaPtr, int AreaLength)
{
u8 *PhbPtr = AreaPtr;
int DataLen = AreaLength;
- char PhbId = 0xFF;
+ char PhbId = 0xFF;
while (DataLen > 0) {
if ((*PhbPtr == 'B') && (*(PhbPtr + 1) == 'U')
++PhbPtr;
PhbId = (*PhbPtr & 0x0F);
break;
- }
+ }
++PhbPtr;
--DataLen;
}
/*
* Parse out the VPD Areas
*/
-static void iSeries_Parse_Vpd(u8 *VpdData, int VpdDataLen,
- struct iSeries_Device_Node *DevNode)
+static void __init iSeries_Parse_Vpd(u8 *VpdData, int VpdDataLen,
+ HvAgentId agent, u8 *frame, char card[4])
{
u8 *TagPtr = VpdData;
int DataLen = VpdDataLen - 3;
+ u8 PhbId;
while ((*TagPtr != VpdEndOfAreaTag) && (DataLen > 0)) {
- int AreaLen = *(TagPtr + 1) + (*(TagPtr + 2) * 256);
+ int AreaLen = *(TagPtr + 1) + (*(TagPtr + 2) * 256);
u8 *AreaData = TagPtr + 3;
if (*TagPtr == VpdIdStringTag)
- DevNode->PhbId = iSeries_Parse_PhbId(AreaData, AreaLen);
+ PhbId = iSeries_Parse_PhbId(AreaData, AreaLen);
else if (*TagPtr == VpdVendorAreaTag)
- iSeries_Parse_MfgArea(AreaData, AreaLen, DevNode);
+ iSeries_Parse_MfgArea(AreaData, AreaLen,
+ agent, &PhbId, frame, card);
/* Point to next Area. */
TagPtr = AreaData + AreaLen;
DataLen -= AreaLen;
}
-}
+}
-void iSeries_Get_Location_Code(struct iSeries_Device_Node *DevNode)
+static void __init iSeries_Get_Location_Code(u16 bus, HvAgentId agent,
+ u8 *frame, char card[4])
{
int BusVpdLen = 0;
- u8 *BusVpdPtr = (u8 *)kmalloc(BUS_VPDSIZE, GFP_KERNEL);
+ u8 *BusVpdPtr = kmalloc(BUS_VPDSIZE, GFP_KERNEL);
if (BusVpdPtr == NULL) {
printk("PCI: Bus VPD Buffer allocation failure.\n");
return;
}
- BusVpdLen = HvCallPci_getBusVpd(ISERIES_BUS(DevNode),
- ISERIES_HV_ADDR(BusVpdPtr),
+ BusVpdLen = HvCallPci_getBusVpd(bus, ISERIES_HV_ADDR(BusVpdPtr),
BUS_VPDSIZE);
if (BusVpdLen == 0) {
- kfree(BusVpdPtr);
printk("PCI: Bus VPD Buffer zero length.\n");
- return;
+ goto out_free;
}
/* printk("PCI: BusVpdPtr: %p, %d\n",BusVpdPtr, BusVpdLen); */
/* Make sure this is what I think it is */
if (*BusVpdPtr != VpdIdStringTag) { /* 0x82 */
printk("PCI: Bus VPD Buffer missing starting tag.\n");
- kfree(BusVpdPtr);
- return;
+ goto out_free;
}
- iSeries_Parse_Vpd(BusVpdPtr,BusVpdLen, DevNode);
- sprintf(DevNode->Location, "Frame%3d, Card %-4s", DevNode->FrameId,
- DevNode->CardLocation);
+ iSeries_Parse_Vpd(BusVpdPtr, BusVpdLen, agent, frame, card);
+out_free:
kfree(BusVpdPtr);
}
+
+/*
+ * Prints the device information.
+ * - Pass in pci_dev* pointer to the device.
+ * - Pass in the device count
+ *
+ * Format:
+ * PCI: Bus 0, Device 26, Vendor 0x12AE Frame 1, Card C10 Ethernet
+ * controller
+ */
+void __init iSeries_Device_Information(struct pci_dev *PciDev, int count)
+{
+ struct iSeries_Device_Node *DevNode = PciDev->sysdata;
+ u16 bus;
+ u8 frame;
+ char card[4];
+ HvSubBusNumber subbus;
+ HvAgentId agent;
+
+ if (DevNode == NULL) {
+ printk("%d. PCI: iSeries_Device_Information DevNode is NULL\n",
+ count);
+ return;
+ }
+
+ bus = ISERIES_BUS(DevNode);
+ subbus = ISERIES_SUBBUS(DevNode);
+ agent = ISERIES_PCI_AGENTID(ISERIES_GET_DEVICE_FROM_SUBBUS(subbus),
+ ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus));
+ iSeries_Get_Location_Code(bus, agent, &frame, card);
+
+ printk("%d. PCI: Bus%3d, Device%3d, Vendor %04X Frame%3d, Card %4s ",
+ count, bus, PCI_SLOT(PciDev->devfn), PciDev->vendor,
+ frame, card);
+ if (pci_class_name(PciDev->class >> 8) == 0)
+ printk("0x%04X\n", (int)(PciDev->class >> 8));
+ else
+ printk("%s\n", pci_class_name(PciDev->class >> 8));
+}
}
}
-
+#ifdef CONFIG_PCI
/*
* This function compares the known tables to find an iommu_table
* that has already been built for hardware TCEs.
else
kfree(tbl);
}
+#endif
static void iommu_dev_setup_iSeries(struct pci_dev *dev) { }
static void iommu_bus_setup_iSeries(struct pci_bus *bus) { }
-/************************************************************************/
-/* This module supports the iSeries PCI bus interrupt handling */
-/* Copyright (C) 20yy <Robert L Holtorf> <IBM Corp> */
-/* */
-/* 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 */
-/************************************************************************/
-/* Change Activity: */
-/* Created, December 13, 2000 by Wayne Holm */
-/* End Change Activity */
-/************************************************************************/
+/*
+ * This module supports the iSeries PCI bus interrupt handling
+ * Copyright (C) 20yy <Robert L Holtorf> <IBM Corp>
+ * Copyright (C) 2004-2005 IBM Corporation
+ *
+ * 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
+ *
+ * Change Activity:
+ * Created, December 13, 2000 by Wayne Holm
+ * End Change Activity
+ */
+#include <linux/config.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/threads.h>
#include <linux/string.h>
#include <linux/bootmem.h>
#include <linux/ide.h>
-
#include <linux/irq.h>
#include <linux/spinlock.h>
-#include <asm/ppcdebug.h>
+#include <asm/ppcdebug.h>
+#include <asm/iSeries/HvTypes.h>
+#include <asm/iSeries/HvLpEvent.h>
#include <asm/iSeries/HvCallPci.h>
#include <asm/iSeries/HvCallXm.h>
#include <asm/iSeries/iSeries_irq.h>
-#include <asm/iSeries/XmPciLpEvent.h>
-
-static unsigned int iSeries_startup_IRQ(unsigned int irq);
-static void iSeries_shutdown_IRQ(unsigned int irq);
-static void iSeries_enable_IRQ(unsigned int irq);
-static void iSeries_disable_IRQ(unsigned int irq);
-static void iSeries_end_IRQ(unsigned int irq);
-
-static hw_irq_controller iSeries_IRQ_handler = {
- .typename = "iSeries irq controller",
- .startup = iSeries_startup_IRQ,
- .shutdown = iSeries_shutdown_IRQ,
- .enable = iSeries_enable_IRQ,
- .disable = iSeries_disable_IRQ,
- .end = iSeries_end_IRQ
-};
/* This maps virtual irq numbers to real irqs */
unsigned int virt_irq_to_real_map[NR_IRQS];
/* Note: the pcnet32 driver assumes irq numbers < 2 aren't valid. :( */
static int next_virtual_irq = 2;
-/* This is called by init_IRQ. set in ppc_md.init_IRQ by iSeries_setup.c */
-void __init iSeries_init_IRQ(void)
+static long Pci_Interrupt_Count;
+static long Pci_Event_Count;
+
+enum XmPciLpEvent_Subtype {
+ XmPciLpEvent_BusCreated = 0, // PHB has been created
+ XmPciLpEvent_BusError = 1, // PHB has failed
+ XmPciLpEvent_BusFailed = 2, // Msg to Secondary, Primary failed bus
+ XmPciLpEvent_NodeFailed = 4, // Multi-adapter bridge has failed
+ XmPciLpEvent_NodeRecovered = 5, // Multi-adapter bridge has recovered
+ XmPciLpEvent_BusRecovered = 12, // PHB has been recovered
+ XmPciLpEvent_UnQuiesceBus = 18, // Secondary bus unqiescing
+ XmPciLpEvent_BridgeError = 21, // Bridge Error
+ XmPciLpEvent_SlotInterrupt = 22 // Slot interrupt
+};
+
+struct XmPciLpEvent_BusInterrupt {
+ HvBusNumber busNumber;
+ HvSubBusNumber subBusNumber;
+};
+
+struct XmPciLpEvent_NodeInterrupt {
+ HvBusNumber busNumber;
+ HvSubBusNumber subBusNumber;
+ HvAgentId deviceId;
+};
+
+struct XmPciLpEvent {
+ struct HvLpEvent hvLpEvent;
+
+ union {
+ u64 alignData; // Align on an 8-byte boundary
+
+ struct {
+ u32 fisr;
+ HvBusNumber busNumber;
+ HvSubBusNumber subBusNumber;
+ HvAgentId deviceId;
+ } slotInterrupt;
+
+ struct XmPciLpEvent_BusInterrupt busFailed;
+ struct XmPciLpEvent_BusInterrupt busRecovered;
+ struct XmPciLpEvent_BusInterrupt busCreated;
+
+ struct XmPciLpEvent_NodeInterrupt nodeFailed;
+ struct XmPciLpEvent_NodeInterrupt nodeRecovered;
+
+ } eventData;
+
+};
+
+static void intReceived(struct XmPciLpEvent *eventParm,
+ struct pt_regs *regsParm)
{
- /* Register PCI event handler and open an event path */
- XmPciLpEvent_init();
+ int irq;
+
+ ++Pci_Interrupt_Count;
+
+ switch (eventParm->hvLpEvent.xSubtype) {
+ case XmPciLpEvent_SlotInterrupt:
+ irq = eventParm->hvLpEvent.xCorrelationToken;
+ /* Dispatch the interrupt handlers for this irq */
+ ppc_irq_dispatch_handler(regsParm, irq);
+ HvCallPci_eoi(eventParm->eventData.slotInterrupt.busNumber,
+ eventParm->eventData.slotInterrupt.subBusNumber,
+ eventParm->eventData.slotInterrupt.deviceId);
+ break;
+ /* Ignore error recovery events for now */
+ case XmPciLpEvent_BusCreated:
+ printk(KERN_INFO "intReceived: system bus %d created\n",
+ eventParm->eventData.busCreated.busNumber);
+ break;
+ case XmPciLpEvent_BusError:
+ case XmPciLpEvent_BusFailed:
+ printk(KERN_INFO "intReceived: system bus %d failed\n",
+ eventParm->eventData.busFailed.busNumber);
+ break;
+ case XmPciLpEvent_BusRecovered:
+ case XmPciLpEvent_UnQuiesceBus:
+ printk(KERN_INFO "intReceived: system bus %d recovered\n",
+ eventParm->eventData.busRecovered.busNumber);
+ break;
+ case XmPciLpEvent_NodeFailed:
+ case XmPciLpEvent_BridgeError:
+ printk(KERN_INFO
+ "intReceived: multi-adapter bridge %d/%d/%d failed\n",
+ eventParm->eventData.nodeFailed.busNumber,
+ eventParm->eventData.nodeFailed.subBusNumber,
+ eventParm->eventData.nodeFailed.deviceId);
+ break;
+ case XmPciLpEvent_NodeRecovered:
+ printk(KERN_INFO
+ "intReceived: multi-adapter bridge %d/%d/%d recovered\n",
+ eventParm->eventData.nodeRecovered.busNumber,
+ eventParm->eventData.nodeRecovered.subBusNumber,
+ eventParm->eventData.nodeRecovered.deviceId);
+ break;
+ default:
+ printk(KERN_ERR
+ "intReceived: unrecognized event subtype 0x%x\n",
+ eventParm->hvLpEvent.xSubtype);
+ break;
+ }
+}
+
+static void XmPciLpEvent_handler(struct HvLpEvent *eventParm,
+ struct pt_regs *regsParm)
+{
+#ifdef CONFIG_PCI
+ ++Pci_Event_Count;
+
+ if (eventParm && (eventParm->xType == HvLpEvent_Type_PciIo)) {
+ switch (eventParm->xFlags.xFunction) {
+ case HvLpEvent_Function_Int:
+ intReceived((struct XmPciLpEvent *)eventParm, regsParm);
+ break;
+ case HvLpEvent_Function_Ack:
+ printk(KERN_ERR
+ "XmPciLpEvent_handler: unexpected ack received\n");
+ break;
+ default:
+ printk(KERN_ERR
+ "XmPciLpEvent_handler: unexpected event function %d\n",
+ (int)eventParm->xFlags.xFunction);
+ break;
+ }
+ } else if (eventParm)
+ printk(KERN_ERR
+ "XmPciLpEvent_handler: Unrecognized PCI event type 0x%x\n",
+ (int)eventParm->xType);
+ else
+ printk(KERN_ERR "XmPciLpEvent_handler: NULL event received\n");
+#endif
}
/*
- * This is called out of iSeries_scan_slot to allocate an IRQ for an EADS slot
- * It calculates the irq value for the slot.
- * Note that subBusNumber is always 0 (at the moment at least).
+ * This is called by init_IRQ. set in ppc_md.init_IRQ by iSeries_setup.c
+ * It must be called before the bus walk.
*/
-int __init iSeries_allocate_IRQ(HvBusNumber busNumber,
- HvSubBusNumber subBusNumber, HvAgentId deviceId)
+void __init iSeries_init_IRQ(void)
{
- unsigned int realirq, virtirq;
- u8 idsel = (deviceId >> 4);
- u8 function = deviceId & 7;
-
- virtirq = next_virtual_irq++;
- realirq = ((busNumber - 1) << 6) + ((idsel - 1) << 3) + function;
- virt_irq_to_real_map[virtirq] = realirq;
+ /* Register PCI event handler and open an event path */
+ int xRc;
- irq_desc[virtirq].handler = &iSeries_IRQ_handler;
- return virtirq;
+ xRc = HvLpEvent_registerHandler(HvLpEvent_Type_PciIo,
+ &XmPciLpEvent_handler);
+ if (xRc == 0) {
+ xRc = HvLpEvent_openPath(HvLpEvent_Type_PciIo, 0);
+ if (xRc != 0)
+ printk(KERN_ERR "iSeries_init_IRQ: open event path "
+ "failed with rc 0x%x\n", xRc);
+ } else
+ printk(KERN_ERR "iSeries_init_IRQ: register handler "
+ "failed with rc 0x%x\n", xRc);
}
#define REAL_IRQ_TO_BUS(irq) ((((irq) >> 6) & 0xff) + 1)
#define REAL_IRQ_TO_IDSEL(irq) ((((irq) >> 3) & 7) + 1)
#define REAL_IRQ_TO_FUNC(irq) ((irq) & 7)
+/*
+ * This will be called by device drivers (via enable_IRQ)
+ * to enable INTA in the bridge interrupt status register.
+ */
+static void iSeries_enable_IRQ(unsigned int irq)
+{
+ u32 bus, deviceId, function, mask;
+ const u32 subBus = 0;
+ unsigned int rirq = virt_irq_to_real_map[irq];
+
+ /* The IRQ has already been locked by the caller */
+ bus = REAL_IRQ_TO_BUS(rirq);
+ function = REAL_IRQ_TO_FUNC(rirq);
+ deviceId = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;
+
+ /* Unmask secondary INTA */
+ mask = 0x80000000;
+ HvCallPci_unmaskInterrupts(bus, subBus, deviceId, mask);
+ PPCDBG(PPCDBG_BUSWALK, "iSeries_enable_IRQ 0x%02X.%02X.%02X 0x%04X\n",
+ bus, subBus, deviceId, irq);
+}
+
/* This is called by iSeries_activate_IRQs */
static unsigned int iSeries_startup_IRQ(unsigned int irq)
{
desc->handler->startup(irq);
spin_unlock_irqrestore(&desc->lock, flags);
}
- }
+ }
}
/* this is not called anywhere currently */
mask = 0x80000000;
HvCallPci_maskInterrupts(bus, subBus, deviceId, mask);
PPCDBG(PPCDBG_BUSWALK, "iSeries_disable_IRQ 0x%02X.%02X.%02X 0x%04X\n",
- bus, subBus, deviceId, irq);
-}
-
-/*
- * This will be called by device drivers (via enable_IRQ)
- * to enable INTA in the bridge interrupt status register.
- */
-static void iSeries_enable_IRQ(unsigned int irq)
-{
- u32 bus, deviceId, function, mask;
- const u32 subBus = 0;
- unsigned int rirq = virt_irq_to_real_map[irq];
-
- /* The IRQ has already been locked by the caller */
- bus = REAL_IRQ_TO_BUS(rirq);
- function = REAL_IRQ_TO_FUNC(rirq);
- deviceId = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;
-
- /* Unmask secondary INTA */
- mask = 0x80000000;
- HvCallPci_unmaskInterrupts(bus, subBus, deviceId, mask);
- PPCDBG(PPCDBG_BUSWALK, "iSeries_enable_IRQ 0x%02X.%02X.%02X 0x%04X\n",
- bus, subBus, deviceId, irq);
+ bus, subBus, deviceId, irq);
}
/*
static void iSeries_end_IRQ(unsigned int irq)
{
}
+
+static hw_irq_controller iSeries_IRQ_handler = {
+ .typename = "iSeries irq controller",
+ .startup = iSeries_startup_IRQ,
+ .shutdown = iSeries_shutdown_IRQ,
+ .enable = iSeries_enable_IRQ,
+ .disable = iSeries_disable_IRQ,
+ .end = iSeries_end_IRQ
+};
+
+/*
+ * This is called out of iSeries_scan_slot to allocate an IRQ for an EADS slot
+ * It calculates the irq value for the slot.
+ * Note that subBusNumber is always 0 (at the moment at least).
+ */
+int __init iSeries_allocate_IRQ(HvBusNumber busNumber,
+ HvSubBusNumber subBusNumber, HvAgentId deviceId)
+{
+ unsigned int realirq, virtirq;
+ u8 idsel = (deviceId >> 4);
+ u8 function = deviceId & 7;
+
+ virtirq = next_virtual_irq++;
+ realirq = ((busNumber - 1) << 6) + ((idsel - 1) << 3) + function;
+ virt_irq_to_real_map[virtirq] = realirq;
+
+ irq_desc[virtirq].handler = &iSeries_IRQ_handler;
+ return virtirq;
+}
#include <asm/iommu.h>
#include <asm/iSeries/HvCallPci.h>
-#include <asm/iSeries/HvCallSm.h>
#include <asm/iSeries/HvCallXm.h>
-#include <asm/iSeries/LparData.h>
#include <asm/iSeries/iSeries_irq.h>
#include <asm/iSeries/iSeries_pci.h>
#include <asm/iSeries/mf.h>
node->DsaAddr.Dsa.busNumber = Bus;
node->DsaAddr.Dsa.subBusNumber = SubBus;
node->DsaAddr.Dsa.deviceId = 0x10;
- node->AgentId = AgentId;
node->DevFn = PCI_DEVFN(ISERIES_ENCODE_DEVICE(AgentId), Function);
- node->IoRetry = 0;
- iSeries_Get_Location_Code(node);
return node;
}
{
struct pci_dev *pdev = NULL;
struct iSeries_Device_Node *node;
- char Buffer[256];
int DeviceCount = 0;
PPCDBG(PPCDBG_BUSWALK, "iSeries_pcibios_fixup Entry.\n");
"pdev 0x%p <==> DevNode 0x%p\n",
pdev, node);
allocate_device_bars(pdev);
- iSeries_Device_Information(pdev, Buffer,
- sizeof(Buffer));
- printk("%d. %s\n", DeviceCount, Buffer);
+ iSeries_Device_Information(pdev, DeviceCount);
iommu_devnode_init_iSeries(node);
} else
printk("PCI: Device Tree not found for 0x%016lX\n",
++DeviceCount;
node = build_device_node(Bus, SubBus, EADsIdSel, Function);
- node->Vendor = VendorId;
node->Irq = Irq;
node->LogicalSlot = BridgeInfo->logicalSlotNumber;
* Check Return Code
* -> On Failure, print and log information.
* Increment Retry Count, if exceeds max, panic partition.
- * -> If in retry, print and log success
*
* PCI: Device 23.90 ReadL I/O Error( 0): 0x1234
* PCI: Device 23.90 ReadL Retry( 1)
* PCI: Device 23.90 ReadL Retry Successful(1)
*/
static int CheckReturnCode(char *TextHdr, struct iSeries_Device_Node *DevNode,
- u64 ret)
+ int *retry, u64 ret)
{
if (ret != 0) {
++Pci_Error_Count;
- ++DevNode->IoRetry;
+ (*retry)++;
printk("PCI: %s: Device 0x%04X:%02X I/O Error(%2d): 0x%04X\n",
TextHdr, DevNode->DsaAddr.Dsa.busNumber, DevNode->DevFn,
- DevNode->IoRetry, (int)ret);
+ *retry, (int)ret);
/*
* Bump the retry and check for retry count exceeded.
* If, Exceeded, panic the system.
*/
- if ((DevNode->IoRetry > Pci_Retry_Max) &&
+ if (((*retry) > Pci_Retry_Max) &&
(Pci_Error_Flag > 0)) {
mf_display_src(0xB6000103);
- panic_timeout = 0;
+ panic_timeout = 0;
panic("PCI: Hardware I/O Error, SRC B6000103, "
"Automatic Reboot Disabled.\n");
}
return -1; /* Retry Try */
}
- /* If retry was in progress, log success and rest retry count */
- if (DevNode->IoRetry > 0)
- DevNode->IoRetry = 0;
- return 0;
+ return 0;
}
/*
{
u64 BarOffset;
u64 dsa;
+ int retry = 0;
struct HvCallPci_LoadReturn ret;
struct iSeries_Device_Node *DevNode =
xlate_iomm_address(IoAddress, &dsa, &BarOffset);
do {
++Pci_Io_Read_Count;
HvCall3Ret16(HvCallPciBarLoad8, &ret, dsa, BarOffset, 0);
- } while (CheckReturnCode("RDB", DevNode, ret.rc) != 0);
+ } while (CheckReturnCode("RDB", DevNode, &retry, ret.rc) != 0);
return (u8)ret.value;
}
{
u64 BarOffset;
u64 dsa;
+ int retry = 0;
struct HvCallPci_LoadReturn ret;
struct iSeries_Device_Node *DevNode =
xlate_iomm_address(IoAddress, &dsa, &BarOffset);
++Pci_Io_Read_Count;
HvCall3Ret16(HvCallPciBarLoad16, &ret, dsa,
BarOffset, 0);
- } while (CheckReturnCode("RDW", DevNode, ret.rc) != 0);
+ } while (CheckReturnCode("RDW", DevNode, &retry, ret.rc) != 0);
return swab16((u16)ret.value);
}
{
u64 BarOffset;
u64 dsa;
+ int retry = 0;
struct HvCallPci_LoadReturn ret;
struct iSeries_Device_Node *DevNode =
xlate_iomm_address(IoAddress, &dsa, &BarOffset);
++Pci_Io_Read_Count;
HvCall3Ret16(HvCallPciBarLoad32, &ret, dsa,
BarOffset, 0);
- } while (CheckReturnCode("RDL", DevNode, ret.rc) != 0);
+ } while (CheckReturnCode("RDL", DevNode, &retry, ret.rc) != 0);
return swab32((u32)ret.value);
}
{
u64 BarOffset;
u64 dsa;
+ int retry = 0;
u64 rc;
struct iSeries_Device_Node *DevNode =
xlate_iomm_address(IoAddress, &dsa, &BarOffset);
do {
++Pci_Io_Write_Count;
rc = HvCall4(HvCallPciBarStore8, dsa, BarOffset, data, 0);
- } while (CheckReturnCode("WWB", DevNode, rc) != 0);
+ } while (CheckReturnCode("WWB", DevNode, &retry, rc) != 0);
}
EXPORT_SYMBOL(iSeries_Write_Byte);
{
u64 BarOffset;
u64 dsa;
+ int retry = 0;
u64 rc;
struct iSeries_Device_Node *DevNode =
xlate_iomm_address(IoAddress, &dsa, &BarOffset);
do {
++Pci_Io_Write_Count;
rc = HvCall4(HvCallPciBarStore16, dsa, BarOffset, swab16(data), 0);
- } while (CheckReturnCode("WWW", DevNode, rc) != 0);
+ } while (CheckReturnCode("WWW", DevNode, &retry, rc) != 0);
}
EXPORT_SYMBOL(iSeries_Write_Word);
{
u64 BarOffset;
u64 dsa;
+ int retry = 0;
u64 rc;
struct iSeries_Device_Node *DevNode =
xlate_iomm_address(IoAddress, &dsa, &BarOffset);
do {
++Pci_Io_Write_Count;
rc = HvCall4(HvCallPciBarStore32, dsa, BarOffset, swab32(data), 0);
- } while (CheckReturnCode("WWL", DevNode, rc) != 0);
+ } while (CheckReturnCode("WWL", DevNode, &retry, rc) != 0);
}
EXPORT_SYMBOL(iSeries_Write_Long);
+++ /dev/null
-#define PCIFR(...)
-/************************************************************************/
-/* File iSeries_pci_reset.c created by Allan Trautman on Mar 21 2001. */
-/************************************************************************/
-/* This code supports the pci interface on the IBM iSeries systems. */
-/* Copyright (C) 20yy <Allan H Trautman> <IBM Corp> */
-/* */
-/* 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 */
-/************************************************************************/
-/* Change Activity: */
-/* Created, March 20, 2001 */
-/* April 30, 2001, Added return codes on functions. */
-/* September 10, 2001, Ported to ppc64. */
-/* End Change Activity */
-/************************************************************************/
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/irq.h>
-#include <linux/delay.h>
-
-#include <asm/io.h>
-#include <asm/iSeries/HvCallPci.h>
-#include <asm/iSeries/HvTypes.h>
-#include <asm/iSeries/mf.h>
-#include <asm/pci.h>
-
-#include <asm/iSeries/iSeries_pci.h>
-#include "pci.h"
-
-/*
- * Interface to toggle the reset line
- * Time is in .1 seconds, need for seconds.
- */
-int iSeries_Device_ToggleReset(struct pci_dev *PciDev, int AssertTime,
- int DelayTime)
-{
- unsigned int AssertDelay, WaitDelay;
- struct iSeries_Device_Node *DeviceNode =
- (struct iSeries_Device_Node *)PciDev->sysdata;
-
- if (DeviceNode == NULL) {
- printk("PCI: Pci Reset Failed, Device Node not found for pci_dev %p\n",
- PciDev);
- return -1;
- }
- /*
- * Set defaults, Assert is .5 second, Wait is 3 seconds.
- */
- if (AssertTime == 0)
- AssertDelay = 500;
- else
- AssertDelay = AssertTime * 100;
-
- if (DelayTime == 0)
- WaitDelay = 3000;
- else
- WaitDelay = DelayTime * 100;
-
- /*
- * Assert reset
- */
- DeviceNode->ReturnCode = HvCallPci_setSlotReset(ISERIES_BUS(DeviceNode),
- 0x00, DeviceNode->AgentId, 1);
- if (DeviceNode->ReturnCode == 0) {
- msleep(AssertDelay); /* Sleep for the time */
- DeviceNode->ReturnCode =
- HvCallPci_setSlotReset(ISERIES_BUS(DeviceNode),
- 0x00, DeviceNode->AgentId, 0);
-
- /*
- * Wait for device to reset
- */
- msleep(WaitDelay);
- }
- if (DeviceNode->ReturnCode == 0)
- PCIFR("Slot 0x%04X.%02 Reset\n", ISERIES_BUS(DeviceNode),
- DeviceNode->AgentId);
- else {
- printk("PCI: Slot 0x%04X.%02X Reset Failed, RCode: %04X\n",
- ISERIES_BUS(DeviceNode), DeviceNode->AgentId,
- DeviceNode->ReturnCode);
- PCIFR("Slot 0x%04X.%02X Reset Failed, RCode: %04X\n",
- ISERIES_BUS(DeviceNode), DeviceNode->AgentId,
- DeviceNode->ReturnCode);
- }
- return DeviceNode->ReturnCode;
-}
-EXPORT_SYMBOL(iSeries_Device_ToggleReset);
#include <asm/iSeries/ItLpQueue.h>
#include <asm/iSeries/HvCallXm.h>
#include <asm/iSeries/IoHriMainStore.h>
-#include <asm/iSeries/LparData.h>
-#include <asm/iSeries/iSeries_proc.h>
+#include <asm/iSeries/IoHriProcessorVpd.h>
static int __init iseries_proc_create(void)
{
#include <asm/paca.h>
#include <asm/cache.h>
#include <asm/sections.h>
-#include <asm/iSeries/LparData.h>
+#include <asm/abs_addr.h>
#include <asm/iSeries/HvCallHpt.h>
#include <asm/iSeries/HvLpConfig.h>
#include <asm/iSeries/HvCallEvent.h>
#include <asm/iSeries/HvCallXm.h>
#include <asm/iSeries/ItLpQueue.h>
#include <asm/iSeries/IoHriMainStore.h>
-#include <asm/iSeries/iSeries_proc.h>
#include <asm/iSeries/mf.h>
#include <asm/iSeries/HvLpEvent.h>
#include <asm/iSeries/iSeries_irq.h>
+#include <asm/iSeries/IoHriProcessorVpd.h>
+#include <asm/iSeries/ItVpdAreas.h>
+#include <asm/iSeries/LparMap.h>
extern void hvlog(char *fmt, ...);
static void build_iSeries_Memory_Map(void);
static void setup_iSeries_cache_sizes(void);
static void iSeries_bolt_kernel(unsigned long saddr, unsigned long eaddr);
+#ifdef CONFIG_PCI
extern void iSeries_pci_final_fixup(void);
+#else
+static void iSeries_pci_final_fixup(void) { }
+#endif
/* Global Variables */
static unsigned long procFreqHz;
}
__setup("spread_lpevents=", set_spread_lpevents);
+#ifndef CONFIG_PCI
+void __init iSeries_init_IRQ(void) { }
+#endif
+
void __init iSeries_early_setup(void)
{
iSeries_fixup_klimit();
#include <asm/io.h>
#include <asm/smp.h>
#include <asm/paca.h>
-#include <asm/iSeries/LparData.h>
#include <asm/iSeries/HvCall.h>
-#include <asm/iSeries/HvCallCfg.h>
#include <asm/time.h>
#include <asm/ppcdebug.h>
#include <asm/machdep.h>
static unsigned long maxYieldTime = 0;
static unsigned long minYieldTime = 0xffffffffffffffffUL;
+static inline void process_iSeries_events(void)
+{
+ asm volatile ("li 0,0x5555; sc" : : : "r0", "r3");
+}
+
static void yield_shared_processor(void)
{
unsigned long tb;
if (need_resched())
schedule();
- if (cpu_is_offline(_smp_processor_id()) &&
+ if (cpu_is_offline(raw_smp_processor_id()) &&
system_state == SYSTEM_RUNNING)
cpu_die();
}
#include <asm/cache.h>
#include <asm/prom.h>
#include <asm/ptrace.h>
-#include <asm/iSeries/LparData.h>
+#include <asm/iSeries/ItLpQueue.h>
#include <asm/machdep.h>
#include <asm/paca.h>
#include <asm/uaccess.h>
#include <asm/iSeries/HvLpConfig.h>
#include <asm/lppaca.h>
-#include <asm/iSeries/LparData.h>
#include <asm/hvcall.h>
#include <asm/cputable.h>
#include <asm/rtas.h>
#include <asm/system.h>
#include <asm/time.h>
+#include <asm/iSeries/ItExtVpdPanel.h>
#define MODULE_VERS "1.6"
#define MODULE_NAME "lparcfg"
#include <asm/iSeries/vio.h>
#include <asm/iSeries/mf.h>
#include <asm/iSeries/HvLpConfig.h>
-#include <asm/iSeries/ItSpCommArea.h>
#include <asm/iSeries/ItLpQueue.h>
/*
struct task_struct *last_task_used_altivec = NULL;
#endif
-struct mm_struct ioremap_mm = {
- .pgd = ioremap_dir,
- .mm_users = ATOMIC_INIT(2),
- .mm_count = ATOMIC_INIT(1),
- .cpu_vm_mask = CPU_MASK_ALL,
- .page_table_lock = SPIN_LOCK_UNLOCKED,
-};
-
/*
* Make sure the floating-point register state in the
* the thread_struct is up to date for task tsk.
{
char *type = get_flat_dt_prop(node, "device_type", NULL);
u32 *prop;
+ unsigned long size;
/* We are scanning "cpu" nodes only */
if (type == NULL || strcmp(type, "cpu") != 0)
cur_cpu_spec->cpu_user_features |= PPC_FEATURE_HAS_ALTIVEC;
}
+ /*
+ * Check for an SMT capable CPU and set the CPU feature. We do
+ * this by looking at the size of the ibm,ppc-interrupt-server#s
+ * property
+ */
+ prop = (u32 *)get_flat_dt_prop(node, "ibm,ppc-interrupt-server#s",
+ &size);
+ cur_cpu_spec->cpu_features &= ~CPU_FTR_SMT;
+ if (prop && ((size / sizeof(u32)) > 1))
+ cur_cpu_spec->cpu_features |= CPU_FTR_SMT;
+
return 0;
}
#include <asm/cache.h>
#include <asm/prom.h>
#include <asm/ptrace.h>
-#include <asm/iSeries/LparData.h>
#include <asm/machdep.h>
#include <asm/rtas.h>
#include <asm/ppcdebug.h>
#include <asm/time.h>
#include <asm/rtas.h>
-#include <asm/iSeries/LparData.h>
#include <asm/iSeries/mf.h>
#include <asm/machdep.h>
-#include <asm/iSeries/ItSpCommArea.h>
extern int piranha_simulator;
#include <asm/smp.h>
#include <asm/elf.h>
#include <asm/machdep.h>
-#include <asm/iSeries/LparData.h>
#include <asm/paca.h>
#include <asm/ppcdebug.h>
#include <asm/time.h>
#include <asm/cache.h>
#include <asm/page.h>
#include <asm/mmu.h>
+#include <asm/lmb.h>
+#include <asm/iSeries/ItLpNaca.h>
#ifdef DEBUG
#define DBG(fmt...) udbg_printf(fmt)
asmlinkage int sys32_pciconfig_iobase(u32 which, u32 in_bus, u32 in_devfn)
{
+#ifdef CONFIG_PCI
struct pci_controller* hose;
struct list_head *ln;
struct pci_bus *bus = NULL;
case IOBASE_ISA_MEM:
return -EINVAL;
}
-
+#endif /* CONFIG_PCI */
return -EOPNOTSUPP;
}
static struct iommu_table *vio_build_iommu_table(struct vio_dev *);
static int vio_num_address_cells;
#endif
-static struct vio_dev *vio_bus_device; /* fake "parent" device */
-
#ifdef CONFIG_PPC_ISERIES
-static struct vio_dev *__init vio_register_device_iseries(char *type,
- uint32_t unit_num);
-
static struct iommu_table veth_iommu_table;
static struct iommu_table vio_iommu_table;
-
-static struct vio_dev _vio_dev = {
+#endif
+static struct vio_dev vio_bus_device = { /* fake "parent" device */
+ .name = vio_bus_device.dev.bus_id,
+ .type = "",
+#ifdef CONFIG_PPC_ISERIES
.iommu_table = &vio_iommu_table,
- .dev.bus = &vio_bus_type
+#endif
+ .dev.bus_id = "vio",
+ .dev.bus = &vio_bus_type,
};
-struct device *iSeries_vio_dev = &_vio_dev.dev;
+
+#ifdef CONFIG_PPC_ISERIES
+static struct vio_dev *__init vio_register_device_iseries(char *type,
+ uint32_t unit_num);
+
+struct device *iSeries_vio_dev = &vio_bus_device.dev;
EXPORT_SYMBOL(iSeries_vio_dev);
#define device_is_compatible(a, b) 1
}
/* the fake parent of all vio devices, just to give us a nice directory */
- vio_bus_device = kmalloc(sizeof(struct vio_dev), GFP_KERNEL);
- if (!vio_bus_device) {
- return 1;
- }
- memset(vio_bus_device, 0, sizeof(struct vio_dev));
- strcpy(vio_bus_device->dev.bus_id, "vio");
-
- err = device_register(&vio_bus_device->dev);
+ err = device_register(&vio_bus_device.dev);
if (err) {
printk(KERN_WARNING "%s: device_register returned %i\n", __FUNCTION__,
err);
- kfree(vio_bus_device);
return err;
}
viodev->unit_address = unit_address;
viodev->iommu_table = iommu_table;
/* init generic 'struct device' fields: */
- viodev->dev.parent = &vio_bus_device->dev;
+ viodev->dev.parent = &vio_bus_device.dev;
viodev->dev.bus = &vio_bus_type;
viodev->dev.release = vio_dev_release;
.name = "vio",
.match = vio_bus_match,
};
-
-EXPORT_SYMBOL(vio_bus_type);
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/iSeries/HvTypes.h>
-#include <asm/iSeries/LparData.h>
+#include <asm/iSeries/ItExtVpdPanel.h>
#include <asm/iSeries/HvLpEvent.h>
#include <asm/iSeries/HvLpConfig.h>
-#include <asm/iSeries/HvCallCfg.h>
#include <asm/iSeries/mf.h>
-#include <asm/iSeries/iSeries_proc.h>
#include <asm/iSeries/vio.h>
/* Status of the path to each other partition in the system.
* while we're active
*/
viopath_ourLp = HvLpConfig_getLpIndex();
- viopath_hostLp = HvCallCfg_getHostingLpIndex(viopath_ourLp);
+ viopath_hostLp = HvLpConfig_getHostingLpIndex(viopath_ourLp);
if (viopath_hostLp != HvLpIndexInvalid)
vio_setHandler(viomajorsubtype_config, handleConfig);
unsigned long flags;
int tempNumAllocated;
- if ((remoteLp >= HvMaxArchitectedLps) || (remoteLp == HvLpIndexInvalid))
+ if ((remoteLp >= HVMAXARCHITECTEDLPS) || (remoteLp == HvLpIndexInvalid))
return -EINVAL;
subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT;
int numOpen;
struct alloc_parms parms;
- if ((remoteLp >= HvMaxArchitectedLps) || (remoteLp == HvLpIndexInvalid))
+ if ((remoteLp >= HVMAXARCHITECTEDLPS) || (remoteLp == HvLpIndexInvalid))
return -EINVAL;
subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT;
# e2a provides EBCDIC to ASCII conversions.
ifdef CONFIG_PPC_ISERIES
-obj-$(CONFIG_PCI) += e2a.o
+obj-y += e2a.o
endif
lib-$(CONFIG_DEBUG_KERNEL) += sstep.o
memset((void *)table, 0, htab_size_bytes);
}
- mode_rw = _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX;
+ mode_rw = _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_COHERENT | PP_RWXX;
/* On U3 based machines, we need to reserve the DART area and
* _NOT_ map it to avoid cache paradoxes as it's remapped non
vsid = get_vsid(mm->context.id, ea);
break;
- case IO_REGION_ID:
- mm = &ioremap_mm;
- vsid = get_kernel_vsid(ea);
- break;
case VMALLOC_REGION_ID:
mm = &init_mm;
vsid = get_kernel_vsid(ea);
return hugepte_offset(dir, addr);
}
-static pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
+pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
{
pud_t *pud;
return hugepte_offset(pud, addr);
}
-static pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr)
+pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr)
{
pud_t *pud;
return hugepte_alloc(mm, pud, addr);
}
-static void set_huge_pte(struct mm_struct *mm, struct vm_area_struct *vma,
- unsigned long addr, struct page *page,
- pte_t *ptep, int write_access)
-{
- pte_t entry;
-
- add_mm_counter(mm, rss, HPAGE_SIZE / PAGE_SIZE);
- if (write_access) {
- entry =
- pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
- } else {
- entry = pte_wrprotect(mk_pte(page, vma->vm_page_prot));
- }
- entry = pte_mkyoung(entry);
- entry = pte_mkhuge(entry);
-
- set_pte_at(mm, addr, ptep, entry);
-}
-
/*
* This function checks for proper alignment of input addr and len parameters.
*/
return -EINVAL;
}
-int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
- struct vm_area_struct *vma)
-{
- pte_t *src_pte, *dst_pte, entry;
- struct page *ptepage;
- unsigned long addr = vma->vm_start;
- unsigned long end = vma->vm_end;
- int err = -ENOMEM;
-
- while (addr < end) {
- dst_pte = huge_pte_alloc(dst, addr);
- if (!dst_pte)
- goto out;
-
- src_pte = huge_pte_offset(src, addr);
- entry = *src_pte;
-
- ptepage = pte_page(entry);
- get_page(ptepage);
- add_mm_counter(dst, rss, HPAGE_SIZE / PAGE_SIZE);
- set_pte_at(dst, addr, dst_pte, entry);
-
- addr += HPAGE_SIZE;
- }
-
- err = 0;
- out:
- return err;
-}
-
-int
-follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma,
- struct page **pages, struct vm_area_struct **vmas,
- unsigned long *position, int *length, int i)
-{
- unsigned long vpfn, vaddr = *position;
- int remainder = *length;
-
- WARN_ON(!is_vm_hugetlb_page(vma));
-
- vpfn = vaddr/PAGE_SIZE;
- while (vaddr < vma->vm_end && remainder) {
- if (pages) {
- pte_t *pte;
- struct page *page;
-
- pte = huge_pte_offset(mm, vaddr);
-
- /* hugetlb should be locked, and hence, prefaulted */
- WARN_ON(!pte || pte_none(*pte));
-
- page = &pte_page(*pte)[vpfn % (HPAGE_SIZE/PAGE_SIZE)];
-
- WARN_ON(!PageCompound(page));
-
- get_page(page);
- pages[i] = page;
- }
-
- if (vmas)
- vmas[i] = vma;
-
- vaddr += PAGE_SIZE;
- ++vpfn;
- --remainder;
- ++i;
- }
-
- *length = remainder;
- *position = vaddr;
-
- return i;
-}
-
struct page *
follow_huge_addr(struct mm_struct *mm, unsigned long address, int write)
{
return NULL;
}
-void unmap_hugepage_range(struct vm_area_struct *vma,
- unsigned long start, unsigned long end)
-{
- struct mm_struct *mm = vma->vm_mm;
- unsigned long addr;
- pte_t *ptep;
- struct page *page;
-
- WARN_ON(!is_vm_hugetlb_page(vma));
- BUG_ON((start % HPAGE_SIZE) != 0);
- BUG_ON((end % HPAGE_SIZE) != 0);
-
- for (addr = start; addr < end; addr += HPAGE_SIZE) {
- pte_t pte;
-
- ptep = huge_pte_offset(mm, addr);
- if (!ptep || pte_none(*ptep))
- continue;
-
- pte = *ptep;
- page = pte_page(pte);
- pte_clear(mm, addr, ptep);
-
- put_page(page);
- }
- add_mm_counter(mm, rss, -((end - start) >> PAGE_SHIFT));
- flush_tlb_pending();
-}
-
-int hugetlb_prefault(struct address_space *mapping, struct vm_area_struct *vma)
-{
- struct mm_struct *mm = current->mm;
- unsigned long addr;
- int ret = 0;
-
- WARN_ON(!is_vm_hugetlb_page(vma));
- BUG_ON((vma->vm_start % HPAGE_SIZE) != 0);
- BUG_ON((vma->vm_end % HPAGE_SIZE) != 0);
-
- spin_lock(&mm->page_table_lock);
- for (addr = vma->vm_start; addr < vma->vm_end; addr += HPAGE_SIZE) {
- unsigned long idx;
- pte_t *pte = huge_pte_alloc(mm, addr);
- struct page *page;
-
- if (!pte) {
- ret = -ENOMEM;
- goto out;
- }
- if (! pte_none(*pte))
- continue;
-
- idx = ((addr - vma->vm_start) >> HPAGE_SHIFT)
- + (vma->vm_pgoff >> (HPAGE_SHIFT - PAGE_SHIFT));
- page = find_get_page(mapping, idx);
- if (!page) {
- /* charge the fs quota first */
- if (hugetlb_get_quota(mapping)) {
- ret = -ENOMEM;
- goto out;
- }
- page = alloc_huge_page();
- if (!page) {
- hugetlb_put_quota(mapping);
- ret = -ENOMEM;
- goto out;
- }
- ret = add_to_page_cache(page, mapping, idx, GFP_ATOMIC);
- if (! ret) {
- unlock_page(page);
- } else {
- hugetlb_put_quota(mapping);
- free_huge_page(page);
- goto out;
- }
- }
- set_huge_pte(mm, vma, addr, page, pte, vma->vm_flags & VM_WRITE);
- }
-out:
- spin_unlock(&mm->page_table_lock);
- return ret;
-}
-
/* Because we have an exclusive hugepage region which lies within the
* normal user address space, we have to take special measures to make
* non-huge mmap()s evade the hugepage reserved regions. */
&& !is_hugepage_only_range(mm, addr,len))
return addr;
}
- start_addr = addr = mm->free_area_cache;
+ if (len > mm->cached_hole_size) {
+ start_addr = addr = mm->free_area_cache;
+ } else {
+ start_addr = addr = TASK_UNMAPPED_BASE;
+ mm->cached_hole_size = 0;
+ }
full_search:
vma = find_vma(mm, addr);
mm->free_area_cache = addr + len;
return addr;
}
+ if (addr + mm->cached_hole_size < vma->vm_start)
+ mm->cached_hole_size = vma->vm_start - addr;
addr = vma->vm_end;
vma = vma->vm_next;
}
/* Make sure we didn't miss any holes */
if (start_addr != TASK_UNMAPPED_BASE) {
start_addr = addr = TASK_UNMAPPED_BASE;
+ mm->cached_hole_size = 0;
goto full_search;
}
return -ENOMEM;
struct vm_area_struct *vma, *prev_vma;
struct mm_struct *mm = current->mm;
unsigned long base = mm->mmap_base, addr = addr0;
+ unsigned long largest_hole = mm->cached_hole_size;
int first_time = 1;
/* requested length too big for entire address space */
return addr;
}
+ if (len <= largest_hole) {
+ largest_hole = 0;
+ mm->free_area_cache = base;
+ }
try_again:
/* make sure it can fit in the remaining address space */
if (mm->free_area_cache < len)
* vma->vm_start, use it:
*/
if (addr+len <= vma->vm_start &&
- (!prev_vma || (addr >= prev_vma->vm_end)))
+ (!prev_vma || (addr >= prev_vma->vm_end))) {
/* remember the address as a hint for next time */
- return (mm->free_area_cache = addr);
- else
+ mm->cached_hole_size = largest_hole;
+ return (mm->free_area_cache = addr);
+ } else {
/* pull free_area_cache down to the first hole */
- if (mm->free_area_cache == vma->vm_end)
+ if (mm->free_area_cache == vma->vm_end) {
mm->free_area_cache = vma->vm_start;
+ mm->cached_hole_size = largest_hole;
+ }
+ }
+
+ /* remember the largest hole we saw so far */
+ if (addr + largest_hole < vma->vm_start)
+ largest_hole = vma->vm_start - addr;
/* try just below the current vma->vm_start */
addr = vma->vm_start-len;
*/
if (first_time) {
mm->free_area_cache = base;
+ largest_hole = 0;
first_time = 0;
goto try_again;
}
* allocations.
*/
mm->free_area_cache = TASK_UNMAPPED_BASE;
+ mm->cached_hole_size = ~0UL;
addr = arch_get_unmapped_area(filp, addr0, len, pgoff, flags);
/*
* Restore the topdown base:
*/
mm->free_area_cache = base;
+ mm->cached_hole_size = ~0UL;
return addr;
}
#include <asm/pgtable.h>
#include <asm/semaphore.h>
#include <asm/imalloc.h>
+#include <asm/cacheflush.h>
static DECLARE_MUTEX(imlist_sem);
struct vm_struct * imlist = NULL;
return area;
}
-unsigned long im_free(void * addr)
+void im_free(void * addr)
{
struct vm_struct **p, *tmp;
- unsigned long ret_size = 0;
if (!addr)
- return ret_size;
- if ((PAGE_SIZE-1) & (unsigned long) addr) {
+ return;
+ if ((unsigned long) addr & ~PAGE_MASK) {
printk(KERN_ERR "Trying to %s bad address (%p)\n", __FUNCTION__, addr);
- return ret_size;
+ return;
}
down(&imlist_sem);
for (p = &imlist ; (tmp = *p) ; p = &tmp->next) {
if (tmp->addr == addr) {
- ret_size = tmp->size;
*p = tmp->next;
+
+ /* XXX: do we need the lock? */
+ spin_lock(&init_mm.page_table_lock);
+ unmap_vm_area(tmp);
+ spin_unlock(&init_mm.page_table_lock);
+
kfree(tmp);
up(&imlist_sem);
- return ret_size;
+ return;
}
}
up(&imlist_sem);
printk(KERN_ERR "Trying to %s nonexistent area (%p)\n", __FUNCTION__,
addr);
- return ret_size;
}
extern pgd_t swapper_pg_dir[];
extern struct task_struct *current_set[NR_CPUS];
-extern pgd_t ioremap_dir[];
-pgd_t * ioremap_pgd = (pgd_t *)&ioremap_dir;
-
unsigned long klimit = (unsigned long)_end;
unsigned long _SDR1=0;
#else
-static void unmap_im_area_pte(pmd_t *pmd, unsigned long addr,
- unsigned long end)
-{
- pte_t *pte;
-
- pte = pte_offset_kernel(pmd, addr);
- do {
- pte_t ptent = ptep_get_and_clear(&ioremap_mm, addr, pte);
- WARN_ON(!pte_none(ptent) && !pte_present(ptent));
- } while (pte++, addr += PAGE_SIZE, addr != end);
-}
-
-static inline void unmap_im_area_pmd(pud_t *pud, unsigned long addr,
- unsigned long end)
-{
- pmd_t *pmd;
- unsigned long next;
-
- pmd = pmd_offset(pud, addr);
- do {
- next = pmd_addr_end(addr, end);
- if (pmd_none_or_clear_bad(pmd))
- continue;
- unmap_im_area_pte(pmd, addr, next);
- } while (pmd++, addr = next, addr != end);
-}
-
-static inline void unmap_im_area_pud(pgd_t *pgd, unsigned long addr,
- unsigned long end)
-{
- pud_t *pud;
- unsigned long next;
-
- pud = pud_offset(pgd, addr);
- do {
- next = pud_addr_end(addr, end);
- if (pud_none_or_clear_bad(pud))
- continue;
- unmap_im_area_pmd(pud, addr, next);
- } while (pud++, addr = next, addr != end);
-}
-
-static void unmap_im_area(unsigned long addr, unsigned long end)
-{
- struct mm_struct *mm = &ioremap_mm;
- unsigned long next;
- pgd_t *pgd;
-
- spin_lock(&mm->page_table_lock);
-
- pgd = pgd_offset_i(addr);
- flush_cache_vunmap(addr, end);
- do {
- next = pgd_addr_end(addr, end);
- if (pgd_none_or_clear_bad(pgd))
- continue;
- unmap_im_area_pud(pgd, addr, next);
- } while (pgd++, addr = next, addr != end);
- flush_tlb_kernel_range(start, end);
-
- spin_unlock(&mm->page_table_lock);
-}
-
/*
* map_io_page currently only called by __ioremap
* map_io_page adds an entry to the ioremap page table
unsigned long vsid;
if (mem_init_done) {
- spin_lock(&ioremap_mm.page_table_lock);
- pgdp = pgd_offset_i(ea);
- pudp = pud_alloc(&ioremap_mm, pgdp, ea);
+ spin_lock(&init_mm.page_table_lock);
+ pgdp = pgd_offset_k(ea);
+ pudp = pud_alloc(&init_mm, pgdp, ea);
if (!pudp)
return -ENOMEM;
- pmdp = pmd_alloc(&ioremap_mm, pudp, ea);
+ pmdp = pmd_alloc(&init_mm, pudp, ea);
if (!pmdp)
return -ENOMEM;
- ptep = pte_alloc_kernel(&ioremap_mm, pmdp, ea);
+ ptep = pte_alloc_kernel(&init_mm, pmdp, ea);
if (!ptep)
return -ENOMEM;
pa = abs_to_phys(pa);
- set_pte_at(&ioremap_mm, ea, ptep, pfn_pte(pa >> PAGE_SHIFT,
+ set_pte_at(&init_mm, ea, ptep, pfn_pte(pa >> PAGE_SHIFT,
__pgprot(flags)));
- spin_unlock(&ioremap_mm.page_table_lock);
+ spin_unlock(&init_mm.page_table_lock);
} else {
unsigned long va, vpn, hash, hpteg;
for (i = 0; i < size; i += PAGE_SIZE)
if (map_io_page(ea+i, pa+i, flags))
- goto failure;
+ return NULL;
return (void __iomem *) (ea + (addr & ~PAGE_MASK));
- failure:
- if (mem_init_done)
- unmap_im_area(ea, ea + size);
- return NULL;
}
*/
void iounmap(volatile void __iomem *token)
{
- unsigned long address, size;
void *addr;
if (!mem_init_done)
return;
addr = (void *) ((unsigned long __force) token & PAGE_MASK);
-
- if ((size = im_free(addr)) == 0)
- return;
- address = (unsigned long)addr;
- unmap_im_area(address, address + size);
+ im_free(addr);
}
static int iounmap_subset_regions(unsigned long addr, unsigned long size)
tmpstr[i] = c;
}
tmpstr[i++] = 0;
- *vp = kallsyms_lookup_name(tmpstr);
+ *vp = 0;
+ if (setjmp(bus_error_jmp) == 0) {
+ catch_memory_errors = 1;
+ sync();
+ *vp = kallsyms_lookup_name(tmpstr);
+ sync();
+ }
+ catch_memory_errors = 0;
if (!(*vp)) {
printf("unknown symbol '%s'\n", tmpstr);
return 0;
#include "../../../fs/compat_ioctl.c"
/* s390 only ioctls */
-#if defined(CONFIG_DASD) || defined(CONFIG_DASD_MODULE)
COMPATIBLE_IOCTL(DASDAPIVER)
COMPATIBLE_IOCTL(BIODASDDISABLE)
COMPATIBLE_IOCTL(BIODASDENABLE)
COMPATIBLE_IOCTL(BIODASDPSRD)
COMPATIBLE_IOCTL(BIODASDGATTR)
COMPATIBLE_IOCTL(BIODASDSATTR)
-#if defined(CONFIG_DASD_CMB) || defined(CONFIG_DASD_CMB_MODULE)
COMPATIBLE_IOCTL(BIODASDCMFENABLE)
COMPATIBLE_IOCTL(BIODASDCMFDISABLE)
COMPATIBLE_IOCTL(BIODASDREADALLCMB)
-#endif
-#endif
-#if defined(CONFIG_S390_TAPE) || defined(CONFIG_S390_TAPE_MODULE)
COMPATIBLE_IOCTL(TAPE390_DISPLAY)
-#endif
/* s390 doesn't need handlers here */
COMPATIBLE_IOCTL(TIOCGSERIAL)
bno .Lnoreset
la %r2,.Lreset
lhi %r3,26
- .long 0x83230008
+ diag %r2,%r3,8
+ mvc 0x78(8),.Lrdrnewpsw # set up IO interrupt psw
+.Lwaitrdrirq:
+ lpsw .Lrdrwaitpsw
+.Lrdrint:
+ c %r1,0xb8 # compare subchannel number
+ bne .Lwaitrdrirq
+ la %r5,.Lirb
+ tsch 0(%r5)
.Lnoreset:
+ b .Lnoload
+
+ .align 8
+.Lrdrnewpsw:
+ .long 0x00080000,0x80000000+.Lrdrint
+.Lrdrwaitpsw:
+ .long 0x020a0000,0x80000000+.Lrdrint
#endif
-
+
#
# everything loaded, go for it
#
l %r2, .Lrcp2-.LPG1(%r13) # try with Read SCP
b .Lservicecall-.LPG1(%r13)
.Lprocsccb:
- lh %r1,.Lscpincr1-PARMAREA(%r4) # use this one if != 0
- chi %r1,0x00
- jne .Lscnd
- l %r1,.Lscpincr2-PARMAREA(%r4) # otherwise use this one
+ lhi %r1,0
+ icm %r1,3,.Lscpincr1-PARMAREA(%r4) # use this one if != 0
+ jnz .Lscnd
+ l %r1,.Lscpincr2-PARMAREA+4(%r4) # otherwise use this one
.Lscnd:
xr %r3,%r3 # same logic
ic %r3,.Lscpa1-PARMAREA(%r4)
bno .Lnoreset
la %r2,.Lreset
lhi %r3,26
- .long 0x83230008
+ diag %r2,%r3,8
+ mvc 0x78(8),.Lrdrnewpsw # set up IO interrupt psw
+.Lwaitrdrirq:
+ lpsw .Lrdrwaitpsw
+.Lrdrint:
+ c %r1,0xb8 # compare subchannel number
+ bne .Lwaitrdrirq
+ la %r5,.Lirb
+ tsch 0(%r5)
.Lnoreset:
+ b .Lnoload
+
+ .align 8
+.Lrdrnewpsw:
+ .long 0x00080000,0x80000000+.Lrdrint
+.Lrdrwaitpsw:
+ .long 0x020a0000,0x80000000+.Lrdrint
#endif
-
+
#
# everything loaded, go for it
#
l %r2,.Lrcp2-.LPG1(%r13) # try with Read SCP
b .Lservicecall-.LPG1(%r13)
.Lprocsccb:
- lh %r1,.Lscpincr1-PARMAREA(%r4) # use this one if != 0
- chi %r1,0x00
- jne .Lscnd
+ lghi %r1,0
+ icm %r1,3,.Lscpincr1-PARMAREA(%r4) # use this one if != 0
+ jnz .Lscnd
lg %r1,.Lscpincr2-PARMAREA(%r4) # otherwise use this one
.Lscnd:
xr %r3,%r3 # same logic
asmlinkage void kernel_stack_overflow(struct pt_regs * regs)
{
- die("Kernel stack overflow", regs, 0);
+ bust_spinlocks(1);
+ printk("Kernel stack overflow.\n");
+ show_regs(regs);
+ bust_spinlocks(0);
panic("Corrupt kernel stack, can't continue.");
}
#include <asm/uaccess.h>
static char *sender = "VMRMSVM";
-module_param(sender, charp, 0);
+module_param(sender, charp, 0400);
MODULE_PARM_DESC(sender,
"Guest name that may send SMSG messages (default VMRMSVM)");
(!vma || addr + len <= vma->vm_start))
return addr;
}
+ if (len <= mm->cached_hole_size) {
+ mm->cached_hole_size = 0;
+ mm->free_area_cache = TASK_UNMAPPED_BASE;
+ }
if (flags & MAP_PRIVATE)
addr = PAGE_ALIGN(mm->free_area_cache);
else
*/
if (start_addr != TASK_UNMAPPED_BASE) {
start_addr = addr = TASK_UNMAPPED_BASE;
+ mm->cached_hole_size = 0;
goto full_search;
}
return -ENOMEM;
mm->free_area_cache = addr + len;
return addr;
}
+ if (addr + mm->cached_hole_size < vma->vm_start)
+ mm->cached_hole_size = vma->vm_start - addr;
+
addr = vma->vm_end;
if (!(flags & MAP_PRIVATE))
addr = COLOUR_ALIGN(addr);
__asm__("dmulu.l %0, %2\n\t"
"sts mach, %0"
: "=r" (xloops)
- : "0" (xloops), "r" (cpu_data[_smp_processor_id()].loops_per_jiffy)
+ : "0" (xloops), "r" (cpu_data[raw_smp_processor_id()].loops_per_jiffy)
: "macl", "mach");
__delay(xloops * HZ);
}
#include <asm/tlbflush.h>
#include <asm/cacheflush.h>
-static pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr)
+pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr)
{
pgd_t *pgd;
pmd_t *pmd;
return pte;
}
-static pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
+pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
{
pgd_t *pgd;
pmd_t *pmd;
#define mk_pte_huge(entry) do { pte_val(entry) |= _PAGE_SZHUGE; } while (0)
-static void set_huge_pte(struct mm_struct *mm, struct vm_area_struct *vma,
- struct page *page, pte_t * page_table, int write_access)
+void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t entry)
{
- unsigned long i;
- pte_t entry;
+ int i;
- add_mm_counter(mm, rss, HPAGE_SIZE / PAGE_SIZE);
+ for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) {
+ set_pte_at(mm, addr, ptep, entry);
+ ptep++;
+ addr += PAGE_SIZE;
+ pte_val(entry) += PAGE_SIZE;
+ }
+}
- if (write_access)
- entry = pte_mkwrite(pte_mkdirty(mk_pte(page,
- vma->vm_page_prot)));
- else
- entry = pte_wrprotect(mk_pte(page, vma->vm_page_prot));
- entry = pte_mkyoung(entry);
- mk_pte_huge(entry);
+pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep)
+{
+ pte_t entry;
+ int i;
- for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) {
- set_pte(page_table, entry);
- page_table++;
+ entry = *ptep;
- pte_val(entry) += PAGE_SIZE;
+ for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) {
+ pte_clear(mm, addr, ptep);
+ addr += PAGE_SIZE;
+ ptep++;
}
+
+ return entry;
}
/*
return 0;
}
-int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
- struct vm_area_struct *vma)
-{
- pte_t *src_pte, *dst_pte, entry;
- struct page *ptepage;
- unsigned long addr = vma->vm_start;
- unsigned long end = vma->vm_end;
- int i;
-
- while (addr < end) {
- dst_pte = huge_pte_alloc(dst, addr);
- if (!dst_pte)
- goto nomem;
- src_pte = huge_pte_offset(src, addr);
- BUG_ON(!src_pte || pte_none(*src_pte));
- entry = *src_pte;
- ptepage = pte_page(entry);
- get_page(ptepage);
- for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) {
- set_pte(dst_pte, entry);
- pte_val(entry) += PAGE_SIZE;
- dst_pte++;
- }
- add_mm_counter(dst, rss, HPAGE_SIZE / PAGE_SIZE);
- addr += HPAGE_SIZE;
- }
- return 0;
-
-nomem:
- return -ENOMEM;
-}
-
-int follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma,
- struct page **pages, struct vm_area_struct **vmas,
- unsigned long *position, int *length, int i)
-{
- unsigned long vaddr = *position;
- int remainder = *length;
-
- WARN_ON(!is_vm_hugetlb_page(vma));
-
- while (vaddr < vma->vm_end && remainder) {
- if (pages) {
- pte_t *pte;
- struct page *page;
-
- pte = huge_pte_offset(mm, vaddr);
-
- /* hugetlb should be locked, and hence, prefaulted */
- BUG_ON(!pte || pte_none(*pte));
-
- page = pte_page(*pte);
-
- WARN_ON(!PageCompound(page));
-
- get_page(page);
- pages[i] = page;
- }
-
- if (vmas)
- vmas[i] = vma;
-
- vaddr += PAGE_SIZE;
- --remainder;
- ++i;
- }
-
- *length = remainder;
- *position = vaddr;
-
- return i;
-}
-
struct page *follow_huge_addr(struct mm_struct *mm,
unsigned long address, int write)
{
{
return NULL;
}
-
-void unmap_hugepage_range(struct vm_area_struct *vma,
- unsigned long start, unsigned long end)
-{
- struct mm_struct *mm = vma->vm_mm;
- unsigned long address;
- pte_t *pte;
- struct page *page;
- int i;
-
- BUG_ON(start & (HPAGE_SIZE - 1));
- BUG_ON(end & (HPAGE_SIZE - 1));
-
- for (address = start; address < end; address += HPAGE_SIZE) {
- pte = huge_pte_offset(mm, address);
- BUG_ON(!pte);
- if (pte_none(*pte))
- continue;
- page = pte_page(*pte);
- put_page(page);
- for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) {
- pte_clear(mm, address+(i*PAGE_SIZE), pte);
- pte++;
- }
- }
- add_mm_counter(mm, rss, -((end - start) >> PAGE_SHIFT));
- flush_tlb_range(vma, start, end);
-}
-
-int hugetlb_prefault(struct address_space *mapping, struct vm_area_struct *vma)
-{
- struct mm_struct *mm = current->mm;
- unsigned long addr;
- int ret = 0;
-
- BUG_ON(vma->vm_start & ~HPAGE_MASK);
- BUG_ON(vma->vm_end & ~HPAGE_MASK);
-
- spin_lock(&mm->page_table_lock);
- for (addr = vma->vm_start; addr < vma->vm_end; addr += HPAGE_SIZE) {
- unsigned long idx;
- pte_t *pte = huge_pte_alloc(mm, addr);
- struct page *page;
-
- if (!pte) {
- ret = -ENOMEM;
- goto out;
- }
- if (!pte_none(*pte))
- continue;
-
- idx = ((addr - vma->vm_start) >> HPAGE_SHIFT)
- + (vma->vm_pgoff >> (HPAGE_SHIFT - PAGE_SHIFT));
- page = find_get_page(mapping, idx);
- if (!page) {
- /* charge the fs quota first */
- if (hugetlb_get_quota(mapping)) {
- ret = -ENOMEM;
- goto out;
- }
- page = alloc_huge_page();
- if (!page) {
- hugetlb_put_quota(mapping);
- ret = -ENOMEM;
- goto out;
- }
- ret = add_to_page_cache(page, mapping, idx, GFP_ATOMIC);
- if (! ret) {
- unlock_page(page);
- } else {
- hugetlb_put_quota(mapping);
- free_huge_page(page);
- goto out;
- }
- }
- set_huge_pte(mm, vma, page, pte, vma->vm_flags & VM_WRITE);
- }
-out:
- spin_unlock(&mm->page_table_lock);
- return ret;
-}
#include <asm/tlbflush.h>
#include <asm/cacheflush.h>
-static pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr)
+pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr)
{
pgd_t *pgd;
pmd_t *pmd;
return pte;
}
-static pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
+pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
{
pgd_t *pgd;
pmd_t *pmd;
}
}
+pte_t huge_ptep_get_and_clear(pte_t *ptep)
+{
+ pte_t entry;
+
+ entry = *ptep;
+
+ for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) {
+ pte_clear(pte);
+ pte++;
+ }
+
+ return entry;
+}
+
/*
* This function checks for proper alignment of input addr and len parameters.
*/
struct page *page = pfn_to_page(tmp);
ClearPageReserved(page);
- set_bit(PG_highmem, &page->flags);
set_page_count(page, 1);
__free_page(page);
totalhigh_pages++;
return addr;
}
+ if (len <= mm->cached_hole_size) {
+ mm->cached_hole_size = 0;
+ mm->free_area_cache = TASK_UNMAPPED_BASE;
+ }
start_addr = addr = mm->free_area_cache;
task_size -= len;
if (task_size < addr) {
if (start_addr != TASK_UNMAPPED_BASE) {
start_addr = addr = TASK_UNMAPPED_BASE;
+ mm->cached_hole_size = 0;
goto full_search;
}
return -ENOMEM;
mm->free_area_cache = addr + len;
return addr;
}
+ if (addr + mm->cached_hole_size < vma->vm_start)
+ mm->cached_hole_size = vma->vm_start - addr;
+
addr = vma->vm_end;
if (do_color_align)
addr = COLOUR_ALIGN(addr, pgoff);
{
n *= 4;
- n *= (cpu_data(_smp_processor_id()).udelay_val * (HZ/4));
+ n *= (cpu_data(raw_smp_processor_id()).udelay_val * (HZ/4));
n >>= 32;
__delay(n + 1);
#include <asm/cacheflush.h>
#include <asm/mmu_context.h>
-static pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr)
+pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr)
{
pgd_t *pgd;
pud_t *pud;
return pte;
}
-static pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
+pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
{
pgd_t *pgd;
pud_t *pud;
#define mk_pte_huge(entry) do { pte_val(entry) |= _PAGE_SZHUGE; } while (0)
-static void set_huge_pte(struct mm_struct *mm, struct vm_area_struct *vma,
- unsigned long addr,
- struct page *page, pte_t * page_table, int write_access)
+void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t entry)
{
- unsigned long i;
- pte_t entry;
+ int i;
+
+ for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) {
+ set_pte_at(mm, addr, ptep, entry);
+ ptep++;
+ addr += PAGE_SIZE;
+ pte_val(entry) += PAGE_SIZE;
+ }
+}
- add_mm_counter(mm, rss, HPAGE_SIZE / PAGE_SIZE);
+pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep)
+{
+ pte_t entry;
+ int i;
- if (write_access)
- entry = pte_mkwrite(pte_mkdirty(mk_pte(page,
- vma->vm_page_prot)));
- else
- entry = pte_wrprotect(mk_pte(page, vma->vm_page_prot));
- entry = pte_mkyoung(entry);
- mk_pte_huge(entry);
+ entry = *ptep;
for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) {
- set_pte_at(mm, addr, page_table, entry);
- page_table++;
+ pte_clear(mm, addr, ptep);
addr += PAGE_SIZE;
-
- pte_val(entry) += PAGE_SIZE;
+ ptep++;
}
+
+ return entry;
}
/*
return 0;
}
-int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
- struct vm_area_struct *vma)
-{
- pte_t *src_pte, *dst_pte, entry;
- struct page *ptepage;
- unsigned long addr = vma->vm_start;
- unsigned long end = vma->vm_end;
- int i;
-
- while (addr < end) {
- dst_pte = huge_pte_alloc(dst, addr);
- if (!dst_pte)
- goto nomem;
- src_pte = huge_pte_offset(src, addr);
- BUG_ON(!src_pte || pte_none(*src_pte));
- entry = *src_pte;
- ptepage = pte_page(entry);
- get_page(ptepage);
- for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) {
- set_pte_at(dst, addr, dst_pte, entry);
- pte_val(entry) += PAGE_SIZE;
- dst_pte++;
- addr += PAGE_SIZE;
- }
- add_mm_counter(dst, rss, HPAGE_SIZE / PAGE_SIZE);
- }
- return 0;
-
-nomem:
- return -ENOMEM;
-}
-
-int follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma,
- struct page **pages, struct vm_area_struct **vmas,
- unsigned long *position, int *length, int i)
-{
- unsigned long vaddr = *position;
- int remainder = *length;
-
- WARN_ON(!is_vm_hugetlb_page(vma));
-
- while (vaddr < vma->vm_end && remainder) {
- if (pages) {
- pte_t *pte;
- struct page *page;
-
- pte = huge_pte_offset(mm, vaddr);
-
- /* hugetlb should be locked, and hence, prefaulted */
- BUG_ON(!pte || pte_none(*pte));
-
- page = pte_page(*pte);
-
- WARN_ON(!PageCompound(page));
-
- get_page(page);
- pages[i] = page;
- }
-
- if (vmas)
- vmas[i] = vma;
-
- vaddr += PAGE_SIZE;
- --remainder;
- ++i;
- }
-
- *length = remainder;
- *position = vaddr;
-
- return i;
-}
-
struct page *follow_huge_addr(struct mm_struct *mm,
unsigned long address, int write)
{
return NULL;
}
-void unmap_hugepage_range(struct vm_area_struct *vma,
- unsigned long start, unsigned long end)
-{
- struct mm_struct *mm = vma->vm_mm;
- unsigned long address;
- pte_t *pte;
- struct page *page;
- int i;
-
- BUG_ON(start & (HPAGE_SIZE - 1));
- BUG_ON(end & (HPAGE_SIZE - 1));
-
- for (address = start; address < end; address += HPAGE_SIZE) {
- pte = huge_pte_offset(mm, address);
- BUG_ON(!pte);
- if (pte_none(*pte))
- continue;
- page = pte_page(*pte);
- put_page(page);
- for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) {
- pte_clear(mm, address+(i*PAGE_SIZE), pte);
- pte++;
- }
- }
- add_mm_counter(mm, rss, -((end - start) >> PAGE_SHIFT));
- flush_tlb_range(vma, start, end);
-}
-
static void context_reload(void *__data)
{
struct mm_struct *mm = __data;
load_secondary_context(mm);
}
-int hugetlb_prefault(struct address_space *mapping, struct vm_area_struct *vma)
+void hugetlb_prefault_arch_hook(struct mm_struct *mm)
{
- struct mm_struct *mm = current->mm;
- unsigned long addr;
- int ret = 0;
-
/* On UltraSPARC-III+ and later, configure the second half of
* the Data-TLB for huge pages.
*/
}
spin_unlock(&ctx_alloc_lock);
}
-
- BUG_ON(vma->vm_start & ~HPAGE_MASK);
- BUG_ON(vma->vm_end & ~HPAGE_MASK);
-
- spin_lock(&mm->page_table_lock);
- for (addr = vma->vm_start; addr < vma->vm_end; addr += HPAGE_SIZE) {
- unsigned long idx;
- pte_t *pte = huge_pte_alloc(mm, addr);
- struct page *page;
-
- if (!pte) {
- ret = -ENOMEM;
- goto out;
- }
- if (!pte_none(*pte))
- continue;
-
- idx = ((addr - vma->vm_start) >> HPAGE_SHIFT)
- + (vma->vm_pgoff >> (HPAGE_SHIFT - PAGE_SHIFT));
- page = find_get_page(mapping, idx);
- if (!page) {
- /* charge the fs quota first */
- if (hugetlb_get_quota(mapping)) {
- ret = -ENOMEM;
- goto out;
- }
- page = alloc_huge_page();
- if (!page) {
- hugetlb_put_quota(mapping);
- ret = -ENOMEM;
- goto out;
- }
- ret = add_to_page_cache(page, mapping, idx, GFP_ATOMIC);
- if (! ret) {
- unlock_page(page);
- } else {
- hugetlb_put_quota(mapping);
- free_huge_page(page);
- goto out;
- }
- }
- set_huge_pte(mm, vma, addr, page, pte, vma->vm_flags & VM_WRITE);
- }
-out:
- spin_unlock(&mm->page_table_lock);
- return ret;
}
unsigned long *kcmsg;
compat_size_t cmlen;
- if(kern_msg.msg_controllen > sizeof(ctl) &&
- kern_msg.msg_controllen <= 256) {
+ if (kern_msg.msg_controllen <= sizeof(compat_size_t))
+ return -EINVAL;
+
+ if(kern_msg.msg_controllen > sizeof(ctl)) {
err = -ENOBUFS;
ctl_buf = kmalloc(kern_msg.msg_controllen, GFP_KERNEL);
if(!ctl_buf)
bool
default y
+# Used in kernel/irq/manage.c and include/linux/irq.h
+config IRQ_RELEASE_METHOD
+ bool
+ default y
+
menu "UML-specific options"
config MODE_TT
CPPFLAGS_vmlinux.lds = $(shell echo -U$(SUBARCH) \
-DSTART=$(START) -DELF_ARCH=$(ELF_ARCH) \
-DELF_FORMAT=\"$(ELF_FORMAT)\" $(CPP_MODE-y) \
- -DKERNEL_STACK_SIZE=$(STACK_SIZE))
+ -DKERNEL_STACK_SIZE=$(STACK_SIZE) -DSUBARCH=$(SUBARCH))
#The wrappers will select whether using "malloc" or the kernel allocator.
LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc
if(line->driver->read_irq == current_irq)
free_irq_later(line->driver->read_irq, tty);
else {
- free_irq_by_irq_and_dev(line->driver->read_irq, tty);
free_irq(line->driver->read_irq, tty);
}
if(line->driver->write_irq == current_irq)
free_irq_later(line->driver->write_irq, tty);
else {
- free_irq_by_irq_and_dev(line->driver->write_irq, tty);
free_irq(line->driver->write_irq, tty);
}
if(winch->pid != -1)
os_kill_process(winch->pid, 1);
- free_irq_by_irq_and_dev(WINCH_IRQ, winch);
free_irq(WINCH_IRQ, winch);
list_del(&winch->list);
kfree(winch);
netif_stop_queue(dev);
spin_lock(&lp->lock);
- free_irq_by_irq_and_dev(dev->irq, dev);
free_irq(dev->irq, dev);
if(lp->close != NULL)
(*lp->close)(lp->fd, &lp->user);
* connection. Then we loop here throwing out failed
* connections until a good one is found.
*/
- free_irq_by_irq_and_dev(TELNETD_IRQ, conn);
free_irq(TELNETD_IRQ, conn);
if(conn->fd >= 0) break;
* isn't set) this will hang... */
wait_for_completion(&data->ready);
- free_irq_by_irq_and_dev(XTERM_IRQ, data);
free_irq(XTERM_IRQ, data);
ret = data->new_fd;
spin_unlock_irqrestore(&irq_spinlock, flags);
}
-/* presently hw_interrupt_type must define (startup || enable) &&
- * disable && end */
+/* hw_interrupt_type must define (startup || enable) &&
+ * (shutdown || disable) && end */
static void dummy(unsigned int irq)
{
}
-static struct hw_interrupt_type SIGIO_irq_type = {
+/* This is used for everything else than the timer. */
+static struct hw_interrupt_type normal_irq_type = {
.typename = "SIGIO",
+ .release = free_irq_by_irq_and_dev,
.disable = dummy,
.enable = dummy,
.ack = dummy,
static struct hw_interrupt_type SIGVTALRM_irq_type = {
.typename = "SIGVTALRM",
+ .release = free_irq_by_irq_and_dev,
.shutdown = dummy, /* never called */
.disable = dummy,
.enable = dummy,
irq_desc[i].status = IRQ_DISABLED;
irq_desc[i].action = NULL;
irq_desc[i].depth = 1;
- irq_desc[i].handler = &SIGIO_irq_type;
+ irq_desc[i].handler = &normal_irq_type;
enable_irq(i);
}
}
next = irq_fd->next;
if(irq_fd->freed){
free_irq(irq_fd->irq, irq_fd->id);
- free_irq_by_irq_and_dev(irq_fd->irq,
- irq_fd->id);
}
}
}
for(i = 0; i < highmem_len >> PAGE_SHIFT; i++){
page = &mem_map[highmem_pfn + i];
ClearPageReserved(page);
- set_bit(PG_highmem, &page->flags);
set_page_count(page, 1);
__free_page(page);
}
# Licensed under the GPL
#
-extra-y := unmap_fin.o
-targets := unmap.o
-clean-files := unmap_tmp.o
-
obj-y = exec_kern.o exec_user.o gdb.o ksyms.o mem.o mem_user.o process_kern.o \
syscall_kern.o syscall_user.o time.o tlb.o tracer.o trap_user.o \
uaccess.o uaccess_user.o
USER_OBJS := gdb.o time.o tracer.o
include arch/um/scripts/Makefile.rules
-
-UNMAP_CFLAGS := $(patsubst -pg -DPROFILING,,$(USER_CFLAGS))
-UNMAP_CFLAGS := $(patsubst -fprofile-arcs -ftest-coverage,,$(UNMAP_CFLAGS))
-
-#XXX: partially copied from arch/um/scripts/Makefile.rules
-$(obj)/unmap.o: c_flags = -Wp,-MD,$(depfile) $(UNMAP_CFLAGS)
-
-$(obj)/unmap_fin.o : $(obj)/unmap.o
- $(LD) -r -o $(obj)/unmap_tmp.o $< $(shell $(CC) -print-file-name=libc.a)
- $(OBJCOPY) $(obj)/unmap_tmp.o $@ -G switcheroo
-
+++ /dev/null
-/*
- * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#include <sys/mman.h>
-
-int switcheroo(int fd, int prot, void *from, void *to, int size)
-{
- if(munmap(to, size) < 0){
- return(-1);
- }
- if(mmap(to, size, prot, MAP_SHARED | MAP_FIXED, fd, 0) != to){
- return(-1);
- }
- if(munmap(from, size) < 0){
- return(-1);
- }
- 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:
- */
/* Used in arch/um/kernel/mem.c. Any memory between START and __binary_start
* is remapped.*/
__binary_start = .;
-#ifdef MODE_TT
- .thread_private : {
- __start_thread_private = .;
- errno = .;
- . += 4;
- arch/um/kernel/tt/unmap_fin.o (.data)
- __end_thread_private = .;
- }
- . = ALIGN(4096);
- .remap : { arch/um/kernel/tt/unmap_fin.o (.text) }
- /* We want it only if we are in MODE_TT. In both cases, however, when MODE_TT
- * is off the resulting binary segfaults.*/
+#ifdef MODE_TT
+ .remap_data : { arch/um/sys-SUBARCH/unmap_fin.o (.data .bss) }
+ .remap : { arch/um/sys-SUBARCH/unmap_fin.o (.text) }
. = ALIGN(4096); /* Init code and data */
#endif
$(USER_OBJS) : c_flags = -Wp,-MD,$(depfile) $(USER_CFLAGS) \
$(CFLAGS_$(notdir $@))
+# The stubs and unmap.o can't try to call mcount or update basic block data
+define unprofile
+ $(patsubst -pg,,$(patsubst -fprofile-arcs -ftest-coverage,,$(1)))
+endef
+
+
quiet_cmd_make_link = SYMLINK $@
cmd_make_link = ln -sf $(srctree)/arch/$(SUBARCH)/$($(notdir $@)-dir)/$(notdir $@) $@
--- /dev/null
+clean-files += unmap_tmp.o unmap_fin.o unmap.o
+
+ifdef CONFIG_MODE_TT
+
+#Always build unmap_fin.o
+extra-y += unmap_fin.o
+#Do dependency tracking for unmap.o (it will be always built, but won't get the tracking unless we use this).
+targets += unmap.o
+
+#XXX: partially copied from arch/um/scripts/Makefile.rules
+$(obj)/unmap.o: _c_flags = $(call unprofile,$(CFLAGS))
+
+quiet_cmd_wrapld = LD $@
+define cmd_wrapld
+ $(LD) -r -o $(obj)/unmap_tmp.o $< $(shell $(CC) -print-file-name=libc.a); \
+ $(OBJCOPY) $(obj)/unmap_tmp.o $@ -G switcheroo
+endef
+
+$(obj)/unmap_fin.o : $(obj)/unmap.o FORCE
+ $(call if_changed,wrapld)
+
+endif
module.c-dir = kernel
subdir- := util
+
+include arch/um/scripts/Makefile.unmap
--- /dev/null
+/*
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <linux/mman.h>
+#include <asm/unistd.h>
+
+static int errno;
+
+static inline _syscall2(int,munmap,void *,start,size_t,len)
+static inline _syscall6(void *,mmap2,void *,addr,size_t,len,int,prot,int,flags,int,fd,off_t,offset)
+int switcheroo(int fd, int prot, void *from, void *to, int size)
+{
+ if(munmap(to, size) < 0){
+ return(-1);
+ }
+ if(mmap2(to, size, prot, MAP_SHARED | MAP_FIXED, fd, 0) != to){
+ return(-1);
+ }
+ if(munmap(from, size) < 0){
+ return(-1);
+ }
+ return(0);
+}
module.c-dir = kernel
subdir- := util
+
+include arch/um/scripts/Makefile.unmap
--- /dev/null
+/*
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <linux/mman.h>
+#include <asm/unistd.h>
+
+static int errno;
+
+static inline _syscall2(int,munmap,void *,start,size_t,len)
+static inline _syscall6(void *,mmap,void *,addr,size_t,len,int,prot,int,flags,int,fd,off_t,offset)
+int switcheroo(int fd, int prot, void *from, void *to, int size)
+{
+ if(munmap(to, size) < 0){
+ return(-1);
+ }
+ if(mmap(to, size, prot, MAP_SHARED | MAP_FIXED, fd, 0) != to){
+ return(-1);
+ }
+ if(munmap(from, size) < 0){
+ return(-1);
+ }
+ return(0);
+}
current->mm->brk = ex.a_bss +
(current->mm->start_brk = N_BSSADDR(ex));
current->mm->free_area_cache = TASK_UNMAPPED_BASE;
+ current->mm->cached_hole_size = 0;
set_mm_counter(current->mm, rss, 0);
current->mm->mmap = NULL;
#define IA32_EMULATOR 1
-#define ELF_ET_DYN_BASE (TASK_UNMAPPED_32 + 0x1000000)
+#define ELF_ET_DYN_BASE (TASK_UNMAPPED_BASE + 0x1000000)
#undef ELF_ARCH
#define ELF_ARCH EM_386
#define elf_addr_t __u32
-#undef TASK_SIZE
-#define TASK_SIZE 0xffffffff
-
static void elf32_init(struct pt_regs *);
#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1
switch (code) {
case ARCH_SET_GS:
- if (addr >= TASK_SIZE)
+ if (addr >= TASK_SIZE_OF(task))
return -EPERM;
cpu = get_cpu();
/* handle small bases via the GDT because that's faster to
case ARCH_SET_FS:
/* Not strictly needed for fs, but do it for symmetry
with gs */
- if (addr >= TASK_SIZE)
+ if (addr >= TASK_SIZE_OF(task))
return -EPERM;
cpu = get_cpu();
/* handle small bases via the GDT because that's faster to
value &= 0xffff;
return 0;
case offsetof(struct user_regs_struct,fs_base):
- if (value >= TASK_SIZE)
+ if (value >= TASK_SIZE_OF(child))
return -EIO;
child->thread.fs = value;
return 0;
case offsetof(struct user_regs_struct,gs_base):
- if (value >= TASK_SIZE)
+ if (value >= TASK_SIZE_OF(child))
return -EIO;
child->thread.gs = value;
return 0;
break;
case offsetof(struct user_regs_struct, rip):
/* Check if the new RIP address is canonical */
- if (value >= TASK_SIZE)
+ if (value >= TASK_SIZE_OF(child))
return -EIO;
break;
}
break;
case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
+ {
+ int dsize = test_tsk_thread_flag(child, TIF_IA32) ? 3 : 7;
ret = -EIO;
if ((addr & 7) ||
addr > sizeof(struct user) - 7)
break;
/* Disallows to set a breakpoint into the vsyscall */
case offsetof(struct user, u_debugreg[0]):
- if (data >= TASK_SIZE-7) break;
+ if (data >= TASK_SIZE_OF(child) - dsize) break;
child->thread.debugreg0 = data;
ret = 0;
break;
case offsetof(struct user, u_debugreg[1]):
- if (data >= TASK_SIZE-7) break;
+ if (data >= TASK_SIZE_OF(child) - dsize) break;
child->thread.debugreg1 = data;
ret = 0;
break;
case offsetof(struct user, u_debugreg[2]):
- if (data >= TASK_SIZE-7) break;
+ if (data >= TASK_SIZE_OF(child) - dsize) break;
child->thread.debugreg2 = data;
ret = 0;
break;
case offsetof(struct user, u_debugreg[3]):
- if (data >= TASK_SIZE-7) break;
+ if (data >= TASK_SIZE_OF(child) - dsize) break;
child->thread.debugreg3 = data;
ret = 0;
break;
break;
}
break;
+ }
case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
case PTRACE_CONT: /* restart after signal. */
static void find_start_end(unsigned long flags, unsigned long *begin,
unsigned long *end)
{
-#ifdef CONFIG_IA32_EMULATION
- if (test_thread_flag(TIF_IA32)) {
- *begin = TASK_UNMAPPED_32;
- *end = IA32_PAGE_OFFSET;
- } else
-#endif
- if (flags & MAP_32BIT) {
+ if (!test_thread_flag(TIF_IA32) && (flags & MAP_32BIT)) {
/* This is usually used needed to map code in small
model, so it needs to be in the first 31bit. Limit
it to that. This means we need to move the
of playground for now. -AK */
*begin = 0x40000000;
*end = 0x80000000;
- } else {
- *begin = TASK_UNMAPPED_64;
+ } else {
+ *begin = TASK_UNMAPPED_BASE;
*end = TASK_SIZE;
- }
+ }
}
unsigned long
(!vma || addr + len <= vma->vm_start))
return addr;
}
+ if (((flags & MAP_32BIT) || test_thread_flag(TIF_IA32))
+ && len <= mm->cached_hole_size) {
+ mm->cached_hole_size = 0;
+ mm->free_area_cache = begin;
+ }
addr = mm->free_area_cache;
if (addr < begin)
addr = begin;
*/
if (start_addr != begin) {
start_addr = addr = begin;
+ mm->cached_hole_size = 0;
goto full_search;
}
return -ENOMEM;
mm->free_area_cache = addr + len;
return addr;
}
+ if (addr + mm->cached_hole_size < vma->vm_start)
+ mm->cached_hole_size = vma->vm_start - addr;
+
addr = vma->vm_end;
}
}
inline void __const_udelay(unsigned long xloops)
{
- __delay(((xloops * cpu_data[_smp_processor_id()].loops_per_jiffy) >> 32) * HZ);
+ __delay(((xloops * cpu_data[raw_smp_processor_id()].loops_per_jiffy) >> 32) * HZ);
}
void __udelay(unsigned long usecs)
* (error_code & 4) == 0, and that the fault was not a
* protection error (error_code & 1) == 0.
*/
- if (unlikely(address >= TASK_SIZE)) {
+ if (unlikely(address >= TASK_SIZE64)) {
if (!(error_code & 5) &&
((address >= VMALLOC_START && address < VMALLOC_END) ||
(address >= MODULES_VADDR && address < MODULES_END))) {
source "drivers/infiniband/Kconfig"
+source "drivers/sn/Kconfig"
+
endmenu
obj-$(CONFIG_CPU_FREQ) += cpufreq/
obj-$(CONFIG_MMC) += mmc/
obj-$(CONFIG_INFINIBAND) += infiniband/
-obj-$(CONFIG_BLK_DEV_SGIIOC4) += sn/
+obj-$(CONFIG_SGI_IOC4) += sn/
obj-y += firmware/
obj-$(CONFIG_CRYPTO) += crypto/
static struct i2c_client_address_data addr_data = {
.normal_i2c = normal_addr,
- .normal_i2c_range = ignore,
.probe = ignore,
- .probe_range = ignore,
.ignore = ignore,
- .ignore_range = ignore,
.force = ignore,
};
int sleep_ticks = 0;
u32 t1, t2 = 0;
- pr = processors[_smp_processor_id()];
+ pr = processors[raw_smp_processor_id()];
if (!pr)
return;
for (i = 0; i < MAX_NR_ZONES; i++) {
struct zone *z = &pg->node_zones[i];
for (cpu = 0; cpu < NR_CPUS; cpu++) {
- struct per_cpu_pageset *ps = &z->pageset[cpu];
+ struct per_cpu_pageset *ps = zone_pcp(z,cpu);
numa_hit += ps->numa_hit;
numa_miss += ps->numa_miss;
numa_foreign += ps->numa_foreign;
If compiled as a module, it will be called scx200_gpio.
+config GPIO_VR41XX
+ tristate "NEC VR4100 series General-purpose I/O Unit support"
+ depends on CPU_VR41XX
+
config RAW_DRIVER
tristate "RAW driver (/dev/raw/rawN) (OBSOLETE)"
help
obj-$(CONFIG_NWBUTTON) += nwbutton.o
obj-$(CONFIG_NWFLASH) += nwflash.o
obj-$(CONFIG_SCx200_GPIO) += scx200_gpio.o
+obj-$(CONFIG_GPIO_VR41XX) += vr41xx_giu.o
obj-$(CONFIG_TANBAC_TB0219) += tb0219.o
obj-$(CONFIG_WATCHDOG) += watchdog/
return -ENOMEM;
down_read(&interfaces_sem);
- if ((if_num > MAX_IPMI_INTERFACES) || ipmi_interfaces[if_num] == NULL)
+ if ((if_num >= MAX_IPMI_INTERFACES) || ipmi_interfaces[if_num] == NULL)
{
rv = -EINVAL;
goto out_unlock;
return virtr + wrote;
}
-#if defined(CONFIG_ISA) || !defined(__mc68000__)
+#if (defined(CONFIG_ISA) || !defined(__mc68000__)) && (!defined(CONFIG_PPC_ISERIES) || defined(CONFIG_PCI))
static ssize_t read_port(struct file * file, char __user * buf,
size_t count, loff_t *ppos)
{
.write = write_null,
};
-#if defined(CONFIG_ISA) || !defined(__mc68000__)
+#if (defined(CONFIG_ISA) || !defined(__mc68000__)) && (!defined(CONFIG_PPC_ISERIES) || defined(CONFIG_PCI))
static struct file_operations port_fops = {
.llseek = memory_lseek,
.read = read_port,
case 3:
filp->f_op = &null_fops;
break;
-#if defined(CONFIG_ISA) || !defined(__mc68000__)
+#if (defined(CONFIG_ISA) || !defined(__mc68000__)) && (!defined(CONFIG_PPC_ISERIES) || defined(CONFIG_PCI))
case 4:
filp->f_op = &port_fops;
break;
{1, "mem", S_IRUSR | S_IWUSR | S_IRGRP, &mem_fops},
{2, "kmem", S_IRUSR | S_IWUSR | S_IRGRP, &kmem_fops},
{3, "null", S_IRUGO | S_IWUGO, &null_fops},
-#if defined(CONFIG_ISA) || !defined(__mc68000__)
+#if (defined(CONFIG_ISA) || !defined(__mc68000__)) && (!defined(CONFIG_PPC_ISERIES) || defined(CONFIG_PCI))
{4, "port", S_IRUSR | S_IWUSR | S_IRGRP, &port_fops},
#endif
{5, "zero", S_IRUGO | S_IWUGO, &zero_fops},
--- /dev/null
+/*
+ * Driver for NEC VR4100 series General-purpose I/O Unit.
+ *
+ * Copyright (C) 2002 MontaVista Software Inc.
+ * Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com>
+ * Copyright (C) 2003-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
+ */
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#include <asm/cpu.h>
+#include <asm/io.h>
+#include <asm/vr41xx/giu.h>
+#include <asm/vr41xx/vr41xx.h>
+
+MODULE_AUTHOR("Yoichi Yuasa <yuasa@hh.iij4u.or.jp>");
+MODULE_DESCRIPTION("NEC VR4100 series General-purpose I/O Unit driver");
+MODULE_LICENSE("GPL");
+
+static int major; /* default is dynamic major device number */
+module_param(major, int, 0);
+MODULE_PARM_DESC(major, "Major device number");
+
+#define GIU_TYPE1_START 0x0b000100UL
+#define GIU_TYPE1_SIZE 0x20UL
+
+#define GIU_TYPE2_START 0x0f000140UL
+#define GIU_TYPE2_SIZE 0x20UL
+
+#define GIU_TYPE3_START 0x0f000140UL
+#define GIU_TYPE3_SIZE 0x28UL
+
+#define GIU_PULLUPDOWN_START 0x0b0002e0UL
+#define GIU_PULLUPDOWN_SIZE 0x04UL
+
+#define GIUIOSELL 0x00
+#define GIUIOSELH 0x02
+#define GIUPIODL 0x04
+#define GIUPIODH 0x06
+#define GIUINTSTATL 0x08
+#define GIUINTSTATH 0x0a
+#define GIUINTENL 0x0c
+#define GIUINTENH 0x0e
+#define GIUINTTYPL 0x10
+#define GIUINTTYPH 0x12
+#define GIUINTALSELL 0x14
+#define GIUINTALSELH 0x16
+#define GIUINTHTSELL 0x18
+#define GIUINTHTSELH 0x1a
+#define GIUPODATL 0x1c
+#define GIUPODATEN 0x1c
+#define GIUPODATH 0x1e
+ #define PIOEN0 0x0100
+ #define PIOEN1 0x0200
+#define GIUPODAT 0x1e
+#define GIUFEDGEINHL 0x20
+#define GIUFEDGEINHH 0x22
+#define GIUREDGEINHL 0x24
+#define GIUREDGEINHH 0x26
+
+#define GIUUSEUPDN 0x1e0
+#define GIUTERMUPDN 0x1e2
+
+#define GPIO_HAS_PULLUPDOWN_IO 0x0001
+#define GPIO_HAS_OUTPUT_ENABLE 0x0002
+#define GPIO_HAS_INTERRUPT_EDGE_SELECT 0x0100
+
+static spinlock_t giu_lock;
+static struct resource *giu_resource1;
+static struct resource *giu_resource2;
+static unsigned long giu_flags;
+static unsigned int giu_nr_pins;
+
+static void __iomem *giu_base;
+
+#define giu_read(offset) readw(giu_base + (offset))
+#define giu_write(offset, value) writew((value), giu_base + (offset))
+
+#define GPIO_PIN_OF_IRQ(irq) ((irq) - GIU_IRQ_BASE)
+#define GIUINT_HIGH_OFFSET 16
+#define GIUINT_HIGH_MAX 32
+
+static inline uint16_t giu_set(uint16_t offset, uint16_t set)
+{
+ uint16_t data;
+
+ data = giu_read(offset);
+ data |= set;
+ giu_write(offset, data);
+
+ return data;
+}
+
+static inline uint16_t giu_clear(uint16_t offset, uint16_t clear)
+{
+ uint16_t data;
+
+ data = giu_read(offset);
+ data &= ~clear;
+ giu_write(offset, data);
+
+ return data;
+}
+
+static unsigned int startup_giuint_low_irq(unsigned int irq)
+{
+ unsigned int pin;
+
+ pin = GPIO_PIN_OF_IRQ(irq);
+ giu_write(GIUINTSTATL, 1 << pin);
+ giu_set(GIUINTENL, 1 << pin);
+
+ return 0;
+}
+
+static void shutdown_giuint_low_irq(unsigned int irq)
+{
+ giu_clear(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq));
+}
+
+static void enable_giuint_low_irq(unsigned int irq)
+{
+ giu_set(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq));
+}
+
+#define disable_giuint_low_irq shutdown_giuint_low_irq
+
+static void ack_giuint_low_irq(unsigned int irq)
+{
+ unsigned int pin;
+
+ pin = GPIO_PIN_OF_IRQ(irq);
+ giu_clear(GIUINTENL, 1 << pin);
+ giu_write(GIUINTSTATL, 1 << pin);
+}
+
+static void end_giuint_low_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+ giu_set(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq));
+}
+
+static struct hw_interrupt_type giuint_low_irq_type = {
+ .typename = "GIUINTL",
+ .startup = startup_giuint_low_irq,
+ .shutdown = shutdown_giuint_low_irq,
+ .enable = enable_giuint_low_irq,
+ .disable = disable_giuint_low_irq,
+ .ack = ack_giuint_low_irq,
+ .end = end_giuint_low_irq,
+};
+
+static unsigned int startup_giuint_high_irq(unsigned int irq)
+{
+ unsigned int pin;
+
+ pin = GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET;
+ giu_write(GIUINTSTATH, 1 << pin);
+ giu_set(GIUINTENH, 1 << pin);
+
+ return 0;
+}
+
+static void shutdown_giuint_high_irq(unsigned int irq)
+{
+ giu_clear(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET));
+}
+
+static void enable_giuint_high_irq(unsigned int irq)
+{
+ giu_set(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET));
+}
+
+#define disable_giuint_high_irq shutdown_giuint_high_irq
+
+static void ack_giuint_high_irq(unsigned int irq)
+{
+ unsigned int pin;
+
+ pin = GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET;
+ giu_clear(GIUINTENH, 1 << pin);
+ giu_write(GIUINTSTATH, 1 << pin);
+}
+
+static void end_giuint_high_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+ giu_set(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET));
+}
+
+static struct hw_interrupt_type giuint_high_irq_type = {
+ .typename = "GIUINTH",
+ .startup = startup_giuint_high_irq,
+ .shutdown = shutdown_giuint_high_irq,
+ .enable = enable_giuint_high_irq,
+ .disable = disable_giuint_high_irq,
+ .ack = ack_giuint_high_irq,
+ .end = end_giuint_high_irq,
+};
+
+static int giu_get_irq(unsigned int irq, struct pt_regs *regs)
+{
+ uint16_t pendl, pendh, maskl, maskh;
+ int i;
+
+ pendl = giu_read(GIUINTSTATL);
+ pendh = giu_read(GIUINTSTATH);
+ maskl = giu_read(GIUINTENL);
+ maskh = giu_read(GIUINTENH);
+
+ maskl &= pendl;
+ maskh &= pendh;
+
+ if (maskl) {
+ for (i = 0; i < 16; i++) {
+ if (maskl & (1 << i))
+ return GIU_IRQ(i);
+ }
+ } else if (maskh) {
+ for (i = 0; i < 16; i++) {
+ if (maskh & (1 << i))
+ return GIU_IRQ(i + GIUINT_HIGH_OFFSET);
+ }
+ }
+
+ printk(KERN_ERR "spurious GIU interrupt: %04x(%04x),%04x(%04x)\n",
+ maskl, pendl, maskh, pendh);
+
+ atomic_inc(&irq_err_count);
+
+ return -EINVAL;
+}
+
+void vr41xx_set_irq_trigger(unsigned int pin, irq_trigger_t trigger, irq_signal_t signal)
+{
+ uint16_t mask;
+
+ if (pin < GIUINT_HIGH_OFFSET) {
+ mask = 1 << pin;
+ if (trigger != IRQ_TRIGGER_LEVEL) {
+ giu_set(GIUINTTYPL, mask);
+ if (signal == IRQ_SIGNAL_HOLD)
+ giu_set(GIUINTHTSELL, mask);
+ else
+ giu_clear(GIUINTHTSELL, mask);
+ if (current_cpu_data.cputype == CPU_VR4133) {
+ switch (trigger) {
+ case IRQ_TRIGGER_EDGE_FALLING:
+ giu_set(GIUFEDGEINHL, mask);
+ giu_clear(GIUREDGEINHL, mask);
+ break;
+ case IRQ_TRIGGER_EDGE_RISING:
+ giu_clear(GIUFEDGEINHL, mask);
+ giu_set(GIUREDGEINHL, mask);
+ break;
+ default:
+ giu_set(GIUFEDGEINHL, mask);
+ giu_set(GIUREDGEINHL, mask);
+ break;
+ }
+ }
+ } else {
+ giu_clear(GIUINTTYPL, mask);
+ giu_clear(GIUINTHTSELL, mask);
+ }
+ giu_write(GIUINTSTATL, mask);
+ } else if (pin < GIUINT_HIGH_MAX) {
+ mask = 1 << (pin - GIUINT_HIGH_OFFSET);
+ if (trigger != IRQ_TRIGGER_LEVEL) {
+ giu_set(GIUINTTYPH, mask);
+ if (signal == IRQ_SIGNAL_HOLD)
+ giu_set(GIUINTHTSELH, mask);
+ else
+ giu_clear(GIUINTHTSELH, mask);
+ if (current_cpu_data.cputype == CPU_VR4133) {
+ switch (trigger) {
+ case IRQ_TRIGGER_EDGE_FALLING:
+ giu_set(GIUFEDGEINHH, mask);
+ giu_clear(GIUREDGEINHH, mask);
+ break;
+ case IRQ_TRIGGER_EDGE_RISING:
+ giu_clear(GIUFEDGEINHH, mask);
+ giu_set(GIUREDGEINHH, mask);
+ break;
+ default:
+ giu_set(GIUFEDGEINHH, mask);
+ giu_set(GIUREDGEINHH, mask);
+ break;
+ }
+ }
+ } else {
+ giu_clear(GIUINTTYPH, mask);
+ giu_clear(GIUINTHTSELH, mask);
+ }
+ giu_write(GIUINTSTATH, mask);
+ }
+}
+
+EXPORT_SYMBOL_GPL(vr41xx_set_irq_trigger);
+
+void vr41xx_set_irq_level(unsigned int pin, irq_level_t level)
+{
+ uint16_t mask;
+
+ if (pin < GIUINT_HIGH_OFFSET) {
+ mask = 1 << pin;
+ if (level == IRQ_LEVEL_HIGH)
+ giu_set(GIUINTALSELL, mask);
+ else
+ giu_clear(GIUINTALSELL, mask);
+ giu_write(GIUINTSTATL, mask);
+ } else if (pin < GIUINT_HIGH_MAX) {
+ mask = 1 << (pin - GIUINT_HIGH_OFFSET);
+ if (level == IRQ_LEVEL_HIGH)
+ giu_set(GIUINTALSELH, mask);
+ else
+ giu_clear(GIUINTALSELH, mask);
+ giu_write(GIUINTSTATH, mask);
+ }
+}
+
+EXPORT_SYMBOL_GPL(vr41xx_set_irq_level);
+
+gpio_data_t vr41xx_gpio_get_pin(unsigned int pin)
+{
+ uint16_t reg, mask;
+
+ if (pin >= giu_nr_pins)
+ return GPIO_DATA_INVAL;
+
+ if (pin < 16) {
+ reg = giu_read(GIUPIODL);
+ mask = (uint16_t)1 << pin;
+ } else if (pin < 32) {
+ reg = giu_read(GIUPIODH);
+ mask = (uint16_t)1 << (pin - 16);
+ } else if (pin < 48) {
+ reg = giu_read(GIUPODATL);
+ mask = (uint16_t)1 << (pin - 32);
+ } else {
+ reg = giu_read(GIUPODATH);
+ mask = (uint16_t)1 << (pin - 48);
+ }
+
+ if (reg & mask)
+ return GPIO_DATA_HIGH;
+
+ return GPIO_DATA_LOW;
+}
+
+EXPORT_SYMBOL_GPL(vr41xx_gpio_get_pin);
+
+int vr41xx_gpio_set_pin(unsigned int pin, gpio_data_t data)
+{
+ uint16_t offset, mask, reg;
+ unsigned long flags;
+
+ if (pin >= giu_nr_pins)
+ return -EINVAL;
+
+ if (pin < 16) {
+ offset = GIUPIODL;
+ mask = (uint16_t)1 << pin;
+ } else if (pin < 32) {
+ offset = GIUPIODH;
+ mask = (uint16_t)1 << (pin - 16);
+ } else if (pin < 48) {
+ offset = GIUPODATL;
+ mask = (uint16_t)1 << (pin - 32);
+ } else {
+ offset = GIUPODATH;
+ mask = (uint16_t)1 << (pin - 48);
+ }
+
+ spin_lock_irqsave(&giu_lock, flags);
+
+ reg = giu_read(offset);
+ if (data == GPIO_DATA_HIGH)
+ reg |= mask;
+ else
+ reg &= ~mask;
+ giu_write(offset, reg);
+
+ spin_unlock_irqrestore(&giu_lock, flags);
+
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(vr41xx_gpio_set_pin);
+
+int vr41xx_gpio_set_direction(unsigned int pin, gpio_direction_t dir)
+{
+ uint16_t offset, mask, reg;
+ unsigned long flags;
+
+ if (pin >= giu_nr_pins)
+ return -EINVAL;
+
+ if (pin < 16) {
+ offset = GIUIOSELL;
+ mask = (uint16_t)1 << pin;
+ } else if (pin < 32) {
+ offset = GIUIOSELH;
+ mask = (uint16_t)1 << (pin - 16);
+ } else {
+ if (giu_flags & GPIO_HAS_OUTPUT_ENABLE) {
+ offset = GIUPODATEN;
+ mask = (uint16_t)1 << (pin - 32);
+ } else {
+ switch (pin) {
+ case 48:
+ offset = GIUPODATH;
+ mask = PIOEN0;
+ break;
+ case 49:
+ offset = GIUPODATH;
+ mask = PIOEN1;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+ }
+
+ spin_lock_irqsave(&giu_lock, flags);
+
+ reg = giu_read(offset);
+ if (dir == GPIO_OUTPUT)
+ reg |= mask;
+ else
+ reg &= ~mask;
+ giu_write(offset, reg);
+
+ spin_unlock_irqrestore(&giu_lock, flags);
+
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(vr41xx_gpio_set_direction);
+
+int vr41xx_gpio_pullupdown(unsigned int pin, gpio_pull_t pull)
+{
+ uint16_t reg, mask;
+ unsigned long flags;
+
+ if ((giu_flags & GPIO_HAS_PULLUPDOWN_IO) != GPIO_HAS_PULLUPDOWN_IO)
+ return -EPERM;
+
+ if (pin >= 15)
+ return -EINVAL;
+
+ mask = (uint16_t)1 << pin;
+
+ spin_lock_irqsave(&giu_lock, flags);
+
+ if (pull == GPIO_PULL_UP || pull == GPIO_PULL_DOWN) {
+ reg = giu_read(GIUTERMUPDN);
+ if (pull == GPIO_PULL_UP)
+ reg |= mask;
+ else
+ reg &= ~mask;
+ giu_write(GIUTERMUPDN, reg);
+
+ reg = giu_read(GIUUSEUPDN);
+ reg |= mask;
+ giu_write(GIUUSEUPDN, reg);
+ } else {
+ reg = giu_read(GIUUSEUPDN);
+ reg &= ~mask;
+ giu_write(GIUUSEUPDN, reg);
+ }
+
+ spin_unlock_irqrestore(&giu_lock, flags);
+
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(vr41xx_gpio_pullupdown);
+
+static ssize_t gpio_read(struct file *file, char __user *buf, size_t len,
+ loff_t *ppos)
+{
+ unsigned int pin;
+ char value = '0';
+
+ pin = iminor(file->f_dentry->d_inode);
+ if (pin >= giu_nr_pins)
+ return -EBADF;
+
+ if (vr41xx_gpio_get_pin(pin) == GPIO_DATA_HIGH)
+ value = '1';
+
+ if (len <= 0)
+ return -EFAULT;
+
+ if (put_user(value, buf))
+ return -EFAULT;
+
+ return 1;
+}
+
+static ssize_t gpio_write(struct file *file, const char __user *data,
+ size_t len, loff_t *ppos)
+{
+ unsigned int pin;
+ size_t i;
+ char c;
+ int retval = 0;
+
+ pin = iminor(file->f_dentry->d_inode);
+ if (pin >= giu_nr_pins)
+ return -EBADF;
+
+ for (i = 0; i < len; i++) {
+ if (get_user(c, data + i))
+ return -EFAULT;
+
+ switch (c) {
+ case '0':
+ retval = vr41xx_gpio_set_pin(pin, GPIO_DATA_LOW);
+ break;
+ case '1':
+ retval = vr41xx_gpio_set_pin(pin, GPIO_DATA_HIGH);
+ break;
+ case 'D':
+ printk(KERN_INFO "GPIO%d: pull down\n", pin);
+ retval = vr41xx_gpio_pullupdown(pin, GPIO_PULL_DOWN);
+ break;
+ case 'd':
+ printk(KERN_INFO "GPIO%d: pull up/down disable\n", pin);
+ retval = vr41xx_gpio_pullupdown(pin, GPIO_PULL_DISABLE);
+ break;
+ case 'I':
+ printk(KERN_INFO "GPIO%d: input\n", pin);
+ retval = vr41xx_gpio_set_direction(pin, GPIO_INPUT);
+ break;
+ case 'O':
+ printk(KERN_INFO "GPIO%d: output\n", pin);
+ retval = vr41xx_gpio_set_direction(pin, GPIO_OUTPUT);
+ break;
+ case 'o':
+ printk(KERN_INFO "GPIO%d: output disable\n", pin);
+ retval = vr41xx_gpio_set_direction(pin, GPIO_OUTPUT_DISABLE);
+ break;
+ case 'P':
+ printk(KERN_INFO "GPIO%d: pull up\n", pin);
+ retval = vr41xx_gpio_pullupdown(pin, GPIO_PULL_UP);
+ break;
+ case 'p':
+ printk(KERN_INFO "GPIO%d: pull up/down disable\n", pin);
+ retval = vr41xx_gpio_pullupdown(pin, GPIO_PULL_DISABLE);
+ break;
+ default:
+ break;
+ }
+
+ if (retval < 0)
+ break;
+ }
+
+ return i;
+}
+
+static int gpio_open(struct inode *inode, struct file *file)
+{
+ unsigned int pin;
+
+ pin = iminor(inode);
+ if (pin >= giu_nr_pins)
+ return -EBADF;
+
+ return nonseekable_open(inode, file);
+}
+
+static int gpio_release(struct inode *inode, struct file *file)
+{
+ unsigned int pin;
+
+ pin = iminor(inode);
+ if (pin >= giu_nr_pins)
+ return -EBADF;
+
+ return 0;
+}
+
+static struct file_operations gpio_fops = {
+ .owner = THIS_MODULE,
+ .read = gpio_read,
+ .write = gpio_write,
+ .open = gpio_open,
+ .release = gpio_release,
+};
+
+static int giu_probe(struct device *dev)
+{
+ unsigned long start, size, flags = 0;
+ unsigned int nr_pins = 0;
+ struct resource *res1, *res2 = NULL;
+ void *base;
+ int retval, i;
+
+ switch (current_cpu_data.cputype) {
+ case CPU_VR4111:
+ case CPU_VR4121:
+ start = GIU_TYPE1_START;
+ size = GIU_TYPE1_SIZE;
+ flags = GPIO_HAS_PULLUPDOWN_IO;
+ nr_pins = 50;
+ break;
+ case CPU_VR4122:
+ case CPU_VR4131:
+ start = GIU_TYPE2_START;
+ size = GIU_TYPE2_SIZE;
+ nr_pins = 36;
+ break;
+ case CPU_VR4133:
+ start = GIU_TYPE3_START;
+ size = GIU_TYPE3_SIZE;
+ flags = GPIO_HAS_INTERRUPT_EDGE_SELECT;
+ nr_pins = 48;
+ break;
+ default:
+ return -ENODEV;
+ }
+
+ res1 = request_mem_region(start, size, "GIU");
+ if (res1 == NULL)
+ return -EBUSY;
+
+ base = ioremap(start, size);
+ if (base == NULL) {
+ release_resource(res1);
+ return -ENOMEM;
+ }
+
+ if (flags & GPIO_HAS_PULLUPDOWN_IO) {
+ res2 = request_mem_region(GIU_PULLUPDOWN_START, GIU_PULLUPDOWN_SIZE, "GIU");
+ if (res2 == NULL) {
+ iounmap(base);
+ release_resource(res1);
+ return -EBUSY;
+ }
+ }
+
+ retval = register_chrdev(major, "GIU", &gpio_fops);
+ if (retval < 0) {
+ iounmap(base);
+ release_resource(res1);
+ release_resource(res2);
+ return retval;
+ }
+
+ if (major == 0) {
+ major = retval;
+ printk(KERN_INFO "GIU: major number %d\n", major);
+ }
+
+ spin_lock_init(&giu_lock);
+ giu_base = base;
+ giu_resource1 = res1;
+ giu_resource2 = res2;
+ giu_flags = flags;
+ giu_nr_pins = nr_pins;
+
+ giu_write(GIUINTENL, 0);
+ giu_write(GIUINTENH, 0);
+
+ for (i = GIU_IRQ_BASE; i <= GIU_IRQ_LAST; i++) {
+ if (i < GIU_IRQ(GIUINT_HIGH_OFFSET))
+ irq_desc[i].handler = &giuint_low_irq_type;
+ else
+ irq_desc[i].handler = &giuint_high_irq_type;
+ }
+
+ return cascade_irq(GIUINT_IRQ, giu_get_irq);
+}
+
+static int giu_remove(struct device *dev)
+{
+ iounmap(giu_base);
+
+ release_resource(giu_resource1);
+ if (giu_flags & GPIO_HAS_PULLUPDOWN_IO)
+ release_resource(giu_resource2);
+
+ return 0;
+}
+
+static struct platform_device *giu_platform_device;
+
+static struct device_driver giu_device_driver = {
+ .name = "GIU",
+ .bus = &platform_bus_type,
+ .probe = giu_probe,
+ .remove = giu_remove,
+};
+
+static int __devinit vr41xx_giu_init(void)
+{
+ int retval;
+
+ giu_platform_device = platform_device_register_simple("GIU", -1, NULL, 0);
+ if (IS_ERR(giu_platform_device))
+ return PTR_ERR(giu_platform_device);
+
+ retval = driver_register(&giu_device_driver);
+ if (retval < 0)
+ platform_device_unregister(giu_platform_device);
+
+ return retval;
+}
+
+static void __devexit vr41xx_giu_exit(void)
+{
+ driver_unregister(&giu_device_driver);
+
+ platform_device_unregister(giu_platform_device);
+}
+
+module_init(vr41xx_giu_init);
+module_exit(vr41xx_giu_exit);
/*
* Generate a start condition on the i2c bus.
*
- * returns after the start condition has occured
+ * returns after the start condition has occurred
*/
static void pca_start(struct i2c_algo_pca_data *adap)
{
}
/*
- * Generate a repeated start condition on the i2c bus
+ * Generate a repeated start condition on the i2c bus
*
- * return after the repeated start condition has occured
+ * return after the repeated start condition has occurred
*/
static void pca_repeated_start(struct i2c_algo_pca_data *adap)
{
* returns after the stop condition has been generated
*
* STOPs do not generate an interrupt or set the SI flag, since the
- * part returns the the idle state (0xf8). Hence we don't need to
+ * part returns the idle state (0xf8). Hence we don't need to
* pca_wait here.
*/
static void pca_stop(struct i2c_algo_pca_data *adap)
/* Ported for SiByte SOCs by Broadcom Corporation. */
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
config I2C_ALI1535
tristate "ALI 1535"
- depends on I2C && PCI && EXPERIMENTAL
+ depends on I2C && PCI
help
If you say yes to this option, support will be included for the SMB
Host controller on Acer Labs Inc. (ALI) M1535 South Bridges. The SMB
config I2C_ALI15X3
tristate "ALI 15x3"
- depends on I2C && PCI && EXPERIMENTAL
+ depends on I2C && PCI
help
If you say yes to this option, support will be included for the
Acer Labs Inc. (ALI) M1514 and M1543 motherboard I2C interfaces.
config I2C_AMD756
tristate "AMD 756/766/768/8111 and nVidia nForce"
- depends on I2C && PCI && EXPERIMENTAL
+ depends on I2C && PCI
help
If you say yes to this option, support will be included for the AMD
756/766/768 mainboard I2C interfaces. The driver also includes
config I2C_AMD8111
tristate "AMD 8111"
- depends on I2C && PCI && EXPERIMENTAL
+ depends on I2C && PCI
help
If you say yes to this option, support will be included for the
second (SMBus 2.0) AMD 8111 mainboard I2C interface.
config I2C_I801
tristate "Intel 82801 (ICH)"
- depends on I2C && PCI && EXPERIMENTAL
+ depends on I2C && PCI
help
If you say yes to this option, support will be included for the Intel
801 family of mainboard I2C interfaces. Specifically, the following
config I2C_I810
tristate "Intel 810/815"
- depends on I2C && PCI && EXPERIMENTAL
+ depends on I2C && PCI
select I2C_ALGOBIT
help
If you say yes to this option, support will be included for the Intel
config I2C_ISA
tristate "ISA Bus support"
- depends on I2C && EXPERIMENTAL
+ depends on I2C
help
If you say yes to this option, support will be included for i2c
interfaces that are on the ISA bus.
will be called i2c-mpc.
config I2C_NFORCE2
- tristate "Nvidia Nforce2"
- depends on I2C && PCI && EXPERIMENTAL
+ tristate "Nvidia nForce2, nForce3 and nForce4"
+ depends on I2C && PCI
help
If you say yes to this option, support will be included for the Nvidia
- Nforce2 family of mainboard I2C interfaces.
- This driver also supports the nForce3 Pro 150 MCP.
+ nForce2, nForce3 and nForce4 families of mainboard I2C interfaces.
This driver can also be built as a module. If so, the module
will be called i2c-nforce2.
config I2C_PROSAVAGE
tristate "S3/VIA (Pro)Savage"
- depends on I2C && PCI && EXPERIMENTAL
+ depends on I2C && PCI
select I2C_ALGOBIT
help
If you say yes to this option, support will be included for the
config I2C_SIS5595
tristate "SiS 5595"
- depends on I2C && PCI && EXPERIMENTAL
+ depends on I2C && PCI
help
If you say yes to this option, support will be included for the
SiS5595 SMBus (a subset of I2C) interface.
config I2C_SIS630
tristate "SiS 630/730"
- depends on I2C && PCI && EXPERIMENTAL
+ depends on I2C && PCI
help
If you say yes to this option, support will be included for the
SiS630 and SiS730 SMBus (a subset of I2C) interface.
config I2C_SIS96X
tristate "SiS 96x"
- depends on I2C && PCI && EXPERIMENTAL
+ depends on I2C && PCI
help
If you say yes to this option, support will be included for the SiS
96x SMBus (a subset of I2C) interfaces. Specifically, the following
648/961
650/961
735
+ 745
This driver can also be built as a module. If so, the module
will be called i2c-sis96x.
config I2C_VIAPRO
tristate "VIA 82C596/82C686/823x"
- depends on I2C && PCI && EXPERIMENTAL
+ depends on I2C && PCI
help
If you say yes to this option, support will be included for the VIA
82C596/82C686/823x I2C interfaces. Specifically, the following
config I2C_VOODOO3
tristate "Voodoo 3"
- depends on I2C && PCI && EXPERIMENTAL
+ depends on I2C && PCI
select I2C_ALGOBIT
help
If you say yes to this option, support will be included for the
/* Note: we assume there can only be one ALI1535, with one SMBus interface */
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/kernel.h>
/* Note: we assume there can only be one ALI15X3, with one SMBus interface */
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/kernel.h>
Note: we assume there can only be one device, with one SMBus interface.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/kernel.h>
* the Free Software Foundation version 2.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/kernel.h>
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#include <linux/config.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/module.h>
/* Partialy rewriten by Oleg I. Vdovikin for mmapped support of
for Alpha Processor Inc. UP-2000(+) boards */
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <linux/module.h>
* version 2 as published by the Free Software Foundation.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
/* Note: we assume there can only be one I801, with one SMBus interface */
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/kernel.h>
i815 1132
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
dev->irq = iic_force_poll ? -1 : ocp->def->irq;
if (dev->irq >= 0){
- /* Disable interrupts until we finish intialization,
+ /* Disable interrupts until we finish initialization,
assumes level-sensitive IRQ setup...
*/
iic_interrupt_mode(dev, 0);
#ifndef __I2C_IBM_IIC_H_
#define __I2C_IBM_IIC_H_
-#include <linux/config.h>
#include <linux/i2c.h>
struct iic_regs {
u32 cr = IOP3XX_ICR_GCD | IOP3XX_ICR_SCLEN | IOP3XX_ICR_UE;
/*
- * Everytime unit enable is asserted, GPOD needs to be cleared
+ * Every time unit enable is asserted, GPOD needs to be cleared
* on IOP321 to avoid data corruption on the bus.
*/
#ifdef CONFIG_ARCH_IOP321
the SMBus and the ISA bus very much easier. See lm78.c for an example
of this. */
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
Frodo Looijaard <frodol@dds.nl> */
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <linux/module.h>
* 'enabled' to drive the GPIOs.
*/
-#include <linux/config.h>
-#ifdef CONFIG_I2C_DEBUG_BUS
-#define DEBUG 1
-#endif
-
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/device.h>
* that is passed as the platform_data to this driver.
*/
-#include <linux/config.h>
-#ifdef CONFIG_I2C_DEBUG_BUS
-#define DEBUG 1
-#endif
-
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/device.h>
sound driver to be happy
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
if (i2c->irq != OCP_IRQ_NA)
{
if ((result = request_irq(ocp->def->irq, mpc_i2c_isr,
- 0, "i2c-mpc", i2c)) < 0) {
+ SA_SHIRQ, "i2c-mpc", i2c)) < 0) {
printk(KERN_ERR
"i2c-mpc - failed to attach interrupt\n");
goto fail_irq;
} else
i2c->irq = 0;
+ mpc_i2c_setclock(i2c);
+ ocp_set_drvdata(ocp, i2c);
+
i2c->adap = mpc_ops;
i2c_set_adapdata(&i2c->adap, i2c);
goto fail_add;
}
- mpc_i2c_setclock(i2c);
- ocp_set_drvdata(ocp, i2c);
return result;
fail_add:
static void __devexit mpc_i2c_remove(struct ocp_device *ocp)
{
struct mpc_i2c *i2c = ocp_get_drvdata(ocp);
- ocp_set_drvdata(ocp, NULL);
i2c_del_adapter(&i2c->adap);
+ ocp_set_drvdata(ocp, NULL);
if (ocp->def->irq != OCP_IRQ_NA)
free_irq(i2c->irq, i2c);
if (i2c->irq != 0)
if ((result = request_irq(i2c->irq, mpc_i2c_isr,
- 0, "fsl-i2c", i2c)) < 0) {
+ SA_SHIRQ, "i2c-mpc", i2c)) < 0) {
printk(KERN_ERR
"i2c-mpc - failed to attach interrupt\n");
goto fail_irq;
}
+ mpc_i2c_setclock(i2c);
+ dev_set_drvdata(device, i2c);
+
i2c->adap = mpc_ops;
i2c_set_adapdata(&i2c->adap, i2c);
i2c->adap.dev.parent = &pdev->dev;
goto fail_add;
}
- mpc_i2c_setclock(i2c);
- dev_set_drvdata(device, i2c);
return result;
fail_add:
{
struct mpc_i2c *i2c = dev_get_drvdata(device);
- dev_set_drvdata(device, NULL);
i2c_del_adapter(&i2c->adap);
+ dev_set_drvdata(device, NULL);
if (i2c->irq != 0)
free_irq(i2c->irq, i2c);
/* Note: we assume there can only be one nForce2, with two SMBus interfaces */
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/kernel.h>
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* ------------------------------------------------------------------------ */
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* ------------------------------------------------------------------------ */
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
/* Encapsulate the functions above in the correct structure.
Note that this is only a template, from which the real structures are
copied. The attaching code will set getscl to NULL for adapters that
- cannot read SCL back, and will also make the the data field point to
+ cannot read SCL back, and will also make the data field point to
the parallel port structure. */
static struct i2c_algo_bit_data parport_algo_data = {
.setsda = parport_setsda,
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <linux/module.h>
Note: we assume there can only be one device, with one SMBus interface.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/pci.h>
* (Additional documentation needed :(
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/pci.h>
* changed to eliminate RPXLite references.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
/* s3c24xx_i2c_xfer
*
* first port of call from the i2c bus code when an message needs
- * transfering across the i2c bus.
+ * transferring across the i2c bus.
*/
static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
it easier to add later.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/i2c-algo-sibyte.h>
#include <asm/sibyte/sb1250_regs.h>
* Add adapter resets
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
Note: we assume there can only be one device, with one SMBus interface.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
We assume there can only be one SiS96x with one SMBus interface.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/kernel.h>
#define DEBUG 1
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
Note: we assume there can only be one device, with one SMBus interface.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/pci.h>
/* This interfaces to the I2C bus of the Voodoo3 to gain access to
the BT869 and possibly other I2C devices. */
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#
-# I2C Sensor device configuration
+# I2C Sensor and "other" chip configuration
#
menu "Hardware Sensors Chip support"
config SENSORS_ADM1021
tristate "Analog Devices ADM1021 and compatibles"
- depends on I2C && EXPERIMENTAL
+ depends on I2C
select I2C_SENSOR
help
If you say yes here you get support for Analog Devices ADM1021
help
If you say yes here you get support for Analog Devices ADM1025
and Philips NE1619 sensor chips.
+
This driver can also be built as a module. If so, the module
will be called adm1025.
select I2C_SENSOR
help
If you say yes here you get support for Analog Devices ADM1026
+ sensor chip.
+
This driver can also be built as a module. If so, the module
will be called adm1026.
help
If you say yes here you get support for Analog Devices ADM1031
and ADM1030 sensor chips.
+
This driver can also be built as a module. If so, the module
will be called adm1031.
+config SENSORS_ADM9240
+ tristate "Analog Devices ADM9240 and compatibles"
+ depends on I2C && EXPERIMENTAL
+ select I2C_SENSOR
+ help
+ If you say yes here you get support for Analog Devices ADM9240,
+ Dallas DS1780, National Semiconductor LM81 sensor chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called adm9240.
+
config SENSORS_ASB100
tristate "Asus ASB100 Bach"
depends on I2C && EXPERIMENTAL
This driver can also be built as a module. If so, the module
will be called asb100.
+config SENSORS_ATXP1
+ tristate "Attansic ATXP1 VID controller"
+ depends on I2C && EXPERIMENTAL
+ help
+ If you say yes here you get support for the Attansic ATXP1 VID
+ controller.
+
+ If your board have such a chip, you are able to control your CPU
+ core and other voltages.
+
+ This driver can also be built as a module. If so, the module
+ will be called atxp1.
+
config SENSORS_DS1621
tristate "Dallas Semiconductor DS1621 and DS1625"
depends on I2C && EXPERIMENTAL
config SENSORS_GL518SM
tristate "Genesys Logic GL518SM"
- depends on I2C && EXPERIMENTAL
+ depends on I2C
select I2C_SENSOR
help
If you say yes here you get support for Genesys Logic GL518SM
config SENSORS_IT87
tristate "ITE IT87xx and compatibles"
- depends on I2C && EXPERIMENTAL
+ depends on I2C
select I2C_SENSOR
help
If you say yes here you get support for ITE IT87xx sensor chips
config SENSORS_LM75
tristate "National Semiconductor LM75 and compatibles"
- depends on I2C && EXPERIMENTAL
+ depends on I2C
select I2C_SENSOR
help
If you say yes here you get support for National Semiconductor LM75
select I2C_SENSOR
help
If you say yes here you get support for National Semiconductor LM78,
- LM78-J and LM79. This can also be built as a module which can be
- inserted and removed while the kernel is running.
+ LM78-J and LM79.
This driver can also be built as a module. If so, the module
will be called lm78.
select I2C_SENSOR
help
If you say yes here you get support for National Semiconductor LM85
- sensor chips and clones: ADT7463 and ADM1027.
+ sensor chips and clones: ADT7463, EMC6D100, EMC6D102 and ADM1027.
This driver can also be built as a module. If so, the module
will be called lm85.
help
If you say yes here you get support for the integrated fan
monitoring and control capabilities of the SMSC LPC47B27x,
- LPC47M10x, LPC47M13x and LPC47M14x chips.
+ LPC47M10x, LPC47M13x, LPC47M14x, LPC47M15x and LPC47M192 chips.
This driver can also be built as a module. If so, the module
will be called smsc47m1.
config SENSORS_VIA686A
tristate "VIA686A"
- depends on I2C && PCI && EXPERIMENTAL
+ depends on I2C && PCI
select I2C_SENSOR
select I2C_ISA
help
config SENSORS_W83781D
tristate "Winbond W83781D, W83782D, W83783S, W83627HF, Asus AS99127F"
- depends on I2C && EXPERIMENTAL
+ depends on I2C
select I2C_SENSOR
help
If you say yes here you get support for the Winbond W8378x series
This driver can also be built as a module. If so, the module
will be called w83627hf.
+config SENSORS_W83627EHF
+ tristate "Winbond W83627EHF"
+ depends on I2C && EXPERIMENTAL
+ select I2C_SENSOR
+ select I2C_ISA
+ help
+ If you say yes here you get preliminary support for the hardware
+ monitoring functionality of the Winbond W83627EHF Super-I/O chip.
+ Only fan and temperature inputs are supported at the moment, while
+ the chip does much more than that.
+
+ This driver can also be built as a module. If so, the module
+ will be called w83627ehf.
+
endmenu
menu "Other I2C Chip support"
depends on I2C
config SENSORS_DS1337
- tristate "Dallas Semiconductor DS1337 Real Time Clock"
+ tristate "Dallas Semiconductor DS1337 and DS1339 Real Time Clock"
depends on I2C && EXPERIMENTAL
select I2C_SENSOR
help
If you say yes here you get support for Dallas Semiconductor
- DS1337 real-time clock chips.
+ DS1337 and DS1339 real-time clock chips.
This driver can also be built as a module. If so, the module
will be called ds1337.
+config SENSORS_DS1374
+ tristate "Maxim/Dallas Semiconductor DS1374 Real Time Clock"
+ depends on I2C && EXPERIMENTAL
+ select I2C_SENSOR
+ help
+ If you say yes here you get support for Dallas Semiconductor
+ DS1374 real-time clock chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called ds1374.
+
config SENSORS_EEPROM
tristate "EEPROM reader"
depends on I2C && EXPERIMENTAL
This driver can also be built as a module. If so, the module
will be called pcf8574.
+config SENSORS_PCA9539
+ tristate "Philips PCA9539 16-bit I/O port"
+ depends on I2C && EXPERIMENTAL
+ help
+ If you say yes here you get support for the Philips PCA9539
+ 16-bit I/O port.
+
+ This driver can also be built as a module. If so, the module
+ will be called pca9539.
+
config SENSORS_PCF8591
tristate "Philips PCF8591"
depends on I2C && EXPERIMENTAL
This driver can also be built as a module. If so, the module
will be called isp1301_omap.
+# NOTE: This isn't really OMAP-specific, except for the current
+# interface location in <include/asm-arm/arch-omap/tps65010.h>
+# and having mostly OMAP-specific board support
+config TPS65010
+ tristate "TPS6501x Power Management chips"
+ depends on I2C && ARCH_OMAP
+ default y if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_OSK
+ help
+ If you say yes here you get support for the TPS6501x series of
+ Power Management chips. These include voltage regulators,
+ lithium ion/polymer battery charging, and other features that
+ are often used in portable devices like cell phones and cameras.
+
+ This driver can also be built as a module. If so, the module
+ will be called tps65010.
+
+
config SENSORS_M41T00
tristate "ST M41T00 RTC chip"
depends on I2C && PPC32
This driver can also be built as a module. If so, the module
will be called m41t00.
+config SENSORS_MAX6875
+ tristate "MAXIM MAX6875 Power supply supervisor"
+ depends on I2C && EXPERIMENTAL
+ help
+ If you say yes here you get support for the MAX6875
+ EEPROM-Programmable, Hex/Quad, Power-Suppy Sequencers/Supervisors.
+
+ This provides a interface to program the EEPROM and reset the chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called max6875.
+
endmenu
#
-# Makefile for the kernel hardware sensors chip drivers.
+# Makefile for sensor and "other" I2C chip drivers.
#
# asb100, then w83781d go first, as they can override other drivers' addresses.
obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o
obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o
obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o
+obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o
+obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o
obj-$(CONFIG_SENSORS_DS1337) += ds1337.o
+obj-$(CONFIG_SENSORS_DS1374) += ds1374.o
obj-$(CONFIG_SENSORS_DS1621) += ds1621.o
obj-$(CONFIG_SENSORS_EEPROM) += eeprom.o
obj-$(CONFIG_SENSORS_FSCHER) += fscher.o
obj-$(CONFIG_SENSORS_LM90) += lm90.o
obj-$(CONFIG_SENSORS_LM92) += lm92.o
obj-$(CONFIG_SENSORS_MAX1619) += max1619.o
+obj-$(CONFIG_SENSORS_MAX6875) += max6875.o
obj-$(CONFIG_SENSORS_M41T00) += m41t00.o
obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
+obj-$(CONFIG_SENSORS_PCA9539) += pca9539.o
obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o
obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
obj-$(CONFIG_SENSORS_RTC8564) += rtc8564.o
obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o
obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o
obj-$(CONFIG_SENSORS_VIA686A) += via686a.o
+obj-$(CONFIG_SENSORS_W83627EHF) += w83627ehf.o
obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o
+
obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o
+obj-$(CONFIG_TPS65010) += tps65010.o
ifeq ($(CONFIG_I2C_DEBUG_CHIP),y)
EXTRA_CFLAGS += -DDEBUG
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
u8 remote_temp_hyst;
u8 remote_temp_input;
u8 alarms;
- /* special values for ADM1021 only */
- u8 die_code;
/* Special values for ADM1023 only */
u8 remote_temp_prec;
u8 remote_temp_os_prec;
return sprintf(buf, "%d\n", data->value); \
}
show2(alarms);
-show2(die_code);
#define set(value, reg) \
static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_remote_temp_hyst, set_remote_temp_hyst);
static DEVICE_ATTR(temp2_input, S_IRUGO, show_remote_temp_input, NULL);
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
-static DEVICE_ATTR(die_code, S_IRUGO, show_die_code, NULL);
static int adm1021_attach_adapter(struct i2c_adapter *adapter)
device_create_file(&new_client->dev, &dev_attr_temp2_min);
device_create_file(&new_client->dev, &dev_attr_temp2_input);
device_create_file(&new_client->dev, &dev_attr_alarms);
- if (data->type == adm1021)
- device_create_file(&new_client->dev, &dev_attr_die_code);
return 0;
data->remote_temp_max = adm1021_read_value(client, ADM1021_REG_REMOTE_TOS_R);
data->remote_temp_hyst = adm1021_read_value(client, ADM1021_REG_REMOTE_THYST_R);
data->alarms = adm1021_read_value(client, ADM1021_REG_STATUS) & 0x7c;
- if (data->type == adm1021)
- data->die_code = adm1021_read_value(client, ADM1021_REG_DIE_CODE);
if (data->type == adm1023) {
data->remote_temp_prec = adm1021_read_value(client, ADM1021_REG_REM_TEMP_PREC);
data->remote_temp_os_prec = adm1021_read_value(client, ADM1021_REG_REM_TOS_PREC);
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
struct adm1025_data *data = adm1025_update_device(dev);
return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm));
}
+/* in1_ref is deprecated in favour of cpu0_vid, remove after 2005-11-11 */
static DEVICE_ATTR(in1_ref, S_IRUGO, show_vid, NULL);
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf)
{
device_create_file(&new_client->dev, &dev_attr_temp1_max);
device_create_file(&new_client->dev, &dev_attr_temp2_max);
device_create_file(&new_client->dev, &dev_attr_alarms);
+ /* in1_ref is deprecated, remove after 2005-11-11 */
device_create_file(&new_client->dev, &dev_attr_in1_ref);
+ device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
device_create_file(&new_client->dev, &dev_attr_vrm);
/* Pin 11 is either in4 (+12V) or VID4 */
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/i2c-sensor.h>
-#include <linux/i2c-sysfs.h>
#include <linux/i2c-vid.h>
+#include <linux/hwmon-sysfs.h>
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
struct adm1026_data *data = adm1026_update_device(dev);
return sprintf(buf,"%d\n", vid_from_reg(data->vid & 0x3f, data->vrm));
}
-
+/* vid deprecated in favour of cpu0_vid, remove after 2005-11-11 */
static DEVICE_ATTR(vid, S_IRUGO, show_vid_reg, NULL);
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
{
device_create_file(&new_client->dev, &dev_attr_temp1_crit_enable);
device_create_file(&new_client->dev, &dev_attr_temp2_crit_enable);
device_create_file(&new_client->dev, &dev_attr_temp3_crit_enable);
+ /* vid deprecated in favour of cpu0_vid, remove after 2005-11-11 */
device_create_file(&new_client->dev, &dev_attr_vid);
+ device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
device_create_file(&new_client->dev, &dev_attr_vrm);
device_create_file(&new_client->dev, &dev_attr_alarms);
device_create_file(&new_client->dev, &dev_attr_alarm_mask);
/*
* That function checks the cases where the fan reading is not
- * relevent. It is used to provide 0 as fan reading when the fan is
+ * relevant. It is used to provide 0 as fan reading when the fan is
* not supposed to run
*/
static int trust_fan_readings(struct adm1031_data *data, int chan)
--- /dev/null
+/*
+ * adm9240.c Part of lm_sensors, Linux kernel modules for hardware
+ * monitoring
+ *
+ * Copyright (C) 1999 Frodo Looijaard <frodol@dds.nl>
+ * Philip Edelbrock <phil@netroedge.com>
+ * Copyright (C) 2003 Michiel Rook <michiel@grendelproject.nl>
+ * Copyright (C) 2005 Grant Coady <gcoady@gmail.com> with valuable
+ * guidance from Jean Delvare
+ *
+ * Driver supports Analog Devices ADM9240
+ * Dallas Semiconductor DS1780
+ * National Semiconductor LM81
+ *
+ * ADM9240 is the reference, DS1780 and LM81 are register compatibles
+ *
+ * Voltage Six inputs are scaled by chip, VID also reported
+ * Temperature Chip temperature to 0.5'C, maximum and max_hysteris
+ * Fans 2 fans, low speed alarm, automatic fan clock divider
+ * Alarms 16-bit map of active alarms
+ * Analog Out 0..1250 mV output
+ *
+ * Chassis Intrusion: clear CI latch with 'echo 1 > chassis_clear'
+ *
+ * Test hardware: Intel SE440BX-2 desktop motherboard --Grant
+ *
+ * LM81 extended temp reading not implemented
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/i2c-sensor.h>
+#include <linux/i2c-vid.h>
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f,
+ I2C_CLIENT_END };
+
+static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
+
+/* Insmod parameters */
+SENSORS_INSMOD_3(adm9240, ds1780, lm81);
+
+/* ADM9240 registers */
+#define ADM9240_REG_MAN_ID 0x3e
+#define ADM9240_REG_DIE_REV 0x3f
+#define ADM9240_REG_CONFIG 0x40
+
+#define ADM9240_REG_IN(nr) (0x20 + (nr)) /* 0..5 */
+#define ADM9240_REG_IN_MAX(nr) (0x2b + (nr) * 2)
+#define ADM9240_REG_IN_MIN(nr) (0x2c + (nr) * 2)
+#define ADM9240_REG_FAN(nr) (0x28 + (nr)) /* 0..1 */
+#define ADM9240_REG_FAN_MIN(nr) (0x3b + (nr))
+#define ADM9240_REG_INT(nr) (0x41 + (nr))
+#define ADM9240_REG_INT_MASK(nr) (0x43 + (nr))
+#define ADM9240_REG_TEMP 0x27
+#define ADM9240_REG_TEMP_HIGH 0x39
+#define ADM9240_REG_TEMP_HYST 0x3a
+#define ADM9240_REG_ANALOG_OUT 0x19
+#define ADM9240_REG_CHASSIS_CLEAR 0x46
+#define ADM9240_REG_VID_FAN_DIV 0x47
+#define ADM9240_REG_I2C_ADDR 0x48
+#define ADM9240_REG_VID4 0x49
+#define ADM9240_REG_TEMP_CONF 0x4b
+
+/* generalised scaling with integer rounding */
+static inline int SCALE(long val, int mul, int div)
+{
+ if (val < 0)
+ return (val * mul - div / 2) / div;
+ else
+ return (val * mul + div / 2) / div;
+}
+
+/* adm9240 internally scales voltage measurements */
+static const u16 nom_mv[] = { 2500, 2700, 3300, 5000, 12000, 2700 };
+
+static inline unsigned int IN_FROM_REG(u8 reg, int n)
+{
+ return SCALE(reg, nom_mv[n], 192);
+}
+
+static inline u8 IN_TO_REG(unsigned long val, int n)
+{
+ return SENSORS_LIMIT(SCALE(val, 192, nom_mv[n]), 0, 255);
+}
+
+/* temperature range: -40..125, 127 disables temperature alarm */
+static inline s8 TEMP_TO_REG(long val)
+{
+ return SENSORS_LIMIT(SCALE(val, 1, 1000), -40, 127);
+}
+
+/* two fans, each with low fan speed limit */
+static inline unsigned int FAN_FROM_REG(u8 reg, u8 div)
+{
+ if (!reg) /* error */
+ return -1;
+
+ if (reg == 255)
+ return 0;
+
+ return SCALE(1350000, 1, reg * div);
+}
+
+/* analog out 0..1250mV */
+static inline u8 AOUT_TO_REG(unsigned long val)
+{
+ return SENSORS_LIMIT(SCALE(val, 255, 1250), 0, 255);
+}
+
+static inline unsigned int AOUT_FROM_REG(u8 reg)
+{
+ return SCALE(reg, 1250, 255);
+}
+
+static int adm9240_attach_adapter(struct i2c_adapter *adapter);
+static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind);
+static void adm9240_init_client(struct i2c_client *client);
+static int adm9240_detach_client(struct i2c_client *client);
+static struct adm9240_data *adm9240_update_device(struct device *dev);
+
+/* driver data */
+static struct i2c_driver adm9240_driver = {
+ .owner = THIS_MODULE,
+ .name = "adm9240",
+ .id = I2C_DRIVERID_ADM9240,
+ .flags = I2C_DF_NOTIFY,
+ .attach_adapter = adm9240_attach_adapter,
+ .detach_client = adm9240_detach_client,
+};
+
+/* per client data */
+struct adm9240_data {
+ enum chips type;
+ struct i2c_client client;
+ struct semaphore update_lock;
+ char valid;
+ unsigned long last_updated_measure;
+ unsigned long last_updated_config;
+
+ u8 in[6]; /* ro in0_input */
+ u8 in_max[6]; /* rw in0_max */
+ u8 in_min[6]; /* rw in0_min */
+ u8 fan[2]; /* ro fan1_input */
+ u8 fan_min[2]; /* rw fan1_min */
+ u8 fan_div[2]; /* rw fan1_div, read-only accessor */
+ s16 temp; /* ro temp1_input, 9-bit sign-extended */
+ s8 temp_high; /* rw temp1_max */
+ s8 temp_hyst; /* rw temp1_max_hyst */
+ u16 alarms; /* ro alarms */
+ u8 aout; /* rw aout_output */
+ u8 vid; /* ro vid */
+ u8 vrm; /* -- vrm set on startup, no accessor */
+};
+
+/* i2c byte read/write interface */
+static int adm9240_read_value(struct i2c_client *client, u8 reg)
+{
+ return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int adm9240_write_value(struct i2c_client *client, u8 reg, u8 value)
+{
+ return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+/*** sysfs accessors ***/
+
+/* temperature */
+#define show_temp(value, scale) \
+static ssize_t show_##value(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct adm9240_data *data = adm9240_update_device(dev); \
+ return sprintf(buf, "%d\n", data->value * scale); \
+}
+show_temp(temp_high, 1000);
+show_temp(temp_hyst, 1000);
+show_temp(temp, 500); /* 0.5'C per bit */
+
+#define set_temp(value, reg) \
+static ssize_t set_##value(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, size_t count) \
+{ \
+ struct i2c_client *client = to_i2c_client(dev); \
+ struct adm9240_data *data = adm9240_update_device(dev); \
+ long temp = simple_strtoul(buf, NULL, 10); \
+ \
+ down(&data->update_lock); \
+ data->value = TEMP_TO_REG(temp); \
+ adm9240_write_value(client, reg, data->value); \
+ up(&data->update_lock); \
+ return count; \
+}
+
+set_temp(temp_high, ADM9240_REG_TEMP_HIGH);
+set_temp(temp_hyst, ADM9240_REG_TEMP_HYST);
+
+static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
+ show_temp_high, set_temp_high);
+static DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
+ show_temp_hyst, set_temp_hyst);
+static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL);
+
+/* voltage */
+static ssize_t show_in(struct device *dev, char *buf, int nr)
+{
+ struct adm9240_data *data = adm9240_update_device(dev);
+ return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr], nr));
+}
+
+static ssize_t show_in_min(struct device *dev, char *buf, int nr)
+{
+ struct adm9240_data *data = adm9240_update_device(dev);
+ return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr], nr));
+}
+
+static ssize_t show_in_max(struct device *dev, char *buf, int nr)
+{
+ struct adm9240_data *data = adm9240_update_device(dev);
+ return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr], nr));
+}
+
+static ssize_t set_in_min(struct device *dev, const char *buf,
+ size_t count, int nr)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adm9240_data *data = i2c_get_clientdata(client);
+ unsigned long val = simple_strtoul(buf, NULL, 10);
+
+ down(&data->update_lock);
+ data->in_min[nr] = IN_TO_REG(val, nr);
+ adm9240_write_value(client, ADM9240_REG_IN_MIN(nr), data->in_min[nr]);
+ up(&data->update_lock);
+ return count;
+}
+
+static ssize_t set_in_max(struct device *dev, const char *buf,
+ size_t count, int nr)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adm9240_data *data = i2c_get_clientdata(client);
+ unsigned long val = simple_strtoul(buf, NULL, 10);
+
+ down(&data->update_lock);
+ data->in_max[nr] = IN_TO_REG(val, nr);
+ adm9240_write_value(client, ADM9240_REG_IN_MAX(nr), data->in_max[nr]);
+ up(&data->update_lock);
+ return count;
+}
+
+#define show_in_offset(offset) \
+static ssize_t show_in##offset(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+{ \
+ return show_in(dev, buf, offset); \
+} \
+static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL); \
+static ssize_t show_in##offset##_min(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+{ \
+ return show_in_min(dev, buf, offset); \
+} \
+static ssize_t show_in##offset##_max(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+{ \
+ return show_in_max(dev, buf, offset); \
+} \
+static ssize_t \
+set_in##offset##_min(struct device *dev, \
+ struct device_attribute *attr, const char *buf, \
+ size_t count) \
+{ \
+ return set_in_min(dev, buf, count, offset); \
+} \
+static ssize_t \
+set_in##offset##_max(struct device *dev, \
+ struct device_attribute *attr, const char *buf, \
+ size_t count) \
+{ \
+ return set_in_max(dev, buf, count, offset); \
+} \
+static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
+ show_in##offset##_min, set_in##offset##_min); \
+static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
+ show_in##offset##_max, set_in##offset##_max);
+
+show_in_offset(0);
+show_in_offset(1);
+show_in_offset(2);
+show_in_offset(3);
+show_in_offset(4);
+show_in_offset(5);
+
+/* fans */
+static ssize_t show_fan(struct device *dev, char *buf, int nr)
+{
+ struct adm9240_data *data = adm9240_update_device(dev);
+ return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
+ 1 << data->fan_div[nr]));
+}
+
+static ssize_t show_fan_min(struct device *dev, char *buf, int nr)
+{
+ struct adm9240_data *data = adm9240_update_device(dev);
+ return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr],
+ 1 << data->fan_div[nr]));
+}
+
+static ssize_t show_fan_div(struct device *dev, char *buf, int nr)
+{
+ struct adm9240_data *data = adm9240_update_device(dev);
+ return sprintf(buf, "%d\n", 1 << data->fan_div[nr]);
+}
+
+/* write new fan div, callers must hold data->update_lock */
+static void adm9240_write_fan_div(struct i2c_client *client, int nr,
+ u8 fan_div)
+{
+ u8 reg, old, shift = (nr + 2) * 2;
+
+ reg = adm9240_read_value(client, ADM9240_REG_VID_FAN_DIV);
+ old = (reg >> shift) & 3;
+ reg &= ~(3 << shift);
+ reg |= (fan_div << shift);
+ adm9240_write_value(client, ADM9240_REG_VID_FAN_DIV, reg);
+ dev_dbg(&client->dev, "fan%d clock divider changed from %u "
+ "to %u\n", nr + 1, 1 << old, 1 << fan_div);
+}
+
+/*
+ * set fan speed low limit:
+ *
+ * - value is zero: disable fan speed low limit alarm
+ *
+ * - value is below fan speed measurement range: enable fan speed low
+ * limit alarm to be asserted while fan speed too slow to measure
+ *
+ * - otherwise: select fan clock divider to suit fan speed low limit,
+ * measurement code may adjust registers to ensure fan speed reading
+ */
+static ssize_t set_fan_min(struct device *dev, const char *buf,
+ size_t count, int nr)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adm9240_data *data = i2c_get_clientdata(client);
+ unsigned long val = simple_strtoul(buf, NULL, 10);
+ u8 new_div;
+
+ down(&data->update_lock);
+
+ if (!val) {
+ data->fan_min[nr] = 255;
+ new_div = data->fan_div[nr];
+
+ dev_dbg(&client->dev, "fan%u low limit set disabled\n",
+ nr + 1);
+
+ } else if (val < 1350000 / (8 * 254)) {
+ new_div = 3;
+ data->fan_min[nr] = 254;
+
+ dev_dbg(&client->dev, "fan%u low limit set minimum %u\n",
+ nr + 1, FAN_FROM_REG(254, 1 << new_div));
+
+ } else {
+ unsigned int new_min = 1350000 / val;
+
+ new_div = 0;
+ while (new_min > 192 && new_div < 3) {
+ new_div++;
+ new_min /= 2;
+ }
+ if (!new_min) /* keep > 0 */
+ new_min++;
+
+ data->fan_min[nr] = new_min;
+
+ dev_dbg(&client->dev, "fan%u low limit set fan speed %u\n",
+ nr + 1, FAN_FROM_REG(new_min, 1 << new_div));
+ }
+
+ if (new_div != data->fan_div[nr]) {
+ data->fan_div[nr] = new_div;
+ adm9240_write_fan_div(client, nr, new_div);
+ }
+ adm9240_write_value(client, ADM9240_REG_FAN_MIN(nr),
+ data->fan_min[nr]);
+
+ up(&data->update_lock);
+ return count;
+}
+
+#define show_fan_offset(offset) \
+static ssize_t show_fan_##offset (struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+{ \
+return show_fan(dev, buf, offset - 1); \
+} \
+static ssize_t show_fan_##offset##_div (struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+{ \
+return show_fan_div(dev, buf, offset - 1); \
+} \
+static ssize_t show_fan_##offset##_min (struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+{ \
+return show_fan_min(dev, buf, offset - 1); \
+} \
+static ssize_t set_fan_##offset##_min (struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, size_t count) \
+{ \
+return set_fan_min(dev, buf, count, offset - 1); \
+} \
+static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
+ show_fan_##offset, NULL); \
+static DEVICE_ATTR(fan##offset##_div, S_IRUGO, \
+ show_fan_##offset##_div, NULL); \
+static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
+ show_fan_##offset##_min, set_fan_##offset##_min);
+
+show_fan_offset(1);
+show_fan_offset(2);
+
+/* alarms */
+static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct adm9240_data *data = adm9240_update_device(dev);
+ return sprintf(buf, "%u\n", data->alarms);
+}
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+
+/* vid */
+static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct adm9240_data *data = adm9240_update_device(dev);
+ return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
+}
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
+
+/* analog output */
+static ssize_t show_aout(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct adm9240_data *data = adm9240_update_device(dev);
+ return sprintf(buf, "%d\n", AOUT_FROM_REG(data->aout));
+}
+
+static ssize_t set_aout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adm9240_data *data = i2c_get_clientdata(client);
+ unsigned long val = simple_strtol(buf, NULL, 10);
+
+ down(&data->update_lock);
+ data->aout = AOUT_TO_REG(val);
+ adm9240_write_value(client, ADM9240_REG_ANALOG_OUT, data->aout);
+ up(&data->update_lock);
+ return count;
+}
+static DEVICE_ATTR(aout_output, S_IRUGO | S_IWUSR, show_aout, set_aout);
+
+/* chassis_clear */
+static ssize_t chassis_clear(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ unsigned long val = simple_strtol(buf, NULL, 10);
+
+ if (val == 1) {
+ adm9240_write_value(client, ADM9240_REG_CHASSIS_CLEAR, 0x80);
+ dev_dbg(&client->dev, "chassis intrusion latch cleared\n");
+ }
+ return count;
+}
+static DEVICE_ATTR(chassis_clear, S_IWUSR, NULL, chassis_clear);
+
+
+/*** sensor chip detect and driver install ***/
+
+static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+ struct i2c_client *new_client;
+ struct adm9240_data *data;
+ int err = 0;
+ const char *name = "";
+ u8 man_id, die_rev;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ goto exit;
+
+ if (!(data = kmalloc(sizeof(struct adm9240_data), GFP_KERNEL))) {
+ err = -ENOMEM;
+ goto exit;
+ }
+ memset(data, 0, sizeof(struct adm9240_data));
+
+ new_client = &data->client;
+ i2c_set_clientdata(new_client, data);
+ new_client->addr = address;
+ new_client->adapter = adapter;
+ new_client->driver = &adm9240_driver;
+ new_client->flags = 0;
+
+ if (kind == 0) {
+ kind = adm9240;
+ }
+
+ if (kind < 0) {
+
+ /* verify chip: reg address should match i2c address */
+ if (adm9240_read_value(new_client, ADM9240_REG_I2C_ADDR)
+ != address) {
+ dev_err(&adapter->dev, "detect fail: address match, "
+ "0x%02x\n", address);
+ goto exit_free;
+ }
+
+ /* check known chip manufacturer */
+ man_id = adm9240_read_value(new_client, ADM9240_REG_MAN_ID);
+
+ if (man_id == 0x23) {
+ kind = adm9240;
+ } else if (man_id == 0xda) {
+ kind = ds1780;
+ } else if (man_id == 0x01) {
+ kind = lm81;
+ } else {
+ dev_err(&adapter->dev, "detect fail: unknown manuf, "
+ "0x%02x\n", man_id);
+ goto exit_free;
+ }
+
+ /* successful detect, print chip info */
+ die_rev = adm9240_read_value(new_client, ADM9240_REG_DIE_REV);
+ dev_info(&adapter->dev, "found %s revision %u\n",
+ man_id == 0x23 ? "ADM9240" :
+ man_id == 0xda ? "DS1780" : "LM81", die_rev);
+ }
+
+ /* either forced or detected chip kind */
+ if (kind == adm9240) {
+ name = "adm9240";
+ } else if (kind == ds1780) {
+ name = "ds1780";
+ } else if (kind == lm81) {
+ name = "lm81";
+ }
+
+ /* fill in the remaining client fields and attach */
+ strlcpy(new_client->name, name, I2C_NAME_SIZE);
+ data->type = kind;
+ init_MUTEX(&data->update_lock);
+
+ if ((err = i2c_attach_client(new_client)))
+ goto exit_free;
+
+ adm9240_init_client(new_client);
+
+ /* populate sysfs filesystem */
+ device_create_file(&new_client->dev, &dev_attr_in0_input);
+ device_create_file(&new_client->dev, &dev_attr_in0_min);
+ device_create_file(&new_client->dev, &dev_attr_in0_max);
+ device_create_file(&new_client->dev, &dev_attr_in1_input);
+ device_create_file(&new_client->dev, &dev_attr_in1_min);
+ device_create_file(&new_client->dev, &dev_attr_in1_max);
+ device_create_file(&new_client->dev, &dev_attr_in2_input);
+ device_create_file(&new_client->dev, &dev_attr_in2_min);
+ device_create_file(&new_client->dev, &dev_attr_in2_max);
+ device_create_file(&new_client->dev, &dev_attr_in3_input);
+ device_create_file(&new_client->dev, &dev_attr_in3_min);
+ device_create_file(&new_client->dev, &dev_attr_in3_max);
+ device_create_file(&new_client->dev, &dev_attr_in4_input);
+ device_create_file(&new_client->dev, &dev_attr_in4_min);
+ device_create_file(&new_client->dev, &dev_attr_in4_max);
+ device_create_file(&new_client->dev, &dev_attr_in5_input);
+ device_create_file(&new_client->dev, &dev_attr_in5_min);
+ device_create_file(&new_client->dev, &dev_attr_in5_max);
+ device_create_file(&new_client->dev, &dev_attr_temp1_max);
+ device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
+ device_create_file(&new_client->dev, &dev_attr_temp1_input);
+ device_create_file(&new_client->dev, &dev_attr_fan1_input);
+ device_create_file(&new_client->dev, &dev_attr_fan1_div);
+ device_create_file(&new_client->dev, &dev_attr_fan1_min);
+ device_create_file(&new_client->dev, &dev_attr_fan2_input);
+ device_create_file(&new_client->dev, &dev_attr_fan2_div);
+ device_create_file(&new_client->dev, &dev_attr_fan2_min);
+ device_create_file(&new_client->dev, &dev_attr_alarms);
+ device_create_file(&new_client->dev, &dev_attr_aout_output);
+ device_create_file(&new_client->dev, &dev_attr_chassis_clear);
+ device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
+
+ return 0;
+exit_free:
+ kfree(new_client);
+exit:
+ return err;
+}
+
+static int adm9240_attach_adapter(struct i2c_adapter *adapter)
+{
+ if (!(adapter->class & I2C_CLASS_HWMON))
+ return 0;
+ return i2c_detect(adapter, &addr_data, adm9240_detect);
+}
+
+static int adm9240_detach_client(struct i2c_client *client)
+{
+ int err;
+
+ if ((err = i2c_detach_client(client))) {
+ dev_err(&client->dev, "Client deregistration failed, "
+ "client not detached.\n");
+ return err;
+ }
+
+ kfree(i2c_get_clientdata(client));
+ return 0;
+}
+
+static void adm9240_init_client(struct i2c_client *client)
+{
+ struct adm9240_data *data = i2c_get_clientdata(client);
+ u8 conf = adm9240_read_value(client, ADM9240_REG_CONFIG);
+ u8 mode = adm9240_read_value(client, ADM9240_REG_TEMP_CONF) & 3;
+
+ data->vrm = i2c_which_vrm(); /* need this to report vid as mV */
+
+ dev_info(&client->dev, "Using VRM: %d.%d\n", data->vrm / 10,
+ data->vrm % 10);
+
+ if (conf & 1) { /* measurement cycle running: report state */
+
+ dev_info(&client->dev, "status: config 0x%02x mode %u\n",
+ conf, mode);
+
+ } else { /* cold start: open limits before starting chip */
+ int i;
+
+ for (i = 0; i < 6; i++)
+ {
+ adm9240_write_value(client,
+ ADM9240_REG_IN_MIN(i), 0);
+ adm9240_write_value(client,
+ ADM9240_REG_IN_MAX(i), 255);
+ }
+ adm9240_write_value(client, ADM9240_REG_FAN_MIN(0), 255);
+ adm9240_write_value(client, ADM9240_REG_FAN_MIN(1), 255);
+ adm9240_write_value(client, ADM9240_REG_TEMP_HIGH, 127);
+ adm9240_write_value(client, ADM9240_REG_TEMP_HYST, 127);
+
+ /* start measurement cycle */
+ adm9240_write_value(client, ADM9240_REG_CONFIG, 1);
+
+ dev_info(&client->dev, "cold start: config was 0x%02x "
+ "mode %u\n", conf, mode);
+ }
+}
+
+static struct adm9240_data *adm9240_update_device(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adm9240_data *data = i2c_get_clientdata(client);
+ int i;
+
+ down(&data->update_lock);
+
+ /* minimum measurement cycle: 1.75 seconds */
+ if (time_after(jiffies, data->last_updated_measure + (HZ * 7 / 4))
+ || !data->valid) {
+
+ for (i = 0; i < 6; i++) /* read voltages */
+ {
+ data->in[i] = adm9240_read_value(client,
+ ADM9240_REG_IN(i));
+ }
+ data->alarms = adm9240_read_value(client,
+ ADM9240_REG_INT(0)) |
+ adm9240_read_value(client,
+ ADM9240_REG_INT(1)) << 8;
+
+ /* read temperature: assume temperature changes less than
+ * 0.5'C per two measurement cycles thus ignore possible
+ * but unlikely aliasing error on lsb reading. --Grant */
+ data->temp = ((adm9240_read_value(client,
+ ADM9240_REG_TEMP) << 8) |
+ adm9240_read_value(client,
+ ADM9240_REG_TEMP_CONF)) / 128;
+
+ for (i = 0; i < 2; i++) /* read fans */
+ {
+ data->fan[i] = adm9240_read_value(client,
+ ADM9240_REG_FAN(i));
+
+ /* adjust fan clock divider on overflow */
+ if (data->valid && data->fan[i] == 255 &&
+ data->fan_div[i] < 3) {
+
+ adm9240_write_fan_div(client, i,
+ ++data->fan_div[i]);
+
+ /* adjust fan_min if active, but not to 0 */
+ if (data->fan_min[i] < 255 &&
+ data->fan_min[i] >= 2)
+ data->fan_min[i] /= 2;
+ }
+ }
+ data->last_updated_measure = jiffies;
+ }
+
+ /* minimum config reading cycle: 300 seconds */
+ if (time_after(jiffies, data->last_updated_config + (HZ * 300))
+ || !data->valid) {
+
+ for (i = 0; i < 6; i++)
+ {
+ data->in_min[i] = adm9240_read_value(client,
+ ADM9240_REG_IN_MIN(i));
+ data->in_max[i] = adm9240_read_value(client,
+ ADM9240_REG_IN_MAX(i));
+ }
+ for (i = 0; i < 2; i++)
+ {
+ data->fan_min[i] = adm9240_read_value(client,
+ ADM9240_REG_FAN_MIN(i));
+ }
+ data->temp_high = adm9240_read_value(client,
+ ADM9240_REG_TEMP_HIGH);
+ data->temp_hyst = adm9240_read_value(client,
+ ADM9240_REG_TEMP_HYST);
+
+ /* read fan divs and 5-bit VID */
+ i = adm9240_read_value(client, ADM9240_REG_VID_FAN_DIV);
+ data->fan_div[0] = (i >> 4) & 3;
+ data->fan_div[1] = (i >> 6) & 3;
+ data->vid = i & 0x0f;
+ data->vid |= (adm9240_read_value(client,
+ ADM9240_REG_VID4) & 1) << 4;
+ /* read analog out */
+ data->aout = adm9240_read_value(client,
+ ADM9240_REG_ANALOG_OUT);
+
+ data->last_updated_config = jiffies;
+ data->valid = 1;
+ }
+ up(&data->update_lock);
+ return data;
+}
+
+static int __init sensors_adm9240_init(void)
+{
+ return i2c_add_driver(&adm9240_driver);
+}
+
+static void __exit sensors_adm9240_exit(void)
+{
+ i2c_del_driver(&adm9240_driver);
+}
+
+MODULE_AUTHOR("Michiel Rook <michiel@grendelproject.nl>, "
+ "Grant Coady <gcoady@gmail.com> and others");
+MODULE_DESCRIPTION("ADM9240/DS1780/LM81 driver");
+MODULE_LICENSE("GPL");
+
+module_init(sensors_adm9240_init);
+module_exit(sensors_adm9240_exit);
+
#include <linux/i2c-sensor.h>
#include <linux/i2c-vid.h>
#include <linux/init.h>
+#include <linux/jiffies.h>
#include "lm75.h"
/*
return reg * 16;
}
-#define ALARMS_FROM_REG(val) (val)
-
#define DIV_FROM_REG(val) (1 << (val))
/* FAN DIV: 1, 2, 4, or 8 (defaults to 2)
static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
{
struct asb100_data *data = asb100_update_device(dev);
- return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->alarms));
+ return sprintf(buf, "%u\n", data->alarms);
}
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
--- /dev/null
+/*
+ atxp1.c - kernel module for setting CPU VID and general purpose
+ I/Os using the Attansic ATXP1 chip.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/i2c-sensor.h>
+#include <linux/i2c-vid.h>
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("System voltages control via Attansic ATXP1");
+MODULE_VERSION("0.6.2");
+MODULE_AUTHOR("Sebastian Witt <se.witt@gmx.net>");
+
+#define ATXP1_VID 0x00
+#define ATXP1_CVID 0x01
+#define ATXP1_GPIO1 0x06
+#define ATXP1_GPIO2 0x0a
+#define ATXP1_VIDENA 0x20
+#define ATXP1_VIDMASK 0x1f
+#define ATXP1_GPIO1MASK 0x0f
+
+static unsigned short normal_i2c[] = { 0x37, 0x4e, I2C_CLIENT_END };
+static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
+
+SENSORS_INSMOD_1(atxp1);
+
+static int atxp1_attach_adapter(struct i2c_adapter * adapter);
+static int atxp1_detach_client(struct i2c_client * client);
+static struct atxp1_data * atxp1_update_device(struct device *dev);
+static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind);
+
+static struct i2c_driver atxp1_driver = {
+ .owner = THIS_MODULE,
+ .name = "atxp1",
+ .flags = I2C_DF_NOTIFY,
+ .attach_adapter = atxp1_attach_adapter,
+ .detach_client = atxp1_detach_client,
+};
+
+struct atxp1_data {
+ struct i2c_client client;
+ struct semaphore update_lock;
+ unsigned long last_updated;
+ u8 valid;
+ struct {
+ u8 vid; /* VID output register */
+ u8 cpu_vid; /* VID input from CPU */
+ u8 gpio1; /* General purpose I/O register 1 */
+ u8 gpio2; /* General purpose I/O register 2 */
+ } reg;
+ u8 vrm; /* Detected CPU VRM */
+};
+
+static struct atxp1_data * atxp1_update_device(struct device *dev)
+{
+ struct i2c_client *client;
+ struct atxp1_data *data;
+
+ client = to_i2c_client(dev);
+ data = i2c_get_clientdata(client);
+
+ down(&data->update_lock);
+
+ if ((jiffies - data->last_updated > HZ) ||
+ (jiffies < data->last_updated) ||
+ !data->valid) {
+
+ /* Update local register data */
+ data->reg.vid = i2c_smbus_read_byte_data(client, ATXP1_VID);
+ data->reg.cpu_vid = i2c_smbus_read_byte_data(client, ATXP1_CVID);
+ data->reg.gpio1 = i2c_smbus_read_byte_data(client, ATXP1_GPIO1);
+ data->reg.gpio2 = i2c_smbus_read_byte_data(client, ATXP1_GPIO2);
+
+ data->valid = 1;
+ }
+
+ up(&data->update_lock);
+
+ return(data);
+}
+
+/* sys file functions for cpu0_vid */
+static ssize_t atxp1_showvcore(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int size;
+ struct atxp1_data *data;
+
+ data = atxp1_update_device(dev);
+
+ size = sprintf(buf, "%d\n", vid_from_reg(data->reg.vid & ATXP1_VIDMASK, data->vrm));
+
+ return size;
+}
+
+static ssize_t atxp1_storevcore(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct atxp1_data *data;
+ struct i2c_client *client;
+ char vid;
+ char cvid;
+ unsigned int vcore;
+
+ client = to_i2c_client(dev);
+ data = atxp1_update_device(dev);
+
+ vcore = simple_strtoul(buf, NULL, 10);
+ vcore /= 25;
+ vcore *= 25;
+
+ /* Calculate VID */
+ vid = vid_to_reg(vcore, data->vrm);
+
+ if (vid < 0) {
+ dev_err(dev, "VID calculation failed.\n");
+ return -1;
+ }
+
+ /* If output enabled, use control register value. Otherwise original CPU VID */
+ if (data->reg.vid & ATXP1_VIDENA)
+ cvid = data->reg.vid & ATXP1_VIDMASK;
+ else
+ cvid = data->reg.cpu_vid;
+
+ /* Nothing changed, aborting */
+ if (vid == cvid)
+ return count;
+
+ dev_info(dev, "Setting VCore to %d mV (0x%02x)\n", vcore, vid);
+
+ /* Write every 25 mV step to increase stability */
+ if (cvid > vid) {
+ for (; cvid >= vid; cvid--) {
+ i2c_smbus_write_byte_data(client, ATXP1_VID, cvid | ATXP1_VIDENA);
+ }
+ }
+ else {
+ for (; cvid <= vid; cvid++) {
+ i2c_smbus_write_byte_data(client, ATXP1_VID, cvid | ATXP1_VIDENA);
+ }
+ }
+
+ data->valid = 0;
+
+ return count;
+}
+
+/* CPU core reference voltage
+ unit: millivolt
+*/
+static DEVICE_ATTR(cpu0_vid, S_IRUGO | S_IWUSR, atxp1_showvcore, atxp1_storevcore);
+
+/* sys file functions for GPIO1 */
+static ssize_t atxp1_showgpio1(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int size;
+ struct atxp1_data *data;
+
+ data = atxp1_update_device(dev);
+
+ size = sprintf(buf, "0x%02x\n", data->reg.gpio1 & ATXP1_GPIO1MASK);
+
+ return size;
+}
+
+static ssize_t atxp1_storegpio1(struct device *dev, struct device_attribute *attr, const char*buf, size_t count)
+{
+ struct atxp1_data *data;
+ struct i2c_client *client;
+ unsigned int value;
+
+ client = to_i2c_client(dev);
+ data = atxp1_update_device(dev);
+
+ value = simple_strtoul(buf, NULL, 16);
+
+ value &= ATXP1_GPIO1MASK;
+
+ if (value != (data->reg.gpio1 & ATXP1_GPIO1MASK)) {
+ dev_info(dev, "Writing 0x%x to GPIO1.\n", value);
+
+ i2c_smbus_write_byte_data(client, ATXP1_GPIO1, value);
+
+ data->valid = 0;
+ }
+
+ return count;
+}
+
+/* GPIO1 data register
+ unit: Four bit as hex (e.g. 0x0f)
+*/
+static DEVICE_ATTR(gpio1, S_IRUGO | S_IWUSR, atxp1_showgpio1, atxp1_storegpio1);
+
+/* sys file functions for GPIO2 */
+static ssize_t atxp1_showgpio2(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int size;
+ struct atxp1_data *data;
+
+ data = atxp1_update_device(dev);
+
+ size = sprintf(buf, "0x%02x\n", data->reg.gpio2);
+
+ return size;
+}
+
+static ssize_t atxp1_storegpio2(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct atxp1_data *data;
+ struct i2c_client *client;
+ unsigned int value;
+
+ client = to_i2c_client(dev);
+ data = atxp1_update_device(dev);
+
+ value = simple_strtoul(buf, NULL, 16) & 0xff;
+
+ if (value != data->reg.gpio2) {
+ dev_info(dev, "Writing 0x%x to GPIO1.\n", value);
+
+ i2c_smbus_write_byte_data(client, ATXP1_GPIO2, value);
+
+ data->valid = 0;
+ }
+
+ return count;
+}
+
+/* GPIO2 data register
+ unit: Eight bit as hex (e.g. 0xff)
+*/
+static DEVICE_ATTR(gpio2, S_IRUGO | S_IWUSR, atxp1_showgpio2, atxp1_storegpio2);
+
+
+static int atxp1_attach_adapter(struct i2c_adapter *adapter)
+{
+ return i2c_detect(adapter, &addr_data, &atxp1_detect);
+};
+
+static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+ struct i2c_client * new_client;
+ struct atxp1_data * data;
+ int err = 0;
+ u8 temp;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ goto exit;
+
+ if (!(data = kmalloc(sizeof(struct atxp1_data), GFP_KERNEL))) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ memset(data, 0, sizeof(struct atxp1_data));
+ new_client = &data->client;
+ i2c_set_clientdata(new_client, data);
+
+ new_client->addr = address;
+ new_client->adapter = adapter;
+ new_client->driver = &atxp1_driver;
+ new_client->flags = 0;
+
+ /* Detect ATXP1, checking if vendor ID registers are all zero */
+ if (!((i2c_smbus_read_byte_data(new_client, 0x3e) == 0) &&
+ (i2c_smbus_read_byte_data(new_client, 0x3f) == 0) &&
+ (i2c_smbus_read_byte_data(new_client, 0xfe) == 0) &&
+ (i2c_smbus_read_byte_data(new_client, 0xff) == 0) )) {
+
+ /* No vendor ID, now checking if registers 0x10,0x11 (non-existent)
+ * showing the same as register 0x00 */
+ temp = i2c_smbus_read_byte_data(new_client, 0x00);
+
+ if (!((i2c_smbus_read_byte_data(new_client, 0x10) == temp) &&
+ (i2c_smbus_read_byte_data(new_client, 0x11) == temp) ))
+ goto exit_free;
+ }
+
+ /* Get VRM */
+ data->vrm = i2c_which_vrm();
+
+ if ((data->vrm != 90) && (data->vrm != 91)) {
+ dev_err(&new_client->dev, "Not supporting VRM %d.%d\n",
+ data->vrm / 10, data->vrm % 10);
+ goto exit_free;
+ }
+
+ strncpy(new_client->name, "atxp1", I2C_NAME_SIZE);
+
+ data->valid = 0;
+
+ init_MUTEX(&data->update_lock);
+
+ err = i2c_attach_client(new_client);
+
+ if (err)
+ {
+ dev_err(&new_client->dev, "Attach client error.\n");
+ goto exit_free;
+ }
+
+ device_create_file(&new_client->dev, &dev_attr_gpio1);
+ device_create_file(&new_client->dev, &dev_attr_gpio2);
+ device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
+
+ dev_info(&new_client->dev, "Using VRM: %d.%d\n",
+ data->vrm / 10, data->vrm % 10);
+
+ return 0;
+
+exit_free:
+ kfree(data);
+exit:
+ return err;
+};
+
+static int atxp1_detach_client(struct i2c_client * client)
+{
+ int err;
+
+ err = i2c_detach_client(client);
+
+ if (err)
+ dev_err(&client->dev, "Failed to detach client.\n");
+ else
+ kfree(i2c_get_clientdata(client));
+
+ return err;
+};
+
+static int __init atxp1_init(void)
+{
+ return i2c_add_driver(&atxp1_driver);
+};
+
+static void __exit atxp1_exit(void)
+{
+ i2c_del_driver(&atxp1_driver);
+};
+
+module_init(atxp1_init);
+module_exit(atxp1_exit);
*
* Copyright (C) 2005 James Chapman <jchapman@katalix.com>
*
- * based on linux/drivers/acron/char/pcf8583.c
+ * based on linux/drivers/acorn/char/pcf8583.c
* Copyright (C) 2000 Russell King
*
* 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.
*
- * Driver for Dallas Semiconductor DS1337 real time clock chip
+ * Driver for Dallas Semiconductor DS1337 and DS1339 real time clock chip
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
struct ds1337_data {
struct i2c_client client;
struct list_head list;
- int id;
};
/*
* Internal variables
*/
-static int ds1337_id;
static LIST_HEAD(ds1337_clients);
static inline int ds1337_read(struct i2c_client *client, u8 reg, u8 *value)
*/
static int ds1337_get_datetime(struct i2c_client *client, struct rtc_time *dt)
{
- struct ds1337_data *data = i2c_get_clientdata(client);
int result;
u8 buf[7];
u8 val;
u8 offs = 0;
if (!dt) {
- dev_dbg(&client->adapter->dev, "%s: EINVAL: dt=NULL\n",
- __FUNCTION__);
-
+ dev_dbg(&client->dev, "%s: EINVAL: dt=NULL\n", __FUNCTION__);
return -EINVAL;
}
msg[1].len = sizeof(buf);
msg[1].buf = &buf[0];
- result = client->adapter->algo->master_xfer(client->adapter,
- &msg[0], 2);
+ result = i2c_transfer(client->adapter, msg, 2);
- dev_dbg(&client->adapter->dev,
- "%s: [%d] %02x %02x %02x %02x %02x %02x %02x\n",
+ dev_dbg(&client->dev, "%s: [%d] %02x %02x %02x %02x %02x %02x %02x\n",
__FUNCTION__, result, buf[0], buf[1], buf[2], buf[3],
buf[4], buf[5], buf[6]);
- if (result >= 0) {
- dt->tm_sec = BCD_TO_BIN(buf[0]);
- dt->tm_min = BCD_TO_BIN(buf[1]);
+ if (result == 2) {
+ dt->tm_sec = BCD2BIN(buf[0]);
+ dt->tm_min = BCD2BIN(buf[1]);
val = buf[2] & 0x3f;
- dt->tm_hour = BCD_TO_BIN(val);
- dt->tm_wday = BCD_TO_BIN(buf[3]) - 1;
- dt->tm_mday = BCD_TO_BIN(buf[4]);
+ dt->tm_hour = BCD2BIN(val);
+ dt->tm_wday = BCD2BIN(buf[3]) - 1;
+ dt->tm_mday = BCD2BIN(buf[4]);
val = buf[5] & 0x7f;
- dt->tm_mon = BCD_TO_BIN(val);
- dt->tm_year = 1900 + BCD_TO_BIN(buf[6]);
+ dt->tm_mon = BCD2BIN(val) - 1;
+ dt->tm_year = BCD2BIN(buf[6]);
if (buf[5] & 0x80)
dt->tm_year += 100;
- dev_dbg(&client->adapter->dev, "%s: secs=%d, mins=%d, "
+ dev_dbg(&client->dev, "%s: secs=%d, mins=%d, "
"hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
__FUNCTION__, dt->tm_sec, dt->tm_min,
dt->tm_hour, dt->tm_mday,
dt->tm_mon, dt->tm_year, dt->tm_wday);
- } else {
- dev_err(&client->adapter->dev, "ds1337[%d]: error reading "
- "data! %d\n", data->id, result);
- result = -EIO;
+
+ return 0;
}
- return result;
+ dev_err(&client->dev, "error reading data! %d\n", result);
+ return -EIO;
}
static int ds1337_set_datetime(struct i2c_client *client, struct rtc_time *dt)
{
- struct ds1337_data *data = i2c_get_clientdata(client);
int result;
u8 buf[8];
u8 val;
struct i2c_msg msg[1];
if (!dt) {
- dev_dbg(&client->adapter->dev, "%s: EINVAL: dt=NULL\n",
- __FUNCTION__);
-
+ dev_dbg(&client->dev, "%s: EINVAL: dt=NULL\n", __FUNCTION__);
return -EINVAL;
}
- dev_dbg(&client->adapter->dev, "%s: secs=%d, mins=%d, hours=%d, "
+ dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, "
"mday=%d, mon=%d, year=%d, wday=%d\n", __FUNCTION__,
dt->tm_sec, dt->tm_min, dt->tm_hour,
dt->tm_mday, dt->tm_mon, dt->tm_year, dt->tm_wday);
buf[0] = 0; /* reg offset */
- buf[1] = BIN_TO_BCD(dt->tm_sec);
- buf[2] = BIN_TO_BCD(dt->tm_min);
- buf[3] = BIN_TO_BCD(dt->tm_hour) | (1 << 6);
- buf[4] = BIN_TO_BCD(dt->tm_wday) + 1;
- buf[5] = BIN_TO_BCD(dt->tm_mday);
- buf[6] = BIN_TO_BCD(dt->tm_mon);
- if (dt->tm_year >= 2000) {
- val = dt->tm_year - 2000;
+ buf[1] = BIN2BCD(dt->tm_sec);
+ buf[2] = BIN2BCD(dt->tm_min);
+ buf[3] = BIN2BCD(dt->tm_hour) | (1 << 6);
+ buf[4] = BIN2BCD(dt->tm_wday) + 1;
+ buf[5] = BIN2BCD(dt->tm_mday);
+ buf[6] = BIN2BCD(dt->tm_mon) + 1;
+ val = dt->tm_year;
+ if (val >= 100) {
+ val -= 100;
buf[6] |= (1 << 7);
- } else {
- val = dt->tm_year - 1900;
}
- buf[7] = BIN_TO_BCD(val);
+ buf[7] = BIN2BCD(val);
msg[0].addr = client->addr;
msg[0].flags = 0;
msg[0].len = sizeof(buf);
msg[0].buf = &buf[0];
- result = client->adapter->algo->master_xfer(client->adapter,
- &msg[0], 1);
- if (result < 0) {
- dev_err(&client->adapter->dev, "ds1337[%d]: error "
- "writing data! %d\n", data->id, result);
- result = -EIO;
- } else {
- result = 0;
- }
+ result = i2c_transfer(client->adapter, msg, 1);
+ if (result == 1)
+ return 0;
- return result;
+ dev_err(&client->dev, "error writing data! %d\n", result);
+ return -EIO;
}
static int ds1337_command(struct i2c_client *client, unsigned int cmd,
void *arg)
{
- dev_dbg(&client->adapter->dev, "%s: cmd=%d\n", __FUNCTION__, cmd);
+ dev_dbg(&client->dev, "%s: cmd=%d\n", __FUNCTION__, cmd);
switch (cmd) {
case DS1337_GET_DATE:
* Public API for access to specific device. Useful for low-level
* RTC access from kernel code.
*/
-int ds1337_do_command(int id, int cmd, void *arg)
+int ds1337_do_command(int bus, int cmd, void *arg)
{
struct list_head *walk;
struct list_head *tmp;
list_for_each_safe(walk, tmp, &ds1337_clients) {
data = list_entry(walk, struct ds1337_data, list);
- if (data->id == id)
+ if (data->client.adapter->nr == bus)
return ds1337_command(&data->client, cmd, arg);
}
ds1337_init_client(new_client);
/* Add client to local list */
- data->id = ds1337_id++;
list_add(&data->list, &ds1337_clients);
return 0;
MODULE_DESCRIPTION("DS1337 RTC driver");
MODULE_LICENSE("GPL");
+EXPORT_SYMBOL_GPL(ds1337_do_command);
+
module_init(ds1337_init);
module_exit(ds1337_exit);
--- /dev/null
+/*
+ * drivers/i2c/chips/ds1374.c
+ *
+ * I2C client/driver for the Maxim/Dallas DS1374 Real-Time Clock
+ *
+ * Author: Randy Vinson <rvinson@mvista.com>
+ *
+ * Based on the m41t00.c by Mark Greer <mgreer@mvista.com>
+ *
+ * 2005 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+/*
+ * This i2c client/driver wedges between the drivers/char/genrtc.c RTC
+ * interface and the SMBus interface of the i2c subsystem.
+ * It would be more efficient to use i2c msgs/i2c_transfer directly but, as
+ * recommened in .../Documentation/i2c/writing-clients section
+ * "Sending and receiving", using SMBus level communication is preferred.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+
+#define DS1374_REG_TOD0 0x00
+#define DS1374_REG_TOD1 0x01
+#define DS1374_REG_TOD2 0x02
+#define DS1374_REG_TOD3 0x03
+#define DS1374_REG_WDALM0 0x04
+#define DS1374_REG_WDALM1 0x05
+#define DS1374_REG_WDALM2 0x06
+#define DS1374_REG_CR 0x07
+#define DS1374_REG_SR 0x08
+#define DS1374_REG_SR_OSF 0x80
+#define DS1374_REG_TCR 0x09
+
+#define DS1374_DRV_NAME "ds1374"
+
+static DECLARE_MUTEX(ds1374_mutex);
+
+static struct i2c_driver ds1374_driver;
+static struct i2c_client *save_client;
+
+static unsigned short ignore[] = { I2C_CLIENT_END };
+static unsigned short normal_addr[] = { 0x68, I2C_CLIENT_END };
+
+static struct i2c_client_address_data addr_data = {
+ .normal_i2c = normal_addr,
+ .probe = ignore,
+ .ignore = ignore,
+ .force = ignore,
+};
+
+static ulong ds1374_read_rtc(void)
+{
+ ulong time = 0;
+ int reg = DS1374_REG_WDALM0;
+
+ while (reg--) {
+ s32 tmp;
+ if ((tmp = i2c_smbus_read_byte_data(save_client, reg)) < 0) {
+ dev_warn(&save_client->dev,
+ "can't read from rtc chip\n");
+ return 0;
+ }
+ time = (time << 8) | (tmp & 0xff);
+ }
+ return time;
+}
+
+static void ds1374_write_rtc(ulong time)
+{
+ int reg;
+
+ for (reg = DS1374_REG_TOD0; reg < DS1374_REG_WDALM0; reg++) {
+ if (i2c_smbus_write_byte_data(save_client, reg, time & 0xff)
+ < 0) {
+ dev_warn(&save_client->dev,
+ "can't write to rtc chip\n");
+ break;
+ }
+ time = time >> 8;
+ }
+}
+
+static void ds1374_check_rtc_status(void)
+{
+ s32 tmp;
+
+ tmp = i2c_smbus_read_byte_data(save_client, DS1374_REG_SR);
+ if (tmp < 0) {
+ dev_warn(&save_client->dev,
+ "can't read status from rtc chip\n");
+ return;
+ }
+ if (tmp & DS1374_REG_SR_OSF) {
+ dev_warn(&save_client->dev,
+ "oscillator discontinuity flagged, time unreliable\n");
+ tmp &= ~DS1374_REG_SR_OSF;
+ tmp = i2c_smbus_write_byte_data(save_client, DS1374_REG_SR,
+ tmp & 0xff);
+ if (tmp < 0)
+ dev_warn(&save_client->dev,
+ "can't clear discontinuity notification\n");
+ }
+}
+
+ulong ds1374_get_rtc_time(void)
+{
+ ulong t1, t2;
+ int limit = 10; /* arbitrary retry limit */
+
+ down(&ds1374_mutex);
+
+ /*
+ * Since the reads are being performed one byte at a time using
+ * the SMBus vs a 4-byte i2c transfer, there is a chance that a
+ * carry will occur during the read. To detect this, 2 reads are
+ * performed and compared.
+ */
+ do {
+ t1 = ds1374_read_rtc();
+ t2 = ds1374_read_rtc();
+ } while (t1 != t2 && limit--);
+
+ up(&ds1374_mutex);
+
+ if (t1 != t2) {
+ dev_warn(&save_client->dev,
+ "can't get consistent time from rtc chip\n");
+ t1 = 0;
+ }
+
+ return t1;
+}
+
+static void ds1374_set_tlet(ulong arg)
+{
+ ulong t1, t2;
+ int limit = 10; /* arbitrary retry limit */
+
+ t1 = *(ulong *) arg;
+
+ down(&ds1374_mutex);
+
+ /*
+ * Since the writes are being performed one byte at a time using
+ * the SMBus vs a 4-byte i2c transfer, there is a chance that a
+ * carry will occur during the write. To detect this, the write
+ * value is read back and compared.
+ */
+ do {
+ ds1374_write_rtc(t1);
+ t2 = ds1374_read_rtc();
+ } while (t1 != t2 && limit--);
+
+ up(&ds1374_mutex);
+
+ if (t1 != t2)
+ dev_warn(&save_client->dev,
+ "can't confirm time set from rtc chip\n");
+}
+
+ulong new_time;
+
+DECLARE_TASKLET_DISABLED(ds1374_tasklet, ds1374_set_tlet, (ulong) & new_time);
+
+int ds1374_set_rtc_time(ulong nowtime)
+{
+ new_time = nowtime;
+
+ if (in_interrupt())
+ tasklet_schedule(&ds1374_tasklet);
+ else
+ ds1374_set_tlet((ulong) & new_time);
+
+ return 0;
+}
+
+/*
+ *****************************************************************************
+ *
+ * Driver Interface
+ *
+ *****************************************************************************
+ */
+static int ds1374_probe(struct i2c_adapter *adap, int addr, int kind)
+{
+ struct i2c_client *client;
+ int rc;
+
+ client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ if (!client)
+ return -ENOMEM;
+
+ memset(client, 0, sizeof(struct i2c_client));
+ strncpy(client->name, DS1374_DRV_NAME, I2C_NAME_SIZE);
+ client->flags = I2C_DF_NOTIFY;
+ client->addr = addr;
+ client->adapter = adap;
+ client->driver = &ds1374_driver;
+
+ if ((rc = i2c_attach_client(client)) != 0) {
+ kfree(client);
+ return rc;
+ }
+
+ save_client = client;
+
+ ds1374_check_rtc_status();
+
+ return 0;
+}
+
+static int ds1374_attach(struct i2c_adapter *adap)
+{
+ return i2c_probe(adap, &addr_data, ds1374_probe);
+}
+
+static int ds1374_detach(struct i2c_client *client)
+{
+ int rc;
+
+ if ((rc = i2c_detach_client(client)) == 0) {
+ kfree(i2c_get_clientdata(client));
+ tasklet_kill(&ds1374_tasklet);
+ }
+ return rc;
+}
+
+static struct i2c_driver ds1374_driver = {
+ .owner = THIS_MODULE,
+ .name = DS1374_DRV_NAME,
+ .id = I2C_DRIVERID_DS1374,
+ .flags = I2C_DF_NOTIFY,
+ .attach_adapter = ds1374_attach,
+ .detach_client = ds1374_detach,
+};
+
+static int __init ds1374_init(void)
+{
+ return i2c_add_driver(&ds1374_driver);
+}
+
+static void __exit ds1374_exit(void)
+{
+ i2c_del_driver(&ds1374_driver);
+}
+
+module_init(ds1374_init);
+module_exit(ds1374_exit);
+
+MODULE_AUTHOR("Randy Vinson <rvinson@mvista.com>");
+MODULE_DESCRIPTION("Maxim/Dallas DS1374 RTC I2C Client Driver");
+MODULE_LICENSE("GPL");
static void ds1621_init_client(struct i2c_client *client)
{
int reg = ds1621_read_value(client, DS1621_REG_CONF);
- /* switch to continous conversion mode */
+ /* switch to continuous conversion mode */
reg &= ~ DS1621_REG_CONFIG_1SHOT;
/* setup output polarity */
data->temp_max = ds1621_read_value(client,
DS1621_REG_TEMP_MAX);
- /* reset alarms if neccessary */
+ /* reset alarms if necessary */
new_conf = data->conf;
if (data->temp < data->temp_min)
new_conf &= ~DS1621_ALARM_TEMP_LOW;
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
* and Philip Edelbrock <phil@netroedge.com>
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
* 2004-01-31 Code review and approval. (Jean Delvare)
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
static unsigned short normal_i2c[] = {
ISP_BASE, ISP_BASE + 1,
I2C_CLIENT_END };
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
I2C_CLIENT_INSMOD;
type at module load time.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/i2c-sensor.h>
#include <linux/i2c-vid.h>
+#include <linux/hwmon-sysfs.h>
#include <asm/io.h>
((val)+500)/1000),-128,127))
#define TEMP_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*1000)
-#define ALARMS_FROM_REG(val) (val)
-
#define PWM_TO_REG(val) ((val) >> 1)
#define PWM_FROM_REG(val) (((val)&0x7f) << 1)
.detach_client = it87_detach_client,
};
-static ssize_t show_in(struct device *dev, char *buf, int nr)
+static ssize_t show_in(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+
struct it87_data *data = it87_update_device(dev);
return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr]));
}
-static ssize_t show_in_min(struct device *dev, char *buf, int nr)
+static ssize_t show_in_min(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+
struct it87_data *data = it87_update_device(dev);
return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr]));
}
-static ssize_t show_in_max(struct device *dev, char *buf, int nr)
+static ssize_t show_in_max(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+
struct it87_data *data = it87_update_device(dev);
return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr]));
}
-static ssize_t set_in_min(struct device *dev, const char *buf,
- size_t count, int nr)
+static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+
struct i2c_client *client = to_i2c_client(dev);
struct it87_data *data = i2c_get_clientdata(client);
unsigned long val = simple_strtoul(buf, NULL, 10);
up(&data->update_lock);
return count;
}
-static ssize_t set_in_max(struct device *dev, const char *buf,
- size_t count, int nr)
+static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+
struct i2c_client *client = to_i2c_client(dev);
struct it87_data *data = i2c_get_clientdata(client);
unsigned long val = simple_strtoul(buf, NULL, 10);
}
#define show_in_offset(offset) \
-static ssize_t \
- show_in##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_in(dev, buf, offset); \
-} \
-static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL);
+static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
+ show_in, NULL, offset);
#define limit_in_offset(offset) \
-static ssize_t \
- show_in##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_in_min(dev, buf, offset); \
-} \
-static ssize_t \
- show_in##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_in_max(dev, buf, offset); \
-} \
-static ssize_t set_in##offset##_min (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_in_min(dev, buf, count, offset); \
-} \
-static ssize_t set_in##offset##_max (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_in_max(dev, buf, count, offset); \
-} \
-static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
- show_in##offset##_min, set_in##offset##_min); \
-static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
- show_in##offset##_max, set_in##offset##_max);
+static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
+ show_in_min, set_in_min, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
+ show_in_max, set_in_max, offset);
show_in_offset(0);
limit_in_offset(0);
show_in_offset(8);
/* 3 temperatures */
-static ssize_t show_temp(struct device *dev, char *buf, int nr)
+static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+
struct it87_data *data = it87_update_device(dev);
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr]));
}
-static ssize_t show_temp_max(struct device *dev, char *buf, int nr)
+static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+
struct it87_data *data = it87_update_device(dev);
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_high[nr]));
}
-static ssize_t show_temp_min(struct device *dev, char *buf, int nr)
+static ssize_t show_temp_min(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+
struct it87_data *data = it87_update_device(dev);
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_low[nr]));
}
-static ssize_t set_temp_max(struct device *dev, const char *buf,
- size_t count, int nr)
+static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+
struct i2c_client *client = to_i2c_client(dev);
struct it87_data *data = i2c_get_clientdata(client);
int val = simple_strtol(buf, NULL, 10);
up(&data->update_lock);
return count;
}
-static ssize_t set_temp_min(struct device *dev, const char *buf,
- size_t count, int nr)
+static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+
struct i2c_client *client = to_i2c_client(dev);
struct it87_data *data = i2c_get_clientdata(client);
int val = simple_strtol(buf, NULL, 10);
return count;
}
#define show_temp_offset(offset) \
-static ssize_t show_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_temp(dev, buf, offset - 1); \
-} \
-static ssize_t \
-show_temp_##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_temp_max(dev, buf, offset - 1); \
-} \
-static ssize_t \
-show_temp_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_temp_min(dev, buf, offset - 1); \
-} \
-static ssize_t set_temp_##offset##_max (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_temp_max(dev, buf, count, offset - 1); \
-} \
-static ssize_t set_temp_##offset##_min (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_temp_min(dev, buf, count, offset - 1); \
-} \
-static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, NULL); \
-static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \
- show_temp_##offset##_max, set_temp_##offset##_max); \
-static DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \
- show_temp_##offset##_min, set_temp_##offset##_min);
+static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
+ show_temp, NULL, offset - 1); \
+static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \
+ show_temp_max, set_temp_max, offset - 1); \
+static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \
+ show_temp_min, set_temp_min, offset - 1);
show_temp_offset(1);
show_temp_offset(2);
show_temp_offset(3);
-static ssize_t show_sensor(struct device *dev, char *buf, int nr)
+static ssize_t show_sensor(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+
struct it87_data *data = it87_update_device(dev);
u8 reg = data->sensor; /* In case the value is updated while we use it */
return sprintf(buf, "2\n"); /* thermistor */
return sprintf(buf, "0\n"); /* disabled */
}
-static ssize_t set_sensor(struct device *dev, const char *buf,
- size_t count, int nr)
+static ssize_t set_sensor(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+
struct i2c_client *client = to_i2c_client(dev);
struct it87_data *data = i2c_get_clientdata(client);
int val = simple_strtol(buf, NULL, 10);
return count;
}
#define show_sensor_offset(offset) \
-static ssize_t show_sensor_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_sensor(dev, buf, offset - 1); \
-} \
-static ssize_t set_sensor_##offset (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_sensor(dev, buf, count, offset - 1); \
-} \
-static DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \
- show_sensor_##offset, set_sensor_##offset);
+static SENSOR_DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \
+ show_sensor, set_sensor, offset - 1);
show_sensor_offset(1);
show_sensor_offset(2);
show_sensor_offset(3);
/* 3 Fans */
-static ssize_t show_fan(struct device *dev, char *buf, int nr)
+static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+
struct it87_data *data = it87_update_device(dev);
return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan[nr],
DIV_FROM_REG(data->fan_div[nr])));
}
-static ssize_t show_fan_min(struct device *dev, char *buf, int nr)
+static ssize_t show_fan_min(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+
struct it87_data *data = it87_update_device(dev);
return sprintf(buf,"%d\n",
FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])));
}
-static ssize_t show_fan_div(struct device *dev, char *buf, int nr)
+static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+
struct it87_data *data = it87_update_device(dev);
return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]));
}
-static ssize_t show_pwm_enable(struct device *dev, char *buf, int nr)
+static ssize_t show_pwm_enable(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+
struct it87_data *data = it87_update_device(dev);
return sprintf(buf,"%d\n", (data->fan_main_ctrl & (1 << nr)) ? 1 : 0);
}
-static ssize_t show_pwm(struct device *dev, char *buf, int nr)
+static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+
struct it87_data *data = it87_update_device(dev);
return sprintf(buf,"%d\n", data->manual_pwm_ctl[nr]);
}
-static ssize_t set_fan_min(struct device *dev, const char *buf,
- size_t count, int nr)
+static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+
struct i2c_client *client = to_i2c_client(dev);
struct it87_data *data = i2c_get_clientdata(client);
int val = simple_strtol(buf, NULL, 10);
up(&data->update_lock);
return count;
}
-static ssize_t set_fan_div(struct device *dev, const char *buf,
- size_t count, int nr)
+static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+
struct i2c_client *client = to_i2c_client(dev);
struct it87_data *data = i2c_get_clientdata(client);
int val = simple_strtol(buf, NULL, 10);
up(&data->update_lock);
return count;
}
-static ssize_t set_pwm_enable(struct device *dev, const char *buf,
- size_t count, int nr)
+static ssize_t set_pwm_enable(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+
struct i2c_client *client = to_i2c_client(dev);
struct it87_data *data = i2c_get_clientdata(client);
int val = simple_strtol(buf, NULL, 10);
up(&data->update_lock);
return count;
}
-static ssize_t set_pwm(struct device *dev, const char *buf,
- size_t count, int nr)
+static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+
struct i2c_client *client = to_i2c_client(dev);
struct it87_data *data = i2c_get_clientdata(client);
int val = simple_strtol(buf, NULL, 10);
return count;
}
-#define show_fan_offset(offset) \
-static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_fan(dev, buf, offset - 1); \
-} \
-static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_fan_min(dev, buf, offset - 1); \
-} \
-static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_fan_div(dev, buf, offset - 1); \
-} \
-static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_fan_min(dev, buf, count, offset - 1); \
-} \
-static ssize_t set_fan_##offset##_div (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_fan_div(dev, buf, count, offset - 1); \
-} \
-static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL); \
-static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
- show_fan_##offset##_min, set_fan_##offset##_min); \
-static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
- show_fan_##offset##_div, set_fan_##offset##_div);
+#define show_fan_offset(offset) \
+static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
+ show_fan, NULL, offset - 1); \
+static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
+ show_fan_min, set_fan_min, offset - 1); \
+static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
+ show_fan_div, set_fan_div, offset - 1);
show_fan_offset(1);
show_fan_offset(2);
show_fan_offset(3);
#define show_pwm_offset(offset) \
-static ssize_t show_pwm##offset##_enable (struct device *dev, struct device_attribute *attr, \
- char *buf) \
-{ \
- return show_pwm_enable(dev, buf, offset - 1); \
-} \
-static ssize_t show_pwm##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_pwm(dev, buf, offset - 1); \
-} \
-static ssize_t set_pwm##offset##_enable (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_pwm_enable(dev, buf, count, offset - 1); \
-} \
-static ssize_t set_pwm##offset (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_pwm(dev, buf, count, offset - 1); \
-} \
-static DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \
- show_pwm##offset##_enable, \
- set_pwm##offset##_enable); \
-static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \
- show_pwm##offset , set_pwm##offset );
+static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \
+ show_pwm_enable, set_pwm_enable, offset - 1); \
+static SENSOR_DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \
+ show_pwm, set_pwm, offset - 1);
show_pwm_offset(1);
show_pwm_offset(2);
static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
{
struct it87_data *data = it87_update_device(dev);
- return sprintf(buf,"%d\n", ALARMS_FROM_REG(data->alarms));
+ return sprintf(buf, "%u\n", data->alarms);
}
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
it87_init_client(new_client, data);
/* Register sysfs hooks */
- device_create_file(&new_client->dev, &dev_attr_in0_input);
- device_create_file(&new_client->dev, &dev_attr_in1_input);
- device_create_file(&new_client->dev, &dev_attr_in2_input);
- device_create_file(&new_client->dev, &dev_attr_in3_input);
- device_create_file(&new_client->dev, &dev_attr_in4_input);
- device_create_file(&new_client->dev, &dev_attr_in5_input);
- device_create_file(&new_client->dev, &dev_attr_in6_input);
- device_create_file(&new_client->dev, &dev_attr_in7_input);
- device_create_file(&new_client->dev, &dev_attr_in8_input);
- device_create_file(&new_client->dev, &dev_attr_in0_min);
- device_create_file(&new_client->dev, &dev_attr_in1_min);
- device_create_file(&new_client->dev, &dev_attr_in2_min);
- device_create_file(&new_client->dev, &dev_attr_in3_min);
- device_create_file(&new_client->dev, &dev_attr_in4_min);
- device_create_file(&new_client->dev, &dev_attr_in5_min);
- device_create_file(&new_client->dev, &dev_attr_in6_min);
- device_create_file(&new_client->dev, &dev_attr_in7_min);
- device_create_file(&new_client->dev, &dev_attr_in0_max);
- device_create_file(&new_client->dev, &dev_attr_in1_max);
- device_create_file(&new_client->dev, &dev_attr_in2_max);
- device_create_file(&new_client->dev, &dev_attr_in3_max);
- device_create_file(&new_client->dev, &dev_attr_in4_max);
- device_create_file(&new_client->dev, &dev_attr_in5_max);
- device_create_file(&new_client->dev, &dev_attr_in6_max);
- device_create_file(&new_client->dev, &dev_attr_in7_max);
- device_create_file(&new_client->dev, &dev_attr_temp1_input);
- device_create_file(&new_client->dev, &dev_attr_temp2_input);
- device_create_file(&new_client->dev, &dev_attr_temp3_input);
- device_create_file(&new_client->dev, &dev_attr_temp1_max);
- device_create_file(&new_client->dev, &dev_attr_temp2_max);
- device_create_file(&new_client->dev, &dev_attr_temp3_max);
- device_create_file(&new_client->dev, &dev_attr_temp1_min);
- device_create_file(&new_client->dev, &dev_attr_temp2_min);
- device_create_file(&new_client->dev, &dev_attr_temp3_min);
- device_create_file(&new_client->dev, &dev_attr_temp1_type);
- device_create_file(&new_client->dev, &dev_attr_temp2_type);
- device_create_file(&new_client->dev, &dev_attr_temp3_type);
- device_create_file(&new_client->dev, &dev_attr_fan1_input);
- device_create_file(&new_client->dev, &dev_attr_fan2_input);
- device_create_file(&new_client->dev, &dev_attr_fan3_input);
- device_create_file(&new_client->dev, &dev_attr_fan1_min);
- device_create_file(&new_client->dev, &dev_attr_fan2_min);
- device_create_file(&new_client->dev, &dev_attr_fan3_min);
- device_create_file(&new_client->dev, &dev_attr_fan1_div);
- device_create_file(&new_client->dev, &dev_attr_fan2_div);
- device_create_file(&new_client->dev, &dev_attr_fan3_div);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in0_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in1_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in2_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in3_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in4_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in5_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in6_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in7_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in8_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in0_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in1_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in2_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in3_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in4_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in5_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in6_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in7_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in0_max.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in1_max.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in2_max.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in3_max.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in4_max.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in5_max.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in6_max.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in7_max.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp1_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp2_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp3_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp1_max.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp2_max.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp3_max.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp1_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp2_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp3_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp1_type.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp2_type.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp3_type.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_fan1_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_fan2_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_fan3_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_fan1_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_fan2_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_fan3_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_fan1_div.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_fan2_div.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_fan3_div.dev_attr);
device_create_file(&new_client->dev, &dev_attr_alarms);
if (enable_pwm_interface) {
- device_create_file(&new_client->dev, &dev_attr_pwm1_enable);
- device_create_file(&new_client->dev, &dev_attr_pwm2_enable);
- device_create_file(&new_client->dev, &dev_attr_pwm3_enable);
- device_create_file(&new_client->dev, &dev_attr_pwm1);
- device_create_file(&new_client->dev, &dev_attr_pwm2);
- device_create_file(&new_client->dev, &dev_attr_pwm3);
+ device_create_file(&new_client->dev, &sensor_dev_attr_pwm1_enable.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_pwm2_enable.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_pwm3_enable.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_pwm1.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_pwm2.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_pwm3.dev_attr);
}
if (data->type == it8712) {
return 0;
}
-/* The SMBus locks itself, but ISA access must be locked explicitely!
+/* The SMBus locks itself, but ISA access must be locked explicitly!
We don't want to lock the whole ISA bus, so we lock each client
separately.
We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
return i2c_smbus_read_byte_data(client, reg);
}
-/* The SMBus locks itself, but ISA access muse be locked explicitely!
+/* The SMBus locks itself, but ISA access muse be locked explicitly!
We don't want to lock the whole ISA bus, so we lock each client
separately.
We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
/*
* lm63.c - driver for the National Semiconductor LM63 temperature sensor
* with integrated fan control
- * Copyright (C) 2004 Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2004-2005 Jean Delvare <khali@linux-fr.org>
* Based on the lm90 driver.
*
* The LM63 is a sensor chip made by National Semiconductor. It measures
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/i2c-sensor.h>
+#include <linux/hwmon-sysfs.h>
/*
* Addresses to scan
* Conversions and various macros
* For tachometer counts, the LM63 uses 16-bit values.
* For local temperature and high limit, remote critical limit and hysteresis
- * value, it uses signed 8-bit values with LSB = 1 degree Celcius.
+ * value, it uses signed 8-bit values with LSB = 1 degree Celsius.
* For remote temperature, low and high limits, it uses signed 11-bit values
- * with LSB = 0.125 degree Celcius, left-justified in 16-bit registers.
+ * with LSB = 0.125 degree Celsius, left-justified in 16-bit registers.
*/
#define FAN_FROM_REG(reg) ((reg) == 0xFFFC || (reg) == 0 ? 0 : \
/* registers values */
u8 config, config_fan;
- u16 fan1_input;
- u16 fan1_low;
+ u16 fan[2]; /* 0: input
+ 1: low limit */
u8 pwm1_freq;
u8 pwm1_value;
- s8 temp1_input;
- s8 temp1_high;
- s16 temp2_input;
- s16 temp2_high;
- s16 temp2_low;
- s8 temp2_crit;
+ s8 temp8[3]; /* 0: local input
+ 1: local high limit
+ 2: remote critical limit */
+ s16 temp11[3]; /* 0: remote input
+ 1: remote low limit
+ 2: remote high limit */
u8 temp2_crit_hyst;
u8 alarms;
};
* Sysfs callback functions and files
*/
-#define show_fan(value) \
-static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct lm63_data *data = lm63_update_device(dev); \
- return sprintf(buf, "%d\n", FAN_FROM_REG(data->value)); \
+static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct lm63_data *data = lm63_update_device(dev);
+ return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[attr->index]));
}
-show_fan(fan1_input);
-show_fan(fan1_low);
-static ssize_t set_fan1_low(struct device *dev, struct device_attribute *attr, const char *buf,
- size_t count)
+static ssize_t set_fan(struct device *dev, struct device_attribute *dummy,
+ const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct lm63_data *data = i2c_get_clientdata(client);
unsigned long val = simple_strtoul(buf, NULL, 10);
down(&data->update_lock);
- data->fan1_low = FAN_TO_REG(val);
+ data->fan[1] = FAN_TO_REG(val);
i2c_smbus_write_byte_data(client, LM63_REG_TACH_LIMIT_LSB,
- data->fan1_low & 0xFF);
+ data->fan[1] & 0xFF);
i2c_smbus_write_byte_data(client, LM63_REG_TACH_LIMIT_MSB,
- data->fan1_low >> 8);
+ data->fan[1] >> 8);
up(&data->update_lock);
return count;
}
-static ssize_t show_pwm1(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_pwm1(struct device *dev, struct device_attribute *dummy,
+ char *buf)
{
struct lm63_data *data = lm63_update_device(dev);
return sprintf(buf, "%d\n", data->pwm1_value >= 2 * data->pwm1_freq ?
(2 * data->pwm1_freq));
}
-static ssize_t set_pwm1(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t set_pwm1(struct device *dev, struct device_attribute *dummy,
+ const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct lm63_data *data = i2c_get_clientdata(client);
return count;
}
-static ssize_t show_pwm1_enable(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_pwm1_enable(struct device *dev, struct device_attribute *dummy,
+ char *buf)
{
struct lm63_data *data = lm63_update_device(dev);
return sprintf(buf, "%d\n", data->config_fan & 0x20 ? 1 : 2);
}
-#define show_temp8(value) \
-static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct lm63_data *data = lm63_update_device(dev); \
- return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->value)); \
+static ssize_t show_temp8(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct lm63_data *data = lm63_update_device(dev);
+ return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp8[attr->index]));
}
-#define show_temp11(value) \
-static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct lm63_data *data = lm63_update_device(dev); \
- return sprintf(buf, "%d\n", TEMP11_FROM_REG(data->value)); \
+
+static ssize_t set_temp8(struct device *dev, struct device_attribute *dummy,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm63_data *data = i2c_get_clientdata(client);
+ long val = simple_strtol(buf, NULL, 10);
+
+ down(&data->update_lock);
+ data->temp8[1] = TEMP8_TO_REG(val);
+ i2c_smbus_write_byte_data(client, LM63_REG_LOCAL_HIGH, data->temp8[1]);
+ up(&data->update_lock);
+ return count;
}
-show_temp8(temp1_input);
-show_temp8(temp1_high);
-show_temp11(temp2_input);
-show_temp11(temp2_high);
-show_temp11(temp2_low);
-show_temp8(temp2_crit);
-
-#define set_temp8(value, reg) \
-static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, \
- size_t count) \
-{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct lm63_data *data = i2c_get_clientdata(client); \
- long val = simple_strtol(buf, NULL, 10); \
- \
- down(&data->update_lock); \
- data->value = TEMP8_TO_REG(val); \
- i2c_smbus_write_byte_data(client, reg, data->value); \
- up(&data->update_lock); \
- return count; \
+
+static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct lm63_data *data = lm63_update_device(dev);
+ return sprintf(buf, "%d\n", TEMP11_FROM_REG(data->temp11[attr->index]));
}
-#define set_temp11(value, reg_msb, reg_lsb) \
-static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, \
- size_t count) \
-{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct lm63_data *data = i2c_get_clientdata(client); \
- long val = simple_strtol(buf, NULL, 10); \
- \
- down(&data->update_lock); \
- data->value = TEMP11_TO_REG(val); \
- i2c_smbus_write_byte_data(client, reg_msb, data->value >> 8); \
- i2c_smbus_write_byte_data(client, reg_lsb, data->value & 0xff); \
- up(&data->update_lock); \
- return count; \
+
+static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ static const u8 reg[4] = {
+ LM63_REG_REMOTE_LOW_MSB,
+ LM63_REG_REMOTE_LOW_LSB,
+ LM63_REG_REMOTE_HIGH_MSB,
+ LM63_REG_REMOTE_HIGH_LSB,
+ };
+
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm63_data *data = i2c_get_clientdata(client);
+ long val = simple_strtol(buf, NULL, 10);
+ int nr = attr->index;
+
+ down(&data->update_lock);
+ data->temp11[nr] = TEMP11_TO_REG(val);
+ i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2],
+ data->temp11[nr] >> 8);
+ i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2 + 1],
+ data->temp11[nr] & 0xff);
+ up(&data->update_lock);
+ return count;
}
-set_temp8(temp1_high, LM63_REG_LOCAL_HIGH);
-set_temp11(temp2_high, LM63_REG_REMOTE_HIGH_MSB, LM63_REG_REMOTE_HIGH_LSB);
-set_temp11(temp2_low, LM63_REG_REMOTE_LOW_MSB, LM63_REG_REMOTE_LOW_LSB);
/* Hysteresis register holds a relative value, while we want to present
an absolute to user-space */
-static ssize_t show_temp2_crit_hyst(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_temp2_crit_hyst(struct device *dev, struct device_attribute *dummy,
+ char *buf)
{
struct lm63_data *data = lm63_update_device(dev);
- return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp2_crit)
+ return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp8[2])
- TEMP8_FROM_REG(data->temp2_crit_hyst));
}
/* And now the other way around, user-space provides an absolute
hysteresis value and we have to store a relative one */
-static ssize_t set_temp2_crit_hyst(struct device *dev, struct device_attribute *attr, const char *buf,
- size_t count)
+static ssize_t set_temp2_crit_hyst(struct device *dev, struct device_attribute *dummy,
+ const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct lm63_data *data = i2c_get_clientdata(client);
long hyst;
down(&data->update_lock);
- hyst = TEMP8_FROM_REG(data->temp2_crit) - val;
+ hyst = TEMP8_FROM_REG(data->temp8[2]) - val;
i2c_smbus_write_byte_data(client, LM63_REG_REMOTE_TCRIT_HYST,
HYST_TO_REG(hyst));
up(&data->update_lock);
return count;
}
-static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy,
+ char *buf)
{
struct lm63_data *data = lm63_update_device(dev);
return sprintf(buf, "%u\n", data->alarms);
}
-static DEVICE_ATTR(fan1_input, S_IRUGO, show_fan1_input, NULL);
-static DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan1_low,
- set_fan1_low);
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan,
+ set_fan, 1);
static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm1, set_pwm1);
static DEVICE_ATTR(pwm1_enable, S_IRUGO, show_pwm1_enable, NULL);
-static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp1_input, NULL);
-static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp1_high,
- set_temp1_high);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp8, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp8,
+ set_temp8, 1);
-static DEVICE_ATTR(temp2_input, S_IRUGO, show_temp2_input, NULL);
-static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp2_low,
- set_temp2_low);
-static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp2_high,
- set_temp2_high);
-static DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp2_crit, NULL);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp11,
+ set_temp11, 1);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp11,
+ set_temp11, 2);
+static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp8, NULL, 2);
static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp2_crit_hyst,
set_temp2_crit_hyst);
/* Register sysfs hooks */
if (data->config & 0x04) { /* tachometer enabled */
- device_create_file(&new_client->dev, &dev_attr_fan1_input);
- device_create_file(&new_client->dev, &dev_attr_fan1_min);
+ device_create_file(&new_client->dev,
+ &sensor_dev_attr_fan1_input.dev_attr);
+ device_create_file(&new_client->dev,
+ &sensor_dev_attr_fan1_min.dev_attr);
}
device_create_file(&new_client->dev, &dev_attr_pwm1);
device_create_file(&new_client->dev, &dev_attr_pwm1_enable);
- device_create_file(&new_client->dev, &dev_attr_temp1_input);
- device_create_file(&new_client->dev, &dev_attr_temp2_input);
- device_create_file(&new_client->dev, &dev_attr_temp2_min);
- device_create_file(&new_client->dev, &dev_attr_temp1_max);
- device_create_file(&new_client->dev, &dev_attr_temp2_max);
- device_create_file(&new_client->dev, &dev_attr_temp2_crit);
+ device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp1_input.dev_attr);
+ device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp2_input.dev_attr);
+ device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp2_min.dev_attr);
+ device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp1_max.dev_attr);
+ device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp2_max.dev_attr);
+ device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp2_crit.dev_attr);
device_create_file(&new_client->dev, &dev_attr_temp2_crit_hyst);
device_create_file(&new_client->dev, &dev_attr_alarms);
if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
if (data->config & 0x04) { /* tachometer enabled */
/* order matters for fan1_input */
- data->fan1_input = i2c_smbus_read_byte_data(client,
- LM63_REG_TACH_COUNT_LSB) & 0xFC;
- data->fan1_input |= i2c_smbus_read_byte_data(client,
- LM63_REG_TACH_COUNT_MSB) << 8;
- data->fan1_low = (i2c_smbus_read_byte_data(client,
- LM63_REG_TACH_LIMIT_LSB) & 0xFC)
- | (i2c_smbus_read_byte_data(client,
- LM63_REG_TACH_LIMIT_MSB) << 8);
+ data->fan[0] = i2c_smbus_read_byte_data(client,
+ LM63_REG_TACH_COUNT_LSB) & 0xFC;
+ data->fan[0] |= i2c_smbus_read_byte_data(client,
+ LM63_REG_TACH_COUNT_MSB) << 8;
+ data->fan[1] = (i2c_smbus_read_byte_data(client,
+ LM63_REG_TACH_LIMIT_LSB) & 0xFC)
+ | (i2c_smbus_read_byte_data(client,
+ LM63_REG_TACH_LIMIT_MSB) << 8);
}
data->pwm1_freq = i2c_smbus_read_byte_data(client,
data->pwm1_value = i2c_smbus_read_byte_data(client,
LM63_REG_PWM_VALUE);
- data->temp1_input = i2c_smbus_read_byte_data(client,
- LM63_REG_LOCAL_TEMP);
- data->temp1_high = i2c_smbus_read_byte_data(client,
- LM63_REG_LOCAL_HIGH);
+ data->temp8[0] = i2c_smbus_read_byte_data(client,
+ LM63_REG_LOCAL_TEMP);
+ data->temp8[1] = i2c_smbus_read_byte_data(client,
+ LM63_REG_LOCAL_HIGH);
/* order matters for temp2_input */
- data->temp2_input = i2c_smbus_read_byte_data(client,
- LM63_REG_REMOTE_TEMP_MSB) << 8;
- data->temp2_input |= i2c_smbus_read_byte_data(client,
- LM63_REG_REMOTE_TEMP_LSB);
- data->temp2_high = (i2c_smbus_read_byte_data(client,
- LM63_REG_REMOTE_HIGH_MSB) << 8)
- | i2c_smbus_read_byte_data(client,
- LM63_REG_REMOTE_HIGH_LSB);
- data->temp2_low = (i2c_smbus_read_byte_data(client,
+ data->temp11[0] = i2c_smbus_read_byte_data(client,
+ LM63_REG_REMOTE_TEMP_MSB) << 8;
+ data->temp11[0] |= i2c_smbus_read_byte_data(client,
+ LM63_REG_REMOTE_TEMP_LSB);
+ data->temp11[1] = (i2c_smbus_read_byte_data(client,
LM63_REG_REMOTE_LOW_MSB) << 8)
| i2c_smbus_read_byte_data(client,
LM63_REG_REMOTE_LOW_LSB);
- data->temp2_crit = i2c_smbus_read_byte_data(client,
- LM63_REG_REMOTE_TCRIT);
+ data->temp11[2] = (i2c_smbus_read_byte_data(client,
+ LM63_REG_REMOTE_HIGH_MSB) << 8)
+ | i2c_smbus_read_byte_data(client,
+ LM63_REG_REMOTE_HIGH_LSB);
+ data->temp8[2] = i2c_smbus_read_byte_data(client,
+ LM63_REG_REMOTE_TCRIT);
data->temp2_crit_hyst = i2c_smbus_read_byte_data(client,
LM63_REG_REMOTE_TCRIT_HYST);
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
return 0;
}
-/* The SMBus locks itself, but ISA access must be locked explicitely!
+/* The SMBus locks itself, but ISA access must be locked explicitly!
We don't want to lock the whole ISA bus, so we lock each client
separately.
We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks,
return i2c_smbus_read_byte_data(client, reg);
}
-/* The SMBus locks itself, but ISA access muse be locked explicitely!
+/* The SMBus locks itself, but ISA access muse be locked explicitly!
We don't want to lock the whole ISA bus, so we lock each client
separately.
We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks,
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
/*
* lm83.c - Part of lm_sensors, Linux kernel modules for hardware
* monitoring
- * Copyright (C) 2003 Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2003-2005 Jean Delvare <khali@linux-fr.org>
*
* Heavily inspired from the lm78, lm75 and adm1021 drivers. The LM83 is
* a sensor chip made by National Semiconductor. It reports up to four
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/i2c-sensor.h>
+#include <linux/hwmon-sysfs.h>
/*
* Addresses to scan
/*
* Conversions and various macros
- * The LM83 uses signed 8-bit values with LSB = 1 degree Celcius.
+ * The LM83 uses signed 8-bit values with LSB = 1 degree Celsius.
*/
#define TEMP_FROM_REG(val) ((val) * 1000)
LM83_REG_R_LOCAL_TEMP,
LM83_REG_R_REMOTE1_TEMP,
LM83_REG_R_REMOTE2_TEMP,
- LM83_REG_R_REMOTE3_TEMP
-};
-
-static const u8 LM83_REG_R_HIGH[] = {
+ LM83_REG_R_REMOTE3_TEMP,
LM83_REG_R_LOCAL_HIGH,
LM83_REG_R_REMOTE1_HIGH,
LM83_REG_R_REMOTE2_HIGH,
- LM83_REG_R_REMOTE3_HIGH
+ LM83_REG_R_REMOTE3_HIGH,
+ LM83_REG_R_TCRIT,
};
static const u8 LM83_REG_W_HIGH[] = {
LM83_REG_W_LOCAL_HIGH,
LM83_REG_W_REMOTE1_HIGH,
LM83_REG_W_REMOTE2_HIGH,
- LM83_REG_W_REMOTE3_HIGH
+ LM83_REG_W_REMOTE3_HIGH,
+ LM83_REG_W_TCRIT,
};
/*
unsigned long last_updated; /* in jiffies */
/* registers values */
- s8 temp_input[4];
- s8 temp_high[4];
- s8 temp_crit;
+ s8 temp[9]; /* 0..3: input 1-4,
+ 4..7: high limit 1-4,
+ 8 : critical limit */
u16 alarms; /* bitvector, combined */
};
* Sysfs stuff
*/
-#define show_temp(suffix, value) \
-static ssize_t show_temp_##suffix(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct lm83_data *data = lm83_update_device(dev); \
- return sprintf(buf, "%d\n", TEMP_FROM_REG(data->value)); \
+static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct lm83_data *data = lm83_update_device(dev);
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index]));
}
-show_temp(input1, temp_input[0]);
-show_temp(input2, temp_input[1]);
-show_temp(input3, temp_input[2]);
-show_temp(input4, temp_input[3]);
-show_temp(high1, temp_high[0]);
-show_temp(high2, temp_high[1]);
-show_temp(high3, temp_high[2]);
-show_temp(high4, temp_high[3]);
-show_temp(crit, temp_crit);
-
-#define set_temp(suffix, value, reg) \
-static ssize_t set_temp_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \
- size_t count) \
-{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct lm83_data *data = i2c_get_clientdata(client); \
- long val = simple_strtol(buf, NULL, 10); \
- \
- down(&data->update_lock); \
- data->value = TEMP_TO_REG(val); \
- i2c_smbus_write_byte_data(client, reg, data->value); \
- up(&data->update_lock); \
- return count; \
+
+static ssize_t set_temp(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm83_data *data = i2c_get_clientdata(client);
+ long val = simple_strtol(buf, NULL, 10);
+ int nr = attr->index;
+
+ down(&data->update_lock);
+ data->temp[nr] = TEMP_TO_REG(val);
+ i2c_smbus_write_byte_data(client, LM83_REG_W_HIGH[nr - 4],
+ data->temp[nr]);
+ up(&data->update_lock);
+ return count;
}
-set_temp(high1, temp_high[0], LM83_REG_W_LOCAL_HIGH);
-set_temp(high2, temp_high[1], LM83_REG_W_REMOTE1_HIGH);
-set_temp(high3, temp_high[2], LM83_REG_W_REMOTE2_HIGH);
-set_temp(high4, temp_high[3], LM83_REG_W_REMOTE3_HIGH);
-set_temp(crit, temp_crit, LM83_REG_W_TCRIT);
-static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy,
+ char *buf)
{
struct lm83_data *data = lm83_update_device(dev);
return sprintf(buf, "%d\n", data->alarms);
}
-static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL);
-static DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_input2, NULL);
-static DEVICE_ATTR(temp3_input, S_IRUGO, show_temp_input3, NULL);
-static DEVICE_ATTR(temp4_input, S_IRUGO, show_temp_input4, NULL);
-static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_high1,
- set_temp_high1);
-static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_high2,
- set_temp_high2);
-static DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_temp_high3,
- set_temp_high3);
-static DEVICE_ATTR(temp4_max, S_IWUSR | S_IRUGO, show_temp_high4,
- set_temp_high4);
-static DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp_crit, NULL);
-static DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp_crit, NULL);
-static DEVICE_ATTR(temp3_crit, S_IWUSR | S_IRUGO, show_temp_crit,
- set_temp_crit);
-static DEVICE_ATTR(temp4_crit, S_IRUGO, show_temp_crit, NULL);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp,
+ set_temp, 4);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp,
+ set_temp, 5);
+static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_temp,
+ set_temp, 6);
+static SENSOR_DEVICE_ATTR(temp4_max, S_IWUSR | S_IRUGO, show_temp,
+ set_temp, 7);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp, NULL, 8);
+static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp, NULL, 8);
+static SENSOR_DEVICE_ATTR(temp3_crit, S_IWUSR | S_IRUGO, show_temp,
+ set_temp, 8);
+static SENSOR_DEVICE_ATTR(temp4_crit, S_IRUGO, show_temp, NULL, 8);
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
/*
*/
/* Register sysfs hooks */
- device_create_file(&new_client->dev, &dev_attr_temp1_input);
- device_create_file(&new_client->dev, &dev_attr_temp2_input);
- device_create_file(&new_client->dev, &dev_attr_temp3_input);
- device_create_file(&new_client->dev, &dev_attr_temp4_input);
- device_create_file(&new_client->dev, &dev_attr_temp1_max);
- device_create_file(&new_client->dev, &dev_attr_temp2_max);
- device_create_file(&new_client->dev, &dev_attr_temp3_max);
- device_create_file(&new_client->dev, &dev_attr_temp4_max);
- device_create_file(&new_client->dev, &dev_attr_temp1_crit);
- device_create_file(&new_client->dev, &dev_attr_temp2_crit);
- device_create_file(&new_client->dev, &dev_attr_temp3_crit);
- device_create_file(&new_client->dev, &dev_attr_temp4_crit);
+ device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp1_input.dev_attr);
+ device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp2_input.dev_attr);
+ device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp3_input.dev_attr);
+ device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp4_input.dev_attr);
+ device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp1_max.dev_attr);
+ device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp2_max.dev_attr);
+ device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp3_max.dev_attr);
+ device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp4_max.dev_attr);
+ device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp1_crit.dev_attr);
+ device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp2_crit.dev_attr);
+ device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp3_crit.dev_attr);
+ device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp4_crit.dev_attr);
device_create_file(&new_client->dev, &dev_attr_alarms);
return 0;
int nr;
dev_dbg(&client->dev, "Updating lm83 data.\n");
- for (nr = 0; nr < 4 ; nr++) {
- data->temp_input[nr] =
+ for (nr = 0; nr < 9; nr++) {
+ data->temp[nr] =
i2c_smbus_read_byte_data(client,
LM83_REG_R_TEMP[nr]);
- data->temp_high[nr] =
- i2c_smbus_read_byte_data(client,
- LM83_REG_R_HIGH[nr]);
}
- data->temp_crit =
- i2c_smbus_read_byte_data(client, LM83_REG_R_TCRIT);
data->alarms =
i2c_smbus_read_byte_data(client, LM83_REG_R_STATUS1)
+ (i2c_smbus_read_byte_data(client, LM83_REG_R_STATUS2)
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
/* i2c-vid.h defines vid_from_reg() */
#define VID_FROM_REG(val,vrm) (vid_from_reg((val),(vrm)))
-#define ALARMS_FROM_REG(val) (val)
-
/* Unlike some other drivers we DO NOT set initial limits. Use
* the config file to set limits. Some users have reported
* motherboards shutting down when we set limits in a previous
static ssize_t show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
{
struct lm85_data *data = lm85_update_device(dev);
- return sprintf(buf, "%ld\n", (long) ALARMS_FROM_REG(data->alarms));
+ return sprintf(buf, "%u\n", data->alarms);
}
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
/*
* lm90.c - Part of lm_sensors, Linux kernel modules for hardware
* monitoring
- * Copyright (C) 2003-2004 Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2003-2005 Jean Delvare <khali@linux-fr.org>
*
* Based on the lm83 driver. The LM90 is a sensor chip made by National
* Semiconductor. It reports up to two temperatures (its own plus up to
* Complete datasheets can be obtained from National's website at:
* http://www.national.com/pf/LM/LM89.html
* http://www.national.com/pf/LM/LM99.html
- * Note that there is no way to differenciate between both chips.
+ * Note that there is no way to differentiate between both chips.
*
* This driver also supports the LM86, another sensor chip made by
* National Semiconductor. It is exactly similar to the LM90 except it
* chips made by Maxim. These chips are similar to the LM86. Complete
* datasheet can be obtained at Maxim's website at:
* http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2578
- * Note that there is no easy way to differenciate between the three
+ * Note that there is no easy way to differentiate between the three
* variants. The extra address and features of the MAX6659 are not
* supported by this driver.
*
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/i2c-sensor.h>
+#include <linux/hwmon-sysfs.h>
/*
* Addresses to scan
/*
* Conversions and various macros
* For local temperatures and limits, critical limits and the hysteresis
- * value, the LM90 uses signed 8-bit values with LSB = 1 degree Celcius.
+ * value, the LM90 uses signed 8-bit values with LSB = 1 degree Celsius.
* For remote temperatures and limits, it uses signed 11-bit values with
- * LSB = 0.125 degree Celcius, left-justified in 16-bit registers.
+ * LSB = 0.125 degree Celsius, left-justified in 16-bit registers.
*/
#define TEMP1_FROM_REG(val) ((val) * 1000)
int kind;
/* registers values */
- s8 temp_input1, temp_low1, temp_high1; /* local */
- s16 temp_input2, temp_low2, temp_high2; /* remote, combined */
- s8 temp_crit1, temp_crit2;
+ s8 temp8[5]; /* 0: local input
+ 1: local low limit
+ 2: local high limit
+ 3: local critical limit
+ 4: remote critical limit */
+ s16 temp11[3]; /* 0: remote input
+ 1: remote low limit
+ 2: remote high limit */
u8 temp_hyst;
u8 alarms; /* bitvector */
};
* Sysfs stuff
*/
-#define show_temp(value, converter) \
-static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct lm90_data *data = lm90_update_device(dev); \
- return sprintf(buf, "%d\n", converter(data->value)); \
+static ssize_t show_temp8(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct lm90_data *data = lm90_update_device(dev);
+ return sprintf(buf, "%d\n", TEMP1_FROM_REG(data->temp8[attr->index]));
+}
+
+static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ static const u8 reg[4] = {
+ LM90_REG_W_LOCAL_LOW,
+ LM90_REG_W_LOCAL_HIGH,
+ LM90_REG_W_LOCAL_CRIT,
+ LM90_REG_W_REMOTE_CRIT,
+ };
+
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm90_data *data = i2c_get_clientdata(client);
+ long val = simple_strtol(buf, NULL, 10);
+ int nr = attr->index;
+
+ down(&data->update_lock);
+ if (data->kind == adt7461)
+ data->temp8[nr] = TEMP1_TO_REG_ADT7461(val);
+ else
+ data->temp8[nr] = TEMP1_TO_REG(val);
+ i2c_smbus_write_byte_data(client, reg[nr - 1], data->temp8[nr]);
+ up(&data->update_lock);
+ return count;
}
-show_temp(temp_input1, TEMP1_FROM_REG);
-show_temp(temp_input2, TEMP2_FROM_REG);
-show_temp(temp_low1, TEMP1_FROM_REG);
-show_temp(temp_low2, TEMP2_FROM_REG);
-show_temp(temp_high1, TEMP1_FROM_REG);
-show_temp(temp_high2, TEMP2_FROM_REG);
-show_temp(temp_crit1, TEMP1_FROM_REG);
-show_temp(temp_crit2, TEMP1_FROM_REG);
-
-#define set_temp1(value, reg) \
-static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, \
- size_t count) \
-{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct lm90_data *data = i2c_get_clientdata(client); \
- long val = simple_strtol(buf, NULL, 10); \
- \
- down(&data->update_lock); \
- if (data->kind == adt7461) \
- data->value = TEMP1_TO_REG_ADT7461(val); \
- else \
- data->value = TEMP1_TO_REG(val); \
- i2c_smbus_write_byte_data(client, reg, data->value); \
- up(&data->update_lock); \
- return count; \
+
+static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct lm90_data *data = lm90_update_device(dev);
+ return sprintf(buf, "%d\n", TEMP2_FROM_REG(data->temp11[attr->index]));
}
-#define set_temp2(value, regh, regl) \
-static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, \
- size_t count) \
-{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct lm90_data *data = i2c_get_clientdata(client); \
- long val = simple_strtol(buf, NULL, 10); \
- \
- down(&data->update_lock); \
- if (data->kind == adt7461) \
- data->value = TEMP2_TO_REG_ADT7461(val); \
- else \
- data->value = TEMP2_TO_REG(val); \
- i2c_smbus_write_byte_data(client, regh, data->value >> 8); \
- i2c_smbus_write_byte_data(client, regl, data->value & 0xff); \
- up(&data->update_lock); \
- return count; \
+
+static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ static const u8 reg[4] = {
+ LM90_REG_W_REMOTE_LOWH,
+ LM90_REG_W_REMOTE_LOWL,
+ LM90_REG_W_REMOTE_HIGHH,
+ LM90_REG_W_REMOTE_HIGHL,
+ };
+
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm90_data *data = i2c_get_clientdata(client);
+ long val = simple_strtol(buf, NULL, 10);
+ int nr = attr->index;
+
+ down(&data->update_lock);
+ if (data->kind == adt7461)
+ data->temp11[nr] = TEMP2_TO_REG_ADT7461(val);
+ else
+ data->temp11[nr] = TEMP2_TO_REG(val);
+ i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2],
+ data->temp11[nr] >> 8);
+ i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2 + 1],
+ data->temp11[nr] & 0xff);
+ up(&data->update_lock);
+ return count;
}
-set_temp1(temp_low1, LM90_REG_W_LOCAL_LOW);
-set_temp2(temp_low2, LM90_REG_W_REMOTE_LOWH, LM90_REG_W_REMOTE_LOWL);
-set_temp1(temp_high1, LM90_REG_W_LOCAL_HIGH);
-set_temp2(temp_high2, LM90_REG_W_REMOTE_HIGHH, LM90_REG_W_REMOTE_HIGHL);
-set_temp1(temp_crit1, LM90_REG_W_LOCAL_CRIT);
-set_temp1(temp_crit2, LM90_REG_W_REMOTE_CRIT);
-
-#define show_temp_hyst(value, basereg) \
-static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct lm90_data *data = lm90_update_device(dev); \
- return sprintf(buf, "%d\n", TEMP1_FROM_REG(data->basereg) \
- - TEMP1_FROM_REG(data->temp_hyst)); \
+
+static ssize_t show_temphyst(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct lm90_data *data = lm90_update_device(dev);
+ return sprintf(buf, "%d\n", TEMP1_FROM_REG(data->temp8[attr->index])
+ - TEMP1_FROM_REG(data->temp_hyst));
}
-show_temp_hyst(temp_hyst1, temp_crit1);
-show_temp_hyst(temp_hyst2, temp_crit2);
-static ssize_t set_temp_hyst1(struct device *dev, struct device_attribute *attr, const char *buf,
- size_t count)
+static ssize_t set_temphyst(struct device *dev, struct device_attribute *dummy,
+ const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct lm90_data *data = i2c_get_clientdata(client);
long hyst;
down(&data->update_lock);
- hyst = TEMP1_FROM_REG(data->temp_crit1) - val;
+ hyst = TEMP1_FROM_REG(data->temp8[3]) - val;
i2c_smbus_write_byte_data(client, LM90_REG_W_TCRIT_HYST,
HYST_TO_REG(hyst));
up(&data->update_lock);
return count;
}
-static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy,
+ char *buf)
{
struct lm90_data *data = lm90_update_device(dev);
return sprintf(buf, "%d\n", data->alarms);
}
-static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL);
-static DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_input2, NULL);
-static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_low1,
- set_temp_low1);
-static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp_low2,
- set_temp_low2);
-static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_high1,
- set_temp_high1);
-static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_high2,
- set_temp_high2);
-static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp_crit1,
- set_temp_crit1);
-static DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp_crit2,
- set_temp_crit2);
-static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp_hyst1,
- set_temp_hyst1);
-static DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temp_hyst2, NULL);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp8, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp8,
+ set_temp8, 1);
+static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp11,
+ set_temp11, 1);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp8,
+ set_temp8, 2);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp11,
+ set_temp11, 2);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp8,
+ set_temp8, 3);
+static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp8,
+ set_temp8, 4);
+static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temphyst,
+ set_temphyst, 3);
+static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temphyst, NULL, 4);
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
/*
lm90_init_client(new_client);
/* Register sysfs hooks */
- device_create_file(&new_client->dev, &dev_attr_temp1_input);
- device_create_file(&new_client->dev, &dev_attr_temp2_input);
- device_create_file(&new_client->dev, &dev_attr_temp1_min);
- device_create_file(&new_client->dev, &dev_attr_temp2_min);
- device_create_file(&new_client->dev, &dev_attr_temp1_max);
- device_create_file(&new_client->dev, &dev_attr_temp2_max);
- device_create_file(&new_client->dev, &dev_attr_temp1_crit);
- device_create_file(&new_client->dev, &dev_attr_temp2_crit);
- device_create_file(&new_client->dev, &dev_attr_temp1_crit_hyst);
- device_create_file(&new_client->dev, &dev_attr_temp2_crit_hyst);
+ device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp1_input.dev_attr);
+ device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp2_input.dev_attr);
+ device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp1_min.dev_attr);
+ device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp2_min.dev_attr);
+ device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp1_max.dev_attr);
+ device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp2_max.dev_attr);
+ device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp1_crit.dev_attr);
+ device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp2_crit.dev_attr);
+ device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp1_crit_hyst.dev_attr);
+ device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp2_crit_hyst.dev_attr);
device_create_file(&new_client->dev, &dev_attr_alarms);
return 0;
u8 oldh, newh;
dev_dbg(&client->dev, "Updating lm90 data.\n");
- data->temp_input1 = i2c_smbus_read_byte_data(client,
- LM90_REG_R_LOCAL_TEMP);
- data->temp_high1 = i2c_smbus_read_byte_data(client,
- LM90_REG_R_LOCAL_HIGH);
- data->temp_low1 = i2c_smbus_read_byte_data(client,
- LM90_REG_R_LOCAL_LOW);
- data->temp_crit1 = i2c_smbus_read_byte_data(client,
- LM90_REG_R_LOCAL_CRIT);
- data->temp_crit2 = i2c_smbus_read_byte_data(client,
- LM90_REG_R_REMOTE_CRIT);
+ data->temp8[0] = i2c_smbus_read_byte_data(client,
+ LM90_REG_R_LOCAL_TEMP);
+ data->temp8[1] = i2c_smbus_read_byte_data(client,
+ LM90_REG_R_LOCAL_LOW);
+ data->temp8[2] = i2c_smbus_read_byte_data(client,
+ LM90_REG_R_LOCAL_HIGH);
+ data->temp8[3] = i2c_smbus_read_byte_data(client,
+ LM90_REG_R_LOCAL_CRIT);
+ data->temp8[4] = i2c_smbus_read_byte_data(client,
+ LM90_REG_R_REMOTE_CRIT);
data->temp_hyst = i2c_smbus_read_byte_data(client,
LM90_REG_R_TCRIT_HYST);
*/
oldh = i2c_smbus_read_byte_data(client,
LM90_REG_R_REMOTE_TEMPH);
- data->temp_input2 = i2c_smbus_read_byte_data(client,
- LM90_REG_R_REMOTE_TEMPL);
+ data->temp11[0] = i2c_smbus_read_byte_data(client,
+ LM90_REG_R_REMOTE_TEMPL);
newh = i2c_smbus_read_byte_data(client,
LM90_REG_R_REMOTE_TEMPH);
if (newh != oldh) {
- data->temp_input2 = i2c_smbus_read_byte_data(client,
- LM90_REG_R_REMOTE_TEMPL);
+ data->temp11[0] = i2c_smbus_read_byte_data(client,
+ LM90_REG_R_REMOTE_TEMPL);
#ifdef DEBUG
oldh = i2c_smbus_read_byte_data(client,
LM90_REG_R_REMOTE_TEMPH);
"wrong.\n");
#endif
}
- data->temp_input2 |= (newh << 8);
+ data->temp11[0] |= (newh << 8);
- data->temp_high2 = (i2c_smbus_read_byte_data(client,
+ data->temp11[1] = (i2c_smbus_read_byte_data(client,
+ LM90_REG_R_REMOTE_LOWH) << 8) +
+ i2c_smbus_read_byte_data(client,
+ LM90_REG_R_REMOTE_LOWL);
+ data->temp11[2] = (i2c_smbus_read_byte_data(client,
LM90_REG_R_REMOTE_HIGHH) << 8) +
i2c_smbus_read_byte_data(client,
LM90_REG_R_REMOTE_HIGHL);
- data->temp_low2 = (i2c_smbus_read_byte_data(client,
- LM90_REG_R_REMOTE_LOWH) << 8) +
- i2c_smbus_read_byte_data(client,
- LM90_REG_R_REMOTE_LOWL);
data->alarms = i2c_smbus_read_byte_data(client,
LM90_REG_R_STATUS);
static struct i2c_client_address_data addr_data = {
.normal_i2c = normal_addr,
- .normal_i2c_range = ignore,
.probe = ignore,
- .probe_range = ignore,
.ignore = ignore,
- .ignore_range = ignore,
.force = ignore,
};
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
--- /dev/null
+/*
+ max6875.c - driver for MAX6874/MAX6875
+
+ Copyright (C) 2005 Ben Gardner <bgardner@wabtec.com>
+
+ Based on i2c/chips/eeprom.c
+
+ The MAX6875 has two EEPROM sections: config and user.
+ At reset, the config EEPROM is read into the registers.
+
+ This driver make 3 binary files available in sysfs:
+ reg_config - direct access to the registers
+ eeprom_config - acesses configuration eeprom space
+ eeprom_user - free for application use
+
+ In our application, we put device serial & model numbers in user eeprom.
+
+ Notes:
+ 1) The datasheet says that register 0x44 / EEPROM 0x8044 should NOT
+ be overwritten, so the driver explicitly prevents that.
+ 2) It's a good idea to keep the config (0x45) locked in config EEPROM.
+ You can temporarily enable config writes by changing register 0x45.
+
+ 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; version 2 of the License.
+*/
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/i2c-sensor.h>
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = {0x50, 0x52, I2C_CLIENT_END};
+static unsigned int normal_isa[] = {I2C_CLIENT_ISA_END};
+
+/* Insmod parameters */
+SENSORS_INSMOD_1(max6875);
+
+/* this param will prevent 'accidental' writes to the eeprom */
+static int allow_write = 0;
+module_param(allow_write, int, 0);
+MODULE_PARM_DESC(allow_write,
+ "Enable write access:\n"
+ "*0: Read only\n"
+ " 1: Read/Write access");
+
+/* The MAX6875 can only read/write 16 bytes at a time */
+#define SLICE_SIZE 16
+#define SLICE_BITS 4
+
+/* CONFIG EEPROM is at addresses 0x8000 - 0x8045, registers are at 0 - 0x45 */
+#define CONFIG_EEPROM_BASE 0x8000
+#define CONFIG_EEPROM_SIZE 0x0046
+#define CONFIG_EEPROM_SLICES 5
+
+/* USER EEPROM is at addresses 0x8100 - 0x82FF */
+#define USER_EEPROM_BASE 0x8100
+#define USER_EEPROM_SIZE 0x0200
+#define USER_EEPROM_SLICES 32
+
+/* MAX6875 commands */
+#define MAX6875_CMD_BLOCK_WRITE 0x83
+#define MAX6875_CMD_BLOCK_READ 0x84
+#define MAX6875_CMD_REBOOT 0x88
+
+enum max6875_area_type {
+ max6875_register_config=0,
+ max6875_eeprom_config,
+ max6875_eeprom_user,
+ max6857_max
+};
+
+struct eeprom_block {
+ enum max6875_area_type type;
+ u8 slices;
+ u32 size;
+ u32 valid;
+ u32 base;
+ unsigned long *updated;
+ u8 *data;
+};
+
+/* Each client has this additional data */
+struct max6875_data {
+ struct i2c_client client;
+ struct semaphore update_lock;
+ struct eeprom_block blocks[max6857_max];
+ /* the above structs point into the arrays below */
+ u8 data[USER_EEPROM_SIZE + (CONFIG_EEPROM_SIZE*2)];
+ unsigned long last_updated[USER_EEPROM_SLICES + (CONFIG_EEPROM_SLICES*2)];
+};
+
+static int max6875_attach_adapter(struct i2c_adapter *adapter);
+static int max6875_detect(struct i2c_adapter *adapter, int address, int kind);
+static int max6875_detach_client(struct i2c_client *client);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver max6875_driver = {
+ .owner = THIS_MODULE,
+ .name = "max6875",
+ .flags = I2C_DF_NOTIFY,
+ .attach_adapter = max6875_attach_adapter,
+ .detach_client = max6875_detach_client,
+};
+
+static int max6875_update_slice(struct i2c_client *client,
+ struct eeprom_block *blk,
+ int slice)
+{
+ struct max6875_data *data = i2c_get_clientdata(client);
+ int i, j, addr, count;
+ u8 rdbuf[SLICE_SIZE];
+ int retval = 0;
+
+ if (slice >= blk->slices)
+ return -1;
+
+ down(&data->update_lock);
+
+ if (!(blk->valid & (1 << slice)) ||
+ (jiffies - blk->updated[slice] > 300 * HZ) ||
+ (jiffies < blk->updated[slice])) {
+ dev_dbg(&client->dev, "Starting eeprom update, slice %u, base %u\n",
+ slice, blk->base);
+
+ addr = blk->base + (slice << SLICE_BITS);
+ count = blk->size - (slice << SLICE_BITS);
+ if (count > SLICE_SIZE) {
+ count = SLICE_SIZE;
+ }
+
+ /* Preset the read address */
+ if (addr < 0x100) {
+ /* select the register */
+ if (i2c_smbus_write_byte(client, addr & 0xFF)) {
+ dev_dbg(&client->dev, "max6875 register select has failed!\n");
+ retval = -1;
+ goto exit;
+ }
+ } else {
+ /* select the eeprom */
+ if (i2c_smbus_write_byte_data(client, addr >> 8, addr & 0xFF)) {
+ dev_dbg(&client->dev, "max6875 address set has failed!\n");
+ retval = -1;
+ goto exit;
+ }
+ }
+
+ if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
+ if (i2c_smbus_read_i2c_block_data(client, MAX6875_CMD_BLOCK_READ,
+ rdbuf) != SLICE_SIZE)
+ {
+ retval = -1;
+ goto exit;
+ }
+
+ memcpy(&blk->data[slice << SLICE_BITS], rdbuf, count);
+ } else {
+ for (i = 0; i < count; i++) {
+ j = i2c_smbus_read_byte(client);
+ if (j < 0)
+ {
+ retval = -1;
+ goto exit;
+ }
+ blk->data[(slice << SLICE_BITS) + i] = (u8) j;
+ }
+ }
+ blk->updated[slice] = jiffies;
+ blk->valid |= (1 << slice);
+ }
+ exit:
+ up(&data->update_lock);
+ return retval;
+}
+
+static ssize_t max6875_read(struct kobject *kobj, char *buf, loff_t off, size_t count,
+ enum max6875_area_type area_type)
+{
+ struct i2c_client *client = to_i2c_client(container_of(kobj, struct device, kobj));
+ struct max6875_data *data = i2c_get_clientdata(client);
+ struct eeprom_block *blk;
+ int slice;
+
+ blk = &data->blocks[area_type];
+
+ if (off > blk->size)
+ return 0;
+ if (off + count > blk->size)
+ count = blk->size - off;
+
+ /* Only refresh slices which contain requested bytes */
+ for (slice = (off >> SLICE_BITS); slice <= ((off + count - 1) >> SLICE_BITS); slice++)
+ max6875_update_slice(client, blk, slice);
+
+ memcpy(buf, &blk->data[off], count);
+
+ return count;
+}
+
+static ssize_t max6875_user_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
+{
+ return max6875_read(kobj, buf, off, count, max6875_eeprom_user);
+}
+
+static ssize_t max6875_config_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
+{
+ return max6875_read(kobj, buf, off, count, max6875_eeprom_config);
+}
+
+static ssize_t max6875_cfgreg_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
+{
+ return max6875_read(kobj, buf, off, count, max6875_register_config);
+}
+
+
+static ssize_t max6875_write(struct kobject *kobj, char *buf, loff_t off, size_t count,
+ enum max6875_area_type area_type)
+{
+ struct i2c_client *client = to_i2c_client(container_of(kobj, struct device, kobj));
+ struct max6875_data *data = i2c_get_clientdata(client);
+ struct eeprom_block *blk;
+ int slice, addr, retval;
+ ssize_t sent = 0;
+
+ blk = &data->blocks[area_type];
+
+ if (off > blk->size)
+ return 0;
+ if ((off + count) > blk->size)
+ count = blk->size - off;
+
+ if (down_interruptible(&data->update_lock))
+ return -EAGAIN;
+
+ /* writing to a register is done with i2c_smbus_write_byte_data() */
+ if (blk->type == max6875_register_config) {
+ for (sent = 0; sent < count; sent++) {
+ addr = off + sent;
+ if (addr == 0x44)
+ continue;
+
+ retval = i2c_smbus_write_byte_data(client, addr, buf[sent]);
+ }
+ } else {
+ int cmd, val;
+
+ /* We are writing to EEPROM */
+ for (sent = 0; sent < count; sent++) {
+ addr = blk->base + off + sent;
+ cmd = addr >> 8;
+ val = (addr & 0xff) | (buf[sent] << 8); // reversed
+
+ if (addr == 0x8044)
+ continue;
+
+ retval = i2c_smbus_write_word_data(client, cmd, val);
+
+ if (retval) {
+ goto error_exit;
+ }
+
+ /* A write takes up to 11 ms */
+ msleep(11);
+ }
+ }
+
+ /* Invalidate the scratch buffer */
+ for (slice = (off >> SLICE_BITS); slice <= ((off + count - 1) >> SLICE_BITS); slice++)
+ blk->valid &= ~(1 << slice);
+
+ error_exit:
+ up(&data->update_lock);
+
+ return sent;
+}
+
+static ssize_t max6875_user_write(struct kobject *kobj, char *buf, loff_t off, size_t count)
+{
+ return max6875_write(kobj, buf, off, count, max6875_eeprom_user);
+}
+
+static ssize_t max6875_config_write(struct kobject *kobj, char *buf, loff_t off, size_t count)
+{
+ return max6875_write(kobj, buf, off, count, max6875_eeprom_config);
+}
+
+static ssize_t max6875_cfgreg_write(struct kobject *kobj, char *buf, loff_t off, size_t count)
+{
+ return max6875_write(kobj, buf, off, count, max6875_register_config);
+}
+
+static struct bin_attribute user_eeprom_attr = {
+ .attr = {
+ .name = "eeprom_user",
+ .mode = S_IRUGO | S_IWUSR | S_IWGRP,
+ .owner = THIS_MODULE,
+ },
+ .size = USER_EEPROM_SIZE,
+ .read = max6875_user_read,
+ .write = max6875_user_write,
+};
+
+static struct bin_attribute config_eeprom_attr = {
+ .attr = {
+ .name = "eeprom_config",
+ .mode = S_IRUGO | S_IWUSR,
+ .owner = THIS_MODULE,
+ },
+ .size = CONFIG_EEPROM_SIZE,
+ .read = max6875_config_read,
+ .write = max6875_config_write,
+};
+
+static struct bin_attribute config_register_attr = {
+ .attr = {
+ .name = "reg_config",
+ .mode = S_IRUGO | S_IWUSR,
+ .owner = THIS_MODULE,
+ },
+ .size = CONFIG_EEPROM_SIZE,
+ .read = max6875_cfgreg_read,
+ .write = max6875_cfgreg_write,
+};
+
+static int max6875_attach_adapter(struct i2c_adapter *adapter)
+{
+ return i2c_detect(adapter, &addr_data, max6875_detect);
+}
+
+/* This function is called by i2c_detect */
+static int max6875_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+ struct i2c_client *new_client;
+ struct max6875_data *data;
+ int err = 0;
+
+ /* There are three ways we can read the EEPROM data:
+ (1) I2C block reads (faster, but unsupported by most adapters)
+ (2) Consecutive byte reads (100% overhead)
+ (3) Regular byte data reads (200% overhead)
+ The third method is not implemented by this driver because all
+ known adapters support at least the second. */
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA |
+ I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
+ goto exit;
+
+ /* OK. For now, we presume we have a valid client. We now create the
+ client structure, even though we cannot fill it completely yet.
+ But it allows us to access eeprom_{read,write}_value. */
+ if (!(data = kmalloc(sizeof(struct max6875_data), GFP_KERNEL))) {
+ err = -ENOMEM;
+ goto exit;
+ }
+ memset(data, 0, sizeof(struct max6875_data));
+
+ new_client = &data->client;
+ i2c_set_clientdata(new_client, data);
+ new_client->addr = address;
+ new_client->adapter = adapter;
+ new_client->driver = &max6875_driver;
+ new_client->flags = 0;
+
+ /* Setup the user section */
+ data->blocks[max6875_eeprom_user].type = max6875_eeprom_user;
+ data->blocks[max6875_eeprom_user].slices = USER_EEPROM_SLICES;
+ data->blocks[max6875_eeprom_user].size = USER_EEPROM_SIZE;
+ data->blocks[max6875_eeprom_user].base = USER_EEPROM_BASE;
+ data->blocks[max6875_eeprom_user].data = data->data;
+ data->blocks[max6875_eeprom_user].updated = data->last_updated;
+
+ /* Setup the config section */
+ data->blocks[max6875_eeprom_config].type = max6875_eeprom_config;
+ data->blocks[max6875_eeprom_config].slices = CONFIG_EEPROM_SLICES;
+ data->blocks[max6875_eeprom_config].size = CONFIG_EEPROM_SIZE;
+ data->blocks[max6875_eeprom_config].base = CONFIG_EEPROM_BASE;
+ data->blocks[max6875_eeprom_config].data = &data->data[USER_EEPROM_SIZE];
+ data->blocks[max6875_eeprom_config].updated = &data->last_updated[USER_EEPROM_SLICES];
+
+ /* Setup the register section */
+ data->blocks[max6875_register_config].type = max6875_register_config;
+ data->blocks[max6875_register_config].slices = CONFIG_EEPROM_SLICES;
+ data->blocks[max6875_register_config].size = CONFIG_EEPROM_SIZE;
+ data->blocks[max6875_register_config].base = 0;
+ data->blocks[max6875_register_config].data = &data->data[USER_EEPROM_SIZE+CONFIG_EEPROM_SIZE];
+ data->blocks[max6875_register_config].updated = &data->last_updated[USER_EEPROM_SLICES+CONFIG_EEPROM_SLICES];
+
+ /* Init the data */
+ memset(data->data, 0xff, sizeof(data->data));
+
+ /* Fill in the remaining client fields */
+ strlcpy(new_client->name, "max6875", I2C_NAME_SIZE);
+ init_MUTEX(&data->update_lock);
+
+ /* Verify that the chip is really what we think it is */
+ if ((max6875_update_slice(new_client, &data->blocks[max6875_eeprom_config], 4) < 0) ||
+ (max6875_update_slice(new_client, &data->blocks[max6875_register_config], 4) < 0))
+ goto exit_kfree;
+
+ /* 0x41,0x42 must be zero and 0x40 must match in eeprom and registers */
+ if ((data->blocks[max6875_eeprom_config].data[0x41] != 0) ||
+ (data->blocks[max6875_eeprom_config].data[0x42] != 0) ||
+ (data->blocks[max6875_register_config].data[0x41] != 0) ||
+ (data->blocks[max6875_register_config].data[0x42] != 0) ||
+ (data->blocks[max6875_eeprom_config].data[0x40] !=
+ data->blocks[max6875_register_config].data[0x40]))
+ goto exit_kfree;
+
+ /* Tell the I2C layer a new client has arrived */
+ if ((err = i2c_attach_client(new_client)))
+ goto exit_kfree;
+
+ /* create the sysfs eeprom files with the correct permissions */
+ if (allow_write == 0) {
+ user_eeprom_attr.attr.mode &= ~S_IWUGO;
+ user_eeprom_attr.write = NULL;
+ config_eeprom_attr.attr.mode &= ~S_IWUGO;
+ config_eeprom_attr.write = NULL;
+ config_register_attr.attr.mode &= ~S_IWUGO;
+ config_register_attr.write = NULL;
+ }
+ sysfs_create_bin_file(&new_client->dev.kobj, &user_eeprom_attr);
+ sysfs_create_bin_file(&new_client->dev.kobj, &config_eeprom_attr);
+ sysfs_create_bin_file(&new_client->dev.kobj, &config_register_attr);
+
+ return 0;
+
+exit_kfree:
+ kfree(data);
+exit:
+ return err;
+}
+
+static int max6875_detach_client(struct i2c_client *client)
+{
+ int err;
+
+ err = i2c_detach_client(client);
+ if (err) {
+ dev_err(&client->dev, "Client deregistration failed, client not detached.\n");
+ return err;
+ }
+
+ kfree(i2c_get_clientdata(client));
+
+ return 0;
+}
+
+static int __init max6875_init(void)
+{
+ return i2c_add_driver(&max6875_driver);
+}
+
+static void __exit max6875_exit(void)
+{
+ i2c_del_driver(&max6875_driver);
+}
+
+
+MODULE_AUTHOR("Ben Gardner <bgardner@wabtec.com>");
+MODULE_DESCRIPTION("MAX6875 driver");
+MODULE_LICENSE("GPL");
+
+module_init(max6875_init);
+module_exit(max6875_exit);
* the standard Super-I/O addresses is used (0x2E/0x2F or 0x4E/0x4F).
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
--- /dev/null
+/*
+ pca9539.c - 16-bit I/O port with interrupt and reset
+
+ Copyright (C) 2005 Ben Gardner <bgardner@wabtec.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; version 2 of the License.
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/i2c-sensor.h>
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = {0x74, 0x75, 0x76, 0x77, I2C_CLIENT_END};
+static unsigned int normal_isa[] = {I2C_CLIENT_ISA_END};
+
+/* Insmod parameters */
+SENSORS_INSMOD_1(pca9539);
+
+enum pca9539_cmd
+{
+ PCA9539_INPUT_0 = 0,
+ PCA9539_INPUT_1 = 1,
+ PCA9539_OUTPUT_0 = 2,
+ PCA9539_OUTPUT_1 = 3,
+ PCA9539_INVERT_0 = 4,
+ PCA9539_INVERT_1 = 5,
+ PCA9539_DIRECTION_0 = 6,
+ PCA9539_DIRECTION_1 = 7,
+};
+
+static int pca9539_attach_adapter(struct i2c_adapter *adapter);
+static int pca9539_detect(struct i2c_adapter *adapter, int address, int kind);
+static int pca9539_detach_client(struct i2c_client *client);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver pca9539_driver = {
+ .owner = THIS_MODULE,
+ .name = "pca9539",
+ .flags = I2C_DF_NOTIFY,
+ .attach_adapter = pca9539_attach_adapter,
+ .detach_client = pca9539_detach_client,
+};
+
+struct pca9539_data {
+ struct i2c_client client;
+};
+
+/* following are the sysfs callback functions */
+static ssize_t pca9539_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute *psa = to_sensor_dev_attr(attr);
+ struct i2c_client *client = to_i2c_client(dev);
+ return sprintf(buf, "%d\n", i2c_smbus_read_byte_data(client,
+ psa->index));
+}
+
+static ssize_t pca9539_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *psa = to_sensor_dev_attr(attr);
+ struct i2c_client *client = to_i2c_client(dev);
+ unsigned long val = simple_strtoul(buf, NULL, 0);
+ if (val > 0xff)
+ return -EINVAL;
+ i2c_smbus_write_byte_data(client, psa->index, val);
+ return count;
+}
+
+/* Define the device attributes */
+
+#define PCA9539_ENTRY_RO(name, cmd_idx) \
+ static SENSOR_DEVICE_ATTR(name, S_IRUGO, pca9539_show, NULL, cmd_idx)
+
+#define PCA9539_ENTRY_RW(name, cmd_idx) \
+ static SENSOR_DEVICE_ATTR(name, S_IRUGO | S_IWUSR, pca9539_show, \
+ pca9539_store, cmd_idx)
+
+PCA9539_ENTRY_RO(input0, PCA9539_INPUT_0);
+PCA9539_ENTRY_RO(input1, PCA9539_INPUT_1);
+PCA9539_ENTRY_RW(output0, PCA9539_OUTPUT_0);
+PCA9539_ENTRY_RW(output1, PCA9539_OUTPUT_1);
+PCA9539_ENTRY_RW(invert0, PCA9539_INVERT_0);
+PCA9539_ENTRY_RW(invert1, PCA9539_INVERT_1);
+PCA9539_ENTRY_RW(direction0, PCA9539_DIRECTION_0);
+PCA9539_ENTRY_RW(direction1, PCA9539_DIRECTION_1);
+
+static struct attribute *pca9539_attributes[] = {
+ &sensor_dev_attr_input0.dev_attr.attr,
+ &sensor_dev_attr_input1.dev_attr.attr,
+ &sensor_dev_attr_output0.dev_attr.attr,
+ &sensor_dev_attr_output1.dev_attr.attr,
+ &sensor_dev_attr_invert0.dev_attr.attr,
+ &sensor_dev_attr_invert1.dev_attr.attr,
+ &sensor_dev_attr_direction0.dev_attr.attr,
+ &sensor_dev_attr_direction1.dev_attr.attr,
+ NULL
+};
+
+static struct attribute_group pca9539_defattr_group = {
+ .attrs = pca9539_attributes,
+};
+
+static int pca9539_attach_adapter(struct i2c_adapter *adapter)
+{
+ return i2c_detect(adapter, &addr_data, pca9539_detect);
+}
+
+/* This function is called by i2c_detect */
+static int pca9539_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+ struct i2c_client *new_client;
+ struct pca9539_data *data;
+ int err = 0;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ goto exit;
+
+ /* OK. For now, we presume we have a valid client. We now create the
+ client structure, even though we cannot fill it completely yet. */
+ if (!(data = kmalloc(sizeof(struct pca9539_data), GFP_KERNEL))) {
+ err = -ENOMEM;
+ goto exit;
+ }
+ memset(data, 0, sizeof(struct pca9539_data));
+
+ new_client = &data->client;
+ i2c_set_clientdata(new_client, data);
+ new_client->addr = address;
+ new_client->adapter = adapter;
+ new_client->driver = &pca9539_driver;
+ new_client->flags = 0;
+
+ /* Detection: the pca9539 only has 8 registers (0-7).
+ A read of 7 should succeed, but a read of 8 should fail. */
+ if ((i2c_smbus_read_byte_data(new_client, 7) < 0) ||
+ (i2c_smbus_read_byte_data(new_client, 8) >= 0))
+ goto exit_kfree;
+
+ strlcpy(new_client->name, "pca9539", I2C_NAME_SIZE);
+
+ /* Tell the I2C layer a new client has arrived */
+ if ((err = i2c_attach_client(new_client)))
+ goto exit_kfree;
+
+ /* Register sysfs hooks (don't care about failure) */
+ sysfs_create_group(&new_client->dev.kobj, &pca9539_defattr_group);
+
+ return 0;
+
+exit_kfree:
+ kfree(data);
+exit:
+ return err;
+}
+
+static int pca9539_detach_client(struct i2c_client *client)
+{
+ int err;
+
+ if ((err = i2c_detach_client(client))) {
+ dev_err(&client->dev, "Client deregistration failed.\n");
+ return err;
+ }
+
+ kfree(i2c_get_clientdata(client));
+ return 0;
+}
+
+static int __init pca9539_init(void)
+{
+ return i2c_add_driver(&pca9539_driver);
+}
+
+static void __exit pca9539_exit(void)
+{
+ i2c_del_driver(&pca9539_driver);
+}
+
+MODULE_AUTHOR("Ben Gardner <bgardner@wabtec.com>");
+MODULE_DESCRIPTION("PCA9539 driver");
+MODULE_LICENSE("GPL");
+
+module_init(pca9539_init);
+module_exit(pca9539_exit);
+
struct pcf8574_data {
struct i2c_client client;
- u8 read, write; /* Register values */
+ u8 write; /* Remember last written value */
};
static int pcf8574_attach_adapter(struct i2c_adapter *adapter);
static ssize_t show_read(struct device *dev, struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
- struct pcf8574_data *data = i2c_get_clientdata(client);
- data->read = i2c_smbus_read_byte(client);
- return sprintf(buf, "%u\n", data->read);
+ return sprintf(buf, "%u\n", i2c_smbus_read_byte(client));
}
static DEVICE_ATTR(read, S_IRUGO, show_read, NULL);
#include <linux/string.h>
#include <linux/rtc.h> /* get the user-level API */
#include <linux/init.h>
-#include <linux/init.h>
#include "rtc8564.h"
static struct i2c_client_address_data addr_data = {
.normal_i2c = normal_addr,
- .normal_i2c_range = ignore,
.probe = ignore,
- .probe_range = ignore,
.ignore = ignore,
- .ignore_range = ignore,
.force = ignore,
};
#include <linux/i2c.h>
#include <linux/i2c-sensor.h>
#include <linux/init.h>
+#include <linux/jiffies.h>
#include <asm/io.h>
* SMSC LPC47M10x/LPC47M13x (device id 0x59), LPC47M14x (device id
* 0x5F) and LPC47B27x (device id 0x51) have fan control.
* The LPC47M15x and LPC47M192 chips "with hardware monitoring block"
- * can do much more besides (device id 0x60, unsupported).
+ * can do much more besides (device id 0x60).
*/
if (val == 0x51)
- printk(KERN_INFO "smsc47m1: Found SMSC47B27x\n");
+ printk(KERN_INFO "smsc47m1: Found SMSC LPC47B27x\n");
else if (val == 0x59)
- printk(KERN_INFO "smsc47m1: Found SMSC47M10x/SMSC47M13x\n");
+ printk(KERN_INFO "smsc47m1: Found SMSC LPC47M10x/LPC47M13x\n");
else if (val == 0x5F)
- printk(KERN_INFO "smsc47m1: Found SMSC47M14x\n");
+ printk(KERN_INFO "smsc47m1: Found SMSC LPC47M14x\n");
+ else if (val == 0x60)
+ printk(KERN_INFO "smsc47m1: Found SMSC LPC47M15x/LPC47M192\n");
else {
superio_exit();
return -ENODEV;
--- /dev/null
+/*
+ * tps65010 - driver for tps6501x power management chips
+ *
+ * Copyright (C) 2004 Texas Instruments
+ * Copyright (C) 2004-2005 David Brownell
+ *
+ * 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.
+ */
+#undef DEBUG
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <linux/suspend.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/tps65010.h>
+
+/*-------------------------------------------------------------------------*/
+
+#define DRIVER_VERSION "2 May 2005"
+#define DRIVER_NAME (tps65010_driver.name)
+
+MODULE_DESCRIPTION("TPS6501x Power Management Driver");
+MODULE_LICENSE("GPL");
+
+/* only two addresses possible */
+#define TPS_BASE 0x48
+static unsigned short normal_i2c[] = {
+ TPS_BASE,
+ I2C_CLIENT_END };
+static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
+
+I2C_CLIENT_INSMOD;
+
+static struct i2c_driver tps65010_driver;
+
+/*-------------------------------------------------------------------------*/
+
+/* This driver handles a family of multipurpose chips, which incorporate
+ * voltage regulators, lithium ion/polymer battery charging, GPIOs, LEDs,
+ * and other features often needed in portable devices like cell phones
+ * or digital cameras.
+ *
+ * The tps65011 and tps65013 have different voltage settings compared
+ * to tps65010 and tps65012. The tps65013 has a NO_CHG status/irq.
+ * All except tps65010 have "wait" mode, possibly defaulted so that
+ * battery-insert != device-on.
+ *
+ * We could distinguish between some models by checking VDCDC1.UVLO or
+ * other registers, unless they've been changed already after powerup
+ * as part of board setup by a bootloader.
+ */
+enum tps_model {
+ TPS_UNKNOWN = 0,
+ TPS65010,
+ TPS65011,
+ TPS65012,
+ TPS65013,
+};
+
+struct tps65010 {
+ struct i2c_client client;
+ struct semaphore lock;
+ int irq;
+ struct work_struct work;
+ struct dentry *file;
+ unsigned charging:1;
+ unsigned por:1;
+ unsigned model:8;
+ u16 vbus;
+ unsigned long flags;
+#define FLAG_VBUS_CHANGED 0
+#define FLAG_IRQ_ENABLE 1
+
+ /* copies of last register state */
+ u8 chgstatus, regstatus, chgconf;
+ u8 nmask1, nmask2;
+
+ /* plus four GPIOs, probably used to switch power */
+};
+
+#define POWER_POLL_DELAY msecs_to_jiffies(800)
+
+/*-------------------------------------------------------------------------*/
+
+#if defined(DEBUG) || defined(CONFIG_DEBUG_FS)
+
+static void dbg_chgstat(char *buf, size_t len, u8 chgstatus)
+{
+ snprintf(buf, len, "%02x%s%s%s%s%s%s%s%s\n",
+ chgstatus,
+ (chgstatus & TPS_CHG_USB) ? " USB" : "",
+ (chgstatus & TPS_CHG_AC) ? " AC" : "",
+ (chgstatus & TPS_CHG_THERM) ? " therm" : "",
+ (chgstatus & TPS_CHG_TERM) ? " done" :
+ ((chgstatus & (TPS_CHG_USB|TPS_CHG_AC))
+ ? " (charging)" : ""),
+ (chgstatus & TPS_CHG_TAPER_TMO) ? " taper_tmo" : "",
+ (chgstatus & TPS_CHG_CHG_TMO) ? " charge_tmo" : "",
+ (chgstatus & TPS_CHG_PRECHG_TMO) ? " prechg_tmo" : "",
+ (chgstatus & TPS_CHG_TEMP_ERR) ? " temp_err" : "");
+}
+
+static void dbg_regstat(char *buf, size_t len, u8 regstatus)
+{
+ snprintf(buf, len, "%02x %s%s%s%s%s%s%s%s\n",
+ regstatus,
+ (regstatus & TPS_REG_ONOFF) ? "off" : "(on)",
+ (regstatus & TPS_REG_COVER) ? " uncover" : "",
+ (regstatus & TPS_REG_UVLO) ? " UVLO" : "",
+ (regstatus & TPS_REG_NO_CHG) ? " NO_CHG" : "",
+ (regstatus & TPS_REG_PG_LD02) ? " ld01_bad" : "",
+ (regstatus & TPS_REG_PG_LD01) ? " ld01_bad" : "",
+ (regstatus & TPS_REG_PG_MAIN) ? " main_bad" : "",
+ (regstatus & TPS_REG_PG_CORE) ? " core_bad" : "");
+}
+
+static void dbg_chgconf(int por, char *buf, size_t len, u8 chgconfig)
+{
+ char *hibit;
+
+ if (por)
+ hibit = (chgconfig & TPS_CHARGE_POR)
+ ? "POR=69ms" : "POR=1sec";
+ else
+ hibit = (chgconfig & TPS65013_AUA) ? "AUA" : "";
+
+ snprintf(buf, len, "%02x %s%s%s AC=%d%% USB=%dmA %sCharge\n",
+ chgconfig, hibit,
+ (chgconfig & TPS_CHARGE_RESET) ? " reset" : "",
+ (chgconfig & TPS_CHARGE_FAST) ? " fast" : "",
+ ({int p; switch ((chgconfig >> 3) & 3) {
+ case 3: p = 100; break;
+ case 2: p = 75; break;
+ case 1: p = 50; break;
+ default: p = 25; break;
+ }; p; }),
+ (chgconfig & TPS_VBUS_CHARGING)
+ ? ((chgconfig & TPS_VBUS_500MA) ? 500 : 100)
+ : 0,
+ (chgconfig & TPS_CHARGE_ENABLE) ? "" : "No");
+}
+
+#endif
+
+#ifdef DEBUG
+
+static void show_chgstatus(const char *label, u8 chgstatus)
+{
+ char buf [100];
+
+ dbg_chgstat(buf, sizeof buf, chgstatus);
+ pr_debug("%s: %s %s", DRIVER_NAME, label, buf);
+}
+
+static void show_regstatus(const char *label, u8 regstatus)
+{
+ char buf [100];
+
+ dbg_regstat(buf, sizeof buf, regstatus);
+ pr_debug("%s: %s %s", DRIVER_NAME, label, buf);
+}
+
+static void show_chgconfig(int por, const char *label, u8 chgconfig)
+{
+ char buf [100];
+
+ dbg_chgconf(por, buf, sizeof buf, chgconfig);
+ pr_debug("%s: %s %s", DRIVER_NAME, label, buf);
+}
+
+#else
+
+static inline void show_chgstatus(const char *label, u8 chgstatus) { }
+static inline void show_regstatus(const char *label, u8 chgstatus) { }
+static inline void show_chgconfig(int por, const char *label, u8 chgconfig) { }
+
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+
+static int dbg_show(struct seq_file *s, void *_)
+{
+ struct tps65010 *tps = s->private;
+ u8 value, v2;
+ unsigned i;
+ char buf[100];
+ const char *chip;
+
+ switch (tps->model) {
+ case TPS65010: chip = "tps65010"; break;
+ case TPS65011: chip = "tps65011"; break;
+ case TPS65012: chip = "tps65012"; break;
+ case TPS65013: chip = "tps65013"; break;
+ default: chip = NULL; break;
+ }
+ seq_printf(s, "driver %s\nversion %s\nchip %s\n\n",
+ DRIVER_NAME, DRIVER_VERSION, chip);
+
+ down(&tps->lock);
+
+ /* FIXME how can we tell whether a battery is present?
+ * likely involves a charge gauging chip (like BQ26501).
+ */
+
+ seq_printf(s, "%scharging\n\n", tps->charging ? "" : "(not) ");
+
+
+ /* registers for monitoring battery charging and status; note
+ * that reading chgstat and regstat may ack IRQs...
+ */
+ value = i2c_smbus_read_byte_data(&tps->client, TPS_CHGCONFIG);
+ dbg_chgconf(tps->por, buf, sizeof buf, value);
+ seq_printf(s, "chgconfig %s", buf);
+
+ value = i2c_smbus_read_byte_data(&tps->client, TPS_CHGSTATUS);
+ dbg_chgstat(buf, sizeof buf, value);
+ seq_printf(s, "chgstat %s", buf);
+ value = i2c_smbus_read_byte_data(&tps->client, TPS_MASK1);
+ dbg_chgstat(buf, sizeof buf, value);
+ seq_printf(s, "mask1 %s", buf);
+ /* ignore ackint1 */
+
+ value = i2c_smbus_read_byte_data(&tps->client, TPS_REGSTATUS);
+ dbg_regstat(buf, sizeof buf, value);
+ seq_printf(s, "regstat %s", buf);
+ value = i2c_smbus_read_byte_data(&tps->client, TPS_MASK2);
+ dbg_regstat(buf, sizeof buf, value);
+ seq_printf(s, "mask2 %s\n", buf);
+ /* ignore ackint2 */
+
+ (void) schedule_delayed_work(&tps->work, POWER_POLL_DELAY);
+
+
+ /* VMAIN voltage, enable lowpower, etc */
+ value = i2c_smbus_read_byte_data(&tps->client, TPS_VDCDC1);
+ seq_printf(s, "vdcdc1 %02x\n", value);
+
+ /* VCORE voltage, vibrator on/off */
+ value = i2c_smbus_read_byte_data(&tps->client, TPS_VDCDC2);
+ seq_printf(s, "vdcdc2 %02x\n", value);
+
+ /* both LD0s, and their lowpower behavior */
+ value = i2c_smbus_read_byte_data(&tps->client, TPS_VREGS1);
+ seq_printf(s, "vregs1 %02x\n\n", value);
+
+
+ /* LEDs and GPIOs */
+ value = i2c_smbus_read_byte_data(&tps->client, TPS_LED1_ON);
+ v2 = i2c_smbus_read_byte_data(&tps->client, TPS_LED1_PER);
+ seq_printf(s, "led1 %s, on=%02x, per=%02x, %d/%d msec\n",
+ (value & 0x80)
+ ? ((v2 & 0x80) ? "on" : "off")
+ : ((v2 & 0x80) ? "blink" : "(nPG)"),
+ value, v2,
+ (value & 0x7f) * 10, (v2 & 0x7f) * 100);
+
+ value = i2c_smbus_read_byte_data(&tps->client, TPS_LED2_ON);
+ v2 = i2c_smbus_read_byte_data(&tps->client, TPS_LED2_PER);
+ seq_printf(s, "led2 %s, on=%02x, per=%02x, %d/%d msec\n",
+ (value & 0x80)
+ ? ((v2 & 0x80) ? "on" : "off")
+ : ((v2 & 0x80) ? "blink" : "off"),
+ value, v2,
+ (value & 0x7f) * 10, (v2 & 0x7f) * 100);
+
+ value = i2c_smbus_read_byte_data(&tps->client, TPS_DEFGPIO);
+ v2 = i2c_smbus_read_byte_data(&tps->client, TPS_MASK3);
+ seq_printf(s, "defgpio %02x mask3 %02x\n", value, v2);
+
+ for (i = 0; i < 4; i++) {
+ if (value & (1 << (4 +i)))
+ seq_printf(s, " gpio%d-out %s\n", i + 1,
+ (value & (1 << i)) ? "low" : "hi ");
+ else
+ seq_printf(s, " gpio%d-in %s %s %s\n", i + 1,
+ (value & (1 << i)) ? "hi " : "low",
+ (v2 & (1 << i)) ? "no-irq" : "irq",
+ (v2 & (1 << (4 + i))) ? "rising" : "falling");
+ }
+
+ up(&tps->lock);
+ return 0;
+}
+
+static int dbg_tps_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, dbg_show, inode->u.generic_ip);
+}
+
+static struct file_operations debug_fops = {
+ .open = dbg_tps_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+#define DEBUG_FOPS &debug_fops
+
+#else
+#define DEBUG_FOPS NULL
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+/* handle IRQS in a task context, so we can use I2C calls */
+static void tps65010_interrupt(struct tps65010 *tps)
+{
+ u8 tmp = 0, mask, poll;
+
+ /* IRQs won't trigger irqs for certain events, but we can get
+ * others by polling (normally, with external power applied).
+ */
+ poll = 0;
+
+ /* regstatus irqs */
+ if (tps->nmask2) {
+ tmp = i2c_smbus_read_byte_data(&tps->client, TPS_REGSTATUS);
+ mask = tmp ^ tps->regstatus;
+ tps->regstatus = tmp;
+ mask &= tps->nmask2;
+ } else
+ mask = 0;
+ if (mask) {
+ tps->regstatus = tmp;
+ /* may need to shut something down ... */
+
+ /* "off" usually means deep sleep */
+ if (tmp & TPS_REG_ONOFF) {
+ pr_info("%s: power off button\n", DRIVER_NAME);
+#if 0
+ /* REVISIT: this might need its own workqueue
+ * plus tweaks including deadlock avoidance ...
+ */
+ software_suspend();
+#endif
+ poll = 1;
+ }
+ }
+
+ /* chgstatus irqs */
+ if (tps->nmask1) {
+ tmp = i2c_smbus_read_byte_data(&tps->client, TPS_CHGSTATUS);
+ mask = tmp ^ tps->chgstatus;
+ tps->chgstatus = tmp;
+ mask &= tps->nmask1;
+ } else
+ mask = 0;
+ if (mask) {
+ unsigned charging = 0;
+
+ show_chgstatus("chg/irq", tmp);
+ if (tmp & (TPS_CHG_USB|TPS_CHG_AC))
+ show_chgconfig(tps->por, "conf", tps->chgconf);
+
+ /* Unless it was turned off or disabled, we charge any
+ * battery whenever there's power available for it
+ * and the charger hasn't been disabled.
+ */
+ if (!(tps->chgstatus & ~(TPS_CHG_USB|TPS_CHG_AC))
+ && (tps->chgstatus & (TPS_CHG_USB|TPS_CHG_AC))
+ && (tps->chgconf & TPS_CHARGE_ENABLE)
+ ) {
+ if (tps->chgstatus & TPS_CHG_USB) {
+ /* VBUS options are readonly until reconnect */
+ if (mask & TPS_CHG_USB)
+ set_bit(FLAG_VBUS_CHANGED, &tps->flags);
+ charging = 1;
+ } else if (tps->chgstatus & TPS_CHG_AC)
+ charging = 1;
+ }
+ if (charging != tps->charging) {
+ tps->charging = charging;
+ pr_info("%s: battery %scharging\n",
+ DRIVER_NAME, charging ? "" :
+ ((tps->chgstatus & (TPS_CHG_USB|TPS_CHG_AC))
+ ? "NOT " : "dis"));
+ }
+ }
+
+ /* always poll to detect (a) power removal, without tps65013
+ * NO_CHG IRQ; or (b) restart of charging after stop.
+ */
+ if ((tps->model != TPS65013 || !tps->charging)
+ && (tps->chgstatus & (TPS_CHG_USB|TPS_CHG_AC)))
+ poll = 1;
+ if (poll)
+ (void) schedule_delayed_work(&tps->work, POWER_POLL_DELAY);
+
+ /* also potentially gpio-in rise or fall */
+}
+
+/* handle IRQs and polling using keventd for now */
+static void tps65010_work(void *_tps)
+{
+ struct tps65010 *tps = _tps;
+
+ down(&tps->lock);
+
+ tps65010_interrupt(tps);
+
+ if (test_and_clear_bit(FLAG_VBUS_CHANGED, &tps->flags)) {
+ int status;
+ u8 chgconfig, tmp;
+
+ chgconfig = i2c_smbus_read_byte_data(&tps->client,
+ TPS_CHGCONFIG);
+ chgconfig &= ~(TPS_VBUS_500MA | TPS_VBUS_CHARGING);
+ if (tps->vbus == 500)
+ chgconfig |= TPS_VBUS_500MA | TPS_VBUS_CHARGING;
+ else if (tps->vbus >= 100)
+ chgconfig |= TPS_VBUS_CHARGING;
+
+ status = i2c_smbus_write_byte_data(&tps->client,
+ TPS_CHGCONFIG, chgconfig);
+
+ /* vbus update fails unless VBUS is connected! */
+ tmp = i2c_smbus_read_byte_data(&tps->client, TPS_CHGCONFIG);
+ tps->chgconf = tmp;
+ show_chgconfig(tps->por, "update vbus", tmp);
+ }
+
+ if (test_and_clear_bit(FLAG_IRQ_ENABLE, &tps->flags))
+ enable_irq(tps->irq);
+
+ up(&tps->lock);
+}
+
+static irqreturn_t tps65010_irq(int irq, void *_tps, struct pt_regs *regs)
+{
+ struct tps65010 *tps = _tps;
+
+ disable_irq_nosync(irq);
+ set_bit(FLAG_IRQ_ENABLE, &tps->flags);
+ (void) schedule_work(&tps->work);
+ return IRQ_HANDLED;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static struct tps65010 *the_tps;
+
+static int __exit tps65010_detach_client(struct i2c_client *client)
+{
+ struct tps65010 *tps;
+
+ tps = container_of(client, struct tps65010, client);
+#ifdef CONFIG_ARM
+ if (machine_is_omap_h2())
+ omap_free_gpio(58);
+ if (machine_is_omap_osk())
+ omap_free_gpio(OMAP_MPUIO(1));
+#endif
+ free_irq(tps->irq, tps);
+ debugfs_remove(tps->file);
+ if (i2c_detach_client(client) == 0)
+ kfree(tps);
+ the_tps = 0;
+ return 0;
+}
+
+static int tps65010_noscan(struct i2c_adapter *bus)
+{
+ /* pure paranoia, in case someone adds another i2c bus
+ * after our init section's gone...
+ */
+ return -ENODEV;
+}
+
+/* no error returns, they'd just make bus scanning stop */
+static int __init
+tps65010_probe(struct i2c_adapter *bus, int address, int kind)
+{
+ struct tps65010 *tps;
+ int status;
+
+ if (the_tps) {
+ dev_dbg(&bus->dev, "only one %s for now\n", DRIVER_NAME);
+ return 0;
+ }
+
+ tps = kmalloc(sizeof *tps, GFP_KERNEL);
+ if (!tps)
+ return 0;
+
+ memset(tps, 0, sizeof *tps);
+ init_MUTEX(&tps->lock);
+ INIT_WORK(&tps->work, tps65010_work, tps);
+ tps->irq = -1;
+ tps->client.addr = address;
+ i2c_set_clientdata(&tps->client, tps);
+ tps->client.adapter = bus;
+ tps->client.driver = &tps65010_driver;
+ strlcpy(tps->client.name, DRIVER_NAME, I2C_NAME_SIZE);
+
+ status = i2c_attach_client(&tps->client);
+ if (status < 0) {
+ dev_dbg(&bus->dev, "can't attach %s to device %d, err %d\n",
+ DRIVER_NAME, address, status);
+fail1:
+ kfree(tps);
+ return 0;
+ }
+
+#ifdef CONFIG_ARM
+ if (machine_is_omap_h2()) {
+ tps->model = TPS65010;
+ omap_cfg_reg(W4_GPIO58);
+ tps->irq = OMAP_GPIO_IRQ(58);
+ omap_request_gpio(58);
+ omap_set_gpio_direction(58, 1);
+ omap_set_gpio_edge_ctrl(58, OMAP_GPIO_FALLING_EDGE);
+ }
+ if (machine_is_omap_osk()) {
+ tps->model = TPS65010;
+ // omap_cfg_reg(U19_1610_MPUIO1);
+ tps->irq = OMAP_GPIO_IRQ(OMAP_MPUIO(1));
+ omap_request_gpio(OMAP_MPUIO(1));
+ omap_set_gpio_direction(OMAP_MPUIO(1), 1);
+ omap_set_gpio_edge_ctrl(OMAP_MPUIO(1), OMAP_GPIO_FALLING_EDGE);
+ }
+ if (machine_is_omap_h3()) {
+ tps->model = TPS65013;
+
+ // FIXME set up this board's IRQ ...
+ }
+#else
+#define set_irq_type(num,trigger) do{}while(0)
+#endif
+
+ if (tps->irq > 0) {
+ set_irq_type(tps->irq, IRQT_LOW);
+ status = request_irq(tps->irq, tps65010_irq,
+ SA_SAMPLE_RANDOM, DRIVER_NAME, tps);
+ if (status < 0) {
+ dev_dbg(&tps->client.dev, "can't get IRQ %d, err %d\n",
+ tps->irq, status);
+ i2c_detach_client(&tps->client);
+ goto fail1;
+ }
+#ifdef CONFIG_ARM
+ /* annoying race here, ideally we'd have an option
+ * to claim the irq now and enable it later.
+ */
+ disable_irq(tps->irq);
+ set_bit(FLAG_IRQ_ENABLE, &tps->flags);
+#endif
+ } else
+ printk(KERN_WARNING "%s: IRQ not configured!\n",
+ DRIVER_NAME);
+
+
+ switch (tps->model) {
+ case TPS65010:
+ case TPS65012:
+ tps->por = 1;
+ break;
+ case TPS_UNKNOWN:
+ printk(KERN_WARNING "%s: unknown TPS chip\n", DRIVER_NAME);
+ break;
+ /* else CHGCONFIG.POR is replaced by AUA, enabling a WAIT mode */
+ }
+ tps->chgconf = i2c_smbus_read_byte_data(&tps->client, TPS_CHGCONFIG);
+ show_chgconfig(tps->por, "conf/init", tps->chgconf);
+
+ show_chgstatus("chg/init",
+ i2c_smbus_read_byte_data(&tps->client, TPS_CHGSTATUS));
+ show_regstatus("reg/init",
+ i2c_smbus_read_byte_data(&tps->client, TPS_REGSTATUS));
+
+ pr_debug("%s: vdcdc1 0x%02x, vdcdc2 %02x, vregs1 %02x\n", DRIVER_NAME,
+ i2c_smbus_read_byte_data(&tps->client, TPS_VDCDC1),
+ i2c_smbus_read_byte_data(&tps->client, TPS_VDCDC2),
+ i2c_smbus_read_byte_data(&tps->client, TPS_VREGS1));
+ pr_debug("%s: defgpio 0x%02x, mask3 0x%02x\n", DRIVER_NAME,
+ i2c_smbus_read_byte_data(&tps->client, TPS_DEFGPIO),
+ i2c_smbus_read_byte_data(&tps->client, TPS_MASK3));
+
+ tps65010_driver.attach_adapter = tps65010_noscan;
+ the_tps = tps;
+
+#if defined(CONFIG_USB_GADGET) && !defined(CONFIG_USB_OTG)
+ /* USB hosts can't draw VBUS. OTG devices could, later
+ * when OTG infrastructure enables it. USB peripherals
+ * could be relying on VBUS while booting, though.
+ */
+ tps->vbus = 100;
+#endif
+
+ /* unmask the "interesting" irqs, then poll once to
+ * kickstart monitoring, initialize shadowed status
+ * registers, and maybe disable VBUS draw.
+ */
+ tps->nmask1 = ~0;
+ (void) i2c_smbus_write_byte_data(&tps->client, TPS_MASK1, ~tps->nmask1);
+
+ tps->nmask2 = TPS_REG_ONOFF;
+ if (tps->model == TPS65013)
+ tps->nmask2 |= TPS_REG_NO_CHG;
+ (void) i2c_smbus_write_byte_data(&tps->client, TPS_MASK2, ~tps->nmask2);
+
+ (void) i2c_smbus_write_byte_data(&tps->client, TPS_MASK3, 0x0f
+ | i2c_smbus_read_byte_data(&tps->client, TPS_MASK3));
+
+ tps65010_work(tps);
+
+ tps->file = debugfs_create_file(DRIVER_NAME, S_IRUGO, NULL,
+ tps, DEBUG_FOPS);
+ return 0;
+}
+
+static int __init tps65010_scan_bus(struct i2c_adapter *bus)
+{
+ if (!i2c_check_functionality(bus, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -EINVAL;
+ return i2c_probe(bus, &addr_data, tps65010_probe);
+}
+
+static struct i2c_driver tps65010_driver = {
+ .owner = THIS_MODULE,
+ .name = "tps65010",
+ .id = 888, /* FIXME assign "official" value */
+ .flags = I2C_DF_NOTIFY,
+ .attach_adapter = tps65010_scan_bus,
+ .detach_client = __exit_p(tps65010_detach_client),
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* Draw from VBUS:
+ * 0 mA -- DON'T DRAW (might supply power instead)
+ * 100 mA -- usb unit load (slowest charge rate)
+ * 500 mA -- usb high power (fast battery charge)
+ */
+int tps65010_set_vbus_draw(unsigned mA)
+{
+ unsigned long flags;
+
+ if (!the_tps)
+ return -ENODEV;
+
+ /* assumes non-SMP */
+ local_irq_save(flags);
+ if (mA >= 500)
+ mA = 500;
+ else if (mA >= 100)
+ mA = 100;
+ else
+ mA = 0;
+ the_tps->vbus = mA;
+ if ((the_tps->chgstatus & TPS_CHG_USB)
+ && test_and_set_bit(
+ FLAG_VBUS_CHANGED, &the_tps->flags)) {
+ /* gadget drivers call this in_irq() */
+ (void) schedule_work(&the_tps->work);
+ }
+ local_irq_restore(flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(tps65010_set_vbus_draw);
+
+/*-------------------------------------------------------------------------*/
+/* tps65010_set_gpio_out_value parameter:
+ * gpio: GPIO1, GPIO2, GPIO3 or GPIO4
+ * value: LOW or HIGH
+ */
+int tps65010_set_gpio_out_value(unsigned gpio, unsigned value)
+{
+ int status;
+ unsigned defgpio;
+
+ if (!the_tps)
+ return -ENODEV;
+ if ((gpio < GPIO1) || (gpio > GPIO4))
+ return -EINVAL;
+
+ down(&the_tps->lock);
+
+ defgpio = i2c_smbus_read_byte_data(&the_tps->client, TPS_DEFGPIO);
+
+ /* Configure GPIO for output */
+ defgpio |= 1 << (gpio + 3);
+
+ /* Writing 1 forces a logic 0 on that GPIO and vice versa */
+ switch (value) {
+ case LOW:
+ defgpio |= 1 << (gpio - 1); /* set GPIO low by writing 1 */
+ break;
+ /* case HIGH: */
+ default:
+ defgpio &= ~(1 << (gpio - 1)); /* set GPIO high by writing 0 */
+ break;
+ }
+
+ status = i2c_smbus_write_byte_data(&the_tps->client,
+ TPS_DEFGPIO, defgpio);
+
+ pr_debug("%s: gpio%dout = %s, defgpio 0x%02x\n", DRIVER_NAME,
+ gpio, value ? "high" : "low",
+ i2c_smbus_read_byte_data(&the_tps->client, TPS_DEFGPIO));
+
+ up(&the_tps->lock);
+ return status;
+}
+EXPORT_SYMBOL(tps65010_set_gpio_out_value);
+
+/*-------------------------------------------------------------------------*/
+/* tps65010_set_led parameter:
+ * led: LED1 or LED2
+ * mode: ON, OFF or BLINK
+ */
+int tps65010_set_led(unsigned led, unsigned mode)
+{
+ int status;
+ unsigned led_on, led_per, offs;
+
+ if (!the_tps)
+ return -ENODEV;
+
+ if(led == LED1)
+ offs = 0;
+ else {
+ offs = 2;
+ led = LED2;
+ }
+
+ down(&the_tps->lock);
+
+ dev_dbg (&the_tps->client.dev, "led%i_on 0x%02x\n", led,
+ i2c_smbus_read_byte_data(&the_tps->client, TPS_LED1_ON + offs));
+
+ dev_dbg (&the_tps->client.dev, "led%i_per 0x%02x\n", led,
+ i2c_smbus_read_byte_data(&the_tps->client, TPS_LED1_PER + offs));
+
+ switch (mode) {
+ case OFF:
+ led_on = 1 << 7;
+ led_per = 0 << 7;
+ break;
+ case ON:
+ led_on = 1 << 7;
+ led_per = 1 << 7;
+ break;
+ case BLINK:
+ led_on = 0x30 | (0 << 7);
+ led_per = 0x08 | (1 << 7);
+ break;
+ default:
+ printk(KERN_ERR "%s: Wrong mode parameter for tps65010_set_led()\n",
+ DRIVER_NAME);
+ up(&the_tps->lock);
+ return -EINVAL;
+ }
+
+ status = i2c_smbus_write_byte_data(&the_tps->client,
+ TPS_LED1_ON + offs, led_on);
+
+ if (status != 0) {
+ printk(KERN_ERR "%s: Failed to write led%i_on register\n",
+ DRIVER_NAME, led);
+ up(&the_tps->lock);
+ return status;
+ }
+
+ dev_dbg (&the_tps->client.dev, "led%i_on 0x%02x\n", led,
+ i2c_smbus_read_byte_data(&the_tps->client, TPS_LED1_ON + offs));
+
+ status = i2c_smbus_write_byte_data(&the_tps->client,
+ TPS_LED1_PER + offs, led_per);
+
+ if (status != 0) {
+ printk(KERN_ERR "%s: Failed to write led%i_per register\n",
+ DRIVER_NAME, led);
+ up(&the_tps->lock);
+ return status;
+ }
+
+ dev_dbg (&the_tps->client.dev, "led%i_per 0x%02x\n", led,
+ i2c_smbus_read_byte_data(&the_tps->client, TPS_LED1_PER + offs));
+
+ up(&the_tps->lock);
+
+ return status;
+}
+EXPORT_SYMBOL(tps65010_set_led);
+
+/*-------------------------------------------------------------------------*/
+/* tps65010_set_vib parameter:
+ * value: ON or OFF
+ */
+int tps65010_set_vib(unsigned value)
+{
+ int status;
+ unsigned vdcdc2;
+
+ if (!the_tps)
+ return -ENODEV;
+
+ down(&the_tps->lock);
+
+ vdcdc2 = i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC2);
+ vdcdc2 &= ~(1 << 1);
+ if (value)
+ vdcdc2 |= (1 << 1);
+ status = i2c_smbus_write_byte_data(&the_tps->client,
+ TPS_VDCDC2, vdcdc2);
+
+ pr_debug("%s: vibrator %s\n", DRIVER_NAME, value ? "on" : "off");
+
+ up(&the_tps->lock);
+ return status;
+}
+EXPORT_SYMBOL(tps65010_set_vib);
+
+/*-------------------------------------------------------------------------*/
+/* tps65010_set_low_pwr parameter:
+ * mode: ON or OFF
+ */
+int tps65010_set_low_pwr(unsigned mode)
+{
+ int status;
+ unsigned vdcdc1;
+
+ if (!the_tps)
+ return -ENODEV;
+
+ down(&the_tps->lock);
+
+ pr_debug("%s: %s low_pwr, vdcdc1 0x%02x\n", DRIVER_NAME,
+ mode ? "enable" : "disable",
+ i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1));
+
+ vdcdc1 = i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1);
+
+ switch (mode) {
+ case OFF:
+ vdcdc1 &= ~TPS_ENABLE_LP; /* disable ENABLE_LP bit */
+ break;
+ /* case ON: */
+ default:
+ vdcdc1 |= TPS_ENABLE_LP; /* enable ENABLE_LP bit */
+ break;
+ }
+
+ status = i2c_smbus_write_byte_data(&the_tps->client,
+ TPS_VDCDC1, vdcdc1);
+
+ if (status != 0)
+ printk(KERN_ERR "%s: Failed to write vdcdc1 register\n",
+ DRIVER_NAME);
+ else
+ pr_debug("%s: vdcdc1 0x%02x\n", DRIVER_NAME,
+ i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1));
+
+ up(&the_tps->lock);
+
+ return status;
+}
+EXPORT_SYMBOL(tps65010_set_low_pwr);
+
+/*-------------------------------------------------------------------------*/
+/* tps65010_config_vregs1 parameter:
+ * value to be written to VREGS1 register
+ * Note: The complete register is written, set all bits you need
+ */
+int tps65010_config_vregs1(unsigned value)
+{
+ int status;
+
+ if (!the_tps)
+ return -ENODEV;
+
+ down(&the_tps->lock);
+
+ pr_debug("%s: vregs1 0x%02x\n", DRIVER_NAME,
+ i2c_smbus_read_byte_data(&the_tps->client, TPS_VREGS1));
+
+ status = i2c_smbus_write_byte_data(&the_tps->client,
+ TPS_VREGS1, value);
+
+ if (status != 0)
+ printk(KERN_ERR "%s: Failed to write vregs1 register\n",
+ DRIVER_NAME);
+ else
+ pr_debug("%s: vregs1 0x%02x\n", DRIVER_NAME,
+ i2c_smbus_read_byte_data(&the_tps->client, TPS_VREGS1));
+
+ up(&the_tps->lock);
+
+ return status;
+}
+EXPORT_SYMBOL(tps65010_config_vregs1);
+
+/*-------------------------------------------------------------------------*/
+/* tps65013_set_low_pwr parameter:
+ * mode: ON or OFF
+ */
+
+/* FIXME: Assumes AC or USB power is present. Setting AUA bit is not
+ required if power supply is through a battery */
+
+int tps65013_set_low_pwr(unsigned mode)
+{
+ int status;
+ unsigned vdcdc1, chgconfig;
+
+ if (!the_tps || the_tps->por)
+ return -ENODEV;
+
+ down(&the_tps->lock);
+
+ pr_debug("%s: %s low_pwr, chgconfig 0x%02x vdcdc1 0x%02x\n",
+ DRIVER_NAME,
+ mode ? "enable" : "disable",
+ i2c_smbus_read_byte_data(&the_tps->client, TPS_CHGCONFIG),
+ i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1));
+
+ chgconfig = i2c_smbus_read_byte_data(&the_tps->client, TPS_CHGCONFIG);
+ vdcdc1 = i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1);
+
+ switch (mode) {
+ case OFF:
+ chgconfig &= ~TPS65013_AUA; /* disable AUA bit */
+ vdcdc1 &= ~TPS_ENABLE_LP; /* disable ENABLE_LP bit */
+ break;
+ /* case ON: */
+ default:
+ chgconfig |= TPS65013_AUA; /* enable AUA bit */
+ vdcdc1 |= TPS_ENABLE_LP; /* enable ENABLE_LP bit */
+ break;
+ }
+
+ status = i2c_smbus_write_byte_data(&the_tps->client,
+ TPS_CHGCONFIG, chgconfig);
+ if (status != 0) {
+ printk(KERN_ERR "%s: Failed to write chconfig register\n",
+ DRIVER_NAME);
+ up(&the_tps->lock);
+ return status;
+ }
+
+ chgconfig = i2c_smbus_read_byte_data(&the_tps->client, TPS_CHGCONFIG);
+ the_tps->chgconf = chgconfig;
+ show_chgconfig(0, "chgconf", chgconfig);
+
+ status = i2c_smbus_write_byte_data(&the_tps->client,
+ TPS_VDCDC1, vdcdc1);
+
+ if (status != 0)
+ printk(KERN_ERR "%s: Failed to write vdcdc1 register\n",
+ DRIVER_NAME);
+ else
+ pr_debug("%s: vdcdc1 0x%02x\n", DRIVER_NAME,
+ i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1));
+
+ up(&the_tps->lock);
+
+ return status;
+}
+EXPORT_SYMBOL(tps65013_set_low_pwr);
+
+/*-------------------------------------------------------------------------*/
+
+static int __init tps_init(void)
+{
+ u32 tries = 3;
+ int status = -ENODEV;
+
+ printk(KERN_INFO "%s: version %s\n", DRIVER_NAME, DRIVER_VERSION);
+
+ /* some boards have startup glitches */
+ while (tries--) {
+ status = i2c_add_driver(&tps65010_driver);
+ if (the_tps)
+ break;
+ i2c_del_driver(&tps65010_driver);
+ if (!tries) {
+ printk(KERN_ERR "%s: no chip?\n", DRIVER_NAME);
+ return -ENODEV;
+ }
+ pr_debug("%s: re-probe ...\n", DRIVER_NAME);
+ msleep(10);
+ }
+
+#if defined(CONFIG_ARM)
+ if (machine_is_omap_osk()) {
+
+ // FIXME: More should be placed in the initialization code
+ // of the submodules (DSP, ethernet, power management,
+ // board-osk.c). Careful: I2C is initialized "late".
+
+ /* Let LED1 (D9) blink */
+ tps65010_set_led(LED1, BLINK);
+
+ /* Disable LED 2 (D2) */
+ tps65010_set_led(LED2, OFF);
+
+ /* Set GPIO 1 HIGH to disable VBUS power supply;
+ * OHCI driver powers it up/down as needed.
+ */
+ tps65010_set_gpio_out_value(GPIO1, HIGH);
+
+ /* Set GPIO 2 low to turn on LED D3 */
+ tps65010_set_gpio_out_value(GPIO2, HIGH);
+
+ /* Set GPIO 3 low to take ethernet out of reset */
+ tps65010_set_gpio_out_value(GPIO3, LOW);
+
+ /* gpio4 for VDD_DSP */
+
+ /* Enable LOW_PWR */
+ tps65010_set_low_pwr(ON);
+
+ /* Switch VLDO2 to 3.0V for AIC23 */
+ tps65010_config_vregs1(TPS_LDO2_ENABLE | TPS_VLDO2_3_0V | TPS_LDO1_ENABLE);
+
+ } else if (machine_is_omap_h2()) {
+ /* gpio3 for SD, gpio4 for VDD_DSP */
+
+ /* Enable LOW_PWR */
+ tps65010_set_low_pwr(ON);
+ } else if (machine_is_omap_h3()) {
+ /* gpio4 for SD, gpio3 for VDD_DSP */
+#ifdef CONFIG_PM
+ /* Enable LOW_PWR */
+ tps65013_set_low_pwr(ON);
+#endif
+ }
+#endif
+
+ return status;
+}
+/* NOTE: this MUST be initialized before the other parts of the system
+ * that rely on it ... but after the i2c bus on which this relies.
+ * That is, much earlier than on PC-type systems, which don't often use
+ * I2C as a core system bus.
+ */
+subsys_initcall(tps_init);
+
+static void __exit tps_exit(void)
+{
+ i2c_del_driver(&tps65010_driver);
+}
+module_exit(tps_exit);
+
/*
via686a.c - Part of lm_sensors, Linux kernel modules
for hardware monitoring
-
+
Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>,
Kyösti Mälkki <kmalkki@cc.hut.fi>,
Mark Studebaker <mdsxyz123@yahoo.com>,
and Bob Dougherty <bobd@stanford.edu>
- (Some conversion-factor data were contributed by Jonathan Teh Soon Yew
+ (Some conversion-factor data were contributed by Jonathan Teh Soon Yew
<j.teh@iname.com> and Alex van Kaam <darkside@chello.nl>.)
This program is free software; you can redistribute it and/or modify
Warning - only supports a single device.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/pci.h>
-#include <linux/delay.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/i2c-sensor.h>
/* Many VIA686A constants specified below */
/* Length of ISA address segment */
-#define VIA686A_EXTENT 0x80
-#define VIA686A_BASE_REG 0x70
-#define VIA686A_ENABLE_REG 0x74
+#define VIA686A_EXTENT 0x80
+#define VIA686A_BASE_REG 0x70
+#define VIA686A_ENABLE_REG 0x74
/* The VIA686A registers */
/* ins numbered 0-4 */
-#define VIA686A_REG_IN_MAX(nr) (0x2b + ((nr) * 2))
-#define VIA686A_REG_IN_MIN(nr) (0x2c + ((nr) * 2))
-#define VIA686A_REG_IN(nr) (0x22 + (nr))
+#define VIA686A_REG_IN_MAX(nr) (0x2b + ((nr) * 2))
+#define VIA686A_REG_IN_MIN(nr) (0x2c + ((nr) * 2))
+#define VIA686A_REG_IN(nr) (0x22 + (nr))
/* fans numbered 1-2 */
-#define VIA686A_REG_FAN_MIN(nr) (0x3a + (nr))
-#define VIA686A_REG_FAN(nr) (0x28 + (nr))
-
-/* the following values are as speced by VIA: */
-static const u8 regtemp[] = { 0x20, 0x21, 0x1f };
-static const u8 regover[] = { 0x39, 0x3d, 0x1d };
-static const u8 reghyst[] = { 0x3a, 0x3e, 0x1e };
+#define VIA686A_REG_FAN_MIN(nr) (0x3a + (nr))
+#define VIA686A_REG_FAN(nr) (0x28 + (nr))
/* temps numbered 1-3 */
-#define VIA686A_REG_TEMP(nr) (regtemp[nr])
-#define VIA686A_REG_TEMP_OVER(nr) (regover[nr])
-#define VIA686A_REG_TEMP_HYST(nr) (reghyst[nr])
-#define VIA686A_REG_TEMP_LOW1 0x4b // bits 7-6
-#define VIA686A_REG_TEMP_LOW23 0x49 // 2 = bits 5-4, 3 = bits 7-6
-
-#define VIA686A_REG_ALARM1 0x41
-#define VIA686A_REG_ALARM2 0x42
-#define VIA686A_REG_FANDIV 0x47
-#define VIA686A_REG_CONFIG 0x40
-/* The following register sets temp interrupt mode (bits 1-0 for temp1,
+static const u8 VIA686A_REG_TEMP[] = { 0x20, 0x21, 0x1f };
+static const u8 VIA686A_REG_TEMP_OVER[] = { 0x39, 0x3d, 0x1d };
+static const u8 VIA686A_REG_TEMP_HYST[] = { 0x3a, 0x3e, 0x1e };
+/* bits 7-6 */
+#define VIA686A_REG_TEMP_LOW1 0x4b
+/* 2 = bits 5-4, 3 = bits 7-6 */
+#define VIA686A_REG_TEMP_LOW23 0x49
+
+#define VIA686A_REG_ALARM1 0x41
+#define VIA686A_REG_ALARM2 0x42
+#define VIA686A_REG_FANDIV 0x47
+#define VIA686A_REG_CONFIG 0x40
+/* The following register sets temp interrupt mode (bits 1-0 for temp1,
3-2 for temp2, 5-4 for temp3). Modes are:
00 interrupt stays as long as value is out-of-range
01 interrupt is cleared once register is read (default)
10 comparator mode- like 00, but ignores hysteresis
11 same as 00 */
-#define VIA686A_REG_TEMP_MODE 0x4b
+#define VIA686A_REG_TEMP_MODE 0x4b
/* We'll just assume that you want to set all 3 simultaneously: */
-#define VIA686A_TEMP_MODE_MASK 0x3F
-#define VIA686A_TEMP_MODE_CONTINUOUS (0x00)
+#define VIA686A_TEMP_MODE_MASK 0x3F
+#define VIA686A_TEMP_MODE_CONTINUOUS 0x00
/* Conversions. Limit checking is only done on the TO_REG
- variants.
+ variants.
********* VOLTAGE CONVERSIONS (Bob Dougherty) ********
From HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew):
That is:
volts = (25*regVal+133)*factor
regVal = (volts/factor-133)/25
- (These conversions were contributed by Jonathan Teh Soon Yew
+ (These conversions were contributed by Jonathan Teh Soon Yew
<j.teh@iname.com>) */
static inline u8 IN_TO_REG(long val, int inNum)
{
else
return double(temp)*0.924-127.33;
- A fifth-order polynomial fits the unofficial data (provided by Alex van
- Kaam <darkside@chello.nl>) a bit better. It also give more reasonable
- numbers on my machine (ie. they agree with what my BIOS tells me).
+ A fifth-order polynomial fits the unofficial data (provided by Alex van
+ Kaam <darkside@chello.nl>) a bit better. It also give more reasonable
+ numbers on my machine (ie. they agree with what my BIOS tells me).
Here's the fifth-order fit to the 8-bit data:
- temp = 1.625093e-10*val^5 - 1.001632e-07*val^4 + 2.457653e-05*val^3 -
+ temp = 1.625093e-10*val^5 - 1.001632e-07*val^4 + 2.457653e-05*val^3 -
2.967619e-03*val^2 + 2.175144e-01*val - 7.090067e+0.
- (2000-10-25- RFD: thanks to Uwe Andersen <uandersen@mayah.com> for
+ (2000-10-25- RFD: thanks to Uwe Andersen <uandersen@mayah.com> for
finding my typos in this formula!)
- Alas, none of the elegant function-fit solutions will work because we
- aren't allowed to use floating point in the kernel and doing it with
- integers doesn't rpovide enough precision. So we'll do boring old
- look-up table stuff. The unofficial data (see below) have effectively
- 7-bit resolution (they are rounded to the nearest degree). I'm assuming
- that the transfer function of the device is monotonic and smooth, so a
- smooth function fit to the data will allow us to get better precision.
+ Alas, none of the elegant function-fit solutions will work because we
+ aren't allowed to use floating point in the kernel and doing it with
+ integers doesn't provide enough precision. So we'll do boring old
+ look-up table stuff. The unofficial data (see below) have effectively
+ 7-bit resolution (they are rounded to the nearest degree). I'm assuming
+ that the transfer function of the device is monotonic and smooth, so a
+ smooth function fit to the data will allow us to get better precision.
I used the 5th-order poly fit described above and solved for
- VIA register values 0-255. I *10 before rounding, so we get tenth-degree
- precision. (I could have done all 1024 values for our 10-bit readings,
- but the function is very linear in the useful range (0-80 deg C), so
- we'll just use linear interpolation for 10-bit readings.) So, tempLUT
+ VIA register values 0-255. I *10 before rounding, so we get tenth-degree
+ precision. (I could have done all 1024 values for our 10-bit readings,
+ but the function is very linear in the useful range (0-80 deg C), so
+ we'll just use linear interpolation for 10-bit readings.) So, tempLUT
is the temp at via register values 0-255: */
static const long tempLUT[] =
- { -709, -688, -667, -646, -627, -607, -589, -570, -553, -536, -519,
- -503, -487, -471, -456, -442, -428, -414, -400, -387, -375,
- -362, -350, -339, -327, -316, -305, -295, -285, -275, -265,
- -255, -246, -237, -229, -220, -212, -204, -196, -188, -180,
- -173, -166, -159, -152, -145, -139, -132, -126, -120, -114,
- -108, -102, -96, -91, -85, -80, -74, -69, -64, -59, -54, -49,
- -44, -39, -34, -29, -25, -20, -15, -11, -6, -2, 3, 7, 12, 16,
- 20, 25, 29, 33, 37, 42, 46, 50, 54, 59, 63, 67, 71, 75, 79, 84,
- 88, 92, 96, 100, 104, 109, 113, 117, 121, 125, 130, 134, 138,
- 142, 146, 151, 155, 159, 163, 168, 172, 176, 181, 185, 189,
- 193, 198, 202, 206, 211, 215, 219, 224, 228, 232, 237, 241,
- 245, 250, 254, 259, 263, 267, 272, 276, 281, 285, 290, 294,
- 299, 303, 307, 312, 316, 321, 325, 330, 334, 339, 344, 348,
- 353, 357, 362, 366, 371, 376, 380, 385, 390, 395, 399, 404,
- 409, 414, 419, 423, 428, 433, 438, 443, 449, 454, 459, 464,
- 469, 475, 480, 486, 491, 497, 502, 508, 514, 520, 526, 532,
- 538, 544, 551, 557, 564, 571, 578, 584, 592, 599, 606, 614,
- 621, 629, 637, 645, 654, 662, 671, 680, 689, 698, 708, 718,
- 728, 738, 749, 759, 770, 782, 793, 805, 818, 830, 843, 856,
- 870, 883, 898, 912, 927, 943, 958, 975, 991, 1008, 1026, 1044,
- 1062, 1081, 1101, 1121, 1141, 1162, 1184, 1206, 1229, 1252,
- 1276, 1301, 1326, 1352, 1378, 1406, 1434, 1462
+{ -709, -688, -667, -646, -627, -607, -589, -570, -553, -536, -519,
+ -503, -487, -471, -456, -442, -428, -414, -400, -387, -375,
+ -362, -350, -339, -327, -316, -305, -295, -285, -275, -265,
+ -255, -246, -237, -229, -220, -212, -204, -196, -188, -180,
+ -173, -166, -159, -152, -145, -139, -132, -126, -120, -114,
+ -108, -102, -96, -91, -85, -80, -74, -69, -64, -59, -54, -49,
+ -44, -39, -34, -29, -25, -20, -15, -11, -6, -2, 3, 7, 12, 16,
+ 20, 25, 29, 33, 37, 42, 46, 50, 54, 59, 63, 67, 71, 75, 79, 84,
+ 88, 92, 96, 100, 104, 109, 113, 117, 121, 125, 130, 134, 138,
+ 142, 146, 151, 155, 159, 163, 168, 172, 176, 181, 185, 189,
+ 193, 198, 202, 206, 211, 215, 219, 224, 228, 232, 237, 241,
+ 245, 250, 254, 259, 263, 267, 272, 276, 281, 285, 290, 294,
+ 299, 303, 307, 312, 316, 321, 325, 330, 334, 339, 344, 348,
+ 353, 357, 362, 366, 371, 376, 380, 385, 390, 395, 399, 404,
+ 409, 414, 419, 423, 428, 433, 438, 443, 449, 454, 459, 464,
+ 469, 475, 480, 486, 491, 497, 502, 508, 514, 520, 526, 532,
+ 538, 544, 551, 557, 564, 571, 578, 584, 592, 599, 606, 614,
+ 621, 629, 637, 645, 654, 662, 671, 680, 689, 698, 708, 718,
+ 728, 738, 749, 759, 770, 782, 793, 805, 818, 830, 843, 856,
+ 870, 883, 898, 912, 927, 943, 958, 975, 991, 1008, 1026, 1044,
+ 1062, 1081, 1101, 1121, 1141, 1162, 1184, 1206, 1229, 1252,
+ 1276, 1301, 1326, 1352, 1378, 1406, 1434, 1462
};
-/* the original LUT values from Alex van Kaam <darkside@chello.nl>
+/* the original LUT values from Alex van Kaam <darkside@chello.nl>
(for via register values 12-240):
{-50,-49,-47,-45,-43,-41,-39,-38,-37,-35,-34,-33,-32,-31,
-30,-29,-28,-27,-26,-25,-24,-24,-23,-22,-21,-20,-20,-19,-18,-17,-17,-16,-15,
Here's the reverse LUT. I got it by doing a 6-th order poly fit (needed
- an extra term for a good fit to these inverse data!) and then
- solving for each temp value from -50 to 110 (the useable range for
- this chip). Here's the fit:
- viaRegVal = -1.160370e-10*val^6 +3.193693e-08*val^5 - 1.464447e-06*val^4
+ an extra term for a good fit to these inverse data!) and then
+ solving for each temp value from -50 to 110 (the useable range for
+ this chip). Here's the fit:
+ viaRegVal = -1.160370e-10*val^6 +3.193693e-08*val^5 - 1.464447e-06*val^4
- 2.525453e-04*val^3 + 1.424593e-02*val^2 + 2.148941e+00*val +7.275808e+01)
Note that n=161: */
static const u8 viaLUT[] =
- { 12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 18, 19, 20, 20, 21, 22, 23,
- 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 39, 40,
- 41, 43, 45, 46, 48, 49, 51, 53, 55, 57, 59, 60, 62, 64, 66,
- 69, 71, 73, 75, 77, 79, 82, 84, 86, 88, 91, 93, 95, 98, 100,
- 103, 105, 107, 110, 112, 115, 117, 119, 122, 124, 126, 129,
- 131, 134, 136, 138, 140, 143, 145, 147, 150, 152, 154, 156,
- 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180,
- 182, 183, 185, 187, 188, 190, 192, 193, 195, 196, 198, 199,
- 200, 202, 203, 205, 206, 207, 208, 209, 210, 211, 212, 213,
- 214, 215, 216, 217, 218, 219, 220, 221, 222, 222, 223, 224,
- 225, 226, 226, 227, 228, 228, 229, 230, 230, 231, 232, 232,
- 233, 233, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239,
- 239, 240
+{ 12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 18, 19, 20, 20, 21, 22, 23,
+ 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 39, 40,
+ 41, 43, 45, 46, 48, 49, 51, 53, 55, 57, 59, 60, 62, 64, 66,
+ 69, 71, 73, 75, 77, 79, 82, 84, 86, 88, 91, 93, 95, 98, 100,
+ 103, 105, 107, 110, 112, 115, 117, 119, 122, 124, 126, 129,
+ 131, 134, 136, 138, 140, 143, 145, 147, 150, 152, 154, 156,
+ 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180,
+ 182, 183, 185, 187, 188, 190, 192, 193, 195, 196, 198, 199,
+ 200, 202, 203, 205, 206, 207, 208, 209, 210, 211, 212, 213,
+ 214, 215, 216, 217, 218, 219, 220, 221, 222, 222, 223, 224,
+ 225, 226, 226, 227, 228, 228, 229, 230, 230, 231, 232, 232,
+ 233, 233, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239,
+ 239, 240
};
/* Converting temps to (8-bit) hyst and over registers
The +50 is because the temps start at -50 */
static inline u8 TEMP_TO_REG(long val)
{
- return viaLUT[val <= -50000 ? 0 : val >= 110000 ? 160 :
+ return viaLUT[val <= -50000 ? 0 : val >= 110000 ? 160 :
(val < 0 ? val - 500 : val + 500) / 1000 + 50];
}
/* do some linear interpolation */
return (tempLUT[eightBits] * (4 - twoBits) +
- tempLUT[eightBits + 1] * twoBits) * 25;
+ tempLUT[eightBits + 1] * twoBits) * 25;
}
-#define ALARMS_FROM_REG(val) (val)
-
#define DIV_FROM_REG(val) (1 << (val))
#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1)
return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_max[nr], nr));
}
-static ssize_t set_in_min(struct device *dev, const char *buf,
+static ssize_t set_in_min(struct device *dev, const char *buf,
size_t count, int nr) {
struct i2c_client *client = to_i2c_client(dev);
struct via686a_data *data = i2c_get_clientdata(client);
unsigned long val = simple_strtoul(buf, NULL, 10);
down(&data->update_lock);
- data->in_min[nr] = IN_TO_REG(val,nr);
- via686a_write_value(client, VIA686A_REG_IN_MIN(nr),
+ data->in_min[nr] = IN_TO_REG(val, nr);
+ via686a_write_value(client, VIA686A_REG_IN_MIN(nr),
data->in_min[nr]);
up(&data->update_lock);
return count;
}
-static ssize_t set_in_max(struct device *dev, const char *buf,
+static ssize_t set_in_max(struct device *dev, const char *buf,
size_t count, int nr) {
struct i2c_client *client = to_i2c_client(dev);
struct via686a_data *data = i2c_get_clientdata(client);
unsigned long val = simple_strtoul(buf, NULL, 10);
down(&data->update_lock);
- data->in_max[nr] = IN_TO_REG(val,nr);
- via686a_write_value(client, VIA686A_REG_IN_MAX(nr),
+ data->in_max[nr] = IN_TO_REG(val, nr);
+ via686a_write_value(client, VIA686A_REG_IN_MAX(nr),
data->in_max[nr]);
up(&data->update_lock);
return count;
struct via686a_data *data = via686a_update_device(dev);
return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_hyst[nr]));
}
-static ssize_t set_temp_over(struct device *dev, const char *buf,
+static ssize_t set_temp_over(struct device *dev, const char *buf,
size_t count, int nr) {
struct i2c_client *client = to_i2c_client(dev);
struct via686a_data *data = i2c_get_clientdata(client);
down(&data->update_lock);
data->temp_over[nr] = TEMP_TO_REG(val);
- via686a_write_value(client, VIA686A_REG_TEMP_OVER(nr), data->temp_over[nr]);
+ via686a_write_value(client, VIA686A_REG_TEMP_OVER[nr],
+ data->temp_over[nr]);
up(&data->update_lock);
return count;
}
-static ssize_t set_temp_hyst(struct device *dev, const char *buf,
+static ssize_t set_temp_hyst(struct device *dev, const char *buf,
size_t count, int nr) {
struct i2c_client *client = to_i2c_client(dev);
struct via686a_data *data = i2c_get_clientdata(client);
down(&data->update_lock);
data->temp_hyst[nr] = TEMP_TO_REG(val);
- via686a_write_value(client, VIA686A_REG_TEMP_HYST(nr), data->temp_hyst[nr]);
+ via686a_write_value(client, VIA686A_REG_TEMP_HYST[nr],
+ data->temp_hyst[nr]);
up(&data->update_lock);
return count;
}
static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \
show_temp_##offset##_over, set_temp_##offset##_over); \
static DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR, \
- show_temp_##offset##_hyst, set_temp_##offset##_hyst);
+ show_temp_##offset##_hyst, set_temp_##offset##_hyst);
show_temp_offset(1);
show_temp_offset(2);
/* 2 Fans */
static ssize_t show_fan(struct device *dev, char *buf, int nr) {
struct via686a_data *data = via686a_update_device(dev);
- return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan[nr],
+ return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
DIV_FROM_REG(data->fan_div[nr])) );
}
static ssize_t show_fan_min(struct device *dev, char *buf, int nr) {
struct via686a_data *data = via686a_update_device(dev);
- return sprintf(buf,"%d\n",
+ return sprintf(buf, "%d\n",
FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])) );
}
static ssize_t show_fan_div(struct device *dev, char *buf, int nr) {
struct via686a_data *data = via686a_update_device(dev);
- return sprintf(buf,"%d\n", DIV_FROM_REG(data->fan_div[nr]) );
+ return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]) );
}
-static ssize_t set_fan_min(struct device *dev, const char *buf,
+static ssize_t set_fan_min(struct device *dev, const char *buf,
size_t count, int nr) {
struct i2c_client *client = to_i2c_client(dev);
struct via686a_data *data = i2c_get_clientdata(client);
up(&data->update_lock);
return count;
}
-static ssize_t set_fan_div(struct device *dev, const char *buf,
+static ssize_t set_fan_div(struct device *dev, const char *buf,
size_t count, int nr) {
struct i2c_client *client = to_i2c_client(dev);
struct via686a_data *data = i2c_get_clientdata(client);
/* Alarms */
static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) {
struct via686a_data *data = via686a_update_device(dev);
- return sprintf(buf,"%d\n", ALARMS_FROM_REG(data->alarms));
+ return sprintf(buf, "%u\n", data->alarms);
}
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
}
/* 8231 requires multiple of 256, we enforce that on 686 as well */
- if(force_addr)
+ if (force_addr)
address = force_addr & 0xFF00;
- if(force_addr) {
- dev_warn(&adapter->dev,"forcing ISA address 0x%04X\n", address);
+ if (force_addr) {
+ dev_warn(&adapter->dev, "forcing ISA address 0x%04X\n",
+ address);
if (PCIBIOS_SUCCESSFUL !=
pci_write_config_word(s_bridge, VIA686A_BASE_REG, address))
return -ENODEV;
pci_read_config_word(s_bridge, VIA686A_ENABLE_REG, &val))
return -ENODEV;
if (!(val & 0x0001)) {
- dev_warn(&adapter->dev,"enabling sensors\n");
+ dev_warn(&adapter->dev, "enabling sensors\n");
if (PCIBIOS_SUCCESSFUL !=
pci_write_config_word(s_bridge, VIA686A_ENABLE_REG,
- val | 0x0001))
+ val | 0x0001))
return -ENODEV;
}
/* Reserve the ISA region */
if (!request_region(address, VIA686A_EXTENT, via686a_driver.name)) {
- dev_err(&adapter->dev,"region 0x%x already in use!\n",
- address);
+ dev_err(&adapter->dev, "region 0x%x already in use!\n",
+ address);
return -ENODEV;
}
/* Tell the I2C layer a new client has arrived */
if ((err = i2c_attach_client(new_client)))
goto ERROR3;
-
+
/* Initialize the VIA686A chip */
via686a_init_client(new_client);
return 0;
- ERROR3:
+ERROR3:
kfree(data);
- ERROR0:
+ERROR0:
release_region(address, VIA686A_EXTENT);
return err;
}
via686a_write_value(client, VIA686A_REG_CONFIG, (reg|0x01)&0x7F);
/* Configure temp interrupt mode for continuous-interrupt operation */
- via686a_write_value(client, VIA686A_REG_TEMP_MODE,
+ via686a_write_value(client, VIA686A_REG_TEMP_MODE,
via686a_read_value(client, VIA686A_REG_TEMP_MODE) &
!(VIA686A_TEMP_MODE_MASK | VIA686A_TEMP_MODE_CONTINUOUS));
}
}
for (i = 0; i <= 2; i++) {
data->temp[i] = via686a_read_value(client,
- VIA686A_REG_TEMP(i)) << 2;
+ VIA686A_REG_TEMP[i]) << 2;
data->temp_over[i] =
via686a_read_value(client,
- VIA686A_REG_TEMP_OVER(i));
+ VIA686A_REG_TEMP_OVER[i]);
data->temp_hyst[i] =
via686a_read_value(client,
- VIA686A_REG_TEMP_HYST(i));
+ VIA686A_REG_TEMP_HYST[i]);
}
- /* add in lower 2 bits
+ /* add in lower 2 bits
temp1 uses bits 7-6 of VIA686A_REG_TEMP_LOW1
temp2 uses bits 5-4 of VIA686A_REG_TEMP_LOW23
temp3 uses bits 7-6 of VIA686A_REG_TEMP_LOW23
}
static struct pci_device_id via686a_pci_ids[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4) },
- { 0, }
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4) },
+ { 0, }
};
MODULE_DEVICE_TABLE(pci, via686a_pci_ids);
static int __devinit via686a_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *id)
+ const struct pci_device_id *id)
{
- u16 val;
- int addr = 0;
-
- if (PCIBIOS_SUCCESSFUL !=
- pci_read_config_word(dev, VIA686A_BASE_REG, &val))
- return -ENODEV;
-
- addr = val & ~(VIA686A_EXTENT - 1);
- if (addr == 0 && force_addr == 0) {
- dev_err(&dev->dev,"base address not set - upgrade BIOS or use force_addr=0xaddr\n");
- return -ENODEV;
- }
- if (force_addr)
- addr = force_addr; /* so detect will get called */
-
- if (!addr) {
- dev_err(&dev->dev,"No Via 686A sensors found.\n");
- return -ENODEV;
- }
- normal_isa[0] = addr;
+ u16 val;
+ int addr = 0;
+
+ if (PCIBIOS_SUCCESSFUL !=
+ pci_read_config_word(dev, VIA686A_BASE_REG, &val))
+ return -ENODEV;
+
+ addr = val & ~(VIA686A_EXTENT - 1);
+ if (addr == 0 && force_addr == 0) {
+ dev_err(&dev->dev, "base address not set - upgrade BIOS "
+ "or use force_addr=0xaddr\n");
+ return -ENODEV;
+ }
+ if (force_addr)
+ addr = force_addr; /* so detect will get called */
+
+ if (!addr) {
+ dev_err(&dev->dev, "No Via 686A sensors found.\n");
+ return -ENODEV;
+ }
+ normal_isa[0] = addr;
s_bridge = pci_dev_get(dev);
if (i2c_add_driver(&via686a_driver)) {
}
static struct pci_driver via686a_pci_driver = {
- .name = "via686a",
- .id_table = via686a_pci_ids,
- .probe = via686a_pci_probe,
+ .name = "via686a",
+ .id_table = via686a_pci_ids,
+ .probe = via686a_pci_probe,
};
static int __init sm_via686a_init(void)
{
- return pci_register_driver(&via686a_pci_driver);
+ return pci_register_driver(&via686a_pci_driver);
}
static void __exit sm_via686a_exit(void)
}
MODULE_AUTHOR("Kyösti Mälkki <kmalkki@cc.hut.fi>, "
- "Mark Studebaker <mdsxyz123@yahoo.com> "
- "and Bob Dougherty <bobd@stanford.edu>");
+ "Mark Studebaker <mdsxyz123@yahoo.com> "
+ "and Bob Dougherty <bobd@stanford.edu>");
MODULE_DESCRIPTION("VIA 686A Sensor device");
MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ w83627ehf - Driver for the hardware monitoring functionality of
+ the Winbond W83627EHF Super-I/O chip
+ Copyright (C) 2005 Jean Delvare <khali@linux-fr.org>
+
+ Shamelessly ripped from the w83627hf driver
+ Copyright (C) 2003 Mark Studebaker
+
+ Thanks to Leon Moonen, Steve Cliffe and Grant Coady for their help
+ in testing and debugging this driver.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ 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.
+
+
+ Supports the following chips:
+
+ Chip #vin #fan #pwm #temp chip_id man_id
+ w83627ehf - 5 - 3 0x88 0x5ca3
+
+ This is a preliminary version of the driver, only supporting the
+ fan and temperature inputs. The chip does much more than that.
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/i2c-sensor.h>
+#include <asm/io.h>
+#include "lm75.h"
+
+/* Addresses to scan
+ The actual ISA address is read from Super-I/O configuration space */
+static unsigned short normal_i2c[] = { I2C_CLIENT_END };
+static unsigned int normal_isa[] = { 0, I2C_CLIENT_ISA_END };
+
+/* Insmod parameters */
+SENSORS_INSMOD_1(w83627ehf);
+
+/*
+ * Super-I/O constants and functions
+ */
+
+static int REG; /* The register to read/write */
+static int VAL; /* The value to read/write */
+
+#define W83627EHF_LD_HWM 0x0b
+
+#define SIO_REG_LDSEL 0x07 /* Logical device select */
+#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
+#define SIO_REG_ENABLE 0x30 /* Logical device enable */
+#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
+
+#define SIO_W83627EHF_ID 0x8840
+#define SIO_ID_MASK 0xFFC0
+
+static inline void
+superio_outb(int reg, int val)
+{
+ outb(reg, REG);
+ outb(val, VAL);
+}
+
+static inline int
+superio_inb(int reg)
+{
+ outb(reg, REG);
+ return inb(VAL);
+}
+
+static inline void
+superio_select(int ld)
+{
+ outb(SIO_REG_LDSEL, REG);
+ outb(ld, VAL);
+}
+
+static inline void
+superio_enter(void)
+{
+ outb(0x87, REG);
+ outb(0x87, REG);
+}
+
+static inline void
+superio_exit(void)
+{
+ outb(0x02, REG);
+ outb(0x02, VAL);
+}
+
+/*
+ * ISA constants
+ */
+
+#define REGION_LENGTH 8
+#define ADDR_REG_OFFSET 5
+#define DATA_REG_OFFSET 6
+
+#define W83627EHF_REG_BANK 0x4E
+#define W83627EHF_REG_CONFIG 0x40
+#define W83627EHF_REG_CHIP_ID 0x49
+#define W83627EHF_REG_MAN_ID 0x4F
+
+static const u16 W83627EHF_REG_FAN[] = { 0x28, 0x29, 0x2a, 0x3f, 0x553 };
+static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c };
+
+#define W83627EHF_REG_TEMP1 0x27
+#define W83627EHF_REG_TEMP1_HYST 0x3a
+#define W83627EHF_REG_TEMP1_OVER 0x39
+static const u16 W83627EHF_REG_TEMP[] = { 0x150, 0x250 };
+static const u16 W83627EHF_REG_TEMP_HYST[] = { 0x153, 0x253 };
+static const u16 W83627EHF_REG_TEMP_OVER[] = { 0x155, 0x255 };
+static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0x152, 0x252 };
+
+/* Fan clock dividers are spread over the following five registers */
+#define W83627EHF_REG_FANDIV1 0x47
+#define W83627EHF_REG_FANDIV2 0x4B
+#define W83627EHF_REG_VBAT 0x5D
+#define W83627EHF_REG_DIODE 0x59
+#define W83627EHF_REG_SMI_OVT 0x4C
+
+/*
+ * Conversions
+ */
+
+static inline unsigned int
+fan_from_reg(u8 reg, unsigned int div)
+{
+ if (reg == 0 || reg == 255)
+ return 0;
+ return 1350000U / (reg * div);
+}
+
+static inline unsigned int
+div_from_reg(u8 reg)
+{
+ return 1 << reg;
+}
+
+static inline int
+temp1_from_reg(s8 reg)
+{
+ return reg * 1000;
+}
+
+static inline s8
+temp1_to_reg(int temp)
+{
+ if (temp <= -128000)
+ return -128;
+ if (temp >= 127000)
+ return 127;
+ if (temp < 0)
+ return (temp - 500) / 1000;
+ return (temp + 500) / 1000;
+}
+
+/*
+ * Data structures and manipulation thereof
+ */
+
+struct w83627ehf_data {
+ struct i2c_client client;
+ struct semaphore lock;
+
+ struct semaphore update_lock;
+ char valid; /* !=0 if following fields are valid */
+ unsigned long last_updated; /* In jiffies */
+
+ /* Register values */
+ u8 fan[5];
+ u8 fan_min[5];
+ u8 fan_div[5];
+ u8 has_fan; /* some fan inputs can be disabled */
+ s8 temp1;
+ s8 temp1_max;
+ s8 temp1_max_hyst;
+ s16 temp[2];
+ s16 temp_max[2];
+ s16 temp_max_hyst[2];
+};
+
+static inline int is_word_sized(u16 reg)
+{
+ return (((reg & 0xff00) == 0x100
+ || (reg & 0xff00) == 0x200)
+ && ((reg & 0x00ff) == 0x50
+ || (reg & 0x00ff) == 0x53
+ || (reg & 0x00ff) == 0x55));
+}
+
+/* We assume that the default bank is 0, thus the following two functions do
+ nothing for registers which live in bank 0. For others, they respectively
+ set the bank register to the correct value (before the register is
+ accessed), and back to 0 (afterwards). */
+static inline void w83627ehf_set_bank(struct i2c_client *client, u16 reg)
+{
+ if (reg & 0xff00) {
+ outb_p(W83627EHF_REG_BANK, client->addr + ADDR_REG_OFFSET);
+ outb_p(reg >> 8, client->addr + DATA_REG_OFFSET);
+ }
+}
+
+static inline void w83627ehf_reset_bank(struct i2c_client *client, u16 reg)
+{
+ if (reg & 0xff00) {
+ outb_p(W83627EHF_REG_BANK, client->addr + ADDR_REG_OFFSET);
+ outb_p(0, client->addr + DATA_REG_OFFSET);
+ }
+}
+
+static u16 w83627ehf_read_value(struct i2c_client *client, u16 reg)
+{
+ struct w83627ehf_data *data = i2c_get_clientdata(client);
+ int res, word_sized = is_word_sized(reg);
+
+ down(&data->lock);
+
+ w83627ehf_set_bank(client, reg);
+ outb_p(reg & 0xff, client->addr + ADDR_REG_OFFSET);
+ res = inb_p(client->addr + DATA_REG_OFFSET);
+ if (word_sized) {
+ outb_p((reg & 0xff) + 1,
+ client->addr + ADDR_REG_OFFSET);
+ res = (res << 8) + inb_p(client->addr + DATA_REG_OFFSET);
+ }
+ w83627ehf_reset_bank(client, reg);
+
+ up(&data->lock);
+
+ return res;
+}
+
+static int w83627ehf_write_value(struct i2c_client *client, u16 reg, u16 value)
+{
+ struct w83627ehf_data *data = i2c_get_clientdata(client);
+ int word_sized = is_word_sized(reg);
+
+ down(&data->lock);
+
+ w83627ehf_set_bank(client, reg);
+ outb_p(reg & 0xff, client->addr + ADDR_REG_OFFSET);
+ if (word_sized) {
+ outb_p(value >> 8, client->addr + DATA_REG_OFFSET);
+ outb_p((reg & 0xff) + 1,
+ client->addr + ADDR_REG_OFFSET);
+ }
+ outb_p(value & 0xff, client->addr + DATA_REG_OFFSET);
+ w83627ehf_reset_bank(client, reg);
+
+ up(&data->lock);
+ return 0;
+}
+
+/* This function assumes that the caller holds data->update_lock */
+static void w83627ehf_write_fan_div(struct i2c_client *client, int nr)
+{
+ struct w83627ehf_data *data = i2c_get_clientdata(client);
+ u8 reg;
+
+ switch (nr) {
+ case 0:
+ reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) & 0xcf)
+ | ((data->fan_div[0] & 0x03) << 4);
+ w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg);
+ reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0xdf)
+ | ((data->fan_div[0] & 0x04) << 3);
+ w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg);
+ break;
+ case 1:
+ reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) & 0x3f)
+ | ((data->fan_div[1] & 0x03) << 6);
+ w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg);
+ reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0xbf)
+ | ((data->fan_div[1] & 0x04) << 4);
+ w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg);
+ break;
+ case 2:
+ reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV2) & 0x3f)
+ | ((data->fan_div[2] & 0x03) << 6);
+ w83627ehf_write_value(client, W83627EHF_REG_FANDIV2, reg);
+ reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0x7f)
+ | ((data->fan_div[2] & 0x04) << 5);
+ w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg);
+ break;
+ case 3:
+ reg = (w83627ehf_read_value(client, W83627EHF_REG_DIODE) & 0xfc)
+ | (data->fan_div[3] & 0x03);
+ w83627ehf_write_value(client, W83627EHF_REG_DIODE, reg);
+ reg = (w83627ehf_read_value(client, W83627EHF_REG_SMI_OVT) & 0x7f)
+ | ((data->fan_div[3] & 0x04) << 5);
+ w83627ehf_write_value(client, W83627EHF_REG_SMI_OVT, reg);
+ break;
+ case 4:
+ reg = (w83627ehf_read_value(client, W83627EHF_REG_DIODE) & 0x73)
+ | ((data->fan_div[4] & 0x03) << 3)
+ | ((data->fan_div[4] & 0x04) << 5);
+ w83627ehf_write_value(client, W83627EHF_REG_DIODE, reg);
+ break;
+ }
+}
+
+static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83627ehf_data *data = i2c_get_clientdata(client);
+ int i;
+
+ down(&data->update_lock);
+
+ if (time_after(jiffies, data->last_updated + HZ)
+ || !data->valid) {
+ /* Fan clock dividers */
+ i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1);
+ data->fan_div[0] = (i >> 4) & 0x03;
+ data->fan_div[1] = (i >> 6) & 0x03;
+ i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV2);
+ data->fan_div[2] = (i >> 6) & 0x03;
+ i = w83627ehf_read_value(client, W83627EHF_REG_VBAT);
+ data->fan_div[0] |= (i >> 3) & 0x04;
+ data->fan_div[1] |= (i >> 4) & 0x04;
+ data->fan_div[2] |= (i >> 5) & 0x04;
+ if (data->has_fan & ((1 << 3) | (1 << 4))) {
+ i = w83627ehf_read_value(client, W83627EHF_REG_DIODE);
+ data->fan_div[3] = i & 0x03;
+ data->fan_div[4] = ((i >> 2) & 0x03)
+ | ((i >> 5) & 0x04);
+ }
+ if (data->has_fan & (1 << 3)) {
+ i = w83627ehf_read_value(client, W83627EHF_REG_SMI_OVT);
+ data->fan_div[3] |= (i >> 5) & 0x04;
+ }
+
+ /* Measured fan speeds and limits */
+ for (i = 0; i < 5; i++) {
+ if (!(data->has_fan & (1 << i)))
+ continue;
+
+ data->fan[i] = w83627ehf_read_value(client,
+ W83627EHF_REG_FAN[i]);
+ data->fan_min[i] = w83627ehf_read_value(client,
+ W83627EHF_REG_FAN_MIN[i]);
+
+ /* If we failed to measure the fan speed and clock
+ divider can be increased, let's try that for next
+ time */
+ if (data->fan[i] == 0xff
+ && data->fan_div[i] < 0x07) {
+ dev_dbg(&client->dev, "Increasing fan %d "
+ "clock divider from %u to %u\n",
+ i, div_from_reg(data->fan_div[i]),
+ div_from_reg(data->fan_div[i] + 1));
+ data->fan_div[i]++;
+ w83627ehf_write_fan_div(client, i);
+ /* Preserve min limit if possible */
+ if (data->fan_min[i] >= 2
+ && data->fan_min[i] != 255)
+ w83627ehf_write_value(client,
+ W83627EHF_REG_FAN_MIN[i],
+ (data->fan_min[i] /= 2));
+ }
+ }
+
+ /* Measured temperatures and limits */
+ data->temp1 = w83627ehf_read_value(client,
+ W83627EHF_REG_TEMP1);
+ data->temp1_max = w83627ehf_read_value(client,
+ W83627EHF_REG_TEMP1_OVER);
+ data->temp1_max_hyst = w83627ehf_read_value(client,
+ W83627EHF_REG_TEMP1_HYST);
+ for (i = 0; i < 2; i++) {
+ data->temp[i] = w83627ehf_read_value(client,
+ W83627EHF_REG_TEMP[i]);
+ data->temp_max[i] = w83627ehf_read_value(client,
+ W83627EHF_REG_TEMP_OVER[i]);
+ data->temp_max_hyst[i] = w83627ehf_read_value(client,
+ W83627EHF_REG_TEMP_HYST[i]);
+ }
+
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+
+ up(&data->update_lock);
+ return data;
+}
+
+/*
+ * Sysfs callback functions
+ */
+
+#define show_fan_reg(reg) \
+static ssize_t \
+show_##reg(struct device *dev, char *buf, int nr) \
+{ \
+ struct w83627ehf_data *data = w83627ehf_update_device(dev); \
+ return sprintf(buf, "%d\n", \
+ fan_from_reg(data->reg[nr], \
+ div_from_reg(data->fan_div[nr]))); \
+}
+show_fan_reg(fan);
+show_fan_reg(fan_min);
+
+static ssize_t
+show_fan_div(struct device *dev, char *buf, int nr)
+{
+ struct w83627ehf_data *data = w83627ehf_update_device(dev);
+ return sprintf(buf, "%u\n",
+ div_from_reg(data->fan_div[nr]));
+}
+
+static ssize_t
+store_fan_min(struct device *dev, const char *buf, size_t count, int nr)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83627ehf_data *data = i2c_get_clientdata(client);
+ unsigned int val = simple_strtoul(buf, NULL, 10);
+ unsigned int reg;
+ u8 new_div;
+
+ down(&data->update_lock);
+ if (!val) {
+ /* No min limit, alarm disabled */
+ data->fan_min[nr] = 255;
+ new_div = data->fan_div[nr]; /* No change */
+ dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
+ } else if ((reg = 1350000U / val) >= 128 * 255) {
+ /* Speed below this value cannot possibly be represented,
+ even with the highest divider (128) */
+ data->fan_min[nr] = 254;
+ new_div = 7; /* 128 == (1 << 7) */
+ dev_warn(dev, "fan%u low limit %u below minimum %u, set to "
+ "minimum\n", nr + 1, val, fan_from_reg(254, 128));
+ } else if (!reg) {
+ /* Speed above this value cannot possibly be represented,
+ even with the lowest divider (1) */
+ data->fan_min[nr] = 1;
+ new_div = 0; /* 1 == (1 << 0) */
+ dev_warn(dev, "fan%u low limit %u above maximum %u, set to "
+ "maximum\n", nr + 1, val, fan_from_reg(1, 1));
+ } else {
+ /* Automatically pick the best divider, i.e. the one such
+ that the min limit will correspond to a register value
+ in the 96..192 range */
+ new_div = 0;
+ while (reg > 192 && new_div < 7) {
+ reg >>= 1;
+ new_div++;
+ }
+ data->fan_min[nr] = reg;
+ }
+
+ /* Write both the fan clock divider (if it changed) and the new
+ fan min (unconditionally) */
+ if (new_div != data->fan_div[nr]) {
+ if (new_div > data->fan_div[nr])
+ data->fan[nr] >>= (data->fan_div[nr] - new_div);
+ else
+ data->fan[nr] <<= (new_div - data->fan_div[nr]);
+
+ dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
+ nr + 1, div_from_reg(data->fan_div[nr]),
+ div_from_reg(new_div));
+ data->fan_div[nr] = new_div;
+ w83627ehf_write_fan_div(client, nr);
+ }
+ w83627ehf_write_value(client, W83627EHF_REG_FAN_MIN[nr],
+ data->fan_min[nr]);
+ up(&data->update_lock);
+
+ return count;
+}
+
+#define sysfs_fan_offset(offset) \
+static ssize_t \
+show_reg_fan_##offset(struct device *dev, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ return show_fan(dev, buf, offset-1); \
+} \
+static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
+ show_reg_fan_##offset, NULL);
+
+#define sysfs_fan_min_offset(offset) \
+static ssize_t \
+show_reg_fan##offset##_min(struct device *dev, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ return show_fan_min(dev, buf, offset-1); \
+} \
+static ssize_t \
+store_reg_fan##offset##_min(struct device *dev, struct device_attribute *attr, \
+ const char *buf, size_t count) \
+{ \
+ return store_fan_min(dev, buf, count, offset-1); \
+} \
+static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
+ show_reg_fan##offset##_min, \
+ store_reg_fan##offset##_min);
+
+#define sysfs_fan_div_offset(offset) \
+static ssize_t \
+show_reg_fan##offset##_div(struct device *dev, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ return show_fan_div(dev, buf, offset - 1); \
+} \
+static DEVICE_ATTR(fan##offset##_div, S_IRUGO, \
+ show_reg_fan##offset##_div, NULL);
+
+sysfs_fan_offset(1);
+sysfs_fan_min_offset(1);
+sysfs_fan_div_offset(1);
+sysfs_fan_offset(2);
+sysfs_fan_min_offset(2);
+sysfs_fan_div_offset(2);
+sysfs_fan_offset(3);
+sysfs_fan_min_offset(3);
+sysfs_fan_div_offset(3);
+sysfs_fan_offset(4);
+sysfs_fan_min_offset(4);
+sysfs_fan_div_offset(4);
+sysfs_fan_offset(5);
+sysfs_fan_min_offset(5);
+sysfs_fan_div_offset(5);
+
+#define show_temp1_reg(reg) \
+static ssize_t \
+show_##reg(struct device *dev, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct w83627ehf_data *data = w83627ehf_update_device(dev); \
+ return sprintf(buf, "%d\n", temp1_from_reg(data->reg)); \
+}
+show_temp1_reg(temp1);
+show_temp1_reg(temp1_max);
+show_temp1_reg(temp1_max_hyst);
+
+#define store_temp1_reg(REG, reg) \
+static ssize_t \
+store_temp1_##reg(struct device *dev, struct device_attribute *attr, \
+ const char *buf, size_t count) \
+{ \
+ struct i2c_client *client = to_i2c_client(dev); \
+ struct w83627ehf_data *data = i2c_get_clientdata(client); \
+ u32 val = simple_strtoul(buf, NULL, 10); \
+ \
+ down(&data->update_lock); \
+ data->temp1_##reg = temp1_to_reg(val); \
+ w83627ehf_write_value(client, W83627EHF_REG_TEMP1_##REG, \
+ data->temp1_##reg); \
+ up(&data->update_lock); \
+ return count; \
+}
+store_temp1_reg(OVER, max);
+store_temp1_reg(HYST, max_hyst);
+
+static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp1, NULL);
+static DEVICE_ATTR(temp1_max, S_IRUGO| S_IWUSR,
+ show_temp1_max, store_temp1_max);
+static DEVICE_ATTR(temp1_max_hyst, S_IRUGO| S_IWUSR,
+ show_temp1_max_hyst, store_temp1_max_hyst);
+
+#define show_temp_reg(reg) \
+static ssize_t \
+show_##reg (struct device *dev, char *buf, int nr) \
+{ \
+ struct w83627ehf_data *data = w83627ehf_update_device(dev); \
+ return sprintf(buf, "%d\n", \
+ LM75_TEMP_FROM_REG(data->reg[nr])); \
+}
+show_temp_reg(temp);
+show_temp_reg(temp_max);
+show_temp_reg(temp_max_hyst);
+
+#define store_temp_reg(REG, reg) \
+static ssize_t \
+store_##reg (struct device *dev, const char *buf, size_t count, int nr) \
+{ \
+ struct i2c_client *client = to_i2c_client(dev); \
+ struct w83627ehf_data *data = i2c_get_clientdata(client); \
+ u32 val = simple_strtoul(buf, NULL, 10); \
+ \
+ down(&data->update_lock); \
+ data->reg[nr] = LM75_TEMP_TO_REG(val); \
+ w83627ehf_write_value(client, W83627EHF_REG_TEMP_##REG[nr], \
+ data->reg[nr]); \
+ up(&data->update_lock); \
+ return count; \
+}
+store_temp_reg(OVER, temp_max);
+store_temp_reg(HYST, temp_max_hyst);
+
+#define sysfs_temp_offset(offset) \
+static ssize_t \
+show_reg_temp##offset (struct device *dev, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ return show_temp(dev, buf, offset - 2); \
+} \
+static DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
+ show_reg_temp##offset, NULL);
+
+#define sysfs_temp_reg_offset(reg, offset) \
+static ssize_t \
+show_reg_temp##offset##_##reg(struct device *dev, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ return show_temp_##reg(dev, buf, offset - 2); \
+} \
+static ssize_t \
+store_reg_temp##offset##_##reg(struct device *dev, struct device_attribute *attr, \
+ const char *buf, size_t count) \
+{ \
+ return store_temp_##reg(dev, buf, count, offset - 2); \
+} \
+static DEVICE_ATTR(temp##offset##_##reg, S_IRUGO| S_IWUSR, \
+ show_reg_temp##offset##_##reg, \
+ store_reg_temp##offset##_##reg);
+
+sysfs_temp_offset(2);
+sysfs_temp_reg_offset(max, 2);
+sysfs_temp_reg_offset(max_hyst, 2);
+sysfs_temp_offset(3);
+sysfs_temp_reg_offset(max, 3);
+sysfs_temp_reg_offset(max_hyst, 3);
+
+/*
+ * Driver and client management
+ */
+
+static struct i2c_driver w83627ehf_driver;
+
+static void w83627ehf_init_client(struct i2c_client *client)
+{
+ int i;
+ u8 tmp;
+
+ /* Start monitoring is needed */
+ tmp = w83627ehf_read_value(client, W83627EHF_REG_CONFIG);
+ if (!(tmp & 0x01))
+ w83627ehf_write_value(client, W83627EHF_REG_CONFIG,
+ tmp | 0x01);
+
+ /* Enable temp2 and temp3 if needed */
+ for (i = 0; i < 2; i++) {
+ tmp = w83627ehf_read_value(client,
+ W83627EHF_REG_TEMP_CONFIG[i]);
+ if (tmp & 0x01)
+ w83627ehf_write_value(client,
+ W83627EHF_REG_TEMP_CONFIG[i],
+ tmp & 0xfe);
+ }
+}
+
+static int w83627ehf_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+ struct i2c_client *client;
+ struct w83627ehf_data *data;
+ int i, err = 0;
+
+ if (!i2c_is_isa_adapter(adapter))
+ return 0;
+
+ if (!request_region(address, REGION_LENGTH, w83627ehf_driver.name)) {
+ err = -EBUSY;
+ goto exit;
+ }
+
+ if (!(data = kmalloc(sizeof(struct w83627ehf_data), GFP_KERNEL))) {
+ err = -ENOMEM;
+ goto exit_release;
+ }
+ memset(data, 0, sizeof(struct w83627ehf_data));
+
+ client = &data->client;
+ i2c_set_clientdata(client, data);
+ client->addr = address;
+ init_MUTEX(&data->lock);
+ client->adapter = adapter;
+ client->driver = &w83627ehf_driver;
+ client->flags = 0;
+
+ strlcpy(client->name, "w83627ehf", I2C_NAME_SIZE);
+ data->valid = 0;
+ init_MUTEX(&data->update_lock);
+
+ /* Tell the i2c layer a new client has arrived */
+ if ((err = i2c_attach_client(client)))
+ goto exit_free;
+
+ /* Initialize the chip */
+ w83627ehf_init_client(client);
+
+ /* A few vars need to be filled upon startup */
+ for (i = 0; i < 5; i++)
+ data->fan_min[i] = w83627ehf_read_value(client,
+ W83627EHF_REG_FAN_MIN[i]);
+
+ /* It looks like fan4 and fan5 pins can be alternatively used
+ as fan on/off switches */
+ data->has_fan = 0x07; /* fan1, fan2 and fan3 */
+ i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1);
+ if (i & (1 << 2))
+ data->has_fan |= (1 << 3);
+ if (i & (1 << 0))
+ data->has_fan |= (1 << 4);
+
+ /* Register sysfs hooks */
+ device_create_file(&client->dev, &dev_attr_fan1_input);
+ device_create_file(&client->dev, &dev_attr_fan1_min);
+ device_create_file(&client->dev, &dev_attr_fan1_div);
+ device_create_file(&client->dev, &dev_attr_fan2_input);
+ device_create_file(&client->dev, &dev_attr_fan2_min);
+ device_create_file(&client->dev, &dev_attr_fan2_div);
+ device_create_file(&client->dev, &dev_attr_fan3_input);
+ device_create_file(&client->dev, &dev_attr_fan3_min);
+ device_create_file(&client->dev, &dev_attr_fan3_div);
+
+ if (data->has_fan & (1 << 3)) {
+ device_create_file(&client->dev, &dev_attr_fan4_input);
+ device_create_file(&client->dev, &dev_attr_fan4_min);
+ device_create_file(&client->dev, &dev_attr_fan4_div);
+ }
+ if (data->has_fan & (1 << 4)) {
+ device_create_file(&client->dev, &dev_attr_fan5_input);
+ device_create_file(&client->dev, &dev_attr_fan5_min);
+ device_create_file(&client->dev, &dev_attr_fan5_div);
+ }
+
+ device_create_file(&client->dev, &dev_attr_temp1_input);
+ device_create_file(&client->dev, &dev_attr_temp1_max);
+ device_create_file(&client->dev, &dev_attr_temp1_max_hyst);
+ device_create_file(&client->dev, &dev_attr_temp2_input);
+ device_create_file(&client->dev, &dev_attr_temp2_max);
+ device_create_file(&client->dev, &dev_attr_temp2_max_hyst);
+ device_create_file(&client->dev, &dev_attr_temp3_input);
+ device_create_file(&client->dev, &dev_attr_temp3_max);
+ device_create_file(&client->dev, &dev_attr_temp3_max_hyst);
+
+ return 0;
+
+exit_free:
+ kfree(data);
+exit_release:
+ release_region(address, REGION_LENGTH);
+exit:
+ return err;
+}
+
+static int w83627ehf_attach_adapter(struct i2c_adapter *adapter)
+{
+ if (!(adapter->class & I2C_CLASS_HWMON))
+ return 0;
+ return i2c_detect(adapter, &addr_data, w83627ehf_detect);
+}
+
+static int w83627ehf_detach_client(struct i2c_client *client)
+{
+ int err;
+
+ if ((err = i2c_detach_client(client))) {
+ dev_err(&client->dev, "Client deregistration failed, "
+ "client not detached.\n");
+ return err;
+ }
+ release_region(client->addr, REGION_LENGTH);
+ kfree(i2c_get_clientdata(client));
+
+ return 0;
+}
+
+static struct i2c_driver w83627ehf_driver = {
+ .owner = THIS_MODULE,
+ .name = "w83627ehf",
+ .flags = I2C_DF_NOTIFY,
+ .attach_adapter = w83627ehf_attach_adapter,
+ .detach_client = w83627ehf_detach_client,
+};
+
+static int __init w83627ehf_find(int sioaddr, int *address)
+{
+ u16 val;
+
+ REG = sioaddr;
+ VAL = sioaddr + 1;
+ superio_enter();
+
+ val = (superio_inb(SIO_REG_DEVID) << 8)
+ | superio_inb(SIO_REG_DEVID + 1);
+ if ((val & SIO_ID_MASK) != SIO_W83627EHF_ID) {
+ superio_exit();
+ return -ENODEV;
+ }
+
+ superio_select(W83627EHF_LD_HWM);
+ val = (superio_inb(SIO_REG_ADDR) << 8)
+ | superio_inb(SIO_REG_ADDR + 1);
+ *address = val & ~(REGION_LENGTH - 1);
+ if (*address == 0) {
+ superio_exit();
+ return -ENODEV;
+ }
+
+ /* Activate logical device if needed */
+ val = superio_inb(SIO_REG_ENABLE);
+ if (!(val & 0x01))
+ superio_outb(SIO_REG_ENABLE, val | 0x01);
+
+ superio_exit();
+ return 0;
+}
+
+static int __init sensors_w83627ehf_init(void)
+{
+ if (w83627ehf_find(0x2e, &normal_isa[0])
+ && w83627ehf_find(0x4e, &normal_isa[0]))
+ return -ENODEV;
+
+ return i2c_add_driver(&w83627ehf_driver);
+}
+
+static void __exit sensors_w83627ehf_exit(void)
+{
+ i2c_del_driver(&w83627ehf_driver);
+}
+
+MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
+MODULE_DESCRIPTION("W83627EHF driver");
+MODULE_LICENSE("GPL");
+
+module_init(sensors_w83627ehf_init);
+module_exit(sensors_w83627ehf_exit);
{
int i;
val = SENSORS_LIMIT(val, 1, 128) >> 1;
- for (i = 0; i < 6; i++) {
+ for (i = 0; i < 7; i++) {
if (val == 0)
break;
val >>= 1;
as99127f rev.2 (type_name = as99127f) 0x31 0x5ca3 yes no
w83781d 7 3 0 3 0x10-1 0x5ca3 yes yes
w83627hf 9 3 2 3 0x21 0x5ca3 yes yes(LPC)
- w83627thf 9 3 2 3 0x90 0x5ca3 no yes(LPC)
w83782d 9 3 2-4 3 0x30 0x5ca3 yes yes
w83783s 5-6 3 2 1-2 0x40 0x5ca3 yes no
- w83697hf 8 2 2 2 0x60 0x5ca3 no yes(LPC)
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
static unsigned int normal_isa[] = { 0x0290, I2C_CLIENT_ISA_END };
/* Insmod parameters */
-SENSORS_INSMOD_6(w83781d, w83782d, w83783s, w83627hf, as99127f, w83697hf);
+SENSORS_INSMOD_5(w83781d, w83782d, w83783s, w83627hf, as99127f);
I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: "
"{bus, clientaddr, subclientaddr1, subclientaddr2}");
: (val)) / 1000, 0, 0xff))
#define TEMP_FROM_REG(val) (((val) & 0x80 ? (val)-0x100 : (val)) * 1000)
-#define ALARMS_FROM_REG(val) (val)
#define PWM_FROM_REG(val) (val)
#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255))
#define BEEP_MASK_FROM_REG(val,type) ((type) == as99127f ? \
val = SENSORS_LIMIT(val, 1,
((type == w83781d
|| type == as99127f) ? 8 : 128)) >> 1;
- for (i = 0; i < 6; i++) {
+ for (i = 0; i < 7; i++) {
if (val == 0)
break;
val >>= 1;
show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
{
struct w83781d_data *data = w83781d_update_device(dev);
- return sprintf(buf, "%ld\n", (long) ALARMS_FROM_REG(data->alarms));
+ return sprintf(buf, "%u\n", data->alarms);
}
static
err = -EINVAL;
goto ERROR0;
}
- if (!is_isa && kind == w83697hf) {
- dev_err(&adapter->dev,
- "Cannot force ISA-only chip for I2C address 0x%02x.\n",
- address);
- err = -EINVAL;
- goto ERROR0;
- }
if (is_isa)
if (!request_region(address, W83781D_EXTENT,
else if (val1 == 0x40 && vendid == winbond && !is_isa
&& address == 0x2d)
kind = w83783s;
- else if ((val1 == 0x21 || val1 == 0x90) && vendid == winbond)
+ else if (val1 == 0x21 && vendid == winbond)
kind = w83627hf;
else if (val1 == 0x31 && !is_isa && address >= 0x28)
kind = as99127f;
- else if (val1 == 0x60 && vendid == winbond && is_isa)
- kind = w83697hf;
else {
if (kind == 0)
dev_warn(&new_client->dev, "Ignoring 'force' "
} else if (kind == w83783s) {
client_name = "w83783s";
} else if (kind == w83627hf) {
- if (val1 == 0x90)
- client_name = "w83627thf";
- else
- client_name = "w83627hf";
+ client_name = "w83627hf";
} else if (kind == as99127f) {
client_name = "as99127f";
- } else if (kind == w83697hf) {
- client_name = "w83697hf";
}
/* Fill in the remaining client fields and put into the global list */
/* Register sysfs hooks */
device_create_file_in(new_client, 0);
- if (kind != w83783s && kind != w83697hf)
+ if (kind != w83783s)
device_create_file_in(new_client, 1);
device_create_file_in(new_client, 2);
device_create_file_in(new_client, 3);
device_create_file_fan(new_client, 1);
device_create_file_fan(new_client, 2);
- if (kind != w83697hf)
- device_create_file_fan(new_client, 3);
+ device_create_file_fan(new_client, 3);
device_create_file_temp(new_client, 1);
device_create_file_temp(new_client, 2);
- if (kind != w83783s && kind != w83697hf)
+ if (kind != w83783s)
device_create_file_temp(new_client, 3);
- if (kind != w83697hf)
- device_create_file_vid(new_client);
-
- if (kind != w83697hf)
- device_create_file_vrm(new_client);
+ device_create_file_vid(new_client);
+ device_create_file_vrm(new_client);
device_create_file_fan_div(new_client, 1);
device_create_file_fan_div(new_client, 2);
- if (kind != w83697hf)
- device_create_file_fan_div(new_client, 3);
+ device_create_file_fan_div(new_client, 3);
device_create_file_alarms(new_client);
if (kind != as99127f && kind != w83781d) {
device_create_file_sensor(new_client, 1);
device_create_file_sensor(new_client, 2);
- if (kind != w83783s && kind != w83697hf)
+ if (kind != w83783s)
device_create_file_sensor(new_client, 3);
}
else
data->sens[i - 1] = 2;
}
- if ((type == w83783s || type == w83697hf) && (i == 2))
+ if (type == w83783s && i == 2)
break;
}
}
}
/* Enable temp3 */
- if (type != w83783s && type != w83697hf) {
+ if (type != w83783s) {
tmp = w83781d_read_value(client,
W83781D_REG_TEMP3_CONFIG);
if (tmp & 0x01) {
dev_dbg(dev, "Starting device update\n");
for (i = 0; i <= 8; i++) {
- if ((data->type == w83783s || data->type == w83697hf)
- && (i == 1))
+ if (data->type == w83783s && i == 1)
continue; /* 783S has no in1 */
data->in[i] =
w83781d_read_value(client, W83781D_REG_IN(i));
w83781d_read_value(client, W83781D_REG_IN_MIN(i));
data->in_max[i] =
w83781d_read_value(client, W83781D_REG_IN_MAX(i));
- if ((data->type != w83782d) && (data->type != w83697hf)
+ if ((data->type != w83782d)
&& (data->type != w83627hf) && (i == 6))
break;
}
w83781d_read_value(client, W83781D_REG_TEMP_OVER(2));
data->temp_max_hyst_add[0] =
w83781d_read_value(client, W83781D_REG_TEMP_HYST(2));
- if (data->type != w83783s && data->type != w83697hf) {
+ if (data->type != w83783s) {
data->temp_add[1] =
w83781d_read_value(client, W83781D_REG_TEMP(3));
data->temp_max_add[1] =
W83781D_REG_TEMP_HYST(3));
}
i = w83781d_read_value(client, W83781D_REG_VID_FANDIV);
- if (data->type != w83697hf) {
- data->vid = i & 0x0f;
- data->vid |=
- (w83781d_read_value(client, W83781D_REG_CHIPID) &
- 0x01)
- << 4;
- }
+ data->vid = i & 0x0f;
+ data->vid |= (w83781d_read_value(client,
+ W83781D_REG_CHIPID) & 0x01) << 4;
data->fan_div[0] = (i >> 4) & 0x03;
data->fan_div[1] = (i >> 6) & 0x03;
- if (data->type != w83697hf) {
- data->fan_div[2] = (w83781d_read_value(client,
- W83781D_REG_PIN)
- >> 6) & 0x03;
- }
+ data->fan_div[2] = (w83781d_read_value(client,
+ W83781D_REG_PIN) >> 6) & 0x03;
if ((data->type != w83781d) && (data->type != as99127f)) {
i = w83781d_read_value(client, W83781D_REG_VBAT);
data->fan_div[0] |= (i >> 3) & 0x04;
data->fan_div[1] |= (i >> 4) & 0x04;
- if (data->type != w83697hf)
- data->fan_div[2] |= (i >> 5) & 0x04;
+ data->fan_div[2] |= (i >> 5) & 0x04;
}
data->alarms =
w83781d_read_value(client,
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/init.h>
All SMBus-related things are written by Frodo Looijaard <frodol@dds.nl>
SMBus 2.0 support by Mark Studebaker <mdsxyz123@yahoo.com> */
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
}
/* detach any active clients. This must be done first, because
- * it can fail; in which case we give upp. */
+ * it can fail; in which case we give up. */
list_for_each_safe(item, _n, &adap->clients) {
client = list_entry(item, struct i2c_client, list);
struct i2c_adapter *adap=client->adapter;
struct i2c_msg msg;
- if (client->adapter->algo->master_xfer) {
- msg.addr = client->addr;
- msg.flags = client->flags & I2C_M_TEN;
- msg.len = count;
- msg.buf = (char *)buf;
+ msg.addr = client->addr;
+ msg.flags = client->flags & I2C_M_TEN;
+ msg.len = count;
+ msg.buf = (char *)buf;
- dev_dbg(&client->adapter->dev, "master_send: writing %d bytes.\n",
- count);
-
- down(&adap->bus_lock);
- ret = adap->algo->master_xfer(adap,&msg,1);
- up(&adap->bus_lock);
+ ret = i2c_transfer(adap, &msg, 1);
- /* if everything went ok (i.e. 1 msg transmitted), return #bytes
- * transmitted, else error code.
- */
- return (ret == 1 )? count : ret;
- } else {
- dev_err(&client->adapter->dev, "I2C level transfers not supported\n");
- return -ENOSYS;
- }
+ /* If everything went ok (i.e. 1 msg transmitted), return #bytes
+ transmitted, else error code. */
+ return (ret == 1) ? count : ret;
}
int i2c_master_recv(struct i2c_client *client, char *buf ,int count)
struct i2c_adapter *adap=client->adapter;
struct i2c_msg msg;
int ret;
- if (client->adapter->algo->master_xfer) {
- msg.addr = client->addr;
- msg.flags = client->flags & I2C_M_TEN;
- msg.flags |= I2C_M_RD;
- msg.len = count;
- msg.buf = buf;
-
- dev_dbg(&client->adapter->dev, "master_recv: reading %d bytes.\n",
- count);
-
- down(&adap->bus_lock);
- ret = adap->algo->master_xfer(adap,&msg,1);
- up(&adap->bus_lock);
-
- dev_dbg(&client->adapter->dev, "master_recv: return:%d (count:%d, addr:0x%02x)\n",
- ret, count, client->addr);
-
- /* if everything went ok (i.e. 1 msg transmitted), return #bytes
- * transmitted, else error code.
- */
- return (ret == 1 )? count : ret;
- } else {
- dev_err(&client->adapter->dev, "I2C level transfers not supported\n");
- return -ENOSYS;
- }
+
+ msg.addr = client->addr;
+ msg.flags = client->flags & I2C_M_TEN;
+ msg.flags |= I2C_M_RD;
+ msg.len = count;
+ msg.buf = buf;
+
+ ret = i2c_transfer(adap, &msg, 1);
+
+ /* If everything went ok (i.e. 1 msg transmitted), return #bytes
+ transmitted, else error code. */
+ return (ret == 1) ? count : ret;
}
found = 1;
}
}
- for (i = 0;
- !found && (address_data->ignore_range[i] != I2C_CLIENT_END);
- i += 3) {
- if (((adap_id == address_data->ignore_range[i]) ||
- ((address_data->ignore_range[i]==ANY_I2C_BUS))) &&
- (addr >= address_data->ignore_range[i+1]) &&
- (addr <= address_data->ignore_range[i+2])) {
- dev_dbg(&adapter->dev, "found ignore_range parameter for adapter %d, "
- "addr %04x\n", adap_id,addr);
- found = 1;
- }
- }
if (found)
continue;
}
}
- for (i = 0;
- !found && (address_data->normal_i2c_range[i] != I2C_CLIENT_END);
- i += 2) {
- if ((addr >= address_data->normal_i2c_range[i]) &&
- (addr <= address_data->normal_i2c_range[i+1])) {
- found = 1;
- dev_dbg(&adapter->dev, "found normal i2c_range entry for adapter %d, "
- "addr %04x\n", adap_id,addr);
- }
- }
-
for (i = 0;
!found && (address_data->probe[i] != I2C_CLIENT_END);
i += 2) {
"addr %04x\n", adap_id,addr);
}
}
- for (i = 0;
- !found && (address_data->probe_range[i] != I2C_CLIENT_END);
- i += 3) {
- if (((adap_id == address_data->probe_range[i]) ||
- (address_data->probe_range[i] == ANY_I2C_BUS)) &&
- (addr >= address_data->probe_range[i+1]) &&
- (addr <= address_data->probe_range[i+2])) {
- found = 1;
- dev_dbg(&adapter->dev, "found probe_range parameter for adapter %d, "
- "addr %04x\n", adap_id,addr);
- }
- }
if (!found)
continue;
/* The devfs code is contributed by Philipp Matthias Hahn
<pmhahn@titan.lahn.de> */
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
sizeof(rdwr_arg)))
return -EFAULT;
- /* Put an arbritrary limit on the number of messages that can
+ /* Put an arbitrary limit on the number of messages that can
* be sent at once */
if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS)
return -EINVAL;
chipsets.
config BLK_DEV_SGIIOC4
- tristate "Silicon Graphics IOC4 chipset support"
- depends on IA64_SGI_SN2 || IA64_GENERIC
+ tristate "Silicon Graphics IOC4 chipset ATA/ATAPI support"
+ depends on (IA64_SGI_SN2 || IA64_GENERIC) && SGI_IOC4
help
This driver adds PIO & MultiMode DMA-2 support for the SGI IOC4
chipset, which has one channel and can support two devices.
#include <linux/mm.h>
#include <linux/ioport.h>
#include <linux/blkdev.h>
-#include <linux/ioc4_common.h>
+#include <linux/ioc4.h>
#include <asm/io.h>
#include <linux/ide.h>
};
int
-ioc4_ide_attach_one(struct pci_dev *dev, const struct pci_device_id *id)
+ioc4_ide_attach_one(struct ioc4_driver_data *idd)
{
- return pci_init_sgiioc4(dev, &sgiioc4_chipsets[id->driver_data]);
+ return pci_init_sgiioc4(idd->idd_pdev,
+ &sgiioc4_chipsets[idd->idd_pci_id->driver_data]);
}
+static struct ioc4_submodule ioc4_ide_submodule = {
+ .is_name = "IOC4_ide",
+ .is_owner = THIS_MODULE,
+ .is_probe = ioc4_ide_attach_one,
+/* .is_remove = ioc4_ide_remove_one, */
+};
+
+static int __devinit
+ioc4_ide_init(void)
+{
+ return ioc4_register_submodule(&ioc4_ide_submodule);
+}
+
+static void __devexit
+ioc4_ide_exit(void)
+{
+ ioc4_unregister_submodule(&ioc4_ide_submodule);
+}
+
+module_init(ioc4_ide_init);
+module_exit(ioc4_ide_exit);
MODULE_AUTHOR("Aniket Malatpure - Silicon Graphics Inc. (SGI)");
MODULE_DESCRIPTION("IDE PCI driver module for SGI IOC4 Base-IO Card");
MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(ioc4_ide_attach_one);
}
gameport_close(gameport);
- return (cpu_data[_smp_processor_id()].loops_per_jiffy * (unsigned long)HZ / (1000 / 50)) / (tx < 1 ? 1 : tx);
+ return (cpu_data[raw_smp_processor_id()].loops_per_jiffy * (unsigned long)HZ / (1000 / 50)) / (tx < 1 ? 1 : tx);
#else
static int do_probe( struct i2c_adapter *adapter, int addr, int kind);
/* scan 0x48-0x4f (DS1775) and 0x2c-2x2f (ADM1030) */
-static unsigned short normal_i2c[] = { 0x49, 0x2c, I2C_CLIENT_END };
-static unsigned short normal_i2c_range[] = { 0x48, 0x4f, 0x2c, 0x2f, I2C_CLIENT_END };
+static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
+ 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x2c, 0x2d, 0x2e, 0x2f,
+ I2C_CLIENT_END };
I2C_CLIENT_INSMOD;
dm-multipath-objs := dm-hw-handler.o dm-path-selector.o dm-mpath.o
dm-snapshot-objs := dm-snap.o dm-exception-store.o
dm-mirror-objs := dm-log.o dm-raid1.o
+md-mod-objs := md.o bitmap.o
raid6-objs := raid6main.o raid6algos.o raid6recov.o raid6tables.o \
raid6int1.o raid6int2.o raid6int4.o \
raid6int8.o raid6int16.o raid6int32.o \
obj-$(CONFIG_MD_RAID6) += raid6.o xor.o
obj-$(CONFIG_MD_MULTIPATH) += multipath.o
obj-$(CONFIG_MD_FAULTY) += faulty.o
-obj-$(CONFIG_BLK_DEV_MD) += md.o
+obj-$(CONFIG_BLK_DEV_MD) += md-mod.o
obj-$(CONFIG_BLK_DEV_DM) += dm-mod.o
obj-$(CONFIG_DM_CRYPT) += dm-crypt.o
obj-$(CONFIG_DM_MULTIPATH) += dm-multipath.o dm-round-robin.o
--- /dev/null
+/*
+ * bitmap.c two-level bitmap (C) Peter T. Breuer (ptb@ot.uc3m.es) 2003
+ *
+ * bitmap_create - sets up the bitmap structure
+ * bitmap_destroy - destroys the bitmap structure
+ *
+ * additions, Copyright (C) 2003-2004, Paul Clements, SteelEye Technology, Inc.:
+ * - added disk storage for bitmap
+ * - changes to allow various bitmap chunk sizes
+ * - added bitmap daemon (to asynchronously clear bitmap bits from disk)
+ */
+
+/*
+ * Still to do:
+ *
+ * flush after percent set rather than just time based. (maybe both).
+ * wait if count gets too high, wake when it drops to half.
+ * allow bitmap to be mirrored with superblock (before or after...)
+ * allow hot-add to re-instate a current device.
+ * allow hot-add of bitmap after quiessing device
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/config.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/file.h>
+#include <linux/mount.h>
+#include <linux/buffer_head.h>
+#include <linux/raid/md.h>
+#include <linux/raid/bitmap.h>
+
+/* debug macros */
+
+#define DEBUG 0
+
+#if DEBUG
+/* these are for debugging purposes only! */
+
+/* define one and only one of these */
+#define INJECT_FAULTS_1 0 /* cause bitmap_alloc_page to fail always */
+#define INJECT_FAULTS_2 0 /* cause bitmap file to be kicked when first bit set*/
+#define INJECT_FAULTS_3 0 /* treat bitmap file as kicked at init time */
+#define INJECT_FAULTS_4 0 /* undef */
+#define INJECT_FAULTS_5 0 /* undef */
+#define INJECT_FAULTS_6 0
+
+/* if these are defined, the driver will fail! debug only */
+#define INJECT_FATAL_FAULT_1 0 /* fail kmalloc, causing bitmap_create to fail */
+#define INJECT_FATAL_FAULT_2 0 /* undef */
+#define INJECT_FATAL_FAULT_3 0 /* undef */
+#endif
+
+//#define DPRINTK PRINTK /* set this NULL to avoid verbose debug output */
+#define DPRINTK(x...) do { } while(0)
+
+#ifndef PRINTK
+# if DEBUG > 0
+# define PRINTK(x...) printk(KERN_DEBUG x)
+# else
+# define PRINTK(x...)
+# endif
+#endif
+
+static inline char * bmname(struct bitmap *bitmap)
+{
+ return bitmap->mddev ? mdname(bitmap->mddev) : "mdX";
+}
+
+
+/*
+ * test if the bitmap is active
+ */
+int bitmap_active(struct bitmap *bitmap)
+{
+ unsigned long flags;
+ int res = 0;
+
+ if (!bitmap)
+ return res;
+ spin_lock_irqsave(&bitmap->lock, flags);
+ res = bitmap->flags & BITMAP_ACTIVE;
+ spin_unlock_irqrestore(&bitmap->lock, flags);
+ return res;
+}
+
+#define WRITE_POOL_SIZE 256
+/* mempool for queueing pending writes on the bitmap file */
+static void *write_pool_alloc(unsigned int gfp_flags, void *data)
+{
+ return kmalloc(sizeof(struct page_list), gfp_flags);
+}
+
+static void write_pool_free(void *ptr, void *data)
+{
+ kfree(ptr);
+}
+
+/*
+ * just a placeholder - calls kmalloc for bitmap pages
+ */
+static unsigned char *bitmap_alloc_page(struct bitmap *bitmap)
+{
+ unsigned char *page;
+
+#if INJECT_FAULTS_1
+ page = NULL;
+#else
+ page = kmalloc(PAGE_SIZE, GFP_NOIO);
+#endif
+ if (!page)
+ printk("%s: bitmap_alloc_page FAILED\n", bmname(bitmap));
+ else
+ PRINTK("%s: bitmap_alloc_page: allocated page at %p\n",
+ bmname(bitmap), page);
+ return page;
+}
+
+/*
+ * for now just a placeholder -- just calls kfree for bitmap pages
+ */
+static void bitmap_free_page(struct bitmap *bitmap, unsigned char *page)
+{
+ PRINTK("%s: bitmap_free_page: free page %p\n", bmname(bitmap), page);
+ kfree(page);
+}
+
+/*
+ * check a page and, if necessary, allocate it (or hijack it if the alloc fails)
+ *
+ * 1) check to see if this page is allocated, if it's not then try to alloc
+ * 2) if the alloc fails, set the page's hijacked flag so we'll use the
+ * page pointer directly as a counter
+ *
+ * if we find our page, we increment the page's refcount so that it stays
+ * allocated while we're using it
+ */
+static int bitmap_checkpage(struct bitmap *bitmap, unsigned long page, int create)
+{
+ unsigned char *mappage;
+
+ if (page >= bitmap->pages) {
+ printk(KERN_ALERT
+ "%s: invalid bitmap page request: %lu (> %lu)\n",
+ bmname(bitmap), page, bitmap->pages-1);
+ return -EINVAL;
+ }
+
+
+ if (bitmap->bp[page].hijacked) /* it's hijacked, don't try to alloc */
+ return 0;
+
+ if (bitmap->bp[page].map) /* page is already allocated, just return */
+ return 0;
+
+ if (!create)
+ return -ENOENT;
+
+ spin_unlock_irq(&bitmap->lock);
+
+ /* this page has not been allocated yet */
+
+ if ((mappage = bitmap_alloc_page(bitmap)) == NULL) {
+ PRINTK("%s: bitmap map page allocation failed, hijacking\n",
+ bmname(bitmap));
+ /* failed - set the hijacked flag so that we can use the
+ * pointer as a counter */
+ spin_lock_irq(&bitmap->lock);
+ if (!bitmap->bp[page].map)
+ bitmap->bp[page].hijacked = 1;
+ goto out;
+ }
+
+ /* got a page */
+
+ spin_lock_irq(&bitmap->lock);
+
+ /* recheck the page */
+
+ if (bitmap->bp[page].map || bitmap->bp[page].hijacked) {
+ /* somebody beat us to getting the page */
+ bitmap_free_page(bitmap, mappage);
+ return 0;
+ }
+
+ /* no page was in place and we have one, so install it */
+
+ memset(mappage, 0, PAGE_SIZE);
+ bitmap->bp[page].map = mappage;
+ bitmap->missing_pages--;
+out:
+ return 0;
+}
+
+
+/* if page is completely empty, put it back on the free list, or dealloc it */
+/* if page was hijacked, unmark the flag so it might get alloced next time */
+/* Note: lock should be held when calling this */
+static inline void bitmap_checkfree(struct bitmap *bitmap, unsigned long page)
+{
+ char *ptr;
+
+ if (bitmap->bp[page].count) /* page is still busy */
+ return;
+
+ /* page is no longer in use, it can be released */
+
+ if (bitmap->bp[page].hijacked) { /* page was hijacked, undo this now */
+ bitmap->bp[page].hijacked = 0;
+ bitmap->bp[page].map = NULL;
+ return;
+ }
+
+ /* normal case, free the page */
+
+#if 0
+/* actually ... let's not. We will probably need the page again exactly when
+ * memory is tight and we are flusing to disk
+ */
+ return;
+#else
+ ptr = bitmap->bp[page].map;
+ bitmap->bp[page].map = NULL;
+ bitmap->missing_pages++;
+ bitmap_free_page(bitmap, ptr);
+ return;
+#endif
+}
+
+
+/*
+ * bitmap file handling - read and write the bitmap file and its superblock
+ */
+
+/* copy the pathname of a file to a buffer */
+char *file_path(struct file *file, char *buf, int count)
+{
+ struct dentry *d;
+ struct vfsmount *v;
+
+ if (!buf)
+ return NULL;
+
+ d = file->f_dentry;
+ v = file->f_vfsmnt;
+
+ buf = d_path(d, v, buf, count);
+
+ return IS_ERR(buf) ? NULL : buf;
+}
+
+/*
+ * basic page I/O operations
+ */
+
+/* IO operations when bitmap is stored near all superblocks */
+static struct page *read_sb_page(mddev_t *mddev, long offset, unsigned long index)
+{
+ /* choose a good rdev and read the page from there */
+
+ mdk_rdev_t *rdev;
+ struct list_head *tmp;
+ struct page *page = alloc_page(GFP_KERNEL);
+ sector_t target;
+
+ if (!page)
+ return ERR_PTR(-ENOMEM);
+ do {
+ ITERATE_RDEV(mddev, rdev, tmp)
+ if (rdev->in_sync && !rdev->faulty)
+ goto found;
+ return ERR_PTR(-EIO);
+
+ found:
+ target = (rdev->sb_offset << 1) + offset + index * (PAGE_SIZE/512);
+
+ } while (!sync_page_io(rdev->bdev, target, PAGE_SIZE, page, READ));
+
+ page->index = index;
+ return page;
+}
+
+static int write_sb_page(mddev_t *mddev, long offset, struct page *page, int wait)
+{
+ mdk_rdev_t *rdev;
+ struct list_head *tmp;
+
+ ITERATE_RDEV(mddev, rdev, tmp)
+ if (rdev->in_sync && !rdev->faulty)
+ md_super_write(mddev, rdev,
+ (rdev->sb_offset<<1) + offset
+ + page->index * (PAGE_SIZE/512),
+ PAGE_SIZE,
+ page);
+
+ if (wait)
+ wait_event(mddev->sb_wait, atomic_read(&mddev->pending_writes)==0);
+ return 0;
+}
+
+/*
+ * write out a page to a file
+ */
+static int write_page(struct bitmap *bitmap, struct page *page, int wait)
+{
+ int ret = -ENOMEM;
+
+ if (bitmap->file == NULL)
+ return write_sb_page(bitmap->mddev, bitmap->offset, page, wait);
+
+ if (wait)
+ lock_page(page);
+ else {
+ if (TestSetPageLocked(page))
+ return -EAGAIN; /* already locked */
+ if (PageWriteback(page)) {
+ unlock_page(page);
+ return -EAGAIN;
+ }
+ }
+
+ ret = page->mapping->a_ops->prepare_write(NULL, page, 0, PAGE_SIZE);
+ if (!ret)
+ ret = page->mapping->a_ops->commit_write(NULL, page, 0,
+ PAGE_SIZE);
+ if (ret) {
+ unlock_page(page);
+ return ret;
+ }
+
+ set_page_dirty(page); /* force it to be written out */
+
+ if (!wait) {
+ /* add to list to be waited for by daemon */
+ struct page_list *item = mempool_alloc(bitmap->write_pool, GFP_NOIO);
+ item->page = page;
+ page_cache_get(page);
+ spin_lock(&bitmap->write_lock);
+ list_add(&item->list, &bitmap->complete_pages);
+ spin_unlock(&bitmap->write_lock);
+ md_wakeup_thread(bitmap->writeback_daemon);
+ }
+ return write_one_page(page, wait);
+}
+
+/* read a page from a file, pinning it into cache, and return bytes_read */
+static struct page *read_page(struct file *file, unsigned long index,
+ unsigned long *bytes_read)
+{
+ struct inode *inode = file->f_mapping->host;
+ struct page *page = NULL;
+ loff_t isize = i_size_read(inode);
+ unsigned long end_index = isize >> PAGE_CACHE_SHIFT;
+
+ PRINTK("read bitmap file (%dB @ %Lu)\n", (int)PAGE_CACHE_SIZE,
+ (unsigned long long)index << PAGE_CACHE_SHIFT);
+
+ page = read_cache_page(inode->i_mapping, index,
+ (filler_t *)inode->i_mapping->a_ops->readpage, file);
+ if (IS_ERR(page))
+ goto out;
+ wait_on_page_locked(page);
+ if (!PageUptodate(page) || PageError(page)) {
+ page_cache_release(page);
+ page = ERR_PTR(-EIO);
+ goto out;
+ }
+
+ if (index > end_index) /* we have read beyond EOF */
+ *bytes_read = 0;
+ else if (index == end_index) /* possible short read */
+ *bytes_read = isize & ~PAGE_CACHE_MASK;
+ else
+ *bytes_read = PAGE_CACHE_SIZE; /* got a full page */
+out:
+ if (IS_ERR(page))
+ printk(KERN_ALERT "md: bitmap read error: (%dB @ %Lu): %ld\n",
+ (int)PAGE_CACHE_SIZE,
+ (unsigned long long)index << PAGE_CACHE_SHIFT,
+ PTR_ERR(page));
+ return page;
+}
+
+/*
+ * bitmap file superblock operations
+ */
+
+/* update the event counter and sync the superblock to disk */
+int bitmap_update_sb(struct bitmap *bitmap)
+{
+ bitmap_super_t *sb;
+ unsigned long flags;
+
+ if (!bitmap || !bitmap->mddev) /* no bitmap for this array */
+ return 0;
+ spin_lock_irqsave(&bitmap->lock, flags);
+ if (!bitmap->sb_page) { /* no superblock */
+ spin_unlock_irqrestore(&bitmap->lock, flags);
+ return 0;
+ }
+ spin_unlock_irqrestore(&bitmap->lock, flags);
+ sb = (bitmap_super_t *)kmap(bitmap->sb_page);
+ sb->events = cpu_to_le64(bitmap->mddev->events);
+ if (!bitmap->mddev->degraded)
+ sb->events_cleared = cpu_to_le64(bitmap->mddev->events);
+ kunmap(bitmap->sb_page);
+ return write_page(bitmap, bitmap->sb_page, 1);
+}
+
+/* print out the bitmap file superblock */
+void bitmap_print_sb(struct bitmap *bitmap)
+{
+ bitmap_super_t *sb;
+
+ if (!bitmap || !bitmap->sb_page)
+ return;
+ sb = (bitmap_super_t *)kmap(bitmap->sb_page);
+ printk(KERN_DEBUG "%s: bitmap file superblock:\n", bmname(bitmap));
+ printk(KERN_DEBUG " magic: %08x\n", le32_to_cpu(sb->magic));
+ printk(KERN_DEBUG " version: %d\n", le32_to_cpu(sb->version));
+ printk(KERN_DEBUG " uuid: %08x.%08x.%08x.%08x\n",
+ *(__u32 *)(sb->uuid+0),
+ *(__u32 *)(sb->uuid+4),
+ *(__u32 *)(sb->uuid+8),
+ *(__u32 *)(sb->uuid+12));
+ printk(KERN_DEBUG " events: %llu\n",
+ (unsigned long long) le64_to_cpu(sb->events));
+ printk(KERN_DEBUG "events cleared: %llu\n",
+ (unsigned long long) le64_to_cpu(sb->events_cleared));
+ printk(KERN_DEBUG " state: %08x\n", le32_to_cpu(sb->state));
+ printk(KERN_DEBUG " chunksize: %d B\n", le32_to_cpu(sb->chunksize));
+ printk(KERN_DEBUG " daemon sleep: %ds\n", le32_to_cpu(sb->daemon_sleep));
+ printk(KERN_DEBUG " sync size: %llu KB\n",
+ (unsigned long long)le64_to_cpu(sb->sync_size)/2);
+ kunmap(bitmap->sb_page);
+}
+
+/* read the superblock from the bitmap file and initialize some bitmap fields */
+static int bitmap_read_sb(struct bitmap *bitmap)
+{
+ char *reason = NULL;
+ bitmap_super_t *sb;
+ unsigned long chunksize, daemon_sleep;
+ unsigned long bytes_read;
+ unsigned long long events;
+ int err = -EINVAL;
+
+ /* page 0 is the superblock, read it... */
+ if (bitmap->file)
+ bitmap->sb_page = read_page(bitmap->file, 0, &bytes_read);
+ else {
+ bitmap->sb_page = read_sb_page(bitmap->mddev, bitmap->offset, 0);
+ bytes_read = PAGE_SIZE;
+ }
+ if (IS_ERR(bitmap->sb_page)) {
+ err = PTR_ERR(bitmap->sb_page);
+ bitmap->sb_page = NULL;
+ return err;
+ }
+
+ sb = (bitmap_super_t *)kmap(bitmap->sb_page);
+
+ if (bytes_read < sizeof(*sb)) { /* short read */
+ printk(KERN_INFO "%s: bitmap file superblock truncated\n",
+ bmname(bitmap));
+ err = -ENOSPC;
+ goto out;
+ }
+
+ chunksize = le32_to_cpu(sb->chunksize);
+ daemon_sleep = le32_to_cpu(sb->daemon_sleep);
+
+ /* verify that the bitmap-specific fields are valid */
+ if (sb->magic != cpu_to_le32(BITMAP_MAGIC))
+ reason = "bad magic";
+ else if (sb->version != cpu_to_le32(BITMAP_MAJOR))
+ reason = "unrecognized superblock version";
+ else if (chunksize < 512 || chunksize > (1024 * 1024 * 4))
+ reason = "bitmap chunksize out of range (512B - 4MB)";
+ else if ((1 << ffz(~chunksize)) != chunksize)
+ reason = "bitmap chunksize not a power of 2";
+ else if (daemon_sleep < 1 || daemon_sleep > 15)
+ reason = "daemon sleep period out of range";
+ if (reason) {
+ printk(KERN_INFO "%s: invalid bitmap file superblock: %s\n",
+ bmname(bitmap), reason);
+ goto out;
+ }
+
+ /* keep the array size field of the bitmap superblock up to date */
+ sb->sync_size = cpu_to_le64(bitmap->mddev->resync_max_sectors);
+
+ if (!bitmap->mddev->persistent)
+ goto success;
+
+ /*
+ * if we have a persistent array superblock, compare the
+ * bitmap's UUID and event counter to the mddev's
+ */
+ if (memcmp(sb->uuid, bitmap->mddev->uuid, 16)) {
+ printk(KERN_INFO "%s: bitmap superblock UUID mismatch\n",
+ bmname(bitmap));
+ goto out;
+ }
+ events = le64_to_cpu(sb->events);
+ if (events < bitmap->mddev->events) {
+ printk(KERN_INFO "%s: bitmap file is out of date (%llu < %llu) "
+ "-- forcing full recovery\n", bmname(bitmap), events,
+ (unsigned long long) bitmap->mddev->events);
+ sb->state |= BITMAP_STALE;
+ }
+success:
+ /* assign fields using values from superblock */
+ bitmap->chunksize = chunksize;
+ bitmap->daemon_sleep = daemon_sleep;
+ bitmap->flags |= sb->state;
+ bitmap->events_cleared = le64_to_cpu(sb->events_cleared);
+ err = 0;
+out:
+ kunmap(bitmap->sb_page);
+ if (err)
+ bitmap_print_sb(bitmap);
+ return err;
+}
+
+enum bitmap_mask_op {
+ MASK_SET,
+ MASK_UNSET
+};
+
+/* record the state of the bitmap in the superblock */
+static void bitmap_mask_state(struct bitmap *bitmap, enum bitmap_state bits,
+ enum bitmap_mask_op op)
+{
+ bitmap_super_t *sb;
+ unsigned long flags;
+
+ spin_lock_irqsave(&bitmap->lock, flags);
+ if (!bitmap || !bitmap->sb_page) { /* can't set the state */
+ spin_unlock_irqrestore(&bitmap->lock, flags);
+ return;
+ }
+ page_cache_get(bitmap->sb_page);
+ spin_unlock_irqrestore(&bitmap->lock, flags);
+ sb = (bitmap_super_t *)kmap(bitmap->sb_page);
+ switch (op) {
+ case MASK_SET: sb->state |= bits;
+ break;
+ case MASK_UNSET: sb->state &= ~bits;
+ break;
+ default: BUG();
+ }
+ kunmap(bitmap->sb_page);
+ page_cache_release(bitmap->sb_page);
+}
+
+/*
+ * general bitmap file operations
+ */
+
+/* calculate the index of the page that contains this bit */
+static inline unsigned long file_page_index(unsigned long chunk)
+{
+ return CHUNK_BIT_OFFSET(chunk) >> PAGE_BIT_SHIFT;
+}
+
+/* calculate the (bit) offset of this bit within a page */
+static inline unsigned long file_page_offset(unsigned long chunk)
+{
+ return CHUNK_BIT_OFFSET(chunk) & (PAGE_BITS - 1);
+}
+
+/*
+ * return a pointer to the page in the filemap that contains the given bit
+ *
+ * this lookup is complicated by the fact that the bitmap sb might be exactly
+ * 1 page (e.g., x86) or less than 1 page -- so the bitmap might start on page
+ * 0 or page 1
+ */
+static inline struct page *filemap_get_page(struct bitmap *bitmap,
+ unsigned long chunk)
+{
+ return bitmap->filemap[file_page_index(chunk) - file_page_index(0)];
+}
+
+
+static void bitmap_file_unmap(struct bitmap *bitmap)
+{
+ struct page **map, *sb_page;
+ unsigned long *attr;
+ int pages;
+ unsigned long flags;
+
+ spin_lock_irqsave(&bitmap->lock, flags);
+ map = bitmap->filemap;
+ bitmap->filemap = NULL;
+ attr = bitmap->filemap_attr;
+ bitmap->filemap_attr = NULL;
+ pages = bitmap->file_pages;
+ bitmap->file_pages = 0;
+ sb_page = bitmap->sb_page;
+ bitmap->sb_page = NULL;
+ spin_unlock_irqrestore(&bitmap->lock, flags);
+
+ while (pages--)
+ if (map[pages]->index != 0) /* 0 is sb_page, release it below */
+ page_cache_release(map[pages]);
+ kfree(map);
+ kfree(attr);
+
+ if (sb_page)
+ page_cache_release(sb_page);
+}
+
+static void bitmap_stop_daemons(struct bitmap *bitmap);
+
+/* dequeue the next item in a page list -- don't call from irq context */
+static struct page_list *dequeue_page(struct bitmap *bitmap)
+{
+ struct page_list *item = NULL;
+ struct list_head *head = &bitmap->complete_pages;
+
+ spin_lock(&bitmap->write_lock);
+ if (list_empty(head))
+ goto out;
+ item = list_entry(head->prev, struct page_list, list);
+ list_del(head->prev);
+out:
+ spin_unlock(&bitmap->write_lock);
+ return item;
+}
+
+static void drain_write_queues(struct bitmap *bitmap)
+{
+ struct page_list *item;
+
+ while ((item = dequeue_page(bitmap))) {
+ /* don't bother to wait */
+ page_cache_release(item->page);
+ mempool_free(item, bitmap->write_pool);
+ }
+
+ wake_up(&bitmap->write_wait);
+}
+
+static void bitmap_file_put(struct bitmap *bitmap)
+{
+ struct file *file;
+ struct inode *inode;
+ unsigned long flags;
+
+ spin_lock_irqsave(&bitmap->lock, flags);
+ file = bitmap->file;
+ bitmap->file = NULL;
+ spin_unlock_irqrestore(&bitmap->lock, flags);
+
+ bitmap_stop_daemons(bitmap);
+
+ drain_write_queues(bitmap);
+
+ bitmap_file_unmap(bitmap);
+
+ if (file) {
+ inode = file->f_mapping->host;
+ spin_lock(&inode->i_lock);
+ atomic_set(&inode->i_writecount, 1); /* allow writes again */
+ spin_unlock(&inode->i_lock);
+ fput(file);
+ }
+}
+
+
+/*
+ * bitmap_file_kick - if an error occurs while manipulating the bitmap file
+ * then it is no longer reliable, so we stop using it and we mark the file
+ * as failed in the superblock
+ */
+static void bitmap_file_kick(struct bitmap *bitmap)
+{
+ char *path, *ptr = NULL;
+
+ bitmap_mask_state(bitmap, BITMAP_STALE, MASK_SET);
+ bitmap_update_sb(bitmap);
+
+ if (bitmap->file) {
+ path = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (path)
+ ptr = file_path(bitmap->file, path, PAGE_SIZE);
+
+ printk(KERN_ALERT "%s: kicking failed bitmap file %s from array!\n",
+ bmname(bitmap), ptr ? ptr : "");
+
+ kfree(path);
+ }
+
+ bitmap_file_put(bitmap);
+
+ return;
+}
+
+enum bitmap_page_attr {
+ BITMAP_PAGE_DIRTY = 1, // there are set bits that need to be synced
+ BITMAP_PAGE_CLEAN = 2, // there are bits that might need to be cleared
+ BITMAP_PAGE_NEEDWRITE=4, // there are cleared bits that need to be synced
+};
+
+static inline void set_page_attr(struct bitmap *bitmap, struct page *page,
+ enum bitmap_page_attr attr)
+{
+ bitmap->filemap_attr[page->index] |= attr;
+}
+
+static inline void clear_page_attr(struct bitmap *bitmap, struct page *page,
+ enum bitmap_page_attr attr)
+{
+ bitmap->filemap_attr[page->index] &= ~attr;
+}
+
+static inline unsigned long get_page_attr(struct bitmap *bitmap, struct page *page)
+{
+ return bitmap->filemap_attr[page->index];
+}
+
+/*
+ * bitmap_file_set_bit -- called before performing a write to the md device
+ * to set (and eventually sync) a particular bit in the bitmap file
+ *
+ * we set the bit immediately, then we record the page number so that
+ * when an unplug occurs, we can flush the dirty pages out to disk
+ */
+static void bitmap_file_set_bit(struct bitmap *bitmap, sector_t block)
+{
+ unsigned long bit;
+ struct page *page;
+ void *kaddr;
+ unsigned long chunk = block >> CHUNK_BLOCK_SHIFT(bitmap);
+
+ if (!bitmap->filemap) {
+ return;
+ }
+
+ page = filemap_get_page(bitmap, chunk);
+ bit = file_page_offset(chunk);
+
+
+ /* make sure the page stays cached until it gets written out */
+ if (! (get_page_attr(bitmap, page) & BITMAP_PAGE_DIRTY))
+ page_cache_get(page);
+
+ /* set the bit */
+ kaddr = kmap_atomic(page, KM_USER0);
+ set_bit(bit, kaddr);
+ kunmap_atomic(kaddr, KM_USER0);
+ PRINTK("set file bit %lu page %lu\n", bit, page->index);
+
+ /* record page number so it gets flushed to disk when unplug occurs */
+ set_page_attr(bitmap, page, BITMAP_PAGE_DIRTY);
+
+}
+
+/* this gets called when the md device is ready to unplug its underlying
+ * (slave) device queues -- before we let any writes go down, we need to
+ * sync the dirty pages of the bitmap file to disk */
+int bitmap_unplug(struct bitmap *bitmap)
+{
+ unsigned long i, attr, flags;
+ struct page *page;
+ int wait = 0;
+ int err;
+
+ if (!bitmap)
+ return 0;
+
+ /* look at each page to see if there are any set bits that need to be
+ * flushed out to disk */
+ for (i = 0; i < bitmap->file_pages; i++) {
+ spin_lock_irqsave(&bitmap->lock, flags);
+ if (!bitmap->filemap) {
+ spin_unlock_irqrestore(&bitmap->lock, flags);
+ return 0;
+ }
+ page = bitmap->filemap[i];
+ attr = get_page_attr(bitmap, page);
+ clear_page_attr(bitmap, page, BITMAP_PAGE_DIRTY);
+ clear_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE);
+ if ((attr & BITMAP_PAGE_DIRTY))
+ wait = 1;
+ spin_unlock_irqrestore(&bitmap->lock, flags);
+
+ if (attr & (BITMAP_PAGE_DIRTY | BITMAP_PAGE_NEEDWRITE)) {
+ err = write_page(bitmap, page, 0);
+ if (err == -EAGAIN) {
+ if (attr & BITMAP_PAGE_DIRTY)
+ err = write_page(bitmap, page, 1);
+ else
+ err = 0;
+ }
+ if (err)
+ return 1;
+ }
+ }
+ if (wait) { /* if any writes were performed, we need to wait on them */
+ if (bitmap->file) {
+ spin_lock_irq(&bitmap->write_lock);
+ wait_event_lock_irq(bitmap->write_wait,
+ list_empty(&bitmap->complete_pages), bitmap->write_lock,
+ wake_up_process(bitmap->writeback_daemon->tsk));
+ spin_unlock_irq(&bitmap->write_lock);
+ } else
+ wait_event(bitmap->mddev->sb_wait,
+ atomic_read(&bitmap->mddev->pending_writes)==0);
+ }
+ return 0;
+}
+
+static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset,
+ unsigned long sectors, int in_sync);
+/* * bitmap_init_from_disk -- called at bitmap_create time to initialize
+ * the in-memory bitmap from the on-disk bitmap -- also, sets up the
+ * memory mapping of the bitmap file
+ * Special cases:
+ * if there's no bitmap file, or if the bitmap file had been
+ * previously kicked from the array, we mark all the bits as
+ * 1's in order to cause a full resync.
+ */
+static int bitmap_init_from_disk(struct bitmap *bitmap, int in_sync)
+{
+ unsigned long i, chunks, index, oldindex, bit;
+ struct page *page = NULL, *oldpage = NULL;
+ unsigned long num_pages, bit_cnt = 0;
+ struct file *file;
+ unsigned long bytes, offset, dummy;
+ int outofdate;
+ int ret = -ENOSPC;
+
+ chunks = bitmap->chunks;
+ file = bitmap->file;
+
+ BUG_ON(!file && !bitmap->offset);
+
+#if INJECT_FAULTS_3
+ outofdate = 1;
+#else
+ outofdate = bitmap->flags & BITMAP_STALE;
+#endif
+ if (outofdate)
+ printk(KERN_INFO "%s: bitmap file is out of date, doing full "
+ "recovery\n", bmname(bitmap));
+
+ bytes = (chunks + 7) / 8;
+
+ num_pages = (bytes + sizeof(bitmap_super_t) + PAGE_SIZE - 1) / PAGE_SIZE;
+
+ if (file && i_size_read(file->f_mapping->host) < bytes + sizeof(bitmap_super_t)) {
+ printk(KERN_INFO "%s: bitmap file too short %lu < %lu\n",
+ bmname(bitmap),
+ (unsigned long) i_size_read(file->f_mapping->host),
+ bytes + sizeof(bitmap_super_t));
+ goto out;
+ }
+
+ ret = -ENOMEM;
+
+ bitmap->filemap = kmalloc(sizeof(struct page *) * num_pages, GFP_KERNEL);
+ if (!bitmap->filemap)
+ goto out;
+
+ bitmap->filemap_attr = kmalloc(sizeof(long) * num_pages, GFP_KERNEL);
+ if (!bitmap->filemap_attr)
+ goto out;
+
+ memset(bitmap->filemap_attr, 0, sizeof(long) * num_pages);
+
+ oldindex = ~0L;
+
+ for (i = 0; i < chunks; i++) {
+ index = file_page_index(i);
+ bit = file_page_offset(i);
+ if (index != oldindex) { /* this is a new page, read it in */
+ /* unmap the old page, we're done with it */
+ if (oldpage != NULL)
+ kunmap(oldpage);
+ if (index == 0) {
+ /*
+ * if we're here then the superblock page
+ * contains some bits (PAGE_SIZE != sizeof sb)
+ * we've already read it in, so just use it
+ */
+ page = bitmap->sb_page;
+ offset = sizeof(bitmap_super_t);
+ } else if (file) {
+ page = read_page(file, index, &dummy);
+ offset = 0;
+ } else {
+ page = read_sb_page(bitmap->mddev, bitmap->offset, index);
+ offset = 0;
+ }
+ if (IS_ERR(page)) { /* read error */
+ ret = PTR_ERR(page);
+ goto out;
+ }
+
+ oldindex = index;
+ oldpage = page;
+ kmap(page);
+
+ if (outofdate) {
+ /*
+ * if bitmap is out of date, dirty the
+ * whole page and write it out
+ */
+ memset(page_address(page) + offset, 0xff,
+ PAGE_SIZE - offset);
+ ret = write_page(bitmap, page, 1);
+ if (ret) {
+ kunmap(page);
+ /* release, page not in filemap yet */
+ page_cache_release(page);
+ goto out;
+ }
+ }
+
+ bitmap->filemap[bitmap->file_pages++] = page;
+ }
+ if (test_bit(bit, page_address(page))) {
+ /* if the disk bit is set, set the memory bit */
+ bitmap_set_memory_bits(bitmap,
+ i << CHUNK_BLOCK_SHIFT(bitmap), 1, in_sync);
+ bit_cnt++;
+ }
+ }
+
+ /* everything went OK */
+ ret = 0;
+ bitmap_mask_state(bitmap, BITMAP_STALE, MASK_UNSET);
+
+ if (page) /* unmap the last page */
+ kunmap(page);
+
+ if (bit_cnt) { /* Kick recovery if any bits were set */
+ set_bit(MD_RECOVERY_NEEDED, &bitmap->mddev->recovery);
+ md_wakeup_thread(bitmap->mddev->thread);
+ }
+
+out:
+ printk(KERN_INFO "%s: bitmap initialized from disk: "
+ "read %lu/%lu pages, set %lu bits, status: %d\n",
+ bmname(bitmap), bitmap->file_pages, num_pages, bit_cnt, ret);
+
+ return ret;
+}
+
+void bitmap_write_all(struct bitmap *bitmap)
+{
+ /* We don't actually write all bitmap blocks here,
+ * just flag them as needing to be written
+ */
+
+ unsigned long chunks = bitmap->chunks;
+ unsigned long bytes = (chunks+7)/8 + sizeof(bitmap_super_t);
+ unsigned long num_pages = (bytes + PAGE_SIZE-1) / PAGE_SIZE;
+ while (num_pages--)
+ bitmap->filemap_attr[num_pages] |= BITMAP_PAGE_NEEDWRITE;
+}
+
+
+static void bitmap_count_page(struct bitmap *bitmap, sector_t offset, int inc)
+{
+ sector_t chunk = offset >> CHUNK_BLOCK_SHIFT(bitmap);
+ unsigned long page = chunk >> PAGE_COUNTER_SHIFT;
+ bitmap->bp[page].count += inc;
+/*
+ if (page == 0) printk("count page 0, offset %llu: %d gives %d\n",
+ (unsigned long long)offset, inc, bitmap->bp[page].count);
+*/
+ bitmap_checkfree(bitmap, page);
+}
+static bitmap_counter_t *bitmap_get_counter(struct bitmap *bitmap,
+ sector_t offset, int *blocks,
+ int create);
+
+/*
+ * bitmap daemon -- periodically wakes up to clean bits and flush pages
+ * out to disk
+ */
+
+int bitmap_daemon_work(struct bitmap *bitmap)
+{
+ unsigned long j;
+ unsigned long flags;
+ struct page *page = NULL, *lastpage = NULL;
+ int err = 0;
+ int blocks;
+ int attr;
+
+ if (bitmap == NULL)
+ return 0;
+ if (time_before(jiffies, bitmap->daemon_lastrun + bitmap->daemon_sleep*HZ))
+ return 0;
+ bitmap->daemon_lastrun = jiffies;
+
+ for (j = 0; j < bitmap->chunks; j++) {
+ bitmap_counter_t *bmc;
+ spin_lock_irqsave(&bitmap->lock, flags);
+ if (!bitmap->filemap) {
+ /* error or shutdown */
+ spin_unlock_irqrestore(&bitmap->lock, flags);
+ break;
+ }
+
+ page = filemap_get_page(bitmap, j);
+
+ if (page != lastpage) {
+ /* skip this page unless it's marked as needing cleaning */
+ if (!((attr=get_page_attr(bitmap, page)) & BITMAP_PAGE_CLEAN)) {
+ if (attr & BITMAP_PAGE_NEEDWRITE) {
+ page_cache_get(page);
+ clear_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE);
+ }
+ spin_unlock_irqrestore(&bitmap->lock, flags);
+ if (attr & BITMAP_PAGE_NEEDWRITE) {
+ switch (write_page(bitmap, page, 0)) {
+ case -EAGAIN:
+ set_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE);
+ break;
+ case 0:
+ break;
+ default:
+ bitmap_file_kick(bitmap);
+ }
+ page_cache_release(page);
+ }
+ continue;
+ }
+
+ /* grab the new page, sync and release the old */
+ page_cache_get(page);
+ if (lastpage != NULL) {
+ if (get_page_attr(bitmap, lastpage) & BITMAP_PAGE_NEEDWRITE) {
+ clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
+ spin_unlock_irqrestore(&bitmap->lock, flags);
+ err = write_page(bitmap, lastpage, 0);
+ if (err == -EAGAIN) {
+ err = 0;
+ set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
+ }
+ } else {
+ set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
+ spin_unlock_irqrestore(&bitmap->lock, flags);
+ }
+ kunmap(lastpage);
+ page_cache_release(lastpage);
+ if (err)
+ bitmap_file_kick(bitmap);
+ } else
+ spin_unlock_irqrestore(&bitmap->lock, flags);
+ lastpage = page;
+ kmap(page);
+/*
+ printk("bitmap clean at page %lu\n", j);
+*/
+ spin_lock_irqsave(&bitmap->lock, flags);
+ clear_page_attr(bitmap, page, BITMAP_PAGE_CLEAN);
+ }
+ bmc = bitmap_get_counter(bitmap, j << CHUNK_BLOCK_SHIFT(bitmap),
+ &blocks, 0);
+ if (bmc) {
+/*
+ if (j < 100) printk("bitmap: j=%lu, *bmc = 0x%x\n", j, *bmc);
+*/
+ if (*bmc == 2) {
+ *bmc=1; /* maybe clear the bit next time */
+ set_page_attr(bitmap, page, BITMAP_PAGE_CLEAN);
+ } else if (*bmc == 1) {
+ /* we can clear the bit */
+ *bmc = 0;
+ bitmap_count_page(bitmap, j << CHUNK_BLOCK_SHIFT(bitmap),
+ -1);
+
+ /* clear the bit */
+ clear_bit(file_page_offset(j), page_address(page));
+ }
+ }
+ spin_unlock_irqrestore(&bitmap->lock, flags);
+ }
+
+ /* now sync the final page */
+ if (lastpage != NULL) {
+ kunmap(lastpage);
+ spin_lock_irqsave(&bitmap->lock, flags);
+ if (get_page_attr(bitmap, lastpage) &BITMAP_PAGE_NEEDWRITE) {
+ clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
+ spin_unlock_irqrestore(&bitmap->lock, flags);
+ err = write_page(bitmap, lastpage, 0);
+ if (err == -EAGAIN) {
+ set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
+ err = 0;
+ }
+ } else {
+ set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
+ spin_unlock_irqrestore(&bitmap->lock, flags);
+ }
+
+ page_cache_release(lastpage);
+ }
+
+ return err;
+}
+
+static void daemon_exit(struct bitmap *bitmap, mdk_thread_t **daemon)
+{
+ mdk_thread_t *dmn;
+ unsigned long flags;
+
+ /* if no one is waiting on us, we'll free the md thread struct
+ * and exit, otherwise we let the waiter clean things up */
+ spin_lock_irqsave(&bitmap->lock, flags);
+ if ((dmn = *daemon)) { /* no one is waiting, cleanup and exit */
+ *daemon = NULL;
+ spin_unlock_irqrestore(&bitmap->lock, flags);
+ kfree(dmn);
+ complete_and_exit(NULL, 0); /* do_exit not exported */
+ }
+ spin_unlock_irqrestore(&bitmap->lock, flags);
+}
+
+static void bitmap_writeback_daemon(mddev_t *mddev)
+{
+ struct bitmap *bitmap = mddev->bitmap;
+ struct page *page;
+ struct page_list *item;
+ int err = 0;
+
+ if (signal_pending(current)) {
+ printk(KERN_INFO
+ "%s: bitmap writeback daemon got signal, exiting...\n",
+ bmname(bitmap));
+ err = -EINTR;
+ goto out;
+ }
+
+ PRINTK("%s: bitmap writeback daemon woke up...\n", bmname(bitmap));
+ /* wait on bitmap page writebacks */
+ while ((item = dequeue_page(bitmap))) {
+ page = item->page;
+ mempool_free(item, bitmap->write_pool);
+ PRINTK("wait on page writeback: %p\n", page);
+ wait_on_page_writeback(page);
+ PRINTK("finished page writeback: %p\n", page);
+
+ err = PageError(page);
+ page_cache_release(page);
+ if (err) {
+ printk(KERN_WARNING "%s: bitmap file writeback "
+ "failed (page %lu): %d\n",
+ bmname(bitmap), page->index, err);
+ bitmap_file_kick(bitmap);
+ goto out;
+ }
+ }
+ out:
+ wake_up(&bitmap->write_wait);
+ if (err) {
+ printk(KERN_INFO "%s: bitmap writeback daemon exiting (%d)\n",
+ bmname(bitmap), err);
+ daemon_exit(bitmap, &bitmap->writeback_daemon);
+ }
+}
+
+static int bitmap_start_daemon(struct bitmap *bitmap, mdk_thread_t **ptr,
+ void (*func)(mddev_t *), char *name)
+{
+ mdk_thread_t *daemon;
+ unsigned long flags;
+ char namebuf[32];
+
+ spin_lock_irqsave(&bitmap->lock, flags);
+ *ptr = NULL;
+
+ if (!bitmap->file) /* no need for daemon if there's no backing file */
+ goto out_unlock;
+
+ spin_unlock_irqrestore(&bitmap->lock, flags);
+
+#if INJECT_FATAL_FAULT_2
+ daemon = NULL;
+#else
+ sprintf(namebuf, "%%s_%s", name);
+ daemon = md_register_thread(func, bitmap->mddev, namebuf);
+#endif
+ if (!daemon) {
+ printk(KERN_ERR "%s: failed to start bitmap daemon\n",
+ bmname(bitmap));
+ return -ECHILD;
+ }
+
+ spin_lock_irqsave(&bitmap->lock, flags);
+ *ptr = daemon;
+
+ md_wakeup_thread(daemon); /* start it running */
+
+ PRINTK("%s: %s daemon (pid %d) started...\n",
+ bmname(bitmap), name, daemon->tsk->pid);
+out_unlock:
+ spin_unlock_irqrestore(&bitmap->lock, flags);
+ return 0;
+}
+
+static int bitmap_start_daemons(struct bitmap *bitmap)
+{
+ int err = bitmap_start_daemon(bitmap, &bitmap->writeback_daemon,
+ bitmap_writeback_daemon, "bitmap_wb");
+ return err;
+}
+
+static void bitmap_stop_daemon(struct bitmap *bitmap, mdk_thread_t **ptr)
+{
+ mdk_thread_t *daemon;
+ unsigned long flags;
+
+ spin_lock_irqsave(&bitmap->lock, flags);
+ daemon = *ptr;
+ *ptr = NULL;
+ spin_unlock_irqrestore(&bitmap->lock, flags);
+ if (daemon)
+ md_unregister_thread(daemon); /* destroy the thread */
+}
+
+static void bitmap_stop_daemons(struct bitmap *bitmap)
+{
+ /* the daemons can't stop themselves... they'll just exit instead... */
+ if (bitmap->writeback_daemon &&
+ current->pid != bitmap->writeback_daemon->tsk->pid)
+ bitmap_stop_daemon(bitmap, &bitmap->writeback_daemon);
+}
+
+static bitmap_counter_t *bitmap_get_counter(struct bitmap *bitmap,
+ sector_t offset, int *blocks,
+ int create)
+{
+ /* If 'create', we might release the lock and reclaim it.
+ * The lock must have been taken with interrupts enabled.
+ * If !create, we don't release the lock.
+ */
+ sector_t chunk = offset >> CHUNK_BLOCK_SHIFT(bitmap);
+ unsigned long page = chunk >> PAGE_COUNTER_SHIFT;
+ unsigned long pageoff = (chunk & PAGE_COUNTER_MASK) << COUNTER_BYTE_SHIFT;
+ sector_t csize;
+
+ if (bitmap_checkpage(bitmap, page, create) < 0) {
+ csize = ((sector_t)1) << (CHUNK_BLOCK_SHIFT(bitmap));
+ *blocks = csize - (offset & (csize- 1));
+ return NULL;
+ }
+ /* now locked ... */
+
+ if (bitmap->bp[page].hijacked) { /* hijacked pointer */
+ /* should we use the first or second counter field
+ * of the hijacked pointer? */
+ int hi = (pageoff > PAGE_COUNTER_MASK);
+ csize = ((sector_t)1) << (CHUNK_BLOCK_SHIFT(bitmap) +
+ PAGE_COUNTER_SHIFT - 1);
+ *blocks = csize - (offset & (csize- 1));
+ return &((bitmap_counter_t *)
+ &bitmap->bp[page].map)[hi];
+ } else { /* page is allocated */
+ csize = ((sector_t)1) << (CHUNK_BLOCK_SHIFT(bitmap));
+ *blocks = csize - (offset & (csize- 1));
+ return (bitmap_counter_t *)
+ &(bitmap->bp[page].map[pageoff]);
+ }
+}
+
+int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sectors)
+{
+ if (!bitmap) return 0;
+ while (sectors) {
+ int blocks;
+ bitmap_counter_t *bmc;
+
+ spin_lock_irq(&bitmap->lock);
+ bmc = bitmap_get_counter(bitmap, offset, &blocks, 1);
+ if (!bmc) {
+ spin_unlock_irq(&bitmap->lock);
+ return 0;
+ }
+
+ switch(*bmc) {
+ case 0:
+ bitmap_file_set_bit(bitmap, offset);
+ bitmap_count_page(bitmap,offset, 1);
+ blk_plug_device(bitmap->mddev->queue);
+ /* fall through */
+ case 1:
+ *bmc = 2;
+ }
+ if ((*bmc & COUNTER_MAX) == COUNTER_MAX) BUG();
+ (*bmc)++;
+
+ spin_unlock_irq(&bitmap->lock);
+
+ offset += blocks;
+ if (sectors > blocks)
+ sectors -= blocks;
+ else sectors = 0;
+ }
+ return 0;
+}
+
+void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long sectors,
+ int success)
+{
+ if (!bitmap) return;
+ while (sectors) {
+ int blocks;
+ unsigned long flags;
+ bitmap_counter_t *bmc;
+
+ spin_lock_irqsave(&bitmap->lock, flags);
+ bmc = bitmap_get_counter(bitmap, offset, &blocks, 0);
+ if (!bmc) {
+ spin_unlock_irqrestore(&bitmap->lock, flags);
+ return;
+ }
+
+ if (!success && ! (*bmc & NEEDED_MASK))
+ *bmc |= NEEDED_MASK;
+
+ (*bmc)--;
+ if (*bmc <= 2) {
+ set_page_attr(bitmap,
+ filemap_get_page(bitmap, offset >> CHUNK_BLOCK_SHIFT(bitmap)),
+ BITMAP_PAGE_CLEAN);
+ }
+ spin_unlock_irqrestore(&bitmap->lock, flags);
+ offset += blocks;
+ if (sectors > blocks)
+ sectors -= blocks;
+ else sectors = 0;
+ }
+}
+
+int bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *blocks)
+{
+ bitmap_counter_t *bmc;
+ int rv;
+ if (bitmap == NULL) {/* FIXME or bitmap set as 'failed' */
+ *blocks = 1024;
+ return 1; /* always resync if no bitmap */
+ }
+ spin_lock_irq(&bitmap->lock);
+ bmc = bitmap_get_counter(bitmap, offset, blocks, 0);
+ rv = 0;
+ if (bmc) {
+ /* locked */
+ if (RESYNC(*bmc))
+ rv = 1;
+ else if (NEEDED(*bmc)) {
+ rv = 1;
+ *bmc |= RESYNC_MASK;
+ *bmc &= ~NEEDED_MASK;
+ }
+ }
+ spin_unlock_irq(&bitmap->lock);
+ return rv;
+}
+
+void bitmap_end_sync(struct bitmap *bitmap, sector_t offset, int *blocks, int aborted)
+{
+ bitmap_counter_t *bmc;
+ unsigned long flags;
+/*
+ if (offset == 0) printk("bitmap_end_sync 0 (%d)\n", aborted);
+*/ if (bitmap == NULL) {
+ *blocks = 1024;
+ return;
+ }
+ spin_lock_irqsave(&bitmap->lock, flags);
+ bmc = bitmap_get_counter(bitmap, offset, blocks, 0);
+ if (bmc == NULL)
+ goto unlock;
+ /* locked */
+/*
+ if (offset == 0) printk("bitmap_end sync found 0x%x, blocks %d\n", *bmc, *blocks);
+*/
+ if (RESYNC(*bmc)) {
+ *bmc &= ~RESYNC_MASK;
+
+ if (!NEEDED(*bmc) && aborted)
+ *bmc |= NEEDED_MASK;
+ else {
+ if (*bmc <= 2) {
+ set_page_attr(bitmap,
+ filemap_get_page(bitmap, offset >> CHUNK_BLOCK_SHIFT(bitmap)),
+ BITMAP_PAGE_CLEAN);
+ }
+ }
+ }
+ unlock:
+ spin_unlock_irqrestore(&bitmap->lock, flags);
+}
+
+void bitmap_close_sync(struct bitmap *bitmap)
+{
+ /* Sync has finished, and any bitmap chunks that weren't synced
+ * properly have been aborted. It remains to us to clear the
+ * RESYNC bit wherever it is still on
+ */
+ sector_t sector = 0;
+ int blocks;
+ if (!bitmap) return;
+ while (sector < bitmap->mddev->resync_max_sectors) {
+ bitmap_end_sync(bitmap, sector, &blocks, 0);
+/*
+ if (sector < 500) printk("bitmap_close_sync: sec %llu blks %d\n",
+ (unsigned long long)sector, blocks);
+*/ sector += blocks;
+ }
+}
+
+static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset,
+ unsigned long sectors, int in_sync)
+{
+ /* For each chunk covered by any of these sectors, set the
+ * counter to 1 and set resync_needed unless in_sync. They should all
+ * be 0 at this point
+ */
+ while (sectors) {
+ int secs;
+ bitmap_counter_t *bmc;
+ spin_lock_irq(&bitmap->lock);
+ bmc = bitmap_get_counter(bitmap, offset, &secs, 1);
+ if (!bmc) {
+ spin_unlock_irq(&bitmap->lock);
+ return;
+ }
+ if (! *bmc) {
+ struct page *page;
+ *bmc = 1 | (in_sync? 0 : NEEDED_MASK);
+ bitmap_count_page(bitmap, offset, 1);
+ page = filemap_get_page(bitmap, offset >> CHUNK_BLOCK_SHIFT(bitmap));
+ set_page_attr(bitmap, page, BITMAP_PAGE_CLEAN);
+ }
+ spin_unlock_irq(&bitmap->lock);
+ if (sectors > secs)
+ sectors -= secs;
+ else
+ sectors = 0;
+ }
+}
+
+/*
+ * free memory that was allocated
+ */
+void bitmap_destroy(mddev_t *mddev)
+{
+ unsigned long k, pages;
+ struct bitmap_page *bp;
+ struct bitmap *bitmap = mddev->bitmap;
+
+ if (!bitmap) /* there was no bitmap */
+ return;
+
+ mddev->bitmap = NULL; /* disconnect from the md device */
+
+ /* release the bitmap file and kill the daemon */
+ bitmap_file_put(bitmap);
+
+ bp = bitmap->bp;
+ pages = bitmap->pages;
+
+ /* free all allocated memory */
+
+ mempool_destroy(bitmap->write_pool);
+
+ if (bp) /* deallocate the page memory */
+ for (k = 0; k < pages; k++)
+ if (bp[k].map && !bp[k].hijacked)
+ kfree(bp[k].map);
+ kfree(bp);
+ kfree(bitmap);
+}
+
+/*
+ * initialize the bitmap structure
+ * if this returns an error, bitmap_destroy must be called to do clean up
+ */
+int bitmap_create(mddev_t *mddev)
+{
+ struct bitmap *bitmap;
+ unsigned long blocks = mddev->resync_max_sectors;
+ unsigned long chunks;
+ unsigned long pages;
+ struct file *file = mddev->bitmap_file;
+ int err;
+
+ BUG_ON(sizeof(bitmap_super_t) != 256);
+
+ if (!file && !mddev->bitmap_offset) /* bitmap disabled, nothing to do */
+ return 0;
+
+ BUG_ON(file && mddev->bitmap_offset);
+
+ bitmap = kmalloc(sizeof(*bitmap), GFP_KERNEL);
+ if (!bitmap)
+ return -ENOMEM;
+
+ memset(bitmap, 0, sizeof(*bitmap));
+
+ spin_lock_init(&bitmap->lock);
+ bitmap->mddev = mddev;
+ mddev->bitmap = bitmap;
+
+ spin_lock_init(&bitmap->write_lock);
+ INIT_LIST_HEAD(&bitmap->complete_pages);
+ init_waitqueue_head(&bitmap->write_wait);
+ bitmap->write_pool = mempool_create(WRITE_POOL_SIZE, write_pool_alloc,
+ write_pool_free, NULL);
+ if (!bitmap->write_pool)
+ return -ENOMEM;
+
+ bitmap->file = file;
+ bitmap->offset = mddev->bitmap_offset;
+ if (file) get_file(file);
+ /* read superblock from bitmap file (this sets bitmap->chunksize) */
+ err = bitmap_read_sb(bitmap);
+ if (err)
+ return err;
+
+ bitmap->chunkshift = find_first_bit(&bitmap->chunksize,
+ sizeof(bitmap->chunksize));
+
+ /* now that chunksize and chunkshift are set, we can use these macros */
+ chunks = (blocks + CHUNK_BLOCK_RATIO(bitmap) - 1) /
+ CHUNK_BLOCK_RATIO(bitmap);
+ pages = (chunks + PAGE_COUNTER_RATIO - 1) / PAGE_COUNTER_RATIO;
+
+ BUG_ON(!pages);
+
+ bitmap->chunks = chunks;
+ bitmap->pages = pages;
+ bitmap->missing_pages = pages;
+ bitmap->counter_bits = COUNTER_BITS;
+
+ bitmap->syncchunk = ~0UL;
+
+#if INJECT_FATAL_FAULT_1
+ bitmap->bp = NULL;
+#else
+ bitmap->bp = kmalloc(pages * sizeof(*bitmap->bp), GFP_KERNEL);
+#endif
+ if (!bitmap->bp)
+ return -ENOMEM;
+ memset(bitmap->bp, 0, pages * sizeof(*bitmap->bp));
+
+ bitmap->flags |= BITMAP_ACTIVE;
+
+ /* now that we have some pages available, initialize the in-memory
+ * bitmap from the on-disk bitmap */
+ err = bitmap_init_from_disk(bitmap, mddev->recovery_cp == MaxSector);
+ if (err)
+ return err;
+
+ printk(KERN_INFO "created bitmap (%lu pages) for device %s\n",
+ pages, bmname(bitmap));
+
+ /* kick off the bitmap daemons */
+ err = bitmap_start_daemons(bitmap);
+ if (err)
+ return err;
+ return bitmap_update_sb(bitmap);
+}
+
+/* the bitmap API -- for raid personalities */
+EXPORT_SYMBOL(bitmap_startwrite);
+EXPORT_SYMBOL(bitmap_endwrite);
+EXPORT_SYMBOL(bitmap_start_sync);
+EXPORT_SYMBOL(bitmap_end_sync);
+EXPORT_SYMBOL(bitmap_unplug);
+EXPORT_SYMBOL(bitmap_close_sync);
+EXPORT_SYMBOL(bitmap_daemon_work);
mempool_destroy(cc->page_pool);
mempool_destroy(cc->io_pool);
- if (cc->iv_mode)
- kfree(cc->iv_mode);
+ kfree(cc->iv_mode);
if (cc->iv_gen_ops && cc->iv_gen_ops->dtr)
cc->iv_gen_ops->dtr(cc);
crypto_free_tfm(cc->tfm);
return 0;
out:
- if (conf)
- kfree(conf);
+ kfree(conf);
return 1;
}
Neil Brown <neilb@cse.unsw.edu.au>.
+ - persistent bitmap code
+ Copyright (C) 2003-2004, Paul Clements, SteelEye Technology, 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, or (at your option)
#include <linux/config.h>
#include <linux/linkage.h>
#include <linux/raid/md.h>
+#include <linux/raid/bitmap.h>
#include <linux/sysctl.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/buffer_head.h> /* for invalidate_bdev */
#include <linux/init.h>
+#include <linux/file.h>
+
#ifdef CONFIG_KMOD
#include <linux/kmod.h>
#endif
if (mddev->unit == unit) {
mddev_get(mddev);
spin_unlock(&all_mddevs_lock);
- if (new)
- kfree(new);
+ kfree(new);
return mddev;
}
INIT_LIST_HEAD(&new->all_mddevs);
init_timer(&new->safemode_timer);
atomic_set(&new->active, 1);
+ spin_lock_init(&new->write_lock);
+ init_waitqueue_head(&new->sb_wait);
new->queue = blk_alloc_queue(GFP_KERNEL);
if (!new->queue) {
}
+static int super_written(struct bio *bio, unsigned int bytes_done, int error)
+{
+ mdk_rdev_t *rdev = bio->bi_private;
+ if (bio->bi_size)
+ return 1;
+
+ if (error || !test_bit(BIO_UPTODATE, &bio->bi_flags))
+ md_error(rdev->mddev, rdev);
+
+ if (atomic_dec_and_test(&rdev->mddev->pending_writes))
+ wake_up(&rdev->mddev->sb_wait);
+ return 0;
+}
+
+void md_super_write(mddev_t *mddev, mdk_rdev_t *rdev,
+ sector_t sector, int size, struct page *page)
+{
+ /* write first size bytes of page to sector of rdev
+ * Increment mddev->pending_writes before returning
+ * and decrement it on completion, waking up sb_wait
+ * if zero is reached.
+ * If an error occurred, call md_error
+ */
+ struct bio *bio = bio_alloc(GFP_NOIO, 1);
+
+ bio->bi_bdev = rdev->bdev;
+ bio->bi_sector = sector;
+ bio_add_page(bio, page, size, 0);
+ bio->bi_private = rdev;
+ bio->bi_end_io = super_written;
+ atomic_inc(&mddev->pending_writes);
+ submit_bio((1<<BIO_RW)|(1<<BIO_RW_SYNC), bio);
+}
+
static int bi_complete(struct bio *bio, unsigned int bytes_done, int error)
{
if (bio->bi_size)
return 0;
}
-static int sync_page_io(struct block_device *bdev, sector_t sector, int size,
+int sync_page_io(struct block_device *bdev, sector_t sector, int size,
struct page *page, int rw)
{
struct bio *bio = bio_alloc(GFP_NOIO, 1);
ret = 1;
abort:
- if (tmp1)
- kfree(tmp1);
- if (tmp2)
- kfree(tmp2);
-
+ kfree(tmp1);
+ kfree(tmp2);
return ret;
}
mdp_disk_t *desc;
mdp_super_t *sb = (mdp_super_t *)page_address(rdev->sb_page);
+ rdev->raid_disk = -1;
+ rdev->in_sync = 0;
if (mddev->raid_disks == 0) {
mddev->major_version = 0;
mddev->minor_version = sb->minor_version;
memcpy(mddev->uuid+12,&sb->set_uuid3, 4);
mddev->max_disks = MD_SB_DISKS;
- } else {
- __u64 ev1;
- ev1 = md_event(sb);
+
+ if (sb->state & (1<<MD_SB_BITMAP_PRESENT) &&
+ mddev->bitmap_file == NULL) {
+ if (mddev->level != 1) {
+ /* FIXME use a better test */
+ printk(KERN_WARNING "md: bitmaps only support for raid1\n");
+ return -EINVAL;
+ }
+ mddev->bitmap_offset = (MD_SB_BYTES >> 9);
+ }
+
+ } else if (mddev->pers == NULL) {
+ /* Insist on good event counter while assembling */
+ __u64 ev1 = md_event(sb);
++ev1;
if (ev1 < mddev->events)
return -EINVAL;
- }
+ } else if (mddev->bitmap) {
+ /* if adding to array with a bitmap, then we can accept an
+ * older device ... but not too old.
+ */
+ __u64 ev1 = md_event(sb);
+ if (ev1 < mddev->bitmap->events_cleared)
+ return 0;
+ } else /* just a hot-add of a new device, leave raid_disk at -1 */
+ return 0;
+
if (mddev->level != LEVEL_MULTIPATH) {
- rdev->raid_disk = -1;
- rdev->in_sync = rdev->faulty = 0;
+ rdev->faulty = 0;
desc = sb->disks + rdev->desc_nr;
if (desc->state & (1<<MD_DISK_FAULTY))
rdev->in_sync = 1;
rdev->raid_disk = desc->raid_disk;
}
- }
+ } else /* MULTIPATH are always insync */
+ rdev->in_sync = 1;
return 0;
}
sb->layout = mddev->layout;
sb->chunk_size = mddev->chunk_size;
+ if (mddev->bitmap && mddev->bitmap_file == NULL)
+ sb->state |= (1<<MD_SB_BITMAP_PRESENT);
+
sb->disks[0].state = (1<<MD_DISK_REMOVED);
ITERATE_RDEV(mddev,rdev2,tmp) {
mdp_disk_t *d;
case 0:
sb_offset = rdev->bdev->bd_inode->i_size >> 9;
sb_offset -= 8*2;
- sb_offset &= ~(4*2-1);
+ sb_offset &= ~(sector_t)(4*2-1);
/* convert from sectors to K */
sb_offset /= 2;
break;
{
struct mdp_superblock_1 *sb = (struct mdp_superblock_1*)page_address(rdev->sb_page);
+ rdev->raid_disk = -1;
+ rdev->in_sync = 0;
if (mddev->raid_disks == 0) {
mddev->major_version = 1;
mddev->patch_version = 0;
memcpy(mddev->uuid, sb->set_uuid, 16);
mddev->max_disks = (4096-256)/2;
- } else {
- __u64 ev1;
- ev1 = le64_to_cpu(sb->events);
+
+ if ((le32_to_cpu(sb->feature_map) & 1) &&
+ mddev->bitmap_file == NULL ) {
+ if (mddev->level != 1) {
+ printk(KERN_WARNING "md: bitmaps only supported for raid1\n");
+ return -EINVAL;
+ }
+ mddev->bitmap_offset = (__s32)le32_to_cpu(sb->bitmap_offset);
+ }
+ } else if (mddev->pers == NULL) {
+ /* Insist of good event counter while assembling */
+ __u64 ev1 = le64_to_cpu(sb->events);
++ev1;
if (ev1 < mddev->events)
return -EINVAL;
- }
+ } else if (mddev->bitmap) {
+ /* If adding to array with a bitmap, then we can accept an
+ * older device, but not too old.
+ */
+ __u64 ev1 = le64_to_cpu(sb->events);
+ if (ev1 < mddev->bitmap->events_cleared)
+ return 0;
+ } else /* just a hot-add of a new device, leave raid_disk at -1 */
+ return 0;
if (mddev->level != LEVEL_MULTIPATH) {
int role;
role = le16_to_cpu(sb->dev_roles[rdev->desc_nr]);
switch(role) {
case 0xffff: /* spare */
- rdev->in_sync = 0;
rdev->faulty = 0;
- rdev->raid_disk = -1;
break;
case 0xfffe: /* faulty */
- rdev->in_sync = 0;
rdev->faulty = 1;
- rdev->raid_disk = -1;
break;
default:
rdev->in_sync = 1;
rdev->raid_disk = role;
break;
}
- }
+ } else /* MULTIPATH are always insync */
+ rdev->in_sync = 1;
+
return 0;
}
else
sb->resync_offset = cpu_to_le64(0);
+ if (mddev->bitmap && mddev->bitmap_file == NULL) {
+ sb->bitmap_offset = cpu_to_le32((__u32)mddev->bitmap_offset);
+ sb->feature_map = cpu_to_le32(1);
+ }
+
max_dev = 0;
ITERATE_RDEV(mddev,rdev2,tmp)
if (rdev2->desc_nr+1 > max_dev)
printk("md: * <COMPLETE RAID STATE PRINTOUT> *\n");
printk("md: **********************************\n");
ITERATE_MDDEV(mddev,tmp) {
- printk("%s: ", mdname(mddev));
+ if (mddev->bitmap)
+ bitmap_print_sb(mddev->bitmap);
+ else
+ printk("%s: ", mdname(mddev));
ITERATE_RDEV(mddev,rdev,tmp2)
printk("<%s>", bdevname(rdev->bdev,b));
printk("\n");
}
-static int write_disk_sb(mdk_rdev_t * rdev)
-{
- char b[BDEVNAME_SIZE];
- if (!rdev->sb_loaded) {
- MD_BUG();
- return 1;
- }
- if (rdev->faulty) {
- MD_BUG();
- return 1;
- }
-
- dprintk(KERN_INFO "(write) %s's sb offset: %llu\n",
- bdevname(rdev->bdev,b),
- (unsigned long long)rdev->sb_offset);
-
- if (sync_page_io(rdev->bdev, rdev->sb_offset<<1, MD_SB_BYTES, rdev->sb_page, WRITE))
- return 0;
-
- printk("md: write_disk_sb failed for device %s\n",
- bdevname(rdev->bdev,b));
- return 1;
-}
-
static void sync_sbs(mddev_t * mddev)
{
mdk_rdev_t *rdev;
static void md_update_sb(mddev_t * mddev)
{
- int err, count = 100;
+ int err;
struct list_head *tmp;
mdk_rdev_t *rdev;
+ int sync_req;
- mddev->sb_dirty = 0;
repeat:
+ spin_lock(&mddev->write_lock);
+ sync_req = mddev->in_sync;
mddev->utime = get_seconds();
mddev->events ++;
MD_BUG();
mddev->events --;
}
+ mddev->sb_dirty = 2;
sync_sbs(mddev);
/*
* do not write anything to disk if using
* nonpersistent superblocks
*/
- if (!mddev->persistent)
+ if (!mddev->persistent) {
+ mddev->sb_dirty = 0;
+ spin_unlock(&mddev->write_lock);
+ wake_up(&mddev->sb_wait);
return;
+ }
+ spin_unlock(&mddev->write_lock);
dprintk(KERN_INFO
"md: updating %s RAID superblock on device (in sync %d)\n",
mdname(mddev),mddev->in_sync);
- err = 0;
+ err = bitmap_update_sb(mddev->bitmap);
ITERATE_RDEV(mddev,rdev,tmp) {
char b[BDEVNAME_SIZE];
dprintk(KERN_INFO "md: ");
dprintk("%s ", bdevname(rdev->bdev,b));
if (!rdev->faulty) {
- err += write_disk_sb(rdev);
+ md_super_write(mddev,rdev,
+ rdev->sb_offset<<1, MD_SB_BYTES,
+ rdev->sb_page);
+ dprintk(KERN_INFO "(write) %s's sb offset: %llu\n",
+ bdevname(rdev->bdev,b),
+ (unsigned long long)rdev->sb_offset);
+
} else
dprintk(")\n");
- if (!err && mddev->level == LEVEL_MULTIPATH)
+ if (mddev->level == LEVEL_MULTIPATH)
/* only need to write one superblock... */
break;
}
- if (err) {
- if (--count) {
- printk(KERN_ERR "md: errors occurred during superblock"
- " update, repeating\n");
- goto repeat;
- }
- printk(KERN_ERR \
- "md: excessive errors occurred during superblock update, exiting\n");
+ wait_event(mddev->sb_wait, atomic_read(&mddev->pending_writes)==0);
+ /* if there was a failure, sb_dirty was set to 1, and we re-write super */
+
+ spin_lock(&mddev->write_lock);
+ if (mddev->in_sync != sync_req|| mddev->sb_dirty == 1) {
+ /* have to write it out again */
+ spin_unlock(&mddev->write_lock);
+ goto repeat;
}
+ mddev->sb_dirty = 0;
+ spin_unlock(&mddev->write_lock);
+ wake_up(&mddev->sb_wait);
+
}
/*
mddev->resync_max_sectors = mddev->size << 1; /* may be over-ridden by personality */
- err = mddev->pers->run(mddev);
+ /* before we start the array running, initialise the bitmap */
+ err = bitmap_create(mddev);
+ if (err)
+ printk(KERN_ERR "%s: failed to create bitmap (%d)\n",
+ mdname(mddev), err);
+ else
+ err = mddev->pers->run(mddev);
if (err) {
printk(KERN_ERR "md: pers->run() failed ...\n");
module_put(mddev->pers->owner);
mddev->pers = NULL;
- return -EINVAL;
+ bitmap_destroy(mddev);
+ return err;
}
atomic_set(&mddev->writes_pending,0);
mddev->safemode = 0;
if (ro)
set_disk_ro(disk, 1);
}
+
+ bitmap_destroy(mddev);
+ if (mddev->bitmap_file) {
+ atomic_set(&mddev->bitmap_file->f_dentry->d_inode->i_writecount, 1);
+ fput(mddev->bitmap_file);
+ mddev->bitmap_file = NULL;
+ }
+
/*
* Free resources if final stop
*/
return 0;
}
+static int get_bitmap_file(mddev_t * mddev, void * arg)
+{
+ mdu_bitmap_file_t *file = NULL; /* too big for stack allocation */
+ char *ptr, *buf = NULL;
+ int err = -ENOMEM;
+
+ file = kmalloc(sizeof(*file), GFP_KERNEL);
+ if (!file)
+ goto out;
+
+ /* bitmap disabled, zero the first byte and copy out */
+ if (!mddev->bitmap || !mddev->bitmap->file) {
+ file->pathname[0] = '\0';
+ goto copy_out;
+ }
+
+ buf = kmalloc(sizeof(file->pathname), GFP_KERNEL);
+ if (!buf)
+ goto out;
+
+ ptr = file_path(mddev->bitmap->file, buf, sizeof(file->pathname));
+ if (!ptr)
+ goto out;
+
+ strcpy(file->pathname, ptr);
+
+copy_out:
+ err = 0;
+ if (copy_to_user(arg, file, sizeof(*file)))
+ err = -EFAULT;
+out:
+ kfree(buf);
+ kfree(file);
+ return err;
+}
+
static int get_disk_info(mddev_t * mddev, void __user * arg)
{
mdu_disk_info_t info;
PTR_ERR(rdev));
return PTR_ERR(rdev);
}
+ /* set save_raid_disk if appropriate */
+ if (!mddev->persistent) {
+ if (info->state & (1<<MD_DISK_SYNC) &&
+ info->raid_disk < mddev->raid_disks)
+ rdev->raid_disk = info->raid_disk;
+ else
+ rdev->raid_disk = -1;
+ } else
+ super_types[mddev->major_version].
+ validate_super(mddev, rdev);
+ rdev->saved_raid_disk = rdev->raid_disk;
+
rdev->in_sync = 0; /* just to be sure */
rdev->raid_disk = -1;
err = bind_rdev_to_array(rdev, mddev);
if (err)
export_rdev(rdev);
+
+ set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
if (mddev->thread)
md_wakeup_thread(mddev->thread);
return err;
return err;
}
+/* similar to deny_write_access, but accounts for our holding a reference
+ * to the file ourselves */
+static int deny_bitmap_write_access(struct file * file)
+{
+ struct inode *inode = file->f_mapping->host;
+
+ spin_lock(&inode->i_lock);
+ if (atomic_read(&inode->i_writecount) > 1) {
+ spin_unlock(&inode->i_lock);
+ return -ETXTBSY;
+ }
+ atomic_set(&inode->i_writecount, -1);
+ spin_unlock(&inode->i_lock);
+
+ return 0;
+}
+
+static int set_bitmap_file(mddev_t *mddev, int fd)
+{
+ int err;
+
+ if (mddev->pers)
+ return -EBUSY;
+
+ mddev->bitmap_file = fget(fd);
+
+ if (mddev->bitmap_file == NULL) {
+ printk(KERN_ERR "%s: error: failed to get bitmap file\n",
+ mdname(mddev));
+ return -EBADF;
+ }
+
+ err = deny_bitmap_write_access(mddev->bitmap_file);
+ if (err) {
+ printk(KERN_ERR "%s: error: bitmap file is already in use\n",
+ mdname(mddev));
+ fput(mddev->bitmap_file);
+ mddev->bitmap_file = NULL;
+ } else
+ mddev->bitmap_offset = 0; /* file overrides offset */
+ return err;
+}
+
/*
* set_array_info is used two different ways
* The original usage is when creating a new array.
/*
* Commands querying/configuring an existing array:
*/
- /* if we are initialised yet, only ADD_NEW_DISK or STOP_ARRAY is allowed */
- if (!mddev->raid_disks && cmd != ADD_NEW_DISK && cmd != STOP_ARRAY && cmd != RUN_ARRAY) {
+ /* if we are not initialised yet, only ADD_NEW_DISK, STOP_ARRAY,
+ * RUN_ARRAY, and SET_BITMAP_FILE are allowed */
+ if (!mddev->raid_disks && cmd != ADD_NEW_DISK && cmd != STOP_ARRAY
+ && cmd != RUN_ARRAY && cmd != SET_BITMAP_FILE) {
err = -ENODEV;
goto abort_unlock;
}
err = get_array_info(mddev, argp);
goto done_unlock;
+ case GET_BITMAP_FILE:
+ err = get_bitmap_file(mddev, (void *)arg);
+ goto done_unlock;
+
case GET_DISK_INFO:
err = get_disk_info(mddev, argp);
goto done_unlock;
err = do_md_run (mddev);
goto done_unlock;
+ case SET_BITMAP_FILE:
+ err = set_bitmap_file(mddev, (int)arg);
+ goto done_unlock;
+
default:
if (_IOC_TYPE(cmd) == MD_MAJOR)
printk(KERN_WARNING "md: %s(pid %d) used"
while (thread->run) {
void (*run)(mddev_t *);
- wait_event_interruptible(thread->wqueue,
- test_bit(THREAD_WAKEUP, &thread->flags));
+ wait_event_interruptible_timeout(thread->wqueue,
+ test_bit(THREAD_WAKEUP, &thread->flags),
+ thread->timeout);
if (current->flags & PF_FREEZE)
refrigerator(PF_FREEZE);
thread->run = run;
thread->mddev = mddev;
thread->name = name;
+ thread->timeout = MAX_SCHEDULE_TIMEOUT;
ret = kernel_thread(md_thread, thread, 0);
if (ret < 0) {
kfree(thread);
if (!rdev || rdev->faulty)
return;
-
+/*
dprintk("md_error dev:%s, rdev:(%d:%d), (caller: %p,%p,%p,%p).\n",
mdname(mddev),
MAJOR(rdev->bdev->bd_dev), MINOR(rdev->bdev->bd_dev),
__builtin_return_address(0),__builtin_return_address(1),
__builtin_return_address(2),__builtin_return_address(3));
-
+*/
if (!mddev->pers->error_handler)
return;
mddev->pers->error_handler(mddev,rdev);
struct list_head *tmp2;
mdk_rdev_t *rdev;
int i;
+ struct bitmap *bitmap;
if (v == (void*)1) {
seq_printf(seq, "Personalities : ");
if (mddev->pers) {
mddev->pers->status (seq, mddev);
seq_printf(seq, "\n ");
- if (mddev->curr_resync > 2)
+ if (mddev->curr_resync > 2) {
status_resync (seq, mddev);
- else if (mddev->curr_resync == 1 || mddev->curr_resync == 2)
- seq_printf(seq, " resync=DELAYED");
+ seq_printf(seq, "\n ");
+ } else if (mddev->curr_resync == 1 || mddev->curr_resync == 2)
+ seq_printf(seq, " resync=DELAYED\n ");
+ } else
+ seq_printf(seq, "\n ");
+
+ if ((bitmap = mddev->bitmap)) {
+ unsigned long chunk_kb;
+ unsigned long flags;
+ spin_lock_irqsave(&bitmap->lock, flags);
+ chunk_kb = bitmap->chunksize >> 10;
+ seq_printf(seq, "bitmap: %lu/%lu pages [%luKB], "
+ "%lu%s chunk",
+ bitmap->pages - bitmap->missing_pages,
+ bitmap->pages,
+ (bitmap->pages - bitmap->missing_pages)
+ << (PAGE_SHIFT - 10),
+ chunk_kb ? chunk_kb : bitmap->chunksize,
+ chunk_kb ? "KB" : "B");
+ if (bitmap->file) {
+ seq_printf(seq, ", file: ");
+ seq_path(seq, bitmap->file->f_vfsmnt,
+ bitmap->file->f_dentry," \t\n");
+ }
+
+ seq_printf(seq, "\n");
+ spin_unlock_irqrestore(&bitmap->lock, flags);
}
seq_printf(seq, "\n");
}
-void md_write_start(mddev_t *mddev)
+/* md_write_start(mddev, bi)
+ * If we need to update some array metadata (e.g. 'active' flag
+ * in superblock) before writing, schedule a superblock update
+ * and wait for it to complete.
+ */
+void md_write_start(mddev_t *mddev, struct bio *bi)
{
- if (!atomic_read(&mddev->writes_pending)) {
- mddev_lock_uninterruptible(mddev);
+ DEFINE_WAIT(w);
+ if (bio_data_dir(bi) != WRITE)
+ return;
+
+ atomic_inc(&mddev->writes_pending);
+ if (mddev->in_sync) {
+ spin_lock(&mddev->write_lock);
if (mddev->in_sync) {
mddev->in_sync = 0;
- del_timer(&mddev->safemode_timer);
- md_update_sb(mddev);
+ mddev->sb_dirty = 1;
+ md_wakeup_thread(mddev->thread);
}
- atomic_inc(&mddev->writes_pending);
- mddev_unlock(mddev);
- } else
- atomic_inc(&mddev->writes_pending);
+ spin_unlock(&mddev->write_lock);
+ }
+ wait_event(mddev->sb_wait, mddev->sb_dirty==0);
}
void md_write_end(mddev_t *mddev)
}
}
-static inline void md_enter_safemode(mddev_t *mddev)
-{
- if (!mddev->safemode) return;
- if (mddev->safemode == 2 &&
- (atomic_read(&mddev->writes_pending) || mddev->in_sync ||
- mddev->recovery_cp != MaxSector))
- return; /* avoid the lock */
- mddev_lock_uninterruptible(mddev);
- if (mddev->safemode && !atomic_read(&mddev->writes_pending) &&
- !mddev->in_sync && mddev->recovery_cp == MaxSector) {
- mddev->in_sync = 1;
- md_update_sb(mddev);
- }
- mddev_unlock(mddev);
-
- if (mddev->safemode == 1)
- mddev->safemode = 0;
-}
-
-void md_handle_safemode(mddev_t *mddev)
-{
- if (signal_pending(current)) {
- printk(KERN_INFO "md: %s in immediate safe mode\n",
- mdname(mddev));
- mddev->safemode = 2;
- flush_signals(current);
- }
- md_enter_safemode(mddev);
-}
-
-
static DECLARE_WAIT_QUEUE_HEAD(resync_wait);
#define SYNC_MARKS 10
mddev_t *mddev2;
unsigned int currspeed = 0,
window;
- sector_t max_sectors,j;
+ sector_t max_sectors,j, io_sectors;
unsigned long mark[SYNC_MARKS];
sector_t mark_cnt[SYNC_MARKS];
int last_mark,m;
struct list_head *tmp;
sector_t last_check;
+ int skipped = 0;
/* just incase thread restarts... */
if (test_bit(MD_RECOVERY_DONE, &mddev->recovery))
if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery))
/* resync follows the size requested by the personality,
- * which default to physical size, but can be virtual size
+ * which defaults to physical size, but can be virtual size
*/
max_sectors = mddev->resync_max_sectors;
else
sysctl_speed_limit_max);
is_mddev_idle(mddev); /* this also initializes IO event counters */
- if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery))
+ /* we don't use the checkpoint if there's a bitmap */
+ if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) && !mddev->bitmap)
j = mddev->recovery_cp;
else
j = 0;
+ io_sectors = 0;
for (m = 0; m < SYNC_MARKS; m++) {
mark[m] = jiffies;
- mark_cnt[m] = j;
+ mark_cnt[m] = io_sectors;
}
last_mark = 0;
mddev->resync_mark = mark[last_mark];
}
while (j < max_sectors) {
- int sectors;
+ sector_t sectors;
- sectors = mddev->pers->sync_request(mddev, j, currspeed < sysctl_speed_limit_min);
- if (sectors < 0) {
+ skipped = 0;
+ sectors = mddev->pers->sync_request(mddev, j, &skipped,
+ currspeed < sysctl_speed_limit_min);
+ if (sectors == 0) {
set_bit(MD_RECOVERY_ERR, &mddev->recovery);
goto out;
}
- atomic_add(sectors, &mddev->recovery_active);
+
+ if (!skipped) { /* actual IO requested */
+ io_sectors += sectors;
+ atomic_add(sectors, &mddev->recovery_active);
+ }
+
j += sectors;
if (j>1) mddev->curr_resync = j;
- if (last_check + window > j || j == max_sectors)
+
+ if (last_check + window > io_sectors || j == max_sectors)
continue;
- last_check = j;
+ last_check = io_sectors;
if (test_bit(MD_RECOVERY_INTR, &mddev->recovery) ||
test_bit(MD_RECOVERY_ERR, &mddev->recovery))
mddev->resync_mark = mark[next];
mddev->resync_mark_cnt = mark_cnt[next];
mark[next] = jiffies;
- mark_cnt[next] = j - atomic_read(&mddev->recovery_active);
+ mark_cnt[next] = io_sectors - atomic_read(&mddev->recovery_active);
last_mark = next;
}
mddev->queue->unplug_fn(mddev->queue);
cond_resched();
- currspeed = ((unsigned long)(j-mddev->resync_mark_cnt))/2/((jiffies-mddev->resync_mark)/HZ +1) +1;
+ currspeed = ((unsigned long)(io_sectors-mddev->resync_mark_cnt))/2
+ /((jiffies-mddev->resync_mark)/HZ +1) +1;
if (currspeed > sysctl_speed_limit_min) {
if ((currspeed > sysctl_speed_limit_max) ||
wait_event(mddev->recovery_wait, !atomic_read(&mddev->recovery_active));
/* tell personality that we are finished */
- mddev->pers->sync_request(mddev, max_sectors, 1);
+ mddev->pers->sync_request(mddev, max_sectors, &skipped, 1);
if (!test_bit(MD_RECOVERY_ERR, &mddev->recovery) &&
mddev->curr_resync > 2 &&
mddev->recovery_cp = MaxSector;
}
- md_enter_safemode(mddev);
skip:
mddev->curr_resync = 0;
wake_up(&resync_wait);
struct list_head *rtmp;
- dprintk(KERN_INFO "md: recovery thread got woken up ...\n");
+ if (mddev->bitmap)
+ bitmap_daemon_work(mddev->bitmap);
if (mddev->ro)
return;
+
+ if (signal_pending(current)) {
+ if (mddev->pers->sync_request) {
+ printk(KERN_INFO "md: %s in immediate safe mode\n",
+ mdname(mddev));
+ mddev->safemode = 2;
+ }
+ flush_signals(current);
+ }
+
if ( ! (
mddev->sb_dirty ||
test_bit(MD_RECOVERY_NEEDED, &mddev->recovery) ||
- test_bit(MD_RECOVERY_DONE, &mddev->recovery)
+ test_bit(MD_RECOVERY_DONE, &mddev->recovery) ||
+ (mddev->safemode == 1) ||
+ (mddev->safemode == 2 && ! atomic_read(&mddev->writes_pending)
+ && !mddev->in_sync && mddev->recovery_cp == MaxSector)
))
return;
+
if (mddev_trylock(mddev)==0) {
int spares =0;
+
+ spin_lock(&mddev->write_lock);
+ if (mddev->safemode && !atomic_read(&mddev->writes_pending) &&
+ !mddev->in_sync && mddev->recovery_cp == MaxSector) {
+ mddev->in_sync = 1;
+ mddev->sb_dirty = 1;
+ }
+ if (mddev->safemode == 1)
+ mddev->safemode = 0;
+ spin_unlock(&mddev->write_lock);
+
if (mddev->sb_dirty)
md_update_sb(mddev);
+
+
if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) &&
!test_bit(MD_RECOVERY_DONE, &mddev->recovery)) {
/* resync/recovery still happening */
mddev->pers->spare_active(mddev);
}
md_update_sb(mddev);
+
+ /* if array is no-longer degraded, then any saved_raid_disk
+ * information must be scrapped
+ */
+ if (!mddev->degraded)
+ ITERATE_RDEV(mddev,rdev,rtmp)
+ rdev->saved_raid_disk = -1;
+
mddev->recovery = 0;
/* flag recovery needed just to double check */
set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
set_bit(MD_RECOVERY_RUNNING, &mddev->recovery);
if (!spares)
set_bit(MD_RECOVERY_SYNC, &mddev->recovery);
+ if (spares && mddev->bitmap && ! mddev->bitmap->file) {
+ /* We are adding a device or devices to an array
+ * which has the bitmap stored on all devices.
+ * So make sure all bitmap pages get written
+ */
+ bitmap_write_all(mddev->bitmap);
+ }
mddev->sync_thread = md_register_thread(md_do_sync,
mddev,
"%s_resync");
" MD_SB_DISKS=%d\n",
MD_MAJOR_VERSION, MD_MINOR_VERSION,
MD_PATCHLEVEL_VERSION, MAX_MD_DEVS, MD_SB_DISKS);
+ printk(KERN_INFO "md: bitmap version %d.%d\n", BITMAP_MAJOR,
+ BITMAP_MINOR);
if (register_blkdev(MAJOR_NR, "md"))
return -1;
EXPORT_SYMBOL(md_done_sync);
EXPORT_SYMBOL(md_write_start);
EXPORT_SYMBOL(md_write_end);
-EXPORT_SYMBOL(md_handle_safemode);
EXPORT_SYMBOL(md_register_thread);
EXPORT_SYMBOL(md_unregister_thread);
EXPORT_SYMBOL(md_wakeup_thread);
out_free_conf:
if (conf->pool)
mempool_destroy(conf->pool);
- if (conf->multipaths)
- kfree(conf->multipaths);
+ kfree(conf->multipaths);
kfree(conf);
mddev->private = NULL;
out:
return 0;
out_free_conf:
- if (conf->strip_zone)
- kfree(conf->strip_zone);
- if (conf->devlist)
- kfree (conf->devlist);
+ kfree(conf->strip_zone);
+ kfree(conf->devlist);
kfree(conf);
mddev->private = NULL;
out:
raid0_conf_t *conf = mddev_to_conf(mddev);
blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
- kfree (conf->hash_table);
+ kfree(conf->hash_table);
conf->hash_table = NULL;
- kfree (conf->strip_zone);
+ kfree(conf->strip_zone);
conf->strip_zone = NULL;
- kfree (conf);
+ kfree(conf);
mddev->private = NULL;
return 0;
* Fixes to reconstruction by Jakob Østergaard" <jakob@ostenfeld.dk>
* Various fixes by Neil Brown <neilb@cse.unsw.edu.au>
*
+ * Changes by Peter T. Breuer <ptb@it.uc3m.es> 31/1/2003 to support
+ * bitmapped intelligence in resync:
+ *
+ * - bitmap marked during normal i/o
+ * - bitmap used to skip nondirty blocks during sync
+ *
+ * Additions to bitmap code, (C) 2003-2004 Paul Clements, SteelEye Technology:
+ * - persistent bitmap code
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include "dm-bio-list.h"
#include <linux/raid/raid1.h>
+#include <linux/raid/bitmap.h>
+
+#define DEBUG 0
+#if DEBUG
+#define PRINTK(x...) printk(x)
+#else
+#define PRINTK(x...)
+#endif
/*
* Number of guaranteed r1bios in case of extreme VM load:
/*
* this branch is our 'one mirror IO has finished' event handler:
*/
- if (!uptodate)
+ if (!uptodate) {
md_error(r1_bio->mddev, conf->mirrors[mirror].rdev);
- else
+ /* an I/O failed, we can't clear the bitmap */
+ set_bit(R1BIO_Degraded, &r1_bio->state);
+ } else
/*
* Set R1BIO_Uptodate in our master bio, so that
* we will return a good error code for to the higher
* already.
*/
if (atomic_dec_and_test(&r1_bio->remaining)) {
+ /* clear the bitmap if all writes complete successfully */
+ bitmap_endwrite(r1_bio->mddev->bitmap, r1_bio->sector,
+ r1_bio->sectors,
+ !test_bit(R1BIO_Degraded, &r1_bio->state));
md_write_end(r1_bio->mddev);
raid_end_bio_io(r1_bio);
}
static void raid1_unplug(request_queue_t *q)
{
- unplug_slaves(q->queuedata);
+ mddev_t *mddev = q->queuedata;
+
+ unplug_slaves(mddev);
+ md_wakeup_thread(mddev->thread);
}
static int raid1_issue_flush(request_queue_t *q, struct gendisk *disk,
{
spin_lock_irq(&conf->resync_lock);
wait_event_lock_irq(conf->wait_idle, !waitqueue_active(&conf->wait_resume),
- conf->resync_lock, unplug_slaves(conf->mddev));
+ conf->resync_lock, raid1_unplug(conf->mddev->queue));
if (!conf->barrier++) {
wait_event_lock_irq(conf->wait_idle, !conf->nr_pending,
- conf->resync_lock, unplug_slaves(conf->mddev));
+ conf->resync_lock, raid1_unplug(conf->mddev->queue));
if (conf->nr_pending)
BUG();
}
wait_event_lock_irq(conf->wait_resume, conf->barrier < RESYNC_DEPTH,
- conf->resync_lock, unplug_slaves(conf->mddev));
+ conf->resync_lock, raid1_unplug(conf->mddev->queue));
conf->next_resync = sect;
spin_unlock_irq(&conf->resync_lock);
}
mirror_info_t *mirror;
r1bio_t *r1_bio;
struct bio *read_bio;
- int i, disks;
+ int i, targets = 0, disks;
mdk_rdev_t *rdev;
+ struct bitmap *bitmap = mddev->bitmap;
+ unsigned long flags;
+ struct bio_list bl;
+
/*
* Register the new request and wait if the reconstruction
* thread has put up a bar for new requests.
* Continue immediately if no resync is active currently.
*/
+ md_write_start(mddev, bio); /* wait on superblock update early */
+
spin_lock_irq(&conf->resync_lock);
wait_event_lock_irq(conf->wait_resume, !conf->barrier, conf->resync_lock, );
conf->nr_pending++;
r1_bio->master_bio = bio;
r1_bio->sectors = bio->bi_size >> 9;
-
+ r1_bio->state = 0;
r1_bio->mddev = mddev;
r1_bio->sector = bio->bi_sector;
* bios[x] to bio
*/
disks = conf->raid_disks;
+#if 0
+ { static int first=1;
+ if (first) printk("First Write sector %llu disks %d\n",
+ (unsigned long long)r1_bio->sector, disks);
+ first = 0;
+ }
+#endif
rcu_read_lock();
for (i = 0; i < disks; i++) {
if ((rdev=conf->mirrors[i].rdev) != NULL &&
r1_bio->bios[i] = NULL;
} else
r1_bio->bios[i] = bio;
+ targets++;
} else
r1_bio->bios[i] = NULL;
}
rcu_read_unlock();
- atomic_set(&r1_bio->remaining, 1);
- md_write_start(mddev);
+ if (targets < conf->raid_disks) {
+ /* array is degraded, we will not clear the bitmap
+ * on I/O completion (see raid1_end_write_request) */
+ set_bit(R1BIO_Degraded, &r1_bio->state);
+ }
+
+ atomic_set(&r1_bio->remaining, 0);
+
+ bio_list_init(&bl);
for (i = 0; i < disks; i++) {
struct bio *mbio;
if (!r1_bio->bios[i])
mbio->bi_private = r1_bio;
atomic_inc(&r1_bio->remaining);
- generic_make_request(mbio);
- }
- if (atomic_dec_and_test(&r1_bio->remaining)) {
- md_write_end(mddev);
- raid_end_bio_io(r1_bio);
+ bio_list_add(&bl, mbio);
}
+ bitmap_startwrite(bitmap, bio->bi_sector, r1_bio->sectors);
+ spin_lock_irqsave(&conf->device_lock, flags);
+ bio_list_merge(&conf->pending_bio_list, &bl);
+ bio_list_init(&bl);
+
+ blk_plug_device(mddev->queue);
+ spin_unlock_irqrestore(&conf->device_lock, flags);
+
+#if 0
+ while ((bio = bio_list_pop(&bl)) != NULL)
+ generic_make_request(bio);
+#endif
+
return 0;
}
{
spin_lock_irq(&conf->resync_lock);
wait_event_lock_irq(conf->wait_resume, !conf->barrier,
- conf->resync_lock, unplug_slaves(conf->mddev));
+ conf->resync_lock, raid1_unplug(conf->mddev->queue));
spin_unlock_irq(&conf->resync_lock);
if (conf->barrier) BUG();
{
conf_t *conf = mddev->private;
int found = 0;
- int mirror;
+ int mirror = 0;
mirror_info_t *p;
+ if (rdev->saved_raid_disk >= 0 &&
+ conf->mirrors[rdev->saved_raid_disk].rdev == NULL)
+ mirror = rdev->saved_raid_disk;
for (mirror=0; mirror < mddev->raid_disks; mirror++)
if ( !(p=conf->mirrors+mirror)->rdev) {
p->head_position = 0;
rdev->raid_disk = mirror;
found = 1;
+ if (rdev->saved_raid_disk != mirror)
+ conf->fullsync = 1;
p->rdev = rdev;
break;
}
* or re-read if the read failed.
* We don't do much here, just schedule handling by raid1d
*/
- if (!uptodate)
+ if (!uptodate) {
md_error(r1_bio->mddev,
conf->mirrors[r1_bio->read_disk].rdev);
- else
+ set_bit(R1BIO_Degraded, &r1_bio->state);
+ } else
set_bit(R1BIO_Uptodate, &r1_bio->state);
rdev_dec_pending(conf->mirrors[r1_bio->read_disk].rdev, conf->mddev);
reschedule_retry(r1_bio);
mirror = i;
break;
}
- if (!uptodate)
+ if (!uptodate) {
md_error(mddev, conf->mirrors[mirror].rdev);
+ set_bit(R1BIO_Degraded, &r1_bio->state);
+ }
update_head_pos(mirror, r1_bio);
if (atomic_dec_and_test(&r1_bio->remaining)) {
bio = r1_bio->bios[r1_bio->read_disk];
+/*
+ if (r1_bio->sector == 0) printk("First sync write startss\n");
+*/
/*
* schedule writes
*/
atomic_inc(&conf->mirrors[i].rdev->nr_pending);
atomic_inc(&r1_bio->remaining);
md_sync_acct(conf->mirrors[i].rdev->bdev, wbio->bi_size >> 9);
+
generic_make_request(wbio);
}
if (atomic_dec_and_test(&r1_bio->remaining)) {
+ /* if we're here, all write(s) have completed, so clean up */
md_done_sync(mddev, r1_bio->sectors, 1);
put_buf(r1_bio);
}
mdk_rdev_t *rdev;
md_check_recovery(mddev);
- md_handle_safemode(mddev);
for (;;) {
char b[BDEVNAME_SIZE];
spin_lock_irqsave(&conf->device_lock, flags);
+
+ if (conf->pending_bio_list.head) {
+ bio = bio_list_get(&conf->pending_bio_list);
+ blk_remove_plug(mddev->queue);
+ spin_unlock_irqrestore(&conf->device_lock, flags);
+ /* flush any pending bitmap writes to disk before proceeding w/ I/O */
+ if (bitmap_unplug(mddev->bitmap) != 0)
+ printk("%s: bitmap file write failed!\n", mdname(mddev));
+
+ while (bio) { /* submit pending writes */
+ struct bio *next = bio->bi_next;
+ bio->bi_next = NULL;
+ generic_make_request(bio);
+ bio = next;
+ }
+ unplug = 1;
+
+ continue;
+ }
+
if (list_empty(head))
break;
r1_bio = list_entry(head->prev, r1bio_t, retry_list);
* that can be installed to exclude normal IO requests.
*/
-static int sync_request(mddev_t *mddev, sector_t sector_nr, int go_faster)
+static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, int go_faster)
{
conf_t *conf = mddev_to_conf(mddev);
mirror_info_t *mirror;
int disk;
int i;
int write_targets = 0;
+ int sync_blocks;
if (!conf->r1buf_pool)
+ {
+/*
+ printk("sync start - bitmap %p\n", mddev->bitmap);
+*/
if (init_resync(conf))
- return -ENOMEM;
+ return 0;
+ }
max_sector = mddev->size << 1;
if (sector_nr >= max_sector) {
+ /* If we aborted, we need to abort the
+ * sync on the 'current' bitmap chunk (there will
+ * only be one in raid1 resync.
+ * We can find the current addess in mddev->curr_resync
+ */
+ if (!conf->fullsync) {
+ if (mddev->curr_resync < max_sector)
+ bitmap_end_sync(mddev->bitmap,
+ mddev->curr_resync,
+ &sync_blocks, 1);
+ bitmap_close_sync(mddev->bitmap);
+ }
+ if (mddev->curr_resync >= max_sector)
+ conf->fullsync = 0;
close_sync(conf);
return 0;
}
+ if (!conf->fullsync &&
+ !bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks)) {
+ /* We can skip this block, and probably several more */
+ *skipped = 1;
+ return sync_blocks;
+ }
/*
* If there is non-resync activity waiting for us then
* put in a delay to throttle resync.
r1_bio->mddev = mddev;
r1_bio->sector = sector_nr;
+ r1_bio->state = 0;
set_bit(R1BIO_IsSync, &r1_bio->state);
r1_bio->read_disk = disk;
bio->bi_bdev = conf->mirrors[i].rdev->bdev;
bio->bi_private = r1_bio;
}
+
+ if (write_targets + 1 < conf->raid_disks)
+ /* array degraded, can't clear bitmap */
+ set_bit(R1BIO_Degraded, &r1_bio->state);
+
if (write_targets == 0) {
/* There is nowhere to write, so all non-sync
* drives must be failed - so we are finished
*/
- int rv = max_sector - sector_nr;
- md_done_sync(mddev, rv, 1);
+ sector_t rv = max_sector - sector_nr;
+ *skipped = 1;
put_buf(r1_bio);
rdev_dec_pending(conf->mirrors[disk].rdev, mddev);
return rv;
}
nr_sectors = 0;
+ sync_blocks = 0;
do {
struct page *page;
int len = PAGE_SIZE;
len = (max_sector - sector_nr) << 9;
if (len == 0)
break;
+ if (!conf->fullsync) {
+ if (sync_blocks == 0) {
+ if (!bitmap_start_sync(mddev->bitmap,
+ sector_nr, &sync_blocks))
+ break;
+ if (sync_blocks < (PAGE_SIZE>>9))
+ BUG();
+ if (len > (sync_blocks<<9)) len = sync_blocks<<9;
+ }
+ }
+
for (i=0 ; i < conf->raid_disks; i++) {
bio = r1_bio->bios[i];
if (bio->bi_end_io) {
}
nr_sectors += len>>9;
sector_nr += len>>9;
+ sync_blocks -= (len>>9);
} while (r1_bio->bios[disk]->bi_vcnt < RESYNC_PAGES);
bio_full:
bio = r1_bio->bios[disk];
init_waitqueue_head(&conf->wait_idle);
init_waitqueue_head(&conf->wait_resume);
+ bio_list_init(&conf->pending_bio_list);
+ bio_list_init(&conf->flushing_bio_list);
+
if (!conf->working_disks) {
printk(KERN_ERR "raid1: no operational mirrors for %s\n",
mdname(mddev));
conf->last_used = j;
-
- {
- mddev->thread = md_register_thread(raid1d, mddev, "%s_raid1");
- if (!mddev->thread) {
- printk(KERN_ERR
- "raid1: couldn't allocate thread for %s\n",
- mdname(mddev));
- goto out_free_conf;
- }
+ mddev->thread = md_register_thread(raid1d, mddev, "%s_raid1");
+ if (!mddev->thread) {
+ printk(KERN_ERR
+ "raid1: couldn't allocate thread for %s\n",
+ mdname(mddev));
+ goto out_free_conf;
}
+ if (mddev->bitmap) mddev->thread->timeout = mddev->bitmap->daemon_sleep * HZ;
+
printk(KERN_INFO
"raid1: raid set %s active with %d out of %d mirrors\n",
mdname(mddev), mddev->raid_disks - mddev->degraded,
if (conf) {
if (conf->r1bio_pool)
mempool_destroy(conf->r1bio_pool);
- if (conf->mirrors)
- kfree(conf->mirrors);
- if (conf->poolinfo)
- kfree(conf->poolinfo);
+ kfree(conf->mirrors);
+ kfree(conf->poolinfo);
kfree(conf);
mddev->private = NULL;
}
blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
if (conf->r1bio_pool)
mempool_destroy(conf->r1bio_pool);
- if (conf->mirrors)
- kfree(conf->mirrors);
- if (conf->poolinfo)
- kfree(conf->poolinfo);
+ kfree(conf->mirrors);
+ kfree(conf->poolinfo);
kfree(conf);
mddev->private = NULL;
return 0;
* We allocate a new r1bio_pool if we can.
* Then raise a device barrier and wait until all IO stops.
* Then resize conf->mirrors and swap in the new r1bio pool.
+ *
+ * At the same time, we "pack" the devices so that all the missing
+ * devices have the higher raid_disk numbers.
*/
mempool_t *newpool, *oldpool;
struct pool_info *newpoolinfo;
mirror_info_t *newmirrors;
conf_t *conf = mddev_to_conf(mddev);
+ int cnt;
- int d;
+ int d, d2;
- for (d= raid_disks; d < conf->raid_disks; d++)
- if (conf->mirrors[d].rdev)
+ if (raid_disks < conf->raid_disks) {
+ cnt=0;
+ for (d= 0; d < conf->raid_disks; d++)
+ if (conf->mirrors[d].rdev)
+ cnt++;
+ if (cnt > raid_disks)
return -EBUSY;
+ }
newpoolinfo = kmalloc(sizeof(*newpoolinfo), GFP_KERNEL);
if (!newpoolinfo)
spin_lock_irq(&conf->resync_lock);
conf->barrier++;
wait_event_lock_irq(conf->wait_idle, !conf->nr_pending,
- conf->resync_lock, unplug_slaves(mddev));
+ conf->resync_lock, raid1_unplug(mddev->queue));
spin_unlock_irq(&conf->resync_lock);
/* ok, everything is stopped */
oldpool = conf->r1bio_pool;
conf->r1bio_pool = newpool;
- for (d=0; d < raid_disks && d < conf->raid_disks; d++)
- newmirrors[d] = conf->mirrors[d];
+
+ for (d=d2=0; d < conf->raid_disks; d++)
+ if (conf->mirrors[d].rdev) {
+ conf->mirrors[d].rdev->raid_disk = d2;
+ newmirrors[d2++].rdev = conf->mirrors[d].rdev;
+ }
kfree(conf->mirrors);
conf->mirrors = newmirrors;
kfree(conf->poolinfo);
mddev->degraded += (raid_disks - conf->raid_disks);
conf->raid_disks = mddev->raid_disks = raid_disks;
+ conf->last_used = 0; /* just make sure it is in-range */
spin_lock_irq(&conf->resync_lock);
conf->barrier--;
spin_unlock_irq(&conf->resync_lock);
return 0;
}
+ md_write_start(mddev, bio);
+
/*
* Register the new request and wait if the reconstruction
* thread has put up a bar for new requests.
rcu_read_unlock();
atomic_set(&r10_bio->remaining, 1);
- md_write_start(mddev);
+
for (i = 0; i < conf->copies; i++) {
struct bio *mbio;
int d = r10_bio->devs[i].devnum;
mdk_rdev_t *rdev;
md_check_recovery(mddev);
- md_handle_safemode(mddev);
for (;;) {
char b[BDEVNAME_SIZE];
*
*/
-static int sync_request(mddev_t *mddev, sector_t sector_nr, int go_faster)
+static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, int go_faster)
{
conf_t *conf = mddev_to_conf(mddev);
r10bio_t *r10_bio;
if (!conf->r10buf_pool)
if (init_resync(conf))
- return -ENOMEM;
+ return 0;
skipped:
max_sector = mddev->size << 1;
max_sector = mddev->resync_max_sectors;
if (sector_nr >= max_sector) {
close_sync(conf);
+ *skipped = 1;
return sectors_skipped;
}
if (chunks_skipped >= conf->raid_disks) {
/* if there has been nothing to do on any drive,
* then there is nothing to do at all..
*/
- sector_t sec = max_sector - sector_nr;
- md_done_sync(mddev, sec, 1);
- return sec + sectors_skipped;
+ *skipped = 1;
+ return (max_sector - sector_nr) + sectors_skipped;
}
/* make sure whole request will fit in a chunk - if chunks
}
}
+ if (sectors_skipped)
+ /* pretend they weren't skipped, it makes
+ * no important difference in this case
+ */
+ md_done_sync(mddev, sectors_skipped, 1);
+
return sectors_skipped + nr_sectors;
giveup:
/* There is nowhere to write, so all non-sync
* drives must be failed, so try the next chunk...
*/
{
- int sec = max_sector - sector_nr;
+ sector_t sec = max_sector - sector_nr;
sectors_skipped += sec;
chunks_skipped ++;
sector_nr = max_sector;
- md_done_sync(mddev, sec, 1);
goto skipped;
}
}
out_free_conf:
if (conf->r10bio_pool)
mempool_destroy(conf->r10bio_pool);
- if (conf->mirrors)
- kfree(conf->mirrors);
+ kfree(conf->mirrors);
kfree(conf);
mddev->private = NULL;
out:
blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
if (conf->r10bio_pool)
mempool_destroy(conf->r10bio_pool);
- if (conf->mirrors)
- kfree(conf->mirrors);
+ kfree(conf->mirrors);
kfree(conf);
mddev->private = NULL;
return 0;
sector_t logical_sector, last_sector;
struct stripe_head *sh;
+ md_write_start(mddev, bi);
+
if (bio_data_dir(bi)==WRITE) {
disk_stat_inc(mddev->gendisk, writes);
disk_stat_add(mddev->gendisk, write_sectors, bio_sectors(bi));
last_sector = bi->bi_sector + (bi->bi_size>>9);
bi->bi_next = NULL;
bi->bi_phys_segments = 1; /* over-loaded to count active stripes */
- if ( bio_data_dir(bi) == WRITE )
- md_write_start(mddev);
+
for (;logical_sector < last_sector; logical_sector += STRIPE_SECTORS) {
DEFINE_WAIT(w);
}
/* FIXME go_faster isn't used */
-static int sync_request (mddev_t *mddev, sector_t sector_nr, int go_faster)
+static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, int go_faster)
{
raid5_conf_t *conf = (raid5_conf_t *) mddev->private;
struct stripe_head *sh;
* nothing we can do.
*/
if (mddev->degraded >= 1 && test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
- int rv = (mddev->size << 1) - sector_nr;
- md_done_sync(mddev, rv, 1);
+ sector_t rv = (mddev->size << 1) - sector_nr;
+ *skipped = 1;
return rv;
}
PRINTK("+++ raid5d active\n");
md_check_recovery(mddev);
- md_handle_safemode(mddev);
handled = 0;
spin_lock_irq(&conf->device_lock);
sector_t logical_sector, last_sector;
struct stripe_head *sh;
+ md_write_start(mddev, bi);
+
if (bio_data_dir(bi)==WRITE) {
disk_stat_inc(mddev->gendisk, writes);
disk_stat_add(mddev->gendisk, write_sectors, bio_sectors(bi));
bi->bi_next = NULL;
bi->bi_phys_segments = 1; /* over-loaded to count active stripes */
- if ( bio_data_dir(bi) == WRITE )
- md_write_start(mddev);
+
for (;logical_sector < last_sector; logical_sector += STRIPE_SECTORS) {
DEFINE_WAIT(w);
}
/* FIXME go_faster isn't used */
-static int sync_request (mddev_t *mddev, sector_t sector_nr, int go_faster)
+static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, int go_faster)
{
raid6_conf_t *conf = (raid6_conf_t *) mddev->private;
struct stripe_head *sh;
* nothing we can do.
*/
if (mddev->degraded >= 2 && test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
- int rv = (mddev->size << 1) - sector_nr;
- md_done_sync(mddev, rv, 1);
+ sector_t rv = (mddev->size << 1) - sector_nr;
+ *skipped = 1;
return rv;
}
PRINTK("+++ raid6d active\n");
md_check_recovery(mddev);
- md_handle_safemode(mddev);
handled = 0;
spin_lock_irq(&conf->device_lock);
I2C_ADV7171 >> 1, (I2C_ADV7171 >> 1) + 1,
I2C_CLIENT_END
};
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
-static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END };
+static unsigned short ignore = I2C_CLIENT_END;
static struct i2c_client_address_data addr_data = {
.normal_i2c = normal_i2c,
- .normal_i2c_range = normal_i2c_range,
- .probe = probe,
- .probe_range = probe_range,
- .ignore = ignore,
- .ignore_range = ignore_range,
- .force = force
+ .probe = &ignore,
+ .ignore = &ignore,
+ .force = &ignore,
};
static struct i2c_driver i2c_driver_adv7170;
I2C_ADV7176 >> 1, (I2C_ADV7176 >> 1) + 1,
I2C_CLIENT_END
};
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
-static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END };
+static unsigned short ignore = I2C_CLIENT_END;
static struct i2c_client_address_data addr_data = {
.normal_i2c = normal_i2c,
- .normal_i2c_range = normal_i2c_range,
- .probe = probe,
- .probe_range = probe_range,
- .ignore = ignore,
- .ignore_range = ignore_range,
- .force = force
+ .probe = &ignore,
+ .ignore = &ignore,
+ .force = &ignore,
};
static struct i2c_driver i2c_driver_adv7175;
I2C_BT819 >> 1,
I2C_CLIENT_END,
};
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
-static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END };
+static unsigned short ignore = I2C_CLIENT_END;
static struct i2c_client_address_data addr_data = {
.normal_i2c = normal_i2c,
- .normal_i2c_range = normal_i2c_range,
- .probe = probe,
- .probe_range = probe_range,
- .ignore = ignore,
- .ignore_range = ignore_range,
- .force = force
+ .probe = &ignore,
+ .ignore = &ignore,
+ .force = &ignore,
};
static struct i2c_driver i2c_driver_bt819;
MODULE_LICENSE("GPL");
/* Addresses to scan */
-static unsigned short normal_i2c[] = {I2C_CLIENT_END};
-static unsigned short normal_i2c_range[] = {I2C_BT832_ALT1>>1,I2C_BT832_ALT2>>1,I2C_CLIENT_END};
+static unsigned short normal_i2c[] = { I2C_BT832_ALT1>>1, I2C_BT832_ALT2>>1,
+ I2C_CLIENT_END };
I2C_CLIENT_INSMOD;
/* ---------------------------------------------------------------------- */
* concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
*/
static unsigned short normal_i2c[] = { I2C_BT856 >> 1, I2C_CLIENT_END };
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
-static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END };
+static unsigned short ignore = I2C_CLIENT_END;
static struct i2c_client_address_data addr_data = {
.normal_i2c = normal_i2c,
- .normal_i2c_range = normal_i2c_range,
- .probe = probe,
- .probe_range = probe_range,
- .ignore = ignore,
- .ignore_range = ignore_range,
- .force = force
+ .probe = &ignore,
+ .ignore = &ignore,
+ .force = &ignore,
};
static struct i2c_driver i2c_driver_bt856;
I2C_MSP3400C_ALT >> 1,
I2C_CLIENT_END
};
-static unsigned short normal_i2c_range[] = {I2C_CLIENT_END,I2C_CLIENT_END};
I2C_CLIENT_INSMOD;
/* ----------------------------------------------------------------------- */
/* Addresses to scan */
static unsigned short normal_i2c[] = { I2C_ADDRESS, I2C_CLIENT_END };
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
I2C_CLIENT_INSMOD;
static struct i2c_client client_template;
/* Addresses to scan */
static unsigned short normal_i2c[] = {34>>1,I2C_CLIENT_END};
-static unsigned short normal_i2c_range[] = {I2C_CLIENT_END};
I2C_CLIENT_INSMOD;
static struct i2c_client client_template;
(I2C_SAA7110 >> 1) + 1,
I2C_CLIENT_END
};
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
-static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END };
+static unsigned short ignore = I2C_CLIENT_END;
static struct i2c_client_address_data addr_data = {
.normal_i2c = normal_i2c,
- .normal_i2c_range = normal_i2c_range,
- .probe = probe,
- .probe_range = probe_range,
- .ignore = ignore,
- .ignore_range = ignore_range,
- .force = force
+ .probe = &ignore,
+ .ignore = &ignore,
+ .force = &ignore,
};
static struct i2c_driver i2c_driver_saa7110;
* concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
*/
static unsigned short normal_i2c[] = { I2C_SAA7111 >> 1, I2C_CLIENT_END };
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
-static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END };
+static unsigned short ignore = I2C_CLIENT_END;
static struct i2c_client_address_data addr_data = {
.normal_i2c = normal_i2c,
- .normal_i2c_range = normal_i2c_range,
- .probe = probe,
- .probe_range = probe_range,
- .ignore = ignore,
- .ignore_range = ignore_range,
- .force = force
+ .probe = &ignore,
+ .ignore = &ignore,
+ .force = &ignore,
};
static struct i2c_driver i2c_driver_saa7111;
*/
static unsigned short normal_i2c[] =
{ I2C_SAA7114 >> 1, I2C_SAA7114A >> 1, I2C_CLIENT_END };
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
-static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END };
+static unsigned short ignore = I2C_CLIENT_END;
static struct i2c_client_address_data addr_data = {
.normal_i2c = normal_i2c,
- .normal_i2c_range = normal_i2c_range,
- .probe = probe,
- .probe_range = probe_range,
- .ignore = ignore,
- .ignore_range = ignore_range,
- .force = force
+ .probe = &ignore,
+ .ignore = &ignore,
+ .force = &ignore,
};
static struct i2c_driver i2c_driver_saa7114;
/* Addresses to scan */
static unsigned short normal_i2c[] = {0x20, I2C_CLIENT_END};
-static unsigned short normal_i2c_range[] = {I2C_CLIENT_END};
I2C_CLIENT_INSMOD;
MODULE_DESCRIPTION("device driver for saa6752hs MPEG2 encoder");
* concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
*/
static unsigned short normal_i2c[] = { I2C_SAA7185 >> 1, I2C_CLIENT_END };
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
-static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END };
+static unsigned short ignore = I2C_CLIENT_END;
static struct i2c_client_address_data addr_data = {
.normal_i2c = normal_i2c,
- .normal_i2c_range = normal_i2c_range,
- .probe = probe,
- .probe_range = probe_range,
- .ignore = ignore,
- .ignore_range = ignore_range,
- .force = force
+ .probe = &ignore,
+ .ignore = &ignore,
+ .force = &ignore,
};
static struct i2c_driver i2c_driver_saa7185;
I2C_TDA7432 >> 1,
I2C_CLIENT_END,
};
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END, I2C_CLIENT_END };
I2C_CLIENT_INSMOD;
/* Structure of address and subaddresses for the tda7432 */
/* addresses to scan, found only at 0x42 (7-Bit) */
static unsigned short normal_i2c[] = { I2C_TDA9840, I2C_CLIENT_END };
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
/* magic definition of all other variables and things */
I2C_CLIENT_INSMOD;
I2C_TDA9875 >> 1,
I2C_CLIENT_END
};
-static unsigned short normal_i2c_range[] = {I2C_CLIENT_END};
I2C_CLIENT_INSMOD;
/* This is a superset of the TDA9875 */
0x96 >>1,
I2C_CLIENT_END,
};
-static unsigned short normal_i2c_range[] = {I2C_CLIENT_END,I2C_CLIENT_END};
I2C_CLIENT_INSMOD;
/* insmod options */
/* addresses to scan, found only at 0x03 and/or 0x43 (7-bit) */
static unsigned short normal_i2c[] = { I2C_TEA6415C_1, I2C_TEA6415C_2, I2C_CLIENT_END };
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
/* magic definition of all other variables and things */
I2C_CLIENT_INSMOD;
/* addresses to scan, found only at 0x4c and/or 0x4d (7-Bit) */
static unsigned short normal_i2c[] = { I2C_TEA6420_1, I2C_TEA6420_2, I2C_CLIENT_END };
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
/* magic definition of all other variables and things */
I2C_CLIENT_INSMOD;
static struct i2c_client client_template;
/* Addresses to scan */
-static unsigned short normal_i2c[] = {I2C_CLIENT_END};
-static unsigned short normal_i2c_range[] = {0x60, 0x61, I2C_CLIENT_END};
-static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short normal_i2c[] = { 0x60, 0x61, I2C_CLIENT_END };
+static unsigned short ignore = I2C_CLIENT_END;
static struct i2c_client_address_data addr_data = {
- normal_i2c, normal_i2c_range,
- probe, probe_range,
- ignore, ignore_range,
- force
+ .normal_i2c = normal_i2c,
+ .probe = &ignore,
+ .ignore = &ignore,
+ .force = &ignore,
};
/* ---------------------------------------------------------------------- */
/* standard i2c insmod options */
static unsigned short normal_i2c[] = {
0x4b, /* tda8290 */
- I2C_CLIENT_END
-};
-static unsigned short normal_i2c_range[] = {
- 0x60, 0x6f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
I2C_CLIENT_END
};
I2C_CLIENT_INSMOD;
static int tuner_probe(struct i2c_adapter *adap)
{
if (0 != addr) {
- normal_i2c[0] = addr;
- normal_i2c_range[0] = addr;
- normal_i2c_range[1] = addr;
+ normal_i2c[0] = addr;
+ normal_i2c[1] = I2C_CLIENT_END;
}
this_adap = 0;
I2C_TDA9874 >> 1,
I2C_PIC16C54 >> 1,
I2C_CLIENT_END };
-static unsigned short normal_i2c_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
I2C_CLIENT_INSMOD;
static struct i2c_driver driver;
0xa0 >> 1,
I2C_CLIENT_END,
};
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
I2C_CLIENT_INSMOD;
struct i2c_driver i2c_driver_tveeprom;
{ I2C_VPX3220 >> 1, (I2C_VPX3220 >> 1) + 4,
I2C_CLIENT_END
};
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
-static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END };
+static unsigned short ignore = I2C_CLIENT_END;
static struct i2c_client_address_data addr_data = {
.normal_i2c = normal_i2c,
- .normal_i2c_range = normal_i2c_range,
- .probe = probe,
- .probe_range = probe_range,
- .ignore = ignore,
- .ignore_range = ignore_range,
- .force = force
+ .probe = &ignore,
+ .ignore = &ignore,
+ .force = &ignore,
};
static struct i2c_driver vpx3220_i2c_driver;
*/
#include "ibmasm.h"
+#include "lowlevel.h"
static void exec_next_command(struct service_processor *sp);
static void free_command(struct kobject *kobj);
.release = free_command,
};
+static atomic_t command_count = ATOMIC_INIT(0);
-struct command *ibmasm_new_command(size_t buffer_size)
+struct command *ibmasm_new_command(struct service_processor *sp, size_t buffer_size)
{
struct command *cmd;
kobject_init(&cmd->kobj);
cmd->kobj.ktype = &ibmasm_cmd_kobj_type;
+ cmd->lock = &sp->lock;
cmd->status = IBMASM_CMD_PENDING;
init_waitqueue_head(&cmd->wait);
INIT_LIST_HEAD(&cmd->queue_node);
+ atomic_inc(&command_count);
+ dbg("command count: %d\n", atomic_read(&command_count));
+
return cmd;
}
struct command *cmd = to_command(kobj);
list_del(&cmd->queue_node);
+ atomic_dec(&command_count);
+ dbg("command count: %d\n", atomic_read(&command_count));
kfree(cmd->buffer);
kfree(cmd);
}
static inline void do_exec_command(struct service_processor *sp)
{
+ char tsbuf[32];
+
+ dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf));
+
if (ibmasm_send_i2o_message(sp)) {
sp->current_command->status = IBMASM_CMD_FAILED;
+ wake_up(&sp->current_command->wait);
+ command_put(sp->current_command);
exec_next_command(sp);
}
}
void ibmasm_exec_command(struct service_processor *sp, struct command *cmd)
{
unsigned long flags;
+ char tsbuf[32];
+
+ dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf));
spin_lock_irqsave(&sp->lock, flags);
if (!sp->current_command) {
- command_get(cmd);
sp->current_command = cmd;
+ command_get(sp->current_command);
spin_unlock_irqrestore(&sp->lock, flags);
-
do_exec_command(sp);
} else {
enqueue_command(sp, cmd);
static void exec_next_command(struct service_processor *sp)
{
unsigned long flags;
+ char tsbuf[32];
- wake_up(&sp->current_command->wait);
- command_put(sp->current_command);
+ dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf));
spin_lock_irqsave(&sp->lock, flags);
sp->current_command = dequeue_command(sp);
if (!sp->current_command)
return;
- memcpy(cmd->buffer, response, min(size, cmd->buffer_size));
+ memcpy_fromio(cmd->buffer, response, min(size, cmd->buffer_size));
cmd->status = IBMASM_CMD_COMPLETE;
+ wake_up(&sp->current_command->wait);
+ command_put(sp->current_command);
exec_next_command(sp);
}
u32 size;
struct dot_command_header *header = (struct dot_command_header *)message;
+ if (message_size == 0)
+ return;
+
size = get_dot_command_size(message);
+ if (size == 0)
+ return;
+
if (size > message_size)
size = message_size;
u8 *vpd_data;
int result = 0;
- command = ibmasm_new_command(INIT_BUFFER_SIZE);
+ command = ibmasm_new_command(sp, INIT_BUFFER_SIZE);
if (command == NULL)
return -ENOMEM;
struct os_state_command *os_state_cmd;
int result = 0;
- cmd = ibmasm_new_command(sizeof(struct os_state_command));
+ cmd = ibmasm_new_command(sp, sizeof(struct os_state_command));
if (cmd == NULL)
return -ENOMEM;
*/
#include "ibmasm.h"
+#include "lowlevel.h"
/*
* ASM service processor event handling routines.
* circular buffer.
*/
-
static void wake_up_event_readers(struct service_processor *sp)
{
struct event_reader *reader;
spin_lock_irqsave(&sp->lock, flags);
/* copy the event into the next slot in the circular buffer */
event = &buffer->events[buffer->next_index];
- memcpy(event->data, data, data_size);
+ memcpy_fromio(event->data, data, data_size);
event->data_size = data_size;
event->serial_number = buffer->next_serial_number;
unsigned int index;
unsigned long flags;
- if (wait_event_interruptible(reader->wait, event_available(buffer, reader)))
+ reader->cancelled = 0;
+
+ if (wait_event_interruptible(reader->wait,
+ event_available(buffer, reader) || reader->cancelled))
return -ERESTARTSYS;
if (!event_available(buffer, reader))
return event->data_size;
}
+void ibmasm_cancel_next_event(struct event_reader *reader)
+{
+ reader->cancelled = 1;
+ wake_up_interruptible(&reader->wait);
+}
+
void ibmasm_event_reader_register(struct service_processor *sp, struct event_reader *reader)
{
unsigned long flags;
{
unsigned long flags;
- wake_up_interruptible(&reader->wait);
-
spin_lock_irqsave(&sp->lock, flags);
list_del(&reader->node);
spin_unlock_irqrestore(&sp->lock, flags);
void ibmasm_event_buffer_exit(struct service_processor *sp)
{
- wake_up_event_readers(sp);
kfree(sp->event_buffer);
}
#include <linux/notifier.h>
#include "ibmasm.h"
#include "dot_command.h"
+#include "lowlevel.h"
static int suspend_heartbeats = 0;
int ibmasm_heartbeat_init(struct service_processor *sp)
{
- sp->heartbeat = ibmasm_new_command(HEARTBEAT_BUFFER_SIZE);
+ sp->heartbeat = ibmasm_new_command(sp, HEARTBEAT_BUFFER_SIZE);
if (sp->heartbeat == NULL)
return -ENOMEM;
void ibmasm_heartbeat_exit(struct service_processor *sp)
{
+ char tsbuf[32];
+
+ dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf));
+ ibmasm_wait_for_response(sp->heartbeat, IBMASM_CMD_TIMEOUT_NORMAL);
+ dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf));
+ suspend_heartbeats = 1;
command_put(sp->heartbeat);
}
{
struct command *cmd = sp->heartbeat;
struct dot_command_header *header = (struct dot_command_header *)cmd->buffer;
+ char tsbuf[32];
+ dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf));
if (suspend_heartbeats)
return;
/* return the received dot command to sender */
cmd->status = IBMASM_CMD_PENDING;
size = min(size, cmd->buffer_size);
- memcpy(cmd->buffer, message, size);
+ memcpy_fromio(cmd->buffer, message, size);
header->type = sp_write;
ibmasm_exec_command(sp, cmd);
}
#include <linux/version.h>
#include <linux/interrupt.h>
#include <linux/device.h>
+#include <linux/input.h>
/* Driver identification */
#define DRIVER_NAME "ibmasm"
-#define DRIVER_VERSION "0.4"
-#define DRIVER_AUTHOR "Max Asbock"
+#define DRIVER_VERSION "1.0"
+#define DRIVER_AUTHOR "Max Asbock <masbock@us.ibm.com>, Vernon Mauery <vernux@us.ibm.com>"
#define DRIVER_DESC "IBM ASM Service Processor Driver"
#define err(msg) printk(KERN_ERR "%s: " msg "\n", DRIVER_NAME)
#define info(msg) printk(KERN_INFO "%s: " msg "\n", DRIVER_NAME)
+extern int ibmasm_debug;
+#define dbg(STR, ARGS...) \
+ do { \
+ if (ibmasm_debug) \
+ printk(KERN_DEBUG STR , ##ARGS); \
+ } while (0)
+
+static inline char *get_timestamp(char *buf)
+{
+ struct timeval now;
+ do_gettimeofday(&now);
+ sprintf(buf, "%lu.%lu", now.tv_sec, now.tv_usec);
+ return buf;
+}
#define IBMASM_CMD_PENDING 0
#define IBMASM_CMD_COMPLETE 1
#define IBMASM_CMD_TIMEOUT_NORMAL 45
#define IBMASM_CMD_TIMEOUT_EXTRA 240
-#define IBMASM_CMD_MAX_BUFFER_SIZE 0x4000
+#define IBMASM_CMD_MAX_BUFFER_SIZE 0x8000
#define REVERSE_HEARTBEAT_TIMEOUT 120
size_t buffer_size;
int status;
struct kobject kobj;
+ spinlock_t *lock;
};
#define to_command(c) container_of(c, struct command, kobj)
static inline void command_put(struct command *cmd)
{
+ unsigned long flags;
+
+ spin_lock_irqsave(cmd->lock, flags);
kobject_put(&cmd->kobj);
+ spin_unlock_irqrestore(cmd->lock, flags);
}
static inline void command_get(struct command *cmd)
};
struct event_reader {
+ int cancelled;
unsigned int next_serial_number;
wait_queue_head_t wait;
struct list_head node;
unsigned int stopped;
};
-
-/* remote console events */
-struct mouse_event {
- long x;
- long y;
- unsigned char buttons;
- unsigned char transitions;
-};
-
-struct keyboard_event {
- unsigned long key_code;
- unsigned char key_down;
+struct ibmasm_remote {
+ struct input_dev keybd_dev;
+ struct input_dev mouse_dev;
};
-struct remote_event {
- unsigned long type;
- union {
- struct mouse_event mouse;
- struct keyboard_event keyboard;
- } data;
-};
-
-#define DRIVER_REMOTE_QUEUE_SIZE 240
-
-struct remote_queue {
- struct remote_event *start;
- struct remote_event *end;
- struct remote_event *reader;
- struct remote_event *writer;
- unsigned int size;
- int open;
- wait_queue_head_t wait;
-};
-
-
struct service_processor {
struct list_head node;
spinlock_t lock;
char dirname[IBMASM_NAME_SIZE];
char devname[IBMASM_NAME_SIZE];
unsigned int number;
- struct remote_queue remote_queue;
+ struct ibmasm_remote *remote;
int serial_line;
struct device *dev;
};
/* command processing */
-extern struct command *ibmasm_new_command(size_t buffer_size);
+extern struct command *ibmasm_new_command(struct service_processor *sp, size_t buffer_size);
extern void ibmasm_exec_command(struct service_processor *sp, struct command *cmd);
extern void ibmasm_wait_for_response(struct command *cmd, int timeout);
extern void ibmasm_receive_command_response(struct service_processor *sp, void *response, size_t size);
extern void ibmasm_event_reader_register(struct service_processor *sp, struct event_reader *reader);
extern void ibmasm_event_reader_unregister(struct service_processor *sp, struct event_reader *reader);
extern int ibmasm_get_next_event(struct service_processor *sp, struct event_reader *reader);
+extern void ibmasm_cancel_next_event(struct event_reader *reader);
/* heartbeat - from SP to OS */
extern void ibmasm_register_panic_notifier(void);
extern irqreturn_t ibmasm_interrupt_handler(int irq, void * dev_id, struct pt_regs *regs);
/* remote console */
-extern void ibmasm_handle_mouse_interrupt(struct service_processor *sp);
-extern int ibmasm_init_remote_queue(struct service_processor *sp);
-extern void ibmasm_free_remote_queue(struct service_processor *sp);
-extern void ibmasm_advance_reader(struct remote_queue *q, unsigned int n);
-extern size_t ibmasm_events_available(struct remote_queue *q);
+extern void ibmasm_handle_mouse_interrupt(struct service_processor *sp, struct pt_regs *regs);
+extern int ibmasm_init_remote_input_dev(struct service_processor *sp);
+extern void ibmasm_free_remote_input_dev(struct service_processor *sp);
/* file system */
extern int ibmasmfs_register(void);
* | |-- event
* | |-- reverse_heartbeat
* | `-- remote_video
- * | |-- connected
* | |-- depth
- * | |-- events
* | |-- height
* | `-- width
* .
* |-- event
* |-- reverse_heartbeat
* `-- remote_video
- * |-- connected
* |-- depth
- * |-- events
* |-- height
* `-- width
*
* remote_video/width: control remote display settings
* write: set value
* read: read value
- *
- * remote_video/connected
- * read: return "1" if web browser VNC java applet is connected,
- * "0" otherwise
- *
- * remote_video/events
- * read: sleep until a remote mouse or keyboard event occurs, then return
- * then event.
*/
#include <linux/fs.h>
if (command_data->command)
return -EAGAIN;
- cmd = ibmasm_new_command(count);
+ cmd = ibmasm_new_command(command_data->sp, count);
if (!cmd)
return -ENOMEM;
ibmasm_event_reader_register(sp, &event_data->reader);
event_data->sp = sp;
+ event_data->active = 0;
file->private_data = event_data;
return 0;
}
{
struct ibmasmfs_event_data *event_data = file->private_data;
struct event_reader *reader = &event_data->reader;
+ struct service_processor *sp = event_data->sp;
int ret;
+ unsigned long flags;
if (*offset < 0)
return -EINVAL;
if (*offset != 0)
return 0;
- ret = ibmasm_get_next_event(event_data->sp, reader);
+ spin_lock_irqsave(&sp->lock, flags);
+ if (event_data->active) {
+ spin_unlock_irqrestore(&sp->lock, flags);
+ return -EBUSY;
+ }
+ event_data->active = 1;
+ spin_unlock_irqrestore(&sp->lock, flags);
+
+ ret = ibmasm_get_next_event(sp, reader);
if (ret <= 0)
- return ret;
+ goto out;
- if (count < reader->data_size)
- return -EINVAL;
+ if (count < reader->data_size) {
+ ret = -EINVAL;
+ goto out;
+ }
- if (copy_to_user(buf, reader->data, reader->data_size))
- return -EFAULT;
+ if (copy_to_user(buf, reader->data, reader->data_size)) {
+ ret = -EFAULT;
+ goto out;
+ }
+ ret = reader->data_size;
- return reader->data_size;
+out:
+ event_data->active = 0;
+ return ret;
}
static ssize_t event_file_write(struct file *file, const char __user *buf, size_t count, loff_t *offset)
if (*offset != 0)
return 0;
- wake_up_interruptible(&event_data->reader.wait);
+ ibmasm_cancel_next_event(&event_data->reader);
return 0;
}
return count;
}
-static int remote_event_file_open(struct inode *inode, struct file *file)
-{
- struct service_processor *sp;
- unsigned long flags;
- struct remote_queue *q;
-
- file->private_data = inode->u.generic_ip;
- sp = file->private_data;
- q = &sp->remote_queue;
-
- /* allow only one event reader */
- spin_lock_irqsave(&sp->lock, flags);
- if (q->open) {
- spin_unlock_irqrestore(&sp->lock, flags);
- return -EBUSY;
- }
- q->open = 1;
- spin_unlock_irqrestore(&sp->lock, flags);
-
- enable_mouse_interrupts(sp);
-
- return 0;
-}
-
-static int remote_event_file_close(struct inode *inode, struct file *file)
-{
- struct service_processor *sp = file->private_data;
-
- disable_mouse_interrupts(sp);
- wake_up_interruptible(&sp->remote_queue.wait);
- sp->remote_queue.open = 0;
-
- return 0;
-}
-
-static ssize_t remote_event_file_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
-{
- struct service_processor *sp = file->private_data;
- struct remote_queue *q = &sp->remote_queue;
- size_t data_size;
- struct remote_event *reader = q->reader;
- size_t num_events;
-
- if (*offset < 0)
- return -EINVAL;
- if (count == 0 || count > 1024)
- return 0;
- if (*offset != 0)
- return 0;
-
- if (wait_event_interruptible(q->wait, q->reader != q->writer))
- return -ERESTARTSYS;
-
- /* only get multiples of struct remote_event */
- num_events = min((count/sizeof(struct remote_event)), ibmasm_events_available(q));
- if (!num_events)
- return 0;
-
- data_size = num_events * sizeof(struct remote_event);
-
- if (copy_to_user(buf, reader, data_size))
- return -EFAULT;
-
- ibmasm_advance_reader(q, num_events);
-
- return data_size;
-}
-
-
static struct file_operations command_fops = {
.open = command_file_open,
.release = command_file_close,
.write = remote_settings_file_write,
};
-static struct file_operations remote_event_fops = {
- .open = remote_event_file_open,
- .release = remote_event_file_close,
- .read = remote_event_file_read,
-};
-
static void ibmasmfs_create_files (struct super_block *sb, struct dentry *root)
{
ibmasmfs_create_file(sb, remote_dir, "width", &remote_settings_fops, (void *)display_width(sp), S_IRUSR|S_IWUSR);
ibmasmfs_create_file(sb, remote_dir, "height", &remote_settings_fops, (void *)display_height(sp), S_IRUSR|S_IWUSR);
ibmasmfs_create_file(sb, remote_dir, "depth", &remote_settings_fops, (void *)display_depth(sp), S_IRUSR|S_IWUSR);
- ibmasmfs_create_file(sb, remote_dir, "connected", &remote_settings_fops, (void *)vnc_status(sp), S_IRUSR);
- ibmasmfs_create_file(sb, remote_dir, "events", &remote_event_fops, (void *)sp, S_IRUSR);
}
}
message = get_i2o_message(sp->base_address, mfa);
- memcpy(&message->header, &header, sizeof(struct i2o_header));
- memcpy(&message->data, command->buffer, command_size);
+ memcpy_toio(&message->header, &header, sizeof(struct i2o_header));
+ memcpy_toio(&message->data, command->buffer, command_size);
set_mfa_inbound(sp->base_address, mfa);
u32 mfa;
struct service_processor *sp = (struct service_processor *)dev_id;
void __iomem *base_address = sp->base_address;
+ char tsbuf[32];
if (!sp_interrupt_pending(base_address))
return IRQ_NONE;
+ dbg("respond to interrupt at %s\n", get_timestamp(tsbuf));
+
if (mouse_interrupt_pending(sp)) {
- ibmasm_handle_mouse_interrupt(sp);
- mfa = get_mfa_outbound(base_address);
+ ibmasm_handle_mouse_interrupt(sp, regs);
clear_mouse_interrupt(sp);
- set_mfa_outbound(base_address, mfa);
- return IRQ_HANDLED;
}
mfa = get_mfa_outbound(base_address);
if (valid_mfa(mfa)) {
struct i2o_message *msg = get_i2o_message(base_address, mfa);
ibmasm_receive_message(sp, &msg->data, incoming_data_size(msg));
- }
+ } else
+ dbg("didn't get a valid MFA\n");
+
set_mfa_outbound(base_address, mfa);
+ dbg("finished interrupt at %s\n", get_timestamp(tsbuf));
+
return IRQ_HANDLED;
}
#include "lowlevel.h"
#include "remote.h"
+int ibmasm_debug = 0;
+module_param(ibmasm_debug, int , S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(ibmasm_debug, " Set debug mode on or off");
+
static int __devinit ibmasm_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
{
- int err, result = -ENOMEM;
+ int result;
struct service_processor *sp;
- if ((err = pci_enable_device(pdev))) {
- printk(KERN_ERR "%s: can't enable PCI device at %s\n",
- DRIVER_NAME, pci_name(pdev));
- return err;
+ if ((result = pci_enable_device(pdev))) {
+ dev_err(&pdev->dev, "Failed to enable PCI device\n");
+ return result;
}
+ if ((result = pci_request_regions(pdev, DRIVER_NAME))) {
+ dev_err(&pdev->dev, "Failed to allocate PCI resources\n");
+ goto error_resources;
+ }
+ /* vnc client won't work without bus-mastering */
+ pci_set_master(pdev);
sp = kmalloc(sizeof(struct service_processor), GFP_KERNEL);
if (sp == NULL) {
}
memset(sp, 0, sizeof(struct service_processor));
+ sp->lock = SPIN_LOCK_UNLOCKED;
+ INIT_LIST_HEAD(&sp->command_queue);
+
pci_set_drvdata(pdev, (void *)sp);
sp->dev = &pdev->dev;
sp->number = pdev->bus->number;
goto error_ioremap;
}
- result = ibmasm_init_remote_queue(sp);
- if (result) {
- dev_err(sp->dev, "Failed to initialize remote queue\n");
- goto error_remote_queue;
- }
-
- spin_lock_init(&sp->lock);
- INIT_LIST_HEAD(&sp->command_queue);
-
result = request_irq(sp->irq, ibmasm_interrupt_handler, SA_SHIRQ, sp->devname, (void*)sp);
if (result) {
dev_err(sp->dev, "Failed to register interrupt handler\n");
}
enable_sp_interrupts(sp->base_address);
- disable_mouse_interrupts(sp);
+
+ result = ibmasm_init_remote_input_dev(sp);
+ if (result) {
+ dev_err(sp->dev, "Failed to initialize remote queue\n");
+ goto error_send_message;
+ }
result = ibmasm_send_driver_vpd(sp);
if (result) {
ibmasm_register_uart(sp);
- dev_printk(KERN_DEBUG, &pdev->dev, "WARNING: This software may not be supported or function\n");
- dev_printk(KERN_DEBUG, &pdev->dev, "correctly on your IBM server. Please consult the IBM\n");
- dev_printk(KERN_DEBUG, &pdev->dev, "ServerProven website\n");
- dev_printk(KERN_DEBUG, &pdev->dev, "http://www.pc.ibm.com/ww/eserver/xseries/serverproven\n");
- dev_printk(KERN_DEBUG, &pdev->dev, "for information on the specific driver level and support\n");
- dev_printk(KERN_DEBUG, &pdev->dev, "statement for your IBM server.\n");
-
return 0;
error_send_message:
disable_sp_interrupts(sp->base_address);
+ ibmasm_free_remote_input_dev(sp);
free_irq(sp->irq, (void *)sp);
error_request_irq:
- ibmasm_free_remote_queue(sp);
-error_remote_queue:
iounmap(sp->base_address);
error_ioremap:
ibmasm_heartbeat_exit(sp);
error_heartbeat:
ibmasm_event_buffer_exit(sp);
error_eventbuffer:
+ pci_set_drvdata(pdev, NULL);
kfree(sp);
error_kmalloc:
- pci_disable_device(pdev);
+ pci_release_regions(pdev);
+error_resources:
+ pci_disable_device(pdev);
return result;
}
{
struct service_processor *sp = (struct service_processor *)pci_get_drvdata(pdev);
+ dbg("Unregistering UART\n");
ibmasm_unregister_uart(sp);
- ibmasm_send_os_state(sp, SYSTEM_STATE_OS_DOWN);
+ dbg("Sending OS down message\n");
+ if (ibmasm_send_os_state(sp, SYSTEM_STATE_OS_DOWN))
+ err("failed to get repsonse to 'Send OS State' command\n");
+ dbg("Disabling heartbeats\n");
+ ibmasm_heartbeat_exit(sp);
+ dbg("Disabling interrupts\n");
disable_sp_interrupts(sp->base_address);
- disable_mouse_interrupts(sp);
+ dbg("Freeing SP irq\n");
free_irq(sp->irq, (void *)sp);
- ibmasm_heartbeat_exit(sp);
- ibmasm_free_remote_queue(sp);
+ dbg("Cleaning up\n");
+ ibmasm_free_remote_input_dev(sp);
iounmap(sp->base_address);
ibmasm_event_buffer_exit(sp);
+ pci_set_drvdata(pdev, NULL);
kfree(sp);
+ pci_release_regions(pdev);
pci_disable_device(pdev);
}
int times_failed = 0;
int result = 1;
- cmd = ibmasm_new_command(sizeof rhb_dot_cmd);
+ cmd = ibmasm_new_command(sp, sizeof rhb_dot_cmd);
if (!cmd)
return -ENOMEM;
-
/*
* IBM ASM Service Processor Device Driver
*
*
* Copyright (C) IBM Corporation, 2004
*
- * Author: Max Asböck <amax@us.ibm.com>
+ * Authors: Max Asböck <amax@us.ibm.com>
+ * Vernon Mauery <vernux@us.ibm.com>
*
*/
/* Remote mouse and keyboard event handling functions */
+#include <linux/pci.h>
#include "ibmasm.h"
#include "remote.h"
-int ibmasm_init_remote_queue(struct service_processor *sp)
-{
- struct remote_queue *q = &sp->remote_queue;
-
- disable_mouse_interrupts(sp);
+static int xmax = 1600;
+static int ymax = 1200;
- q->open = 0;
- q->size = 0;
- q->start = kmalloc(DRIVER_REMOTE_QUEUE_SIZE * sizeof(struct remote_event), GFP_KERNEL);
- if (q->start == 0)
- return -ENOMEM;
+static unsigned short xlate_high[XLATE_SIZE] = {
+ [KEY_SYM_ENTER & 0xff] = KEY_ENTER,
+ [KEY_SYM_KPSLASH & 0xff] = KEY_KPSLASH,
+ [KEY_SYM_KPSTAR & 0xff] = KEY_KPASTERISK,
+ [KEY_SYM_KPMINUS & 0xff] = KEY_KPMINUS,
+ [KEY_SYM_KPDOT & 0xff] = KEY_KPDOT,
+ [KEY_SYM_KPPLUS & 0xff] = KEY_KPPLUS,
+ [KEY_SYM_KP0 & 0xff] = KEY_KP0,
+ [KEY_SYM_KP1 & 0xff] = KEY_KP1,
+ [KEY_SYM_KP2 & 0xff] = KEY_KP2, [KEY_SYM_KPDOWN & 0xff] = KEY_KP2,
+ [KEY_SYM_KP3 & 0xff] = KEY_KP3,
+ [KEY_SYM_KP4 & 0xff] = KEY_KP4, [KEY_SYM_KPLEFT & 0xff] = KEY_KP4,
+ [KEY_SYM_KP5 & 0xff] = KEY_KP5,
+ [KEY_SYM_KP6 & 0xff] = KEY_KP6, [KEY_SYM_KPRIGHT & 0xff] = KEY_KP6,
+ [KEY_SYM_KP7 & 0xff] = KEY_KP7,
+ [KEY_SYM_KP8 & 0xff] = KEY_KP8, [KEY_SYM_KPUP & 0xff] = KEY_KP8,
+ [KEY_SYM_KP9 & 0xff] = KEY_KP9,
+ [KEY_SYM_BK_SPC & 0xff] = KEY_BACKSPACE,
+ [KEY_SYM_TAB & 0xff] = KEY_TAB,
+ [KEY_SYM_CTRL & 0xff] = KEY_LEFTCTRL,
+ [KEY_SYM_ALT & 0xff] = KEY_LEFTALT,
+ [KEY_SYM_INSERT & 0xff] = KEY_INSERT,
+ [KEY_SYM_DELETE & 0xff] = KEY_DELETE,
+ [KEY_SYM_SHIFT & 0xff] = KEY_LEFTSHIFT,
+ [KEY_SYM_UARROW & 0xff] = KEY_UP,
+ [KEY_SYM_DARROW & 0xff] = KEY_DOWN,
+ [KEY_SYM_LARROW & 0xff] = KEY_LEFT,
+ [KEY_SYM_RARROW & 0xff] = KEY_RIGHT,
+ [KEY_SYM_ESCAPE & 0xff] = KEY_ESC,
+ [KEY_SYM_PAGEUP & 0xff] = KEY_PAGEUP,
+ [KEY_SYM_PAGEDOWN & 0xff] = KEY_PAGEDOWN,
+ [KEY_SYM_HOME & 0xff] = KEY_HOME,
+ [KEY_SYM_END & 0xff] = KEY_END,
+ [KEY_SYM_F1 & 0xff] = KEY_F1,
+ [KEY_SYM_F2 & 0xff] = KEY_F2,
+ [KEY_SYM_F3 & 0xff] = KEY_F3,
+ [KEY_SYM_F4 & 0xff] = KEY_F4,
+ [KEY_SYM_F5 & 0xff] = KEY_F5,
+ [KEY_SYM_F6 & 0xff] = KEY_F6,
+ [KEY_SYM_F7 & 0xff] = KEY_F7,
+ [KEY_SYM_F8 & 0xff] = KEY_F8,
+ [KEY_SYM_F9 & 0xff] = KEY_F9,
+ [KEY_SYM_F10 & 0xff] = KEY_F10,
+ [KEY_SYM_F11 & 0xff] = KEY_F11,
+ [KEY_SYM_F12 & 0xff] = KEY_F12,
+ [KEY_SYM_CAP_LOCK & 0xff] = KEY_CAPSLOCK,
+ [KEY_SYM_NUM_LOCK & 0xff] = KEY_NUMLOCK,
+ [KEY_SYM_SCR_LOCK & 0xff] = KEY_SCROLLLOCK,
+};
+static unsigned short xlate[XLATE_SIZE] = {
+ [NO_KEYCODE] = KEY_RESERVED,
+ [KEY_SYM_SPACE] = KEY_SPACE,
+ [KEY_SYM_TILDE] = KEY_GRAVE, [KEY_SYM_BKTIC] = KEY_GRAVE,
+ [KEY_SYM_ONE] = KEY_1, [KEY_SYM_BANG] = KEY_1,
+ [KEY_SYM_TWO] = KEY_2, [KEY_SYM_AT] = KEY_2,
+ [KEY_SYM_THREE] = KEY_3, [KEY_SYM_POUND] = KEY_3,
+ [KEY_SYM_FOUR] = KEY_4, [KEY_SYM_DOLLAR] = KEY_4,
+ [KEY_SYM_FIVE] = KEY_5, [KEY_SYM_PERCENT] = KEY_5,
+ [KEY_SYM_SIX] = KEY_6, [KEY_SYM_CARAT] = KEY_6,
+ [KEY_SYM_SEVEN] = KEY_7, [KEY_SYM_AMPER] = KEY_7,
+ [KEY_SYM_EIGHT] = KEY_8, [KEY_SYM_STAR] = KEY_8,
+ [KEY_SYM_NINE] = KEY_9, [KEY_SYM_LPAREN] = KEY_9,
+ [KEY_SYM_ZERO] = KEY_0, [KEY_SYM_RPAREN] = KEY_0,
+ [KEY_SYM_MINUS] = KEY_MINUS, [KEY_SYM_USCORE] = KEY_MINUS,
+ [KEY_SYM_EQUAL] = KEY_EQUAL, [KEY_SYM_PLUS] = KEY_EQUAL,
+ [KEY_SYM_LBRKT] = KEY_LEFTBRACE, [KEY_SYM_LCURLY] = KEY_LEFTBRACE,
+ [KEY_SYM_RBRKT] = KEY_RIGHTBRACE, [KEY_SYM_RCURLY] = KEY_RIGHTBRACE,
+ [KEY_SYM_SLASH] = KEY_BACKSLASH, [KEY_SYM_PIPE] = KEY_BACKSLASH,
+ [KEY_SYM_TIC] = KEY_APOSTROPHE, [KEY_SYM_QUOTE] = KEY_APOSTROPHE,
+ [KEY_SYM_SEMIC] = KEY_SEMICOLON, [KEY_SYM_COLON] = KEY_SEMICOLON,
+ [KEY_SYM_COMMA] = KEY_COMMA, [KEY_SYM_LT] = KEY_COMMA,
+ [KEY_SYM_PERIOD] = KEY_DOT, [KEY_SYM_GT] = KEY_DOT,
+ [KEY_SYM_BSLASH] = KEY_SLASH, [KEY_SYM_QMARK] = KEY_SLASH,
+ [KEY_SYM_A] = KEY_A, [KEY_SYM_a] = KEY_A,
+ [KEY_SYM_B] = KEY_B, [KEY_SYM_b] = KEY_B,
+ [KEY_SYM_C] = KEY_C, [KEY_SYM_c] = KEY_C,
+ [KEY_SYM_D] = KEY_D, [KEY_SYM_d] = KEY_D,
+ [KEY_SYM_E] = KEY_E, [KEY_SYM_e] = KEY_E,
+ [KEY_SYM_F] = KEY_F, [KEY_SYM_f] = KEY_F,
+ [KEY_SYM_G] = KEY_G, [KEY_SYM_g] = KEY_G,
+ [KEY_SYM_H] = KEY_H, [KEY_SYM_h] = KEY_H,
+ [KEY_SYM_I] = KEY_I, [KEY_SYM_i] = KEY_I,
+ [KEY_SYM_J] = KEY_J, [KEY_SYM_j] = KEY_J,
+ [KEY_SYM_K] = KEY_K, [KEY_SYM_k] = KEY_K,
+ [KEY_SYM_L] = KEY_L, [KEY_SYM_l] = KEY_L,
+ [KEY_SYM_M] = KEY_M, [KEY_SYM_m] = KEY_M,
+ [KEY_SYM_N] = KEY_N, [KEY_SYM_n] = KEY_N,
+ [KEY_SYM_O] = KEY_O, [KEY_SYM_o] = KEY_O,
+ [KEY_SYM_P] = KEY_P, [KEY_SYM_p] = KEY_P,
+ [KEY_SYM_Q] = KEY_Q, [KEY_SYM_q] = KEY_Q,
+ [KEY_SYM_R] = KEY_R, [KEY_SYM_r] = KEY_R,
+ [KEY_SYM_S] = KEY_S, [KEY_SYM_s] = KEY_S,
+ [KEY_SYM_T] = KEY_T, [KEY_SYM_t] = KEY_T,
+ [KEY_SYM_U] = KEY_U, [KEY_SYM_u] = KEY_U,
+ [KEY_SYM_V] = KEY_V, [KEY_SYM_v] = KEY_V,
+ [KEY_SYM_W] = KEY_W, [KEY_SYM_w] = KEY_W,
+ [KEY_SYM_X] = KEY_X, [KEY_SYM_x] = KEY_X,
+ [KEY_SYM_Y] = KEY_Y, [KEY_SYM_y] = KEY_Y,
+ [KEY_SYM_Z] = KEY_Z, [KEY_SYM_z] = KEY_Z,
+};
- q->end = q->start + DRIVER_REMOTE_QUEUE_SIZE;
- q->reader = q->start;
- q->writer = q->start;
- q->size = DRIVER_REMOTE_QUEUE_SIZE;
- init_waitqueue_head(&q->wait);
+static char remote_mouse_name[] = "ibmasm RSA I remote mouse";
+static char remote_keybd_name[] = "ibmasm RSA I remote keyboard";
- return 0;
-}
-
-void ibmasm_free_remote_queue(struct service_processor *sp)
+static void print_input(struct remote_input *input)
{
- kfree(sp->remote_queue.start);
+ if (input->type == INPUT_TYPE_MOUSE) {
+ unsigned char buttons = input->mouse_buttons;
+ dbg("remote mouse movement: (x,y)=(%d,%d)%s%s%s%s\n",
+ input->data.mouse.x, input->data.mouse.y,
+ (buttons)?" -- buttons:":"",
+ (buttons & REMOTE_BUTTON_LEFT)?"left ":"",
+ (buttons & REMOTE_BUTTON_MIDDLE)?"middle ":"",
+ (buttons & REMOTE_BUTTON_RIGHT)?"right":""
+ );
+ } else {
+ dbg("remote keypress (code, flag, down):"
+ "%d (0x%x) [0x%x] [0x%x]\n",
+ input->data.keyboard.key_code,
+ input->data.keyboard.key_code,
+ input->data.keyboard.key_flag,
+ input->data.keyboard.key_down
+ );
+ }
}
-void ibmasm_advance_reader(struct remote_queue *q, unsigned int n)
+static void send_mouse_event(struct input_dev *dev, struct pt_regs *regs,
+ struct remote_input *input)
{
- q->reader += n;
- if (q->reader >= q->end)
- q->reader -= q->size;
-}
+ unsigned char buttons = input->mouse_buttons;
-size_t ibmasm_events_available(struct remote_queue *q)
-{
- ssize_t diff = q->writer - q->reader;
-
- return (diff >= 0) ? diff : q->end - q->reader;
+ input_regs(dev, regs);
+ input_report_abs(dev, ABS_X, input->data.mouse.x);
+ input_report_abs(dev, ABS_Y, input->data.mouse.y);
+ input_report_key(dev, BTN_LEFT, buttons & REMOTE_BUTTON_LEFT);
+ input_report_key(dev, BTN_MIDDLE, buttons & REMOTE_BUTTON_MIDDLE);
+ input_report_key(dev, BTN_RIGHT, buttons & REMOTE_BUTTON_RIGHT);
+ input_sync(dev);
}
-
-static int space_free(struct remote_queue *q)
+static void send_keyboard_event(struct input_dev *dev, struct pt_regs *regs,
+ struct remote_input *input)
{
- if (q->reader == q->writer)
- return q->size - 1;
+ unsigned int key;
+ unsigned short code = input->data.keyboard.key_code;
- return ( (q->reader + q->size - q->writer) % q->size ) - 1;
+ if (code & 0xff00)
+ key = xlate_high[code & 0xff];
+ else
+ key = xlate[code];
+ input_regs(dev, regs);
+ input_report_key(dev, key, (input->data.keyboard.key_down) ? 1 : 0);
+ input_sync(dev);
}
-static void set_mouse_event(struct remote_input *input, struct mouse_event *mouse)
+void ibmasm_handle_mouse_interrupt(struct service_processor *sp,
+ struct pt_regs *regs)
{
- static char last_buttons = 0;
+ unsigned long reader;
+ unsigned long writer;
+ struct remote_input input;
- mouse->x = input->data.mouse.x;
- mouse->y = input->data.mouse.y;
+ reader = get_queue_reader(sp);
+ writer = get_queue_writer(sp);
- if (input->mouse_buttons == REMOTE_MOUSE_DOUBLE_CLICK) {
- mouse->buttons = REMOTE_MOUSE_DOUBLE_CLICK;
- last_buttons = 0;
- return;
- }
- mouse->transitions = last_buttons ^ input->mouse_buttons;
- mouse->buttons = input->mouse_buttons;
+ while (reader != writer) {
+ memcpy_fromio(&input, get_queue_entry(sp, reader),
+ sizeof(struct remote_input));
- last_buttons = input->mouse_buttons;
-}
+ print_input(&input);
+ if (input.type == INPUT_TYPE_MOUSE) {
+ send_mouse_event(&sp->remote->mouse_dev, regs, &input);
+ } else if (input.type == INPUT_TYPE_KEYBOARD) {
+ send_keyboard_event(&sp->remote->keybd_dev, regs, &input);
+ } else
+ break;
-static void set_keyboard_event(struct remote_input *input, struct keyboard_event *keyboard)
-{
- keyboard->key_code = input->data.keyboard.key_code;
- keyboard->key_down = input->data.keyboard.key_down;
+ reader = advance_queue_reader(sp, reader);
+ writer = get_queue_writer(sp);
+ }
}
-static int add_to_driver_queue(struct remote_queue *q, struct remote_input *input)
+int ibmasm_init_remote_input_dev(struct service_processor *sp)
{
- struct remote_event *event = q->writer;
+ /* set up the mouse input device */
+ struct ibmasm_remote *remote;
+ struct pci_dev *pdev = to_pci_dev(sp->dev);
+ int i;
- if (space_free(q) < 1) {
- return 1;
- }
+ sp->remote = remote = kmalloc(sizeof(*remote), GFP_KERNEL);
+ if (!remote)
+ return -ENOMEM;
- switch(input->type) {
- case (INPUT_TYPE_MOUSE):
- event->type = INPUT_TYPE_MOUSE;
- set_mouse_event(input, &event->data.mouse);
- break;
- case (INPUT_TYPE_KEYBOARD):
- event->type = INPUT_TYPE_KEYBOARD;
- set_keyboard_event(input, &event->data.keyboard);
- break;
- default:
- return 0;
- }
- event->type = input->type;
+ memset(remote, 0, sizeof(*remote));
- q->writer++;
- if (q->writer == q->end)
- q->writer = q->start;
+ remote->mouse_dev.private = remote;
+ init_input_dev(&remote->mouse_dev);
+ remote->mouse_dev.id.vendor = pdev->vendor;
+ remote->mouse_dev.id.product = pdev->device;
+ remote->mouse_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ remote->mouse_dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) |
+ BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
+ set_bit(BTN_TOUCH, remote->mouse_dev.keybit);
+ remote->mouse_dev.name = remote_mouse_name;
+ input_set_abs_params(&remote->mouse_dev, ABS_X, 0, xmax, 0, 0);
+ input_set_abs_params(&remote->mouse_dev, ABS_Y, 0, ymax, 0, 0);
- return 0;
-}
-
+ remote->keybd_dev.private = remote;
+ init_input_dev(&remote->keybd_dev);
+ remote->keybd_dev.id.vendor = pdev->vendor;
+ remote->keybd_dev.id.product = pdev->device;
+ remote->keybd_dev.evbit[0] = BIT(EV_KEY);
+ remote->keybd_dev.name = remote_keybd_name;
-void ibmasm_handle_mouse_interrupt(struct service_processor *sp)
-{
- unsigned long reader;
- unsigned long writer;
- struct remote_input input;
+ for (i=0; i<XLATE_SIZE; i++) {
+ if (xlate_high[i])
+ set_bit(xlate_high[i], remote->keybd_dev.keybit);
+ if (xlate[i])
+ set_bit(xlate[i], remote->keybd_dev.keybit);
+ }
- reader = get_queue_reader(sp);
- writer = get_queue_writer(sp);
+ input_register_device(&remote->mouse_dev);
+ input_register_device(&remote->keybd_dev);
+ enable_mouse_interrupts(sp);
- while (reader != writer) {
- memcpy(&input, (void *)get_queue_entry(sp, reader), sizeof(struct remote_input));
+ printk(KERN_INFO "ibmasm remote responding to events on RSA card %d\n", sp->number);
- if (add_to_driver_queue(&sp->remote_queue, &input))
- break;
+ return 0;
+}
- reader = advance_queue_reader(sp, reader);
- }
- wake_up_interruptible(&sp->remote_queue.wait);
+void ibmasm_free_remote_input_dev(struct service_processor *sp)
+{
+ disable_mouse_interrupts(sp);
+ input_unregister_device(&sp->remote->keybd_dev);
+ input_unregister_device(&sp->remote->mouse_dev);
+ kfree(sp->remote);
}
+
/* mouse button states received from SP */
-#define REMOTE_MOUSE_DOUBLE_CLICK 0xF0
-#define REMOTE_MOUSE_BUTTON_LEFT 0x01
-#define REMOTE_MOUSE_BUTTON_MIDDLE 0x02
-#define REMOTE_MOUSE_BUTTON_RIGHT 0x04
+#define REMOTE_DOUBLE_CLICK 0xF0
+#define REMOTE_BUTTON_LEFT 0x01
+#define REMOTE_BUTTON_MIDDLE 0x02
+#define REMOTE_BUTTON_RIGHT 0x04
+/* size of keysym/keycode translation matricies */
+#define XLATE_SIZE 256
struct mouse_input {
unsigned short y;
unsigned char pad3;
};
-#define mouse_addr(sp) sp->base_address + CONDOR_MOUSE_DATA
-#define display_width(sp) mouse_addr(sp) + CONDOR_INPUT_DISPLAY_RESX
-#define display_height(sp) mouse_addr(sp) + CONDOR_INPUT_DISPLAY_RESY
-#define display_depth(sp) mouse_addr(sp) + CONDOR_INPUT_DISPLAY_BITS
-#define vnc_status(sp) mouse_addr(sp) + CONDOR_OUTPUT_VNC_STATUS
+#define mouse_addr(sp) (sp->base_address + CONDOR_MOUSE_DATA)
+#define display_width(sp) (mouse_addr(sp) + CONDOR_INPUT_DISPLAY_RESX)
+#define display_height(sp) (mouse_addr(sp) + CONDOR_INPUT_DISPLAY_RESY)
+#define display_depth(sp) (mouse_addr(sp) + CONDOR_INPUT_DISPLAY_BITS)
+#define desktop_info(sp) (mouse_addr(sp) + CONDOR_INPUT_DESKTOP_INFO)
+#define vnc_status(sp) (mouse_addr(sp) + CONDOR_OUTPUT_VNC_STATUS)
+#define isr_control(sp) (mouse_addr(sp) + CONDOR_MOUSE_ISR_CONTROL)
#define mouse_interrupt_pending(sp) readl(mouse_addr(sp) + CONDOR_MOUSE_ISR_STATUS)
#define clear_mouse_interrupt(sp) writel(0, mouse_addr(sp) + CONDOR_MOUSE_ISR_STATUS)
#define get_queue_reader(sp) readl(mouse_addr(sp) + CONDOR_MOUSE_Q_READER)
#define set_queue_reader(sp, reader) writel(reader, mouse_addr(sp) + CONDOR_MOUSE_Q_READER)
-#define queue_begin mouse_addr(sp) + CONDOR_MOUSE_Q_BEGIN
+#define queue_begin (mouse_addr(sp) + CONDOR_MOUSE_Q_BEGIN)
#define get_queue_entry(sp, read_index) \
- queue_begin + read_index * sizeof(struct remote_input)
+ ((void*)(queue_begin + read_index * sizeof(struct remote_input)))
static inline int advance_queue_reader(struct service_processor *sp, unsigned long reader)
{
return reader;
}
+#define NO_KEYCODE 0
+#define KEY_SYM_BK_SPC 0xFF08
+#define KEY_SYM_TAB 0xFF09
+#define KEY_SYM_ENTER 0xFF0D
+#define KEY_SYM_SCR_LOCK 0xFF14
+#define KEY_SYM_ESCAPE 0xFF1B
+#define KEY_SYM_HOME 0xFF50
+#define KEY_SYM_LARROW 0xFF51
+#define KEY_SYM_UARROW 0xFF52
+#define KEY_SYM_RARROW 0xFF53
+#define KEY_SYM_DARROW 0xFF54
+#define KEY_SYM_PAGEUP 0xFF55
+#define KEY_SYM_PAGEDOWN 0xFF56
+#define KEY_SYM_END 0xFF57
+#define KEY_SYM_INSERT 0xFF63
+#define KEY_SYM_NUM_LOCK 0xFF7F
+#define KEY_SYM_KPSTAR 0xFFAA
+#define KEY_SYM_KPPLUS 0xFFAB
+#define KEY_SYM_KPMINUS 0xFFAD
+#define KEY_SYM_KPDOT 0xFFAE
+#define KEY_SYM_KPSLASH 0xFFAF
+#define KEY_SYM_KPRIGHT 0xFF96
+#define KEY_SYM_KPUP 0xFF97
+#define KEY_SYM_KPLEFT 0xFF98
+#define KEY_SYM_KPDOWN 0xFF99
+#define KEY_SYM_KP0 0xFFB0
+#define KEY_SYM_KP1 0xFFB1
+#define KEY_SYM_KP2 0xFFB2
+#define KEY_SYM_KP3 0xFFB3
+#define KEY_SYM_KP4 0xFFB4
+#define KEY_SYM_KP5 0xFFB5
+#define KEY_SYM_KP6 0xFFB6
+#define KEY_SYM_KP7 0xFFB7
+#define KEY_SYM_KP8 0xFFB8
+#define KEY_SYM_KP9 0xFFB9
+#define KEY_SYM_F1 0xFFBE // 1B 5B 5B 41
+#define KEY_SYM_F2 0xFFBF // 1B 5B 5B 42
+#define KEY_SYM_F3 0xFFC0 // 1B 5B 5B 43
+#define KEY_SYM_F4 0xFFC1 // 1B 5B 5B 44
+#define KEY_SYM_F5 0xFFC2 // 1B 5B 5B 45
+#define KEY_SYM_F6 0xFFC3 // 1B 5B 31 37 7E
+#define KEY_SYM_F7 0xFFC4 // 1B 5B 31 38 7E
+#define KEY_SYM_F8 0xFFC5 // 1B 5B 31 39 7E
+#define KEY_SYM_F9 0xFFC6 // 1B 5B 32 30 7E
+#define KEY_SYM_F10 0xFFC7 // 1B 5B 32 31 7E
+#define KEY_SYM_F11 0xFFC8 // 1B 5B 32 33 7E
+#define KEY_SYM_F12 0xFFC9 // 1B 5B 32 34 7E
+#define KEY_SYM_SHIFT 0xFFE1
+#define KEY_SYM_CTRL 0xFFE3
+#define KEY_SYM_ALT 0xFFE9
+#define KEY_SYM_CAP_LOCK 0xFFE5
+#define KEY_SYM_DELETE 0xFFFF
+#define KEY_SYM_TILDE 0x60
+#define KEY_SYM_BKTIC 0x7E
+#define KEY_SYM_ONE 0x31
+#define KEY_SYM_BANG 0x21
+#define KEY_SYM_TWO 0x32
+#define KEY_SYM_AT 0x40
+#define KEY_SYM_THREE 0x33
+#define KEY_SYM_POUND 0x23
+#define KEY_SYM_FOUR 0x34
+#define KEY_SYM_DOLLAR 0x24
+#define KEY_SYM_FIVE 0x35
+#define KEY_SYM_PERCENT 0x25
+#define KEY_SYM_SIX 0x36
+#define KEY_SYM_CARAT 0x5E
+#define KEY_SYM_SEVEN 0x37
+#define KEY_SYM_AMPER 0x26
+#define KEY_SYM_EIGHT 0x38
+#define KEY_SYM_STAR 0x2A
+#define KEY_SYM_NINE 0x39
+#define KEY_SYM_LPAREN 0x28
+#define KEY_SYM_ZERO 0x30
+#define KEY_SYM_RPAREN 0x29
+#define KEY_SYM_MINUS 0x2D
+#define KEY_SYM_USCORE 0x5F
+#define KEY_SYM_EQUAL 0x2B
+#define KEY_SYM_PLUS 0x3D
+#define KEY_SYM_LBRKT 0x5B
+#define KEY_SYM_LCURLY 0x7B
+#define KEY_SYM_RBRKT 0x5D
+#define KEY_SYM_RCURLY 0x7D
+#define KEY_SYM_SLASH 0x5C
+#define KEY_SYM_PIPE 0x7C
+#define KEY_SYM_TIC 0x27
+#define KEY_SYM_QUOTE 0x22
+#define KEY_SYM_SEMIC 0x3B
+#define KEY_SYM_COLON 0x3A
+#define KEY_SYM_COMMA 0x2C
+#define KEY_SYM_LT 0x3C
+#define KEY_SYM_PERIOD 0x2E
+#define KEY_SYM_GT 0x3E
+#define KEY_SYM_BSLASH 0x2F
+#define KEY_SYM_QMARK 0x3F
+#define KEY_SYM_A 0x41
+#define KEY_SYM_B 0x42
+#define KEY_SYM_C 0x43
+#define KEY_SYM_D 0x44
+#define KEY_SYM_E 0x45
+#define KEY_SYM_F 0x46
+#define KEY_SYM_G 0x47
+#define KEY_SYM_H 0x48
+#define KEY_SYM_I 0x49
+#define KEY_SYM_J 0x4A
+#define KEY_SYM_K 0x4B
+#define KEY_SYM_L 0x4C
+#define KEY_SYM_M 0x4D
+#define KEY_SYM_N 0x4E
+#define KEY_SYM_O 0x4F
+#define KEY_SYM_P 0x50
+#define KEY_SYM_Q 0x51
+#define KEY_SYM_R 0x52
+#define KEY_SYM_S 0x53
+#define KEY_SYM_T 0x54
+#define KEY_SYM_U 0x55
+#define KEY_SYM_V 0x56
+#define KEY_SYM_W 0x57
+#define KEY_SYM_X 0x58
+#define KEY_SYM_Y 0x59
+#define KEY_SYM_Z 0x5A
+#define KEY_SYM_a 0x61
+#define KEY_SYM_b 0x62
+#define KEY_SYM_c 0x63
+#define KEY_SYM_d 0x64
+#define KEY_SYM_e 0x65
+#define KEY_SYM_f 0x66
+#define KEY_SYM_g 0x67
+#define KEY_SYM_h 0x68
+#define KEY_SYM_i 0x69
+#define KEY_SYM_j 0x6A
+#define KEY_SYM_k 0x6B
+#define KEY_SYM_l 0x6C
+#define KEY_SYM_m 0x6D
+#define KEY_SYM_n 0x6E
+#define KEY_SYM_o 0x6F
+#define KEY_SYM_p 0x70
+#define KEY_SYM_q 0x71
+#define KEY_SYM_r 0x72
+#define KEY_SYM_s 0x73
+#define KEY_SYM_t 0x74
+#define KEY_SYM_u 0x75
+#define KEY_SYM_v 0x76
+#define KEY_SYM_w 0x77
+#define KEY_SYM_x 0x78
+#define KEY_SYM_y 0x79
+#define KEY_SYM_z 0x7A
+#define KEY_SYM_SPACE 0x20
#endif /* _IBMASM_REMOTE_H_ */
if (vortex_debug > 6) {
printk(KERN_DEBUG "boomerang_start_xmit()\n");
- if (vortex_debug > 3)
- printk(KERN_DEBUG "%s: Trying to send a packet, Tx index %d.\n",
- dev->name, vp->cur_tx);
+ printk(KERN_DEBUG "%s: Trying to send a packet, Tx index %d.\n",
+ dev->name, vp->cur_tx);
}
if (vp->cur_tx - vp->dirty_tx >= TX_RING_SIZE) {
unsigned long icucr;
local_irq_save(flags);
- icucr = inl(ICUCR1);
+ icucr = inl(M32R_ICU_CR1_PORTL);
icucr |= M32R_ICUCR_ISMOD11;
- outl(icucr, ICUCR1);
+ outl(icucr, M32R_ICU_CR1_PORTL);
local_irq_restore(flags);
#endif
ei_local->stat.tx_errors++;
/* To avoid latency problems, we only process the current CPU,
* hoping that most samples for the task are on this CPU
*/
- sync_buffer(_smp_processor_id());
+ sync_buffer(raw_smp_processor_id());
return 0;
}
/* To avoid latency problems, we only process the current CPU,
* hoping that most samples for the task are on this CPU
*/
- sync_buffer(_smp_processor_id());
+ sync_buffer(raw_smp_processor_id());
return 0;
}
config M32R_PCC
bool "M32R PCMCIA I/F"
depends on M32R && CHIP_M32700 && PCMCIA
+ select PCCARD_NONSTATIC
help
Say Y here to use the M32R PCMCIA controller.
config M32R_CFC
bool "M32R CF I/F Controller"
- depends on M32R && (PLAT_USRV || PLAT_M32700UT || PLAT_MAPPI2 || PLAT_OPSPUT)
+ depends on M32R && (PLAT_USRV || PLAT_M32700UT || PLAT_MAPPI2 || PLAT_MAPPI3 || PLAT_OPSPUT)
+ select PCCARD_NONSTATIC
help
Say Y here to use the M32R CompactFlash controller.
config M32R_CFC_NUM
int "M32R CF I/F number"
depends on M32R_CFC
- default "1" if PLAT_USRV || PLAT_M32700UT || PLAT_MAPPI2 || PLAT_OPSPUT
+ default "1" if PLAT_USRV || PLAT_M32700UT || PLAT_MAPPI2 || PLAT_MAPPI3 || PLAT_OPSPUT
help
Set the number of M32R CF slots.
#include <linux/workqueue.h>
#include <linux/interrupt.h>
#include <linux/device.h>
+#include <linux/bitops.h>
#include <asm/irq.h>
#include <asm/io.h>
-#include <asm/bitops.h>
#include <asm/system.h>
#include <pcmcia/version.h>
debug(3, "m32r_cfc: _pcc_get_status: "
"power off (CPCR=0x%08x)\n", status);
}
-#elif defined(CONFIG_PLAT_MAPPI2)
+#elif defined(CONFIG_PLAT_MAPPI2) || defined(CONFIG_PLAT_MAPPI3)
if ( status ) {
status = pcc_get(sock, (unsigned int)PLD_CPCR);
if (status == 0) { /* power off */
pcc_set(sock, (unsigned int)PLD_CFBUFCR,0); /* force buffer off for ZA-36 */
udelay(50);
}
- status = pcc_get(sock, (unsigned int)PLD_CFBUFCR);
- if (status != 0) { /* buffer off */
- pcc_set(sock, (unsigned int)PLD_CFBUFCR,0);
- udelay(50);
- pcc_set(sock, (unsigned int)PLD_CFRSTCR, 0x0101);
- udelay(25); /* for IDE reset */
- pcc_set(sock, (unsigned int)PLD_CFRSTCR, 0x0100);
- mdelay(2); /* for IDE reset */
- } else {
- *value |= SS_POWERON;
- *value |= SS_READY;
- }
+ *value |= SS_POWERON;
+
+ pcc_set(sock, (unsigned int)PLD_CFBUFCR,0);
+ udelay(50);
+ pcc_set(sock, (unsigned int)PLD_CFRSTCR, 0x0101);
+ udelay(25); /* for IDE reset */
+ pcc_set(sock, (unsigned int)PLD_CFRSTCR, 0x0100);
+ mdelay(2); /* for IDE reset */
+
+ *value |= SS_READY;
+ *value |= SS_3VCARD;
+ } else {
+ /* disable CF power */
+ pcc_set(sock, (unsigned int)PLD_CPCR, 0);
+ udelay(100);
+ debug(3, "m32r_cfc: _pcc_get_status: "
+ "power off (CPCR=0x%08x)\n", status);
}
#else
#error no platform configuration
{
// pcc_socket_t *t = &socket[sock];
-#if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_USRV) || defined(CONFIG_PLAT_OPSPUT)
state->flags = 0;
state->csc_mask = SS_DETECT;
state->csc_mask |= SS_READY;
state->io_irq = 0;
state->Vcc = 33; /* 3.3V fixed */
state->Vpp = 33;
-#endif
+
debug(3, "m32r_cfc: GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d, "
"io_irq %d, csc_mask %#2.2x\n", sock, state->flags,
state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
static int _pcc_set_socket(u_short sock, socket_state_t *state)
{
-#if defined(CONFIG_PLAT_MAPPI2)
- u_long reg = 0;
-#endif
debug(3, "m32r_cfc: SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "
"io_irq %d, csc_mask %#2.2x)\n", sock, state->flags,
state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
-#if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_USRV) || defined(CONFIG_PLAT_OPSPUT)
+#if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_USRV) || defined(CONFIG_PLAT_OPSPUT) || defined(CONFIG_PLAT_MAPPI2) || defined(CONFIG_PLAT_MAPPI3)
if (state->Vcc) {
if ((state->Vcc != 50) && (state->Vcc != 33))
return -EINVAL;
/* accept 5V and 3.3V */
}
-#elif defined(CONFIG_PLAT_MAPPI2)
- if (state->Vcc) {
- /*
- * 5V only
- */
- if (state->Vcc == 50) {
- reg |= PCCSIGCR_VEN;
- } else {
- return -EINVAL;
- }
- }
#endif
-
if (state->flags & SS_RESET) {
debug(3, ":RESET\n");
pcc_set(sock,(unsigned int)PLD_CFRSTCR,0x101);
return ret;
}
-#if defined(CONFIG_PLAT_MAPPI2)
+#if defined(CONFIG_PLAT_MAPPI2) || defined(CONFIG_PLAT_MAPPI3)
pcc_set(0, (unsigned int)PLD_CFCR0, 0x0f0f);
pcc_set(0, (unsigned int)PLD_CFCR1, 0x0200);
#endif
for (i = 0 ; i < pcc_sockets ; i++) {
socket[i].socket.dev.dev = &pcc_device.dev;
socket[i].socket.ops = &pcc_operations;
- socket[i].socket.resource_ops = &pccard_static_ops;
+ socket[i].socket.resource_ops = &pccard_nonstatic_ops;
socket[i].socket.owner = THIS_MODULE;
socket[i].number = i;
ret = pcmcia_register_socket(&socket[i].socket);
#define CFC_IOPORT_BASE 0x1000
-#if !defined(CONFIG_PLAT_USRV)
+#if defined(CONFIG_PLAT_MAPPI3)
+#define CFC_ATTR_MAPBASE 0x14014000
+#define CFC_IO_MAPBASE_BYTE 0xb4012000
+#define CFC_IO_MAPBASE_WORD 0xb4002000
+#elif !defined(CONFIG_PLAT_USRV)
#define CFC_ATTR_MAPBASE 0x0c014000
#define CFC_IO_MAPBASE_BYTE 0xac012000
#define CFC_IO_MAPBASE_WORD 0xac002000
-#else /* CONFIG_PLAT_USRV */
+#else
#define CFC_ATTR_MAPBASE 0x04014000
#define CFC_IO_MAPBASE_BYTE 0xa4012000
#define CFC_IO_MAPBASE_WORD 0xa4002000
/*
* drivers/s390/cio/blacklist.c
* S/390 common I/O routines -- blacklisting of specific devices
- * $Revision: 1.33 $
+ * $Revision: 1.34 $
*
* Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation
len = 0;
for (devno = off; /* abuse the page variable
* as counter, see fs/proc/generic.c */
- devno <= __MAX_SUBCHANNELS && len + entry_size < count; devno++) {
+ devno < __MAX_SUBCHANNELS && len + entry_size < count; devno++) {
if (!test_bit(devno, bl_dev))
continue;
len += sprintf(page + len, "0.0.%04lx", devno);
len += sprintf(page + len, "\n");
}
- if (devno <= __MAX_SUBCHANNELS)
+ if (devno < __MAX_SUBCHANNELS)
*eof = 1;
*start = (char *) (devno - off); /* number of checked entries */
return len;
static int
megaraid_reset(Scsi_Cmnd *cmd)
{
- adapter = (adapter_t *)cmd->device->host->hostdata;
+ adapter_t *adapter = (adapter_t *)cmd->device->host->hostdata;
int rc;
spin_lock_irq(&adapter->lock);
config SERIAL_ICOM
tristate "IBM Multiport Serial Adapter"
- depends on PPC_ISERIES || PPC_PSERIES
+ depends on PCI && (PPC_ISERIES || PPC_PSERIES)
select SERIAL_CORE
help
This driver is for a family of multiport serial adapters
To compile this driver as a module, choose M here: the
module will be called jsm.
+config SERIAL_SGI_IOC4
+ tristate "SGI IOC4 controller serial support"
+ depends on (IA64_GENERIC || IA64_SGI_SN2) && SGI_IOC4
+ select SERIAL_CORE
+ help
+ If you have an SGI Altix with an IOC4 based Base IO card
+ and wish to use the serial ports on this card, say Y.
+ Otherwise, say N.
+
endmenu
obj-$(CONFIG_SERIAL_JSM) += jsm/
obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o
obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o
-obj-$(CONFIG_BLK_DEV_SGIIOC4) += ioc4_serial.o
+obj-$(CONFIG_SERIAL_SGI_IOC4) += ioc4_serial.o
void scc2_lineif(struct uart_cpm_port *pinfo)
{
+ /*
+ * STx GP3 uses the SCC2 secondary option pin assignment
+ * which this driver doesn't account for in the static
+ * pin assignments. This kind of board specific info
+ * really has to get out of the driver so boards can
+ * be supported in a sane fashion.
+ */
+#ifndef CONFIG_STX_GP3
volatile iop_cpm2_t *io = &cpm2_immr->im_ioport;
io->iop_pparb |= 0x008b0000;
io->iop_pdirb |= 0x00880000;
io->iop_psorb |= 0x00880000;
io->iop_pdirb &= ~0x00030000;
io->iop_psorb &= ~0x00030000;
+#endif
cpm2_immr->im_cpmux.cmx_scr &= 0xff00ffff;
cpm2_immr->im_cpmux.cmx_scr |= 0x00090000;
pinfo->brg = 2;
#include <linux/serial_reg.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/ioc4_common.h>
+#include <linux/ioc4.h>
#include <linux/serial_core.h>
/*
IOC4_SIO_IR_S3_TX_EXPLICIT)
/* Bitmasks for IOC4_OTHER_IR, IOC4_OTHER_IEC, and IOC4_OTHER_IES */
-#define IOC4_OTHER_IR_ATA_INT 0x00000001 /* ATAPI intr pass-thru */
-#define IOC4_OTHER_IR_ATA_MEMERR 0x00000002 /* ATAPI DMA PCI error */
-#define IOC4_OTHER_IR_S0_MEMERR 0x00000004 /* Port 0 PCI error */
-#define IOC4_OTHER_IR_S1_MEMERR 0x00000008 /* Port 1 PCI error */
-#define IOC4_OTHER_IR_S2_MEMERR 0x00000010 /* Port 2 PCI error */
-#define IOC4_OTHER_IR_S3_MEMERR 0x00000020 /* Port 3 PCI error */
+#define IOC4_OTHER_IR_ATA_INT 0x00000001 /* ATAPI intr pass-thru */
+#define IOC4_OTHER_IR_ATA_MEMERR 0x00000002 /* ATAPI DMA PCI error */
+#define IOC4_OTHER_IR_S0_MEMERR 0x00000004 /* Port 0 PCI error */
+#define IOC4_OTHER_IR_S1_MEMERR 0x00000008 /* Port 1 PCI error */
+#define IOC4_OTHER_IR_S2_MEMERR 0x00000010 /* Port 2 PCI error */
+#define IOC4_OTHER_IR_S3_MEMERR 0x00000020 /* Port 3 PCI error */
+#define IOC4_OTHER_IR_KBD_INT 0x00000040 /* Keyboard/mouse */
+#define IOC4_OTHER_IR_RESERVED 0x007fff80 /* Reserved */
+#define IOC4_OTHER_IR_RT_INT 0x00800000 /* INT_OUT section output */
+#define IOC4_OTHER_IR_GEN_INT 0xff000000 /* Generic pins */
+
+#define IOC4_OTHER_IR_SER_MEMERR (IOC4_OTHER_IR_S0_MEMERR | IOC4_OTHER_IR_S1_MEMERR | \
+ IOC4_OTHER_IR_S2_MEMERR | IOC4_OTHER_IR_S3_MEMERR)
/* Bitmasks for IOC4_SIO_CR */
#define IOC4_SIO_CR_CMD_PULSE_SHIFT 0 /* byte bus strobe shift */
#define i4u_dlm u2.dlm
#define i4u_fcr u3.fcr
-/* PCI memory space register map addressed using pci_bar0 */
-struct ioc4_memregs {
- struct ioc4_mem {
- /* Miscellaneous IOC4 registers */
- uint32_t pci_err_addr_l;
- uint32_t pci_err_addr_h;
- uint32_t sio_ir;
- uint32_t other_ir;
-
- /* These registers are read-only for general kernel code. */
- uint32_t sio_ies_ro;
- uint32_t other_ies_ro;
- uint32_t sio_iec_ro;
- uint32_t other_iec_ro;
- uint32_t sio_cr;
- uint32_t misc_fill1;
- uint32_t int_out;
- uint32_t misc_fill2;
- uint32_t gpcr_s;
- uint32_t gpcr_c;
- uint32_t gpdr;
- uint32_t misc_fill3;
- uint32_t gppr_0;
- uint32_t gppr_1;
- uint32_t gppr_2;
- uint32_t gppr_3;
- uint32_t gppr_4;
- uint32_t gppr_5;
- uint32_t gppr_6;
- uint32_t gppr_7;
- } ioc4_mem;
-
- char misc_fill4[0x100 - 0x5C - 4];
-
- /* ATA/ATAP registers */
- uint32_t ata_notused[9];
- char ata_fill1[0x140 - 0x120 - 4];
- uint32_t ata_notused1[8];
- char ata_fill2[0x200 - 0x15C - 4];
-
- /* Keyboard and mouse registers */
- uint32_t km_notused[5];;
- char km_fill1[0x300 - 0x210 - 4];
-
- /* Serial port registers used for DMA serial I/O */
- struct ioc4_serial {
- uint32_t sbbr01_l;
- uint32_t sbbr01_h;
- uint32_t sbbr23_l;
- uint32_t sbbr23_h;
-
- struct ioc4_serialregs port_0;
- struct ioc4_serialregs port_1;
- struct ioc4_serialregs port_2;
- struct ioc4_serialregs port_3;
- struct ioc4_uartregs uart_0;
- struct ioc4_uartregs uart_1;
- struct ioc4_uartregs uart_2;
- struct ioc4_uartregs uart_3;
- } ioc4_serial;
-};
+/* Serial port registers used for DMA serial I/O */
+struct ioc4_serial {
+ uint32_t sbbr01_l;
+ uint32_t sbbr01_h;
+ uint32_t sbbr23_l;
+ uint32_t sbbr23_h;
+
+ struct ioc4_serialregs port_0;
+ struct ioc4_serialregs port_1;
+ struct ioc4_serialregs port_2;
+ struct ioc4_serialregs port_3;
+ struct ioc4_uartregs uart_0;
+ struct ioc4_uartregs uart_1;
+ struct ioc4_uartregs uart_2;
+ struct ioc4_uartregs uart_3;
+} ioc4_serial;
/* UART clock speed */
-#define IOC4_SER_XIN_CLK IOC4_SER_XIN_CLK_66
#define IOC4_SER_XIN_CLK_66 66666667
#define IOC4_SER_XIN_CLK_33 33333333
| UART_LCR_WLEN7 | UART_LCR_WLEN8)
#define LCR_MASK_STOP_BITS (UART_LCR_STOP)
-#define PENDING(_p) (readl(&(_p)->ip_mem->sio_ir) & _p->ip_ienb)
-#define READ_SIO_IR(_p) readl(&(_p)->ip_mem->sio_ir)
+#define PENDING(_p) (readl(&(_p)->ip_mem->sio_ir.raw) & _p->ip_ienb)
+#define READ_SIO_IR(_p) readl(&(_p)->ip_mem->sio_ir.raw)
/* Default to 4k buffers */
#ifdef IOC4_1K_BUFFERS
*/
#define MAX_IOC4_INTR_ENTS (8 * sizeof(uint32_t))
struct ioc4_soft {
- struct ioc4_mem __iomem *is_ioc4_mem_addr;
+ struct ioc4_misc_regs __iomem *is_ioc4_misc_addr;
struct ioc4_serial __iomem *is_ioc4_serial_addr;
/* Each interrupt type has an entry in the array */
struct ioc4_soft *ip_ioc4_soft;
/* pci mem addresses */
- struct ioc4_mem __iomem *ip_mem;
+ struct ioc4_misc_regs __iomem *ip_mem;
struct ioc4_serial __iomem *ip_serial;
struct ioc4_serialregs __iomem *ip_serial_regs;
struct ioc4_uartregs __iomem *ip_uart_regs;
uint32_t intr_dma_error;
uint32_t intr_clear;
uint32_t intr_all;
- char rs422_select_pin;
+ int rs422_select_pin;
};
static struct hooks hooks_array[IOC4_NUM_SERIAL_PORTS] = {
static inline void
write_ireg(struct ioc4_soft *ioc4_soft, uint32_t val, int which, int type)
{
- struct ioc4_mem __iomem *mem = ioc4_soft->is_ioc4_mem_addr;
+ struct ioc4_misc_regs __iomem *mem = ioc4_soft->is_ioc4_misc_addr;
unsigned long flags;
spin_lock_irqsave(&ioc4_soft->is_ir_lock, flags);
case IOC4_SIO_INTR_TYPE:
switch (which) {
case IOC4_W_IES:
- writel(val, &mem->sio_ies_ro);
+ writel(val, &mem->sio_ies.raw);
break;
case IOC4_W_IEC:
- writel(val, &mem->sio_iec_ro);
+ writel(val, &mem->sio_iec.raw);
break;
}
break;
case IOC4_OTHER_INTR_TYPE:
switch (which) {
case IOC4_W_IES:
- writel(val, &mem->other_ies_ro);
+ writel(val, &mem->other_ies.raw);
break;
case IOC4_W_IEC:
- writel(val, &mem->other_iec_ro);
+ writel(val, &mem->other_iec.raw);
break;
}
break;
*/
static struct ioc4_port *get_ioc4_port(struct uart_port *the_port)
{
- struct ioc4_control *control = dev_get_drvdata(the_port->dev);
+ struct ioc4_driver_data *idd = dev_get_drvdata(the_port->dev);
+ struct ioc4_control *control = idd->idd_serial_data;
int ii;
if (control) {
static inline uint32_t
pending_intrs(struct ioc4_soft *soft, int type)
{
- struct ioc4_mem __iomem *mem = soft->is_ioc4_mem_addr;
+ struct ioc4_misc_regs __iomem *mem = soft->is_ioc4_misc_addr;
unsigned long flag;
uint32_t intrs = 0;
switch (type) {
case IOC4_SIO_INTR_TYPE:
- intrs = readl(&mem->sio_ir) & readl(&mem->sio_ies_ro);
+ intrs = readl(&mem->sio_ir.raw) & readl(&mem->sio_ies.raw);
break;
case IOC4_OTHER_INTR_TYPE:
- intrs = readl(&mem->other_ir) & readl(&mem->other_ies_ro);
+ intrs = readl(&mem->other_ir.raw) & readl(&mem->other_ies.raw);
/* Don't process any ATA interrupte */
intrs &= ~(IOC4_OTHER_IR_ATA_INT | IOC4_OTHER_IR_ATA_MEMERR);
/* Wait until any pending bus activity for this port has ceased */
do
- sio_cr = readl(&port->ip_mem->sio_cr);
+ sio_cr = readl(&port->ip_mem->sio_cr.raw);
while (!(sio_cr & IOC4_SIO_CR_SIO_DIAG_IDLE));
/* Finish reset sequence */
write_ireg(port->ip_ioc4_soft, hooks->intr_clear,
IOC4_W_IEC, IOC4_SIO_INTR_TYPE);
port->ip_ienb &= ~hooks->intr_clear;
- writel(hooks->intr_clear, &port->ip_mem->sio_ir);
+ writel(hooks->intr_clear, &port->ip_mem->sio_ir.raw);
return 0;
}
spin_lock_irqsave(&port->ip_lock, flags);
/* ACK the interrupt */
- writel(hooks->intr_dma_error, &port->ip_mem->other_ir);
+ writel(hooks->intr_dma_error, &port->ip_mem->other_ir.raw);
- if (readl(&port->ip_mem->pci_err_addr_l) & IOC4_PCI_ERR_ADDR_VLD) {
+ if (readl(&port->ip_mem->pci_err_addr_l.raw) & IOC4_PCI_ERR_ADDR_VLD) {
printk(KERN_ERR
"PCI error address is 0x%lx, "
"master is serial port %c %s\n",
(((uint64_t)readl(&port->ip_mem->pci_err_addr_h)
<< 32)
- | readl(&port->ip_mem->pci_err_addr_l))
+ | readl(&port->ip_mem->pci_err_addr_l.raw))
& IOC4_PCI_ERR_ADDR_ADDR_MSK, '1' +
- ((char)(readl(&port->ip_mem-> pci_err_addr_l) &
+ ((char)(readl(&port->ip_mem->pci_err_addr_l.raw) &
IOC4_PCI_ERR_ADDR_MST_NUM_MSK) >> 1),
- (readl(&port->ip_mem->pci_err_addr_l)
+ (readl(&port->ip_mem->pci_err_addr_l.raw)
& IOC4_PCI_ERR_ADDR_MST_TYP_MSK)
? "RX" : "TX");
- if (readl(&port->ip_mem->pci_err_addr_l)
+ if (readl(&port->ip_mem->pci_err_addr_l.raw)
& IOC4_PCI_ERR_ADDR_MUL_ERR) {
printk(KERN_ERR
"Multiple errors occurred\n");
"other_ies = 0x%x\n",
(intr_type == IOC4_SIO_INTR_TYPE) ? "sio" :
"other", this_ir,
- readl(&soft->is_ioc4_mem_addr->sio_ir),
- readl(&soft->is_ioc4_mem_addr->sio_ies_ro),
- readl(&soft->is_ioc4_mem_addr->other_ir),
- readl(&soft->is_ioc4_mem_addr->other_ies_ro));
+ readl(&soft->is_ioc4_misc_addr->sio_ir.raw),
+ readl(&soft->is_ioc4_misc_addr->sio_ies.raw),
+ readl(&soft->is_ioc4_misc_addr->other_ir.raw),
+ readl(&soft->is_ioc4_misc_addr->other_ies.raw));
}
}
#ifdef DEBUG_INTERRUPTS
{
- struct ioc4_mem __iomem *mem = soft->is_ioc4_mem_addr;
+ struct ioc4_misc_regs __iomem *mem = soft->is_ioc4_misc_addr;
spinlock_t *lp = &soft->is_ir_lock;
unsigned long flag;
spin_lock_irqsave(&soft->is_ir_lock, flag);
- printk ("%s : %d : mem 0x%p sio_ir 0x%x sio_ies_ro 0x%x "
- "other_ir 0x%x other_ies_ro 0x%x mask 0x%x\n",
+ printk ("%s : %d : mem 0x%p sio_ir 0x%x sio_ies 0x%x "
+ "other_ir 0x%x other_ies 0x%x mask 0x%x\n",
__FUNCTION__, __LINE__,
- (void *)mem, readl(&mem->sio_ir),
- readl(&mem->sio_ies_ro),
- readl(&mem->other_ir),
- readl(&mem->other_ies_ro),
+ (void *)mem, readl(&mem->sio_ir.raw),
+ readl(&mem->sio_ies.raw),
+ readl(&mem->other_ir.raw),
+ readl(&mem->other_ies.raw),
IOC4_OTHER_IR_ATA_INT | IOC4_OTHER_IR_ATA_MEMERR);
spin_unlock_irqrestore(&soft->is_ir_lock, flag);
}
* ioc4_attach_local - Device initialization.
* Called at *_attach() time for each
* IOC4 with serial ports in the system.
- * @control: ioc4_control ptr
- * @pdev: PCI handle for this device
- * @soft: soft struct for this device
- * @ioc4: ioc4 mem space
+ * @idd: Master module data for this IOC4
*/
-static int inline ioc4_attach_local(struct pci_dev *pdev,
- struct ioc4_control *control,
- struct ioc4_soft *soft, void __iomem *ioc4_mem,
- void __iomem *ioc4_serial)
+static int inline ioc4_attach_local(struct ioc4_driver_data *idd)
{
struct ioc4_port *port;
struct ioc4_port *ports[IOC4_NUM_SERIAL_PORTS];
int port_number;
uint16_t ioc4_revid_min = 62;
uint16_t ioc4_revid;
+ struct pci_dev *pdev = idd->idd_pdev;
+ struct ioc4_control* control = idd->idd_serial_data;
+ struct ioc4_soft *soft = control->ic_soft;
+ void __iomem *ioc4_misc = idd->idd_misc_regs;
+ void __iomem *ioc4_serial = soft->is_ioc4_serial_addr;
/* IOC4 firmware must be at least rev 62 */
pci_read_config_word(pdev, PCI_COMMAND_SPECIAL, &ioc4_revid);
ioc4_revid, ioc4_revid_min);
return -EPERM;
}
- BUG_ON(ioc4_mem == NULL);
+ BUG_ON(ioc4_misc == NULL);
BUG_ON(ioc4_serial == NULL);
/* Create port structures for each port */
port->ip_ioc4_soft = soft;
port->ip_pdev = pdev;
port->ip_ienb = 0;
- port->ip_pci_bus_speed = IOC4_SER_XIN_CLK;
+ /* Use baud rate calculations based on detected PCI
+ * bus speed. Simply test whether the PCI clock is
+ * running closer to 66MHz or 33MHz.
+ */
+ if (idd->count_period/IOC4_EXTINT_COUNT_DIVISOR < 20) {
+ port->ip_pci_bus_speed = IOC4_SER_XIN_CLK_66;
+ } else {
+ port->ip_pci_bus_speed = IOC4_SER_XIN_CLK_33;
+ }
port->ip_baud = 9600;
port->ip_control = control;
- port->ip_mem = ioc4_mem;
+ port->ip_mem = ioc4_misc;
port->ip_serial = ioc4_serial;
/* point to the right hook */
switch (proto) {
case PROTO_RS232:
/* Clear the appropriate GIO pin */
- writel(0, (&port->ip_mem->gppr_0 +
- hooks->rs422_select_pin));
+ writel(0, (&port->ip_mem->gppr[hooks->rs422_select_pin].raw));
break;
case PROTO_RS422:
/* Set the appropriate GIO pin */
- writel(1, (&port->ip_mem->gppr_0 +
- hooks->rs422_select_pin));
+ writel(1, (&port->ip_mem->gppr[hooks->rs422_select_pin].raw));
break;
default:
if (sio_ir & hooks->intr_delta_dcd) {
/* ACK the interrupt */
writel(hooks->intr_delta_dcd,
- &port->ip_mem->sio_ir);
+ &port->ip_mem->sio_ir.raw);
shadow = readl(&port->ip_serial_regs->shadow);
if (sio_ir & hooks->intr_delta_cts) {
/* ACK the interrupt */
writel(hooks->intr_delta_cts,
- &port->ip_mem->sio_ir);
+ &port->ip_mem->sio_ir.raw);
shadow = readl(&port->ip_serial_regs->shadow);
if (sio_ir & hooks->intr_rx_timer) {
/* ACK the interrupt */
writel(hooks->intr_rx_timer,
- &port->ip_mem->sio_ir);
+ &port->ip_mem->sio_ir.raw);
if ((port->ip_notify & N_DATA_READY)
&& (port->ip_port)) {
/* ACK the interrupt */
writel(hooks->intr_tx_explicit,
- &port->ip_mem->sio_ir);
+ &port->ip_mem->sio_ir.raw);
if (port->ip_notify & N_OUTPUT_LOWAT)
ioc4_cb_output_lowat(port);
{
struct ioc4_port *port;
struct uart_port *the_port;
- struct ioc4_control *control = pci_get_drvdata(pdev);
+ struct ioc4_driver_data *idd = pci_get_drvdata(pdev);
+ struct ioc4_control *control = idd->idd_serial_data;
int ii;
DPRINT_CONFIG(("%s: attach pdev 0x%p - control 0x%p\n",
/**
* ioc4_serial_attach_one - register attach function
- * called per card found from ioc4_serial_detect as part
- * of module_init().
- * @pdev: handle for this card
- * @pci_id: pci id for this card
+ * called per card found from IOC4 master module.
+ * @idd: Master module data for this IOC4
*/
int
-ioc4_serial_attach_one(struct pci_dev *pdev, const struct pci_device_id *pci_id)
+ioc4_serial_attach_one(struct ioc4_driver_data *idd)
{
- struct ioc4_mem __iomem *mem;
- unsigned long tmp_addr, tmp_addr1;
+ unsigned long tmp_addr1;
struct ioc4_serial __iomem *serial;
struct ioc4_soft *soft;
struct ioc4_control *control;
- int tmp, ret = 0;
+ int ret = 0;
- DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __FUNCTION__, pdev, pci_id));
-
- /* Map in the ioc4 memory */
- tmp_addr = pci_resource_start(pdev, 0);
- if (!tmp_addr) {
- printk(KERN_WARNING
- "ioc4 (%p) : unable to get PIO mapping for "
- "MEM space\n", (void *)pdev);
- return -ENODEV;
- }
- if (!request_region(tmp_addr, sizeof(struct ioc4_mem), "sioc4_mem")) {
- printk(KERN_ALERT
- "ioc4 (%p): unable to get request region for "
- "MEM space\n", (void *)pdev);
- return -ENODEV;
- }
- mem = ioremap(tmp_addr, sizeof(struct ioc4_mem));
- if (!mem) {
- printk(KERN_WARNING
- "ioc4 (%p) : unable to remap ioc4 memory\n",
- (void *)pdev);
- ret = -ENODEV;
- goto out1;
- }
+ DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __FUNCTION__, idd->idd_pdev, idd->idd_pci_id));
/* request serial registers */
- tmp_addr1 = pci_resource_start(pdev, 0) + IOC4_SERIAL_OFFSET;
+ tmp_addr1 = idd->idd_bar0 + IOC4_SERIAL_OFFSET;
if (!request_region(tmp_addr1, sizeof(struct ioc4_serial),
"sioc4_uart")) {
printk(KERN_WARNING
"ioc4 (%p): unable to get request region for "
- "uart space\n", (void *)pdev);
+ "uart space\n", (void *)idd->idd_pdev);
ret = -ENODEV;
goto out1;
}
if (!serial) {
printk(KERN_WARNING
"ioc4 (%p) : unable to remap ioc4 serial register\n",
- (void *)pdev);
+ (void *)idd->idd_pdev);
ret = -ENODEV;
goto out2;
}
DPRINT_CONFIG(("%s : mem 0x%p, serial 0x%p\n",
- __FUNCTION__, (void *)mem, (void *)serial));
+ __FUNCTION__, (void *)idd->idd_misc_regs, (void *)serial));
/* Get memory for the new card */
control = kmalloc(sizeof(struct ioc4_control) * IOC4_NUM_SERIAL_PORTS,
goto out2;
}
memset(control, 0, sizeof(struct ioc4_control));
- pci_set_drvdata(pdev, control);
+ idd->idd_serial_data = control;
/* Allocate the soft structure */
soft = kmalloc(sizeof(struct ioc4_soft), GFP_KERNEL);
if (!soft) {
printk(KERN_WARNING
"ioc4 (%p): unable to get memory for the soft struct\n",
- (void *)pdev);
+ (void *)idd->idd_pdev);
ret = -ENOMEM;
goto out3;
}
memset(soft, 0, sizeof(struct ioc4_soft));
spin_lock_init(&soft->is_ir_lock);
- soft->is_ioc4_mem_addr = mem;
+ soft->is_ioc4_misc_addr = idd->idd_misc_regs;
soft->is_ioc4_serial_addr = serial;
/* Init the IOC4 */
- pci_read_config_dword(pdev, PCI_COMMAND, &tmp);
- pci_write_config_dword(pdev, PCI_COMMAND,
- tmp | PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
-
- writel(0xf << IOC4_SIO_CR_CMD_PULSE_SHIFT, &mem->sio_cr);
+ writel(0xf << IOC4_SIO_CR_CMD_PULSE_SHIFT,
+ &idd->idd_misc_regs->sio_cr.raw);
/* Enable serial port mode select generic PIO pins as outputs */
writel(IOC4_GPCR_UART0_MODESEL | IOC4_GPCR_UART1_MODESEL
| IOC4_GPCR_UART2_MODESEL | IOC4_GPCR_UART3_MODESEL,
- &mem->gpcr_s);
+ &idd->idd_misc_regs->gpcr_s.raw);
- /* Clear and disable all interrupts */
+ /* Clear and disable all serial interrupts */
write_ireg(soft, ~0, IOC4_W_IEC, IOC4_SIO_INTR_TYPE);
- writel(~0, &mem->sio_ir);
- write_ireg(soft, ~(IOC4_OTHER_IR_ATA_INT | IOC4_OTHER_IR_ATA_MEMERR),
- IOC4_W_IEC, IOC4_OTHER_INTR_TYPE);
- writel(~(IOC4_OTHER_IR_ATA_MEMERR | IOC4_OTHER_IR_ATA_MEMERR),
- &mem->other_ir);
+ writel(~0, &idd->idd_misc_regs->sio_ir.raw);
+ write_ireg(soft, IOC4_OTHER_IR_SER_MEMERR, IOC4_W_IEC,
+ IOC4_OTHER_INTR_TYPE);
+ writel(IOC4_OTHER_IR_SER_MEMERR, &idd->idd_misc_regs->other_ir.raw);
control->ic_soft = soft;
- if (!request_irq(pdev->irq, ioc4_intr, SA_SHIRQ,
+
+ /* Hook up interrupt handler */
+ if (!request_irq(idd->idd_pdev->irq, ioc4_intr, SA_SHIRQ,
"sgi-ioc4serial", (void *)soft)) {
- control->ic_irq = pdev->irq;
+ control->ic_irq = idd->idd_pdev->irq;
} else {
printk(KERN_WARNING
"%s : request_irq fails for IRQ 0x%x\n ",
- __FUNCTION__, pdev->irq);
+ __FUNCTION__, idd->idd_pdev->irq);
}
- if ((ret = ioc4_attach_local(pdev, control, soft,
- soft->is_ioc4_mem_addr,
- soft->is_ioc4_serial_addr)))
+ ret = ioc4_attach_local(idd);
+ if (ret)
goto out4;
/* register port with the serial core */
- if ((ret = ioc4_serial_core_attach(pdev)))
+ if ((ret = ioc4_serial_core_attach(idd->idd_pdev)))
goto out4;
return ret;
out2:
release_region(tmp_addr1, sizeof(struct ioc4_serial));
out1:
- release_region(tmp_addr, sizeof(struct ioc4_mem));
return ret;
}
/**
* ioc4_serial_remove_one - detach function
*
- * @pdev: handle for this card
+ * @idd: IOC4 master module data for this IOC4
*/
-#if 0
-void ioc4_serial_remove_one(struct pci_dev *pdev)
+int ioc4_serial_remove_one(struct ioc4_driver_data *idd)
{
int ii;
struct ioc4_control *control;
struct ioc4_port *port;
struct ioc4_soft *soft;
- control = pci_get_drvdata(pdev);
+ control = idd->idd_serial_data;
for (ii = 0; ii < IOC4_NUM_SERIAL_PORTS; ii++) {
the_port = &control->ic_port[ii].icp_uart_port;
kfree(soft);
}
kfree(control);
- pci_set_drvdata(pdev, NULL);
- uart_unregister_driver(&ioc4_uart);
+ idd->idd_serial_data = NULL;
+
+ return 0;
}
-#endif
+
+static struct ioc4_submodule ioc4_serial_submodule = {
+ .is_name = "IOC4_serial",
+ .is_owner = THIS_MODULE,
+ .is_probe = ioc4_serial_attach_one,
+ .is_remove = ioc4_serial_remove_one,
+};
/**
* ioc4_serial_init - module init
__FUNCTION__);
return ret;
}
- return 0;
+
+ /* register with IOC4 main module */
+ return ioc4_register_submodule(&ioc4_serial_submodule);
+}
+
+static void __devexit ioc4_serial_exit(void)
+{
+ ioc4_unregister_submodule(&ioc4_serial_submodule);
+ uart_unregister_driver(&ioc4_uart);
}
+module_init(ioc4_serial_init);
+module_exit(ioc4_serial_exit);
+
MODULE_AUTHOR("Pat Gefre - Silicon Graphics Inc. (SGI) <pfg@sgi.com>");
MODULE_DESCRIPTION("Serial PCI driver module for SGI IOC4 Base-IO Card");
MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(ioc4_serial_init);
-EXPORT_SYMBOL(ioc4_serial_attach_one);
--- /dev/null
+#
+# Miscellaneous SN-specific devices
+#
+
+menu "SN Devices"
+
+config SGI_IOC4
+ tristate "SGI IOC4 Base IO support"
+ depends on (IA64_GENERIC || IA64_SGI_SN2) && MMTIMER
+ default m
+ ---help---
+ This option enables basic support for the SGI IOC4-based Base IO
+ controller card. This option does not enable any specific
+ functions on such a card, but provides necessary infrastructure
+ for other drivers to utilize.
+
+ If you have an SGI Altix with an IOC4-based
+ I/O controller say Y. Otherwise say N.
+
+endmenu
#
#
-obj-$(CONFIG_BLK_DEV_SGIIOC4) += ioc4.o
+obj-$(CONFIG_SGI_IOC4) += ioc4.o
* Copyright (C) 2005 Silicon Graphics, Inc. All Rights Reserved.
*/
-/*
- * This file contains a shim driver for the IOC4 IDE and serial drivers.
+/* This file contains the master driver module for use by SGI IOC4 subdrivers.
+ *
+ * It allocates any resources shared between multiple subdevices, and
+ * provides accessor functions (where needed) and the like for those
+ * resources. It also provides a mechanism for the subdevice modules
+ * to support loading and unloading.
+ *
+ * Non-shared resources (e.g. external interrupt A_INT_OUT register page
+ * alias, serial port and UART registers) are handled by the subdevice
+ * modules themselves.
+ *
+ * This is all necessary because IOC4 is not implemented as a multi-function
+ * PCI device, but an amalgamation of disparate registers for several
+ * types of device (ATA, serial, external interrupts). The normal
+ * resource management in the kernel doesn't have quite the right interfaces
+ * to handle this situation (e.g. multiple modules can't claim the same
+ * PCI ID), thus this IOC4 master module.
*/
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/ioc4_common.h>
-#include <linux/ide.h>
+#include <linux/ioc4.h>
+#include <linux/mmtimer.h>
+#include <linux/rtc.h>
+#include <linux/rwsem.h>
+#include <asm/sn/addrs.h>
+#include <asm/sn/clksupport.h>
+#include <asm/sn/shub_mmr.h>
+/***************
+ * Definitions *
+ ***************/
-static int __devinit
-ioc4_probe_one(struct pci_dev *pdev, const struct pci_device_id *pci_id)
+/* Tweakable values */
+
+/* PCI bus speed detection/calibration */
+#define IOC4_CALIBRATE_COUNT 63 /* Calibration cycle period */
+#define IOC4_CALIBRATE_CYCLES 256 /* Average over this many cycles */
+#define IOC4_CALIBRATE_DISCARD 2 /* Discard first few cycles */
+#define IOC4_CALIBRATE_LOW_MHZ 25 /* Lower bound on bus speed sanity */
+#define IOC4_CALIBRATE_HIGH_MHZ 75 /* Upper bound on bus speed sanity */
+#define IOC4_CALIBRATE_DEFAULT_MHZ 66 /* Assumed if sanity check fails */
+
+/************************
+ * Submodule management *
+ ************************/
+
+static LIST_HEAD(ioc4_devices);
+static DECLARE_RWSEM(ioc4_devices_rwsem);
+
+static LIST_HEAD(ioc4_submodules);
+static DECLARE_RWSEM(ioc4_submodules_rwsem);
+
+/* Register an IOC4 submodule */
+int
+ioc4_register_submodule(struct ioc4_submodule *is)
+{
+ struct ioc4_driver_data *idd;
+
+ down_write(&ioc4_submodules_rwsem);
+ list_add(&is->is_list, &ioc4_submodules);
+ up_write(&ioc4_submodules_rwsem);
+
+ /* Initialize submodule for each IOC4 */
+ if (!is->is_probe)
+ return 0;
+
+ down_read(&ioc4_devices_rwsem);
+ list_for_each_entry(idd, &ioc4_devices, idd_list) {
+ if (is->is_probe(idd)) {
+ printk(KERN_WARNING
+ "%s: IOC4 submodule %s probe failed "
+ "for pci_dev %s",
+ __FUNCTION__, module_name(is->is_owner),
+ pci_name(idd->idd_pdev));
+ }
+ }
+ up_read(&ioc4_devices_rwsem);
+
+ return 0;
+}
+
+/* Unregister an IOC4 submodule */
+void
+ioc4_unregister_submodule(struct ioc4_submodule *is)
+{
+ struct ioc4_driver_data *idd;
+
+ down_write(&ioc4_submodules_rwsem);
+ list_del(&is->is_list);
+ up_write(&ioc4_submodules_rwsem);
+
+ /* Remove submodule for each IOC4 */
+ if (!is->is_remove)
+ return;
+
+ down_read(&ioc4_devices_rwsem);
+ list_for_each_entry(idd, &ioc4_devices, idd_list) {
+ if (is->is_remove(idd)) {
+ printk(KERN_WARNING
+ "%s: IOC4 submodule %s remove failed "
+ "for pci_dev %s.\n",
+ __FUNCTION__, module_name(is->is_owner),
+ pci_name(idd->idd_pdev));
+ }
+ }
+ up_read(&ioc4_devices_rwsem);
+}
+
+/*********************
+ * Device management *
+ *********************/
+
+#define IOC4_CALIBRATE_LOW_LIMIT \
+ (1000*IOC4_EXTINT_COUNT_DIVISOR/IOC4_CALIBRATE_LOW_MHZ)
+#define IOC4_CALIBRATE_HIGH_LIMIT \
+ (1000*IOC4_EXTINT_COUNT_DIVISOR/IOC4_CALIBRATE_HIGH_MHZ)
+#define IOC4_CALIBRATE_DEFAULT \
+ (1000*IOC4_EXTINT_COUNT_DIVISOR/IOC4_CALIBRATE_DEFAULT_MHZ)
+
+#define IOC4_CALIBRATE_END \
+ (IOC4_CALIBRATE_CYCLES + IOC4_CALIBRATE_DISCARD)
+
+#define IOC4_INT_OUT_MODE_TOGGLE 0x7 /* Toggle INT_OUT every COUNT+1 ticks */
+
+/* Determines external interrupt output clock period of the PCI bus an
+ * IOC4 is attached to. This value can be used to determine the PCI
+ * bus speed.
+ *
+ * IOC4 has a design feature that various internal timers are derived from
+ * the PCI bus clock. This causes IOC4 device drivers to need to take the
+ * bus speed into account when setting various register values (e.g. INT_OUT
+ * register COUNT field, UART divisors, etc). Since this information is
+ * needed by several subdrivers, it is determined by the main IOC4 driver,
+ * even though the following code utilizes external interrupt registers
+ * to perform the speed calculation.
+ */
+static void
+ioc4_clock_calibrate(struct ioc4_driver_data *idd)
+{
+ extern unsigned long sn_rtc_cycles_per_second;
+ union ioc4_int_out int_out;
+ union ioc4_gpcr gpcr;
+ unsigned int state, last_state = 1;
+ uint64_t start = 0, end, period;
+ unsigned int count = 0;
+
+ /* Enable output */
+ gpcr.raw = 0;
+ gpcr.fields.dir = IOC4_GPCR_DIR_0;
+ gpcr.fields.int_out_en = 1;
+ writel(gpcr.raw, &idd->idd_misc_regs->gpcr_s.raw);
+
+ /* Reset to power-on state */
+ writel(0, &idd->idd_misc_regs->int_out.raw);
+ mmiowb();
+
+ printk(KERN_INFO
+ "%s: Calibrating PCI bus speed "
+ "for pci_dev %s ... ", __FUNCTION__, pci_name(idd->idd_pdev));
+ /* Set up square wave */
+ int_out.raw = 0;
+ int_out.fields.count = IOC4_CALIBRATE_COUNT;
+ int_out.fields.mode = IOC4_INT_OUT_MODE_TOGGLE;
+ int_out.fields.diag = 0;
+ writel(int_out.raw, &idd->idd_misc_regs->int_out.raw);
+ mmiowb();
+
+ /* Check square wave period averaged over some number of cycles */
+ do {
+ int_out.raw = readl(&idd->idd_misc_regs->int_out.raw);
+ state = int_out.fields.int_out;
+ if (!last_state && state) {
+ count++;
+ if (count == IOC4_CALIBRATE_END) {
+ end = rtc_time();
+ break;
+ } else if (count == IOC4_CALIBRATE_DISCARD)
+ start = rtc_time();
+ }
+ last_state = state;
+ } while (1);
+
+ /* Calculation rearranged to preserve intermediate precision.
+ * Logically:
+ * 1. "end - start" gives us number of RTC cycles over all the
+ * square wave cycles measured.
+ * 2. Divide by number of square wave cycles to get number of
+ * RTC cycles per square wave cycle.
+ * 3. Divide by 2*(int_out.fields.count+1), which is the formula
+ * by which the IOC4 generates the square wave, to get the
+ * number of RTC cycles per IOC4 INT_OUT count.
+ * 4. Divide by sn_rtc_cycles_per_second to get seconds per
+ * count.
+ * 5. Multiply by 1E9 to get nanoseconds per count.
+ */
+ period = ((end - start) * 1000000000) /
+ (IOC4_CALIBRATE_CYCLES * 2 * (IOC4_CALIBRATE_COUNT + 1)
+ * sn_rtc_cycles_per_second);
+
+ /* Bounds check the result. */
+ if (period > IOC4_CALIBRATE_LOW_LIMIT ||
+ period < IOC4_CALIBRATE_HIGH_LIMIT) {
+ printk("failed. Assuming PCI clock ticks are %d ns.\n",
+ IOC4_CALIBRATE_DEFAULT / IOC4_EXTINT_COUNT_DIVISOR);
+ period = IOC4_CALIBRATE_DEFAULT;
+ } else {
+ printk("succeeded. PCI clock ticks are %ld ns.\n",
+ period / IOC4_EXTINT_COUNT_DIVISOR);
+ }
+
+ /* Remember results. We store the extint clock period rather
+ * than the PCI clock period so that greater precision is
+ * retained. Divide by IOC4_EXTINT_COUNT_DIVISOR to get
+ * PCI clock period.
+ */
+ idd->count_period = period;
+}
+
+/* Adds a new instance of an IOC4 card */
+static int
+ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
{
+ struct ioc4_driver_data *idd;
+ struct ioc4_submodule *is;
+ uint32_t pcmd;
int ret;
+ /* Enable IOC4 and take ownership of it */
if ((ret = pci_enable_device(pdev))) {
printk(KERN_WARNING
- "%s: Failed to enable device with "
- "pci_dev 0x%p... returning\n",
- __FUNCTION__, (void *)pdev);
- return ret;
+ "%s: Failed to enable IOC4 device for pci_dev %s.\n",
+ __FUNCTION__, pci_name(pdev));
+ goto out;
}
pci_set_master(pdev);
- /* attach each sub-device */
- ret = ioc4_ide_attach_one(pdev, pci_id);
- if (ret)
- return ret;
- return ioc4_serial_attach_one(pdev, pci_id);
+ /* Set up per-IOC4 data */
+ idd = kmalloc(sizeof(struct ioc4_driver_data), GFP_KERNEL);
+ if (!idd) {
+ printk(KERN_WARNING
+ "%s: Failed to allocate IOC4 data for pci_dev %s.\n",
+ __FUNCTION__, pci_name(pdev));
+ ret = -ENODEV;
+ goto out_idd;
+ }
+ idd->idd_pdev = pdev;
+ idd->idd_pci_id = pci_id;
+
+ /* Map IOC4 misc registers. These are shared between subdevices
+ * so the main IOC4 module manages them.
+ */
+ idd->idd_bar0 = pci_resource_start(idd->idd_pdev, 0);
+ if (!idd->idd_bar0) {
+ printk(KERN_WARNING
+ "%s: Unable to find IOC4 misc resource "
+ "for pci_dev %s.\n",
+ __FUNCTION__, pci_name(idd->idd_pdev));
+ ret = -ENODEV;
+ goto out_pci;
+ }
+ if (!request_region(idd->idd_bar0, sizeof(struct ioc4_misc_regs),
+ "ioc4_misc")) {
+ printk(KERN_WARNING
+ "%s: Unable to request IOC4 misc region "
+ "for pci_dev %s.\n",
+ __FUNCTION__, pci_name(idd->idd_pdev));
+ ret = -ENODEV;
+ goto out_pci;
+ }
+ idd->idd_misc_regs = ioremap(idd->idd_bar0,
+ sizeof(struct ioc4_misc_regs));
+ if (!idd->idd_misc_regs) {
+ printk(KERN_WARNING
+ "%s: Unable to remap IOC4 misc region "
+ "for pci_dev %s.\n",
+ __FUNCTION__, pci_name(idd->idd_pdev));
+ ret = -ENODEV;
+ goto out_misc_region;
+ }
+
+ /* Failsafe portion of per-IOC4 initialization */
+
+ /* Initialize IOC4 */
+ pci_read_config_dword(idd->idd_pdev, PCI_COMMAND, &pcmd);
+ pci_write_config_dword(idd->idd_pdev, PCI_COMMAND,
+ pcmd | PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
+
+ /* Determine PCI clock */
+ ioc4_clock_calibrate(idd);
+
+ /* Disable/clear all interrupts. Need to do this here lest
+ * one submodule request the shared IOC4 IRQ, but interrupt
+ * is generated by a different subdevice.
+ */
+ /* Disable */
+ writel(~0, &idd->idd_misc_regs->other_iec.raw);
+ writel(~0, &idd->idd_misc_regs->sio_iec);
+ /* Clear (i.e. acknowledge) */
+ writel(~0, &idd->idd_misc_regs->other_ir.raw);
+ writel(~0, &idd->idd_misc_regs->sio_ir);
+
+ /* Track PCI-device specific data */
+ idd->idd_serial_data = NULL;
+ pci_set_drvdata(idd->idd_pdev, idd);
+ down_write(&ioc4_devices_rwsem);
+ list_add(&idd->idd_list, &ioc4_devices);
+ up_write(&ioc4_devices_rwsem);
+
+ /* Add this IOC4 to all submodules */
+ down_read(&ioc4_submodules_rwsem);
+ list_for_each_entry(is, &ioc4_submodules, is_list) {
+ if (is->is_probe && is->is_probe(idd)) {
+ printk(KERN_WARNING
+ "%s: IOC4 submodule 0x%s probe failed "
+ "for pci_dev %s.\n",
+ __FUNCTION__, module_name(is->is_owner),
+ pci_name(idd->idd_pdev));
+ }
+ }
+ up_read(&ioc4_submodules_rwsem);
+
+ return 0;
+
+out_misc_region:
+ release_region(idd->idd_bar0, sizeof(struct ioc4_misc_regs));
+out_pci:
+ kfree(idd);
+out_idd:
+ pci_disable_device(pdev);
+out:
+ return ret;
}
-/* pci device struct */
-static struct pci_device_id ioc4_s_id_table[] = {
+/* Removes a particular instance of an IOC4 card. */
+static void
+ioc4_remove(struct pci_dev *pdev)
+{
+ struct ioc4_submodule *is;
+ struct ioc4_driver_data *idd;
+
+ idd = pci_get_drvdata(pdev);
+
+ /* Remove this IOC4 from all submodules */
+ down_read(&ioc4_submodules_rwsem);
+ list_for_each_entry(is, &ioc4_submodules, is_list) {
+ if (is->is_remove && is->is_remove(idd)) {
+ printk(KERN_WARNING
+ "%s: IOC4 submodule 0x%s remove failed "
+ "for pci_dev %s.\n",
+ __FUNCTION__, module_name(is->is_owner),
+ pci_name(idd->idd_pdev));
+ }
+ }
+ up_read(&ioc4_submodules_rwsem);
+
+ /* Release resources */
+ iounmap(idd->idd_misc_regs);
+ if (!idd->idd_bar0) {
+ printk(KERN_WARNING
+ "%s: Unable to get IOC4 misc mapping for pci_dev %s. "
+ "Device removal may be incomplete.\n",
+ __FUNCTION__, pci_name(idd->idd_pdev));
+ }
+ release_region(idd->idd_bar0, sizeof(struct ioc4_misc_regs));
+
+ /* Disable IOC4 and relinquish */
+ pci_disable_device(pdev);
+
+ /* Remove and free driver data */
+ down_write(&ioc4_devices_rwsem);
+ list_del(&idd->idd_list);
+ up_write(&ioc4_devices_rwsem);
+ kfree(idd);
+}
+
+static struct pci_device_id ioc4_id_table[] = {
{PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC4, PCI_ANY_ID,
PCI_ANY_ID, 0x0b4000, 0xFFFFFF},
{0}
};
-MODULE_DEVICE_TABLE(pci, ioc4_s_id_table);
-static struct pci_driver __devinitdata ioc4_s_driver = {
- .name = "IOC4",
- .id_table = ioc4_s_id_table,
- .probe = ioc4_probe_one,
+static struct pci_driver __devinitdata ioc4_driver = {
+ .name = "IOC4",
+ .id_table = ioc4_id_table,
+ .probe = ioc4_probe,
+ .remove = ioc4_remove,
};
-static int __devinit ioc4_detect(void)
+MODULE_DEVICE_TABLE(pci, ioc4_id_table);
+
+/*********************
+ * Module management *
+ *********************/
+
+/* Module load */
+static int __devinit
+ioc4_init(void)
{
- ioc4_serial_init();
+ return pci_register_driver(&ioc4_driver);
+}
- return pci_register_driver(&ioc4_s_driver);
+/* Module unload */
+static void __devexit
+ioc4_exit(void)
+{
+ pci_unregister_driver(&ioc4_driver);
}
-module_init(ioc4_detect);
-MODULE_AUTHOR("Pat Gefre - Silicon Graphics Inc. (SGI) <pfg@sgi.com>");
-MODULE_DESCRIPTION("PCI driver module for SGI IOC4 Base-IO Card");
+module_init(ioc4_init);
+module_exit(ioc4_exit);
+
+MODULE_AUTHOR("Brent Casavant - Silicon Graphics, Inc. <bcasavan@sgi.com>");
+MODULE_DESCRIPTION("PCI driver master module for SGI IOC4 Base-IO Card");
MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(ioc4_register_submodule);
+EXPORT_SYMBOL(ioc4_unregister_submodule);
This is the frame buffer device driver for the Amiga FrameMaster
card from BSC (exhibited 1992 but not shipped as a CBM product).
+config FB_ARC
+ tristate "Arc Monochrome LCD board support"
+ depends on FB && X86
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ select FB_SOFT_CURSOR
+ help
+ This enables support for the Arc Monochrome LCD board. The board
+ is based on the KS-108 lcd controller and is typically a matrix
+ of 2*n chips. This driver was tested with a 128x64 panel. This
+ driver supports it for use with x86 SBCs through a 16 bit GPIO
+ interface (8 bit data, 8 bit control). If you anticpate using
+ this driver, say Y or M; otherwise say N. You must specify the
+ GPIO IO address to be used for setting control and data.
+
config FB_ATARI
bool "Atari native chipset support"
depends on (FB = y) && ATARI && BROKEN
# Hardware specific drivers go first
obj-$(CONFIG_FB_RETINAZ3) += retz3fb.o
obj-$(CONFIG_FB_AMIGA) += amifb.o c2p.o
+obj-$(CONFIG_FB_ARC) += arcfb.o
obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o
obj-$(CONFIG_FB_CYBER) += cyberfb.o
obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o
--- /dev/null
+/*
+ * linux/drivers/video/arcfb.c -- FB driver for Arc monochrome LCD board
+ *
+ * Copyright (C) 2005, Jaya Kumar <jayalk@intworks.biz>
+ * http://www.intworks.biz/arclcd
+ *
+ * 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.
+ *
+ * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven.
+ *
+ * This driver was written to be used with the Arc LCD board. Arc uses a
+ * set of KS108 chips that control individual 64x64 LCD matrices. The board
+ * can be paneled in a variety of setups such as 2x1=128x64, 4x4=256x256 and
+ * so on. The interface between the board and the host is TTL based GPIO. The
+ * GPIO requirements are 8 writable data lines and 4+n lines for control. On a
+ * GPIO-less system, the board can be tested by connecting the respective sigs
+ * up to a parallel port connector. The driver requires the IO addresses for
+ * data and control GPIO at load time. It is unable to probe for the
+ * existence of the LCD so it must be told at load time whether it should
+ * be enabled or not.
+ *
+ * Todo:
+ * - testing with 4x4
+ * - testing with interrupt hw
+ *
+ * General notes:
+ * - User must set tuhold. It's in microseconds. According to the 108 spec,
+ * the hold time is supposed to be at least 1 microsecond.
+ * - User must set num_cols=x num_rows=y, eg: x=2 means 128
+ * - User must set arcfb_enable=1 to enable it
+ * - User must set dio_addr=0xIOADDR cio_addr=0xIOADDR
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/arcfb.h>
+
+#include <asm/uaccess.h>
+
+#define floor8(a) (a&(~0x07))
+#define floorXres(a,xres) (a&(~(xres - 1)))
+#define iceil8(a) (((int)((a+7)/8))*8)
+#define ceil64(a) (a|0x3F)
+#define ceilXres(a,xres) (a|(xres - 1))
+
+/* ks108 chipset specific defines and code */
+
+#define KS_SET_DPY_START_LINE 0xC0
+#define KS_SET_PAGE_NUM 0xB8
+#define KS_SET_X 0x40
+#define KS_CEHI 0x01
+#define KS_CELO 0x00
+#define KS_SEL_CMD 0x08
+#define KS_SEL_DATA 0x00
+#define KS_DPY_ON 0x3F
+#define KS_DPY_OFF 0x3E
+#define KS_INTACK 0x40
+#define KS_CLRINT 0x02
+
+struct arcfb_par {
+ unsigned long dio_addr;
+ unsigned long cio_addr;
+ unsigned long c2io_addr;
+ atomic_t ref_count;
+ unsigned char cslut[9];
+ struct fb_info *info;
+ unsigned int irq;
+ spinlock_t lock;
+};
+
+static struct fb_fix_screeninfo arcfb_fix __initdata = {
+ .id = "arcfb",
+ .type = FB_TYPE_PACKED_PIXELS,
+ .visual = FB_VISUAL_MONO01,
+ .xpanstep = 0,
+ .ypanstep = 1,
+ .ywrapstep = 0,
+ .accel = FB_ACCEL_NONE,
+};
+
+static struct fb_var_screeninfo arcfb_var __initdata = {
+ .xres = 128,
+ .yres = 64,
+ .xres_virtual = 128,
+ .yres_virtual = 64,
+ .bits_per_pixel = 1,
+ .nonstd = 1,
+};
+
+static unsigned long num_cols;
+static unsigned long num_rows;
+static unsigned long dio_addr;
+static unsigned long cio_addr;
+static unsigned long c2io_addr;
+static unsigned long splashval;
+static unsigned long tuhold;
+static unsigned int nosplash;
+static unsigned int arcfb_enable;
+static unsigned int irq;
+
+static DECLARE_WAIT_QUEUE_HEAD(arcfb_waitq);
+
+static void ks108_writeb_ctl(struct arcfb_par *par,
+ unsigned int chipindex, unsigned char value)
+{
+ unsigned char chipselval = par->cslut[chipindex];
+
+ outb(chipselval|KS_CEHI|KS_SEL_CMD, par->cio_addr);
+ outb(value, par->dio_addr);
+ udelay(tuhold);
+ outb(chipselval|KS_CELO|KS_SEL_CMD, par->cio_addr);
+}
+
+static void ks108_writeb_mainctl(struct arcfb_par *par, unsigned char value)
+{
+
+ outb(value, par->cio_addr);
+ udelay(tuhold);
+}
+
+static unsigned char ks108_readb_ctl2(struct arcfb_par *par)
+{
+ return inb(par->c2io_addr);
+}
+
+static void ks108_writeb_data(struct arcfb_par *par,
+ unsigned int chipindex, unsigned char value)
+{
+ unsigned char chipselval = par->cslut[chipindex];
+
+ outb(chipselval|KS_CEHI|KS_SEL_DATA, par->cio_addr);
+ outb(value, par->dio_addr);
+ udelay(tuhold);
+ outb(chipselval|KS_CELO|KS_SEL_DATA, par->cio_addr);
+}
+
+static void ks108_set_start_line(struct arcfb_par *par,
+ unsigned int chipindex, unsigned char y)
+{
+ ks108_writeb_ctl(par, chipindex, KS_SET_DPY_START_LINE|y);
+}
+
+static void ks108_set_yaddr(struct arcfb_par *par,
+ unsigned int chipindex, unsigned char y)
+{
+ ks108_writeb_ctl(par, chipindex, KS_SET_PAGE_NUM|y);
+}
+
+static void ks108_set_xaddr(struct arcfb_par *par,
+ unsigned int chipindex, unsigned char x)
+{
+ ks108_writeb_ctl(par, chipindex, KS_SET_X|x);
+}
+
+static void ks108_clear_lcd(struct arcfb_par *par, unsigned int chipindex)
+{
+ int i,j;
+
+ for (i = 0; i <= 8; i++) {
+ ks108_set_yaddr(par, chipindex, i);
+ ks108_set_xaddr(par, chipindex, 0);
+ for (j = 0; j < 64; j++) {
+ ks108_writeb_data(par, chipindex,
+ (unsigned char) splashval);
+ }
+ }
+}
+
+/* main arcfb functions */
+
+static int arcfb_open(struct fb_info *info, int user)
+{
+ struct arcfb_par *par = info->par;
+
+ atomic_inc(&par->ref_count);
+ return 0;
+}
+
+static int arcfb_release(struct fb_info *info, int user)
+{
+ struct arcfb_par *par = info->par;
+ int count = atomic_read(&par->ref_count);
+
+ if (!count)
+ return -EINVAL;
+ atomic_dec(&par->ref_count);
+ return 0;
+}
+
+static int arcfb_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ int i;
+ struct arcfb_par *par = info->par;
+
+ if ((var->vmode & FB_VMODE_YWRAP) && (var->yoffset < 64)
+ && (info->var.yres <= 64)) {
+ for (i = 0; i < num_cols; i++) {
+ ks108_set_start_line(par, i, var->yoffset);
+ }
+ info->var.yoffset = var->yoffset;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static irqreturn_t arcfb_interrupt(int vec, void *dev_instance,
+ struct pt_regs *regs)
+{
+ struct fb_info *info = dev_instance;
+ unsigned char ctl2status;
+ struct arcfb_par *par = info->par;
+
+ ctl2status = ks108_readb_ctl2(par);
+
+ if (!(ctl2status & KS_INTACK)) /* not arc generated interrupt */
+ return IRQ_NONE;
+
+ ks108_writeb_mainctl(par, KS_CLRINT);
+
+ spin_lock(&par->lock);
+ if (waitqueue_active(&arcfb_waitq)) {
+ wake_up(&arcfb_waitq);
+ }
+ spin_unlock(&par->lock);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * here we handle a specific page on the lcd. the complexity comes from
+ * the fact that the fb is laidout in 8xX vertical columns. we extract
+ * each write of 8 vertical pixels. then we shift out as we move along
+ * X. That's what rightshift does. bitmask selects the desired input bit.
+ */
+static void arcfb_lcd_update_page(struct arcfb_par *par, unsigned int upper,
+ unsigned int left, unsigned int right, unsigned int distance)
+{
+ unsigned char *src;
+ unsigned int xindex, yindex, chipindex, linesize;
+ int i, count;
+ unsigned char val;
+ unsigned char bitmask, rightshift;
+
+ xindex = left >> 6;
+ yindex = upper >> 6;
+ chipindex = (xindex + (yindex*num_cols));
+
+ ks108_set_yaddr(par, chipindex, upper/8);
+
+ linesize = par->info->var.xres/8;
+ src = par->info->screen_base + (left/8) + (upper * linesize);
+ ks108_set_xaddr(par, chipindex, left);
+
+ bitmask=1;
+ rightshift=0;
+ while (left <= right) {
+ val = 0;
+ for (i = 0; i < 8; i++) {
+ if ( i > rightshift) {
+ val |= (*(src + (i*linesize)) & bitmask)
+ << (i - rightshift);
+ } else {
+ val |= (*(src + (i*linesize)) & bitmask)
+ >> (rightshift - i);
+ }
+ }
+ ks108_writeb_data(par, chipindex, val);
+ left++;
+ count++;
+ if (bitmask == 0x80) {
+ bitmask = 1;
+ src++;
+ rightshift=0;
+ } else {
+ bitmask <<= 1;
+ rightshift++;
+ }
+ }
+}
+
+/*
+ * here we handle the entire vertical page of the update. we write across
+ * lcd chips. update_page uses the upper/left values to decide which
+ * chip to select for the right. upper is needed for setting the page
+ * desired for the write.
+ */
+static void arcfb_lcd_update_vert(struct arcfb_par *par, unsigned int top,
+ unsigned int bottom, unsigned int left, unsigned int right)
+{
+ unsigned int distance, upper, lower;
+
+ distance = (bottom - top) + 1;
+ upper = top;
+ lower = top + 7;
+
+ while (distance > 0) {
+ distance -= 8;
+ arcfb_lcd_update_page(par, upper, left, right, 8);
+ upper = lower + 1;
+ lower = upper + 7;
+ }
+}
+
+/*
+ * here we handle horizontal blocks for the update. update_vert will
+ * handle spaning multiple pages. we break out each horizontal
+ * block in to individual blocks no taller than 64 pixels.
+ */
+static void arcfb_lcd_update_horiz(struct arcfb_par *par, unsigned int left,
+ unsigned int right, unsigned int top, unsigned int h)
+{
+ unsigned int distance, upper, lower;
+
+ distance = h;
+ upper = floor8(top);
+ lower = min(upper + distance - 1, ceil64(upper));
+
+ while (distance > 0) {
+ distance -= ((lower - upper) + 1 );
+ arcfb_lcd_update_vert(par, upper, lower, left, right);
+ upper = lower + 1;
+ lower = min(upper + distance - 1, ceil64(upper));
+ }
+}
+
+/*
+ * here we start the process of spliting out the fb update into
+ * individual blocks of pixels. we end up spliting into 64x64 blocks
+ * and finally down to 64x8 pages.
+ */
+static void arcfb_lcd_update(struct arcfb_par *par, unsigned int dx,
+ unsigned int dy, unsigned int w, unsigned int h)
+{
+ unsigned int left, right, distance, y;
+
+ /* align the request first */
+ y = floor8(dy);
+ h += dy - y;
+ h = iceil8(h);
+
+ distance = w;
+ left = dx;
+ right = min(left + w - 1, ceil64(left));
+
+ while (distance > 0) {
+ arcfb_lcd_update_horiz(par, left, right, y, h);
+ distance -= ((right - left) + 1);
+ left = right + 1;
+ right = min(left + distance - 1, ceil64(left));
+ }
+}
+
+void arcfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+ struct arcfb_par *par = info->par;
+
+ cfb_fillrect(info, rect);
+
+ /* update the physical lcd */
+ arcfb_lcd_update(par, rect->dx, rect->dy, rect->width, rect->height);
+}
+
+void arcfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
+{
+ struct arcfb_par *par = info->par;
+
+ cfb_copyarea(info, area);
+
+ /* update the physical lcd */
+ arcfb_lcd_update(par, area->dx, area->dy, area->width, area->height);
+}
+
+void arcfb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+ struct arcfb_par *par = info->par;
+
+ cfb_imageblit(info, image);
+
+ /* update the physical lcd */
+ arcfb_lcd_update(par, image->dx, image->dy, image->width,
+ image->height);
+}
+
+static int arcfb_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg,
+ struct fb_info *info)
+{
+ void __user *argp = (void __user *)arg;
+ struct arcfb_par *par = info->par;
+ unsigned long flags;
+
+ switch (cmd) {
+ case FBIO_WAITEVENT:
+ {
+ DEFINE_WAIT(wait);
+ /* illegal to wait on arc if no irq will occur */
+ if (!par->irq)
+ return -EINVAL;
+
+ /* wait until the Arc has generated an interrupt
+ * which will wake us up */
+ spin_lock_irqsave(&par->lock, flags);
+ prepare_to_wait(&arcfb_waitq, &wait,
+ TASK_INTERRUPTIBLE);
+ spin_unlock_irqrestore(&par->lock, flags);
+ schedule();
+ finish_wait(&arcfb_waitq, &wait);
+ }
+ case FBIO_GETCONTROL2:
+ {
+ unsigned char ctl2;
+
+ ctl2 = ks108_readb_ctl2(info->par);
+ if (copy_to_user(argp, &ctl2, sizeof(ctl2)))
+ return -EFAULT;
+ return 0;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+/*
+ * this is the access path from userspace. they can seek and write to
+ * the fb. it's inefficient for them to do anything less than 64*8
+ * writes since we update the lcd in each write() anyway.
+ */
+static ssize_t arcfb_write(struct file *file, const char *buf, size_t count,
+ loff_t *ppos)
+{
+ /* modded from epson 1355 */
+
+ struct inode *inode;
+ int fbidx;
+ struct fb_info *info;
+ unsigned long p;
+ int err=-EINVAL;
+ unsigned int fbmemlength,x,y,w,h, bitppos, startpos, endpos, bitcount;
+ struct arcfb_par *par;
+ unsigned int xres;
+
+ p = *ppos;
+ inode = file->f_dentry->d_inode;
+ fbidx = iminor(inode);
+ info = registered_fb[fbidx];
+ par = info->par;
+
+ if (!info || !info->screen_base)
+ return -ENODEV;
+
+ xres = info->var.xres;
+ fbmemlength = (xres * info->var.yres)/8;
+
+ if (p > fbmemlength)
+ return -ENOSPC;
+
+ err = 0;
+ if ((count + p) > fbmemlength) {
+ count = fbmemlength - p;
+ err = -ENOSPC;
+ }
+
+ if (count) {
+ char *base_addr;
+
+ base_addr = info->screen_base;
+ count -= copy_from_user(base_addr + p, buf, count);
+ *ppos += count;
+ err = -EFAULT;
+ }
+
+
+ bitppos = p*8;
+ startpos = floorXres(bitppos, xres);
+ endpos = ceilXres((bitppos + (count*8)), xres);
+ bitcount = endpos - startpos;
+
+ x = startpos % xres;
+ y = startpos / xres;
+ w = xres;
+ h = bitcount / xres;
+ arcfb_lcd_update(par, x, y, w, h);
+
+ if (count)
+ return count;
+ return err;
+}
+
+static void arcfb_platform_release(struct device *device)
+{
+}
+
+static struct fb_ops arcfb_ops = {
+ .owner = THIS_MODULE,
+ .fb_open = arcfb_open,
+ .fb_write = arcfb_write,
+ .fb_release = arcfb_release,
+ .fb_pan_display = arcfb_pan_display,
+ .fb_fillrect = arcfb_fillrect,
+ .fb_copyarea = arcfb_copyarea,
+ .fb_imageblit = arcfb_imageblit,
+ .fb_cursor = soft_cursor,
+ .fb_ioctl = arcfb_ioctl,
+};
+
+static int __init arcfb_probe(struct device *device)
+{
+ struct platform_device *dev = to_platform_device(device);
+ struct fb_info *info;
+ int retval = -ENOMEM;
+ int videomemorysize;
+ unsigned char *videomemory;
+ struct arcfb_par *par;
+ int i;
+
+ videomemorysize = (((64*64)*num_cols)*num_rows)/8;
+
+ /* We need a flat backing store for the Arc's
+ less-flat actual paged framebuffer */
+ if (!(videomemory = vmalloc(videomemorysize)))
+ return retval;
+
+ memset(videomemory, 0, videomemorysize);
+
+ info = framebuffer_alloc(sizeof(struct arcfb_par), &dev->dev);
+ if (!info)
+ goto err;
+
+ info->screen_base = (char __iomem *)videomemory;
+ info->fbops = &arcfb_ops;
+
+ info->var = arcfb_var;
+ info->fix = arcfb_fix;
+ par = info->par;
+ par->info = info;
+
+ if (!dio_addr || !cio_addr || !c2io_addr) {
+ printk(KERN_WARNING "no IO addresses supplied\n");
+ goto err1;
+ }
+ par->dio_addr = dio_addr;
+ par->cio_addr = cio_addr;
+ par->c2io_addr = c2io_addr;
+ par->cslut[0] = 0x00;
+ par->cslut[1] = 0x06;
+ info->flags = FBINFO_FLAG_DEFAULT;
+ spin_lock_init(&par->lock);
+ retval = register_framebuffer(info);
+ if (retval < 0)
+ goto err1;
+ dev_set_drvdata(&dev->dev, info);
+ if (irq) {
+ par->irq = irq;
+ if (request_irq(par->irq, &arcfb_interrupt, SA_SHIRQ,
+ "arcfb", info)) {
+ printk(KERN_INFO
+ "arcfb: Failed req IRQ %d\n", par->irq);
+ goto err1;
+ }
+ }
+ printk(KERN_INFO
+ "fb%d: Arc frame buffer device, using %dK of video memory\n",
+ info->node, videomemorysize >> 10);
+
+ /* this inits the lcd but doesn't clear dirty pixels */
+ for (i = 0; i < num_cols * num_rows; i++) {
+ ks108_writeb_ctl(par, i, KS_DPY_OFF);
+ ks108_set_start_line(par, i, 0);
+ ks108_set_yaddr(par, i, 0);
+ ks108_set_xaddr(par, i, 0);
+ ks108_writeb_ctl(par, i, KS_DPY_ON);
+ }
+
+ /* if we were told to splash the screen, we just clear it */
+ if (!nosplash) {
+ for (i = 0; i < num_cols * num_rows; i++) {
+ printk(KERN_INFO "fb%d: splashing lcd %d\n",
+ info->node, i);
+ ks108_set_start_line(par, i, 0);
+ ks108_clear_lcd(par, i);
+ }
+ }
+
+ return 0;
+err1:
+ framebuffer_release(info);
+err:
+ vfree(videomemory);
+ return retval;
+}
+
+static int arcfb_remove(struct device *device)
+{
+ struct fb_info *info = dev_get_drvdata(device);
+
+ if (info) {
+ unregister_framebuffer(info);
+ vfree(info->screen_base);
+ framebuffer_release(info);
+ }
+ return 0;
+}
+
+static struct device_driver arcfb_driver = {
+ .name = "arcfb",
+ .bus = &platform_bus_type,
+ .probe = arcfb_probe,
+ .remove = arcfb_remove,
+};
+
+static struct platform_device arcfb_device = {
+ .name = "arcfb",
+ .id = 0,
+ .dev = {
+ .release = arcfb_platform_release,
+ }
+};
+
+static int __init arcfb_init(void)
+{
+ int ret;
+
+ if (!arcfb_enable)
+ return -ENXIO;
+
+ ret = driver_register(&arcfb_driver);
+ if (!ret) {
+ ret = platform_device_register(&arcfb_device);
+ if (ret)
+ driver_unregister(&arcfb_driver);
+ }
+ return ret;
+
+}
+
+static void __exit arcfb_exit(void)
+{
+ platform_device_unregister(&arcfb_device);
+ driver_unregister(&arcfb_driver);
+}
+
+module_param(num_cols, ulong, 0);
+MODULE_PARM_DESC(num_cols, "Num horiz panels, eg: 2 = 128 bit wide");
+module_param(num_rows, ulong, 0);
+MODULE_PARM_DESC(num_rows, "Num vert panels, eg: 1 = 64 bit high");
+module_param(nosplash, uint, 0);
+MODULE_PARM_DESC(nosplash, "Disable doing the splash screen");
+module_param(arcfb_enable, uint, 0);
+MODULE_PARM_DESC(arcfb_enable, "Enable communication with Arc board");
+module_param(dio_addr, ulong, 0);
+MODULE_PARM_DESC(dio_addr, "IO address for data, eg: 0x480");
+module_param(cio_addr, ulong, 0);
+MODULE_PARM_DESC(cio_addr, "IO address for control, eg: 0x400");
+module_param(c2io_addr, ulong, 0);
+MODULE_PARM_DESC(c2io_addr, "IO address for secondary control, eg: 0x408");
+module_param(splashval, ulong, 0);
+MODULE_PARM_DESC(splashval, "Splash pattern: 0xFF is black, 0x00 is green");
+module_param(tuhold, ulong, 0);
+MODULE_PARM_DESC(tuhold, "Time to hold between strobing data to Arc board");
+module_param(irq, uint, 0);
+MODULE_PARM_DESC(irq, "IRQ for the Arc board");
+
+module_init(arcfb_init);
+module_exit(arcfb_exit);
+
+MODULE_DESCRIPTION("fbdev driver for Arc monochrome LCD board");
+MODULE_AUTHOR("Jaya Kumar");
+MODULE_LICENSE("GPL");
+
pmu_register_sleep_notifier(&chips_sleep_notifier);
#endif /* CONFIG_PMAC_PBOOK */
- /* Clear the entire framebuffer */
- memset(p->screen_base, 0, 0x100000);
-
pci_set_drvdata(dp, p);
return 0;
}
Small console font with Macintosh-style high-half glyphs. Some Mac
framebuffer drivers don't support this one at all.
+config FONT_7x14
+ bool "console 7x14 font (not supported by all drivers)" if FONTS
+ depends on FRAMEBUFFER_CONSOLE
+ default y if !SPARC32 && !SPARC64 && !FONTS
+ help
+ Console font with characters just a bit smaller than the default.
+ If the standard 8x16 font is a little too big for you, say Y.
+ Otherwise, say N.
+
config FONT_PEARL_8x8
bool "Pearl (old m68k) console 8x8 font" if FONTS
depends on FRAMEBUFFER_CONSOLE
big letters (like the letters used in the SPARC PROM). If the
standard font is unreadable for you, say Y, otherwise say N.
+config FONT_10x18
+ bool "console 10x18 font (not supported by all drivers)"
+ depends on FONTS
+ help
+ This is a high resolution console font for machines with very
+ big letters. It fits between the sun 12x22 and the normal 8x16 font.
+ If other fonts are too big or too small for you, say Y, otherwise say N.
+
endmenu
font-objs-$(CONFIG_FONT_8x8) += font_8x8.o
font-objs-$(CONFIG_FONT_8x16) += font_8x16.o
font-objs-$(CONFIG_FONT_6x11) += font_6x11.o
+font-objs-$(CONFIG_FONT_7x14) += font_7x14.o
+font-objs-$(CONFIG_FONT_10x18) += font_10x18.o
font-objs-$(CONFIG_FONT_PEARL_8x8) += font_pearl_8x8.o
font-objs-$(CONFIG_FONT_ACORN_8x8) += font_acorn_8x8.o
font-objs-$(CONFIG_FONT_MINI_4x6) += font_mini_4x6.o
const unsigned short *s, int count, int yy, int xx,
int fg, int bg)
{
- void (*move_unaligned)(struct fb_info *info, struct fb_pixmap *buf,
- u8 *dst, u32 d_pitch, u8 *src, u32 idx,
- u32 height, u32 shift_high, u32 shift_low,
- u32 mod);
- void (*move_aligned)(struct fb_info *info, struct fb_pixmap *buf,
- u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch,
- u32 height);
unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
unsigned int width = (vc->vc_font.width + 7) >> 3;
unsigned int cellsize = vc->vc_font.height * width;
image.height = vc->vc_font.height;
image.depth = 1;
- if (info->pixmap.outbuf && info->pixmap.inbuf) {
- move_aligned = fb_iomove_buf_aligned;
- move_unaligned = fb_iomove_buf_unaligned;
- } else {
- move_aligned = fb_sysmove_buf_aligned;
- move_unaligned = fb_sysmove_buf_unaligned;
- }
while (count) {
if (count > maxcnt)
cnt = k = maxcnt;
src = buf;
}
- move_unaligned(info, &info->pixmap, dst, pitch,
- src, idx, image.height,
- shift_high, shift_low, mod);
+ fb_pad_unaligned_buffer(dst, pitch, src, idx,
+ image.height, shift_high,
+ shift_low, mod);
shift_low += mod;
dst += (shift_low >= 8) ? width : width - 1;
shift_low &= 7;
src = buf;
}
- move_aligned(info, &info->pixmap, dst, pitch,
- src, idx, image.height);
+ fb_pad_aligned_buffer(dst, pitch, src, idx, image.height);
dst += width;
}
}
--- /dev/null
+/********************************
+ * adapted from font_sun12x22.c *
+ * by Jurriaan Kalkman 06-2005 *
+ ********************************/
+
+#include <linux/font.h>
+
+#define FONTDATAMAX 9216
+
+static unsigned char fontdata_10x18[FONTDATAMAX] = {
+
+ /* 0 0x00 '^@' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 1 0x01 '^A' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x3f, 0x80, /* 0011111110 */
+ 0x40, 0x40, /* 0100000001 */
+ 0x5b, 0x40, /* 0101101101 */
+ 0x40, 0x40, /* 0100000001 */
+ 0x44, 0x40, /* 0100010001 */
+ 0x44, 0x40, /* 0100010001 */
+ 0x51, 0x40, /* 0101000101 */
+ 0x4e, 0x40, /* 0100111001 */
+ 0x40, 0x40, /* 0100000001 */
+ 0x3f, 0x80, /* 0011111110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 2 0x02 '^B' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x3f, 0x80, /* 0011111110 */
+ 0x7f, 0xc0, /* 0111111111 */
+ 0x64, 0xc0, /* 0110010011 */
+ 0x7f, 0xc0, /* 0111111111 */
+ 0x7b, 0xc0, /* 0111101111 */
+ 0x7b, 0xc0, /* 0111101111 */
+ 0x6e, 0xc0, /* 0110111011 */
+ 0x71, 0xc0, /* 0111000111 */
+ 0x7f, 0xc0, /* 0111111111 */
+ 0x3f, 0x80, /* 0011111110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 3 0x03 '^C' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x11, 0x00, /* 0001000100 */
+ 0x3b, 0x80, /* 0011101110 */
+ 0x7f, 0xc0, /* 0111111111 */
+ 0x3f, 0x80, /* 0011111110 */
+ 0x3f, 0x80, /* 0011111110 */
+ 0x1f, 0x00, /* 0001111100 */
+ 0x1f, 0x00, /* 0001111100 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x04, 0x00, /* 0000010000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 4 0x04 '^D' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x04, 0x00, /* 0000010000 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x1f, 0x00, /* 0001111100 */
+ 0x1f, 0x00, /* 0001111100 */
+ 0x3f, 0x80, /* 0011111110 */
+ 0x1f, 0x00, /* 0001111100 */
+ 0x1f, 0x00, /* 0001111100 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x04, 0x00, /* 0000010000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 5 0x05 '^E' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x7b, 0xc0, /* 0111101111 */
+ 0x35, 0x80, /* 0011010110 */
+ 0x04, 0x00, /* 0000010000 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x1f, 0x00, /* 0001111100 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 6 0x06 '^F' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x04, 0x00, /* 0000010000 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x1f, 0x00, /* 0001111100 */
+ 0x1f, 0x00, /* 0001111100 */
+ 0x3f, 0x80, /* 0011111110 */
+ 0x7f, 0xc0, /* 0111111111 */
+ 0x7f, 0xc0, /* 0111111111 */
+ 0x35, 0x80, /* 0011010110 */
+ 0x04, 0x00, /* 0000010000 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x1f, 0x00, /* 0001111100 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 7 0x07 '^G' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 8 0x08 '^H' */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xf3, 0xc0, /* 1111001111 */
+ 0xe1, 0xc0, /* 1110000111 */
+ 0xe1, 0xc0, /* 1110000111 */
+ 0xc0, 0xc0, /* 1100000011 */
+ 0xc0, 0xc0, /* 1100000011 */
+ 0xe1, 0xc0, /* 1110000111 */
+ 0xe1, 0xc0, /* 1110000111 */
+ 0xf3, 0xc0, /* 1111001111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+
+ /* 9 0x09 '^I' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x12, 0x00, /* 0001001000 */
+ 0x12, 0x00, /* 0001001000 */
+ 0x21, 0x00, /* 0010000100 */
+ 0x21, 0x00, /* 0010000100 */
+ 0x12, 0x00, /* 0001001000 */
+ 0x12, 0x00, /* 0001001000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 10 0x0a '^J' */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xf3, 0xc0, /* 1111001111 */
+ 0xed, 0xc0, /* 1110110111 */
+ 0xed, 0xc0, /* 1110110111 */
+ 0xde, 0xc0, /* 1101111011 */
+ 0xde, 0xc0, /* 1101111011 */
+ 0xed, 0xc0, /* 1110110111 */
+ 0xed, 0xc0, /* 1110110111 */
+ 0xf3, 0xc0, /* 1111001111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+
+ /* 11 0x0b '^K' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0f, 0xc0, /* 0000111111 */
+ 0x0f, 0xc0, /* 0000111111 */
+ 0x03, 0xc0, /* 0000001111 */
+ 0x06, 0xc0, /* 0000011011 */
+ 0x0c, 0xc0, /* 0000110011 */
+ 0x3c, 0x00, /* 0011110000 */
+ 0x66, 0x00, /* 0110011000 */
+ 0xc3, 0x00, /* 1100001100 */
+ 0xc3, 0x00, /* 1100001100 */
+ 0xc3, 0x00, /* 1100001100 */
+ 0x66, 0x00, /* 0110011000 */
+ 0x3c, 0x00, /* 0011110000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 12 0x0c '^L' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 13 0x0d '^M' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0f, 0x80, /* 0000111110 */
+ 0x08, 0x80, /* 0000100010 */
+ 0x0f, 0x80, /* 0000111110 */
+ 0x08, 0x00, /* 0000100000 */
+ 0x08, 0x00, /* 0000100000 */
+ 0x08, 0x00, /* 0000100000 */
+ 0x08, 0x00, /* 0000100000 */
+ 0x08, 0x00, /* 0000100000 */
+ 0x08, 0x00, /* 0000100000 */
+ 0x38, 0x00, /* 0011100000 */
+ 0x78, 0x00, /* 0111100000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 14 0x0e '^N' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x1f, 0x80, /* 0001111110 */
+ 0x10, 0x80, /* 0001000010 */
+ 0x1f, 0x80, /* 0001111110 */
+ 0x10, 0x80, /* 0001000010 */
+ 0x10, 0x80, /* 0001000010 */
+ 0x10, 0x80, /* 0001000010 */
+ 0x10, 0x80, /* 0001000010 */
+ 0x13, 0x80, /* 0001001110 */
+ 0x17, 0x80, /* 0001011110 */
+ 0x73, 0x00, /* 0111001100 */
+ 0xf0, 0x00, /* 1111000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 15 0x0f '^O' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x04, 0x00, /* 0000010000 */
+ 0x24, 0x80, /* 0010010010 */
+ 0x15, 0x00, /* 0001010100 */
+ 0x55, 0x40, /* 0101010101 */
+ 0x3f, 0x80, /* 0011111110 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x3f, 0x80, /* 0011111110 */
+ 0x55, 0x40, /* 0101010101 */
+ 0x15, 0x00, /* 0001010100 */
+ 0x24, 0x80, /* 0010010010 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 16 0x10 '^P' */
+ 0x00, 0x80, /* 0000000010 */
+ 0x01, 0x80, /* 0000000110 */
+ 0x03, 0x80, /* 0000001110 */
+ 0x07, 0x80, /* 0000011110 */
+ 0x0f, 0x80, /* 0000111110 */
+ 0x1f, 0x80, /* 0001111110 */
+ 0x3f, 0x80, /* 0011111110 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0xff, 0x80, /* 1111111110 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x3f, 0x80, /* 0011111110 */
+ 0x1f, 0x80, /* 0001111110 */
+ 0x0f, 0x80, /* 0000111110 */
+ 0x07, 0x80, /* 0000011110 */
+ 0x03, 0x80, /* 0000001110 */
+ 0x01, 0x80, /* 0000000110 */
+ 0x00, 0x80, /* 0000000010 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 17 0x11 '^Q' */
+ 0x40, 0x00, /* 0100000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x70, 0x00, /* 0111000000 */
+ 0x78, 0x00, /* 0111100000 */
+ 0x7c, 0x00, /* 0111110000 */
+ 0x7e, 0x00, /* 0111111000 */
+ 0x7f, 0x00, /* 0111111100 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x7f, 0xc0, /* 0111111111 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x7f, 0x00, /* 0111111100 */
+ 0x7e, 0x00, /* 0111111000 */
+ 0x7c, 0x00, /* 0111110000 */
+ 0x78, 0x00, /* 0111100000 */
+ 0x70, 0x00, /* 0111000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x40, 0x00, /* 0100000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 18 0x12 '^R' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 19 0x13 '^S' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 20 0x14 '^T' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x1f, 0xc0, /* 0001111111 */
+ 0x39, 0x80, /* 0011100110 */
+ 0x79, 0x80, /* 0111100110 */
+ 0x79, 0x80, /* 0111100110 */
+ 0x79, 0x80, /* 0111100110 */
+ 0x39, 0x80, /* 0011100110 */
+ 0x19, 0x80, /* 0001100110 */
+ 0x19, 0x80, /* 0001100110 */
+ 0x19, 0x80, /* 0001100110 */
+ 0x19, 0x80, /* 0001100110 */
+ 0x19, 0x80, /* 0001100110 */
+ 0x19, 0x80, /* 0001100110 */
+ 0x39, 0xc0, /* 0011100111 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 21 0x15 '^U' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x3e, 0x00, /* 0011111000 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x3e, 0x00, /* 0011111000 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x3e, 0x00, /* 0011111000 */
+ 0x03, 0x00, /* 0000001100 */
+ 0x03, 0x00, /* 0000001100 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x3e, 0x00, /* 0011111000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 22 0x16 '^V' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 23 0x17 '^W' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 24 0x18 '^X' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 25 0x19 '^Y' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 26 0x1a '^Z' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x04, 0x00, /* 0000010000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x07, 0x00, /* 0000011100 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x07, 0x00, /* 0000011100 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x04, 0x00, /* 0000010000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 27 0x1b '^[' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x08, 0x00, /* 0000100000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x38, 0x00, /* 0011100000 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x38, 0x00, /* 0011100000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x08, 0x00, /* 0000100000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 28 0x1c '^\' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 29 0x1d '^]' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x12, 0x00, /* 0001001000 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x73, 0x80, /* 0111001110 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0x73, 0x80, /* 0111001110 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x12, 0x00, /* 0001001000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 30 0x1e '^^' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x04, 0x00, /* 0000010000 */
+ 0x04, 0x00, /* 0000010000 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x1f, 0x00, /* 0001111100 */
+ 0x1f, 0x00, /* 0001111100 */
+ 0x3f, 0x80, /* 0011111110 */
+ 0x3f, 0x80, /* 0011111110 */
+ 0x7f, 0xc0, /* 0111111111 */
+ 0x7f, 0xc0, /* 0111111111 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 31 0x1f '^_' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x7f, 0xc0, /* 0111111111 */
+ 0x7f, 0xc0, /* 0111111111 */
+ 0x3f, 0x80, /* 0011111110 */
+ 0x3f, 0x80, /* 0011111110 */
+ 0x1f, 0x00, /* 0001111100 */
+ 0x1f, 0x00, /* 0001111100 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x04, 0x00, /* 0000010000 */
+ 0x04, 0x00, /* 0000010000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 32 0x20 ' ' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 33 0x21 '!' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 34 0x22 '"' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x63, 0x00, /* 0110001100 */
+ 0xf7, 0x80, /* 1111011110 */
+ 0xf7, 0x80, /* 1111011110 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x42, 0x00, /* 0100001000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 35 0x23 '#' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 36 0x24 '$' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x3e, 0x00, /* 0011111000 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x6f, 0x80, /* 0110111110 */
+ 0x6d, 0x80, /* 0110110110 */
+ 0x6c, 0x80, /* 0110110010 */
+ 0x3c, 0x00, /* 0011110000 */
+ 0x0f, 0x00, /* 0000111100 */
+ 0x0d, 0x80, /* 0000110110 */
+ 0x4d, 0x80, /* 0100110110 */
+ 0x6d, 0x80, /* 0110110110 */
+ 0x7f, 0x00, /* 0111111100 */
+ 0x3e, 0x00, /* 0011111000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 37 0x25 '%' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x7b, 0x00, /* 0111101100 */
+ 0x7b, 0x00, /* 0111101100 */
+ 0x36, 0x00, /* 0011011000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x37, 0x80, /* 0011011110 */
+ 0x37, 0x80, /* 0011011110 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 38 0x26 '&' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x07, 0x00, /* 0000011100 */
+ 0x0f, 0x80, /* 0000111110 */
+ 0x19, 0x80, /* 0001100110 */
+ 0x19, 0x80, /* 0001100110 */
+ 0x0f, 0x80, /* 0000111110 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x3e, 0x00, /* 0011111000 */
+ 0x76, 0x00, /* 0111011000 */
+ 0x66, 0x40, /* 0110011001 */
+ 0x63, 0xc0, /* 0110001111 */
+ 0x63, 0x80, /* 0110001110 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x3f, 0x80, /* 0011111110 */
+ 0x1c, 0xc0, /* 0001110011 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 39 0x27 ''' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x78, 0x00, /* 0111100000 */
+ 0x78, 0x00, /* 0111100000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x20, 0x00, /* 0010000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 40 0x28 '(' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x03, 0x00, /* 0000001100 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x03, 0x00, /* 0000001100 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 41 0x29 ')' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 42 0x2a '*' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x4c, 0x80, /* 0100110010 */
+ 0x6d, 0x80, /* 0110110110 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x6d, 0x80, /* 0110110110 */
+ 0x4c, 0x80, /* 0100110010 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 43 0x2b '+' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 44 0x2c ',' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x78, 0x00, /* 0111100000 */
+ 0x78, 0x00, /* 0111100000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x40, 0x00, /* 0100000000 */
+
+ /* 45 0x2d '-' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 46 0x2e '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x3c, 0x00, /* 0011110000 */
+ 0x3c, 0x00, /* 0011110000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 47 0x2f '/' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x01, 0x80, /* 0000000110 */
+ 0x01, 0x80, /* 0000000110 */
+ 0x03, 0x00, /* 0000001100 */
+ 0x03, 0x00, /* 0000001100 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 48 0x30 '0' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x1f, 0x00, /* 0001111100 */
+ 0x23, 0x00, /* 0010001100 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x63, 0x80, /* 0110001110 */
+ 0x65, 0x80, /* 0110010110 */
+ 0x65, 0x80, /* 0110010110 */
+ 0x69, 0x80, /* 0110100110 */
+ 0x69, 0x80, /* 0110100110 */
+ 0x71, 0x80, /* 0111000110 */
+ 0x61, 0x00, /* 0110000100 */
+ 0x31, 0x00, /* 0011000100 */
+ 0x3e, 0x00, /* 0011111000 */
+ 0x1c, 0x00, /* 0001110000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 49 0x31 '1' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x04, 0x00, /* 0000010000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x1c, 0x00, /* 0001110000 */
+ 0x3c, 0x00, /* 0011110000 */
+ 0x6c, 0x00, /* 0110110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 50 0x32 '2' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x63, 0x80, /* 0110001110 */
+ 0x41, 0x80, /* 0100000110 */
+ 0x01, 0x80, /* 0000000110 */
+ 0x01, 0x80, /* 0000000110 */
+ 0x03, 0x00, /* 0000001100 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x30, 0x80, /* 0011000010 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 51 0x33 '3' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x1c, 0x00, /* 0001110000 */
+ 0x3e, 0x00, /* 0011111000 */
+ 0x47, 0x00, /* 0100011100 */
+ 0x03, 0x00, /* 0000001100 */
+ 0x07, 0x00, /* 0000011100 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x07, 0x00, /* 0000011100 */
+ 0x03, 0x00, /* 0000001100 */
+ 0x01, 0x80, /* 0000000110 */
+ 0x41, 0x80, /* 0100000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 52 0x34 '4' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x36, 0x00, /* 0011011000 */
+ 0x36, 0x00, /* 0011011000 */
+ 0x66, 0x00, /* 0110011000 */
+ 0x66, 0x00, /* 0110011000 */
+ 0xc6, 0x00, /* 1100011000 */
+ 0xc6, 0x00, /* 1100011000 */
+ 0xff, 0x80, /* 1111111110 */
+ 0xff, 0x80, /* 1111111110 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 53 0x35 '5' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x1f, 0x00, /* 0001111100 */
+ 0x1f, 0x00, /* 0001111100 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x7e, 0x00, /* 0111111000 */
+ 0x67, 0x00, /* 0110011100 */
+ 0x03, 0x80, /* 0000001110 */
+ 0x01, 0x80, /* 0000000110 */
+ 0x01, 0x80, /* 0000000110 */
+ 0x01, 0x80, /* 0000000110 */
+ 0x41, 0x80, /* 0100000110 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x3e, 0x00, /* 0011111000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 54 0x36 '6' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x6e, 0x00, /* 0110111000 */
+ 0x7f, 0x00, /* 0111111100 */
+ 0x73, 0x80, /* 0111001110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x71, 0x00, /* 0111000100 */
+ 0x3e, 0x00, /* 0011111000 */
+ 0x1c, 0x00, /* 0001110000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 55 0x37 '7' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x1f, 0x80, /* 0001111110 */
+ 0x3f, 0x80, /* 0011111110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x01, 0x80, /* 0000000110 */
+ 0x03, 0x00, /* 0000001100 */
+ 0x03, 0x00, /* 0000001100 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 56 0x38 '8' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x23, 0x00, /* 0010001100 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x31, 0x00, /* 0011000100 */
+ 0x1a, 0x00, /* 0001101000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x16, 0x00, /* 0001011000 */
+ 0x23, 0x00, /* 0010001100 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x31, 0x00, /* 0011000100 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 57 0x39 '9' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x17, 0x00, /* 0001011100 */
+ 0x23, 0x80, /* 0010001110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x73, 0x80, /* 0111001110 */
+ 0x3d, 0x80, /* 0011110110 */
+ 0x19, 0x80, /* 0001100110 */
+ 0x01, 0x80, /* 0000000110 */
+ 0x03, 0x00, /* 0000001100 */
+ 0x03, 0x00, /* 0000001100 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 58 0x3a ':' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x3c, 0x00, /* 0011110000 */
+ 0x3c, 0x00, /* 0011110000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x3c, 0x00, /* 0011110000 */
+ 0x3c, 0x00, /* 0011110000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 59 0x3b ';' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x3c, 0x00, /* 0011110000 */
+ 0x3c, 0x00, /* 0011110000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x3c, 0x00, /* 0011110000 */
+ 0x3c, 0x00, /* 0011110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x20, 0x00, /* 0010000000 */
+
+ /* 60 0x3c '<' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x03, 0x00, /* 0000001100 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x03, 0x00, /* 0000001100 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 61 0x3d '=' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 62 0x3e '>' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x03, 0x00, /* 0000001100 */
+ 0x01, 0x80, /* 0000000110 */
+ 0x01, 0x80, /* 0000000110 */
+ 0x03, 0x00, /* 0000001100 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 63 0x3f '?' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x1f, 0x00, /* 0001111100 */
+ 0x3b, 0x80, /* 0011101110 */
+ 0x21, 0x80, /* 0010000110 */
+ 0x01, 0x80, /* 0000000110 */
+ 0x03, 0x00, /* 0000001100 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 64 0x40 '@' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x65, 0x80, /* 0110010110 */
+ 0x6d, 0x80, /* 0110110110 */
+ 0x6d, 0x80, /* 0110110110 */
+ 0x6d, 0x80, /* 0110110110 */
+ 0x6d, 0x80, /* 0110110110 */
+ 0x6f, 0x80, /* 0110111110 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x3f, 0x80, /* 0011111110 */
+ 0x0f, 0x00, /* 0000111100 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 65 0x41 'A' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x04, 0x00, /* 0000010000 */
+ 0x04, 0x00, /* 0000010000 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x19, 0x80, /* 0001100110 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x3f, 0x80, /* 0011111110 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x60, 0xc0, /* 0110000011 */
+ 0x60, 0xc0, /* 0110000011 */
+ 0xf1, 0xc0, /* 1111000111 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 66 0x42 'B' */
+ 0x00, 0x00, /* 0000000000 */
+ 0xfc, 0x00, /* 1111110000 */
+ 0x62, 0x00, /* 0110001000 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x66, 0x00, /* 0110011000 */
+ 0x7e, 0x00, /* 0111111000 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x63, 0x00, /* 0110001100 */
+ 0xfe, 0x00, /* 1111111000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 67 0x43 'C' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0f, 0x00, /* 0000111100 */
+ 0x11, 0x80, /* 0001000110 */
+ 0x20, 0x80, /* 0010000010 */
+ 0x20, 0x00, /* 0010000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x20, 0x00, /* 0010000000 */
+ 0x30, 0x80, /* 0011000010 */
+ 0x19, 0x00, /* 0001100100 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 68 0x44 'D' */
+ 0x00, 0x00, /* 0000000000 */
+ 0xfc, 0x00, /* 1111110000 */
+ 0x67, 0x00, /* 0110011100 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x00, /* 0110000100 */
+ 0x66, 0x00, /* 0110011000 */
+ 0xf8, 0x00, /* 1111100000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 69 0x45 'E' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x30, 0x80, /* 0011000010 */
+ 0x30, 0x80, /* 0011000010 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x31, 0x00, /* 0011000100 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x31, 0x00, /* 0011000100 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x80, /* 0011000010 */
+ 0x30, 0x80, /* 0011000010 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 70 0x46 'F' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x30, 0x80, /* 0011000010 */
+ 0x30, 0x80, /* 0011000010 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x31, 0x00, /* 0011000100 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x31, 0x00, /* 0011000100 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x78, 0x00, /* 0111100000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 71 0x47 'G' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0f, 0x00, /* 0000111100 */
+ 0x11, 0x80, /* 0001000110 */
+ 0x20, 0x80, /* 0010000010 */
+ 0x20, 0x00, /* 0010000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x67, 0xc0, /* 0110011111 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x21, 0x80, /* 0010000110 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x19, 0x80, /* 0001100110 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 72 0x48 'H' */
+ 0x00, 0x00, /* 0000000000 */
+ 0xf3, 0xc0, /* 1111001111 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0xf3, 0xc0, /* 1111001111 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 73 0x49 'I' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 74 0x4a 'J' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x08, 0x00, /* 0000100000 */
+ 0x70, 0x00, /* 0111000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 75 0x4b 'K' */
+ 0x00, 0x00, /* 0000000000 */
+ 0xf1, 0x80, /* 1111000110 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x66, 0x00, /* 0110011000 */
+ 0x6c, 0x00, /* 0110110000 */
+ 0x78, 0x00, /* 0111100000 */
+ 0x70, 0x00, /* 0111000000 */
+ 0x70, 0x00, /* 0111000000 */
+ 0x78, 0x00, /* 0111100000 */
+ 0x78, 0x00, /* 0111100000 */
+ 0x6c, 0x00, /* 0110110000 */
+ 0x66, 0x00, /* 0110011000 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x61, 0x80, /* 0110000110 */
+ 0xf0, 0xc0, /* 1111000011 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 76 0x4c 'L' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x78, 0x00, /* 0111100000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x80, /* 0011000010 */
+ 0x30, 0x80, /* 0011000010 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 77 0x4d 'M' */
+ 0x00, 0x00, /* 0000000000 */
+ 0xe0, 0xc0, /* 1110000011 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x73, 0x80, /* 0111001110 */
+ 0x73, 0x80, /* 0111001110 */
+ 0x6d, 0x80, /* 0110110110 */
+ 0x6d, 0x80, /* 0110110110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0xf3, 0xc0, /* 1111001111 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 78 0x4e 'N' */
+ 0x00, 0x00, /* 0000000000 */
+ 0xf3, 0xc0, /* 1111001111 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x71, 0x80, /* 0111000110 */
+ 0x79, 0x80, /* 0111100110 */
+ 0x79, 0x80, /* 0111100110 */
+ 0x6d, 0x80, /* 0110110110 */
+ 0x6d, 0x80, /* 0110110110 */
+ 0x67, 0x80, /* 0110011110 */
+ 0x67, 0x80, /* 0110011110 */
+ 0x63, 0x80, /* 0110001110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0xf3, 0xc0, /* 1111001111 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 79 0x4f 'O' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x17, 0x00, /* 0001011100 */
+ 0x23, 0x00, /* 0010001100 */
+ 0x21, 0x80, /* 0010000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x21, 0x00, /* 0010000100 */
+ 0x31, 0x00, /* 0011000100 */
+ 0x1a, 0x00, /* 0001101000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 80 0x50 'P' */
+ 0x00, 0x00, /* 0000000000 */
+ 0xfe, 0x00, /* 1111111000 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x7e, 0x00, /* 0111111000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0xf0, 0x00, /* 1111000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 81 0x51 'Q' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x13, 0x00, /* 0001001100 */
+ 0x23, 0x00, /* 0010001100 */
+ 0x21, 0x80, /* 0010000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x3b, 0x00, /* 0011101100 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x26, 0x00, /* 0010011000 */
+ 0x03, 0x80, /* 0000001110 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 82 0x52 'R' */
+ 0x00, 0x00, /* 0000000000 */
+ 0xfe, 0x00, /* 1111111000 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x00, /* 0110000100 */
+ 0x7e, 0x00, /* 0111111000 */
+ 0x78, 0x00, /* 0111100000 */
+ 0x6c, 0x00, /* 0110110000 */
+ 0x6e, 0x00, /* 0110111000 */
+ 0x67, 0x00, /* 0110011100 */
+ 0x63, 0x80, /* 0110001110 */
+ 0x61, 0xc0, /* 0110000111 */
+ 0xf0, 0xc0, /* 1111000011 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 83 0x53 'S' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x1f, 0x00, /* 0001111100 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x60, 0x80, /* 0110000010 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x03, 0x00, /* 0000001100 */
+ 0x01, 0x80, /* 0000000110 */
+ 0x41, 0x80, /* 0100000110 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x3e, 0x00, /* 0011111000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 84 0x54 'T' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x4c, 0x80, /* 0100110010 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 85 0x55 'U' */
+ 0x00, 0x00, /* 0000000000 */
+ 0xf3, 0xc0, /* 1111001111 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x73, 0x00, /* 0111001100 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 86 0x56 'V' */
+ 0x00, 0x00, /* 0000000000 */
+ 0xe1, 0xc0, /* 1110000111 */
+ 0xc0, 0xc0, /* 1100000011 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x12, 0x00, /* 0001001000 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 87 0x57 'W' */
+ 0x00, 0x00, /* 0000000000 */
+ 0xe1, 0xc0, /* 1110000111 */
+ 0xc0, 0xc0, /* 1100000011 */
+ 0xc0, 0xc0, /* 1100000011 */
+ 0xc0, 0xc0, /* 1100000011 */
+ 0xe0, 0xc0, /* 1110000011 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x6d, 0x80, /* 0110110110 */
+ 0x6d, 0x80, /* 0110110110 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x77, 0x00, /* 0111011100 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 88 0x58 'X' */
+ 0x00, 0x00, /* 0000000000 */
+ 0xf7, 0x80, /* 1111011110 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x36, 0x00, /* 0011011000 */
+ 0x36, 0x00, /* 0011011000 */
+ 0x36, 0x00, /* 0011011000 */
+ 0x1c, 0x00, /* 0001110000 */
+ 0x1c, 0x00, /* 0001110000 */
+ 0x36, 0x00, /* 0011011000 */
+ 0x36, 0x00, /* 0011011000 */
+ 0x36, 0x00, /* 0011011000 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x63, 0x00, /* 0110001100 */
+ 0xf7, 0x80, /* 1111011110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 89 0x59 'Y' */
+ 0x00, 0x00, /* 0000000000 */
+ 0xf3, 0xc0, /* 1111001111 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 90 0x5a 'Z' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x3f, 0x80, /* 0011111110 */
+ 0x21, 0x80, /* 0010000110 */
+ 0x01, 0x80, /* 0000000110 */
+ 0x03, 0x00, /* 0000001100 */
+ 0x03, 0x00, /* 0000001100 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x80, /* 0011000010 */
+ 0x3f, 0x80, /* 0011111110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 91 0x5b '[' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x1f, 0x00, /* 0001111100 */
+ 0x1f, 0x00, /* 0001111100 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x1f, 0x00, /* 0001111100 */
+ 0x1f, 0x00, /* 0001111100 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 92 0x5c '\' */
+ 0x00, 0x00, /* 0000000000 */
+ 0xc0, 0x00, /* 1100000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x03, 0x00, /* 0000001100 */
+ 0x03, 0x00, /* 0000001100 */
+ 0x01, 0x80, /* 0000000110 */
+ 0x01, 0x80, /* 0000000110 */
+ 0x00, 0xc0, /* 0000000011 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 93 0x5d ']' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x3e, 0x00, /* 0011111000 */
+ 0x3e, 0x00, /* 0011111000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x3e, 0x00, /* 0011111000 */
+ 0x3e, 0x00, /* 0011111000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 94 0x5e '^' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 95 0x5f '_' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 96 0x60 '`' */
+ 0x04, 0x00, /* 0000010000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 97 0x61 'a' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x1f, 0x00, /* 0001111100 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x21, 0x80, /* 0010000110 */
+ 0x07, 0x80, /* 0000011110 */
+ 0x39, 0x80, /* 0011100110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x73, 0x80, /* 0111001110 */
+ 0x3d, 0xc0, /* 0011110111 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 98 0x62 'b' */
+ 0x20, 0x00, /* 0010000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0xe0, 0x00, /* 1110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x66, 0x00, /* 0110011000 */
+ 0x6f, 0x00, /* 0110111100 */
+ 0x73, 0x80, /* 0111001110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x71, 0x80, /* 0111000110 */
+ 0x7b, 0x00, /* 0111101100 */
+ 0x4e, 0x00, /* 0100111000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 99 0x63 'c' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x37, 0x00, /* 0011011100 */
+ 0x23, 0x00, /* 0010001100 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x71, 0x00, /* 0111000100 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 100 0x64 'd' */
+ 0x01, 0x80, /* 0000000110 */
+ 0x03, 0x80, /* 0000001110 */
+ 0x01, 0x80, /* 0000000110 */
+ 0x01, 0x80, /* 0000000110 */
+ 0x01, 0x80, /* 0000000110 */
+ 0x0d, 0x80, /* 0000110110 */
+ 0x37, 0x80, /* 0011011110 */
+ 0x23, 0x80, /* 0010001110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x73, 0x80, /* 0111001110 */
+ 0x35, 0x80, /* 0011010110 */
+ 0x19, 0xc0, /* 0001100111 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 101 0x65 'e' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x19, 0x80, /* 0001100110 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 102 0x66 'f' */
+ 0x07, 0x00, /* 0000011100 */
+ 0x09, 0x80, /* 0000100110 */
+ 0x09, 0x80, /* 0000100110 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x7f, 0x00, /* 0111111100 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x3c, 0x00, /* 0011110000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 103 0x67 'g' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x1c, 0x80, /* 0001110010 */
+ 0x37, 0x80, /* 0011011110 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x36, 0x00, /* 0011011000 */
+ 0x3c, 0x00, /* 0011110000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x7f, 0x00, /* 0111111100 */
+ 0x3f, 0x80, /* 0011111110 */
+ 0x21, 0x80, /* 0010000110 */
+ 0x40, 0x80, /* 0100000010 */
+ 0x7f, 0x00, /* 0111111100 */
+ 0x3e, 0x00, /* 0011111000 */
+
+ /* 104 0x68 'h' */
+ 0x10, 0x00, /* 0001000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x70, 0x00, /* 0111000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x37, 0x00, /* 0011011100 */
+ 0x3b, 0x80, /* 0011101110 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x7b, 0xc0, /* 0111101111 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 105 0x69 'i' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x3c, 0x00, /* 0011110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 106 0x6a 'j' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x01, 0x80, /* 0000000110 */
+ 0x01, 0x80, /* 0000000110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x07, 0x80, /* 0000011110 */
+ 0x01, 0x80, /* 0000000110 */
+ 0x01, 0x80, /* 0000000110 */
+ 0x01, 0x80, /* 0000000110 */
+ 0x01, 0x80, /* 0000000110 */
+ 0x01, 0x80, /* 0000000110 */
+ 0x01, 0x80, /* 0000000110 */
+ 0x01, 0x80, /* 0000000110 */
+ 0x41, 0x80, /* 0100000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x71, 0x80, /* 0111000110 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x1c, 0x00, /* 0001110000 */
+
+ /* 107 0x6b 'k' */
+ 0x60, 0x00, /* 0110000000 */
+ 0xe0, 0x00, /* 1110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x63, 0x80, /* 0110001110 */
+ 0x66, 0x00, /* 0110011000 */
+ 0x6c, 0x00, /* 0110110000 */
+ 0x78, 0x00, /* 0111100000 */
+ 0x70, 0x00, /* 0111000000 */
+ 0x78, 0x00, /* 0111100000 */
+ 0x6c, 0x00, /* 0110110000 */
+ 0x6e, 0x00, /* 0110111000 */
+ 0x67, 0x00, /* 0110011100 */
+ 0xf3, 0x80, /* 1111001110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 108 0x6c 'l' */
+ 0x3c, 0x00, /* 0011110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 109 0x6d 'm' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0xdb, 0x80, /* 1101101110 */
+ 0x6d, 0x80, /* 0110110110 */
+ 0x6d, 0x80, /* 0110110110 */
+ 0x6d, 0x80, /* 0110110110 */
+ 0x6d, 0x80, /* 0110110110 */
+ 0x6d, 0x80, /* 0110110110 */
+ 0x6d, 0x80, /* 0110110110 */
+ 0x6d, 0x80, /* 0110110110 */
+ 0x6d, 0x80, /* 0110110110 */
+ 0xed, 0xc0, /* 1110110111 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 110 0x6e 'n' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x6f, 0x00, /* 0110111100 */
+ 0x7b, 0x80, /* 0111101110 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x7b, 0xc0, /* 0111101111 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 111 0x6f 'o' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x3c, 0x00, /* 0011110000 */
+ 0x66, 0x00, /* 0110011000 */
+ 0xc3, 0x00, /* 1100001100 */
+ 0xc1, 0x80, /* 1100000110 */
+ 0xc1, 0x80, /* 1100000110 */
+ 0xc1, 0x80, /* 1100000110 */
+ 0xc1, 0x80, /* 1100000110 */
+ 0xe1, 0x80, /* 1110000110 */
+ 0x73, 0x00, /* 0111001100 */
+ 0x3c, 0x00, /* 0011110000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 112 0x70 'p' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0xde, 0x00, /* 1101111000 */
+ 0x76, 0x00, /* 0111011000 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x71, 0x80, /* 0111000110 */
+ 0x7b, 0x00, /* 0111101100 */
+ 0x7e, 0x00, /* 0111111000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0xf0, 0x00, /* 1111000000 */
+
+ /* 113 0x71 'q' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0e, 0xc0, /* 0000111011 */
+ 0x1b, 0x80, /* 0001101110 */
+ 0x33, 0x80, /* 0011001110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x71, 0x80, /* 0111000110 */
+ 0x3b, 0x80, /* 0011101110 */
+ 0x1f, 0x80, /* 0001111110 */
+ 0x01, 0x80, /* 0000000110 */
+ 0x01, 0x80, /* 0000000110 */
+ 0x03, 0xc0, /* 0000001111 */
+
+ /* 114 0x72 'r' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x73, 0x00, /* 0111001100 */
+ 0x35, 0x80, /* 0011010110 */
+ 0x39, 0x80, /* 0011100110 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x78, 0x00, /* 0111100000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 115 0x73 's' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x61, 0x00, /* 0110000100 */
+ 0x70, 0x00, /* 0111000000 */
+ 0x38, 0x00, /* 0011100000 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x07, 0x00, /* 0000011100 */
+ 0x43, 0x00, /* 0100001100 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x7e, 0x00, /* 0111111000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 116 0x74 't' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x08, 0x00, /* 0000100000 */
+ 0x08, 0x00, /* 0000100000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x1c, 0x80, /* 0001110010 */
+ 0x0f, 0x00, /* 0000111100 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 117 0x75 'u' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0xf7, 0x80, /* 1111011110 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x77, 0x00, /* 0111011100 */
+ 0x3d, 0x80, /* 0011110110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 118 0x76 'v' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0xf1, 0xc0, /* 1111000111 */
+ 0x60, 0xc0, /* 0110000011 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x19, 0x80, /* 0001100110 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x0f, 0x00, /* 0000111100 */
+ 0x0f, 0x00, /* 0000111100 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 119 0x77 'w' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0xe3, 0xc0, /* 1110001111 */
+ 0xc1, 0x80, /* 1100000110 */
+ 0xc1, 0x80, /* 1100000110 */
+ 0xc1, 0x80, /* 1100000110 */
+ 0xc1, 0x80, /* 1100000110 */
+ 0x6b, 0x00, /* 0110101100 */
+ 0x6b, 0x00, /* 0110101100 */
+ 0x7e, 0x00, /* 0111111000 */
+ 0x36, 0x00, /* 0011011000 */
+ 0x36, 0x00, /* 0011011000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 120 0x78 'x' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0xf7, 0x80, /* 1111011110 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x36, 0x00, /* 0011011000 */
+ 0x36, 0x00, /* 0011011000 */
+ 0x1c, 0x00, /* 0001110000 */
+ 0x1c, 0x00, /* 0001110000 */
+ 0x36, 0x00, /* 0011011000 */
+ 0x66, 0x00, /* 0110011000 */
+ 0x63, 0x00, /* 0110001100 */
+ 0xf7, 0x80, /* 1111011110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 121 0x79 'y' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0xf3, 0xc0, /* 1111001111 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x78, 0x00, /* 0111100000 */
+ 0x70, 0x00, /* 0111000000 */
+
+ /* 122 0x7a 'z' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x43, 0x00, /* 0100001100 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x60, 0x80, /* 0110000010 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 123 0x7b '{' */
+ 0x07, 0x00, /* 0000011100 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x70, 0x00, /* 0111000000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x07, 0x00, /* 0000011100 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 124 0x7c '|' */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 125 0x7d '}' */
+ 0x38, 0x00, /* 0011100000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x03, 0x80, /* 0000001110 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x38, 0x00, /* 0011100000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 126 0x7e '~' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x18, 0x80, /* 0001100010 */
+ 0x3d, 0x80, /* 0011110110 */
+ 0x6f, 0x00, /* 0110111100 */
+ 0x46, 0x00, /* 0100011000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 127 0x7f '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x12, 0x00, /* 0001001000 */
+ 0x21, 0x00, /* 0010000100 */
+ 0x40, 0x80, /* 0100000010 */
+ 0x40, 0x80, /* 0100000010 */
+ 0x40, 0x80, /* 0100000010 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 128 0x80 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x1f, 0x00, /* 0001111100 */
+ 0x21, 0x80, /* 0010000110 */
+ 0x40, 0x80, /* 0100000010 */
+ 0x40, 0x00, /* 0100000000 */
+ 0x40, 0x00, /* 0100000000 */
+ 0x40, 0x00, /* 0100000000 */
+ 0x40, 0x00, /* 0100000000 */
+ 0x40, 0x00, /* 0100000000 */
+ 0x40, 0x00, /* 0100000000 */
+ 0x60, 0x80, /* 0110000010 */
+ 0x31, 0x00, /* 0011000100 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x08, 0x00, /* 0000100000 */
+ 0x04, 0x00, /* 0000010000 */
+ 0x02, 0x00, /* 0000001000 */
+ 0x02, 0x00, /* 0000001000 */
+ 0x1c, 0x00, /* 0001110000 */
+
+ /* 129 0x81 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x7b, 0x80, /* 0111101110 */
+ 0x31, 0x00, /* 0011000100 */
+ 0x31, 0x00, /* 0011000100 */
+ 0x31, 0x00, /* 0011000100 */
+ 0x31, 0x00, /* 0011000100 */
+ 0x31, 0x00, /* 0011000100 */
+ 0x31, 0x00, /* 0011000100 */
+ 0x31, 0x00, /* 0011000100 */
+ 0x3b, 0x00, /* 0011101100 */
+ 0x1c, 0x80, /* 0001110010 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 130 0x82 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x01, 0x00, /* 0000000100 */
+ 0x02, 0x00, /* 0000001000 */
+ 0x04, 0x00, /* 0000010000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x19, 0x80, /* 0001100110 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 131 0x83 '.' */
+ 0x04, 0x00, /* 0000010000 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x1f, 0x00, /* 0001111100 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x21, 0x80, /* 0010000110 */
+ 0x07, 0x80, /* 0000011110 */
+ 0x39, 0x80, /* 0011100110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x73, 0x80, /* 0111001110 */
+ 0x3d, 0xc0, /* 0011110111 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 132 0x84 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x1f, 0x00, /* 0001111100 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x21, 0x80, /* 0010000110 */
+ 0x07, 0x80, /* 0000011110 */
+ 0x39, 0x80, /* 0011100110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x73, 0x80, /* 0111001110 */
+ 0x3d, 0xc0, /* 0011110111 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 133 0x85 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x1f, 0x00, /* 0001111100 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x21, 0x80, /* 0010000110 */
+ 0x07, 0x80, /* 0000011110 */
+ 0x39, 0x80, /* 0011100110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x73, 0x80, /* 0111001110 */
+ 0x3d, 0xc0, /* 0011110111 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 134 0x86 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x1f, 0x00, /* 0001111100 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x21, 0x80, /* 0010000110 */
+ 0x07, 0x80, /* 0000011110 */
+ 0x39, 0x80, /* 0011100110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x73, 0x80, /* 0111001110 */
+ 0x3d, 0xc0, /* 0011110111 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 135 0x87 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x1f, 0x00, /* 0001111100 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x20, 0x80, /* 0010000010 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x70, 0x80, /* 0111000010 */
+ 0x30, 0x80, /* 0011000010 */
+ 0x1f, 0x00, /* 0001111100 */
+ 0x04, 0x00, /* 0000010000 */
+ 0x02, 0x00, /* 0000001000 */
+ 0x01, 0x00, /* 0000000100 */
+ 0x0e, 0x00, /* 0000111000 */
+
+ /* 136 0x88 '.' */
+ 0x04, 0x00, /* 0000010000 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x19, 0x80, /* 0001100110 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 137 0x89 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x36, 0x00, /* 0011011000 */
+ 0x36, 0x00, /* 0011011000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x19, 0x80, /* 0001100110 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 138 0x8a '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x19, 0x80, /* 0001100110 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 139 0x8b '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x36, 0x00, /* 0011011000 */
+ 0x36, 0x00, /* 0011011000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x3c, 0x00, /* 0011110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 140 0x8c '.' */
+ 0x08, 0x00, /* 0000100000 */
+ 0x1c, 0x00, /* 0001110000 */
+ 0x36, 0x00, /* 0011011000 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x3c, 0x00, /* 0011110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 141 0x8d '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x3c, 0x00, /* 0011110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 142 0x8e '.' */
+ 0x31, 0x80, /* 0011000110 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x04, 0x00, /* 0000010000 */
+ 0x04, 0x00, /* 0000010000 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x19, 0x00, /* 0001100100 */
+ 0x19, 0x00, /* 0001100100 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x31, 0x00, /* 0011000100 */
+ 0x31, 0x00, /* 0011000100 */
+ 0x60, 0x80, /* 0110000010 */
+ 0x60, 0x80, /* 0110000010 */
+ 0xf3, 0xc0, /* 1111001111 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 143 0x8f '.' */
+ 0x04, 0x00, /* 0000010000 */
+ 0x0a, 0x00, /* 0000101000 */
+ 0x0a, 0x00, /* 0000101000 */
+ 0x04, 0x00, /* 0000010000 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x19, 0x00, /* 0001100100 */
+ 0x19, 0x00, /* 0001100100 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x31, 0x00, /* 0011000100 */
+ 0x31, 0x00, /* 0011000100 */
+ 0x60, 0x80, /* 0110000010 */
+ 0x60, 0x80, /* 0110000010 */
+ 0xf3, 0xc0, /* 1111001111 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 144 0x90 '.' */
+ 0x03, 0x00, /* 0000001100 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x30, 0x80, /* 0011000010 */
+ 0x30, 0x80, /* 0011000010 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x31, 0x00, /* 0011000100 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x31, 0x00, /* 0011000100 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x80, /* 0011000010 */
+ 0x30, 0x80, /* 0011000010 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 145 0x91 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x3b, 0x80, /* 0011101110 */
+ 0x6c, 0xc0, /* 0110110011 */
+ 0x4c, 0xc0, /* 0100110011 */
+ 0x0c, 0xc0, /* 0000110011 */
+ 0x3f, 0xc0, /* 0011111111 */
+ 0x6c, 0x00, /* 0110110000 */
+ 0xcc, 0x00, /* 1100110000 */
+ 0xcc, 0x00, /* 1100110000 */
+ 0xee, 0xc0, /* 1110111011 */
+ 0x7b, 0x80, /* 0111101110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 146 0x92 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x07, 0xc0, /* 0000011111 */
+ 0x0e, 0x40, /* 0000111001 */
+ 0x0e, 0x40, /* 0000111001 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x16, 0x00, /* 0001011000 */
+ 0x16, 0x80, /* 0001011010 */
+ 0x17, 0x80, /* 0001011110 */
+ 0x16, 0x80, /* 0001011010 */
+ 0x3e, 0x00, /* 0011111000 */
+ 0x26, 0x00, /* 0010011000 */
+ 0x26, 0x00, /* 0010011000 */
+ 0x46, 0x40, /* 0100011001 */
+ 0x46, 0x40, /* 0100011001 */
+ 0xef, 0xc0, /* 1110111111 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 147 0x93 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x08, 0x00, /* 0000100000 */
+ 0x1c, 0x00, /* 0001110000 */
+ 0x36, 0x00, /* 0011011000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x3c, 0x00, /* 0011110000 */
+ 0x66, 0x00, /* 0110011000 */
+ 0xc3, 0x00, /* 1100001100 */
+ 0xc1, 0x80, /* 1100000110 */
+ 0xc1, 0x80, /* 1100000110 */
+ 0xc1, 0x80, /* 1100000110 */
+ 0xc1, 0x80, /* 1100000110 */
+ 0xe1, 0x80, /* 1110000110 */
+ 0x73, 0x00, /* 0111001100 */
+ 0x3c, 0x00, /* 0011110000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 148 0x94 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x3c, 0x00, /* 0011110000 */
+ 0x66, 0x00, /* 0110011000 */
+ 0xc3, 0x00, /* 1100001100 */
+ 0xc1, 0x80, /* 1100000110 */
+ 0xc1, 0x80, /* 1100000110 */
+ 0xc1, 0x80, /* 1100000110 */
+ 0xc1, 0x80, /* 1100000110 */
+ 0xe1, 0x80, /* 1110000110 */
+ 0x73, 0x00, /* 0111001100 */
+ 0x3c, 0x00, /* 0011110000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 149 0x95 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x3c, 0x00, /* 0011110000 */
+ 0x66, 0x00, /* 0110011000 */
+ 0xc3, 0x00, /* 1100001100 */
+ 0xc1, 0x80, /* 1100000110 */
+ 0xc1, 0x80, /* 1100000110 */
+ 0xc1, 0x80, /* 1100000110 */
+ 0xc1, 0x80, /* 1100000110 */
+ 0xe1, 0x80, /* 1110000110 */
+ 0x73, 0x00, /* 0111001100 */
+ 0x3c, 0x00, /* 0011110000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 150 0x96 '.' */
+ 0x08, 0x00, /* 0000100000 */
+ 0x1c, 0x00, /* 0001110000 */
+ 0x36, 0x00, /* 0011011000 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x00, 0x00, /* 0000000000 */
+ 0xf7, 0x80, /* 1111011110 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x77, 0x00, /* 0111011100 */
+ 0x3d, 0x80, /* 0011110110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 151 0x97 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0xf7, 0x80, /* 1111011110 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x77, 0x00, /* 0111011100 */
+ 0x3d, 0x80, /* 0011110110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 152 0x98 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0xf3, 0xc0, /* 1111001111 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x78, 0x00, /* 0111100000 */
+ 0x70, 0x00, /* 0111000000 */
+
+ /* 153 0x99 '.' */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x17, 0x00, /* 0001011100 */
+ 0x23, 0x00, /* 0010001100 */
+ 0x21, 0x80, /* 0010000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x21, 0x00, /* 0010000100 */
+ 0x31, 0x00, /* 0011000100 */
+ 0x1a, 0x00, /* 0001101000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 154 0x9a '.' */
+ 0x33, 0x00, /* 0011001100 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x00, 0x00, /* 0000000000 */
+ 0xf1, 0xc0, /* 1111000111 */
+ 0x60, 0x80, /* 0110000010 */
+ 0x60, 0x80, /* 0110000010 */
+ 0x60, 0x80, /* 0110000010 */
+ 0x60, 0x80, /* 0110000010 */
+ 0x60, 0x80, /* 0110000010 */
+ 0x60, 0x80, /* 0110000010 */
+ 0x60, 0x80, /* 0110000010 */
+ 0x60, 0x80, /* 0110000010 */
+ 0x71, 0x00, /* 0111000100 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 155 0x9b '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x1f, 0x80, /* 0001111110 */
+ 0x36, 0x80, /* 0011011010 */
+ 0x26, 0x00, /* 0010011000 */
+ 0x66, 0x00, /* 0110011000 */
+ 0x66, 0x00, /* 0110011000 */
+ 0x66, 0x00, /* 0110011000 */
+ 0x66, 0x00, /* 0110011000 */
+ 0x76, 0x00, /* 0111011000 */
+ 0x36, 0x80, /* 0011011010 */
+ 0x1f, 0x80, /* 0001111110 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 156 0x9c '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x3b, 0x00, /* 0011101100 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x7e, 0x00, /* 0111111000 */
+ 0x7e, 0x00, /* 0111111000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x7c, 0x80, /* 0111110010 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x43, 0x00, /* 0100001100 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 157 0x9d '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x40, 0x80, /* 0100000010 */
+ 0x40, 0x80, /* 0100000010 */
+ 0x21, 0x00, /* 0010000100 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 158 0x9e '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0xbf, 0x00, /* 1011111100 */
+ 0x40, 0x80, /* 0100000010 */
+ 0x40, 0x80, /* 0100000010 */
+ 0x7f, 0x00, /* 0111111100 */
+ 0x40, 0x00, /* 0100000000 */
+ 0x48, 0x00, /* 0100100000 */
+ 0x48, 0x00, /* 0100100000 */
+ 0x5e, 0x00, /* 0101111000 */
+ 0x48, 0x00, /* 0100100000 */
+ 0x48, 0x00, /* 0100100000 */
+ 0x48, 0x00, /* 0100100000 */
+ 0x48, 0x80, /* 0100100010 */
+ 0x47, 0x00, /* 0100011100 */
+ 0xe0, 0x00, /* 1110000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 159 0x9f '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x03, 0x00, /* 0000001100 */
+ 0x04, 0x80, /* 0000010010 */
+ 0x08, 0x00, /* 0000100000 */
+ 0x08, 0x00, /* 0000100000 */
+ 0x08, 0x00, /* 0000100000 */
+ 0x08, 0x00, /* 0000100000 */
+ 0x09, 0x00, /* 0000100100 */
+ 0x3e, 0x00, /* 0011111000 */
+ 0x48, 0x00, /* 0100100000 */
+ 0x08, 0x00, /* 0000100000 */
+ 0x08, 0x00, /* 0000100000 */
+ 0x08, 0x00, /* 0000100000 */
+ 0x08, 0x00, /* 0000100000 */
+ 0x08, 0x00, /* 0000100000 */
+ 0x90, 0x00, /* 1001000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 160 0xa0 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x03, 0x00, /* 0000001100 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x1f, 0x00, /* 0001111100 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x21, 0x80, /* 0010000110 */
+ 0x07, 0x80, /* 0000011110 */
+ 0x39, 0x80, /* 0011100110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x73, 0x80, /* 0111001110 */
+ 0x3d, 0xc0, /* 0011110111 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 161 0xa1 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x03, 0x00, /* 0000001100 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x3c, 0x00, /* 0011110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 162 0xa2 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x3c, 0x00, /* 0011110000 */
+ 0x66, 0x00, /* 0110011000 */
+ 0xc3, 0x00, /* 1100001100 */
+ 0xc1, 0x80, /* 1100000110 */
+ 0xc1, 0x80, /* 1100000110 */
+ 0xc1, 0x80, /* 1100000110 */
+ 0xc1, 0x80, /* 1100000110 */
+ 0xe1, 0x80, /* 1110000110 */
+ 0x73, 0x00, /* 0111001100 */
+ 0x3c, 0x00, /* 0011110000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 163 0xa3 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0xf7, 0x80, /* 1111011110 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x77, 0x00, /* 0111011100 */
+ 0x3d, 0x80, /* 0011110110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 164 0xa4 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x38, 0x80, /* 0011100010 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x47, 0x00, /* 0100011100 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x6f, 0x00, /* 0110111100 */
+ 0x7b, 0x80, /* 0111101110 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x7b, 0xc0, /* 0111101111 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 165 0xa5 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x38, 0x80, /* 0011100010 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x47, 0x00, /* 0100011100 */
+ 0x00, 0x00, /* 0000000000 */
+ 0xe3, 0xc0, /* 1110001111 */
+ 0x71, 0x80, /* 0111000110 */
+ 0x79, 0x80, /* 0111100110 */
+ 0x79, 0x80, /* 0111100110 */
+ 0x6d, 0x80, /* 0110110110 */
+ 0x6d, 0x80, /* 0110110110 */
+ 0x67, 0x80, /* 0110011110 */
+ 0x63, 0x80, /* 0110001110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0xf0, 0xc0, /* 1111000011 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 166 0xa6 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x3e, 0x00, /* 0011111000 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x03, 0x00, /* 0000001100 */
+ 0x0f, 0x00, /* 0000111100 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x67, 0x00, /* 0110011100 */
+ 0x3b, 0x80, /* 0011101110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 167 0xa7 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x21, 0x80, /* 0010000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x00, /* 0110000100 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x1c, 0x00, /* 0001110000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 168 0xa8 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x80, /* 0110000010 */
+ 0x73, 0x80, /* 0111001110 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 169 0xa9 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 170 0xaa '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x01, 0x80, /* 0000000110 */
+ 0x01, 0x80, /* 0000000110 */
+ 0x01, 0x80, /* 0000000110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 171 0xab '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x20, 0x00, /* 0010000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x20, 0x00, /* 0010000000 */
+ 0x20, 0x80, /* 0010000010 */
+ 0x21, 0x00, /* 0010000100 */
+ 0x22, 0x00, /* 0010001000 */
+ 0x74, 0x00, /* 0111010000 */
+ 0x08, 0x00, /* 0000100000 */
+ 0x17, 0x00, /* 0001011100 */
+ 0x28, 0x80, /* 0010100010 */
+ 0x43, 0x00, /* 0100001100 */
+ 0x04, 0x00, /* 0000010000 */
+ 0x08, 0x00, /* 0000100000 */
+ 0x0f, 0x80, /* 0000111110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 172 0xac '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x20, 0x00, /* 0010000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x20, 0x00, /* 0010000000 */
+ 0x20, 0x80, /* 0010000010 */
+ 0x21, 0x00, /* 0010000100 */
+ 0x22, 0x00, /* 0010001000 */
+ 0x74, 0x00, /* 0111010000 */
+ 0x09, 0x00, /* 0000100100 */
+ 0x13, 0x00, /* 0001001100 */
+ 0x25, 0x00, /* 0010010100 */
+ 0x49, 0x00, /* 0100100100 */
+ 0x1f, 0x80, /* 0001111110 */
+ 0x01, 0x00, /* 0000000100 */
+ 0x01, 0x00, /* 0000000100 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 173 0xad '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 174 0xae '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0d, 0x80, /* 0000110110 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x36, 0x00, /* 0011011000 */
+ 0x6c, 0x00, /* 0110110000 */
+ 0xd8, 0x00, /* 1101100000 */
+ 0x6c, 0x00, /* 0110110000 */
+ 0x36, 0x00, /* 0011011000 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x0d, 0x80, /* 0000110110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 175 0xaf '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x6c, 0x00, /* 0110110000 */
+ 0x36, 0x00, /* 0011011000 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x0d, 0x80, /* 0000110110 */
+ 0x06, 0xc0, /* 0000011011 */
+ 0x0d, 0x80, /* 0000110110 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x36, 0x00, /* 0011011000 */
+ 0x6c, 0x00, /* 0110110000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 176 0xb0 '.' */
+ 0xc3, 0x00, /* 1100001100 */
+ 0x41, 0x00, /* 0100000100 */
+ 0x18, 0x40, /* 0001100001 */
+ 0x10, 0x40, /* 0001000001 */
+ 0xc3, 0x00, /* 1100001100 */
+ 0x41, 0x00, /* 0100000100 */
+ 0x18, 0x40, /* 0001100001 */
+ 0x10, 0x40, /* 0001000001 */
+ 0xc3, 0x00, /* 1100001100 */
+ 0x41, 0x00, /* 0100000100 */
+ 0x18, 0x40, /* 0001100001 */
+ 0x10, 0x40, /* 0001000001 */
+ 0xc3, 0x00, /* 1100001100 */
+ 0x41, 0x00, /* 0100000100 */
+ 0x18, 0x40, /* 0001100001 */
+ 0x10, 0x40, /* 0001000001 */
+ 0xc3, 0x00, /* 1100001100 */
+ 0x41, 0x00, /* 0100000100 */
+
+ /* 177 0xb1 '.' */
+ 0x11, 0x00, /* 0001000100 */
+ 0xbb, 0x80, /* 1011101110 */
+ 0x11, 0x00, /* 0001000100 */
+ 0x44, 0x40, /* 0100010001 */
+ 0xee, 0xc0, /* 1110111011 */
+ 0x44, 0x40, /* 0100010001 */
+ 0x11, 0x00, /* 0001000100 */
+ 0xbb, 0x80, /* 1011101110 */
+ 0x11, 0x00, /* 0001000100 */
+ 0x44, 0x40, /* 0100010001 */
+ 0xee, 0xc0, /* 1110111011 */
+ 0x44, 0x40, /* 0100010001 */
+ 0x11, 0x00, /* 0001000100 */
+ 0xbb, 0x80, /* 1011101110 */
+ 0x11, 0x00, /* 0001000100 */
+ 0x44, 0x40, /* 0100010001 */
+ 0xee, 0xc0, /* 1110111011 */
+ 0x44, 0x40, /* 0100010001 */
+
+ /* 178 0xb2 '.' */
+ 0x3c, 0xc0, /* 0011110011 */
+ 0xbe, 0xc0, /* 1011111011 */
+ 0xe7, 0x80, /* 1110011110 */
+ 0xef, 0x80, /* 1110111110 */
+ 0x3c, 0xc0, /* 0011110011 */
+ 0xbe, 0xc0, /* 1011111011 */
+ 0xe7, 0x80, /* 1110011110 */
+ 0xef, 0x80, /* 1110111110 */
+ 0x3c, 0xc0, /* 0011110011 */
+ 0xbe, 0xc0, /* 1011111011 */
+ 0xe7, 0x80, /* 1110011110 */
+ 0xef, 0x80, /* 1110111110 */
+ 0x3c, 0xc0, /* 0011110011 */
+ 0xbe, 0xc0, /* 1011111011 */
+ 0xe7, 0x80, /* 1110011110 */
+ 0xef, 0x80, /* 1110111110 */
+ 0x3c, 0xc0, /* 0011110011 */
+ 0xbe, 0xc0, /* 1011111011 */
+
+ /* 179 0xb3 '.' */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+
+ /* 180 0xb4 '.' */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0xfc, 0x00, /* 1111110000 */
+ 0xfc, 0x00, /* 1111110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+
+ /* 181 0xb5 '.' */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0xfc, 0x00, /* 1111110000 */
+ 0xfc, 0x00, /* 1111110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0xfc, 0x00, /* 1111110000 */
+ 0xfc, 0x00, /* 1111110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+
+ /* 182 0xb6 '.' */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0xfb, 0x00, /* 1111101100 */
+ 0xfb, 0x00, /* 1111101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+
+ /* 183 0xb7 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0xff, 0x00, /* 1111111100 */
+ 0xff, 0x00, /* 1111111100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+
+ /* 184 0xb8 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0xfc, 0x00, /* 1111110000 */
+ 0xfc, 0x00, /* 1111110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0xfc, 0x00, /* 1111110000 */
+ 0xfc, 0x00, /* 1111110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+
+ /* 185 0xb9 '.' */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0xfb, 0x00, /* 1111101100 */
+ 0xfb, 0x00, /* 1111101100 */
+ 0x03, 0x00, /* 0000001100 */
+ 0xfb, 0x00, /* 1111101100 */
+ 0xfb, 0x00, /* 1111101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+
+ /* 186 0xba '.' */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+
+ /* 187 0xbb '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0xff, 0x00, /* 1111111100 */
+ 0xff, 0x00, /* 1111111100 */
+ 0x03, 0x00, /* 0000001100 */
+ 0xfb, 0x00, /* 1111101100 */
+ 0xfb, 0x00, /* 1111101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+
+ /* 188 0xbc '.' */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0xfb, 0x00, /* 1111101100 */
+ 0xfb, 0x00, /* 1111101100 */
+ 0x03, 0x00, /* 0000001100 */
+ 0xff, 0x00, /* 1111111100 */
+ 0xff, 0x00, /* 1111111100 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 189 0xbd '.' */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0xff, 0x00, /* 1111111100 */
+ 0xff, 0x00, /* 1111111100 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 190 0xbe '.' */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0xfc, 0x00, /* 1111110000 */
+ 0xfc, 0x00, /* 1111110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0xfc, 0x00, /* 1111110000 */
+ 0xfc, 0x00, /* 1111110000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 191 0xbf '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0xfc, 0x00, /* 1111110000 */
+ 0xfc, 0x00, /* 1111110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+
+ /* 192 0xc0 '.' */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0f, 0xc0, /* 0000111111 */
+ 0x0f, 0xc0, /* 0000111111 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 193 0xc1 '.' */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 194 0xc2 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+
+ /* 195 0xc3 '.' */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0f, 0xc0, /* 0000111111 */
+ 0x0f, 0xc0, /* 0000111111 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+
+ /* 196 0xc4 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 197 0xc5 '.' */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+
+ /* 198 0xc6 '.' */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0f, 0xc0, /* 0000111111 */
+ 0x0f, 0xc0, /* 0000111111 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0f, 0xc0, /* 0000111111 */
+ 0x0f, 0xc0, /* 0000111111 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+
+ /* 199 0xc7 '.' */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0xc0, /* 0001101111 */
+ 0x1b, 0xc0, /* 0001101111 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+
+ /* 200 0xc8 '.' */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0xc0, /* 0001101111 */
+ 0x1b, 0xc0, /* 0001101111 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x1f, 0xc0, /* 0001111111 */
+ 0x1f, 0xc0, /* 0001111111 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 201 0xc9 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x1f, 0xc0, /* 0001111111 */
+ 0x1f, 0xc0, /* 0001111111 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x1b, 0xc0, /* 0001101111 */
+ 0x1b, 0xc0, /* 0001101111 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+
+ /* 202 0xca '.' */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0xfb, 0xc0, /* 1111101111 */
+ 0xfb, 0xc0, /* 1111101111 */
+ 0x00, 0x00, /* 0000000000 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 203 0xcb '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0x00, 0x00, /* 0000000000 */
+ 0xfb, 0xc0, /* 1111101111 */
+ 0xfb, 0xc0, /* 1111101111 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+
+ /* 204 0xcc '.' */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0xc0, /* 0001101111 */
+ 0x1b, 0xc0, /* 0001101111 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x1b, 0xc0, /* 0001101111 */
+ 0x1b, 0xc0, /* 0001101111 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+
+ /* 205 0xcd '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0x00, 0x00, /* 0000000000 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 206 0xce '.' */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0xfb, 0xc0, /* 1111101111 */
+ 0xfb, 0xc0, /* 1111101111 */
+ 0x00, 0x00, /* 0000000000 */
+ 0xfb, 0xc0, /* 1111101111 */
+ 0xfb, 0xc0, /* 1111101111 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+
+ /* 207 0xcf '.' */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0x00, 0x00, /* 0000000000 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 208 0xd0 '.' */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 209 0xd1 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0x00, 0x00, /* 0000000000 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+
+ /* 210 0xd2 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+
+ /* 211 0xd3 '.' */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1f, 0xc0, /* 0001111111 */
+ 0x1f, 0xc0, /* 0001111111 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 212 0xd4 '.' */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0f, 0xc0, /* 0000111111 */
+ 0x0f, 0xc0, /* 0000111111 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0f, 0xc0, /* 0000111111 */
+ 0x0f, 0xc0, /* 0000111111 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 213 0xd5 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0f, 0xc0, /* 0000111111 */
+ 0x0f, 0xc0, /* 0000111111 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0f, 0xc0, /* 0000111111 */
+ 0x0f, 0xc0, /* 0000111111 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+
+ /* 214 0xd6 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x1f, 0xc0, /* 0001111111 */
+ 0x1f, 0xc0, /* 0001111111 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+
+ /* 215 0xd7 '.' */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+ 0x1b, 0x00, /* 0001101100 */
+
+ /* 216 0xd8 '.' */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+
+ /* 217 0xd9 '.' */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0xfc, 0x00, /* 1111110000 */
+ 0xfc, 0x00, /* 1111110000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 218 0xda '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0f, 0xc0, /* 0000111111 */
+ 0x0f, 0xc0, /* 0000111111 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+
+ /* 219 0xdb '.' */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+
+ /* 220 0xdc '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+
+ /* 221 0xdd '.' */
+ 0xf8, 0x00, /* 1111100000 */
+ 0xf8, 0x00, /* 1111100000 */
+ 0xf8, 0x00, /* 1111100000 */
+ 0xf8, 0x00, /* 1111100000 */
+ 0xf8, 0x00, /* 1111100000 */
+ 0xf8, 0x00, /* 1111100000 */
+ 0xf8, 0x00, /* 1111100000 */
+ 0xf8, 0x00, /* 1111100000 */
+ 0xf8, 0x00, /* 1111100000 */
+ 0xf8, 0x00, /* 1111100000 */
+ 0xf8, 0x00, /* 1111100000 */
+ 0xf8, 0x00, /* 1111100000 */
+ 0xf8, 0x00, /* 1111100000 */
+ 0xf8, 0x00, /* 1111100000 */
+ 0xf8, 0x00, /* 1111100000 */
+ 0xf8, 0x00, /* 1111100000 */
+ 0xf8, 0x00, /* 1111100000 */
+ 0xf8, 0x00, /* 1111100000 */
+
+ /* 222 0xde '.' */
+ 0x07, 0xc0, /* 0000011111 */
+ 0x07, 0xc0, /* 0000011111 */
+ 0x07, 0xc0, /* 0000011111 */
+ 0x07, 0xc0, /* 0000011111 */
+ 0x07, 0xc0, /* 0000011111 */
+ 0x07, 0xc0, /* 0000011111 */
+ 0x07, 0xc0, /* 0000011111 */
+ 0x07, 0xc0, /* 0000011111 */
+ 0x07, 0xc0, /* 0000011111 */
+ 0x07, 0xc0, /* 0000011111 */
+ 0x07, 0xc0, /* 0000011111 */
+ 0x07, 0xc0, /* 0000011111 */
+ 0x07, 0xc0, /* 0000011111 */
+ 0x07, 0xc0, /* 0000011111 */
+ 0x07, 0xc0, /* 0000011111 */
+ 0x07, 0xc0, /* 0000011111 */
+ 0x07, 0xc0, /* 0000011111 */
+ 0x07, 0xc0, /* 0000011111 */
+
+ /* 223 0xdf '.' */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0xff, 0xc0, /* 1111111111 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 224 0xe0 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x1c, 0x80, /* 0001110010 */
+ 0x35, 0x80, /* 0011010110 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x37, 0x80, /* 0011011110 */
+ 0x1c, 0x80, /* 0001110010 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 225 0xe1 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x6f, 0x00, /* 0110111100 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x6e, 0x00, /* 0110111000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 226 0xe2 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 227 0xe3 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 228 0xe4 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0xff, 0x80, /* 1111111110 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x80, /* 0011000010 */
+ 0x61, 0x80, /* 0110000110 */
+ 0xff, 0x80, /* 1111111110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 229 0xe5 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x1f, 0xc0, /* 0001111111 */
+ 0x36, 0x00, /* 0011011000 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x3e, 0x00, /* 0011111000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 230 0xe6 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x73, 0x80, /* 0111001110 */
+ 0x6d, 0x80, /* 0110110110 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0xc0, 0x00, /* 1100000000 */
+
+ /* 231 0xe7 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x01, 0x80, /* 0000000110 */
+ 0x36, 0x40, /* 0011011001 */
+ 0x5e, 0x00, /* 0101111000 */
+ 0x8c, 0x00, /* 1000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 232 0xe8 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 233 0xe9 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x1f, 0x00, /* 0001111100 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x60, 0xc0, /* 0110000011 */
+ 0x7f, 0xc0, /* 0111111111 */
+ 0x7f, 0xc0, /* 0111111111 */
+ 0x60, 0xc0, /* 0110000011 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x31, 0x80, /* 0011000110 */
+ 0x1f, 0x00, /* 0001111100 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 234 0xea '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x61, 0x80, /* 0110000110 */
+ 0xc0, 0xc0, /* 1100000011 */
+ 0xc0, 0xc0, /* 1100000011 */
+ 0xc0, 0xc0, /* 1100000011 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x33, 0x00, /* 0011001100 */
+ 0xf3, 0xc0, /* 1111001111 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 235 0xeb '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x07, 0x00, /* 0000011100 */
+ 0x1f, 0x80, /* 0001111110 */
+ 0x30, 0xc0, /* 0011000011 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x3e, 0x00, /* 0011111000 */
+ 0x66, 0x00, /* 0110011000 */
+ 0xc3, 0x00, /* 1100001100 */
+ 0xc3, 0x00, /* 1100001100 */
+ 0xc3, 0x00, /* 1100001100 */
+ 0x66, 0x00, /* 0110011000 */
+ 0x3c, 0x00, /* 0011110000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 236 0xec '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x6d, 0x80, /* 0110110110 */
+ 0xcc, 0xc0, /* 1100110011 */
+ 0xcc, 0xc0, /* 1100110011 */
+ 0xcc, 0xc0, /* 1100110011 */
+ 0xcc, 0xc0, /* 1100110011 */
+ 0x6d, 0x80, /* 0110110110 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 237 0xed '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x01, 0x80, /* 0000000110 */
+ 0x01, 0x80, /* 0000000110 */
+ 0x03, 0x00, /* 0000001100 */
+ 0x03, 0x00, /* 0000001100 */
+ 0x37, 0x00, /* 0011011100 */
+ 0x6d, 0x80, /* 0110110110 */
+ 0xcc, 0xc0, /* 1100110011 */
+ 0xcc, 0xc0, /* 1100110011 */
+ 0xcc, 0xc0, /* 1100110011 */
+ 0xcc, 0xc0, /* 1100110011 */
+ 0x6d, 0x80, /* 0110110110 */
+ 0x3b, 0x00, /* 0011101100 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x60, 0x00, /* 0110000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 238 0xee '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x03, 0x80, /* 0000001110 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x3f, 0x80, /* 0011111110 */
+ 0x3f, 0x80, /* 0011111110 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x03, 0x80, /* 0000001110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 239 0xef '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x61, 0x80, /* 0110000110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 240 0xf0 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 241 0xf1 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 242 0xf2 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0xe0, 0x00, /* 1110000000 */
+ 0x38, 0x00, /* 0011100000 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x03, 0x80, /* 0000001110 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x38, 0x00, /* 0011100000 */
+ 0xe0, 0x00, /* 1110000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0xff, 0x00, /* 1111111100 */
+ 0xff, 0x00, /* 1111111100 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 243 0xf3 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x03, 0x80, /* 0000001110 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x38, 0x00, /* 0011100000 */
+ 0xe0, 0x00, /* 1110000000 */
+ 0x38, 0x00, /* 0011100000 */
+ 0x0e, 0x00, /* 0000111000 */
+ 0x03, 0x80, /* 0000001110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0xff, 0x80, /* 1111111110 */
+ 0xff, 0x80, /* 1111111110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 244 0xf4 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x30, 0x00, /* 0011000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 245 0xf5 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x03, 0x00, /* 0000001100 */
+ 0x03, 0x00, /* 0000001100 */
+ 0x03, 0x00, /* 0000001100 */
+ 0x03, 0x00, /* 0000001100 */
+ 0x03, 0x00, /* 0000001100 */
+ 0x03, 0x00, /* 0000001100 */
+ 0x03, 0x00, /* 0000001100 */
+ 0x03, 0x00, /* 0000001100 */
+ 0x03, 0x00, /* 0000001100 */
+ 0x03, 0x00, /* 0000001100 */
+ 0x03, 0x00, /* 0000001100 */
+ 0x03, 0x00, /* 0000001100 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 246 0xf6 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 247 0xf7 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x38, 0x00, /* 0011100000 */
+ 0x6c, 0x00, /* 0110110000 */
+ 0x06, 0xc0, /* 0000011011 */
+ 0x03, 0x80, /* 0000001110 */
+ 0x38, 0x00, /* 0011100000 */
+ 0x6c, 0x00, /* 0110110000 */
+ 0x06, 0xc0, /* 0000011011 */
+ 0x03, 0x80, /* 0000001110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 248 0xf8 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x33, 0x00, /* 0011001100 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 249 0xf9 '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 250 0xfa '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 251 0xfb '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x0f, 0xc0, /* 0000111111 */
+ 0x0f, 0xc0, /* 0000111111 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0xcc, 0x00, /* 1100110000 */
+ 0x6c, 0x00, /* 0110110000 */
+ 0x3c, 0x00, /* 0011110000 */
+ 0x1c, 0x00, /* 0001110000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 252 0xfc '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x27, 0x00, /* 0010011100 */
+ 0x7b, 0x00, /* 0111101100 */
+ 0x31, 0x00, /* 0011000100 */
+ 0x31, 0x00, /* 0011000100 */
+ 0x31, 0x00, /* 0011000100 */
+ 0x7b, 0x80, /* 0111101110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 253 0xfd '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x1e, 0x00, /* 0001111000 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x63, 0x00, /* 0110001100 */
+ 0x43, 0x00, /* 0100001100 */
+ 0x06, 0x00, /* 0000011000 */
+ 0x0c, 0x00, /* 0000110000 */
+ 0x18, 0x00, /* 0001100000 */
+ 0x30, 0x80, /* 0011000010 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x7f, 0x80, /* 0111111110 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 254 0xfe '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x3f, 0x00, /* 0011111100 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+ /* 255 0xff '.' */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+ 0x00, 0x00, /* 0000000000 */
+
+};
+
+
+struct font_desc font_10x18 = {
+ FONT10x18_IDX,
+ "10x18",
+ 10,
+ 18,
+ fontdata_10x18,
+#ifdef __sparc__
+ 5
+#else
+ -1
+#endif
+};
--- /dev/null
+/**************************************/
+/* this file adapted from font_8x16.c */
+/* by Jurriaan Kalkman 05-2005 */
+/**************************************/
+
+#include <linux/font.h>
+
+#define FONTDATAMAX 3584
+
+static unsigned char fontdata_7x14[FONTDATAMAX] = {
+
+ /* 0 0x00 '^@' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 1 0x01 '^A' */
+ 0x00, /* 0000000 */
+ 0x7c, /* 0111110 */
+ 0x82, /* 1000001 */
+ 0xaa, /* 1010101 */
+ 0x82, /* 1000001 */
+ 0x82, /* 1000001 */
+ 0xba, /* 1011101 */
+ 0x92, /* 1001001 */
+ 0x82, /* 1000001 */
+ 0x7c, /* 0111110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 2 0x02 '^B' */
+ 0x00, /* 0000000 */
+ 0x7c, /* 0111110 */
+ 0xfe, /* 1111111 */
+ 0xd6, /* 1101011 */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+ 0xc6, /* 1100011 */
+ 0xee, /* 1110111 */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+ 0x7c, /* 0111110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 3 0x03 '^C' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x6c, /* 0110110 */
+ 0x7c, /* 0111110 */
+ 0xfe, /* 1111111 */
+ 0x7c, /* 0111110 */
+ 0x38, /* 0011100 */
+ 0x18, /* 0001100 */
+ 0x10, /* 0001000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 4 0x04 '^D' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x10, /* 0001000 */
+ 0x38, /* 0011100 */
+ 0x7c, /* 0111110 */
+ 0xfe, /* 1111111 */
+ 0x7c, /* 0111110 */
+ 0x38, /* 0011100 */
+ 0x10, /* 0001000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 5 0x05 '^E' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x38, /* 0011100 */
+ 0x38, /* 0011100 */
+ 0x38, /* 0011100 */
+ 0xee, /* 1110111 */
+ 0xee, /* 1110111 */
+ 0xee, /* 1110111 */
+ 0x10, /* 0001000 */
+ 0x10, /* 0001000 */
+ 0x38, /* 0011100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 6 0x06 '^F' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x10, /* 0001000 */
+ 0x38, /* 0011100 */
+ 0x7c, /* 0111110 */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+ 0x7c, /* 0111110 */
+ 0x10, /* 0001000 */
+ 0x10, /* 0001000 */
+ 0x38, /* 0011100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 7 0x07 '^G' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x18, /* 0001100 */
+ 0x3c, /* 0011110 */
+ 0x3c, /* 0011110 */
+ 0x18, /* 0001100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 8 0x08 '^H' */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+ 0xe6, /* 1110011 */
+ 0xc2, /* 1100001 */
+ 0xc2, /* 1100001 */
+ 0xe6, /* 1110011 */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+
+ /* 9 0x09 '^I' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x38, /* 0011100 */
+ 0x6c, /* 0110110 */
+ 0x44, /* 0100010 */
+ 0x6c, /* 0110110 */
+ 0x38, /* 0011100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 10 0x0a '^J' */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+ 0xc6, /* 1100011 */
+ 0x92, /* 1001001 */
+ 0xba, /* 1011101 */
+ 0x92, /* 1001001 */
+ 0xc6, /* 1100011 */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+
+ /* 11 0x0b '^K' */
+ 0x00, /* 0000000 */
+ 0x1e, /* 0001111 */
+ 0x0e, /* 0000111 */
+ 0x1a, /* 0001101 */
+ 0x1a, /* 0001101 */
+ 0x78, /* 0111100 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x78, /* 0111100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 12 0x0c '^L' */
+ 0x00, /* 0000000 */
+ 0x3c, /* 0011110 */
+ 0x66, /* 0110011 */
+ 0x66, /* 0110011 */
+ 0x66, /* 0110011 */
+ 0x66, /* 0110011 */
+ 0x3c, /* 0011110 */
+ 0x18, /* 0001100 */
+ 0x7e, /* 0111111 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 13 0x0d '^M' */
+ 0x00, /* 0000000 */
+ 0x3e, /* 0011111 */
+ 0x36, /* 0011011 */
+ 0x3e, /* 0011111 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x70, /* 0111000 */
+ 0xf0, /* 1111000 */
+ 0xe0, /* 1110000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 14 0x0e '^N' */
+ 0x00, /* 0000000 */
+ 0x7e, /* 0111111 */
+ 0x66, /* 0110011 */
+ 0x7e, /* 0111111 */
+ 0x66, /* 0110011 */
+ 0x66, /* 0110011 */
+ 0x66, /* 0110011 */
+ 0x66, /* 0110011 */
+ 0x6e, /* 0110111 */
+ 0xee, /* 1110111 */
+ 0xec, /* 1110110 */
+ 0xc0, /* 1100000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 15 0x0f '^O' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x10, /* 0001000 */
+ 0x10, /* 0001000 */
+ 0xd6, /* 1101011 */
+ 0x38, /* 0011100 */
+ 0xee, /* 1110111 */
+ 0x38, /* 0011100 */
+ 0xd6, /* 1101011 */
+ 0x10, /* 0001000 */
+ 0x10, /* 0001000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 16 0x10 '^P' */
+ 0x00, /* 0000000 */
+ 0x80, /* 1000000 */
+ 0xc0, /* 1100000 */
+ 0xe0, /* 1110000 */
+ 0xf0, /* 1111000 */
+ 0xfc, /* 1111110 */
+ 0xf0, /* 1111000 */
+ 0xe0, /* 1110000 */
+ 0xc0, /* 1100000 */
+ 0x80, /* 1000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 17 0x11 '^Q' */
+ 0x00, /* 0000000 */
+ 0x04, /* 0000010 */
+ 0x0c, /* 0000110 */
+ 0x1c, /* 0001110 */
+ 0x3c, /* 0011110 */
+ 0xfc, /* 1111110 */
+ 0x3c, /* 0011110 */
+ 0x1c, /* 0001110 */
+ 0x0c, /* 0000110 */
+ 0x04, /* 0000010 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 18 0x12 '^R' */
+ 0x00, /* 0000000 */
+ 0x18, /* 0001100 */
+ 0x3c, /* 0011110 */
+ 0x7e, /* 0111111 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x7e, /* 0111111 */
+ 0x3c, /* 0011110 */
+ 0x18, /* 0001100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 19 0x13 '^S' */
+ 0x00, /* 0000000 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x00, /* 0000000 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 20 0x14 '^T' */
+ 0x00, /* 0000000 */
+ 0x7e, /* 0111111 */
+ 0xd4, /* 1101010 */
+ 0xd4, /* 1101010 */
+ 0xd4, /* 1101010 */
+ 0x74, /* 0111010 */
+ 0x14, /* 0001010 */
+ 0x14, /* 0001010 */
+ 0x14, /* 0001010 */
+ 0x14, /* 0001010 */
+ 0x16, /* 0001011 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 21 0x15 '^U' */
+ 0x78, /* 0111100 */
+ 0xcc, /* 1100110 */
+ 0x60, /* 0110000 */
+ 0x38, /* 0011100 */
+ 0x6c, /* 0110110 */
+ 0xc6, /* 1100011 */
+ 0xc6, /* 1100011 */
+ 0x6c, /* 0110110 */
+ 0x38, /* 0011100 */
+ 0x18, /* 0001100 */
+ 0xcc, /* 1100110 */
+ 0x78, /* 0111100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 22 0x16 '^V' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0xfc, /* 1111110 */
+ 0xfc, /* 1111110 */
+ 0xfc, /* 1111110 */
+ 0xfc, /* 1111110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 23 0x17 '^W' */
+ 0x00, /* 0000000 */
+ 0x18, /* 0001100 */
+ 0x3c, /* 0011110 */
+ 0x7e, /* 0111111 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x7e, /* 0111111 */
+ 0x3c, /* 0011110 */
+ 0x18, /* 0001100 */
+ 0x7e, /* 0111111 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 24 0x18 '^X' */
+ 0x00, /* 0000000 */
+ 0x18, /* 0001100 */
+ 0x3c, /* 0011110 */
+ 0x7e, /* 0111111 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 25 0x19 '^Y' */
+ 0x00, /* 0000000 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x7e, /* 0111111 */
+ 0x3c, /* 0011110 */
+ 0x18, /* 0001100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 26 0x1a '^Z' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x30, /* 0011000 */
+ 0x18, /* 0001100 */
+ 0xfc, /* 1111110 */
+ 0x18, /* 0001100 */
+ 0x30, /* 0011000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 27 0x1b '^[' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x30, /* 0011000 */
+ 0x60, /* 0110000 */
+ 0xfc, /* 1111110 */
+ 0x60, /* 0110000 */
+ 0x30, /* 0011000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 28 0x1c '^\' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xfc, /* 1111110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 29 0x1d '^]' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x28, /* 0010100 */
+ 0x6c, /* 0110110 */
+ 0xfe, /* 1111111 */
+ 0x6c, /* 0110110 */
+ 0x28, /* 0010100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 30 0x1e '^^' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x78, /* 0111100 */
+ 0x78, /* 0111100 */
+ 0xfc, /* 1111110 */
+ 0xfc, /* 1111110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 31 0x1f '^_' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0xfc, /* 1111110 */
+ 0xfc, /* 1111110 */
+ 0x78, /* 0111100 */
+ 0x78, /* 0111100 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 32 0x20 ' ' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 33 0x21 '!' */
+ 0x00, /* 0000000 */
+ 0x18, /* 0001100 */
+ 0x3c, /* 0011110 */
+ 0x3c, /* 0011110 */
+ 0x3c, /* 0011110 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x00, /* 0000000 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 34 0x22 '"' */
+ 0x00, /* 0000000 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x28, /* 0010100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 35 0x23 '#' */
+ 0x00, /* 0000000 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 36 0x24 '$' */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x78, /* 0111100 */
+ 0xcc, /* 1100110 */
+ 0xc4, /* 1100010 */
+ 0xc0, /* 1100000 */
+ 0x78, /* 0111100 */
+ 0x0c, /* 0000110 */
+ 0x8c, /* 1000110 */
+ 0xcc, /* 1100110 */
+ 0x78, /* 0111100 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x00, /* 0000000 */
+
+ /* 37 0x25 '%' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0xc0, /* 1100000 */
+ 0xc4, /* 1100010 */
+ 0x0c, /* 0000110 */
+ 0x18, /* 0001100 */
+ 0x30, /* 0011000 */
+ 0x60, /* 0110000 */
+ 0xcc, /* 1100110 */
+ 0x8c, /* 1000110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 38 0x26 '&' */
+ 0x00, /* 0000000 */
+ 0x38, /* 0011100 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x38, /* 0011100 */
+ 0x78, /* 0111100 */
+ 0xde, /* 1101111 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xdc, /* 1101110 */
+ 0x76, /* 0111011 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 39 0x27 ''' */
+ 0x00, /* 0000000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x60, /* 0110000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 40 0x28 '(' */
+ 0x00, /* 0000000 */
+ 0x0c, /* 0000110 */
+ 0x18, /* 0001100 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x18, /* 0001100 */
+ 0x0c, /* 0000110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 41 0x29 ')' */
+ 0x00, /* 0000000 */
+ 0x30, /* 0011000 */
+ 0x18, /* 0001100 */
+ 0x0c, /* 0000110 */
+ 0x0c, /* 0000110 */
+ 0x0c, /* 0000110 */
+ 0x0c, /* 0000110 */
+ 0x0c, /* 0000110 */
+ 0x0c, /* 0000110 */
+ 0x18, /* 0001100 */
+ 0x30, /* 0011000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 42 0x2a '*' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x6c, /* 0110110 */
+ 0x38, /* 0011100 */
+ 0xfe, /* 1111111 */
+ 0x38, /* 0011100 */
+ 0x6c, /* 0110110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 43 0x2b '+' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x10, /* 0001000 */
+ 0x10, /* 0001000 */
+ 0x7c, /* 0111110 */
+ 0x10, /* 0001000 */
+ 0x10, /* 0001000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 44 0x2c ',' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x30, /* 0011000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 45 0x2d '-' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0xfc, /* 1111110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 46 0x2e '.' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 47 0x2f '/' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x04, /* 0000010 */
+ 0x0c, /* 0000110 */
+ 0x18, /* 0001100 */
+ 0x30, /* 0011000 */
+ 0x60, /* 0110000 */
+ 0xc0, /* 1100000 */
+ 0x80, /* 1000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 48 0x30 '0' */
+ 0x00, /* 0000000 */
+ 0x30, /* 0011000 */
+ 0x78, /* 0111100 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xdc, /* 1101110 */
+ 0xec, /* 1110110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x78, /* 0111100 */
+ 0x30, /* 0011000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 49 0x31 '1' */
+ 0x00, /* 0000000 */
+ 0x18, /* 0001100 */
+ 0x38, /* 0011100 */
+ 0x78, /* 0111100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x7c, /* 0111110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 50 0x32 '2' */
+ 0x00, /* 0000000 */
+ 0x78, /* 0111100 */
+ 0xcc, /* 1100110 */
+ 0x0c, /* 0000110 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x30, /* 0011000 */
+ 0x60, /* 0110000 */
+ 0xc0, /* 1100000 */
+ 0xcc, /* 1100110 */
+ 0xfc, /* 1111110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 51 0x33 '3' */
+ 0x00, /* 0000000 */
+ 0x78, /* 0111100 */
+ 0xcc, /* 1100110 */
+ 0x0c, /* 0000110 */
+ 0x0c, /* 0000110 */
+ 0x38, /* 0011100 */
+ 0x0c, /* 0000110 */
+ 0x0c, /* 0000110 */
+ 0x0c, /* 0000110 */
+ 0xcc, /* 1100110 */
+ 0x78, /* 0111100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 52 0x34 '4' */
+ 0x00, /* 0000000 */
+ 0x0c, /* 0000110 */
+ 0x1c, /* 0001110 */
+ 0x3c, /* 0011110 */
+ 0x6c, /* 0110110 */
+ 0xcc, /* 1100110 */
+ 0xfe, /* 1111111 */
+ 0x0c, /* 0000110 */
+ 0x0c, /* 0000110 */
+ 0x0c, /* 0000110 */
+ 0x0c, /* 0000110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 53 0x35 '5' */
+ 0x00, /* 0000000 */
+ 0xfc, /* 1111110 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xf8, /* 1111100 */
+ 0x0c, /* 0000110 */
+ 0x0c, /* 0000110 */
+ 0x0c, /* 0000110 */
+ 0xcc, /* 1100110 */
+ 0x78, /* 0111100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 54 0x36 '6' */
+ 0x00, /* 0000000 */
+ 0x30, /* 0011000 */
+ 0x60, /* 0110000 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xf8, /* 1111100 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x78, /* 0111100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 55 0x37 '7' */
+ 0x00, /* 0000000 */
+ 0xfc, /* 1111110 */
+ 0xcc, /* 1100110 */
+ 0x0c, /* 0000110 */
+ 0x0c, /* 0000110 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 56 0x38 '8' */
+ 0x00, /* 0000000 */
+ 0x78, /* 0111100 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x78, /* 0111100 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x78, /* 0111100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 57 0x39 '9' */
+ 0x00, /* 0000000 */
+ 0x78, /* 0111100 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x7c, /* 0111110 */
+ 0x0c, /* 0000110 */
+ 0x0c, /* 0000110 */
+ 0x0c, /* 0000110 */
+ 0x18, /* 0001100 */
+ 0x70, /* 0111000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 58 0x3a ':' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 59 0x3b ';' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x30, /* 0011000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 60 0x3c '<' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x04, /* 0000010 */
+ 0x0c, /* 0000110 */
+ 0x18, /* 0001100 */
+ 0x30, /* 0011000 */
+ 0x60, /* 0110000 */
+ 0x30, /* 0011000 */
+ 0x18, /* 0001100 */
+ 0x0c, /* 0000110 */
+ 0x04, /* 0000010 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 61 0x3d '=' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x7c, /* 0111110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x7c, /* 0111110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 62 0x3e '>' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x40, /* 0100000 */
+ 0x60, /* 0110000 */
+ 0x30, /* 0011000 */
+ 0x18, /* 0001100 */
+ 0x0c, /* 0000110 */
+ 0x18, /* 0001100 */
+ 0x30, /* 0011000 */
+ 0x60, /* 0110000 */
+ 0x40, /* 0100000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 63 0x3f '?' */
+ 0x00, /* 0000000 */
+ 0x78, /* 0111100 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x18, /* 0001100 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x00, /* 0000000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 64 0x40 '@' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x78, /* 0111100 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xdc, /* 1101110 */
+ 0xdc, /* 1101110 */
+ 0xd8, /* 1101100 */
+ 0xc0, /* 1100000 */
+ 0x78, /* 0111100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 65 0x41 'A' */
+ 0x00, /* 0000000 */
+ 0x30, /* 0011000 */
+ 0x78, /* 0111100 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xfc, /* 1111110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 66 0x42 'B' */
+ 0x00, /* 0000000 */
+ 0xf8, /* 1111100 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x78, /* 0111100 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0xf8, /* 1111100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 67 0x43 'C' */
+ 0x00, /* 0000000 */
+ 0x38, /* 0011100 */
+ 0x6c, /* 0110110 */
+ 0xc4, /* 1100010 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xc4, /* 1100010 */
+ 0x6c, /* 0110110 */
+ 0x38, /* 0011100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 68 0x44 'D' */
+ 0x00, /* 0000000 */
+ 0xf0, /* 1111000 */
+ 0xd8, /* 1101100 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xd8, /* 1101100 */
+ 0xf0, /* 1111000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 69 0x45 'E' */
+ 0x00, /* 0000000 */
+ 0x7c, /* 0111110 */
+ 0x6c, /* 0110110 */
+ 0x64, /* 0110010 */
+ 0x68, /* 0110100 */
+ 0x78, /* 0111100 */
+ 0x68, /* 0110100 */
+ 0x60, /* 0110000 */
+ 0x64, /* 0110010 */
+ 0x6c, /* 0110110 */
+ 0x7c, /* 0111110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 70 0x46 'F' */
+ 0x00, /* 0000000 */
+ 0x7c, /* 0111110 */
+ 0x64, /* 0110010 */
+ 0x60, /* 0110000 */
+ 0x68, /* 0110100 */
+ 0x78, /* 0111100 */
+ 0x68, /* 0110100 */
+ 0x60, /* 0110000 */
+ 0x60, /* 0110000 */
+ 0x60, /* 0110000 */
+ 0x70, /* 0111000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 71 0x47 'G' */
+ 0x00, /* 0000000 */
+ 0x38, /* 0011100 */
+ 0x6c, /* 0110110 */
+ 0xc4, /* 1100010 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xdc, /* 1101110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x6c, /* 0110110 */
+ 0x34, /* 0011010 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 72 0x48 'H' */
+ 0x00, /* 0000000 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xfc, /* 1111110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 73 0x49 'I' */
+ 0x00, /* 0000000 */
+ 0x3c, /* 0011110 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x3c, /* 0011110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 74 0x4a 'J' */
+ 0x00, /* 0000000 */
+ 0x1c, /* 0001110 */
+ 0x0c, /* 0000110 */
+ 0x0c, /* 0000110 */
+ 0x0c, /* 0000110 */
+ 0x0c, /* 0000110 */
+ 0x0c, /* 0000110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x78, /* 0111100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 75 0x4b 'K' */
+ 0x00, /* 0000000 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xd8, /* 1101100 */
+ 0xf0, /* 1111000 */
+ 0xf0, /* 1111000 */
+ 0xd8, /* 1101100 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 76 0x4c 'L' */
+ 0x00, /* 0000000 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xc4, /* 1100010 */
+ 0xcc, /* 1100110 */
+ 0xfc, /* 1111110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 77 0x4d 'M' */
+ 0x00, /* 0000000 */
+ 0xc6, /* 1100011 */
+ 0xee, /* 1110111 */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+ 0xd6, /* 1101011 */
+ 0xc6, /* 1100011 */
+ 0xc6, /* 1100011 */
+ 0xc6, /* 1100011 */
+ 0xc6, /* 1100011 */
+ 0xc6, /* 1100011 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 78 0x4e 'N' */
+ 0x00, /* 0000000 */
+ 0xcc, /* 1100110 */
+ 0xec, /* 1110110 */
+ 0xec, /* 1110110 */
+ 0xfc, /* 1111110 */
+ 0xdc, /* 1101110 */
+ 0xdc, /* 1101110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 79 0x4f 'O' */
+ 0x00, /* 0000000 */
+ 0x78, /* 0111100 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x78, /* 0111100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 80 0x50 'P' */
+ 0x00, /* 0000000 */
+ 0xf8, /* 1111100 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xf8, /* 1111100 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 81 0x51 'Q' */
+ 0x00, /* 0000000 */
+ 0x78, /* 0111100 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xdc, /* 1101110 */
+ 0x78, /* 0111100 */
+ 0x18, /* 0001100 */
+ 0x1c, /* 0001110 */
+ 0x00, /* 0000000 */
+
+ /* 82 0x52 'R' */
+ 0x00, /* 0000000 */
+ 0xf8, /* 1111100 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xf8, /* 1111100 */
+ 0xd8, /* 1101100 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 83 0x53 'S' */
+ 0x00, /* 0000000 */
+ 0x7c, /* 0111110 */
+ 0xc4, /* 1100010 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0x60, /* 0110000 */
+ 0x38, /* 0011100 */
+ 0x0c, /* 0000110 */
+ 0x0c, /* 0000110 */
+ 0x8c, /* 1000110 */
+ 0xf8, /* 1111100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 84 0x54 'T' */
+ 0x00, /* 0000000 */
+ 0xfc, /* 1111110 */
+ 0xfc, /* 1111110 */
+ 0xb4, /* 1011010 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x78, /* 0111100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 85 0x55 'U' */
+ 0x00, /* 0000000 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x78, /* 0111100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 86 0x56 'V' */
+ 0x00, /* 0000000 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x78, /* 0111100 */
+ 0x78, /* 0111100 */
+ 0x30, /* 0011000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 87 0x57 'W' */
+ 0x00, /* 0000000 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xfc, /* 1111110 */
+ 0xfc, /* 1111110 */
+ 0x48, /* 0100100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 88 0x58 'X' */
+ 0x00, /* 0000000 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x78, /* 0111100 */
+ 0x78, /* 0111100 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x78, /* 0111100 */
+ 0x78, /* 0111100 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 89 0x59 'Y' */
+ 0x00, /* 0000000 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x78, /* 0111100 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 90 0x5a 'Z' */
+ 0x00, /* 0000000 */
+ 0xfc, /* 1111110 */
+ 0xcc, /* 1100110 */
+ 0x8c, /* 1000110 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x30, /* 0011000 */
+ 0x60, /* 0110000 */
+ 0xc4, /* 1100010 */
+ 0xcc, /* 1100110 */
+ 0xfc, /* 1111110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 91 0x5b '[' */
+ 0x00, /* 0000000 */
+ 0x78, /* 0111100 */
+ 0x60, /* 0110000 */
+ 0x60, /* 0110000 */
+ 0x60, /* 0110000 */
+ 0x60, /* 0110000 */
+ 0x60, /* 0110000 */
+ 0x60, /* 0110000 */
+ 0x60, /* 0110000 */
+ 0x60, /* 0110000 */
+ 0x78, /* 0111100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 92 0x5c '\' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x80, /* 1000000 */
+ 0xc0, /* 1100000 */
+ 0xe0, /* 1110000 */
+ 0x70, /* 0111000 */
+ 0x38, /* 0011100 */
+ 0x1c, /* 0001110 */
+ 0x0c, /* 0000110 */
+ 0x04, /* 0000010 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 93 0x5d ']' */
+ 0x00, /* 0000000 */
+ 0x78, /* 0111100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x78, /* 0111100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 94 0x5e '^' */
+ 0x10, /* 0001000 */
+ 0x38, /* 0011100 */
+ 0x6c, /* 0110110 */
+ 0xc6, /* 1100011 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 95 0x5f '_' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0xfe, /* 1111111 */
+ 0x00, /* 0000000 */
+
+ /* 96 0x60 '`' */
+ 0x00, /* 0000000 */
+ 0x60, /* 0110000 */
+ 0x30, /* 0011000 */
+ 0x18, /* 0001100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 97 0x61 'a' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x78, /* 0111100 */
+ 0x0c, /* 0000110 */
+ 0x7c, /* 0111110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x76, /* 0111011 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 98 0x62 'b' */
+ 0x00, /* 0000000 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xf0, /* 1111000 */
+ 0xd8, /* 1101100 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xf8, /* 1111100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 99 0x63 'c' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x78, /* 0111100 */
+ 0xcc, /* 1100110 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xcc, /* 1100110 */
+ 0x78, /* 0111100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 100 0x64 'd' */
+ 0x00, /* 0000000 */
+ 0x1c, /* 0001110 */
+ 0x0c, /* 0000110 */
+ 0x0c, /* 0000110 */
+ 0x3c, /* 0011110 */
+ 0x6c, /* 0110110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x76, /* 0111011 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 101 0x65 'e' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x78, /* 0111100 */
+ 0xcc, /* 1100110 */
+ 0xfc, /* 1111110 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xcc, /* 1100110 */
+ 0x78, /* 0111100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 102 0x66 'f' */
+ 0x00, /* 0000000 */
+ 0x38, /* 0011100 */
+ 0x6c, /* 0110110 */
+ 0x64, /* 0110010 */
+ 0x60, /* 0110000 */
+ 0xf0, /* 1111000 */
+ 0x60, /* 0110000 */
+ 0x60, /* 0110000 */
+ 0x60, /* 0110000 */
+ 0x60, /* 0110000 */
+ 0xf0, /* 1111000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 103 0x67 'g' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x76, /* 0111011 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x7c, /* 0111110 */
+ 0x0c, /* 0000110 */
+ 0xcc, /* 1100110 */
+ 0x78, /* 0111100 */
+
+ /* 104 0x68 'h' */
+ 0x00, /* 0000000 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xd8, /* 1101100 */
+ 0xec, /* 1110110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 105 0x69 'i' */
+ 0x00, /* 0000000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x00, /* 0000000 */
+ 0x70, /* 0111000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x78, /* 0111100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 106 0x6a 'j' */
+ 0x00, /* 0000000 */
+ 0x0c, /* 0000110 */
+ 0x0c, /* 0000110 */
+ 0x00, /* 0000000 */
+ 0x1c, /* 0001110 */
+ 0x0c, /* 0000110 */
+ 0x0c, /* 0000110 */
+ 0x0c, /* 0000110 */
+ 0x0c, /* 0000110 */
+ 0x0c, /* 0000110 */
+ 0x0c, /* 0000110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x78, /* 0111100 */
+
+ /* 107 0x6b 'k' */
+ 0x00, /* 0000000 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xcc, /* 1100110 */
+ 0xd8, /* 1101100 */
+ 0xf0, /* 1111000 */
+ 0xf0, /* 1111000 */
+ 0xd8, /* 1101100 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 108 0x6c 'l' */
+ 0x00, /* 0000000 */
+ 0x70, /* 0111000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x78, /* 0111100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 109 0x6d 'm' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0xec, /* 1110110 */
+ 0xfe, /* 1111111 */
+ 0xd6, /* 1101011 */
+ 0xd6, /* 1101011 */
+ 0xd6, /* 1101011 */
+ 0xd6, /* 1101011 */
+ 0xd6, /* 1101011 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 110 0x6e 'n' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0xb8, /* 1011100 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 111 0x6f 'o' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x78, /* 0111100 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x78, /* 0111100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 112 0x70 'p' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0xb8, /* 1011100 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xf8, /* 1111100 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+
+ /* 113 0x71 'q' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x74, /* 0111010 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x7c, /* 0111110 */
+ 0x0c, /* 0000110 */
+ 0x0c, /* 0000110 */
+ 0x0c, /* 0000110 */
+
+ /* 114 0x72 'r' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0xb8, /* 1011100 */
+ 0xec, /* 1110110 */
+ 0xcc, /* 1100110 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 115 0x73 's' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x78, /* 0111100 */
+ 0xcc, /* 1100110 */
+ 0x60, /* 0110000 */
+ 0x30, /* 0011000 */
+ 0x18, /* 0001100 */
+ 0xcc, /* 1100110 */
+ 0x78, /* 0111100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 116 0x74 't' */
+ 0x00, /* 0000000 */
+ 0x10, /* 0001000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0xfc, /* 1111110 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x36, /* 0011011 */
+ 0x1c, /* 0001110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 117 0x75 'u' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x76, /* 0111011 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 118 0x76 'v' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x78, /* 0111100 */
+ 0x30, /* 0011000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 119 0x77 'w' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0xc6, /* 1100011 */
+ 0xc6, /* 1100011 */
+ 0xd6, /* 1101011 */
+ 0xd6, /* 1101011 */
+ 0xd6, /* 1101011 */
+ 0xfe, /* 1111111 */
+ 0x6c, /* 0110110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 120 0x78 'x' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x78, /* 0111100 */
+ 0x30, /* 0011000 */
+ 0x78, /* 0111100 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 121 0x79 'y' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x7c, /* 0111110 */
+ 0x0c, /* 0000110 */
+ 0x18, /* 0001100 */
+ 0xf0, /* 1111000 */
+
+ /* 122 0x7a 'z' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0xfc, /* 1111110 */
+ 0xcc, /* 1100110 */
+ 0x18, /* 0001100 */
+ 0x30, /* 0011000 */
+ 0x60, /* 0110000 */
+ 0xcc, /* 1100110 */
+ 0xfc, /* 1111110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 123 0x7b '{' */
+ 0x00, /* 0000000 */
+ 0x1c, /* 0001110 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0xe0, /* 1110000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x1c, /* 0001110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 124 0x7c '|' */
+ 0x00, /* 0000000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 125 0x7d '}' */
+ 0x00, /* 0000000 */
+ 0x70, /* 0111000 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x0e, /* 0000111 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x70, /* 0111000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 126 0x7e '~' */
+ 0x00, /* 0000000 */
+ 0xec, /* 1110110 */
+ 0xb8, /* 1011100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 127 0x7f '\7f' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x10, /* 0001000 */
+ 0x38, /* 0011100 */
+ 0x6c, /* 0110110 */
+ 0xc6, /* 1100011 */
+ 0xc6, /* 1100011 */
+ 0xc6, /* 1100011 */
+ 0xfe, /* 1111111 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 128 0x80 '\80' */
+ 0x00, /* 0000000 */
+ 0x38, /* 0011100 */
+ 0x6c, /* 0110110 */
+ 0xc4, /* 1100010 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xc4, /* 1100010 */
+ 0x6c, /* 0110110 */
+ 0x38, /* 0011100 */
+ 0x18, /* 0001100 */
+ 0x70, /* 0111000 */
+ 0x00, /* 0000000 */
+
+ /* 129 0x81 '\81' */
+ 0x00, /* 0000000 */
+ 0xcc, /* 1100110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x76, /* 0111011 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 130 0x82 '\82' */
+ 0x0c, /* 0000110 */
+ 0x18, /* 0001100 */
+ 0x30, /* 0011000 */
+ 0x00, /* 0000000 */
+ 0x78, /* 0111100 */
+ 0xcc, /* 1100110 */
+ 0xfc, /* 1111110 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xcc, /* 1100110 */
+ 0x78, /* 0111100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 131 0x83 '\83' */
+ 0x10, /* 0001000 */
+ 0x38, /* 0011100 */
+ 0x6c, /* 0110110 */
+ 0x00, /* 0000000 */
+ 0x78, /* 0111100 */
+ 0x0c, /* 0000110 */
+ 0x7c, /* 0111110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x76, /* 0111011 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 132 0x84 '\84' */
+ 0x00, /* 0000000 */
+ 0xcc, /* 1100110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x78, /* 0111100 */
+ 0x0c, /* 0000110 */
+ 0x7c, /* 0111110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x76, /* 0111011 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 133 0x85 '\85' */
+ 0x60, /* 0110000 */
+ 0x30, /* 0011000 */
+ 0x18, /* 0001100 */
+ 0x00, /* 0000000 */
+ 0x78, /* 0111100 */
+ 0x0c, /* 0000110 */
+ 0x7c, /* 0111110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x76, /* 0111011 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 134 0x86 '\86' */
+ 0x38, /* 0011100 */
+ 0x6c, /* 0110110 */
+ 0x38, /* 0011100 */
+ 0x00, /* 0000000 */
+ 0x78, /* 0111100 */
+ 0x0c, /* 0000110 */
+ 0x7c, /* 0111110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x76, /* 0111011 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 135 0x87 '\87' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x78, /* 0111100 */
+ 0xcc, /* 1100110 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xcc, /* 1100110 */
+ 0x78, /* 0111100 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0xe0, /* 1110000 */
+
+ /* 136 0x88 '\88' */
+ 0x10, /* 0001000 */
+ 0x38, /* 0011100 */
+ 0x6c, /* 0110110 */
+ 0x00, /* 0000000 */
+ 0x78, /* 0111100 */
+ 0xcc, /* 1100110 */
+ 0xfc, /* 1111110 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xcc, /* 1100110 */
+ 0x78, /* 0111100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 137 0x89 '\89' */
+ 0x00, /* 0000000 */
+ 0xcc, /* 1100110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x78, /* 0111100 */
+ 0xcc, /* 1100110 */
+ 0xfc, /* 1111110 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xcc, /* 1100110 */
+ 0x78, /* 0111100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 138 0x8a '\8a' */
+ 0xc0, /* 1100000 */
+ 0x60, /* 0110000 */
+ 0x30, /* 0011000 */
+ 0x00, /* 0000000 */
+ 0x78, /* 0111100 */
+ 0xcc, /* 1100110 */
+ 0xfc, /* 1111110 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xcc, /* 1100110 */
+ 0x78, /* 0111100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 139 0x8b '\8b' */
+ 0x00, /* 0000000 */
+ 0x6c, /* 0110110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x38, /* 0011100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x3c, /* 0011110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 140 0x8c '\8c' */
+ 0x30, /* 0011000 */
+ 0x78, /* 0111100 */
+ 0xcc, /* 1100110 */
+ 0x00, /* 0000000 */
+ 0x70, /* 0111000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x78, /* 0111100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 141 0x8d '\8d' */
+ 0xc0, /* 1100000 */
+ 0x60, /* 0110000 */
+ 0x30, /* 0011000 */
+ 0x00, /* 0000000 */
+ 0x70, /* 0111000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x78, /* 0111100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 142 0x8e '\8e' */
+ 0x00, /* 0000000 */
+ 0xcc, /* 1100110 */
+ 0x00, /* 0000000 */
+ 0x30, /* 0011000 */
+ 0x78, /* 0111100 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xfc, /* 1111110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 143 0x8f '\8f' */
+ 0x30, /* 0011000 */
+ 0x48, /* 0100100 */
+ 0x48, /* 0100100 */
+ 0x30, /* 0011000 */
+ 0x78, /* 0111100 */
+ 0xcc, /* 1100110 */
+ 0xfc, /* 1111110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 144 0x90 '\90' */
+ 0x18, /* 0001100 */
+ 0x30, /* 0011000 */
+ 0xfc, /* 1111110 */
+ 0xcc, /* 1100110 */
+ 0xc4, /* 1100010 */
+ 0xd0, /* 1101000 */
+ 0xf0, /* 1111000 */
+ 0xd0, /* 1101000 */
+ 0xc4, /* 1100010 */
+ 0xcc, /* 1100110 */
+ 0xfc, /* 1111110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 145 0x91 '\91' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0xec, /* 1110110 */
+ 0x36, /* 0011011 */
+ 0x36, /* 0011011 */
+ 0x7e, /* 0111111 */
+ 0xd8, /* 1101100 */
+ 0xd8, /* 1101100 */
+ 0x6e, /* 0110111 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 146 0x92 '\92' */
+ 0x00, /* 0000000 */
+ 0x3e, /* 0011111 */
+ 0x6c, /* 0110110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xfe, /* 1111111 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xce, /* 1100111 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 147 0x93 '\93' */
+ 0x10, /* 0001000 */
+ 0x38, /* 0011100 */
+ 0x6c, /* 0110110 */
+ 0x00, /* 0000000 */
+ 0x78, /* 0111100 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x78, /* 0111100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 148 0x94 '\94' */
+ 0x00, /* 0000000 */
+ 0xcc, /* 1100110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x78, /* 0111100 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x78, /* 0111100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 149 0x95 '\95' */
+ 0xc0, /* 1100000 */
+ 0x60, /* 0110000 */
+ 0x30, /* 0011000 */
+ 0x00, /* 0000000 */
+ 0x78, /* 0111100 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x78, /* 0111100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 150 0x96 '\96' */
+ 0x30, /* 0011000 */
+ 0x78, /* 0111100 */
+ 0xcc, /* 1100110 */
+ 0x00, /* 0000000 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x76, /* 0111011 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 151 0x97 '\97' */
+ 0x60, /* 0110000 */
+ 0x30, /* 0011000 */
+ 0x18, /* 0001100 */
+ 0x00, /* 0000000 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x76, /* 0111011 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 152 0x98 '\98' */
+ 0x00, /* 0000000 */
+ 0xcc, /* 1100110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x7c, /* 0111110 */
+ 0x0c, /* 0000110 */
+ 0x18, /* 0001100 */
+ 0x70, /* 0111000 */
+
+ /* 153 0x99 '\99' */
+ 0xcc, /* 1100110 */
+ 0x00, /* 0000000 */
+ 0x78, /* 0111100 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x78, /* 0111100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 154 0x9a '\9a' */
+ 0xcc, /* 1100110 */
+ 0x00, /* 0000000 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x78, /* 0111100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 155 0x9b '\9b' */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x7c, /* 0111110 */
+ 0xcc, /* 1100110 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xcc, /* 1100110 */
+ 0x7c, /* 0111110 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 156 0x9c '\9c' */
+ 0x38, /* 0011100 */
+ 0x6c, /* 0110110 */
+ 0x64, /* 0110010 */
+ 0x60, /* 0110000 */
+ 0xf0, /* 1111000 */
+ 0x60, /* 0110000 */
+ 0x60, /* 0110000 */
+ 0x60, /* 0110000 */
+ 0x60, /* 0110000 */
+ 0xe6, /* 1110011 */
+ 0xfc, /* 1111110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 157 0x9d '\9d' */
+ 0x00, /* 0000000 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x78, /* 0111100 */
+ 0x30, /* 0011000 */
+ 0xfc, /* 1111110 */
+ 0x30, /* 0011000 */
+ 0xfc, /* 1111110 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 158 0x9e '\9e' */
+ 0xf8, /* 1111100 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xf8, /* 1111100 */
+ 0xc4, /* 1100010 */
+ 0xcc, /* 1100110 */
+ 0xde, /* 1101111 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xc6, /* 1100011 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 159 0x9f '\9f' */
+ 0x1c, /* 0001110 */
+ 0x36, /* 0011011 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0xfc, /* 1111110 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0xb0, /* 1011000 */
+ 0xe0, /* 1110000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 160 0xa0 ' ' */
+ 0x18, /* 0001100 */
+ 0x30, /* 0011000 */
+ 0x60, /* 0110000 */
+ 0x00, /* 0000000 */
+ 0x78, /* 0111100 */
+ 0x0c, /* 0000110 */
+ 0x7c, /* 0111110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x76, /* 0111011 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 161 0xa1 '¡' */
+ 0x18, /* 0001100 */
+ 0x30, /* 0011000 */
+ 0x60, /* 0110000 */
+ 0x00, /* 0000000 */
+ 0x70, /* 0111000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x78, /* 0111100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 162 0xa2 '¢' */
+ 0x18, /* 0001100 */
+ 0x30, /* 0011000 */
+ 0x60, /* 0110000 */
+ 0x00, /* 0000000 */
+ 0x78, /* 0111100 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x78, /* 0111100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 163 0xa3 '£' */
+ 0x18, /* 0001100 */
+ 0x30, /* 0011000 */
+ 0x60, /* 0110000 */
+ 0x00, /* 0000000 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x76, /* 0111011 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 164 0xa4 '¤' */
+ 0x00, /* 0000000 */
+ 0x76, /* 0111011 */
+ 0xdc, /* 1101110 */
+ 0x00, /* 0000000 */
+ 0xb8, /* 1011100 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 165 0xa5 '¥' */
+ 0x76, /* 0111011 */
+ 0xdc, /* 1101110 */
+ 0x00, /* 0000000 */
+ 0xcc, /* 1100110 */
+ 0xec, /* 1110110 */
+ 0xec, /* 1110110 */
+ 0xfc, /* 1111110 */
+ 0xdc, /* 1101110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 166 0xa6 '¦' */
+ 0x00, /* 0000000 */
+ 0x78, /* 0111100 */
+ 0xd8, /* 1101100 */
+ 0xd8, /* 1101100 */
+ 0x7c, /* 0111110 */
+ 0x00, /* 0000000 */
+ 0xfc, /* 1111110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 167 0xa7 '§' */
+ 0x00, /* 0000000 */
+ 0x70, /* 0111000 */
+ 0xd8, /* 1101100 */
+ 0xd8, /* 1101100 */
+ 0x70, /* 0111000 */
+ 0x00, /* 0000000 */
+ 0xf8, /* 1111100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 168 0xa8 '¨' */
+ 0x00, /* 0000000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x00, /* 0000000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x60, /* 0110000 */
+ 0xc0, /* 1100000 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x78, /* 0111100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 169 0xa9 '©' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0xfc, /* 1111110 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 170 0xaa 'ª' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0xfc, /* 1111110 */
+ 0x0c, /* 0000110 */
+ 0x0c, /* 0000110 */
+ 0x0c, /* 0000110 */
+ 0x0c, /* 0000110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 171 0xab '«' */
+ 0x60, /* 0110000 */
+ 0xe0, /* 1110000 */
+ 0x62, /* 0110001 */
+ 0x66, /* 0110011 */
+ 0x6c, /* 0110110 */
+ 0x18, /* 0001100 */
+ 0x30, /* 0011000 */
+ 0x60, /* 0110000 */
+ 0xc0, /* 1100000 */
+ 0xb8, /* 1011100 */
+ 0x4c, /* 0100110 */
+ 0x18, /* 0001100 */
+ 0x30, /* 0011000 */
+ 0x7c, /* 0111110 */
+
+ /* 172 0xac '¬' */
+ 0x60, /* 0110000 */
+ 0xe0, /* 1110000 */
+ 0x62, /* 0110001 */
+ 0x66, /* 0110011 */
+ 0x6c, /* 0110110 */
+ 0x18, /* 0001100 */
+ 0x30, /* 0011000 */
+ 0x6c, /* 0110110 */
+ 0xdc, /* 1101110 */
+ 0xb4, /* 1011010 */
+ 0x7e, /* 0111111 */
+ 0x0c, /* 0000110 */
+ 0x0c, /* 0000110 */
+ 0x00, /* 0000000 */
+
+ /* 173 0xad '' */
+ 0x00, /* 0000000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x00, /* 0000000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x78, /* 0111100 */
+ 0x78, /* 0111100 */
+ 0x78, /* 0111100 */
+ 0x30, /* 0011000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 174 0xae '®' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x36, /* 0011011 */
+ 0x6c, /* 0110110 */
+ 0xd8, /* 1101100 */
+ 0x6c, /* 0110110 */
+ 0x36, /* 0011011 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 175 0xaf '¯' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0xd8, /* 1101100 */
+ 0x6c, /* 0110110 */
+ 0x36, /* 0011011 */
+ 0x6c, /* 0110110 */
+ 0xd8, /* 1101100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 176 0xb0 '°' */
+ 0x88, /* 1000100 */
+ 0x22, /* 0010001 */
+ 0x88, /* 1000100 */
+ 0x22, /* 0010001 */
+ 0x88, /* 1000100 */
+ 0x22, /* 0010001 */
+ 0x88, /* 1000100 */
+ 0x22, /* 0010001 */
+ 0x88, /* 1000100 */
+ 0x22, /* 0010001 */
+ 0x88, /* 1000100 */
+ 0x22, /* 0010001 */
+ 0x88, /* 1000100 */
+ 0x22, /* 0010001 */
+
+ /* 177 0xb1 '±' */
+ 0x54, /* 0101010 */
+ 0xaa, /* 1010101 */
+ 0x54, /* 0101010 */
+ 0xaa, /* 1010101 */
+ 0x54, /* 0101010 */
+ 0xaa, /* 1010101 */
+ 0x54, /* 0101010 */
+ 0xaa, /* 1010101 */
+ 0x54, /* 0101010 */
+ 0xaa, /* 1010101 */
+ 0x54, /* 0101010 */
+ 0xaa, /* 1010101 */
+ 0x54, /* 0101010 */
+ 0xaa, /* 1010101 */
+
+ /* 178 0xb2 '²' */
+ 0xee, /* 1110111 */
+ 0xba, /* 1011101 */
+ 0xee, /* 1110111 */
+ 0xba, /* 1011101 */
+ 0xee, /* 1110111 */
+ 0xba, /* 1011101 */
+ 0xee, /* 1110111 */
+ 0xba, /* 1011101 */
+ 0xee, /* 1110111 */
+ 0xba, /* 1011101 */
+ 0xee, /* 1110111 */
+ 0xba, /* 1011101 */
+ 0xee, /* 1110111 */
+ 0xba, /* 1011101 */
+
+ /* 179 0xb3 '³' */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+
+ /* 180 0xb4 '´' */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0xf0, /* 1111000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+
+ /* 181 0xb5 'µ' */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0xf0, /* 1111000 */
+ 0x30, /* 0011000 */
+ 0xf0, /* 1111000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+
+ /* 182 0xb6 '¶' */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0xec, /* 1110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+
+ /* 183 0xb7 '·' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0xfc, /* 1111110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+
+ /* 184 0xb8 '¸' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0xf0, /* 1111000 */
+ 0x30, /* 0011000 */
+ 0xf0, /* 1111000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+
+ /* 185 0xb9 '¹' */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0xec, /* 1110110 */
+ 0x0c, /* 0000110 */
+ 0xec, /* 1110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+
+ /* 186 0xba 'º' */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+
+ /* 187 0xbb '»' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0xfc, /* 1111110 */
+ 0x0c, /* 0000110 */
+ 0xec, /* 1110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+
+ /* 188 0xbc '¼' */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0xec, /* 1110110 */
+ 0x0c, /* 0000110 */
+ 0xfc, /* 1111110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 189 0xbd '½' */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0xfc, /* 1111110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 190 0xbe '¾' */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0xf0, /* 1111000 */
+ 0x30, /* 0011000 */
+ 0xf0, /* 1111000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 191 0xbf '¿' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0xf0, /* 1111000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+
+ /* 192 0xc0 'À' */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x3e, /* 0011111 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 193 0xc1 'Á' */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0xfe, /* 1111111 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 194 0xc2 'Â' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0xfe, /* 1111111 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+
+ /* 195 0xc3 'Ã' */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x3e, /* 0011111 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+
+ /* 196 0xc4 'Ä' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0xfe, /* 1111111 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 197 0xc5 'Å' */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0xfe, /* 1111111 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+
+ /* 198 0xc6 'Æ' */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x3e, /* 0011111 */
+ 0x30, /* 0011000 */
+ 0x3e, /* 0011111 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+
+ /* 199 0xc7 'Ç' */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6e, /* 0110111 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+
+ /* 200 0xc8 'È' */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6e, /* 0110111 */
+ 0x60, /* 0110000 */
+ 0x7e, /* 0111111 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 201 0xc9 'É' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x7e, /* 0111111 */
+ 0x60, /* 0110000 */
+ 0x6e, /* 0110111 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+
+ /* 202 0xca 'Ê' */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0xee, /* 1110111 */
+ 0x00, /* 0000000 */
+ 0xfe, /* 1111111 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 203 0xcb 'Ë' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0xfe, /* 1111111 */
+ 0x00, /* 0000000 */
+ 0xee, /* 1110111 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+
+ /* 204 0xcc 'Ì' */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6e, /* 0110111 */
+ 0x60, /* 0110000 */
+ 0x6e, /* 0110111 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+
+ /* 205 0xcd 'Í' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0xfe, /* 1111111 */
+ 0x00, /* 0000000 */
+ 0xfe, /* 1111111 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 206 0xce 'Î' */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0xee, /* 1110111 */
+ 0x00, /* 0000000 */
+ 0xee, /* 1110111 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+
+ /* 207 0xcf 'Ï' */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0xfe, /* 1111111 */
+ 0x00, /* 0000000 */
+ 0xfe, /* 1111111 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 208 0xd0 'Ð' */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0xfe, /* 1111111 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 209 0xd1 'Ñ' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0xfe, /* 1111111 */
+ 0x00, /* 0000000 */
+ 0xfe, /* 1111111 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+
+ /* 210 0xd2 'Ò' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0xfe, /* 1111111 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+
+ /* 211 0xd3 'Ó' */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x7e, /* 0111111 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 212 0xd4 'Ô' */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x3e, /* 0011111 */
+ 0x30, /* 0011000 */
+ 0x3e, /* 0011111 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 213 0xd5 'Õ' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x3e, /* 0011111 */
+ 0x30, /* 0011000 */
+ 0x3e, /* 0011111 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+
+ /* 214 0xd6 'Ö' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x7e, /* 0111111 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+
+ /* 215 0xd7 '×' */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0xfe, /* 1111111 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+
+ /* 216 0xd8 'Ø' */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0xfe, /* 1111111 */
+ 0x30, /* 0011000 */
+ 0xfe, /* 1111111 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+
+ /* 217 0xd9 'Ù' */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0xf0, /* 1111000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 218 0xda 'Ú' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x3e, /* 0011111 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+
+ /* 219 0xdb 'Û' */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+
+ /* 220 0xdc 'Ü' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+
+ /* 221 0xdd 'Ý' */
+ 0xe0, /* 1110000 */
+ 0xe0, /* 1110000 */
+ 0xe0, /* 1110000 */
+ 0xe0, /* 1110000 */
+ 0xe0, /* 1110000 */
+ 0xe0, /* 1110000 */
+ 0xe0, /* 1110000 */
+ 0xe0, /* 1110000 */
+ 0xe0, /* 1110000 */
+ 0xe0, /* 1110000 */
+ 0xe0, /* 1110000 */
+ 0xe0, /* 1110000 */
+ 0xe0, /* 1110000 */
+ 0xe0, /* 1110000 */
+
+ /* 222 0xde 'Þ' */
+ 0x1e, /* 0001111 */
+ 0x1e, /* 0001111 */
+ 0x1e, /* 0001111 */
+ 0x1e, /* 0001111 */
+ 0x1e, /* 0001111 */
+ 0x1e, /* 0001111 */
+ 0x1e, /* 0001111 */
+ 0x1e, /* 0001111 */
+ 0x1e, /* 0001111 */
+ 0x1e, /* 0001111 */
+ 0x1e, /* 0001111 */
+ 0x1e, /* 0001111 */
+ 0x1e, /* 0001111 */
+ 0x1e, /* 0001111 */
+
+ /* 223 0xdf 'ß' */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 224 0xe0 'à' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x76, /* 0111011 */
+ 0xdc, /* 1101110 */
+ 0xd8, /* 1101100 */
+ 0xd8, /* 1101100 */
+ 0xd8, /* 1101100 */
+ 0xdc, /* 1101110 */
+ 0x76, /* 0111011 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 225 0xe1 'á' */
+ 0x00, /* 0000000 */
+ 0x78, /* 0111100 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xd8, /* 1101100 */
+ 0xcc, /* 1100110 */
+ 0xc6, /* 1100011 */
+ 0xc6, /* 1100011 */
+ 0xc6, /* 1100011 */
+ 0xcc, /* 1100110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 226 0xe2 'â' */
+ 0x00, /* 0000000 */
+ 0xfc, /* 1111110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 227 0xe3 'ã' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0xfe, /* 1111111 */
+ 0xfe, /* 1111111 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 228 0xe4 'ä' */
+ 0x00, /* 0000000 */
+ 0xfc, /* 1111110 */
+ 0xcc, /* 1100110 */
+ 0x60, /* 0110000 */
+ 0x30, /* 0011000 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x30, /* 0011000 */
+ 0x60, /* 0110000 */
+ 0xcc, /* 1100110 */
+ 0xfc, /* 1111110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 229 0xe5 'å' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x7e, /* 0111111 */
+ 0xd8, /* 1101100 */
+ 0xd8, /* 1101100 */
+ 0xd8, /* 1101100 */
+ 0xd8, /* 1101100 */
+ 0xd8, /* 1101100 */
+ 0x70, /* 0111000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 230 0xe6 'æ' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xf8, /* 1111100 */
+ 0xc0, /* 1100000 */
+ 0xc0, /* 1100000 */
+ 0x80, /* 1000000 */
+
+ /* 231 0xe7 'ç' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x76, /* 0111011 */
+ 0xdc, /* 1101110 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 232 0xe8 'è' */
+ 0x00, /* 0000000 */
+ 0xfc, /* 1111110 */
+ 0x30, /* 0011000 */
+ 0x78, /* 0111100 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x78, /* 0111100 */
+ 0x30, /* 0011000 */
+ 0xfc, /* 1111110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 233 0xe9 'é' */
+ 0x00, /* 0000000 */
+ 0x38, /* 0011100 */
+ 0x6c, /* 0110110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xfc, /* 1111110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x6c, /* 0110110 */
+ 0x38, /* 0011100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 234 0xea 'ê' */
+ 0x00, /* 0000000 */
+ 0x38, /* 0011100 */
+ 0x6c, /* 0110110 */
+ 0xc6, /* 1100011 */
+ 0xc6, /* 1100011 */
+ 0xc6, /* 1100011 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0xee, /* 1110111 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 235 0xeb 'ë' */
+ 0x00, /* 0000000 */
+ 0x3c, /* 0011110 */
+ 0x60, /* 0110000 */
+ 0x30, /* 0011000 */
+ 0x18, /* 0001100 */
+ 0x7c, /* 0111110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x78, /* 0111100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 236 0xec 'ì' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x7c, /* 0111110 */
+ 0xd6, /* 1101011 */
+ 0xd6, /* 1101011 */
+ 0xd6, /* 1101011 */
+ 0x7c, /* 0111110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 237 0xed 'í' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x06, /* 0000011 */
+ 0x0c, /* 0000110 */
+ 0x7c, /* 0111110 */
+ 0xd6, /* 1101011 */
+ 0xd6, /* 1101011 */
+ 0xe6, /* 1110011 */
+ 0x7c, /* 0111110 */
+ 0x60, /* 0110000 */
+ 0xc0, /* 1100000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 238 0xee 'î' */
+ 0x00, /* 0000000 */
+ 0x1c, /* 0001110 */
+ 0x30, /* 0011000 */
+ 0x60, /* 0110000 */
+ 0x60, /* 0110000 */
+ 0x7c, /* 0111110 */
+ 0x60, /* 0110000 */
+ 0x60, /* 0110000 */
+ 0x60, /* 0110000 */
+ 0x30, /* 0011000 */
+ 0x1c, /* 0001110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 239 0xef 'ï' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x78, /* 0111100 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0xcc, /* 1100110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 240 0xf0 'ð' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0xfc, /* 1111110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0xfc, /* 1111110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0xfc, /* 1111110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 241 0xf1 'ñ' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0xfc, /* 1111110 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0xfc, /* 1111110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 242 0xf2 'ò' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x60, /* 0110000 */
+ 0x30, /* 0011000 */
+ 0x18, /* 0001100 */
+ 0x0c, /* 0000110 */
+ 0x18, /* 0001100 */
+ 0x30, /* 0011000 */
+ 0x60, /* 0110000 */
+ 0x00, /* 0000000 */
+ 0xfc, /* 1111110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 243 0xf3 'ó' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x18, /* 0001100 */
+ 0x30, /* 0011000 */
+ 0x60, /* 0110000 */
+ 0xc0, /* 1100000 */
+ 0x60, /* 0110000 */
+ 0x30, /* 0011000 */
+ 0x18, /* 0001100 */
+ 0x00, /* 0000000 */
+ 0xfc, /* 1111110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 244 0xf4 'ô' */
+ 0x00, /* 0000000 */
+ 0x1c, /* 0001110 */
+ 0x36, /* 0011011 */
+ 0x36, /* 0011011 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+
+ /* 245 0xf5 'õ' */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0xd8, /* 1101100 */
+ 0xd8, /* 1101100 */
+ 0xd8, /* 1101100 */
+ 0x70, /* 0111000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 246 0xf6 'ö' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x30, /* 0011000 */
+ 0x00, /* 0000000 */
+ 0xfc, /* 1111110 */
+ 0x00, /* 0000000 */
+ 0x30, /* 0011000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 247 0xf7 '÷' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x76, /* 0111011 */
+ 0xdc, /* 1101110 */
+ 0x00, /* 0000000 */
+ 0x76, /* 0111011 */
+ 0xdc, /* 1101110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 248 0xf8 'ø' */
+ 0x38, /* 0011100 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x38, /* 0011100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 249 0xf9 'ù' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x30, /* 0011000 */
+ 0x30, /* 0011000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 250 0xfa 'ú' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x30, /* 0011000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 251 0xfb 'û' */
+ 0x1e, /* 0001111 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0x18, /* 0001100 */
+ 0xd8, /* 1101100 */
+ 0xd8, /* 1101100 */
+ 0xd8, /* 1101100 */
+ 0x78, /* 0111100 */
+ 0x38, /* 0011100 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 252 0xfc 'ü' */
+ 0xd8, /* 1101100 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x6c, /* 0110110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 253 0xfd 'ý' */
+ 0x78, /* 0111100 */
+ 0xcc, /* 1100110 */
+ 0x18, /* 0001100 */
+ 0x30, /* 0011000 */
+ 0x64, /* 0110010 */
+ 0xfc, /* 1111110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 254 0xfe 'þ' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x7c, /* 0111110 */
+ 0x7c, /* 0111110 */
+ 0x7c, /* 0111110 */
+ 0x7c, /* 0111110 */
+ 0x7c, /* 0111110 */
+ 0x7c, /* 0111110 */
+ 0x7c, /* 0111110 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+ /* 255 0xff 'ÿ' */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+ 0x00, /* 0000000 */
+
+};
+
+
+struct font_desc font_7x14 = {
+ FONT7x14_IDX,
+ "7x14",
+ 7,
+ 14,
+ fontdata_7x14,
+ 0
+};
0x00, 0x00, /* 000000000000 */
/* 1 0x01 '^A' */
- /* FIXME */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
+ 0x1f, 0xc0, /* 000111111100 */
+ 0x30, 0x60, /* 001100000110 */
+ 0x65, 0x30, /* 011001010011 */
+ 0x6d, 0xb0, /* 011011011011 */
+ 0x60, 0x30, /* 011000000011 */
+ 0x62, 0x30, /* 011000100011 */
+ 0x62, 0x30, /* 011000100011 */
+ 0x60, 0x30, /* 011000000011 */
+ 0x6f, 0xb0, /* 011011111011 */
+ 0x67, 0x30, /* 011001110011 */
+ 0x30, 0x60, /* 001100000110 */
+ 0x1f, 0xc0, /* 000111111100 */
0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
/* 2 0x02 '^B' */
- /* FIXME */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
+ 0x1f, 0xc0, /* 000111111100 */
+ 0x3f, 0xe0, /* 001111111110 */
+ 0x7a, 0xf0, /* 011110101111 */
+ 0x72, 0x70, /* 011100100111 */
+ 0x7f, 0xf0, /* 011111111111 */
+ 0x7d, 0xf0, /* 011111011111 */
+ 0x7d, 0xf0, /* 011111011111 */
+ 0x7f, 0xf0, /* 011111111111 */
+ 0x70, 0x70, /* 011100000111 */
+ 0x78, 0xf0, /* 011110001111 */
+ 0x3f, 0xe0, /* 001111111110 */
+ 0x1f, 0xc0, /* 000111111100 */
0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
/* 3 0x03 '^C' */
- /* FIXME */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
+ 0x00, 0x00, /* 000000000000 */
+ 0x19, 0x80, /* 000110011000 */
0x3f, 0xc0, /* 001111111100 */
+ 0x7f, 0xe0, /* 011111111110 */
0x3f, 0xc0, /* 001111111100 */
0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
+ 0x1f, 0x80, /* 000111111000 */
+ 0x1f, 0x80, /* 000111111000 */
+ 0x0f, 0x00, /* 000011110000 */
+ 0x0f, 0x00, /* 000011110000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
/* 4 0x04 '^D' */
- /* FIXME */
- 0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
+ 0x02, 0x00, /* 000000100000 */
+ 0x07, 0x00, /* 000001110000 */
+ 0x0f, 0x80, /* 000011111000 */
+ 0x0f, 0x80, /* 000011111000 */
+ 0x1f, 0xc0, /* 000111111100 */
+ 0x1f, 0xc0, /* 000111111100 */
+ 0x3f, 0xe0, /* 001111111110 */
+ 0x1f, 0xc0, /* 000111111100 */
+ 0x1f, 0xc0, /* 000111111100 */
+ 0x0f, 0x80, /* 000011111000 */
+ 0x0f, 0x80, /* 000011111000 */
+ 0x07, 0x00, /* 000001110000 */
+ 0x02, 0x00, /* 000000100000 */
0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
/* 5 0x05 '^E' */
- /* FIXME */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
+ 0x02, 0x00, /* 000000100000 */
+ 0x07, 0x00, /* 000001110000 */
+ 0x07, 0x00, /* 000001110000 */
+ 0x02, 0x00, /* 000000100000 */
+ 0x18, 0xc0, /* 000110001100 */
+ 0x3d, 0xe0, /* 001111011110 */
+ 0x3d, 0xe0, /* 001111011110 */
+ 0x1a, 0xc0, /* 000110101100 */
+ 0x02, 0x00, /* 000000100000 */
+ 0x07, 0x00, /* 000001110000 */
+ 0x0f, 0x80, /* 000011111000 */
+ 0x1f, 0xc0, /* 000111111100 */
0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
/* 6 0x06 '^F' */
- /* FIXME */
- 0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x0f, 0x00, /* 000011110000 */
+ 0x1f, 0x80, /* 000111111000 */
+ 0x1f, 0x80, /* 000111111000 */
0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
+ 0x7f, 0xe0, /* 011111111110 */
+ 0x7f, 0xe0, /* 011111111110 */
+ 0x36, 0xc0, /* 001101101100 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x0f, 0x00, /* 000011110000 */
+ 0x1f, 0x80, /* 000111111000 */
0x3f, 0xc0, /* 001111111100 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
/* 7 0x07 '^G' */
- /* FIXME */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x0f, 0x00, /* 000011110000 */
+ 0x0f, 0x00, /* 000011110000 */
+ 0x1f, 0x80, /* 000111111000 */
+ 0x1f, 0x80, /* 000111111000 */
0x3f, 0xc0, /* 001111111100 */
0x3f, 0xc0, /* 001111111100 */
+ 0x1f, 0x80, /* 000111111000 */
+ 0x1f, 0x80, /* 000111111000 */
+ 0x0f, 0x00, /* 000011110000 */
+ 0x0f, 0x00, /* 000011110000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
/* 8 0x08 '^H' */
- /* FIXME */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
+ 0xff, 0xf0, /* 111111111111 */
+ 0xff, 0xf0, /* 111111111111 */
+ 0xff, 0xf0, /* 111111111111 */
+ 0xff, 0xf0, /* 111111111111 */
+ 0xf9, 0xf0, /* 111110011111 */
+ 0xf0, 0xf0, /* 111100001111 */
+ 0xf0, 0xf0, /* 111100001111 */
+ 0xe0, 0x70, /* 111000000111 */
+ 0xe0, 0x70, /* 111000000111 */
+ 0xc0, 0x30, /* 110000000011 */
+ 0xc0, 0x30, /* 110000000011 */
+ 0xe0, 0x70, /* 111000000111 */
+ 0xe0, 0x70, /* 111000000111 */
+ 0xf0, 0xf0, /* 111100001111 */
+ 0xf0, 0xf0, /* 111100001111 */
+ 0xf9, 0xf0, /* 111110011111 */
+ 0xff, 0xf0, /* 111111111111 */
+ 0xff, 0xf0, /* 111111111111 */
+ 0xff, 0xf0, /* 111111111111 */
+ 0xff, 0xf0, /* 111111111111 */
+ 0xff, 0xf0, /* 111111111111 */
+ 0xff, 0xf0, /* 111111111111 */
/* 9 0x09 '^I' */
- /* FIXME */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x0f, 0x00, /* 000011110000 */
+ 0x0f, 0x00, /* 000011110000 */
+ 0x19, 0x80, /* 000110011000 */
+ 0x19, 0x80, /* 000110011000 */
+ 0x30, 0xc0, /* 001100001100 */
+ 0x30, 0xc0, /* 001100001100 */
+ 0x19, 0x80, /* 000110011000 */
+ 0x19, 0x80, /* 000110011000 */
+ 0x0f, 0x00, /* 000011110000 */
+ 0x0f, 0x00, /* 000011110000 */
+ 0x06, 0x00, /* 000001100000 */
0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
/* 10 0x0a '^J' */
- /* FIXME */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
+ 0xff, 0xf0, /* 111111111111 */
+ 0xff, 0xf0, /* 111111111111 */
+ 0xff, 0xf0, /* 111111111111 */
+ 0xff, 0xf0, /* 111111111111 */
+ 0xf9, 0xf0, /* 111110011111 */
+ 0xf0, 0xf0, /* 111100001111 */
+ 0xf0, 0xf0, /* 111100001111 */
+ 0xe6, 0x70, /* 111001100111 */
+ 0xe6, 0x70, /* 111001100111 */
+ 0xcf, 0x30, /* 110011110011 */
+ 0xcf, 0x30, /* 110011110011 */
+ 0xe6, 0x70, /* 111001100111 */
+ 0xe6, 0x70, /* 111001100111 */
+ 0xf0, 0xf0, /* 111100001111 */
+ 0xf0, 0xf0, /* 111100001111 */
+ 0xf9, 0xf0, /* 111110011111 */
+ 0xff, 0xf0, /* 111111111111 */
+ 0xff, 0xf0, /* 111111111111 */
+ 0xff, 0xf0, /* 111111111111 */
+ 0xff, 0xf0, /* 111111111111 */
+ 0xff, 0xf0, /* 111111111111 */
+ 0xff, 0xf0, /* 111111111111 */
/* 11 0x0b '^K' */
- /* FIXME */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
+ 0x0f, 0xe0, /* 000011111110 */
+ 0x0f, 0xe0, /* 000011111110 */
+ 0x01, 0xe0, /* 000000011110 */
+ 0x03, 0x60, /* 000000110110 */
+ 0x06, 0x60, /* 000001100110 */
+ 0x1e, 0x00, /* 000111100000 */
+ 0x33, 0x00, /* 001100110000 */
+ 0x33, 0x00, /* 001100110000 */
+ 0x61, 0x80, /* 011000011000 */
+ 0x61, 0x80, /* 011000011000 */
+ 0x33, 0x00, /* 001100110000 */
+ 0x33, 0x00, /* 001100110000 */
+ 0x1e, 0x00, /* 000111100000 */
+ 0x0c, 0x00, /* 000011000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
/* 12 0x0c '^L' */
- /* FIXME */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x0f, 0x00, /* 000011110000 */
+ 0x19, 0x80, /* 000110011000 */
+ 0x30, 0xc0, /* 001100001100 */
+ 0x30, 0xc0, /* 001100001100 */
+ 0x19, 0x80, /* 000110011000 */
+ 0x0f, 0x00, /* 000011110000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x06, 0x00, /* 000001100000 */
0x3f, 0xc0, /* 001111111100 */
0x3f, 0xc0, /* 001111111100 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
/* 13 0x0d '^M' */
- /* FIXME */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
+ 0x0f, 0xe0, /* 000011111110 */
+ 0x0c, 0x60, /* 000011000110 */
+ 0x0c, 0x60, /* 000011000110 */
+ 0x0f, 0xe0, /* 000011111110 */
+ 0x0c, 0x00, /* 000011000000 */
+ 0x0c, 0x00, /* 000011000000 */
+ 0x0c, 0x00, /* 000011000000 */
+ 0x0c, 0x00, /* 000011000000 */
+ 0x0c, 0x00, /* 000011000000 */
+ 0x0c, 0x00, /* 000011000000 */
+ 0x0c, 0x00, /* 000011000000 */
+ 0x0c, 0x00, /* 000011000000 */
+ 0x0c, 0x00, /* 000011000000 */
+ 0x3c, 0x00, /* 001111000000 */
+ 0x7c, 0x00, /* 011111000000 */
+ 0x78, 0x00, /* 011110000000 */
+ 0x30, 0x00, /* 001100000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
/* 14 0x0e '^N' */
- /* FIXME */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
+ 0x1f, 0xe0, /* 000111111110 */
+ 0x18, 0x60, /* 000110000110 */
+ 0x18, 0x60, /* 000110000110 */
+ 0x1f, 0xe0, /* 000111111110 */
+ 0x18, 0x60, /* 000110000110 */
+ 0x18, 0x60, /* 000110000110 */
+ 0x18, 0x60, /* 000110000110 */
+ 0x18, 0x60, /* 000110000110 */
+ 0x18, 0x60, /* 000110000110 */
+ 0x18, 0x60, /* 000110000110 */
+ 0x19, 0xe0, /* 000110011110 */
+ 0x1b, 0xe0, /* 000110111110 */
+ 0x1b, 0xc0, /* 000110111100 */
+ 0x79, 0x80, /* 011110011000 */
+ 0xf8, 0x00, /* 111110000000 */
+ 0xf0, 0x00, /* 111100000000 */
+ 0x60, 0x00, /* 011000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
/* 15 0x0f '^O' */
- /* FIXME */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
+ 0x18, 0xc0, /* 000110001100 */
+ 0x0d, 0x80, /* 000011011000 */
+ 0x6d, 0xb0, /* 011011011011 */
+ 0x3d, 0xe0, /* 001111011110 */
0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
-
- /* 16 0x10 '^P' */
- /* FIXME */
- 0x00, 0x00, /* 000000000000 */
+ 0x3d, 0xe0, /* 001111011110 */
+ 0x6d, 0xb0, /* 011011011011 */
+ 0x0d, 0x80, /* 000011011000 */
+ 0x18, 0xc0, /* 000110001100 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
+
+ /* 16 0x10 '^P' */
0x00, 0x00, /* 000000000000 */
+ 0x00, 0x20, /* 000000000010 */
+ 0x00, 0x60, /* 000000000110 */
+ 0x00, 0xe0, /* 000000001110 */
+ 0x01, 0xe0, /* 000000011110 */
+ 0x03, 0xe0, /* 000000111110 */
+ 0x07, 0xe0, /* 000001111110 */
+ 0x0f, 0xe0, /* 000011111110 */
+ 0x1f, 0xe0, /* 000111111110 */
+ 0x3f, 0xe0, /* 001111111110 */
+ 0x7f, 0xe0, /* 011111111110 */
+ 0x3f, 0xe0, /* 001111111110 */
+ 0x1f, 0xe0, /* 000111111110 */
+ 0x0f, 0xe0, /* 000011111110 */
+ 0x07, 0xe0, /* 000001111110 */
+ 0x03, 0xe0, /* 000000111110 */
+ 0x01, 0xe0, /* 000000011110 */
+ 0x00, 0xe0, /* 000000001110 */
+ 0x00, 0x60, /* 000000000110 */
+ 0x00, 0x20, /* 000000000010 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
/* 17 0x11 '^Q' */
- /* FIXME */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
+ 0x40, 0x00, /* 010000000000 */
+ 0x60, 0x00, /* 011000000000 */
+ 0x70, 0x00, /* 011100000000 */
+ 0x78, 0x00, /* 011110000000 */
+ 0x7c, 0x00, /* 011111000000 */
+ 0x7e, 0x00, /* 011111100000 */
+ 0x7f, 0x00, /* 011111110000 */
+ 0x7f, 0x80, /* 011111111000 */
+ 0x7f, 0xc0, /* 011111111100 */
+ 0x7f, 0xe0, /* 011111111110 */
+ 0x7f, 0xc0, /* 011111111100 */
+ 0x7f, 0x80, /* 011111111000 */
+ 0x7f, 0x00, /* 011111110000 */
+ 0x7e, 0x00, /* 011111100000 */
+ 0x7c, 0x00, /* 011111000000 */
+ 0x78, 0x00, /* 011110000000 */
+ 0x70, 0x00, /* 011100000000 */
+ 0x60, 0x00, /* 011000000000 */
+ 0x40, 0x00, /* 010000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
/* 18 0x12 '^R' */
- /* FIXME */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
+ 0x04, 0x00, /* 000001000000 */
+ 0x0e, 0x00, /* 000011100000 */
+ 0x1f, 0x00, /* 000111110000 */
+ 0x3f, 0x80, /* 001111111000 */
+ 0x7f, 0xc0, /* 011111111100 */
+ 0x0e, 0x00, /* 000011100000 */
+ 0x0e, 0x00, /* 000011100000 */
+ 0x7f, 0xc0, /* 011111111100 */
+ 0x3f, 0x80, /* 001111111000 */
+ 0x1f, 0x00, /* 000111110000 */
+ 0x0e, 0x00, /* 000011100000 */
+ 0x04, 0x00, /* 000001000000 */
0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
/* 22 0x16 '^V' */
- /* FIXME */
- 0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
-
- /* 23 0x17 '^W' */
- /* FIXME */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
+ 0x7f, 0xe0, /* 011111111110 */
+ 0x7f, 0xe0, /* 011111111110 */
+ 0x7f, 0xe0, /* 011111111110 */
0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
- /* 24 0x18 '^X' */
- /* FIXME */
+ /* 23 0x17 '^W' */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
+ 0x04, 0x00, /* 000001000000 */
+ 0x0e, 0x00, /* 000011100000 */
+ 0x1f, 0x00, /* 000111110000 */
+ 0x3f, 0x80, /* 001111111000 */
+ 0x7f, 0xc0, /* 011111111100 */
+ 0x0e, 0x00, /* 000011100000 */
+ 0x0e, 0x00, /* 000011100000 */
+ 0x7f, 0xc0, /* 011111111100 */
+ 0x3f, 0x80, /* 001111111000 */
+ 0x1f, 0x00, /* 000111110000 */
+ 0x0e, 0x00, /* 000011100000 */
+ 0x04, 0x00, /* 000001000000 */
0x00, 0x00, /* 000000000000 */
+ 0x7f, 0xe0, /* 011111111110 */
+ 0x7f, 0xe0, /* 011111111110 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
+
+ /* 24 0x18 '^X' */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
-
- /* 25 0x19 '^Y' */
- /* FIXME */
+ 0x04, 0x00, /* 000001000000 */
+ 0x0e, 0x00, /* 000011100000 */
+ 0x1f, 0x00, /* 000111110000 */
+ 0x3f, 0x80, /* 001111111000 */
+ 0x7f, 0xc0, /* 011111111100 */
+ 0x0e, 0x00, /* 000011100000 */
+ 0x0e, 0x00, /* 000011100000 */
+ 0x0e, 0x00, /* 000011100000 */
+ 0x0e, 0x00, /* 000011100000 */
+ 0x0e, 0x00, /* 000011100000 */
+ 0x0e, 0x00, /* 000011100000 */
+ 0x0e, 0x00, /* 000011100000 */
+ 0x0e, 0x00, /* 000011100000 */
+ 0x0e, 0x00, /* 000011100000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
+ 0x00, 0x00, /* 000000000000 */
+
+ /* 25 0x19 '^Y' */
+ 0x00, 0x00, /* 000000000000 */
+ 0x00, 0x00, /* 000000000000 */
+ 0x0e, 0x00, /* 000011100000 */
+ 0x0e, 0x00, /* 000011100000 */
+ 0x0e, 0x00, /* 000011100000 */
+ 0x0e, 0x00, /* 000011100000 */
+ 0x0e, 0x00, /* 000011100000 */
+ 0x0e, 0x00, /* 000011100000 */
+ 0x0e, 0x00, /* 000011100000 */
+ 0x0e, 0x00, /* 000011100000 */
+ 0x0e, 0x00, /* 000011100000 */
+ 0x0e, 0x00, /* 000011100000 */
+ 0x7f, 0xc0, /* 011111111100 */
+ 0x3f, 0x80, /* 001111111000 */
+ 0x1f, 0x00, /* 000111110000 */
+ 0x0e, 0x00, /* 000011100000 */
+ 0x04, 0x00, /* 000001000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
/* 26 0x1a '^Z' */
- /* FIXME */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
+ 0x00, 0x00, /* 000000000000 */
+ 0x08, 0x00, /* 000010000000 */
+ 0x18, 0x00, /* 000110000000 */
+ 0x38, 0x00, /* 001110000000 */
+ 0x7f, 0xe0, /* 011111111110 */
+ 0xff, 0xe0, /* 111111111110 */
+ 0x7f, 0xe0, /* 011111111110 */
+ 0x38, 0x00, /* 001110000000 */
+ 0x18, 0x00, /* 000110000000 */
+ 0x08, 0x00, /* 000010000000 */
+ 0x00, 0x00, /* 000000000000 */
+ 0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
/* 27 0x1b '^[' */
- /* FIXME */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
+ 0x00, 0x00, /* 000000000000 */
+ 0x01, 0x00, /* 000000010000 */
+ 0x01, 0x80, /* 000000011000 */
+ 0x01, 0xc0, /* 000000011100 */
+ 0x7f, 0xe0, /* 011111111110 */
+ 0x7f, 0xf0, /* 011111111111 */
+ 0x7f, 0xe0, /* 011111111110 */
+ 0x01, 0xc0, /* 000000011100 */
+ 0x01, 0x80, /* 000000011000 */
+ 0x01, 0x00, /* 000000010000 */
+ 0x00, 0x00, /* 000000000000 */
+ 0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
/* 28 0x1c '^\' */
- /* FIXME */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
+ 0x00, 0x00, /* 000000000000 */
+ 0x00, 0x00, /* 000000000000 */
+ 0x00, 0x00, /* 000000000000 */
+ 0x00, 0x00, /* 000000000000 */
+ 0x00, 0x00, /* 000000000000 */
+ 0x00, 0x00, /* 000000000000 */
+ 0x00, 0x00, /* 000000000000 */
+ 0x00, 0x00, /* 000000000000 */
+ 0x30, 0x00, /* 001100000000 */
+ 0x30, 0x00, /* 001100000000 */
+ 0x3f, 0xe0, /* 001111111110 */
+ 0x3f, 0xe0, /* 001111111110 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
/* 29 0x1d '^]' */
- /* FIXME */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
+ 0x00, 0x00, /* 000000000000 */
+ 0x09, 0x00, /* 000010010000 */
+ 0x19, 0x80, /* 000110011000 */
+ 0x39, 0xc0, /* 001110011100 */
+ 0x7f, 0xe0, /* 011111111110 */
+ 0xff, 0xf0, /* 111111111111 */
+ 0x7f, 0xe0, /* 011111111110 */
+ 0x39, 0xc0, /* 001110011100 */
+ 0x19, 0x80, /* 000110011000 */
+ 0x09, 0x00, /* 000010010000 */
+ 0x00, 0x00, /* 000000000000 */
+ 0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
/* 30 0x1e '^^' */
- /* FIXME */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
+ 0x00, 0x00, /* 000000000000 */
+ 0x04, 0x00, /* 000001000000 */
+ 0x04, 0x00, /* 000001000000 */
+ 0x0e, 0x00, /* 000011100000 */
+ 0x0e, 0x00, /* 000011100000 */
+ 0x1f, 0x00, /* 000111110000 */
+ 0x1f, 0x00, /* 000111110000 */
+ 0x3f, 0x80, /* 001111111000 */
+ 0x3f, 0x80, /* 001111111000 */
+ 0x7f, 0xc0, /* 011111111100 */
+ 0x7f, 0xc0, /* 011111111100 */
+ 0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
/* 31 0x1f '^_' */
- /* FIXME */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
+ 0x00, 0x00, /* 000000000000 */
+ 0x7f, 0xc0, /* 011111111100 */
+ 0x7f, 0xc0, /* 011111111100 */
+ 0x3f, 0x80, /* 001111111000 */
+ 0x3f, 0x80, /* 001111111000 */
+ 0x1f, 0x00, /* 000111110000 */
+ 0x1f, 0x00, /* 000111110000 */
+ 0x0e, 0x00, /* 000011100000 */
+ 0x0e, 0x00, /* 000011100000 */
+ 0x04, 0x00, /* 000001000000 */
+ 0x04, 0x00, /* 000001000000 */
+ 0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
/* 127 0x7f '.' */
- /* FIXME */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
+ 0x00, 0x00, /* 000000000000 */
+ 0x00, 0x00, /* 000000000000 */
+ 0x00, 0x00, /* 000000000000 */
+ 0x00, 0x00, /* 000000000000 */
+ 0x00, 0x00, /* 000000000000 */
+ 0x00, 0x00, /* 000000000000 */
+ 0x00, 0x00, /* 000000000000 */
+ 0x00, 0x00, /* 000000000000 */
+ 0x00, 0x00, /* 000000000000 */
+ 0xff, 0xf0, /* 111111111111 */
+ 0xff, 0xf0, /* 111111111111 */
+ 0x00, 0x00, /* 000000000000 */
/* 128 0x80 '.' */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
/* 158 0x9e '.' */
- /* FIXME */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
+ 0x7f, 0x80, /* 011111111000 */
+ 0x30, 0xc0, /* 001100001100 */
+ 0x30, 0x60, /* 001100000110 */
+ 0x30, 0x60, /* 001100000110 */
+ 0x30, 0x60, /* 001100000110 */
+ 0x30, 0xc0, /* 001100001100 */
+ 0x37, 0x80, /* 001101111000 */
+ 0x30, 0x00, /* 001100000000 */
+ 0x33, 0x00, /* 001100110000 */
+ 0x37, 0x80, /* 001101111000 */
+ 0x33, 0x00, /* 001100110000 */
+ 0x33, 0x00, /* 001100110000 */
+ 0x33, 0x30, /* 001100110011 */
+ 0x31, 0xe0, /* 001100011110 */
+ 0x78, 0xc0, /* 011110001100 */
0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
/* 159 0x9f '.' */
- /* FIXME */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
+ 0x00, 0xc0, /* 000000001100 */
+ 0x01, 0xe0, /* 000000011110 */
+ 0x03, 0x30, /* 000000110011 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x3f, 0xe0, /* 001111111110 */
+ 0x7f, 0xc0, /* 011111111100 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0xcc, 0x00, /* 110011000000 */
+ 0x78, 0x00, /* 011110000000 */
+ 0x30, 0x00, /* 001100000000 */
0x00, 0x00, /* 000000000000 */
/* 160 0xa0 '.' */
0x00, 0x00, /* 000000000000 */
/* 169 0xa9 '.' */
- /* FIXME */
- 0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x3f, 0xc0, /* 001111111100 */
0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
+ 0x30, 0x00, /* 001100000000 */
+ 0x30, 0x00, /* 001100000000 */
+ 0x30, 0x00, /* 001100000000 */
+ 0x00, 0x00, /* 000000000000 */
+ 0x00, 0x00, /* 000000000000 */
+ 0x00, 0x00, /* 000000000000 */
+ 0x00, 0x00, /* 000000000000 */
+ 0x00, 0x00, /* 000000000000 */
+ 0x00, 0x00, /* 000000000000 */
+ 0x00, 0x00, /* 000000000000 */
+ 0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
/* 224 0xe0 '.' */
- /* FIXME */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
+ 0x00, 0x00, /* 000000000000 */
+ 0x0f, 0x60, /* 000011110110 */
+ 0x13, 0xe0, /* 000100111110 */
+ 0x21, 0xc0, /* 001000011100 */
+ 0x60, 0xc0, /* 011000001100 */
+ 0x60, 0xc0, /* 011000001100 */
+ 0x60, 0xc0, /* 011000001100 */
+ 0x60, 0xc0, /* 011000001100 */
+ 0x70, 0x80, /* 011100001000 */
+ 0x39, 0xc0, /* 001110011100 */
+ 0x1f, 0x60, /* 000111110110 */
+ 0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
/* 226 0xe2 '.' */
- /* FIXME */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
+ 0x3f, 0xe0, /* 001111111110 */
+ 0x3f, 0xe0, /* 001111111110 */
+ 0x30, 0x60, /* 001100000110 */
+ 0x30, 0x60, /* 001100000110 */
+ 0x30, 0x00, /* 001100000000 */
+ 0x30, 0x00, /* 001100000000 */
+ 0x30, 0x00, /* 001100000000 */
+ 0x30, 0x00, /* 001100000000 */
+ 0x30, 0x00, /* 001100000000 */
+ 0x30, 0x00, /* 001100000000 */
+ 0x30, 0x00, /* 001100000000 */
+ 0x30, 0x00, /* 001100000000 */
+ 0x30, 0x00, /* 001100000000 */
+ 0x30, 0x00, /* 001100000000 */
0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
/* 227 0xe3 '.' */
- /* FIXME */
- 0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
+ 0x7f, 0xe0, /* 011111111110 */
+ 0x7f, 0xe0, /* 011111111110 */
+ 0x19, 0x80, /* 000110011000 */
+ 0x19, 0x80, /* 000110011000 */
+ 0x19, 0x80, /* 000110011000 */
+ 0x19, 0x80, /* 000110011000 */
+ 0x19, 0x80, /* 000110011000 */
+ 0x19, 0x80, /* 000110011000 */
+ 0x19, 0x80, /* 000110011000 */
+ 0x19, 0x80, /* 000110011000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
-
- /* 228 0xe4 '.' */
- /* FIXME */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
+
+ /* 228 0xe4 '.' */
0x00, 0x00, /* 000000000000 */
+ 0x7f, 0xe0, /* 011111111110 */
+ 0x7f, 0xe0, /* 011111111110 */
+ 0x60, 0x60, /* 011000000110 */
+ 0x30, 0x60, /* 001100000110 */
+ 0x30, 0x00, /* 001100000000 */
+ 0x18, 0x00, /* 000110000000 */
+ 0x18, 0x00, /* 000110000000 */
+ 0x0c, 0x00, /* 000011000000 */
+ 0x18, 0x00, /* 000110000000 */
+ 0x18, 0x00, /* 000110000000 */
+ 0x30, 0x00, /* 001100000000 */
+ 0x30, 0x60, /* 001100000110 */
+ 0x60, 0x60, /* 011000000110 */
+ 0x7f, 0xe0, /* 011111111110 */
+ 0x7f, 0xe0, /* 011111111110 */
0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
/* 229 0xe5 '.' */
- /* FIXME */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
+ 0x07, 0xe0, /* 000001111110 */
+ 0x0f, 0xe0, /* 000011111110 */
+ 0x13, 0x80, /* 000100111000 */
+ 0x21, 0xc0, /* 001000011100 */
+ 0x60, 0xc0, /* 011000001100 */
+ 0x60, 0xc0, /* 011000001100 */
+ 0x60, 0xc0, /* 011000001100 */
+ 0x60, 0xc0, /* 011000001100 */
+ 0x70, 0x80, /* 011100001000 */
+ 0x39, 0x00, /* 001110010000 */
+ 0x1e, 0x00, /* 000111100000 */
+ 0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
/* 231 0xe7 '.' */
- /* FIXME */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
+ 0x19, 0x80, /* 000110011000 */
0x3f, 0xc0, /* 001111111100 */
+ 0x66, 0x60, /* 011001100110 */
+ 0x66, 0x60, /* 011001100110 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
/* 232 0xe8 '.' */
- /* FIXME */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
+ 0x7f, 0xe0, /* 011111111110 */
+ 0x7f, 0xe0, /* 011111111110 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x0f, 0x00, /* 000011110000 */
+ 0x19, 0x80, /* 000110011000 */
+ 0x30, 0xc0, /* 001100001100 */
+ 0x30, 0xc0, /* 001100001100 */
+ 0x19, 0x80, /* 000110011000 */
+ 0x0f, 0x00, /* 000011110000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x7f, 0xe0, /* 011111111110 */
+ 0x7f, 0xe0, /* 011111111110 */
0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
/* 233 0xe9 '.' */
- /* FIXME */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
+ 0x0f, 0x00, /* 000011110000 */
+ 0x1f, 0x80, /* 000111111000 */
+ 0x30, 0xc0, /* 001100001100 */
+ 0x60, 0x60, /* 011000000110 */
+ 0x60, 0x60, /* 011000000110 */
+ 0x7f, 0xe0, /* 011111111110 */
+ 0x7f, 0xe0, /* 011111111110 */
+ 0x60, 0x60, /* 011000000110 */
+ 0x60, 0x60, /* 011000000110 */
+ 0x30, 0xc0, /* 001100001100 */
+ 0x1f, 0x80, /* 000111111000 */
+ 0x0f, 0x00, /* 000011110000 */
0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
/* 234 0xea '.' */
- /* FIXME */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
+ 0x1f, 0x00, /* 000111110000 */
+ 0x31, 0x80, /* 001100011000 */
+ 0x30, 0xc0, /* 001100001100 */
+ 0x30, 0xc0, /* 001100001100 */
+ 0x60, 0x60, /* 011000000110 */
+ 0x60, 0x60, /* 011000000110 */
+ 0x30, 0xc0, /* 001100001100 */
+ 0x30, 0xc0, /* 001100001100 */
+ 0x19, 0x80, /* 000110011000 */
+ 0x19, 0x80, /* 000110011000 */
+ 0xd9, 0xb0, /* 110110011011 */
+ 0x79, 0xe0, /* 011110011110 */
0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
/* 235 0xeb '.' */
- /* FIXME */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
+ 0x07, 0x80, /* 000001111000 */
+ 0x0c, 0xc0, /* 000011001100 */
+ 0x18, 0x60, /* 000110000110 */
+ 0x18, 0x00, /* 000110000000 */
+ 0x0c, 0x00, /* 000011000000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x03, 0x00, /* 000000110000 */
+ 0x0f, 0x80, /* 000011111000 */
+ 0x11, 0xc0, /* 000100011100 */
+ 0x20, 0xe0, /* 001000001110 */
+ 0x60, 0x60, /* 011000000110 */
+ 0x60, 0x60, /* 011000000110 */
+ 0x70, 0x40, /* 011100000100 */
+ 0x38, 0x80, /* 001110001000 */
+ 0x1f, 0x00, /* 000111110000 */
0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
/* 236 0xec '.' */
- /* FIXME */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
+ 0x39, 0xc0, /* 001110011100 */
+ 0x6f, 0x60, /* 011011110110 */
+ 0x66, 0x60, /* 011001100110 */
+ 0xc6, 0x30, /* 110001100011 */
+ 0xc6, 0x30, /* 110001100011 */
+ 0x66, 0x60, /* 011001100110 */
+ 0x6f, 0x60, /* 011011110110 */
+ 0x39, 0xc0, /* 001110011100 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
-
- /* 237 0xed '.' */
- /* FIXME */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
+
+ /* 237 0xed '.' */
0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
+ 0x00, 0xc0, /* 000000001100 */
+ 0x00, 0xc0, /* 000000001100 */
+ 0x01, 0x80, /* 000000011000 */
+ 0x01, 0x80, /* 000000011000 */
+ 0x3b, 0xc0, /* 001110111100 */
+ 0x6f, 0x60, /* 011011110110 */
+ 0x66, 0x60, /* 011001100110 */
+ 0xc6, 0x30, /* 110001100011 */
+ 0xc6, 0x30, /* 110001100011 */
+ 0x66, 0x60, /* 011001100110 */
+ 0x6f, 0x60, /* 011011110110 */
+ 0x3d, 0xc0, /* 001111011100 */
+ 0x18, 0x00, /* 000110000000 */
+ 0x18, 0x00, /* 000110000000 */
+ 0x30, 0x00, /* 001100000000 */
+ 0x30, 0x00, /* 001100000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
/* 238 0xee '.' */
- /* FIXME */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
+ 0x01, 0xc0, /* 000000011100 */
+ 0x03, 0x00, /* 000000110000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x0c, 0x00, /* 000011000000 */
+ 0x0c, 0x00, /* 000011000000 */
+ 0x18, 0x00, /* 000110000000 */
+ 0x1f, 0xc0, /* 000111111100 */
+ 0x18, 0x00, /* 000110000000 */
+ 0x0c, 0x00, /* 000011000000 */
+ 0x0c, 0x00, /* 000011000000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x03, 0x00, /* 000000110000 */
+ 0x01, 0xc0, /* 000000011100 */
0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
/* 239 0xef '.' */
- /* FIXME */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
+ 0x0f, 0x00, /* 000011110000 */
+ 0x1f, 0x80, /* 000111111000 */
+ 0x39, 0xc0, /* 001110011100 */
+ 0x30, 0xc0, /* 001100001100 */
+ 0x30, 0xc0, /* 001100001100 */
+ 0x30, 0xc0, /* 001100001100 */
+ 0x30, 0xc0, /* 001100001100 */
+ 0x30, 0xc0, /* 001100001100 */
+ 0x30, 0xc0, /* 001100001100 */
+ 0x30, 0xc0, /* 001100001100 */
+ 0x30, 0xc0, /* 001100001100 */
+ 0x30, 0xc0, /* 001100001100 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
/* 240 0xf0 '.' */
- /* FIXME */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
+ 0x7f, 0xe0, /* 011111111110 */
+ 0x7f, 0xe0, /* 011111111110 */
+ 0x00, 0x00, /* 000000000000 */
+ 0x00, 0x00, /* 000000000000 */
+ 0x00, 0x00, /* 000000000000 */
+ 0x7f, 0xe0, /* 011111111110 */
+ 0x7f, 0xe0, /* 011111111110 */
+ 0x00, 0x00, /* 000000000000 */
+ 0x00, 0x00, /* 000000000000 */
+ 0x00, 0x00, /* 000000000000 */
+ 0x7f, 0xe0, /* 011111111110 */
+ 0x7f, 0xe0, /* 011111111110 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
/* 242 0xf2 '.' */
- /* FIXME */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
+ 0x60, 0x00, /* 011000000000 */
+ 0x38, 0x00, /* 001110000000 */
+ 0x0e, 0x00, /* 000011100000 */
+ 0x03, 0x80, /* 000000111000 */
+ 0x00, 0xe0, /* 000000001110 */
+ 0x00, 0xe0, /* 000000001110 */
+ 0x03, 0x80, /* 000000111000 */
+ 0x0e, 0x00, /* 000011100000 */
+ 0x38, 0x00, /* 001110000000 */
+ 0x60, 0x00, /* 011000000000 */
0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
+ 0x7f, 0xe0, /* 011111111110 */
+ 0x7f, 0xe0, /* 011111111110 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
/* 243 0xf3 '.' */
- /* FIXME */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
+ 0x00, 0x60, /* 000000000110 */
+ 0x01, 0xc0, /* 000000011100 */
+ 0x07, 0x00, /* 000001110000 */
+ 0x1c, 0x00, /* 000111000000 */
+ 0x70, 0x00, /* 011100000000 */
+ 0x70, 0x00, /* 011100000000 */
+ 0x1c, 0x00, /* 000111000000 */
+ 0x07, 0x00, /* 000001110000 */
+ 0x01, 0xc0, /* 000000011100 */
+ 0x00, 0x60, /* 000000000110 */
0x00, 0x00, /* 000000000000 */
+ 0x7f, 0xe0, /* 011111111110 */
+ 0x7f, 0xe0, /* 011111111110 */
0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
/* 244 0xf4 '.' */
- /* FIXME */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
+ 0x03, 0x80, /* 000000111000 */
+ 0x07, 0xc0, /* 000001111100 */
+ 0x0c, 0x60, /* 000011000110 */
+ 0x0c, 0x60, /* 000011000110 */
+ 0x0c, 0x00, /* 000011000000 */
+ 0x0c, 0x00, /* 000011000000 */
+ 0x0c, 0x00, /* 000011000000 */
+ 0x0c, 0x00, /* 000011000000 */
+ 0x0c, 0x00, /* 000011000000 */
+ 0x0c, 0x00, /* 000011000000 */
+ 0x0c, 0x00, /* 000011000000 */
+ 0x0c, 0x00, /* 000011000000 */
+ 0x0c, 0x00, /* 000011000000 */
+ 0x0c, 0x00, /* 000011000000 */
+ 0x0c, 0x00, /* 000011000000 */
+ 0x0c, 0x00, /* 000011000000 */
+ 0x0c, 0x00, /* 000011000000 */
+ 0x0c, 0x00, /* 000011000000 */
+ 0x0c, 0x00, /* 000011000000 */
+ 0x0c, 0x00, /* 000011000000 */
+ 0x0c, 0x00, /* 000011000000 */
/* 245 0xf5 '.' */
- /* FIXME */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
- 0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
+ 0x1c, 0x00, /* 000111000000 */
+ 0x3e, 0x00, /* 001111100000 */
+ 0x63, 0x00, /* 011000110000 */
+ 0x63, 0x00, /* 011000110000 */
+ 0x03, 0x00, /* 000000110000 */
+ 0x03, 0x00, /* 000000110000 */
+ 0x03, 0x00, /* 000000110000 */
+ 0x03, 0x00, /* 000000110000 */
+ 0x03, 0x00, /* 000000110000 */
+ 0x03, 0x00, /* 000000110000 */
+ 0x03, 0x00, /* 000000110000 */
+ 0x03, 0x00, /* 000000110000 */
+ 0x03, 0x00, /* 000000110000 */
+ 0x03, 0x00, /* 000000110000 */
+ 0x03, 0x00, /* 000000110000 */
+ 0x03, 0x00, /* 000000110000 */
+ 0x03, 0x00, /* 000000110000 */
+ 0x03, 0x00, /* 000000110000 */
+ 0x03, 0x00, /* 000000110000 */
+ 0x03, 0x00, /* 000000110000 */
+ 0x03, 0x00, /* 000000110000 */
/* 246 0xf6 '.' */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
/* 247 0xf7 '.' */
- /* FIXME */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
+ 0x00, 0x00, /* 000000000000 */
+ 0x00, 0x00, /* 000000000000 */
+ 0x38, 0x00, /* 001110000000 */
+ 0x6c, 0x00, /* 011011000000 */
+ 0x06, 0x30, /* 000001100011 */
+ 0x03, 0x60, /* 000000110110 */
+ 0x39, 0xc0, /* 001110011100 */
+ 0x6c, 0x00, /* 011011000000 */
+ 0x06, 0x30, /* 000001100011 */
+ 0x03, 0x60, /* 000000110110 */
+ 0x01, 0xc0, /* 000000011100 */
+ 0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
/* 249 0xf9 '.' */
- /* FIXME */
- 0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
-
- /* 250 0xfa '.' */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
+ 0x1c, 0x00, /* 000111000000 */
+ 0x3e, 0x00, /* 001111100000 */
+ 0x3e, 0x00, /* 001111100000 */
+ 0x3e, 0x00, /* 001111100000 */
+ 0x1c, 0x00, /* 000111000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
+
+ /* 250 0xfa '.' */
0x00, 0x00, /* 000000000000 */
- 0x06, 0x00, /* 000001100000 */
- 0x0f, 0x00, /* 000011110000 */
- 0x0f, 0x00, /* 000011110000 */
- 0x06, 0x00, /* 000001100000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
-
- /* 251 0xfb '.' */
- /* FIXME */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
+ 0x18, 0x00, /* 000110000000 */
+ 0x3c, 0x00, /* 001111000000 */
+ 0x3c, 0x00, /* 001111000000 */
+ 0x18, 0x00, /* 000110000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
+
+ /* 251 0xfb '.' */
0x00, 0x00, /* 000000000000 */
+ 0x07, 0xe0, /* 000001111110 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0xc6, 0x00, /* 110001100000 */
+ 0x66, 0x00, /* 011001100000 */
+ 0x36, 0x00, /* 001101100000 */
+ 0x1e, 0x00, /* 000111100000 */
+ 0x0e, 0x00, /* 000011100000 */
+ 0x06, 0x00, /* 000001100000 */
+ 0x02, 0x00, /* 000000100000 */
0x00, 0x00, /* 000000000000 */
/* 252 0xfc '.' */
- /* FIXME */
+ 0x00, 0x00, /* 000000000000 */
+ 0x00, 0x00, /* 000000000000 */
+ 0x13, 0x80, /* 000100111000 */
+ 0x3d, 0xc0, /* 001111011100 */
+ 0x18, 0xc0, /* 000110001100 */
+ 0x18, 0xc0, /* 000110001100 */
+ 0x18, 0xc0, /* 000110001100 */
+ 0x18, 0xc0, /* 000110001100 */
+ 0x3d, 0xe0, /* 001111011110 */
+ 0x00, 0x00, /* 000000000000 */
+ 0x00, 0x00, /* 000000000000 */
+ 0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
- 0x3f, 0xc0, /* 001111111100 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */
#undef NO_FONTS
&font_vga_6x11,
#endif
+#ifdef CONFIG_FONT_7x14
+#undef NO_FONTS
+ &font_7x14,
+#endif
#ifdef CONFIG_FONT_SUN8x16
#undef NO_FONTS
&font_sun_8x16,
#undef NO_FONTS
&font_sun_12x22,
#endif
+#ifdef CONFIG_FONT_10x18
+#undef NO_FONTS
+ &font_10x18,
+#endif
#ifdef CONFIG_FONT_ACORN_8x8
#undef NO_FONTS
&font_acorn_8x8,
/* Description of the hardware situation */
static unsigned long vga_vram_base; /* Base of video memory */
static unsigned long vga_vram_end; /* End of video memory */
+static int vga_vram_size; /* Size of video memory */
static u16 vga_video_port_reg; /* Video register select port */
static u16 vga_video_port_val; /* Video register value port */
static unsigned int vga_video_num_columns; /* Number of text columns */
vga_vram_base = VGA_MAP_MEM(vga_vram_base);
vga_vram_end = VGA_MAP_MEM(vga_vram_end);
+ vga_vram_size = vga_vram_end - vga_vram_base;
/*
* Find out if there is a graphics card present.
*/
vga_video_num_columns = c->vc_cols;
vga_video_num_lines = c->vc_rows;
+
+ /* We can only copy out the size of the video buffer here,
+ * otherwise we get into VGA BIOS */
+
if (!vga_is_gfx)
scr_memcpyw((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf,
- c->vc_screenbuf_size);
+ c->vc_screenbuf_size > vga_vram_size ? vga_vram_size : c->vc_screenbuf_size);
return 0; /* Redrawing not needed */
}
if (!lines) /* Turn scrollback off */
c->vc_visible_origin = c->vc_origin;
else {
- int vram_size = vga_vram_end - vga_vram_base;
int margin = c->vc_size_row * 4;
int ul, we, p, st;
we = vga_rolled_over + c->vc_size_row;
} else {
ul = 0;
- we = vram_size;
+ we = vga_vram_size;
}
p = (c->vc_visible_origin - vga_vram_base - ul + we) % we +
lines * c->vc_size_row;
c->vc_x = ORIG_X;
c->vc_y = ORIG_Y;
}
+
+ /* We can't copy in more then the size of the video buffer,
+ * or we'll be copying in VGA BIOS */
+
if (!vga_is_gfx)
scr_memcpyw((u16 *) c->vc_screenbuf, (u16 *) c->vc_origin,
- c->vc_screenbuf_size);
+ c->vc_screenbuf_size > vga_vram_size ? vga_vram_size : c->vc_screenbuf_size);
}
static int vgacon_scroll(struct vc_data *c, int t, int b, int dir,
EXPORT_SYMBOL(fb_get_color_depth);
/*
- * Drawing helpers.
+ * Data padding functions.
*/
-void fb_iomove_buf_aligned(struct fb_info *info, struct fb_pixmap *buf,
- u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch,
- u32 height)
+void fb_pad_aligned_buffer(u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch, u32 height)
{
int i;
for (i = height; i--; ) {
- buf->outbuf(info, dst, src, s_pitch);
+ memcpy(dst, src, s_pitch);
src += s_pitch;
dst += d_pitch;
}
}
+EXPORT_SYMBOL(fb_pad_aligned_buffer);
-void fb_sysmove_buf_aligned(struct fb_info *info, struct fb_pixmap *buf,
- u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch,
- u32 height)
-{
- int i, j;
-
- for (i = height; i--; ) {
- for (j = 0; j < s_pitch; j++)
- dst[j] = src[j];
- src += s_pitch;
- dst += d_pitch;
- }
-}
-
-void fb_iomove_buf_unaligned(struct fb_info *info, struct fb_pixmap *buf,
- u8 *dst, u32 d_pitch, u8 *src, u32 idx,
- u32 height, u32 shift_high, u32 shift_low,
- u32 mod)
-{
- u8 mask = (u8) (0xfff << shift_high), tmp;
- int i, j;
-
- for (i = height; i--; ) {
- for (j = 0; j < idx; j++) {
- tmp = buf->inbuf(info, dst+j);
- tmp &= mask;
- tmp |= *src >> shift_low;
- buf->outbuf(info, dst+j, &tmp, 1);
- tmp = *src << shift_high;
- buf->outbuf(info, dst+j+1, &tmp, 1);
- src++;
- }
- tmp = buf->inbuf(info, dst+idx);
- tmp &= mask;
- tmp |= *src >> shift_low;
- buf->outbuf(info, dst+idx, &tmp, 1);
- if (shift_high < mod) {
- tmp = *src << shift_high;
- buf->outbuf(info, dst+idx+1, &tmp, 1);
- }
- src++;
- dst += d_pitch;
- }
-}
-
-void fb_sysmove_buf_unaligned(struct fb_info *info, struct fb_pixmap *buf,
- u8 *dst, u32 d_pitch, u8 *src, u32 idx,
- u32 height, u32 shift_high, u32 shift_low,
- u32 mod)
+void fb_pad_unaligned_buffer(u8 *dst, u32 d_pitch, u8 *src, u32 idx, u32 height,
+ u32 shift_high, u32 shift_low, u32 mod)
{
u8 mask = (u8) (0xfff << shift_high), tmp;
int i, j;
dst += d_pitch;
}
}
+EXPORT_SYMBOL(fb_pad_unaligned_buffer);
/*
* we need to lock this section since fb_cursor
fb_info->pixmap.size = FBPIXMAPSIZE;
fb_info->pixmap.buf_align = 1;
fb_info->pixmap.scan_align = 1;
- fb_info->pixmap.access_align = 4;
+ fb_info->pixmap.access_align = 32;
fb_info->pixmap.flags = FB_PIXMAP_DEFAULT;
}
}
EXPORT_SYMBOL(fb_blank);
EXPORT_SYMBOL(fb_pan_display);
EXPORT_SYMBOL(fb_get_buffer_offset);
-EXPORT_SYMBOL(fb_iomove_buf_unaligned);
-EXPORT_SYMBOL(fb_iomove_buf_aligned);
-EXPORT_SYMBOL(fb_sysmove_buf_unaligned);
-EXPORT_SYMBOL(fb_sysmove_buf_aligned);
EXPORT_SYMBOL(fb_set_suspend);
EXPORT_SYMBOL(fb_register_client);
EXPORT_SYMBOL(fb_unregister_client);
memset(info->pixmap.addr, 0, 8*1024);
info->pixmap.size = 8*1024;
info->pixmap.buf_align = 8;
+ info->pixmap.access_align = 32;
info->pixmap.flags = FB_PIXMAP_SYSTEM;
if ((err = i810_allocate_pci_resource(par, entry))) {
/* PCI driver module table */
static struct pci_driver intelfb_driver = {
- .name = "Intel(R) " SUPPORTED_CHIPSETS " Framebuffer Driver",
+ .name = "intelfb",
.id_table = intelfb_pci_table,
.probe = intelfb_pci_register,
.remove = __devexit_p(intelfb_pci_unregister)
static int probeonly = 0;
static int idonly = 0;
static int bailearly = 0;
+static int voffset = 48;
static char *mode = NULL;
module_param(accel, bool, S_IRUGO);
MODULE_PARM_DESC(accel, "Enable console acceleration");
module_param(vram, int, S_IRUGO);
MODULE_PARM_DESC(vram, "System RAM to allocate to framebuffer in MiB");
+module_param(voffset, int, S_IRUGO);
+MODULE_PARM_DESC(voffset, "Offset of framebuffer in MiB");
module_param(hwcursor, bool, S_IRUGO);
MODULE_PARM_DESC(hwcursor, "Enable HW cursor");
module_param(mtrr, bool, S_IRUGO);
struct agp_bridge_data *bridge;
int aperture_bar = 0;
int mmio_bar = 1;
+ int offset;
DBG_MSG("intelfb_pci_register\n");
return -ENODEV;
}
+ if (MB(voffset) < stolen_size)
+ offset = (stolen_size >> 12);
+ else
+ offset = ROUND_UP_TO_PAGE(MB(voffset))/GTT_PAGE_SIZE;
+
/* set the mem offsets - set them after the already used pages */
if (dinfo->accel) {
- dinfo->ring.offset = (stolen_size >> 12)
- + gtt_info.current_memory;
+ dinfo->ring.offset = offset + gtt_info.current_memory;
}
if (dinfo->hwcursor) {
- dinfo->cursor.offset = (stolen_size >> 12) +
+ dinfo->cursor.offset = offset +
+ gtt_info.current_memory + (dinfo->ring.size >> 12);
}
if (dinfo->fbmem_gart) {
- dinfo->fb.offset = (stolen_size >> 12) +
+ dinfo->fb.offset = offset +
+ gtt_info.current_memory + (dinfo->ring.size >> 12)
+ (dinfo->cursor.size >> 12);
}
info->pixmap.size = 64*1024;
info->pixmap.buf_align = 8;
+ info->pixmap.access_align = 32;
info->pixmap.flags = FB_PIXMAP_SYSTEM;
if (intelfb_init_var(dinfo))
intelfb_blank(FB_BLANK_POWERDOWN, info);
- if (dinfo->accel)
+ if (ACCEL(dinfo, info))
intelfbhw_2d_stop(dinfo);
memcpy(hw, &dinfo->save_state, sizeof(*hw));
update_dinfo(dinfo, &info->var);
- if (dinfo->accel)
+ if (ACCEL(dinfo, info))
intelfbhw_2d_start(dinfo);
intelfb_pan_display(&info->var, info);
}
static unsigned short normal_i2c[] = { MAVEN_I2CID, I2C_CLIENT_END };
-static unsigned short normal_i2c_range[] = { MAVEN_I2CID, MAVEN_I2CID, I2C_CLIENT_END };
I2C_CLIENT_INSMOD;
static struct i2c_driver maven_driver;
static void nvidiafb_load_cursor_image(struct nvidia_par *par, u8 * data8,
u16 bg, u16 fg, u32 w, u32 h)
{
+ u32 *data = (u32 *) data8;
int i, j, k = 0;
u32 b, tmp;
- u32 *data = (u32 *) data8;
w = (w + 1) & ~1;
{
struct nvidia_par *par = info->par;
u8 data[MAX_CURS * MAX_CURS / 8];
- u16 fg, bg;
int i, set = cursor->set;
+ u16 fg, bg;
if (cursor->image.width > MAX_CURS || cursor->image.height > MAX_CURS)
- return soft_cursor(info, cursor);
+ return -ENXIO;
NVShowHideCursor(par, 0);
if (src) {
switch (cursor->rop) {
case ROP_XOR:
- for (i = 0; i < s_pitch * cursor->image.height;
- i++)
+ for (i = 0; i < s_pitch * cursor->image.height; i++)
src[i] = dat[i] ^ msk[i];
break;
case ROP_COPY:
default:
- for (i = 0; i < s_pitch * cursor->image.height;
- i++)
+ for (i = 0; i < s_pitch * cursor->image.height; i++)
src[i] = dat[i] & msk[i];
break;
}
- fb_sysmove_buf_aligned(info, &info->pixmap, data,
- d_pitch, src, s_pitch,
- cursor->image.height);
+ fb_pad_aligned_buffer(data, d_pitch, src, s_pitch,
+ cursor->image.height);
bg = ((info->cmap.red[bg_idx] & 0xf8) << 7) |
((info->cmap.green[bg_idx] & 0xf8) << 2) |
info->pixmap.scan_align = 4;
info->pixmap.buf_align = 4;
+ info->pixmap.access_align = 32;
info->pixmap.size = 8 * 1024;
info->pixmap.flags = FB_PIXMAP_SYSTEM;
* Based on code written by:
* Sven Luther, <luther@dpt-info.u-strasbg.fr>
* Alan Hourihane, <alanh@fairlite.demon.co.uk>
- * Russel King, <rmk@arm.linux.org.uk>
+ * Russell King, <rmk@arm.linux.org.uk>
* Based on linux/drivers/video/skeletonfb.c:
* Copyright (C) 1997 Geert Uytterhoeven
* Based on linux/driver/video/pm2fb.c:
{
struct riva_par *par = (struct riva_par *) info->par;
u8 data[MAX_CURS * MAX_CURS/8];
- u16 fg, bg;
int i, set = cursor->set;
+ u16 fg, bg;
- if (cursor->image.width > MAX_CURS ||
- cursor->image.height > MAX_CURS)
- return soft_cursor(info, cursor);
+ if (cursor->image.width > MAX_CURS || cursor->image.height > MAX_CURS)
+ return -ENXIO;
par->riva.ShowHideCursor(&par->riva, 0);
if (src) {
switch (cursor->rop) {
case ROP_XOR:
- for (i = 0; i < s_pitch * cursor->image.height;
- i++)
+ for (i = 0; i < s_pitch * cursor->image.height; i++)
src[i] = dat[i] ^ msk[i];
break;
case ROP_COPY:
default:
- for (i = 0; i < s_pitch * cursor->image.height;
- i++)
+ for (i = 0; i < s_pitch * cursor->image.height; i++)
src[i] = dat[i] & msk[i];
break;
}
- fb_sysmove_buf_aligned(info, &info->pixmap, data,
- d_pitch, src, s_pitch,
- cursor->image.height);
+ fb_pad_aligned_buffer(data, d_pitch, src, s_pitch,
+ cursor->image.height);
bg = ((info->cmap.red[bg_idx] & 0xf8) << 7) |
((info->cmap.green[bg_idx] & 0xf8) << 2) |
info->pixmap.size = 8 * 1024;
info->pixmap.buf_align = 4;
+ info->pixmap.access_align = 32;
info->pixmap.flags = FB_PIXMAP_SYSTEM;
info->var.yres_virtual = -1;
NVTRACE_LEAVE();
}
-static int __devexit
+static int
s1d13xxxfb_remove(struct device *dev)
{
struct fb_info *info = dev_get_drvdata(dev);
info->pixmap.size = 8*1024;
info->pixmap.scan_align = 4;
info->pixmap.buf_align = 4;
- info->pixmap.access_align = 4;
+ info->pixmap.access_align = 32;
fb_alloc_cmap (&info->cmap, NR_PALETTE, 0);
info->flags |= FBINFO_HWACCEL_COPYAREA |
} else
memcpy(src, image->data, dsize);
- if (info->pixmap.outbuf)
- fb_iomove_buf_aligned(info, &info->pixmap, dst, d_pitch, src,
- s_pitch, image->height);
- else
- fb_sysmove_buf_aligned(info, &info->pixmap, dst, d_pitch, src,
- s_pitch, image->height);
-
+ fb_pad_aligned_buffer(dst, d_pitch, src, s_pitch, image->height);
image->data = dst;
info->fbops->fb_imageblit(info, image);
kfree(src);
-
return 0;
}
if (!request_mem_region(vesafb_fix.smem_start, size_total, "vesafb")) {
printk(KERN_WARNING
- "vesafb: abort, cannot reserve video memory at 0x%lx\n",
+ "vesafb: cannot reserve video memory at 0x%lx\n",
vesafb_fix.smem_start);
/* We cannot make this fatal. Sometimes this comes from magic
spaces our resource handlers simply don't know about */
info = framebuffer_alloc(sizeof(u32) * 256, &dev->dev);
if (!info) {
- release_mem_region(vesafb_fix.smem_start, vesafb_fix.smem_len);
+ release_mem_region(vesafb_fix.smem_start, size_total);
return -ENOMEM;
}
info->pseudo_palette = info->par;
info->par = NULL;
- info->screen_base = ioremap(vesafb_fix.smem_start, vesafb_fix.smem_len);
+ info->screen_base = ioremap(vesafb_fix.smem_start, vesafb_fix.smem_len);
if (!info->screen_base) {
printk(KERN_ERR
"vesafb: abort, cannot ioremap video memory 0x%x @ 0x%lx\n",
request_region(0x3c0, 32, "vesafb");
if (mtrr) {
- int temp_size = size_total;
+ unsigned int temp_size = size_total;
/* Find the largest power-of-two */
while (temp_size & (temp_size - 1))
temp_size &= (temp_size - 1);
config W1
tristate "Dallas's 1-wire support"
---help---
- Dallas's 1-wire bus is usefull to connect slow 1-pin devices
+ Dallas's 1-wire bus is usefull to connect slow 1-pin devices
such as iButtons and thermal sensors.
-
+
If you want W1 support, you should say Y here.
This W1 support can also be built as a module. If so, the module
help
Say Y here if you want to communicate with your 1-wire devices
using Matrox's G400 GPIO pins.
-
- This support is also available as a module. If so, the module
+
+ This support is also available as a module. If so, the module
will be called matrox_w1.ko.
config W1_DS9490
help
Say Y here if you want to have a driver for DS9490R UWB <-> W1 bridge.
- This support is also available as a module. If so, the module
+ This support is also available as a module. If so, the module
will be called ds9490r.ko.
-config W1_DS9490_BRIDGE
+config W1_DS9490R_BRIDGE
tristate "DS9490R USB <-> W1 transport layer for 1-wire"
depends on W1_DS9490
help
Say Y here if you want to communicate with your 1-wire devices
using DS9490R USB bridge.
- This support is also available as a module. If so, the module
+ This support is also available as a module. If so, the module
will be called ds_w1_bridge.ko.
config W1_THERM
tristate "Simple 64bit memory family implementation"
depends on W1
help
- Say Y here if you want to connect 1-wire
+ Say Y here if you want to connect 1-wire
simple 64bit memory rom(ds2401/ds2411/ds1990*) to you wire.
endmenu
return byte;
}
-static void ds9490r_write_block(unsigned long data, u8 *buf, int len)
+static void ds9490r_write_block(unsigned long data, const u8 *buf, int len)
{
struct ds_device *dev = (struct ds_device *)data;
- ds_write_block(dev, buf, len);
+ ds_write_block(dev, (u8 *)buf, len);
}
static u8 ds9490r_read_block(unsigned long data, u8 *buf, int len)
/*
- * matrox_w1.c
+ * matrox_w1.c
*
* Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
- *
+ *
*
* 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
.remove = __devexit_p(matrox_w1_remove),
};
-/*
+/*
* Matrox G400 DDC registers.
*/
dev->bus_master = (struct w1_bus_master *)(dev + 1);
- /*
- * True for G400, for some other we need resource 0, see drivers/video/matrox/matroxfb_base.c
+ /*
+ * True for G400, for some other we need resource 0, see drivers/video/matrox/matroxfb_base.c
*/
dev->phys_addr = pci_resource_start(pdev, 1);
/*
- * w1.c
+ * w1.c
*
* Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
- *
+ *
*
* 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
static int control_needs_exit;
static DECLARE_COMPLETION(w1_control_complete);
+/* stuff for the default family */
+static ssize_t w1_famdefault_read_name(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
+ return(sprintf(buf, "%s\n", sl->name));
+}
+static struct w1_family_ops w1_default_fops = {
+ .rname = &w1_famdefault_read_name,
+};
+static struct w1_family w1_default_family = {
+ .fops = &w1_default_fops,
+};
+
static int w1_master_match(struct device *dev, struct device_driver *drv)
{
return 1;
return sprintf(buf, "No family registered.\n");
}
+static struct device_attribute w1_slave_attribute =
+ __ATTR(name, S_IRUGO, w1_default_read_name, NULL);
+
+static struct bin_attribute w1_slave_bin_attribute = {
+ .attr = {
+ .name = "w1_slave",
+ .mode = S_IRUGO,
+ .owner = THIS_MODULE,
+ },
+ .size = W1_SLAVE_DATA_SIZE,
+ .read = &w1_default_read_bin,
+};
+
+
static struct bus_type w1_bus_type = {
.name = "w1",
.match = w1_master_match,
.release = &w1_master_release
};
-static struct device_attribute w1_slave_attribute = {
- .attr = {
- .name = "name",
- .mode = S_IRUGO,
- .owner = THIS_MODULE
- },
- .show = &w1_default_read_name,
-};
-
-static struct device_attribute w1_slave_attribute_val = {
- .attr = {
- .name = "value",
- .mode = S_IRUGO,
- .owner = THIS_MODULE
- },
- .show = &w1_default_read_name,
-};
-
static ssize_t w1_master_attribute_show_name(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct w1_master *md = container_of (dev, struct w1_master, dev);
+ struct w1_master *md = container_of(dev, struct w1_master, dev);
ssize_t count;
-
+
if (down_interruptible (&md->mutex))
return -EBUSY;
count = sprintf(buf, "%s\n", md->name);
-
+
+ up(&md->mutex);
+
+ return count;
+}
+
+static ssize_t w1_master_attribute_store_search(struct device * dev,
+ struct device_attribute *attr,
+ const char * buf, size_t count)
+{
+ struct w1_master *md = container_of(dev, struct w1_master, dev);
+
+ if (down_interruptible (&md->mutex))
+ return -EBUSY;
+
+ md->search_count = simple_strtol(buf, NULL, 0);
+
+ up(&md->mutex);
+
+ return count;
+}
+
+static ssize_t w1_master_attribute_show_search(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct w1_master *md = container_of(dev, struct w1_master, dev);
+ ssize_t count;
+
+ if (down_interruptible (&md->mutex))
+ return -EBUSY;
+
+ count = sprintf(buf, "%d\n", md->search_count);
+
up(&md->mutex);
return count;
{
struct w1_master *md = container_of(dev, struct w1_master, dev);
ssize_t count;
-
+
if (down_interruptible(&md->mutex))
return -EBUSY;
count = sprintf(buf, "0x%p\n", md->bus_master);
-
+
up(&md->mutex);
return count;
}
{
struct w1_master *md = container_of(dev, struct w1_master, dev);
ssize_t count;
-
+
if (down_interruptible(&md->mutex))
return -EBUSY;
count = sprintf(buf, "%d\n", md->max_slave_count);
-
+
up(&md->mutex);
return count;
}
{
struct w1_master *md = container_of(dev, struct w1_master, dev);
ssize_t count;
-
+
if (down_interruptible(&md->mutex))
return -EBUSY;
count = sprintf(buf, "%lu\n", md->attempts);
-
+
up(&md->mutex);
return count;
}
{
struct w1_master *md = container_of(dev, struct w1_master, dev);
ssize_t count;
-
+
if (down_interruptible(&md->mutex))
return -EBUSY;
count = sprintf(buf, "%d\n", md->slave_count);
-
+
up(&md->mutex);
return count;
}
static ssize_t w1_master_attribute_show_slaves(struct device *dev, struct device_attribute *attr, char *buf)
-
{
struct w1_master *md = container_of(dev, struct w1_master, dev);
int c = PAGE_SIZE;
list_for_each_safe(ent, n, &md->slist) {
sl = list_entry(ent, struct w1_slave, w1_slave_entry);
- c -= snprintf(buf + PAGE_SIZE - c, c, "%s\n", sl->name);
+ c -= snprintf(buf + PAGE_SIZE - c, c, "%s\n", sl->name);
}
}
return PAGE_SIZE - c;
}
-static struct device_attribute w1_master_attribute_slaves = {
- .attr = {
- .name = "w1_master_slaves",
- .mode = S_IRUGO,
- .owner = THIS_MODULE,
- },
- .show = &w1_master_attribute_show_slaves,
-};
-static struct device_attribute w1_master_attribute_slave_count = {
- .attr = {
- .name = "w1_master_slave_count",
- .mode = S_IRUGO,
- .owner = THIS_MODULE
- },
- .show = &w1_master_attribute_show_slave_count,
-};
-static struct device_attribute w1_master_attribute_attempts = {
- .attr = {
- .name = "w1_master_attempts",
- .mode = S_IRUGO,
- .owner = THIS_MODULE
- },
- .show = &w1_master_attribute_show_attempts,
-};
-static struct device_attribute w1_master_attribute_max_slave_count = {
- .attr = {
- .name = "w1_master_max_slave_count",
- .mode = S_IRUGO,
- .owner = THIS_MODULE
- },
- .show = &w1_master_attribute_show_max_slave_count,
-};
-static struct device_attribute w1_master_attribute_timeout = {
- .attr = {
- .name = "w1_master_timeout",
- .mode = S_IRUGO,
- .owner = THIS_MODULE
- },
- .show = &w1_master_attribute_show_timeout,
-};
-static struct device_attribute w1_master_attribute_pointer = {
- .attr = {
- .name = "w1_master_pointer",
- .mode = S_IRUGO,
- .owner = THIS_MODULE
- },
- .show = &w1_master_attribute_show_pointer,
-};
-static struct device_attribute w1_master_attribute_name = {
- .attr = {
- .name = "w1_master_name",
- .mode = S_IRUGO,
- .owner = THIS_MODULE
- },
- .show = &w1_master_attribute_show_name,
+#define W1_MASTER_ATTR_RO(_name, _mode) \
+ struct device_attribute w1_master_attribute_##_name = \
+ __ATTR(w1_master_##_name, _mode, \
+ w1_master_attribute_show_##_name, NULL)
+
+#define W1_MASTER_ATTR_RW(_name, _mode) \
+ struct device_attribute w1_master_attribute_##_name = \
+ __ATTR(w1_master_##_name, _mode, \
+ w1_master_attribute_show_##_name, \
+ w1_master_attribute_store_##_name)
+
+static W1_MASTER_ATTR_RO(name, S_IRUGO);
+static W1_MASTER_ATTR_RO(slaves, S_IRUGO);
+static W1_MASTER_ATTR_RO(slave_count, S_IRUGO);
+static W1_MASTER_ATTR_RO(max_slave_count, S_IRUGO);
+static W1_MASTER_ATTR_RO(attempts, S_IRUGO);
+static W1_MASTER_ATTR_RO(timeout, S_IRUGO);
+static W1_MASTER_ATTR_RO(pointer, S_IRUGO);
+static W1_MASTER_ATTR_RW(search, S_IRUGO | S_IWUGO);
+
+static struct attribute *w1_master_default_attrs[] = {
+ &w1_master_attribute_name.attr,
+ &w1_master_attribute_slaves.attr,
+ &w1_master_attribute_slave_count.attr,
+ &w1_master_attribute_max_slave_count.attr,
+ &w1_master_attribute_attempts.attr,
+ &w1_master_attribute_timeout.attr,
+ &w1_master_attribute_pointer.attr,
+ &w1_master_attribute_search.attr,
+ NULL
};
-static struct bin_attribute w1_slave_bin_attribute = {
- .attr = {
- .name = "w1_slave",
- .mode = S_IRUGO,
- .owner = THIS_MODULE,
- },
- .size = W1_SLAVE_DATA_SIZE,
- .read = &w1_default_read_bin,
+static struct attribute_group w1_master_defattr_group = {
+ .attrs = w1_master_default_attrs,
};
+int w1_create_master_attributes(struct w1_master *master)
+{
+ return sysfs_create_group(&master->dev.kobj, &w1_master_defattr_group);
+}
+
+void w1_destroy_master_attributes(struct w1_master *master)
+{
+ sysfs_remove_group(&master->dev.kobj, &w1_master_defattr_group);
+}
+
static int __w1_attach_slave_device(struct w1_slave *sl)
{
int err;
sl->dev.release = &w1_slave_release;
snprintf(&sl->dev.bus_id[0], sizeof(sl->dev.bus_id),
- "%02x-%012llx",
- (unsigned int) sl->reg_num.family,
- (unsigned long long) sl->reg_num.id);
- snprintf (&sl->name[0], sizeof(sl->name),
- "%02x-%012llx",
- (unsigned int) sl->reg_num.family,
- (unsigned long long) sl->reg_num.id);
+ "%02x-%012llx",
+ (unsigned int) sl->reg_num.family,
+ (unsigned long long) sl->reg_num.id);
+ snprintf(&sl->name[0], sizeof(sl->name),
+ "%02x-%012llx",
+ (unsigned int) sl->reg_num.family,
+ (unsigned long long) sl->reg_num.id);
dev_dbg(&sl->dev, "%s: registering %s.\n", __func__,
&sl->dev.bus_id[0]);
err = device_register(&sl->dev);
if (err < 0) {
dev_err(&sl->dev,
- "Device registration [%s] failed. err=%d\n",
- sl->dev.bus_id, err);
+ "Device registration [%s] failed. err=%d\n",
+ sl->dev.bus_id, err);
return err;
}
memcpy(&sl->attr_bin, &w1_slave_bin_attribute, sizeof(sl->attr_bin));
memcpy(&sl->attr_name, &w1_slave_attribute, sizeof(sl->attr_name));
- memcpy(&sl->attr_val, &w1_slave_attribute_val, sizeof(sl->attr_val));
-
+
sl->attr_bin.read = sl->family->fops->rbin;
sl->attr_name.show = sl->family->fops->rname;
- sl->attr_val.show = sl->family->fops->rval;
- sl->attr_val.attr.name = sl->family->fops->rvalname;
err = device_create_file(&sl->dev, &sl->attr_name);
if (err < 0) {
dev_err(&sl->dev,
- "sysfs file creation for [%s] failed. err=%d\n",
- sl->dev.bus_id, err);
- device_unregister(&sl->dev);
- return err;
- }
-
- err = device_create_file(&sl->dev, &sl->attr_val);
- if (err < 0) {
- dev_err(&sl->dev,
- "sysfs file creation for [%s] failed. err=%d\n",
- sl->dev.bus_id, err);
- device_remove_file(&sl->dev, &sl->attr_name);
+ "sysfs file creation for [%s] failed. err=%d\n",
+ sl->dev.bus_id, err);
device_unregister(&sl->dev);
return err;
}
- err = sysfs_create_bin_file(&sl->dev.kobj, &sl->attr_bin);
- if (err < 0) {
- dev_err(&sl->dev,
- "sysfs file creation for [%s] failed. err=%d\n",
- sl->dev.bus_id, err);
- device_remove_file(&sl->dev, &sl->attr_name);
- device_remove_file(&sl->dev, &sl->attr_val);
- device_unregister(&sl->dev);
- return err;
+ if ( sl->attr_bin.read ) {
+ err = sysfs_create_bin_file(&sl->dev.kobj, &sl->attr_bin);
+ if (err < 0) {
+ dev_err(&sl->dev,
+ "sysfs file creation for [%s] failed. err=%d\n",
+ sl->dev.bus_id, err);
+ device_remove_file(&sl->dev, &sl->attr_name);
+ device_unregister(&sl->dev);
+ return err;
+ }
}
list_add_tail(&sl->w1_slave_entry, &sl->master->slist);
spin_lock(&w1_flock);
f = w1_family_registered(rn->family);
if (!f) {
- spin_unlock(&w1_flock);
+ f= &w1_default_family;
dev_info(&dev->dev, "Family %x for %02x.%012llx.%02x is not registered.\n",
rn->family, rn->family,
(unsigned long long)rn->id, rn->crc);
- kfree(sl);
- return -ENODEV;
}
__w1_family_get(f);
spin_unlock(&w1_flock);
static void w1_slave_detach(struct w1_slave *sl)
{
struct w1_netlink_msg msg;
-
+
dev_info(&sl->dev, "%s: detaching %s.\n", __func__, sl->name);
while (atomic_read(&sl->refcnt)) {
flush_signals(current);
}
- sysfs_remove_bin_file (&sl->dev.kobj, &sl->attr_bin);
+ if ( sl->attr_bin.read ) {
+ sysfs_remove_bin_file (&sl->dev.kobj, &sl->attr_bin);
+ }
device_remove_file(&sl->dev, &sl->attr_name);
- device_remove_file(&sl->dev, &sl->attr_val);
device_unregister(&sl->dev);
w1_family_put(sl->family);
+ sl->master->slave_count--;
+
memcpy(&msg.id.id, &sl->reg_num, sizeof(msg.id.id));
msg.type = W1_SLAVE_REMOVE;
w1_netlink_send(sl->master, &msg);
{
struct w1_master *dev;
int found = 0;
-
- spin_lock_irq(&w1_mlock);
+
+ spin_lock_bh(&w1_mlock);
list_for_each_entry(dev, &w1_masters, w1_master_entry) {
if (dev->bus_master->data == data) {
found = 1;
break;
}
}
- spin_unlock_irq(&w1_mlock);
+ spin_unlock_bh(&w1_mlock);
return (found)?dev:NULL;
}
-void w1_slave_found(unsigned long data, u64 rn)
+void w1_reconnect_slaves(struct w1_family *f)
+{
+ struct w1_master *dev;
+
+ spin_lock_bh(&w1_mlock);
+ list_for_each_entry(dev, &w1_masters, w1_master_entry) {
+ dev_info(&dev->dev, "Reconnecting slaves in %s into new family %02x.\n",
+ dev->name, f->fid);
+ set_bit(W1_MASTER_NEED_RECONNECT, &dev->flags);
+ }
+ spin_unlock_bh(&w1_mlock);
+}
+
+
+static void w1_slave_found(unsigned long data, u64 rn)
{
int slave_count;
struct w1_slave *sl;
data);
return;
}
-
+
tmp = (struct w1_reg_num *) &rn;
slave_count = 0;
sl->reg_num.crc == tmp->crc) {
set_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags);
break;
- }
- else if (sl->reg_num.family == tmp->family) {
+ } else if (sl->reg_num.family == tmp->family) {
family_found = 1;
break;
}
rn && ((le64_to_cpu(rn) >> 56) & 0xff) == w1_calc_crc8((u8 *)&rn, 7)) {
w1_attach_slave_device(dev, tmp);
}
-
+
atomic_dec(&dev->refcnt);
}
-void w1_search(struct w1_master *dev)
+/**
+ * Performs a ROM Search & registers any devices found.
+ * The 1-wire search is a simple binary tree search.
+ * For each bit of the address, we read two bits and write one bit.
+ * The bit written will put to sleep all devies that don't match that bit.
+ * When the two reads differ, the direction choice is obvious.
+ * When both bits are 0, we must choose a path to take.
+ * When we can scan all 64 bits without having to choose a path, we are done.
+ *
+ * See "Application note 187 1-wire search algorithm" at www.maxim-ic.com
+ *
+ * @dev The master device to search
+ * @cb Function to call when a device is found
+ */
+void w1_search(struct w1_master *dev, w1_slave_found_callback cb)
{
- u64 last, rn, tmp;
- int i, count = 0;
- int last_family_desc, last_zero, last_device;
- int search_bit, id_bit, comp_bit, desc_bit;
+ u64 last_rn, rn, tmp64;
+ int i, slave_count = 0;
+ int last_zero, last_device;
+ int search_bit, desc_bit;
+ u8 triplet_ret = 0;
- search_bit = id_bit = comp_bit = 0;
- rn = tmp = last = 0;
- last_device = last_zero = last_family_desc = 0;
+ search_bit = 0;
+ rn = last_rn = 0;
+ last_device = 0;
+ last_zero = -1;
desc_bit = 64;
- while (!(id_bit && comp_bit) && !last_device
- && count++ < dev->max_slave_count) {
- last = rn;
+ while ( !last_device && (slave_count++ < dev->max_slave_count) ) {
+ last_rn = rn;
rn = 0;
- last_family_desc = 0;
-
/*
* Reset bus and all 1-wire device state machines
* so they can respond to our requests.
break;
}
-#if 1
+ /* Start the search */
w1_write_8(dev, W1_SEARCH);
for (i = 0; i < 64; ++i) {
- /*
- * Read 2 bits from bus.
- * All who don't sleep must send ID bit and COMPLEMENT ID bit.
- * They actually are ANDed between all senders.
- */
- id_bit = w1_touch_bit(dev, 1);
- comp_bit = w1_touch_bit(dev, 1);
-
- if (id_bit && comp_bit)
- break;
-
- if (id_bit == 0 && comp_bit == 0) {
- if (i == desc_bit)
- search_bit = 1;
- else if (i > desc_bit)
- search_bit = 0;
- else
- search_bit = ((last >> i) & 0x1);
-
- if (search_bit == 0) {
- last_zero = i;
- if (last_zero < 9)
- last_family_desc = last_zero;
- }
-
- }
+ /* Determine the direction/search bit */
+ if (i == desc_bit)
+ search_bit = 1; /* took the 0 path last time, so take the 1 path */
+ else if (i > desc_bit)
+ search_bit = 0; /* take the 0 path on the next branch */
else
- search_bit = id_bit;
+ search_bit = ((last_rn >> i) & 0x1);
- tmp = search_bit;
- rn |= (tmp << i);
+ /** Read two bits and write one bit */
+ triplet_ret = w1_triplet(dev, search_bit);
- /*
- * Write 1 bit to bus
- * and make all who don't have "search_bit" in "i"'th position
- * in it's registration number sleep.
- */
- if (dev->bus_master->touch_bit)
- w1_touch_bit(dev, search_bit);
- else
- w1_write_bit(dev, search_bit);
+ /* quit if no device responded */
+ if ( (triplet_ret & 0x03) == 0x03 )
+ break;
- }
-#endif
+ /* If both directions were valid, and we took the 0 path... */
+ if (triplet_ret == 0)
+ last_zero = i;
- if (desc_bit == last_zero)
- last_device = 1;
+ /* extract the direction taken & update the device number */
+ tmp64 = (triplet_ret >> 2);
+ rn |= (tmp64 << i);
+ }
- desc_bit = last_zero;
-
- w1_slave_found(dev->bus_master->data, rn);
+ if ( (triplet_ret & 0x03) != 0x03 ) {
+ if ( (desc_bit == last_zero) || (last_zero < 0))
+ last_device = 1;
+ desc_bit = last_zero;
+ cb(dev->bus_master->data, rn);
+ }
}
}
-int w1_create_master_attributes(struct w1_master *dev)
-{
- if ( device_create_file(&dev->dev, &w1_master_attribute_slaves) < 0 ||
- device_create_file(&dev->dev, &w1_master_attribute_slave_count) < 0 ||
- device_create_file(&dev->dev, &w1_master_attribute_attempts) < 0 ||
- device_create_file(&dev->dev, &w1_master_attribute_max_slave_count) < 0 ||
- device_create_file(&dev->dev, &w1_master_attribute_timeout) < 0||
- device_create_file(&dev->dev, &w1_master_attribute_pointer) < 0||
- device_create_file(&dev->dev, &w1_master_attribute_name) < 0)
- return -EINVAL;
-
- return 0;
-}
-
-void w1_destroy_master_attributes(struct w1_master *dev)
+static int w1_control(void *data)
{
- device_remove_file(&dev->dev, &w1_master_attribute_slaves);
- device_remove_file(&dev->dev, &w1_master_attribute_slave_count);
- device_remove_file(&dev->dev, &w1_master_attribute_attempts);
- device_remove_file(&dev->dev, &w1_master_attribute_max_slave_count);
- device_remove_file(&dev->dev, &w1_master_attribute_timeout);
- device_remove_file(&dev->dev, &w1_master_attribute_pointer);
- device_remove_file(&dev->dev, &w1_master_attribute_name);
-}
-
-
-int w1_control(void *data)
-{
- struct w1_slave *sl;
- struct w1_master *dev;
- struct list_head *ent, *ment, *n, *mn;
+ struct w1_slave *sl, *sln;
+ struct w1_master *dev, *n;
int err, have_to_wait = 0;
daemonize("w1_control");
if (signal_pending(current))
flush_signals(current);
- list_for_each_safe(ment, mn, &w1_masters) {
- dev = list_entry(ment, struct w1_master, w1_master_entry);
-
- if (!control_needs_exit && !dev->need_exit)
+ list_for_each_entry_safe(dev, n, &w1_masters, w1_master_entry) {
+ if (!control_needs_exit && !dev->flags)
continue;
/*
* Little race: we can create thread but not set the flag.
continue;
}
- spin_lock(&w1_mlock);
- list_del(&dev->w1_master_entry);
- spin_unlock(&w1_mlock);
-
if (control_needs_exit) {
- dev->need_exit = 1;
+ set_bit(W1_MASTER_NEED_EXIT, &dev->flags);
err = kill_proc(dev->kpid, SIGTERM, 1);
if (err)
dev->kpid);
}
- wait_for_completion(&dev->dev_exited);
-
- list_for_each_safe(ent, n, &dev->slist) {
- sl = list_entry(ent, struct w1_slave, w1_slave_entry);
+ if (test_bit(W1_MASTER_NEED_EXIT, &dev->flags)) {
+ wait_for_completion(&dev->dev_exited);
+ spin_lock_bh(&w1_mlock);
+ list_del(&dev->w1_master_entry);
+ spin_unlock_bh(&w1_mlock);
- if (!sl)
- dev_warn(&dev->dev,
- "%s: slave entry is NULL.\n",
- __func__);
- else {
+ list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) {
list_del(&sl->w1_slave_entry);
w1_slave_detach(sl);
kfree(sl);
}
+ w1_destroy_master_attributes(dev);
+ atomic_dec(&dev->refcnt);
+ continue;
+ }
+
+ if (test_bit(W1_MASTER_NEED_RECONNECT, &dev->flags)) {
+ dev_info(&dev->dev, "Reconnecting slaves in device %s.\n", dev->name);
+ down(&dev->mutex);
+ list_for_each_entry(sl, &dev->slist, w1_slave_entry) {
+ if (sl->family->fid == W1_FAMILY_DEFAULT) {
+ struct w1_reg_num rn;
+ list_del(&sl->w1_slave_entry);
+ w1_slave_detach(sl);
+
+ memcpy(&rn, &sl->reg_num, sizeof(rn));
+
+ kfree(sl);
+
+ w1_attach_slave_device(dev, &rn);
+ }
+ }
+ clear_bit(W1_MASTER_NEED_RECONNECT, &dev->flags);
+ up(&dev->mutex);
}
- w1_destroy_master_attributes(dev);
- atomic_dec(&dev->refcnt);
}
}
int w1_process(void *data)
{
struct w1_master *dev = (struct w1_master *) data;
- struct list_head *ent, *n;
- struct w1_slave *sl;
+ struct w1_slave *sl, *sln;
daemonize("%s", dev->name);
allow_signal(SIGTERM);
- while (!dev->need_exit) {
+ while (!test_bit(W1_MASTER_NEED_EXIT, &dev->flags)) {
try_to_freeze(PF_FREEZE);
msleep_interruptible(w1_timeout * 1000);
if (signal_pending(current))
flush_signals(current);
- if (dev->need_exit)
+ if (test_bit(W1_MASTER_NEED_EXIT, &dev->flags))
break;
if (!dev->initialized)
continue;
+ if (dev->search_count == 0)
+ continue;
+
if (down_interruptible(&dev->mutex))
continue;
- list_for_each_safe(ent, n, &dev->slist) {
- sl = list_entry(ent, struct w1_slave, w1_slave_entry);
+ list_for_each_entry(sl, &dev->slist, w1_slave_entry)
+ clear_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags);
- if (sl)
- clear_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags);
- }
-
w1_search_devices(dev, w1_slave_found);
- list_for_each_safe(ent, n, &dev->slist) {
- sl = list_entry(ent, struct w1_slave, w1_slave_entry);
-
- if (sl && !test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags) && !--sl->ttl) {
+ list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) {
+ if (!test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags) && !--sl->ttl) {
list_del (&sl->w1_slave_entry);
w1_slave_detach (sl);
kfree (sl);
dev->slave_count--;
- }
- else if (test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags))
+ } else if (test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags))
sl->ttl = dev->slave_ttl;
}
+
+ if (dev->search_count > 0)
+ dev->search_count--;
+
up(&dev->mutex);
}
return 0;
}
-int w1_init(void)
+static int w1_init(void)
{
int retval;
return retval;
}
-void w1_fini(void)
+static void w1_fini(void)
{
struct w1_master *dev;
- struct list_head *ent, *n;
- list_for_each_safe(ent, n, &w1_masters) {
- dev = list_entry(ent, struct w1_master, w1_master_entry);
+ list_for_each_entry(dev, &w1_masters, w1_master_entry)
__w1_remove_master_device(dev);
- }
control_needs_exit = 1;
-
wait_for_completion(&w1_control_complete);
driver_unregister(&w1_driver);
/*
- * w1.h
+ * w1.h
*
* Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
- *
+ *
*
* 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
int ttl;
struct w1_master *master;
- struct w1_family *family;
- struct device dev;
- struct completion dev_released;
+ struct w1_family *family;
+ struct device dev;
+ struct completion dev_released;
- struct bin_attribute attr_bin;
- struct device_attribute attr_name, attr_val;
+ struct bin_attribute attr_bin;
+ struct device_attribute attr_name;
};
typedef void (* w1_slave_found_callback)(unsigned long, u64);
+
+/**
+ * Note: read_bit and write_bit are very low level functions and should only
+ * be used with hardware that doesn't really support 1-wire operations,
+ * like a parallel/serial port.
+ * Either define read_bit and write_bit OR define, at minimum, touch_bit and
+ * reset_bus.
+ */
struct w1_bus_master
{
- unsigned long data;
-
- u8 (*read_bit)(unsigned long);
- void (*write_bit)(unsigned long, u8);
-
- u8 (*read_byte)(unsigned long);
- void (*write_byte)(unsigned long, u8);
-
- u8 (*read_block)(unsigned long, u8 *, int);
- void (*write_block)(unsigned long, u8 *, int);
-
- u8 (*touch_bit)(unsigned long, u8);
-
- u8 (*reset_bus)(unsigned long);
-
- void (*search)(unsigned long, w1_slave_found_callback);
+ /** the first parameter in all the functions below */
+ unsigned long data;
+
+ /**
+ * Sample the line level
+ * @return the level read (0 or 1)
+ */
+ u8 (*read_bit)(unsigned long);
+
+ /** Sets the line level */
+ void (*write_bit)(unsigned long, u8);
+
+ /**
+ * touch_bit is the lowest-level function for devices that really
+ * support the 1-wire protocol.
+ * touch_bit(0) = write-0 cycle
+ * touch_bit(1) = write-1 / read cycle
+ * @return the bit read (0 or 1)
+ */
+ u8 (*touch_bit)(unsigned long, u8);
+
+ /**
+ * Reads a bytes. Same as 8 touch_bit(1) calls.
+ * @return the byte read
+ */
+ u8 (*read_byte)(unsigned long);
+
+ /**
+ * Writes a byte. Same as 8 touch_bit(x) calls.
+ */
+ void (*write_byte)(unsigned long, u8);
+
+ /**
+ * Same as a series of read_byte() calls
+ * @return the number of bytes read
+ */
+ u8 (*read_block)(unsigned long, u8 *, int);
+
+ /** Same as a series of write_byte() calls */
+ void (*write_block)(unsigned long, const u8 *, int);
+
+ /**
+ * Combines two reads and a smart write for ROM searches
+ * @return bit0=Id bit1=comp_id bit2=dir_taken
+ */
+ u8 (*triplet)(unsigned long, u8);
+
+ /**
+ * long write-0 with a read for the presence pulse detection
+ * @return -1=Error, 0=Device present, 1=No device present
+ */
+ u8 (*reset_bus)(unsigned long);
+
+ /** Really nice hardware can handles the ROM searches */
+ void (*search)(unsigned long, w1_slave_found_callback);
};
+#define W1_MASTER_NEED_EXIT 0
+#define W1_MASTER_NEED_RECONNECT 1
+
struct w1_master
{
struct list_head w1_master_entry;
int slave_ttl;
int initialized;
u32 id;
+ int search_count;
atomic_t refcnt;
void *priv;
int priv_size;
- int need_exit;
+ long flags;
+
pid_t kpid;
- struct semaphore mutex;
+ struct semaphore mutex;
struct device_driver *driver;
- struct device dev;
- struct completion dev_released;
- struct completion dev_exited;
+ struct device dev;
+ struct completion dev_released;
+ struct completion dev_exited;
struct w1_bus_master *bus_master;
u32 seq, groups;
- struct sock *nls;
+ struct sock *nls;
};
int w1_create_master_attributes(struct w1_master *);
-void w1_destroy_master_attributes(struct w1_master *);
-void w1_search(struct w1_master *dev);
+void w1_search(struct w1_master *dev, w1_slave_found_callback cb);
#endif /* __KERNEL__ */
/*
- * w1_family.c
+ * w1_family.c
*
* Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
- *
+ *
*
* 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
DEFINE_SPINLOCK(w1_flock);
static LIST_HEAD(w1_families);
+extern void w1_reconnect_slaves(struct w1_family *f);
static int w1_check_family(struct w1_family *f)
{
- if (!f->fops->rname || !f->fops->rbin || !f->fops->rval || !f->fops->rvalname)
+ if (!f->fops->rname || !f->fops->rbin)
return -EINVAL;
return 0;
newf->need_exit = 0;
list_add_tail(&newf->family_entry, &w1_families);
}
-
spin_unlock(&w1_flock);
+ w1_reconnect_slaves(newf);
+
return ret;
}
/*
- * w1_family.h
+ * w1_family.h
*
* Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
- *
+ *
*
* 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
#include <asm/atomic.h>
#define W1_FAMILY_DEFAULT 0
-#define W1_FAMILY_THERM 0x10
-#define W1_FAMILY_SMEM 0x01
+#define W1_FAMILY_SMEM_01 0x01
+#define W1_FAMILY_SMEM_81 0x81
+#define W1_THERM_DS18S20 0x10
+#define W1_THERM_DS1822 0x22
+#define W1_THERM_DS18B20 0x28
#define MAXNAMELEN 32
{
ssize_t (* rname)(struct device *, struct device_attribute *, char *);
ssize_t (* rbin)(struct kobject *, char *, loff_t, size_t);
-
- ssize_t (* rval)(struct device *, struct device_attribute *, char *);
- unsigned char rvalname[MAXNAMELEN];
};
struct w1_family
{
struct list_head family_entry;
u8 fid;
-
+
struct w1_family_ops *fops;
-
+
atomic_t refcnt;
u8 need_exit;
};
/*
- * w1_int.c
+ * w1_int.c
*
* Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
- *
+ *
*
* 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
extern int w1_process(void *);
-struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl,
- struct device_driver *driver, struct device *device)
+static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl,
+ struct device_driver *driver,
+ struct device *device)
{
struct w1_master *dev;
int err;
dev->bus_master = (struct w1_bus_master *)(dev + 1);
- dev->owner = THIS_MODULE;
- dev->max_slave_count = slave_count;
- dev->slave_count = 0;
- dev->attempts = 0;
- dev->kpid = -1;
- dev->initialized = 0;
- dev->id = id;
+ dev->owner = THIS_MODULE;
+ dev->max_slave_count = slave_count;
+ dev->slave_count = 0;
+ dev->attempts = 0;
+ dev->kpid = -1;
+ dev->initialized = 0;
+ dev->id = id;
dev->slave_ttl = slave_ttl;
+ dev->search_count = -1; /* continual scan */
atomic_set(&dev->refcnt, 2);
return dev;
}
-void w1_free_dev(struct w1_master *dev)
+static void w1_free_dev(struct w1_master *dev)
{
device_unregister(&dev->dev);
if (dev->nls && dev->nls->sk_socket)
int retval = 0;
struct w1_netlink_msg msg;
+ /* validate minimum functionality */
+ if (!(master->touch_bit && master->reset_bus) &&
+ !(master->write_bit && master->read_bit)) {
+ printk(KERN_ERR "w1_add_master_device: invalid function set\n");
+ return(-EINVAL);
+ }
+
dev = w1_alloc_dev(w1_ids++, w1_max_slave_count, w1_max_slave_ttl, &w1_driver, &w1_device);
if (!dev)
return -ENOMEM;
return 0;
err_out_kill_thread:
- dev->need_exit = 1;
+ set_bit(W1_MASTER_NEED_EXIT, &dev->flags);
if (kill_proc(dev->kpid, SIGTERM, 1))
dev_err(&dev->dev,
"Failed to send signal to w1 kernel thread %d.\n",
int err;
struct w1_netlink_msg msg;
- dev->need_exit = 1;
+ set_bit(W1_MASTER_NEED_EXIT, &dev->flags);
err = kill_proc(dev->kpid, SIGTERM, 1);
if (err)
dev_err(&dev->dev,
void w1_remove_master_device(struct w1_bus_master *bm)
{
struct w1_master *dev = NULL;
- struct list_head *ent, *n;
- list_for_each_safe(ent, n, &w1_masters) {
- dev = list_entry(ent, struct w1_master, w1_master_entry);
+ list_for_each_entry(dev, &w1_masters, w1_master_entry) {
if (!dev->initialized)
continue;
/*
- * w1_int.h
+ * w1_int.h
*
* Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
- *
+ *
*
* 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
#include "w1.h"
-struct w1_master * w1_alloc_dev(u32, int, int, struct device_driver *, struct device *);
-void w1_free_dev(struct w1_master *dev);
int w1_add_master_device(struct w1_bus_master *);
void w1_remove_master_device(struct w1_bus_master *);
void __w1_remove_master_device(struct w1_master *);
/*
- * w1_io.c
+ * w1_io.c
*
* Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
- *
+ *
*
* 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
udelay(tm * w1_delay_parm);
}
+static void w1_write_bit(struct w1_master *dev, int bit);
+static u8 w1_read_bit(struct w1_master *dev);
+
+/**
+ * Generates a write-0 or write-1 cycle and samples the level.
+ */
u8 w1_touch_bit(struct w1_master *dev, int bit)
{
if (dev->bus_master->touch_bit)
return dev->bus_master->touch_bit(dev->bus_master->data, bit);
- else
+ else if (bit)
return w1_read_bit(dev);
+ else {
+ w1_write_bit(dev, 0);
+ return(0);
+ }
}
-void w1_write_bit(struct w1_master *dev, int bit)
+/**
+ * Generates a write-0 or write-1 cycle.
+ * Only call if dev->bus_master->touch_bit is NULL
+ */
+static void w1_write_bit(struct w1_master *dev, int bit)
{
if (bit) {
dev->bus_master->write_bit(dev->bus_master->data, 0);
}
}
+/**
+ * Writes 8 bits.
+ *
+ * @param dev the master device
+ * @param byte the byte to write
+ */
void w1_write_8(struct w1_master *dev, u8 byte)
{
int i;
dev->bus_master->write_byte(dev->bus_master->data, byte);
else
for (i = 0; i < 8; ++i)
- w1_write_bit(dev, (byte >> i) & 0x1);
+ w1_touch_bit(dev, (byte >> i) & 0x1);
}
-u8 w1_read_bit(struct w1_master *dev)
+
+/**
+ * Generates a write-1 cycle and samples the level.
+ * Only call if dev->bus_master->touch_bit is NULL
+ */
+static u8 w1_read_bit(struct w1_master *dev)
{
int result;
return result & 0x1;
}
+/**
+ * Does a triplet - used for searching ROM addresses.
+ * Return bits:
+ * bit 0 = id_bit
+ * bit 1 = comp_bit
+ * bit 2 = dir_taken
+ * If both bits 0 & 1 are set, the search should be restarted.
+ *
+ * @param dev the master device
+ * @param bdir the bit to write if both id_bit and comp_bit are 0
+ * @return bit fields - see above
+ */
+u8 w1_triplet(struct w1_master *dev, int bdir)
+{
+ if ( dev->bus_master->triplet )
+ return(dev->bus_master->triplet(dev->bus_master->data, bdir));
+ else {
+ u8 id_bit = w1_touch_bit(dev, 1);
+ u8 comp_bit = w1_touch_bit(dev, 1);
+ u8 retval;
+
+ if ( id_bit && comp_bit )
+ return(0x03); /* error */
+
+ if ( !id_bit && !comp_bit ) {
+ /* Both bits are valid, take the direction given */
+ retval = bdir ? 0x04 : 0;
+ } else {
+ /* Only one bit is valid, take that direction */
+ bdir = id_bit;
+ retval = id_bit ? 0x05 : 0x02;
+ }
+
+ if ( dev->bus_master->touch_bit )
+ w1_touch_bit(dev, bdir);
+ else
+ w1_write_bit(dev, bdir);
+ return(retval);
+ }
+}
+
+/**
+ * Reads 8 bits.
+ *
+ * @param dev the master device
+ * @return the byte read
+ */
u8 w1_read_8(struct w1_master * dev)
{
int i;
res = dev->bus_master->read_byte(dev->bus_master->data);
else
for (i = 0; i < 8; ++i)
- res |= (w1_read_bit(dev) << i);
+ res |= (w1_touch_bit(dev,1) << i);
return res;
}
-void w1_write_block(struct w1_master *dev, u8 *buf, int len)
+/**
+ * Writes a series of bytes.
+ *
+ * @param dev the master device
+ * @param buf pointer to the data to write
+ * @param len the number of bytes to write
+ * @return the byte read
+ */
+void w1_write_block(struct w1_master *dev, const u8 *buf, int len)
{
int i;
w1_write_8(dev, buf[i]);
}
+/**
+ * Reads a series of bytes.
+ *
+ * @param dev the master device
+ * @param buf pointer to the buffer to fill
+ * @param len the number of bytes to read
+ * @return the number of bytes read
+ */
u8 w1_read_block(struct w1_master *dev, u8 *buf, int len)
{
int i;
return ret;
}
+/**
+ * Issues a reset bus sequence.
+ *
+ * @param dev The bus master pointer
+ * @return 0=Device present, 1=No device present or error
+ */
int w1_reset_bus(struct w1_master *dev)
{
- int result = 0;
+ int result;
if (dev->bus_master->reset_bus)
result = dev->bus_master->reset_bus(dev->bus_master->data) & 0x1;
if (dev->bus_master->search)
dev->bus_master->search(dev->bus_master->data, cb);
else
- w1_search(dev);
+ w1_search(dev, cb);
}
-EXPORT_SYMBOL(w1_write_bit);
+EXPORT_SYMBOL(w1_touch_bit);
EXPORT_SYMBOL(w1_write_8);
-EXPORT_SYMBOL(w1_read_bit);
EXPORT_SYMBOL(w1_read_8);
EXPORT_SYMBOL(w1_reset_bus);
EXPORT_SYMBOL(w1_calc_crc8);
/*
- * w1_io.h
+ * w1_io.h
*
* Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
- *
+ *
*
* 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
void w1_delay(unsigned long);
u8 w1_touch_bit(struct w1_master *, int);
-void w1_write_bit(struct w1_master *, int);
+u8 w1_triplet(struct w1_master *dev, int bdir);
void w1_write_8(struct w1_master *, u8);
-u8 w1_read_bit(struct w1_master *);
u8 w1_read_8(struct w1_master *);
int w1_reset_bus(struct w1_master *);
u8 w1_calc_crc8(u8 *, int);
-void w1_write_block(struct w1_master *, u8 *, int);
+void w1_write_block(struct w1_master *, const u8 *, int);
u8 w1_read_block(struct w1_master *, u8 *, int);
void w1_search_devices(struct w1_master *dev, w1_slave_found_callback cb);
/*
- * w1_log.h
+ * w1_log.h
*
* Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
- *
+ *
*
* 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
W1_MASTER_REMOVE,
};
-struct w1_netlink_msg
+struct w1_netlink_msg
{
__u8 type;
__u8 reserved[3];
union
{
- struct w1_reg_num id;
+ struct w1_reg_num id;
__u64 w1_id;
struct
{
/*
- * w1_smem.c
+ * w1_smem.c
*
* Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
- *
+ *
*
* This program is free software; you can redistribute it and/or modify
* it under the smems of the GNU General Public License as published by
MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol, 64bit memory family.");
static ssize_t w1_smem_read_name(struct device *, struct device_attribute *attr, char *);
-static ssize_t w1_smem_read_val(struct device *, struct device_attribute *attr, char *);
static ssize_t w1_smem_read_bin(struct kobject *, char *, loff_t, size_t);
static struct w1_family_ops w1_smem_fops = {
.rname = &w1_smem_read_name,
.rbin = &w1_smem_read_bin,
- .rval = &w1_smem_read_val,
- .rvalname = "id",
};
static ssize_t w1_smem_read_name(struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%s\n", sl->name);
}
-static ssize_t w1_smem_read_val(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
- int i;
- ssize_t count = 0;
-
- for (i = 0; i < 8; ++i)
- count += sprintf(buf + count, "%02x ", ((u8 *)&sl->reg_num)[i]);
- count += sprintf(buf + count, "\n");
-
- return count;
-}
-
static ssize_t w1_smem_read_bin(struct kobject *kobj, char *buf, loff_t off, size_t count)
{
struct w1_slave *sl = container_of(container_of(kobj, struct device, kobj),
- struct w1_slave, dev);
+ struct w1_slave, dev);
int i;
atomic_inc(&sl->refcnt);
for (i = 0; i < 8; ++i)
count += sprintf(buf + count, "%02x ", ((u8 *)&sl->reg_num)[i]);
count += sprintf(buf + count, "\n");
-
+
out:
up(&sl->master->mutex);
out_dec:
return count;
}
-static struct w1_family w1_smem_family = {
- .fid = W1_FAMILY_SMEM,
+static struct w1_family w1_smem_family_01 = {
+ .fid = W1_FAMILY_SMEM_01,
+ .fops = &w1_smem_fops,
+};
+
+static struct w1_family w1_smem_family_81 = {
+ .fid = W1_FAMILY_SMEM_81,
.fops = &w1_smem_fops,
};
static int __init w1_smem_init(void)
{
- return w1_register_family(&w1_smem_family);
+ int err;
+
+ err = w1_register_family(&w1_smem_family_01);
+ if (err)
+ return err;
+
+ err = w1_register_family(&w1_smem_family_81);
+ if (err) {
+ w1_unregister_family(&w1_smem_family_01);
+ return err;
+ }
+
+ return 0;
}
static void __exit w1_smem_fini(void)
{
- w1_unregister_family(&w1_smem_family);
+ w1_unregister_family(&w1_smem_family_01);
+ w1_unregister_family(&w1_smem_family_81);
}
module_init(w1_smem_init);
/*
- * w1_therm.c
+ * w1_therm.c
*
* Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
- *
+ *
*
* This program is free software; you can redistribute it and/or modify
* it under the therms of the GNU General Public License as published by
MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol, temperature family.");
static u8 bad_roms[][9] = {
- {0xaa, 0x00, 0x4b, 0x46, 0xff, 0xff, 0x0c, 0x10, 0x87},
+ {0xaa, 0x00, 0x4b, 0x46, 0xff, 0xff, 0x0c, 0x10, 0x87},
{}
};
static ssize_t w1_therm_read_name(struct device *, struct device_attribute *attr, char *);
-static ssize_t w1_therm_read_temp(struct device *, struct device_attribute *attr, char *);
static ssize_t w1_therm_read_bin(struct kobject *, char *, loff_t, size_t);
static struct w1_family_ops w1_therm_fops = {
.rname = &w1_therm_read_name,
.rbin = &w1_therm_read_bin,
- .rval = &w1_therm_read_temp,
- .rvalname = "temp1_input",
+};
+
+static struct w1_family w1_therm_family_DS18S20 = {
+ .fid = W1_THERM_DS18S20,
+ .fops = &w1_therm_fops,
+};
+
+static struct w1_family w1_therm_family_DS18B20 = {
+ .fid = W1_THERM_DS18B20,
+ .fops = &w1_therm_fops,
+};
+static struct w1_family w1_therm_family_DS1822 = {
+ .fid = W1_THERM_DS1822,
+ .fops = &w1_therm_fops,
+};
+
+struct w1_therm_family_converter
+{
+ u8 broken;
+ u16 reserved;
+ struct w1_family *f;
+ int (*convert)(u8 rom[9]);
+};
+
+static inline int w1_DS18B20_convert_temp(u8 rom[9]);
+static inline int w1_DS18S20_convert_temp(u8 rom[9]);
+
+static struct w1_therm_family_converter w1_therm_families[] = {
+ {
+ .f = &w1_therm_family_DS18S20,
+ .convert = w1_DS18S20_convert_temp
+ },
+ {
+ .f = &w1_therm_family_DS1822,
+ .convert = w1_DS18B20_convert_temp
+ },
+ {
+ .f = &w1_therm_family_DS18B20,
+ .convert = w1_DS18B20_convert_temp
+ },
};
static ssize_t w1_therm_read_name(struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%s\n", sl->name);
}
-static inline int w1_convert_temp(u8 rom[9])
+static inline int w1_DS18B20_convert_temp(u8 rom[9])
+{
+ int t = (rom[1] << 8) | rom[0];
+ t /= 16;
+ return t;
+}
+
+static inline int w1_DS18S20_convert_temp(u8 rom[9])
{
int t, h;
+
+ if (!rom[7])
+ return 0;
if (rom[1] == 0)
t = ((s32)rom[0] >> 1)*1000;
return t;
}
-static ssize_t w1_therm_read_temp(struct device *dev, struct device_attribute *attr, char *buf)
+static inline int w1_convert_temp(u8 rom[9], u8 fid)
{
- struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
+ int i;
+
+ for (i=0; i<sizeof(w1_therm_families)/sizeof(w1_therm_families[0]); ++i)
+ if (w1_therm_families[i].f->fid == fid)
+ return w1_therm_families[i].convert(rom);
- return sprintf(buf, "%d\n", w1_convert_temp(sl->rom));
+ return 0;
}
static int w1_therm_check_rom(u8 rom[9])
static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, size_t count)
{
struct w1_slave *sl = container_of(container_of(kobj, struct device, kobj),
- struct w1_slave, dev);
+ struct w1_slave, dev);
struct w1_master *dev = sl->master;
u8 rom[9], crc, verdict;
int i, max_trying = 10;
unsigned int tm = 750;
memcpy(&match[1], (u64 *) & sl->reg_num, 8);
-
+
w1_write_block(dev, match, 9);
w1_write_8(dev, W1_CONVERT_TEMP);
if (!w1_reset_bus (dev)) {
w1_write_block(dev, match, 9);
-
+
w1_write_8(dev, W1_READ_SCRATCHPAD);
if ((count = w1_read_block(dev, rom, 9)) != 9) {
dev_warn(&dev->dev, "w1_read_block() returned %d instead of 9.\n", count);
for (i = 0; i < 9; ++i)
count += sprintf(buf + count, "%02x ", sl->rom[i]);
- count += sprintf(buf + count, "t=%d\n", w1_convert_temp(rom));
+ count += sprintf(buf + count, "t=%d\n", w1_convert_temp(rom, sl->family->fid));
out:
up(&dev->mutex);
out_dec:
return count;
}
-static struct w1_family w1_therm_family = {
- .fid = W1_FAMILY_THERM,
- .fops = &w1_therm_fops,
-};
-
static int __init w1_therm_init(void)
{
- return w1_register_family(&w1_therm_family);
+ int err, i;
+
+ for (i=0; i<sizeof(w1_therm_families)/sizeof(w1_therm_families[0]); ++i) {
+ err = w1_register_family(w1_therm_families[i].f);
+ if (err)
+ w1_therm_families[i].broken = 1;
+ }
+
+ return 0;
}
static void __exit w1_therm_fini(void)
{
- w1_unregister_family(&w1_therm_family);
+ int i;
+
+ for (i=0; i<sizeof(w1_therm_families)/sizeof(w1_therm_families[0]); ++i)
+ if (!w1_therm_families[i].broken)
+ w1_unregister_family(w1_therm_families[i].f);
}
module_init(w1_therm_init);
int autofs4_wait_release(struct autofs_sb_info *,autofs_wqt_t,int);
void autofs4_catatonic_mode(struct autofs_sb_info *);
+static inline int autofs4_follow_mount(struct vfsmount **mnt, struct dentry **dentry)
+{
+ int res = 0;
+
+ while (d_mountpoint(*dentry)) {
+ int followed = follow_down(mnt, dentry);
+ if (!followed)
+ break;
+ res = 1;
+ }
+ return res;
+}
+
static inline int simple_positive(struct dentry *dentry)
{
return dentry->d_inode && !d_unhashed(dentry);
mntget(mnt);
dget(dentry);
- if (!follow_down(&mnt, &dentry))
+ if (!autofs4_follow_mount(&mnt, &dentry))
goto done;
- while (d_mountpoint(dentry) && follow_down(&mnt, &dentry))
- ;
-
/* This is an autofs submount, we can't expire it */
if (is_autofs4_dentry(dentry))
goto done;
struct vfsmount *fp_mnt = mntget(mnt);
struct dentry *fp_dentry = dget(dentry);
- while (follow_down(&fp_mnt, &fp_dentry) && d_mountpoint(fp_dentry));
+ if (!autofs4_follow_mount(&fp_mnt, &fp_dentry)) {
+ dput(fp_dentry);
+ mntput(fp_mnt);
+ return -ENOENT;
+ }
fp = dentry_open(fp_dentry, fp_mnt, file->f_flags);
status = PTR_ERR(fp);
DPRINTK("expire done status=%d", status);
- return 0;
+ /*
+ * If the directory still exists the mount request must
+ * continue otherwise it can't be followed at the right
+ * time during the walk.
+ */
+ status = d_invalidate(dentry);
+ if (status != -EBUSY)
+ return 0;
}
DPRINTK("dentry=%p %.*s ino=%p",
}
if ( !wq ) {
+ /* Can't wait for an expire if there's no mount */
+ if (notify == NFY_NONE && !d_mountpoint(dentry)) {
+ kfree(name);
+ up(&sbi->wq_sem);
+ return -ENOENT;
+ }
+
/* Create a new wait queue */
wq = kmalloc(sizeof(struct autofs_wait_queue),GFP_KERNEL);
if ( !wq ) {
current->mm->brk = ex.a_bss +
(current->mm->start_brk = N_BSSADDR(ex));
current->mm->free_area_cache = current->mm->mmap_base;
+ current->mm->cached_hole_size = 0;
set_mm_counter(current->mm, rss, 0);
current->mm->mmap = NULL;
change some of these later */
set_mm_counter(current->mm, rss, 0);
current->mm->free_area_cache = current->mm->mmap_base;
+ current->mm->cached_hole_size = 0;
retval = setup_arg_pages(bprm, randomize_stack_top(STACK_TOP),
executable_stack);
if (retval < 0) {
for_each_pgdat(pgdat) {
zones = pgdat->node_zonelists[GFP_NOFS&GFP_ZONEMASK].zones;
if (*zones)
- try_to_free_pages(zones, GFP_NOFS, 0);
+ try_to_free_pages(zones, GFP_NOFS);
}
}
start_addr = mm->free_area_cache;
+ if (len <= mm->cached_hole_size)
+ start_addr = TASK_UNMAPPED_BASE;
+
full_search:
addr = ALIGN(start_addr, HPAGE_SIZE);
/* Handle everything else. Do name translation if there
is no Rock Ridge NM field. */
- if (sbi->s_unhide == 'n') {
- /* Do not report hidden or associated files */
- if (de->flags[-sbi->s_high_sierra] & 5) {
- filp->f_pos += de_len;
- continue;
- }
+
+ /*
+ * Do not report hidden files if so instructed, or associated
+ * files unless instructed to do so
+ */
+ if ((sbi->s_hide == 'y' &&
+ (de->flags[-sbi->s_high_sierra] & 1)) ||
+ (sbi->s_showassoc =='n' &&
+ (de->flags[-sbi->s_high_sierra] & 4))) {
+ filp->f_pos += de_len;
+ continue;
}
map = 1;
#define BEQUIET
-#ifdef LEAK_CHECK
-static int check_malloc;
-static int check_bread;
-#endif
-
static int isofs_hashi(struct dentry *parent, struct qstr *qstr);
static int isofs_hash(struct dentry *parent, struct qstr *qstr);
static int isofs_dentry_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b);
}
#endif
-#ifdef LEAK_CHECK
- printk("Outstanding mallocs:%d, outstanding buffers: %d\n",
- check_malloc, check_bread);
-#endif
-
kfree(sbi);
sb->s_fs_info = NULL;
return;
static struct inode *isofs_alloc_inode(struct super_block *sb)
{
struct iso_inode_info *ei;
- ei = (struct iso_inode_info *)kmem_cache_alloc(isofs_inode_cachep, SLAB_KERNEL);
+ ei = kmem_cache_alloc(isofs_inode_cachep, SLAB_KERNEL);
if (!ei)
return NULL;
return &ei->vfs_inode;
kmem_cache_free(isofs_inode_cachep, ISOFS_I(inode));
}
-static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+static void init_once(void *foo, kmem_cache_t * cachep, unsigned long flags)
{
- struct iso_inode_info *ei = (struct iso_inode_info *) foo;
+ struct iso_inode_info *ei = foo;
if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
SLAB_CTOR_CONSTRUCTOR)
static void destroy_inodecache(void)
{
if (kmem_cache_destroy(isofs_inode_cachep))
- printk(KERN_INFO "iso_inode_cache: not all structures were freed\n");
+ printk(KERN_INFO "iso_inode_cache: not all structures were "
+ "freed\n");
}
static int isofs_remount(struct super_block *sb, int *flags, char *data)
{
.d_hash = isofs_hashi_ms,
.d_compare = isofs_dentry_cmpi_ms,
- }
+ },
#endif
};
char rock;
char joliet;
char cruft;
- char unhide;
+ char hide;
+ char showassoc;
char nocompress;
unsigned char check;
unsigned int blocksize;
/*
* Case insensitive compare of two isofs names.
*/
-static int
-isofs_dentry_cmpi_common(struct dentry *dentry,struct qstr *a,struct qstr *b,int ms)
+static int isofs_dentry_cmpi_common(struct dentry *dentry, struct qstr *a,
+ struct qstr *b, int ms)
{
int alen, blen;
/*
* Case sensitive compare of two isofs names.
*/
-static int
-isofs_dentry_cmp_common(struct dentry *dentry,struct qstr *a,struct qstr *b,int ms)
+static int isofs_dentry_cmp_common(struct dentry *dentry, struct qstr *a,
+ struct qstr *b, int ms)
{
int alen, blen;
Opt_block, Opt_check_r, Opt_check_s, Opt_cruft, Opt_gid, Opt_ignore,
Opt_iocharset, Opt_map_a, Opt_map_n, Opt_map_o, Opt_mode, Opt_nojoliet,
Opt_norock, Opt_sb, Opt_session, Opt_uid, Opt_unhide, Opt_utf8, Opt_err,
- Opt_nocompress,
+ Opt_nocompress, Opt_hide, Opt_showassoc,
};
static match_table_t tokens = {
{Opt_norock, "norock"},
{Opt_nojoliet, "nojoliet"},
{Opt_unhide, "unhide"},
+ {Opt_hide, "hide"},
+ {Opt_showassoc, "showassoc"},
{Opt_cruft, "cruft"},
{Opt_utf8, "utf8"},
{Opt_iocharset, "iocharset=%s"},
{Opt_err, NULL}
};
-static int parse_options(char *options, struct iso9660_options * popt)
+static int parse_options(char *options, struct iso9660_options *popt)
{
char *p;
int option;
popt->rock = 'y';
popt->joliet = 'y';
popt->cruft = 'n';
- popt->unhide = 'n';
+ popt->hide = 'n';
+ popt->showassoc = 'n';
popt->check = 'u'; /* unset */
popt->nocompress = 0;
popt->blocksize = 1024;
case Opt_nojoliet:
popt->joliet = 'n';
break;
+ case Opt_hide:
+ popt->hide = 'y';
+ break;
case Opt_unhide:
- popt->unhide = 'y';
+ case Opt_showassoc:
+ popt->showassoc = 'y';
break;
case Opt_cruft:
popt->cruft = 'y';
*/
#define WE_OBEY_THE_WRITTEN_STANDARDS 1
-static unsigned int isofs_get_last_session(struct super_block *sb,s32 session )
+static unsigned int isofs_get_last_session(struct super_block *sb, s32 session)
{
struct cdrom_multisession ms_info;
unsigned int vol_desc_start;
printk(KERN_ERR "Invalid session number or type of track\n");
}
i = ioctl_by_bdev(bdev, CDROMMULTISESSION, (unsigned long) &ms_info);
- if(session > 0) printk(KERN_ERR "Invalid session number\n");
+ if (session > 0)
+ printk(KERN_ERR "Invalid session number\n");
#if 0
printk("isofs.inode: CDROMMULTISESSION: rc=%d\n",i);
if (i==0) {
struct iso9660_options opt;
struct isofs_sb_info * sbi;
- sbi = kmalloc(sizeof(struct isofs_sb_info), GFP_KERNEL);
+ sbi = kmalloc(sizeof(*sbi), GFP_KERNEL);
if (!sbi)
return -ENOMEM;
s->s_fs_info = sbi;
- memset(sbi, 0, sizeof(struct isofs_sb_info));
+ memset(sbi, 0, sizeof(*sbi));
- if (!parse_options((char *) data, &opt))
+ if (!parse_options((char *)data, &opt))
goto out_freesbi;
/*
sbi->s_rock = (opt.rock == 'y' ? 2 : 0);
sbi->s_rock_offset = -1; /* initial offset, will guess until SP is found*/
sbi->s_cruft = opt.cruft;
- sbi->s_unhide = opt.unhide;
+ sbi->s_hide = opt.hide;
+ sbi->s_showassoc = opt.showassoc;
sbi->s_uid = opt.uid;
sbi->s_gid = opt.gid;
sbi->s_utf8 = opt.utf8;
rv++;
}
-
abort:
unlock_kernel();
return rv;
static int isofs_get_block(struct inode *inode, sector_t iblock,
struct buffer_head *bh_result, int create)
{
- if ( create ) {
+ if (create) {
printk("isofs_get_block: Kernel tries to allocate a block\n");
return -EROFS;
}
static inline void test_and_set_uid(uid_t *p, uid_t value)
{
- if(value) {
+ if (value)
*p = value;
- }
}
static inline void test_and_set_gid(gid_t *p, gid_t value)
{
- if(value) {
+ if (value)
*p = value;
- }
}
-static int isofs_read_level3_size(struct inode * inode)
+static int isofs_read_level3_size(struct inode *inode)
{
unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
int high_sierra = ISOFS_SB(inode->i_sb)->s_high_sierra;
bh = sb_bread(inode->i_sb, block);
if (!bh)
goto out_noread;
- memcpy((void *) tmpde + slop, bh->b_data, offset);
+ memcpy((void *)tmpde+slop, bh->b_data, offset);
}
de = tmpde;
}
more_entries = de->flags[-high_sierra] & 0x80;
i++;
- if(i > 100)
+ if (i > 100)
goto out_toomany;
- } while(more_entries);
+ } while (more_entries);
out:
- if (tmpde)
- kfree(tmpde);
+ kfree(tmpde);
if (bh)
brelse(bh);
return 0;
goto out;
}
-static void isofs_read_inode(struct inode * inode)
+static void isofs_read_inode(struct inode *inode)
{
struct super_block *sb = inode->i_sb;
struct isofs_sb_info *sbi = ISOFS_SB(sb);
ei->i_format_parm[2] = 0;
ei->i_section_size = isonum_733 (de->size);
- if(de->flags[-high_sierra] & 0x80) {
+ if (de->flags[-high_sierra] & 0x80) {
if(isofs_read_level3_size(inode)) goto fail;
} else {
ei->i_next_section_block = 0;
/* XXX - parse_rock_ridge_inode() had already set i_rdev. */
init_special_inode(inode, inode->i_mode, inode->i_rdev);
- out:
+out:
if (tmpde)
kfree(tmpde);
if (bh)
brelse(bh);
return;
- out_badread:
+out_badread:
printk(KERN_WARNING "ISOFS: unable to read i-node block\n");
- fail:
+fail:
make_bad_inode(inode);
goto out;
}
hashval = (block << sb->s_blocksize_bits) | offset;
- inode = iget5_locked(sb,
- hashval,
- &isofs_iget5_test,
- &isofs_iget5_set,
- &data);
+ inode = iget5_locked(sb, hashval, &isofs_iget5_test,
+ &isofs_iget5_set, &data);
if (inode && (inode->i_state & I_NEW)) {
sb->s_op->read_inode(inode);
return inode;
}
-#ifdef LEAK_CHECK
-#undef malloc
-#undef free_s
-#undef sb_bread
-#undef brelse
-
-void * leak_check_malloc(unsigned int size){
- void * tmp;
- check_malloc++;
- tmp = kmalloc(size, GFP_KERNEL);
- return tmp;
-}
-
-void leak_check_free_s(void * obj, int size){
- check_malloc--;
- return kfree(obj);
-}
-
-struct buffer_head * leak_check_bread(struct super_block *sb, int block){
- check_bread++;
- return sb_bread(sb, block);
-}
-
-void leak_check_brelse(struct buffer_head * bh){
- check_bread--;
- return brelse(bh);
-}
-
-#endif
-
static struct super_block *isofs_get_sb(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
{
unsigned char s_nosuid;
unsigned char s_nodev;
unsigned char s_nocompress;
+ unsigned char s_hide;
+ unsigned char s_showassoc;
mode_t s_mode;
gid_t s_gid;
}
/*
- * Skip hidden or associated files unless unhide is set
+ * Skip hidden or associated files unless hide or showassoc,
+ * respectively, is set
*/
match = 0;
if (dlen > 0 &&
- (!(de->flags[-sbi->s_high_sierra] & 5)
- || sbi->s_unhide == 'y'))
- {
- match = (isofs_cmp(dentry,dpnt,dlen) == 0);
+ (sbi->s_hide =='n' ||
+ (!(de->flags[-sbi->s_high_sierra] & 1))) &&
+ (sbi->s_showassoc =='y' ||
+ (!(de->flags[-sbi->s_high_sierra] & 4)))) {
+ match = (isofs_cmp(dentry, dpnt, dlen) == 0);
}
if (match) {
isofs_normalize_block_and_offset(de,
&offset_saved);
*block_rv = block_saved;
*offset_rv = offset_saved;
- if (bh) brelse(bh);
+ brelse(bh);
return 1;
}
}
- if (bh) brelse(bh);
+ brelse(bh);
return 0;
}
#include "isofs.h"
#include "rock.h"
-/* These functions are designed to read the system areas of a directory record
+/*
+ * These functions are designed to read the system areas of a directory record
* and extract relevant information. There are different functions provided
* depending upon what information we need at the time. One function fills
* out an inode structure, a second one extracts a filename, a third one
* returns a symbolic link name, and a fourth one returns the extent number
- * for the file. */
-
-#define SIG(A,B) ((A) | ((B) << 8)) /* isonum_721() */
-
-
-/* This is a way of ensuring that we have something in the system
- use fields that is compatible with Rock Ridge */
-#define CHECK_SP(FAIL) \
- if(rr->u.SP.magic[0] != 0xbe) FAIL; \
- if(rr->u.SP.magic[1] != 0xef) FAIL; \
- ISOFS_SB(inode->i_sb)->s_rock_offset=rr->u.SP.skip;
-/* We define a series of macros because each function must do exactly the
- same thing in certain places. We use the macros to ensure that everything
- is done correctly */
-
-#define CONTINUE_DECLS \
- int cont_extent = 0, cont_offset = 0, cont_size = 0; \
- void *buffer = NULL
-
-#define CHECK_CE \
- {cont_extent = isonum_733(rr->u.CE.extent); \
- cont_offset = isonum_733(rr->u.CE.offset); \
- cont_size = isonum_733(rr->u.CE.size);}
-
-#define SETUP_ROCK_RIDGE(DE,CHR,LEN) \
- {LEN= sizeof(struct iso_directory_record) + DE->name_len[0]; \
- if(LEN & 1) LEN++; \
- CHR = ((unsigned char *) DE) + LEN; \
- LEN = *((unsigned char *) DE) - LEN; \
- if (LEN<0) LEN=0; \
- if (ISOFS_SB(inode->i_sb)->s_rock_offset!=-1) \
- { \
- LEN-=ISOFS_SB(inode->i_sb)->s_rock_offset; \
- CHR+=ISOFS_SB(inode->i_sb)->s_rock_offset; \
- if (LEN<0) LEN=0; \
- } \
-}
-
-#define MAYBE_CONTINUE(LABEL,DEV) \
- {if (buffer) { kfree(buffer); buffer = NULL; } \
- if (cont_extent){ \
- int block, offset, offset1; \
- struct buffer_head * pbh; \
- buffer = kmalloc(cont_size,GFP_KERNEL); \
- if (!buffer) goto out; \
- block = cont_extent; \
- offset = cont_offset; \
- offset1 = 0; \
- pbh = sb_bread(DEV->i_sb, block); \
- if(pbh){ \
- if (offset > pbh->b_size || offset + cont_size > pbh->b_size){ \
- brelse(pbh); \
- goto out; \
- } \
- memcpy(buffer + offset1, pbh->b_data + offset, cont_size - offset1); \
- brelse(pbh); \
- chr = (unsigned char *) buffer; \
- len = cont_size; \
- cont_extent = 0; \
- cont_size = 0; \
- cont_offset = 0; \
- goto LABEL; \
- } \
- printk("Unable to read rock-ridge attributes\n"); \
- }}
-
-/* return length of name field; 0: not found, -1: to be ignored */
-int get_rock_ridge_filename(struct iso_directory_record * de,
- char * retname, struct inode * inode)
+ * for the file.
+ */
+
+#define SIG(A,B) ((A) | ((B) << 8)) /* isonum_721() */
+
+struct rock_state {
+ void *buffer;
+ unsigned char *chr;
+ int len;
+ int cont_size;
+ int cont_extent;
+ int cont_offset;
+ struct inode *inode;
+};
+
+/*
+ * This is a way of ensuring that we have something in the system
+ * use fields that is compatible with Rock Ridge. Return zero on success.
+ */
+
+static int check_sp(struct rock_ridge *rr, struct inode *inode)
{
- int len;
- unsigned char * chr;
- CONTINUE_DECLS;
- int retnamlen = 0, truncate=0;
-
- if (!ISOFS_SB(inode->i_sb)->s_rock) return 0;
- *retname = 0;
-
- SETUP_ROCK_RIDGE(de, chr, len);
- repeat:
- {
- struct rock_ridge * rr;
- int sig;
-
- while (len > 2){ /* There may be one byte for padding somewhere */
- rr = (struct rock_ridge *) chr;
- if (rr->len < 3) goto out; /* Something got screwed up here */
- sig = isonum_721(chr);
- chr += rr->len;
- len -= rr->len;
- if (len < 0) goto out; /* corrupted isofs */
-
- switch(sig){
- case SIG('R','R'):
- if((rr->u.RR.flags[0] & RR_NM) == 0) goto out;
- break;
- case SIG('S','P'):
- CHECK_SP(goto out);
- break;
- case SIG('C','E'):
- CHECK_CE;
- break;
- case SIG('N','M'):
- if (truncate) break;
- if (rr->len < 5) break;
- /*
- * If the flags are 2 or 4, this indicates '.' or '..'.
- * We don't want to do anything with this, because it
- * screws up the code that calls us. We don't really
- * care anyways, since we can just use the non-RR
- * name.
- */
- if (rr->u.NM.flags & 6) {
- break;
+ if (rr->u.SP.magic[0] != 0xbe)
+ return -1;
+ if (rr->u.SP.magic[1] != 0xef)
+ return -1;
+ ISOFS_SB(inode->i_sb)->s_rock_offset = rr->u.SP.skip;
+ return 0;
+}
+
+static void setup_rock_ridge(struct iso_directory_record *de,
+ struct inode *inode, struct rock_state *rs)
+{
+ rs->len = sizeof(struct iso_directory_record) + de->name_len[0];
+ if (rs->len & 1)
+ (rs->len)++;
+ rs->chr = (unsigned char *)de + rs->len;
+ rs->len = *((unsigned char *)de) - rs->len;
+ if (rs->len < 0)
+ rs->len = 0;
+
+ if (ISOFS_SB(inode->i_sb)->s_rock_offset != -1) {
+ rs->len -= ISOFS_SB(inode->i_sb)->s_rock_offset;
+ rs->chr += ISOFS_SB(inode->i_sb)->s_rock_offset;
+ if (rs->len < 0)
+ rs->len = 0;
+ }
+}
+
+static void init_rock_state(struct rock_state *rs, struct inode *inode)
+{
+ memset(rs, 0, sizeof(*rs));
+ rs->inode = inode;
+}
+
+/*
+ * Returns 0 if the caller should continue scanning, 1 if the scan must end
+ * and -ve on error.
+ */
+static int rock_continue(struct rock_state *rs)
+{
+ int ret = 1;
+ int blocksize = 1 << rs->inode->i_blkbits;
+ const int min_de_size = offsetof(struct rock_ridge, u);
+
+ kfree(rs->buffer);
+ rs->buffer = NULL;
+
+ if ((unsigned)rs->cont_offset > blocksize - min_de_size ||
+ (unsigned)rs->cont_size > blocksize ||
+ (unsigned)(rs->cont_offset + rs->cont_size) > blocksize) {
+ printk(KERN_NOTICE "rock: corrupted directory entry. "
+ "extent=%d, offset=%d, size=%d\n",
+ rs->cont_extent, rs->cont_offset, rs->cont_size);
+ ret = -EIO;
+ goto out;
}
- if (rr->u.NM.flags & ~1) {
- printk("Unsupported NM flag settings (%d)\n",rr->u.NM.flags);
- break;
+ if (rs->cont_extent) {
+ struct buffer_head *bh;
+
+ rs->buffer = kmalloc(rs->cont_size, GFP_KERNEL);
+ if (!rs->buffer) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ ret = -EIO;
+ bh = sb_bread(rs->inode->i_sb, rs->cont_extent);
+ if (bh) {
+ memcpy(rs->buffer, bh->b_data + rs->cont_offset,
+ rs->cont_size);
+ put_bh(bh);
+ rs->chr = rs->buffer;
+ rs->len = rs->cont_size;
+ rs->cont_extent = 0;
+ rs->cont_size = 0;
+ rs->cont_offset = 0;
+ return 0;
+ }
+ printk("Unable to read rock-ridge attributes\n");
+ }
+out:
+ kfree(rs->buffer);
+ rs->buffer = NULL;
+ return ret;
+}
+
+/*
+ * We think there's a record of type `sig' at rs->chr. Parse the signature
+ * and make sure that there's really room for a record of that type.
+ */
+static int rock_check_overflow(struct rock_state *rs, int sig)
+{
+ int len;
+
+ switch (sig) {
+ case SIG('S', 'P'):
+ len = sizeof(struct SU_SP_s);
+ break;
+ case SIG('C', 'E'):
+ len = sizeof(struct SU_CE_s);
+ break;
+ case SIG('E', 'R'):
+ len = sizeof(struct SU_ER_s);
+ break;
+ case SIG('R', 'R'):
+ len = sizeof(struct RR_RR_s);
+ break;
+ case SIG('P', 'X'):
+ len = sizeof(struct RR_PX_s);
+ break;
+ case SIG('P', 'N'):
+ len = sizeof(struct RR_PN_s);
+ break;
+ case SIG('S', 'L'):
+ len = sizeof(struct RR_SL_s);
+ break;
+ case SIG('N', 'M'):
+ len = sizeof(struct RR_NM_s);
+ break;
+ case SIG('C', 'L'):
+ len = sizeof(struct RR_CL_s);
+ break;
+ case SIG('P', 'L'):
+ len = sizeof(struct RR_PL_s);
+ break;
+ case SIG('T', 'F'):
+ len = sizeof(struct RR_TF_s);
+ break;
+ case SIG('Z', 'F'):
+ len = sizeof(struct RR_ZF_s);
+ break;
+ default:
+ len = 0;
+ break;
}
- if((strlen(retname) + rr->len - 5) >= 254) {
- truncate = 1;
- break;
+ len += offsetof(struct rock_ridge, u);
+ if (len > rs->len) {
+ printk(KERN_NOTICE "rock: directory entry would overflow "
+ "storage\n");
+ printk(KERN_NOTICE "rock: sig=0x%02x, size=%d, remaining=%d\n",
+ sig, len, rs->len);
+ return -EIO;
+ }
+ return 0;
+}
+
+/*
+ * return length of name field; 0: not found, -1: to be ignored
+ */
+int get_rock_ridge_filename(struct iso_directory_record *de,
+ char *retname, struct inode *inode)
+{
+ struct rock_state rs;
+ struct rock_ridge *rr;
+ int sig;
+ int retnamlen = 0;
+ int truncate = 0;
+ int ret = 0;
+
+ if (!ISOFS_SB(inode->i_sb)->s_rock)
+ return 0;
+ *retname = 0;
+
+ init_rock_state(&rs, inode);
+ setup_rock_ridge(de, inode, &rs);
+repeat:
+
+ while (rs.len > 2) { /* There may be one byte for padding somewhere */
+ rr = (struct rock_ridge *)rs.chr;
+ if (rr->len < 3)
+ goto out; /* Something got screwed up here */
+ sig = isonum_721(rs.chr);
+ if (rock_check_overflow(&rs, sig))
+ goto eio;
+ rs.chr += rr->len;
+ rs.len -= rr->len;
+ if (rs.len < 0)
+ goto eio; /* corrupted isofs */
+
+ switch (sig) {
+ case SIG('R', 'R'):
+ if ((rr->u.RR.flags[0] & RR_NM) == 0)
+ goto out;
+ break;
+ case SIG('S', 'P'):
+ if (check_sp(rr, inode))
+ goto out;
+ break;
+ case SIG('C', 'E'):
+ rs.cont_extent = isonum_733(rr->u.CE.extent);
+ rs.cont_offset = isonum_733(rr->u.CE.offset);
+ rs.cont_size = isonum_733(rr->u.CE.size);
+ break;
+ case SIG('N', 'M'):
+ if (truncate)
+ break;
+ if (rr->len < 5)
+ break;
+ /*
+ * If the flags are 2 or 4, this indicates '.' or '..'.
+ * We don't want to do anything with this, because it
+ * screws up the code that calls us. We don't really
+ * care anyways, since we can just use the non-RR
+ * name.
+ */
+ if (rr->u.NM.flags & 6)
+ break;
+
+ if (rr->u.NM.flags & ~1) {
+ printk("Unsupported NM flag settings (%d)\n",
+ rr->u.NM.flags);
+ break;
+ }
+ if ((strlen(retname) + rr->len - 5) >= 254) {
+ truncate = 1;
+ break;
+ }
+ strncat(retname, rr->u.NM.name, rr->len - 5);
+ retnamlen += rr->len - 5;
+ break;
+ case SIG('R', 'E'):
+ kfree(rs.buffer);
+ return -1;
+ default:
+ break;
+ }
}
- strncat(retname, rr->u.NM.name, rr->len - 5);
- retnamlen += rr->len - 5;
- break;
- case SIG('R','E'):
- if (buffer) kfree(buffer);
- return -1;
- default:
- break;
- }
- }
- }
- MAYBE_CONTINUE(repeat,inode);
- if (buffer) kfree(buffer);
- return retnamlen; /* If 0, this file did not have a NM field */
- out:
- if(buffer) kfree(buffer);
- return 0;
+ ret = rock_continue(&rs);
+ if (ret == 0)
+ goto repeat;
+ if (ret == 1)
+ return retnamlen; /* If 0, this file did not have a NM field */
+out:
+ kfree(rs.buffer);
+ return ret;
+eio:
+ ret = -EIO;
+ goto out;
}
static int
parse_rock_ridge_inode_internal(struct iso_directory_record *de,
struct inode *inode, int regard_xa)
{
- int len;
- unsigned char * chr;
- int symlink_len = 0;
- CONTINUE_DECLS;
-
- if (!ISOFS_SB(inode->i_sb)->s_rock) return 0;
-
- SETUP_ROCK_RIDGE(de, chr, len);
- if (regard_xa)
- {
- chr+=14;
- len-=14;
- if (len<0) len=0;
- }
-
- repeat:
- {
- int cnt, sig;
- struct inode * reloc;
- struct rock_ridge * rr;
- int rootflag;
-
- while (len > 2){ /* There may be one byte for padding somewhere */
- rr = (struct rock_ridge *) chr;
- if (rr->len < 3) goto out; /* Something got screwed up here */
- sig = isonum_721(chr);
- chr += rr->len;
- len -= rr->len;
- if (len < 0) goto out; /* corrupted isofs */
-
- switch(sig){
+ int symlink_len = 0;
+ int cnt, sig;
+ struct inode *reloc;
+ struct rock_ridge *rr;
+ int rootflag;
+ struct rock_state rs;
+ int ret = 0;
+
+ if (!ISOFS_SB(inode->i_sb)->s_rock)
+ return 0;
+
+ init_rock_state(&rs, inode);
+ setup_rock_ridge(de, inode, &rs);
+ if (regard_xa) {
+ rs.chr += 14;
+ rs.len -= 14;
+ if (rs.len < 0)
+ rs.len = 0;
+ }
+
+repeat:
+ while (rs.len > 2) { /* There may be one byte for padding somewhere */
+ rr = (struct rock_ridge *)rs.chr;
+ if (rr->len < 3)
+ goto out; /* Something got screwed up here */
+ sig = isonum_721(rs.chr);
+ if (rock_check_overflow(&rs, sig))
+ goto eio;
+ rs.chr += rr->len;
+ rs.len -= rr->len;
+ if (rs.len < 0)
+ goto eio; /* corrupted isofs */
+
+ switch (sig) {
#ifndef CONFIG_ZISOFS /* No flag for SF or ZF */
- case SIG('R','R'):
- if((rr->u.RR.flags[0] &
- (RR_PX | RR_TF | RR_SL | RR_CL)) == 0) goto out;
- break;
+ case SIG('R', 'R'):
+ if ((rr->u.RR.flags[0] &
+ (RR_PX | RR_TF | RR_SL | RR_CL)) == 0)
+ goto out;
+ break;
#endif
- case SIG('S','P'):
- CHECK_SP(goto out);
- break;
- case SIG('C','E'):
- CHECK_CE;
- break;
- case SIG('E','R'):
- ISOFS_SB(inode->i_sb)->s_rock = 1;
- printk(KERN_DEBUG "ISO 9660 Extensions: ");
- { int p;
- for(p=0;p<rr->u.ER.len_id;p++) printk("%c",rr->u.ER.data[p]);
- }
- printk("\n");
- break;
- case SIG('P','X'):
- inode->i_mode = isonum_733(rr->u.PX.mode);
- inode->i_nlink = isonum_733(rr->u.PX.n_links);
- inode->i_uid = isonum_733(rr->u.PX.uid);
- inode->i_gid = isonum_733(rr->u.PX.gid);
- break;
- case SIG('P','N'):
- { int high, low;
- high = isonum_733(rr->u.PN.dev_high);
- low = isonum_733(rr->u.PN.dev_low);
- /*
- * The Rock Ridge standard specifies that if sizeof(dev_t) <= 4,
- * then the high field is unused, and the device number is completely
- * stored in the low field. Some writers may ignore this subtlety,
- * and as a result we test to see if the entire device number is
- * stored in the low field, and use that.
- */
- if((low & ~0xff) && high == 0) {
- inode->i_rdev = MKDEV(low >> 8, low & 0xff);
- } else {
- inode->i_rdev = MKDEV(high, low);
- }
- }
- break;
- case SIG('T','F'):
- /* Some RRIP writers incorrectly place ctime in the TF_CREATE field.
- Try to handle this correctly for either case. */
- cnt = 0; /* Rock ridge never appears on a High Sierra disk */
- if(rr->u.TF.flags & TF_CREATE) {
- inode->i_ctime.tv_sec = iso_date(rr->u.TF.times[cnt++].time, 0);
- inode->i_ctime.tv_nsec = 0;
- }
- if(rr->u.TF.flags & TF_MODIFY) {
- inode->i_mtime.tv_sec = iso_date(rr->u.TF.times[cnt++].time, 0);
- inode->i_mtime.tv_nsec = 0;
- }
- if(rr->u.TF.flags & TF_ACCESS) {
- inode->i_atime.tv_sec = iso_date(rr->u.TF.times[cnt++].time, 0);
- inode->i_atime.tv_nsec = 0;
- }
- if(rr->u.TF.flags & TF_ATTRIBUTES) {
- inode->i_ctime.tv_sec = iso_date(rr->u.TF.times[cnt++].time, 0);
- inode->i_ctime.tv_nsec = 0;
- }
- break;
- case SIG('S','L'):
- {int slen;
- struct SL_component * slp;
- struct SL_component * oldslp;
- slen = rr->len - 5;
- slp = &rr->u.SL.link;
- inode->i_size = symlink_len;
- while (slen > 1){
- rootflag = 0;
- switch(slp->flags &~1){
- case 0:
- inode->i_size += slp->len;
- break;
- case 2:
- inode->i_size += 1;
- break;
- case 4:
- inode->i_size += 2;
- break;
- case 8:
- rootflag = 1;
- inode->i_size += 1;
- break;
- default:
- printk("Symlink component flag not implemented\n");
- }
- slen -= slp->len + 2;
- oldslp = slp;
- slp = (struct SL_component *) (((char *) slp) + slp->len + 2);
-
- if(slen < 2) {
- if( ((rr->u.SL.flags & 1) != 0)
- && ((oldslp->flags & 1) == 0) ) inode->i_size += 1;
- break;
- }
-
- /*
- * If this component record isn't continued, then append a '/'.
- */
- if (!rootflag && (oldslp->flags & 1) == 0)
- inode->i_size += 1;
- }
- }
- symlink_len = inode->i_size;
- break;
- case SIG('R','E'):
- printk(KERN_WARNING "Attempt to read inode for relocated directory\n");
- goto out;
- case SIG('C','L'):
- ISOFS_I(inode)->i_first_extent = isonum_733(rr->u.CL.location);
- reloc = isofs_iget(inode->i_sb, ISOFS_I(inode)->i_first_extent, 0);
- if (!reloc)
- goto out;
- inode->i_mode = reloc->i_mode;
- inode->i_nlink = reloc->i_nlink;
- inode->i_uid = reloc->i_uid;
- inode->i_gid = reloc->i_gid;
- inode->i_rdev = reloc->i_rdev;
- inode->i_size = reloc->i_size;
- inode->i_blocks = reloc->i_blocks;
- inode->i_atime = reloc->i_atime;
- inode->i_ctime = reloc->i_ctime;
- inode->i_mtime = reloc->i_mtime;
- iput(reloc);
- break;
+ case SIG('S', 'P'):
+ if (check_sp(rr, inode))
+ goto out;
+ break;
+ case SIG('C', 'E'):
+ rs.cont_extent = isonum_733(rr->u.CE.extent);
+ rs.cont_offset = isonum_733(rr->u.CE.offset);
+ rs.cont_size = isonum_733(rr->u.CE.size);
+ break;
+ case SIG('E', 'R'):
+ ISOFS_SB(inode->i_sb)->s_rock = 1;
+ printk(KERN_DEBUG "ISO 9660 Extensions: ");
+ {
+ int p;
+ for (p = 0; p < rr->u.ER.len_id; p++)
+ printk("%c", rr->u.ER.data[p]);
+ }
+ printk("\n");
+ break;
+ case SIG('P', 'X'):
+ inode->i_mode = isonum_733(rr->u.PX.mode);
+ inode->i_nlink = isonum_733(rr->u.PX.n_links);
+ inode->i_uid = isonum_733(rr->u.PX.uid);
+ inode->i_gid = isonum_733(rr->u.PX.gid);
+ break;
+ case SIG('P', 'N'):
+ {
+ int high, low;
+ high = isonum_733(rr->u.PN.dev_high);
+ low = isonum_733(rr->u.PN.dev_low);
+ /*
+ * The Rock Ridge standard specifies that if
+ * sizeof(dev_t) <= 4, then the high field is
+ * unused, and the device number is completely
+ * stored in the low field. Some writers may
+ * ignore this subtlety,
+ * and as a result we test to see if the entire
+ * device number is
+ * stored in the low field, and use that.
+ */
+ if ((low & ~0xff) && high == 0) {
+ inode->i_rdev =
+ MKDEV(low >> 8, low & 0xff);
+ } else {
+ inode->i_rdev =
+ MKDEV(high, low);
+ }
+ }
+ break;
+ case SIG('T', 'F'):
+ /*
+ * Some RRIP writers incorrectly place ctime in the
+ * TF_CREATE field. Try to handle this correctly for
+ * either case.
+ */
+ /* Rock ridge never appears on a High Sierra disk */
+ cnt = 0;
+ if (rr->u.TF.flags & TF_CREATE) {
+ inode->i_ctime.tv_sec =
+ iso_date(rr->u.TF.times[cnt++].time,
+ 0);
+ inode->i_ctime.tv_nsec = 0;
+ }
+ if (rr->u.TF.flags & TF_MODIFY) {
+ inode->i_mtime.tv_sec =
+ iso_date(rr->u.TF.times[cnt++].time,
+ 0);
+ inode->i_mtime.tv_nsec = 0;
+ }
+ if (rr->u.TF.flags & TF_ACCESS) {
+ inode->i_atime.tv_sec =
+ iso_date(rr->u.TF.times[cnt++].time,
+ 0);
+ inode->i_atime.tv_nsec = 0;
+ }
+ if (rr->u.TF.flags & TF_ATTRIBUTES) {
+ inode->i_ctime.tv_sec =
+ iso_date(rr->u.TF.times[cnt++].time,
+ 0);
+ inode->i_ctime.tv_nsec = 0;
+ }
+ break;
+ case SIG('S', 'L'):
+ {
+ int slen;
+ struct SL_component *slp;
+ struct SL_component *oldslp;
+ slen = rr->len - 5;
+ slp = &rr->u.SL.link;
+ inode->i_size = symlink_len;
+ while (slen > 1) {
+ rootflag = 0;
+ switch (slp->flags & ~1) {
+ case 0:
+ inode->i_size +=
+ slp->len;
+ break;
+ case 2:
+ inode->i_size += 1;
+ break;
+ case 4:
+ inode->i_size += 2;
+ break;
+ case 8:
+ rootflag = 1;
+ inode->i_size += 1;
+ break;
+ default:
+ printk("Symlink component flag "
+ "not implemented\n");
+ }
+ slen -= slp->len + 2;
+ oldslp = slp;
+ slp = (struct SL_component *)
+ (((char *)slp) + slp->len + 2);
+
+ if (slen < 2) {
+ if (((rr->u.SL.
+ flags & 1) != 0)
+ &&
+ ((oldslp->
+ flags & 1) == 0))
+ inode->i_size +=
+ 1;
+ break;
+ }
+
+ /*
+ * If this component record isn't
+ * continued, then append a '/'.
+ */
+ if (!rootflag
+ && (oldslp->flags & 1) == 0)
+ inode->i_size += 1;
+ }
+ }
+ symlink_len = inode->i_size;
+ break;
+ case SIG('R', 'E'):
+ printk(KERN_WARNING "Attempt to read inode for "
+ "relocated directory\n");
+ goto out;
+ case SIG('C', 'L'):
+ ISOFS_I(inode)->i_first_extent =
+ isonum_733(rr->u.CL.location);
+ reloc =
+ isofs_iget(inode->i_sb,
+ ISOFS_I(inode)->i_first_extent,
+ 0);
+ if (!reloc)
+ goto out;
+ inode->i_mode = reloc->i_mode;
+ inode->i_nlink = reloc->i_nlink;
+ inode->i_uid = reloc->i_uid;
+ inode->i_gid = reloc->i_gid;
+ inode->i_rdev = reloc->i_rdev;
+ inode->i_size = reloc->i_size;
+ inode->i_blocks = reloc->i_blocks;
+ inode->i_atime = reloc->i_atime;
+ inode->i_ctime = reloc->i_ctime;
+ inode->i_mtime = reloc->i_mtime;
+ iput(reloc);
+ break;
#ifdef CONFIG_ZISOFS
- case SIG('Z','F'):
- if ( !ISOFS_SB(inode->i_sb)->s_nocompress ) {
- int algo;
- algo = isonum_721(rr->u.ZF.algorithm);
- if ( algo == SIG('p','z') ) {
- int block_shift = isonum_711(&rr->u.ZF.parms[1]);
- if ( block_shift < PAGE_CACHE_SHIFT || block_shift > 17 ) {
- printk(KERN_WARNING "isofs: Can't handle ZF block size of 2^%d\n", block_shift);
- } else {
- /* Note: we don't change i_blocks here */
- ISOFS_I(inode)->i_file_format = isofs_file_compressed;
- /* Parameters to compression algorithm (header size, block size) */
- ISOFS_I(inode)->i_format_parm[0] = isonum_711(&rr->u.ZF.parms[0]);
- ISOFS_I(inode)->i_format_parm[1] = isonum_711(&rr->u.ZF.parms[1]);
- inode->i_size = isonum_733(rr->u.ZF.real_size);
- }
- } else {
- printk(KERN_WARNING "isofs: Unknown ZF compression algorithm: %c%c\n",
- rr->u.ZF.algorithm[0], rr->u.ZF.algorithm[1]);
- }
- }
- break;
+ case SIG('Z', 'F'): {
+ int algo;
+
+ if (ISOFS_SB(inode->i_sb)->s_nocompress)
+ break;
+ algo = isonum_721(rr->u.ZF.algorithm);
+ if (algo == SIG('p', 'z')) {
+ int block_shift =
+ isonum_711(&rr->u.ZF.parms[1]);
+ if (block_shift < PAGE_CACHE_SHIFT
+ || block_shift > 17) {
+ printk(KERN_WARNING "isofs: "
+ "Can't handle ZF block "
+ "size of 2^%d\n",
+ block_shift);
+ } else {
+ /*
+ * Note: we don't change
+ * i_blocks here
+ */
+ ISOFS_I(inode)->i_file_format =
+ isofs_file_compressed;
+ /*
+ * Parameters to compression
+ * algorithm (header size,
+ * block size)
+ */
+ ISOFS_I(inode)->i_format_parm[0] =
+ isonum_711(&rr->u.ZF.parms[0]);
+ ISOFS_I(inode)->i_format_parm[1] =
+ isonum_711(&rr->u.ZF.parms[1]);
+ inode->i_size =
+ isonum_733(rr->u.ZF.
+ real_size);
+ }
+ } else {
+ printk(KERN_WARNING
+ "isofs: Unknown ZF compression "
+ "algorithm: %c%c\n",
+ rr->u.ZF.algorithm[0],
+ rr->u.ZF.algorithm[1]);
+ }
+ break;
+ }
#endif
- default:
- break;
- }
- }
- }
- MAYBE_CONTINUE(repeat,inode);
- out:
- if(buffer) kfree(buffer);
- return 0;
+ default:
+ break;
+ }
+ }
+ ret = rock_continue(&rs);
+ if (ret == 0)
+ goto repeat;
+ if (ret == 1)
+ ret = 0;
+out:
+ kfree(rs.buffer);
+ return ret;
+eio:
+ ret = -EIO;
+ goto out;
}
static char *get_symlink_chunk(char *rpnt, struct rock_ridge *rr, char *plimit)
if (slp->len > plimit - rpnt)
return NULL;
memcpy(rpnt, slp->text, slp->len);
- rpnt+=slp->len;
+ rpnt += slp->len;
break;
case 2:
if (rpnt >= plimit)
return NULL;
- *rpnt++='.';
+ *rpnt++ = '.';
break;
case 4:
if (2 > plimit - rpnt)
return NULL;
- *rpnt++='.';
- *rpnt++='.';
+ *rpnt++ = '.';
+ *rpnt++ = '.';
break;
case 8:
if (rpnt >= plimit)
return NULL;
rootflag = 1;
- *rpnt++='/';
+ *rpnt++ = '/';
break;
default:
printk("Symlink component flag not implemented (%d)\n",
- slp->flags);
+ slp->flags);
}
slen -= slp->len + 2;
oldslp = slp;
- slp = (struct SL_component *) ((char *) slp + slp->len + 2);
+ slp = (struct SL_component *)((char *)slp + slp->len + 2);
if (slen < 2) {
/*
!(oldslp->flags & 1)) {
if (rpnt >= plimit)
return NULL;
- *rpnt++='/';
+ *rpnt++ = '/';
}
break;
}
if (!rootflag && !(oldslp->flags & 1)) {
if (rpnt >= plimit)
return NULL;
- *rpnt++='/';
+ *rpnt++ = '/';
}
}
return rpnt;
}
-int parse_rock_ridge_inode(struct iso_directory_record * de,
- struct inode * inode)
+int parse_rock_ridge_inode(struct iso_directory_record *de, struct inode *inode)
{
- int result=parse_rock_ridge_inode_internal(de,inode,0);
- /* if rockridge flag was reset and we didn't look for attributes
- * behind eventual XA attributes, have a look there */
- if ((ISOFS_SB(inode->i_sb)->s_rock_offset==-1)
- &&(ISOFS_SB(inode->i_sb)->s_rock==2))
- {
- result=parse_rock_ridge_inode_internal(de,inode,14);
- }
- return result;
-}
+ int result = parse_rock_ridge_inode_internal(de, inode, 0);
-/* readpage() for symlinks: reads symlink contents into the page and either
- makes it uptodate and returns 0 or returns error (-EIO) */
+ /*
+ * if rockridge flag was reset and we didn't look for attributes
+ * behind eventual XA attributes, have a look there
+ */
+ if ((ISOFS_SB(inode->i_sb)->s_rock_offset == -1)
+ && (ISOFS_SB(inode->i_sb)->s_rock == 2)) {
+ result = parse_rock_ridge_inode_internal(de, inode, 14);
+ }
+ return result;
+}
+/*
+ * readpage() for symlinks: reads symlink contents into the page and either
+ * makes it uptodate and returns 0 or returns error (-EIO)
+ */
static int rock_ridge_symlink_readpage(struct file *file, struct page *page)
{
struct inode *inode = page->mapping->host;
- struct iso_inode_info *ei = ISOFS_I(inode);
+ struct iso_inode_info *ei = ISOFS_I(inode);
char *link = kmap(page);
unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
struct buffer_head *bh;
char *rpnt = link;
unsigned char *pnt;
- struct iso_directory_record *raw_inode;
- CONTINUE_DECLS;
+ struct iso_directory_record *raw_de;
unsigned long block, offset;
int sig;
- int len;
- unsigned char *chr;
struct rock_ridge *rr;
+ struct rock_state rs;
+ int ret;
if (!ISOFS_SB(inode->i_sb)->s_rock)
goto error;
+ init_rock_state(&rs, inode);
block = ei->i_iget5_block;
lock_kernel();
bh = sb_bread(inode->i_sb, block);
if (!bh)
goto out_noread;
- offset = ei->i_iget5_offset;
- pnt = (unsigned char *) bh->b_data + offset;
+ offset = ei->i_iget5_offset;
+ pnt = (unsigned char *)bh->b_data + offset;
- raw_inode = (struct iso_directory_record *) pnt;
+ raw_de = (struct iso_directory_record *)pnt;
/*
* If we go past the end of the buffer, there is some sort of error.
if (offset + *pnt > bufsize)
goto out_bad_span;
- /* Now test for possible Rock Ridge extensions which will override
- some of these numbers in the inode structure. */
+ /*
+ * Now test for possible Rock Ridge extensions which will override
+ * some of these numbers in the inode structure.
+ */
- SETUP_ROCK_RIDGE(raw_inode, chr, len);
+ setup_rock_ridge(raw_de, inode, &rs);
- repeat:
- while (len > 2) { /* There may be one byte for padding somewhere */
- rr = (struct rock_ridge *) chr;
+repeat:
+ while (rs.len > 2) { /* There may be one byte for padding somewhere */
+ rr = (struct rock_ridge *)rs.chr;
if (rr->len < 3)
goto out; /* Something got screwed up here */
- sig = isonum_721(chr);
- chr += rr->len;
- len -= rr->len;
- if (len < 0)
+ sig = isonum_721(rs.chr);
+ if (rock_check_overflow(&rs, sig))
+ goto out;
+ rs.chr += rr->len;
+ rs.len -= rr->len;
+ if (rs.len < 0)
goto out; /* corrupted isofs */
switch (sig) {
goto out;
break;
case SIG('S', 'P'):
- CHECK_SP(goto out);
+ if (check_sp(rr, inode))
+ goto out;
break;
case SIG('S', 'L'):
rpnt = get_symlink_chunk(rpnt, rr,
break;
case SIG('C', 'E'):
/* This tells is if there is a continuation record */
- CHECK_CE;
+ rs.cont_extent = isonum_733(rr->u.CE.extent);
+ rs.cont_offset = isonum_733(rr->u.CE.offset);
+ rs.cont_size = isonum_733(rr->u.CE.size);
default:
break;
}
}
- MAYBE_CONTINUE(repeat, inode);
- if (buffer)
- kfree(buffer);
+ ret = rock_continue(&rs);
+ if (ret == 0)
+ goto repeat;
+ if (ret < 0)
+ goto fail;
if (rpnt == link)
goto fail;
return 0;
/* error exit from macro */
- out:
- if (buffer)
- kfree(buffer);
+out:
+ kfree(rs.buffer);
goto fail;
- out_noread:
+out_noread:
printk("unable to read i-node block");
goto fail;
- out_bad_span:
+out_bad_span:
printk("symlink spans iso9660 blocks\n");
- fail:
+fail:
brelse(bh);
unlock_kernel();
- error:
+error:
SetPageError(page);
kunmap(page);
unlock_page(page);
}
struct address_space_operations isofs_symlink_aops = {
- .readpage = rock_ridge_symlink_readpage
+ .readpage = rock_ridge_symlink_readpage
};
-/* These structs are used by the system-use-sharing protocol, in which the
- Rock Ridge extensions are embedded. It is quite possible that other
- extensions are present on the disk, and this is fine as long as they
- all use SUSP */
-
-struct SU_SP{
- unsigned char magic[2];
- unsigned char skip;
-} __attribute__((packed));
-
-struct SU_CE{
- char extent[8];
- char offset[8];
- char size[8];
+/*
+ * These structs are used by the system-use-sharing protocol, in which the
+ * Rock Ridge extensions are embedded. It is quite possible that other
+ * extensions are present on the disk, and this is fine as long as they
+ * all use SUSP
+ */
+
+struct SU_SP_s {
+ unsigned char magic[2];
+ unsigned char skip;
+} __attribute__ ((packed));
+
+struct SU_CE_s {
+ char extent[8];
+ char offset[8];
+ char size[8];
};
-struct SU_ER{
- unsigned char len_id;
- unsigned char len_des;
- unsigned char len_src;
- unsigned char ext_ver;
- char data[0];
-} __attribute__((packed));
-
-struct RR_RR{
- char flags[1];
-} __attribute__((packed));
-
-struct RR_PX{
- char mode[8];
- char n_links[8];
- char uid[8];
- char gid[8];
+struct SU_ER_s {
+ unsigned char len_id;
+ unsigned char len_des;
+ unsigned char len_src;
+ unsigned char ext_ver;
+ char data[0];
+} __attribute__ ((packed));
+
+struct RR_RR_s {
+ char flags[1];
+} __attribute__ ((packed));
+
+struct RR_PX_s {
+ char mode[8];
+ char n_links[8];
+ char uid[8];
+ char gid[8];
};
-struct RR_PN{
- char dev_high[8];
- char dev_low[8];
+struct RR_PN_s {
+ char dev_high[8];
+ char dev_low[8];
};
+struct SL_component {
+ unsigned char flags;
+ unsigned char len;
+ char text[0];
+} __attribute__ ((packed));
-struct SL_component{
- unsigned char flags;
- unsigned char len;
- char text[0];
-} __attribute__((packed));
+struct RR_SL_s {
+ unsigned char flags;
+ struct SL_component link;
+} __attribute__ ((packed));
-struct RR_SL{
- unsigned char flags;
- struct SL_component link;
-} __attribute__((packed));
+struct RR_NM_s {
+ unsigned char flags;
+ char name[0];
+} __attribute__ ((packed));
-struct RR_NM{
- unsigned char flags;
- char name[0];
-} __attribute__((packed));
-
-struct RR_CL{
- char location[8];
+struct RR_CL_s {
+ char location[8];
};
-struct RR_PL{
- char location[8];
+struct RR_PL_s {
+ char location[8];
};
-struct stamp{
- char time[7];
-} __attribute__((packed));
+struct stamp {
+ char time[7];
+} __attribute__ ((packed));
-struct RR_TF{
- char flags;
- struct stamp times[0]; /* Variable number of these beasts */
-} __attribute__((packed));
+struct RR_TF_s {
+ char flags;
+ struct stamp times[0]; /* Variable number of these beasts */
+} __attribute__ ((packed));
/* Linux-specific extension for transparent decompression */
-struct RR_ZF{
- char algorithm[2];
- char parms[2];
- char real_size[8];
+struct RR_ZF_s {
+ char algorithm[2];
+ char parms[2];
+ char real_size[8];
};
-/* These are the bits and their meanings for flags in the TF structure. */
+/*
+ * These are the bits and their meanings for flags in the TF structure.
+ */
#define TF_CREATE 1
#define TF_MODIFY 2
#define TF_ACCESS 4
#define TF_EFFECTIVE 64
#define TF_LONG_FORM 128
-struct rock_ridge{
- char signature[2];
- unsigned char len;
- unsigned char version;
- union{
- struct SU_SP SP;
- struct SU_CE CE;
- struct SU_ER ER;
- struct RR_RR RR;
- struct RR_PX PX;
- struct RR_PN PN;
- struct RR_SL SL;
- struct RR_NM NM;
- struct RR_CL CL;
- struct RR_PL PL;
- struct RR_TF TF;
- struct RR_ZF ZF;
- } u;
+struct rock_ridge {
+ char signature[2];
+ unsigned char len;
+ unsigned char version;
+ union {
+ struct SU_SP_s SP;
+ struct SU_CE_s CE;
+ struct SU_ER_s ER;
+ struct RR_RR_s RR;
+ struct RR_PX_s PX;
+ struct RR_PN_s PN;
+ struct RR_SL_s SL;
+ struct RR_NM_s NM;
+ struct RR_CL_s CL;
+ struct RR_PL_s PL;
+ struct RR_TF_s TF;
+ struct RR_ZF_s ZF;
+ } u;
};
-#define RR_PX 1 /* POSIX attributes */
-#define RR_PN 2 /* POSIX devices */
-#define RR_SL 4 /* Symbolic link */
-#define RR_NM 8 /* Alternate Name */
-#define RR_CL 16 /* Child link */
-#define RR_PL 32 /* Parent link */
-#define RR_RE 64 /* Relocation directory */
-#define RR_TF 128 /* Timestamps */
+#define RR_PX 1 /* POSIX attributes */
+#define RR_PN 2 /* POSIX devices */
+#define RR_SL 4 /* Symbolic link */
+#define RR_NM 8 /* Alternate Name */
+#define RR_CL 16 /* Child link */
+#define RR_PL 32 /* Parent link */
+#define RR_RE 64 /* Relocation directory */
+#define RR_TF 128 /* Timestamps */
.release = seq_release,
};
+extern struct seq_operations zoneinfo_op;
+static int zoneinfo_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &zoneinfo_op);
+}
+
+static struct file_operations proc_zoneinfo_file_operations = {
+ .open = zoneinfo_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
static int version_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
create_seq_entry("slabinfo",S_IWUSR|S_IRUGO,&proc_slabinfo_operations);
create_seq_entry("buddyinfo",S_IRUGO, &fragmentation_file_operations);
create_seq_entry("vmstat",S_IRUGO, &proc_vmstat_file_operations);
+ create_seq_entry("zoneinfo",S_IRUGO, &proc_zoneinfo_file_operations);
create_seq_entry("diskstats", 0, &proc_diskstats_operations);
#ifdef CONFIG_MODULES
create_seq_entry("modules", 0, &proc_modules_operations);
mnt->mnt_parent = mnt;
mnt->mnt_namespace = current->namespace;
up_write(&sb->s_umount);
+ free_secdata(secdata);
put_filesystem(type);
return mnt;
out_sb:
* File wide globals
*/
-STATIC kmem_cache_t *pagebuf_cache;
+STATIC kmem_cache_t *pagebuf_zone;
STATIC kmem_shaker_t pagebuf_shake;
-STATIC int pagebuf_daemon_wakeup(int, unsigned int);
+STATIC int xfsbufd_wakeup(int, unsigned int);
STATIC void pagebuf_delwri_queue(xfs_buf_t *, int);
-STATIC struct workqueue_struct *pagebuf_logio_workqueue;
-STATIC struct workqueue_struct *pagebuf_dataio_workqueue;
+
+STATIC struct workqueue_struct *xfslogd_workqueue;
+STATIC struct workqueue_struct *xfsdatad_workqueue;
/*
* Pagebuf debugging
#define pagebuf_allocate(flags) \
- kmem_zone_alloc(pagebuf_cache, pb_to_km(flags))
+ kmem_zone_alloc(pagebuf_zone, pb_to_km(flags))
#define pagebuf_deallocate(pb) \
- kmem_zone_free(pagebuf_cache, (pb));
+ kmem_zone_free(pagebuf_zone, (pb));
/*
* Page Region interfaces.
__FUNCTION__, gfp_mask);
XFS_STATS_INC(pb_page_retries);
- pagebuf_daemon_wakeup(0, gfp_mask);
+ xfsbufd_wakeup(0, gfp_mask);
blk_congestion_wait(WRITE, HZ/50);
goto retry;
}
if ((pb->pb_iodone) || (pb->pb_flags & PBF_ASYNC)) {
if (schedule) {
INIT_WORK(&pb->pb_iodone_work, pagebuf_iodone_work, pb);
- queue_work(dataio ? pagebuf_dataio_workqueue :
- pagebuf_logio_workqueue, &pb->pb_iodone_work);
+ queue_work(dataio ? xfsdatad_workqueue :
+ xfslogd_workqueue, &pb->pb_iodone_work);
} else {
pagebuf_iodone_work(pb);
}
kmem_free(btp, sizeof(*btp));
}
-void
-xfs_incore_relse(
- xfs_buftarg_t *btp,
- int delwri_only,
- int wait)
-{
- invalidate_bdev(btp->pbr_bdev, 1);
- truncate_inode_pages(btp->pbr_mapping, 0LL);
-}
-
STATIC int
xfs_setsize_buftarg_flags(
xfs_buftarg_t *btp,
}
/* Defines for pagebuf daemon */
-STATIC DECLARE_COMPLETION(pagebuf_daemon_done);
-STATIC struct task_struct *pagebuf_daemon_task;
-STATIC int pagebuf_daemon_active;
-STATIC int force_flush;
-STATIC int force_sleep;
+STATIC DECLARE_COMPLETION(xfsbufd_done);
+STATIC struct task_struct *xfsbufd_task;
+STATIC int xfsbufd_active;
+STATIC int xfsbufd_force_flush;
+STATIC int xfsbufd_force_sleep;
STATIC int
-pagebuf_daemon_wakeup(
+xfsbufd_wakeup(
int priority,
unsigned int mask)
{
- if (force_sleep)
+ if (xfsbufd_force_sleep)
return 0;
- force_flush = 1;
+ xfsbufd_force_flush = 1;
barrier();
- wake_up_process(pagebuf_daemon_task);
+ wake_up_process(xfsbufd_task);
return 0;
}
STATIC int
-pagebuf_daemon(
+xfsbufd(
void *data)
{
struct list_head tmp;
daemonize("xfsbufd");
current->flags |= PF_MEMALLOC;
- pagebuf_daemon_task = current;
- pagebuf_daemon_active = 1;
+ xfsbufd_task = current;
+ xfsbufd_active = 1;
barrier();
INIT_LIST_HEAD(&tmp);
do {
if (unlikely(current->flags & PF_FREEZE)) {
- force_sleep = 1;
+ xfsbufd_force_sleep = 1;
refrigerator(PF_FREEZE);
} else {
- force_sleep = 0;
+ xfsbufd_force_sleep = 0;
}
set_current_state(TASK_INTERRUPTIBLE);
ASSERT(pb->pb_flags & PBF_DELWRI);
if (!pagebuf_ispin(pb) && !pagebuf_cond_lock(pb)) {
- if (!force_flush &&
+ if (!xfsbufd_force_flush &&
time_before(jiffies,
pb->pb_queuetime + age)) {
pagebuf_unlock(pb);
if (as_list_len > 0)
purge_addresses();
- force_flush = 0;
- } while (pagebuf_daemon_active);
+ xfsbufd_force_flush = 0;
+ } while (xfsbufd_active);
- complete_and_exit(&pagebuf_daemon_done, 0);
+ complete_and_exit(&xfsbufd_done, 0);
}
/*
xfs_buf_t *pb, *n;
int pincount = 0;
- pagebuf_runall_queues(pagebuf_dataio_workqueue);
- pagebuf_runall_queues(pagebuf_logio_workqueue);
+ pagebuf_runall_queues(xfsdatad_workqueue);
+ pagebuf_runall_queues(xfslogd_workqueue);
INIT_LIST_HEAD(&tmp);
spin_lock(&pbd_delwrite_lock);
}
STATIC int
-pagebuf_daemon_start(void)
+xfs_buf_daemons_start(void)
{
- int rval;
+ int error = -ENOMEM;
- pagebuf_logio_workqueue = create_workqueue("xfslogd");
- if (!pagebuf_logio_workqueue)
- return -ENOMEM;
+ xfslogd_workqueue = create_workqueue("xfslogd");
+ if (!xfslogd_workqueue)
+ goto out;
- pagebuf_dataio_workqueue = create_workqueue("xfsdatad");
- if (!pagebuf_dataio_workqueue) {
- destroy_workqueue(pagebuf_logio_workqueue);
- return -ENOMEM;
- }
+ xfsdatad_workqueue = create_workqueue("xfsdatad");
+ if (!xfsdatad_workqueue)
+ goto out_destroy_xfslogd_workqueue;
- rval = kernel_thread(pagebuf_daemon, NULL, CLONE_FS|CLONE_FILES);
- if (rval < 0) {
- destroy_workqueue(pagebuf_logio_workqueue);
- destroy_workqueue(pagebuf_dataio_workqueue);
- }
+ error = kernel_thread(xfsbufd, NULL, CLONE_FS|CLONE_FILES);
+ if (error < 0)
+ goto out_destroy_xfsdatad_workqueue;
+ return 0;
- return rval;
+ out_destroy_xfsdatad_workqueue:
+ destroy_workqueue(xfsdatad_workqueue);
+ out_destroy_xfslogd_workqueue:
+ destroy_workqueue(xfslogd_workqueue);
+ out:
+ return error;
}
/*
- * pagebuf_daemon_stop
- *
* Note: do not mark as __exit, it is called from pagebuf_terminate.
*/
STATIC void
-pagebuf_daemon_stop(void)
+xfs_buf_daemons_stop(void)
{
- pagebuf_daemon_active = 0;
+ xfsbufd_active = 0;
barrier();
- wait_for_completion(&pagebuf_daemon_done);
+ wait_for_completion(&xfsbufd_done);
- destroy_workqueue(pagebuf_logio_workqueue);
- destroy_workqueue(pagebuf_dataio_workqueue);
+ destroy_workqueue(xfslogd_workqueue);
+ destroy_workqueue(xfsdatad_workqueue);
}
/*
int __init
pagebuf_init(void)
{
- pagebuf_cache = kmem_cache_create("xfs_buf_t", sizeof(xfs_buf_t), 0,
- SLAB_HWCACHE_ALIGN, NULL, NULL);
- if (pagebuf_cache == NULL) {
- printk("XFS: couldn't init xfs_buf_t cache\n");
- pagebuf_terminate();
- return -ENOMEM;
- }
+ int error = -ENOMEM;
+
+ pagebuf_zone = kmem_zone_init(sizeof(xfs_buf_t), "xfs_buf");
+ if (!pagebuf_zone)
+ goto out;
#ifdef PAGEBUF_TRACE
pagebuf_trace_buf = ktrace_alloc(PAGEBUF_TRACE_SIZE, KM_SLEEP);
#endif
- pagebuf_daemon_start();
+ error = xfs_buf_daemons_start();
+ if (error)
+ goto out_free_buf_zone;
- pagebuf_shake = kmem_shake_register(pagebuf_daemon_wakeup);
- if (pagebuf_shake == NULL) {
- pagebuf_terminate();
- return -ENOMEM;
+ pagebuf_shake = kmem_shake_register(xfsbufd_wakeup);
+ if (!pagebuf_shake) {
+ error = -ENOMEM;
+ goto out_stop_daemons;
}
return 0;
+
+ out_stop_daemons:
+ xfs_buf_daemons_stop();
+ out_free_buf_zone:
+#ifdef PAGEBUF_TRACE
+ ktrace_free(pagebuf_trace_buf);
+#endif
+ kmem_zone_destroy(pagebuf_zone);
+ out:
+ return error;
}
void
pagebuf_terminate(void)
{
- pagebuf_daemon_stop();
+ xfs_buf_daemons_stop();
#ifdef PAGEBUF_TRACE
ktrace_free(pagebuf_trace_buf);
#endif
- kmem_zone_destroy(pagebuf_cache);
+ kmem_zone_destroy(pagebuf_zone);
kmem_shake_deregister(pagebuf_shake);
}
extern void xfs_free_buftarg(xfs_buftarg_t *, int);
extern void xfs_wait_buftarg(xfs_buftarg_t *);
extern int xfs_setsize_buftarg(xfs_buftarg_t *, unsigned int, unsigned int);
-extern void xfs_incore_relse(xfs_buftarg_t *, int, int);
extern int xfs_flush_buftarg(xfs_buftarg_t *, int);
#define xfs_getsize_buftarg(buftarg) \
#include <linux/smp_lock.h>
static struct vm_operations_struct linvfs_file_vm_ops;
-
+#ifdef CONFIG_XFS_DMAPI
+static struct vm_operations_struct linvfs_dmapi_file_vm_ops;
+#endif
STATIC inline ssize_t
__linvfs_read(
return -error;
}
+#ifdef CONFIG_XFS_DMAPI
+STATIC void
+linvfs_mmap_close(
+ struct vm_area_struct *vma)
+{
+ xfs_dm_mm_put(vma);
+}
+#endif /* CONFIG_XFS_DMAPI */
STATIC int
linvfs_file_mmap(
vattr_t va = { .va_mask = XFS_AT_UPDATIME };
int error;
+ vma->vm_ops = &linvfs_file_vm_ops;
+
if (vp->v_vfsp->vfs_flag & VFS_DMI) {
xfs_mount_t *mp = XFS_VFSTOM(vp->v_vfsp);
error = -XFS_SEND_MMAP(mp, vma, 0);
if (error)
return error;
+#ifdef CONFIG_XFS_DMAPI
+ vma->vm_ops = &linvfs_dmapi_file_vm_ops;
+#endif
}
- vma->vm_ops = &linvfs_file_vm_ops;
-
VOP_SETATTR(vp, &va, XFS_AT_UPDATIME, NULL, error);
if (!error)
vn_revalidate(vp); /* update Linux inode flags */
static struct vm_operations_struct linvfs_file_vm_ops = {
.nopage = filemap_nopage,
.populate = filemap_populate,
+};
+
+#ifdef CONFIG_XFS_DMAPI
+static struct vm_operations_struct linvfs_dmapi_file_vm_ops = {
+ .close = linvfs_mmap_close,
+ .nopage = filemap_nopage,
+ .populate = filemap_populate,
#ifdef HAVE_VMOP_MPROTECT
.mprotect = linvfs_mprotect,
#endif
};
+#endif /* CONFIG_XFS_DMAPI */
switch (cmd) {
case XFS_IOC_FSGETXATTR: {
- va.va_mask = XFS_AT_XFLAGS|XFS_AT_EXTSIZE|XFS_AT_NEXTENTS;
+ va.va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | \
+ XFS_AT_NEXTENTS | XFS_AT_PROJID;
VOP_GETATTR(vp, &va, 0, NULL, error);
if (error)
return -error;
fa.fsx_xflags = va.va_xflags;
fa.fsx_extsize = va.va_extsize;
fa.fsx_nextents = va.va_nextents;
+ fa.fsx_projid = va.va_projid;
if (copy_to_user(arg, &fa, sizeof(fa)))
return -XFS_ERROR(EFAULT);
if (filp->f_flags & (O_NDELAY|O_NONBLOCK))
attr_flags |= ATTR_NONBLOCK;
- va.va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE;
+ va.va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | XFS_AT_PROJID;
va.va_xflags = fa.fsx_xflags;
va.va_extsize = fa.fsx_extsize;
+ va.va_projid = fa.fsx_projid;
VOP_SETATTR(vp, &va, attr_flags, NULL, error);
if (!error)
}
case XFS_IOC_FSGETXATTRA: {
- va.va_mask = XFS_AT_XFLAGS|XFS_AT_EXTSIZE|XFS_AT_ANEXTENTS;
+ va.va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | \
+ XFS_AT_ANEXTENTS | XFS_AT_PROJID;
VOP_GETATTR(vp, &va, 0, NULL, error);
if (error)
return -error;
fa.fsx_xflags = va.va_xflags;
fa.fsx_extsize = va.va_extsize;
fa.fsx_nextents = va.va_anextents;
+ fa.fsx_projid = va.va_projid;
if (copy_to_user(arg, &fa, sizeof(fa)))
return -XFS_ERROR(EFAULT);
#define xfs_inherit_nosymlinks xfs_params.inherit_nosym.val
#define xfs_rotorstep xfs_params.rotorstep.val
-#ifndef __smp_processor_id
-#define __smp_processor_id() smp_processor_id()
+#ifndef raw_smp_processor_id
+#define raw_smp_processor_id() smp_processor_id()
#endif
-#define current_cpu() __smp_processor_id()
+#define current_cpu() raw_smp_processor_id()
#define current_pid() (current->pid)
#define current_fsuid(cred) (current->fsuid)
#define current_fsgid(cred) (current->fsgid)
* field (see the QCMD macro in quota.h). These macros help keep the
* code portable - they are not visible from the syscall interface.
*/
-#define Q_XSETGQLIM XQM_CMD(0x8) /* set groups disk limits */
-#define Q_XGETGQUOTA XQM_CMD(0x9) /* get groups disk limits */
+#define Q_XSETGQLIM XQM_CMD(8) /* set groups disk limits */
+#define Q_XGETGQUOTA XQM_CMD(9) /* get groups disk limits */
+#define Q_XSETPQLIM XQM_CMD(10) /* set projects disk limits */
+#define Q_XGETPQUOTA XQM_CMD(11) /* get projects disk limits */
/* IRIX uses a dynamic sizing algorithm (ndquot = 200 + numprocs*2) */
/* we may well need to fine-tune this if it ever becomes an issue. */
return (-status);
}
-/*
- * xfs_inval_cached_pages
- *
- * This routine is responsible for keeping direct I/O and buffered I/O
- * somewhat coherent. From here we make sure that we're at least
- * temporarily holding the inode I/O lock exclusively and then call
- * the page cache to flush and invalidate any cached pages. If there
- * are no cached pages this routine will be very quick.
- */
-void
-xfs_inval_cached_pages(
- vnode_t *vp,
- xfs_iocore_t *io,
- xfs_off_t offset,
- int write,
- int relock)
-{
- if (VN_CACHED(vp)) {
- xfs_inval_cached_trace(io, offset, -1, ctooff(offtoct(offset)), -1);
- VOP_FLUSHINVAL_PAGES(vp, ctooff(offtoct(offset)), -1, FI_REMAPF_LOCKED);
- }
-
-}
-
ssize_t /* bytes read, or (-) error */
xfs_read(
bhv_desc_t *bdp,
if (DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_READ) &&
!(ioflags & IO_INVIS)) {
vrwlock_t locktype = VRWLOCK_READ;
+ int dmflags = FILP_DELAY_FLAG(file) | DM_SEM_FLAG_RD(ioflags);
ret = -XFS_SEND_DATA(mp, DM_EVENT_READ,
BHV_TO_VNODE(bdp), *offset, size,
- FILP_DELAY_FLAG(file), &locktype);
+ dmflags, &locktype);
if (ret) {
xfs_iunlock(ip, XFS_IOLOCK_SHARED);
goto unlock_isem;
!(ioflags & IO_INVIS)) {
xfs_rwunlock(bdp, locktype);
+ if (need_isem)
+ up(&inode->i_sem);
error = XFS_SEND_NAMESP(xip->i_mount, DM_EVENT_NOSPACE, vp,
DM_RIGHT_NULL, vp, DM_RIGHT_NULL, NULL, NULL,
0, 0, 0); /* Delay flag intentionally unused */
if (error)
- goto out_unlock_isem;
+ goto out_nounlocks;
+ if (need_isem)
+ down(&inode->i_sem);
xfs_rwlock(bdp, locktype);
pos = xip->i_d.di_size;
ret = 0;
out_unlock_isem:
if (need_isem)
up(&inode->i_sem);
+ out_nounlocks:
return -error;
}
extern int xfs_zero_eof(struct vnode *, struct xfs_iocore *, xfs_off_t,
xfs_fsize_t, xfs_fsize_t);
-extern void xfs_inval_cached_pages(struct vnode *, struct xfs_iocore *,
- xfs_off_t, int, int);
extern ssize_t xfs_read(struct bhv_desc *, struct kiocb *,
const struct iovec *, unsigned int,
loff_t *, int, struct cred *);
int error;
int flags = SYNC_FSDATA;
- if (wait)
- flags |= SYNC_WAIT;
+ if (unlikely(sb->s_frozen == SB_FREEZE_WRITE))
+ flags = SYNC_QUIESCE;
+ else
+ flags = SYNC_FSDATA | (wait ? SYNC_WAIT : 0);
VFS_SYNC(vfsp, flags, NULL, error);
sb->s_dirt = 0;
struct vfs *vfsp = LINVFS_GET_VFS(sb);
int error, getmode;
- getmode = (type == GRPQUOTA) ? Q_XGETGQUOTA : Q_XGETQUOTA;
+ getmode = (type == USRQUOTA) ? Q_XGETQUOTA :
+ ((type == GRPQUOTA) ? Q_XGETGQUOTA : Q_XGETPQUOTA);
VFS_QUOTACTL(vfsp, getmode, id, (caddr_t)fdq, error);
return -error;
}
struct vfs *vfsp = LINVFS_GET_VFS(sb);
int error, setmode;
- setmode = (type == GRPQUOTA) ? Q_XSETGQLIM : Q_XSETQLIM;
+ setmode = (type == USRQUOTA) ? Q_XSETQLIM :
+ ((type == GRPQUOTA) ? Q_XSETGQLIM : Q_XSETPQLIM);
VFS_QUOTACTL(vfsp, setmode, id, (caddr_t)fdq, error);
return -error;
}
#define SYNC_FSDATA 0x0020 /* flush fs data (e.g. superblocks) */
#define SYNC_REFCACHE 0x0040 /* prune some of the nfs ref cache */
#define SYNC_REMOUNT 0x0080 /* remount readonly, no dummy LRs */
+#define SYNC_QUIESCE 0x0100 /* quiesce fileystem for a snapshot */
typedef int (*vfs_mount_t)(bhv_desc_t *,
struct xfs_mount_args *, struct cred *);
/* 0 */ (void *)(__psint_t)(vk), \
/* 1 */ (void *)(s), \
/* 2 */ (void *)(__psint_t) line, \
-/* 3 */ (void *)(vn_count(vp)), \
+/* 3 */ (void *)(__psint_t)(vn_count(vp)), \
/* 4 */ (void *)(ra), \
/* 5 */ (void *)(__psunsigned_t)(vp)->v_flag, \
/* 6 */ (void *)(__psint_t)current_cpu(), \
/* 7 */ (void *)(__psint_t)current_pid(), \
/* 8 */ (void *)__return_address, \
-/* 9 */ 0, 0, 0, 0, 0, 0, 0)
+/* 9 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL)
/*
* Vnode tracing code.
u_long va_extsize; /* file extent size */
u_long va_nextents; /* number of extents in file */
u_long va_anextents; /* number of attr extents in file */
- int va_projid; /* project id */
+ prid_t va_projid; /* project id */
} vattr_t;
/*
* is the d_id field. The idea is to fill in the entire q_core
* when we read in the on disk dquot.
*/
-xfs_dquot_t *
+STATIC xfs_dquot_t *
xfs_qm_dqinit(
xfs_mount_t *mp,
xfs_dqid_t id,
* We also return 0 as the values of the timers in Q_GETQUOTA calls, when
* enforcement's off.
* In contrast, warnings are a little different in that they don't
- * 'automatically' get started when limits get exceeded.
+ * 'automatically' get started when limits get exceeded. They do
+ * get reset to zero, however, when we find the count to be under
+ * the soft limit (they are only ever set non-zero via userspace).
*/
void
xfs_qm_adjust_dqtimers(
INT_GET(d->d_blk_hardlimit, ARCH_CONVERT)))) {
INT_SET(d->d_btimer, ARCH_CONVERT,
get_seconds() + XFS_QI_BTIMELIMIT(mp));
+ } else {
+ d->d_bwarns = 0;
}
} else {
if ((!d->d_blk_softlimit ||
INT_GET(d->d_ino_hardlimit, ARCH_CONVERT)))) {
INT_SET(d->d_itimer, ARCH_CONVERT,
get_seconds() + XFS_QI_ITIMELIMIT(mp));
+ } else {
+ d->d_iwarns = 0;
}
} else {
if ((!d->d_ino_softlimit ||
INT_GET(d->d_rtb_hardlimit, ARCH_CONVERT)))) {
INT_SET(d->d_rtbtimer, ARCH_CONVERT,
get_seconds() + XFS_QI_RTBTIMELIMIT(mp));
+ } else {
+ d->d_rtbwarns = 0;
}
} else {
if ((!d->d_rtb_softlimit ||
}
}
-/*
- * Increment or reset warnings of a given dquot.
- */
-int
-xfs_qm_dqwarn(
- xfs_disk_dquot_t *d,
- uint flags)
-{
- int warned;
-
- /*
- * root's limits are not real limits.
- */
- if (!d->d_id)
- return (0);
-
- warned = 0;
- if (INT_GET(d->d_blk_softlimit, ARCH_CONVERT) &&
- (INT_GET(d->d_bcount, ARCH_CONVERT) >=
- INT_GET(d->d_blk_softlimit, ARCH_CONVERT))) {
- if (flags & XFS_QMOPT_DOWARN) {
- INT_MOD(d->d_bwarns, ARCH_CONVERT, +1);
- warned++;
- }
- } else {
- if (!d->d_blk_softlimit ||
- (INT_GET(d->d_bcount, ARCH_CONVERT) <
- INT_GET(d->d_blk_softlimit, ARCH_CONVERT))) {
- d->d_bwarns = 0;
- }
- }
-
- if (INT_GET(d->d_ino_softlimit, ARCH_CONVERT) > 0 &&
- (INT_GET(d->d_icount, ARCH_CONVERT) >=
- INT_GET(d->d_ino_softlimit, ARCH_CONVERT))) {
- if (flags & XFS_QMOPT_DOWARN) {
- INT_MOD(d->d_iwarns, ARCH_CONVERT, +1);
- warned++;
- }
- } else {
- if (!d->d_ino_softlimit ||
- (INT_GET(d->d_icount, ARCH_CONVERT) <
- INT_GET(d->d_ino_softlimit, ARCH_CONVERT))) {
- d->d_iwarns = 0;
- }
- }
-#ifdef QUOTADEBUG
- if (INT_GET(d->d_iwarns, ARCH_CONVERT))
- cmn_err(CE_DEBUG,
- "--------@@Inode warnings running : %Lu >= %Lu",
- INT_GET(d->d_icount, ARCH_CONVERT),
- INT_GET(d->d_ino_softlimit, ARCH_CONVERT));
- if (INT_GET(d->d_bwarns, ARCH_CONVERT))
- cmn_err(CE_DEBUG,
- "--------@@Blks warnings running : %Lu >= %Lu",
- INT_GET(d->d_bcount, ARCH_CONVERT),
- INT_GET(d->d_blk_softlimit, ARCH_CONVERT));
-#endif
- return (warned);
-}
-
-
/*
* initialize a buffer full of dquots and log the whole thing
*/
for (i = 0; i < XFS_QM_DQPERBLK(mp); i++, d++, curid++)
xfs_qm_dqinit_core(curid, type, d);
xfs_trans_dquot_buf(tp, bp,
- type & XFS_DQ_USER ?
- XFS_BLI_UDQUOT_BUF :
- XFS_BLI_GDQUOT_BUF);
+ (type & XFS_DQ_USER ? XFS_BLI_UDQUOT_BUF :
+ ((type & XFS_DQ_PROJ) ? XFS_BLI_PDQUOT_BUF :
+ XFS_BLI_GDQUOT_BUF)));
xfs_trans_log_buf(tp, bp, 0, BBTOB(XFS_QI_DQCHUNKLEN(mp)) - 1);
}
* the entire thing.
*/
xfs_qm_init_dquot_blk(tp, mp, INT_GET(dqp->q_core.d_id, ARCH_CONVERT),
- dqp->dq_flags & (XFS_DQ_USER|XFS_DQ_GROUP),
- bp);
+ dqp->dq_flags & XFS_DQ_ALLTYPES, bp);
if ((error = xfs_bmap_finish(&tp, &flist, firstblock, &committed))) {
goto error1;
/*
* A simple sanity check in case we got a corrupted dquot...
*/
- if (xfs_qm_dqcheck(ddq, id,
- dqp->dq_flags & (XFS_DQ_USER|XFS_DQ_GROUP),
+ if (xfs_qm_dqcheck(ddq, id, dqp->dq_flags & XFS_DQ_ALLTYPES,
flags & (XFS_QMOPT_DQREPAIR|XFS_QMOPT_DOWARN),
"dqtobp")) {
if (!(flags & XFS_QMOPT_DQREPAIR)) {
xfs_qm_dqget(
xfs_mount_t *mp,
xfs_inode_t *ip, /* locked inode (optional) */
- xfs_dqid_t id, /* gid or uid, depending on type */
- uint type, /* UDQUOT or GDQUOT */
+ xfs_dqid_t id, /* uid/projid/gid depending on type */
+ uint type, /* XFS_DQ_USER/XFS_DQ_PROJ/XFS_DQ_GROUP */
uint flags, /* DQALLOC, DQSUSER, DQREPAIR, DOWARN */
xfs_dquot_t **O_dqpp) /* OUT : locked incore dquot */
{
ASSERT(XFS_IS_QUOTA_RUNNING(mp));
if ((! XFS_IS_UQUOTA_ON(mp) && type == XFS_DQ_USER) ||
+ (! XFS_IS_PQUOTA_ON(mp) && type == XFS_DQ_PROJ) ||
(! XFS_IS_GQUOTA_ON(mp) && type == XFS_DQ_GROUP)) {
return (ESRCH);
}
again:
#ifdef DEBUG
- ASSERT(type == XFS_DQ_USER || type == XFS_DQ_GROUP);
+ ASSERT(type == XFS_DQ_USER ||
+ type == XFS_DQ_PROJ ||
+ type == XFS_DQ_GROUP);
if (ip) {
ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
if (type == XFS_DQ_USER)
return (error);
}
- if (xfs_qm_dqcheck(&dqp->q_core, INT_GET(ddqp->d_id, ARCH_CONVERT), 0, XFS_QMOPT_DOWARN,
- "dqflush (incore copy)")) {
+ if (xfs_qm_dqcheck(&dqp->q_core, INT_GET(ddqp->d_id, ARCH_CONVERT),
+ 0, XFS_QMOPT_DOWARN, "dqflush (incore copy)")) {
xfs_force_shutdown(dqp->q_mount, XFS_CORRUPT_INCORE);
return XFS_ERROR(EIO);
}
{
if (d1 && d2) {
ASSERT(d1 != d2);
- if (INT_GET(d1->q_core.d_id, ARCH_CONVERT) > INT_GET(d2->q_core.d_id, ARCH_CONVERT)) {
+ if (INT_GET(d1->q_core.d_id, ARCH_CONVERT) >
+ INT_GET(d2->q_core.d_id, ARCH_CONVERT)) {
xfs_dqlock(d2);
xfs_dqlock(d1);
} else {
cmn_err(CE_DEBUG, "-----------KERNEL DQUOT----------------");
cmn_err(CE_DEBUG, "---- dquotID = %d",
(int)INT_GET(dqp->q_core.d_id, ARCH_CONVERT));
- cmn_err(CE_DEBUG, "---- type = %s",
- XFS_QM_ISUDQ(dqp) ? "USR" : "GRP");
+ cmn_err(CE_DEBUG, "---- type = %s", DQFLAGTO_TYPESTR(dqp));
cmn_err(CE_DEBUG, "---- fs = 0x%p", dqp->q_mount);
cmn_err(CE_DEBUG, "---- blkno = 0x%x", (int) dqp->q_blkno);
cmn_err(CE_DEBUG, "---- boffset = 0x%x", (int) dqp->q_bufoffset);
#define XFS_DQHOLD(dqp) ((dqp)->q_nrefs++)
/*
- * Quota Accounting flags
+ * Quota Accounting/Enforcement flags
*/
-#define XFS_ALL_QUOTA_ACCT (XFS_UQUOTA_ACCT | XFS_GQUOTA_ACCT)
-#define XFS_ALL_QUOTA_ENFD (XFS_UQUOTA_ENFD | XFS_GQUOTA_ENFD)
-#define XFS_ALL_QUOTA_CHKD (XFS_UQUOTA_CHKD | XFS_GQUOTA_CHKD)
-#define XFS_ALL_QUOTA_ACTV (XFS_UQUOTA_ACTIVE | XFS_GQUOTA_ACTIVE)
-#define XFS_ALL_QUOTA_ACCT_ENFD (XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\
- XFS_GQUOTA_ACCT|XFS_GQUOTA_ENFD)
+#define XFS_ALL_QUOTA_ACCT \
+ (XFS_UQUOTA_ACCT | XFS_GQUOTA_ACCT | XFS_PQUOTA_ACCT)
+#define XFS_ALL_QUOTA_ENFD (XFS_UQUOTA_ENFD | XFS_OQUOTA_ENFD)
+#define XFS_ALL_QUOTA_CHKD (XFS_UQUOTA_CHKD | XFS_OQUOTA_CHKD)
-#define XFS_IS_QUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_ALL_QUOTA_ACCT)
-#define XFS_IS_UQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_UQUOTA_ACCT)
-#define XFS_IS_GQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_GQUOTA_ACCT)
-
-/*
- * Quota Limit Enforcement flags
- */
+#define XFS_IS_QUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_ALL_QUOTA_ACCT)
#define XFS_IS_QUOTA_ENFORCED(mp) ((mp)->m_qflags & XFS_ALL_QUOTA_ENFD)
-#define XFS_IS_UQUOTA_ENFORCED(mp) ((mp)->m_qflags & XFS_UQUOTA_ENFD)
-#define XFS_IS_GQUOTA_ENFORCED(mp) ((mp)->m_qflags & XFS_GQUOTA_ENFD)
+#define XFS_IS_UQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_UQUOTA_ACCT)
+#define XFS_IS_PQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_PQUOTA_ACCT)
+#define XFS_IS_GQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_GQUOTA_ACCT)
#ifdef DEBUG
static inline int
#define XFS_DQ_IS_ON_FREELIST(dqp) ((dqp)->dq_flnext != (dqp))
#define XFS_DQ_IS_DIRTY(dqp) ((dqp)->dq_flags & XFS_DQ_DIRTY)
#define XFS_QM_ISUDQ(dqp) ((dqp)->dq_flags & XFS_DQ_USER)
+#define XFS_QM_ISPDQ(dqp) ((dqp)->dq_flags & XFS_DQ_PROJ)
+#define XFS_QM_ISGDQ(dqp) ((dqp)->dq_flags & XFS_DQ_GROUP)
#define XFS_DQ_TO_QINF(dqp) ((dqp)->q_mount->m_quotainfo)
#define XFS_DQ_TO_QIP(dqp) (XFS_QM_ISUDQ(dqp) ? \
XFS_DQ_TO_QINF(dqp)->qi_uquotaip : \
#define XFS_IS_THIS_QUOTA_OFF(d) (! (XFS_QM_ISUDQ(d) ? \
(XFS_IS_UQUOTA_ON((d)->q_mount)) : \
- (XFS_IS_GQUOTA_ON((d)->q_mount))))
+ (XFS_IS_OQUOTA_ON((d)->q_mount))))
#ifdef XFS_DQUOT_TRACE
/*
xfs_disk_dquot_t *);
extern void xfs_qm_adjust_dqlimits(xfs_mount_t *,
xfs_disk_dquot_t *);
-extern int xfs_qm_dqwarn(xfs_disk_dquot_t *, uint);
extern int xfs_qm_dqget(xfs_mount_t *, xfs_inode_t *,
xfs_dqid_t, uint, uint, xfs_dquot_t **);
extern void xfs_qm_dqput(xfs_dquot_t *);
/*
* This is the ops vector for dquots
*/
-struct xfs_item_ops xfs_dquot_item_ops = {
+STATIC struct xfs_item_ops xfs_dquot_item_ops = {
.iop_size = (uint(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_size,
.iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*))
xfs_qm_dquot_logitem_format,
return;
}
-struct xfs_item_ops xfs_qm_qoffend_logitem_ops = {
+STATIC struct xfs_item_ops xfs_qm_qoffend_logitem_ops = {
.iop_size = (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_size,
.iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*))
xfs_qm_qoff_logitem_format,
/*
* This is the ops vector shared by all quotaoff-start log items.
*/
-struct xfs_item_ops xfs_qm_qoff_logitem_ops = {
+STATIC struct xfs_item_ops xfs_qm_qoff_logitem_ops = {
.iop_size = (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_size,
.iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*))
xfs_qm_qoff_logitem_format,
kmem_zone_t *qm_dqzone;
kmem_zone_t *qm_dqtrxzone;
-kmem_shaker_t xfs_qm_shaker;
+STATIC kmem_shaker_t xfs_qm_shaker;
STATIC void xfs_qm_list_init(xfs_dqlist_t *, char *, int);
STATIC void xfs_qm_list_destroy(xfs_dqlist_t *);
+STATIC void xfs_qm_freelist_init(xfs_frlist_t *);
+STATIC void xfs_qm_freelist_destroy(xfs_frlist_t *);
+STATIC int xfs_qm_mplist_nowait(xfs_mount_t *);
+STATIC int xfs_qm_dqhashlock_nowait(xfs_dquot_t *);
+
STATIC int xfs_qm_init_quotainos(xfs_mount_t *);
+STATIC int xfs_qm_init_quotainfo(xfs_mount_t *);
STATIC int xfs_qm_shake(int, unsigned int);
#ifdef DEBUG
/*
* Destroy the global quota manager when its reference count goes to zero.
*/
-void
+STATIC void
xfs_qm_destroy(
struct xfs_qm *xqm)
{
uint flags)
{
/*
- * User or group quotas has to be on.
+ * User, projects or group quotas has to be on.
*/
- ASSERT(flags & (XFSMNT_UQUOTA | XFSMNT_GQUOTA));
+ ASSERT(flags & (XFSMNT_UQUOTA | XFSMNT_PQUOTA | XFSMNT_GQUOTA));
/*
* Initialize the flags in the mount structure. From this point
if (flags & XFSMNT_GQUOTA) {
mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE);
if (flags & XFSMNT_GQUOTAENF)
- mp->m_qflags |= XFS_GQUOTA_ENFD;
+ mp->m_qflags |= XFS_OQUOTA_ENFD;
+ } else if (flags & XFSMNT_PQUOTA) {
+ mp->m_qflags |= (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE);
+ if (flags & XFSMNT_PQUOTAENF)
+ mp->m_qflags |= XFS_OQUOTA_ENFD;
}
}
/*
* If a file system had quotas running earlier, but decided to
- * mount without -o quota/uquota/gquota options, revoke the
+ * mount without -o uquota/pquota/gquota options, revoke the
* quotachecked license, and bail out.
*/
if (! XFS_IS_QUOTA_ON(mp) &&
- (mp->m_sb.sb_qflags & (XFS_UQUOTA_ACCT|XFS_GQUOTA_ACCT))) {
+ (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_ACCT)) {
mp->m_qflags = 0;
goto write_changes;
}
* Flush all dquots of the given file system to disk. The dquots are
* _not_ purged from memory here, just their data written to disk.
*/
-int
+STATIC int
xfs_qm_dqflush_all(
xfs_mount_t *mp,
int flags)
STATIC int
xfs_qm_dqpurge_int(
xfs_mount_t *mp,
- uint flags) /* QUOTAOFF/UMOUNTING/UQUOTA/GQUOTA */
+ uint flags) /* QUOTAOFF/UMOUNTING/UQUOTA/PQUOTA/GQUOTA */
{
xfs_dquot_t *dqp;
uint dqtype;
return (0);
dqtype = (flags & XFS_QMOPT_UQUOTA) ? XFS_DQ_USER : 0;
+ dqtype |= (flags & XFS_QMOPT_PQUOTA) ? XFS_DQ_PROJ : 0;
dqtype |= (flags & XFS_QMOPT_GQUOTA) ? XFS_DQ_GROUP : 0;
xfs_qm_mplist_lock(mp);
/*
* udqhint is the i_udquot field in inode, and is non-NULL only
- * when the type arg is XFS_DQ_GROUP. Its purpose is to save a
+ * when the type arg is group/project. Its purpose is to save a
* lookup by dqid (xfs_qm_dqget) by caching a group dquot inside
* the user dquot.
*/
- ASSERT(!udqhint || type == XFS_DQ_GROUP);
+ ASSERT(!udqhint || type == XFS_DQ_GROUP || type == XFS_DQ_PROJ);
if (udqhint && !dolock)
xfs_dqlock(udqhint);
/*
- * Given a locked inode, attach dquot(s) to it, taking UQUOTAON / GQUOTAON
- * in to account.
+ * Given a locked inode, attach dquot(s) to it, taking U/G/P-QUOTAON
+ * into account.
* If XFS_QMOPT_DQALLOC, the dquot(s) will be allocated if needed.
* If XFS_QMOPT_DQLOCK, the dquot(s) will be returned locked. This option pretty
* much made this code a complete mess, but it has been pretty useful.
nquotas++;
}
ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
- if (XFS_IS_GQUOTA_ON(mp)) {
- error = xfs_qm_dqattach_one(ip, ip->i_d.di_gid, XFS_DQ_GROUP,
+ if (XFS_IS_OQUOTA_ON(mp)) {
+ error = XFS_IS_GQUOTA_ON(mp) ?
+ xfs_qm_dqattach_one(ip, ip->i_d.di_gid, XFS_DQ_GROUP,
+ flags & XFS_QMOPT_DQALLOC,
+ flags & XFS_QMOPT_DQLOCK,
+ ip->i_udquot, &ip->i_gdquot) :
+ xfs_qm_dqattach_one(ip, ip->i_d.di_projid, XFS_DQ_PROJ,
flags & XFS_QMOPT_DQALLOC,
flags & XFS_QMOPT_DQLOCK,
ip->i_udquot, &ip->i_gdquot);
}
if (XFS_IS_UQUOTA_ON(mp))
ASSERT(ip->i_udquot);
- if (XFS_IS_GQUOTA_ON(mp))
+ if (XFS_IS_OQUOTA_ON(mp))
ASSERT(ip->i_gdquot);
}
#endif
ASSERT(ip->i_ino != ip->i_mount->m_sb.sb_uquotino);
ASSERT(ip->i_ino != ip->i_mount->m_sb.sb_gquotino);
- if (ip->i_udquot)
- xfs_dqtrace_entry_ino(ip->i_udquot, "DQDETTACH", ip);
if (ip->i_udquot) {
+ xfs_dqtrace_entry_ino(ip->i_udquot, "DQDETTACH", ip);
xfs_qm_dqrele(ip->i_udquot);
ip->i_udquot = NULL;
}
if (ip->i_gdquot) {
+ xfs_dqtrace_entry_ino(ip->i_gdquot, "DQDETTACH", ip);
xfs_qm_dqrele(ip->i_gdquot);
ip->i_gdquot = NULL;
}
* This initializes all the quota information that's kept in the
* mount structure
*/
-int
+STATIC int
xfs_qm_init_quotainfo(
xfs_mount_t *mp)
{
* and group quotas, at least not at this point.
*/
error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)0,
- (XFS_IS_UQUOTA_RUNNING(mp)) ?
- XFS_DQ_USER : XFS_DQ_GROUP,
+ XFS_IS_UQUOTA_RUNNING(mp) ? XFS_DQ_USER :
+ (XFS_IS_GQUOTA_RUNNING(mp) ? XFS_DQ_GROUP :
+ XFS_DQ_PROJ),
XFS_QMOPT_DQSUSER|XFS_QMOPT_DOWARN,
&dqp);
if (! error) {
INT_GET(ddqp->d_iwarns, ARCH_CONVERT) ?
INT_GET(ddqp->d_iwarns, ARCH_CONVERT) :
XFS_QM_IWARNLIMIT;
+ qinf->qi_rtbwarnlimit =
+ INT_GET(ddqp->d_rtbwarns, ARCH_CONVERT) ?
+ INT_GET(ddqp->d_rtbwarns, ARCH_CONVERT) :
+ XFS_QM_RTBWARNLIMIT;
qinf->qi_bhardlimit =
INT_GET(ddqp->d_blk_hardlimit, ARCH_CONVERT);
qinf->qi_bsoftlimit =
qinf->qi_rtbtimelimit = XFS_QM_RTBTIMELIMIT;
qinf->qi_bwarnlimit = XFS_QM_BWARNLIMIT;
qinf->qi_iwarnlimit = XFS_QM_IWARNLIMIT;
+ qinf->qi_rtbwarnlimit = XFS_QM_RTBWARNLIMIT;
}
return (0);
ASSERT(udqp);
}
- if (XFS_IS_GQUOTA_ON(mp)) {
+ if (XFS_IS_OQUOTA_ON(mp)) {
ASSERT(ip->i_gdquot == NULL);
if (udqp)
xfs_dqunlock(udqp);
- if ((error = xfs_qm_dqget(mp, ip, ip->i_d.di_gid, XFS_DQ_GROUP,
- XFS_QMOPT_DQALLOC|XFS_QMOPT_DOWARN,
- &gdqp))) {
+ error = XFS_IS_GQUOTA_ON(mp) ?
+ xfs_qm_dqget(mp, ip,
+ ip->i_d.di_gid, XFS_DQ_GROUP,
+ XFS_QMOPT_DQALLOC|XFS_QMOPT_DOWARN,
+ &gdqp) :
+ xfs_qm_dqget(mp, ip,
+ ip->i_d.di_projid, XFS_DQ_PROJ,
+ XFS_QMOPT_DQALLOC|XFS_QMOPT_DOWARN,
+ &gdqp);
+ if (error) {
if (udqp)
xfs_qm_dqrele(udqp);
ASSERT(error != ESRCH);
INT_SET(ddq->d_rtbcount, ARCH_CONVERT, 0ULL);
INT_SET(ddq->d_btimer, ARCH_CONVERT, (time_t)0);
INT_SET(ddq->d_itimer, ARCH_CONVERT, (time_t)0);
+ INT_SET(ddq->d_rtbtimer, ARCH_CONVERT, (time_t)0);
INT_SET(ddq->d_bwarns, ARCH_CONVERT, 0UL);
INT_SET(ddq->d_iwarns, ARCH_CONVERT, 0UL);
+ INT_SET(ddq->d_rtbwarns, ARCH_CONVERT, 0UL);
ddq = (xfs_disk_dquot_t *) ((xfs_dqblk_t *)ddq + 1);
}
int error;
int notcommitted;
int incr;
+ int type;
ASSERT(blkcnt > 0);
notcommitted = 0;
incr = (blkcnt > XFS_QM_MAX_DQCLUSTER_LOGSZ) ?
XFS_QM_MAX_DQCLUSTER_LOGSZ : blkcnt;
+ type = flags & XFS_QMOPT_UQUOTA ? XFS_DQ_USER :
+ (flags & XFS_QMOPT_PQUOTA ? XFS_DQ_PROJ : XFS_DQ_GROUP);
error = 0;
/*
if (error)
break;
- (void) xfs_qm_reset_dqcounts(mp, bp, firstid,
- flags & XFS_QMOPT_UQUOTA ?
- XFS_DQ_USER : XFS_DQ_GROUP);
+ (void) xfs_qm_reset_dqcounts(mp, bp, firstid, type);
xfs_bdwrite(mp, bp);
/*
* goto the next block.
}
/*
- * Iterate over all allocated USR/GRP dquots in the system, calling a
+ * Iterate over all allocated USR/GRP/PRJ dquots in the system, calling a
* caller supplied function for every chunk of dquots that we find.
*/
STATIC int
xfs_qm_quotacheck_dqadjust(udqp, nblks, rtblks);
xfs_qm_dqput(udqp);
}
- if (XFS_IS_GQUOTA_ON(mp)) {
+ if (XFS_IS_OQUOTA_ON(mp)) {
ASSERT(gdqp);
xfs_qm_quotacheck_dqadjust(gdqp, nblks, rtblks);
xfs_qm_dqput(gdqp);
cmn_err(CE_NOTE, "XFS quotacheck %s: Please wait.", mp->m_fsname);
/*
- * First we go thru all the dquots on disk, USR and GRP, and reset
+ * First we go thru all the dquots on disk, USR and GRP/PRJ, and reset
* their counters to zero. We need a clean slate.
* We don't log our changes till later.
*/
}
if ((gip = XFS_QI_GQIP(mp))) {
- if ((error = xfs_qm_dqiterate(mp, gip, XFS_QMOPT_GQUOTA)))
+ if ((error = xfs_qm_dqiterate(mp, gip, XFS_IS_GQUOTA_ON(mp) ?
+ XFS_QMOPT_GQUOTA : XFS_QMOPT_PQUOTA)))
goto error_return;
- flags |= XFS_GQUOTA_CHKD;
+ flags |= XFS_OQUOTA_CHKD;
}
do {
if (error) {
xfs_qm_dqpurge_all(mp,
XFS_QMOPT_UQUOTA|XFS_QMOPT_GQUOTA|
- XFS_QMOPT_QUOTAOFF);
+ XFS_QMOPT_PQUOTA|XFS_QMOPT_QUOTAOFF);
goto error_return;
}
/*
* quotachecked status, since we won't be doing accounting for
* that type anymore.
*/
- mp->m_qflags &= ~(XFS_GQUOTA_CHKD | XFS_UQUOTA_CHKD);
+ mp->m_qflags &= ~(XFS_OQUOTA_CHKD | XFS_UQUOTA_CHKD);
mp->m_qflags |= flags;
XQM_LIST_PRINT(&(XFS_QI_MPL_LIST(mp)), MPL_NEXT, "++++ Mp list +++");
0, 0, &uip, 0)))
return XFS_ERROR(error);
}
- if (XFS_IS_GQUOTA_ON(mp) &&
+ if (XFS_IS_OQUOTA_ON(mp) &&
mp->m_sb.sb_gquotino != NULLFSINO) {
ASSERT(mp->m_sb.sb_gquotino > 0);
if ((error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino,
flags &= ~XFS_QMOPT_SBVERSION;
}
- if (XFS_IS_GQUOTA_ON(mp) && gip == NULL) {
- if ((error = xfs_qm_qino_alloc(mp, &gip,
- sbflags | XFS_SB_GQUOTINO,
- flags | XFS_QMOPT_GQUOTA))) {
+ if (XFS_IS_OQUOTA_ON(mp) && gip == NULL) {
+ flags |= (XFS_IS_GQUOTA_ON(mp) ?
+ XFS_QMOPT_GQUOTA : XFS_QMOPT_PQUOTA);
+ error = xfs_qm_qino_alloc(mp, &gip,
+ sbflags | XFS_SB_GQUOTINO, flags);
+ if (error) {
if (uip)
VN_RELE(XFS_ITOV(uip));
xfs_inode_t *ip,
uid_t uid,
gid_t gid,
+ prid_t prid,
uint flags,
xfs_dquot_t **O_udqpp,
xfs_dquot_t **O_gdqpp)
}
uq = gq = NULL;
- if ((flags & XFS_QMOPT_UQUOTA) &&
- XFS_IS_UQUOTA_ON(mp)) {
+ if ((flags & XFS_QMOPT_UQUOTA) && XFS_IS_UQUOTA_ON(mp)) {
if (ip->i_d.di_uid != uid) {
/*
* What we need is the dquot that has this uid, and
xfs_dqunlock(uq);
}
}
- if ((flags & XFS_QMOPT_GQUOTA) &&
- XFS_IS_GQUOTA_ON(mp)) {
+ if ((flags & XFS_QMOPT_GQUOTA) && XFS_IS_GQUOTA_ON(mp)) {
if (ip->i_d.di_gid != gid) {
xfs_iunlock(ip, lockflags);
if ((error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)gid,
XFS_DQHOLD(gq);
xfs_dqunlock(gq);
}
+ } else if ((flags & XFS_QMOPT_PQUOTA) && XFS_IS_PQUOTA_ON(mp)) {
+ if (ip->i_d.di_projid != prid) {
+ xfs_iunlock(ip, lockflags);
+ if ((error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)prid,
+ XFS_DQ_PROJ,
+ XFS_QMOPT_DQALLOC |
+ XFS_QMOPT_DOWARN,
+ &gq))) {
+ if (uq)
+ xfs_qm_dqrele(uq);
+ ASSERT(error != ENOENT);
+ return (error);
+ }
+ xfs_dqunlock(gq);
+ lockflags = XFS_ILOCK_SHARED;
+ xfs_ilock(ip, lockflags);
+ } else {
+ ASSERT(ip->i_gdquot);
+ gq = ip->i_gdquot;
+ xfs_dqlock(gq);
+ XFS_DQHOLD(gq);
+ xfs_dqunlock(gq);
+ }
}
if (uq)
xfs_dqtrace_entry_ino(uq, "DQALLOC", ip);
xfs_dquot_t *newdq)
{
xfs_dquot_t *prevdq;
+ uint bfield = XFS_IS_REALTIME_INODE(ip) ?
+ XFS_TRANS_DQ_RTBCOUNT : XFS_TRANS_DQ_BCOUNT;
+
ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
ASSERT(XFS_IS_QUOTA_RUNNING(ip->i_mount));
ASSERT(prevdq);
ASSERT(prevdq != newdq);
- xfs_trans_mod_dquot(tp, prevdq,
- XFS_TRANS_DQ_BCOUNT,
- -(ip->i_d.di_nblocks));
- xfs_trans_mod_dquot(tp, prevdq,
- XFS_TRANS_DQ_ICOUNT,
- -1);
+ xfs_trans_mod_dquot(tp, prevdq, bfield, -(ip->i_d.di_nblocks));
+ xfs_trans_mod_dquot(tp, prevdq, XFS_TRANS_DQ_ICOUNT, -1);
/* the sparkling new dquot */
- xfs_trans_mod_dquot(tp, newdq,
- XFS_TRANS_DQ_BCOUNT,
- ip->i_d.di_nblocks);
- xfs_trans_mod_dquot(tp, newdq,
- XFS_TRANS_DQ_ICOUNT,
- 1);
+ xfs_trans_mod_dquot(tp, newdq, bfield, ip->i_d.di_nblocks);
+ xfs_trans_mod_dquot(tp, newdq, XFS_TRANS_DQ_ICOUNT, 1);
/*
* Take an extra reference, because the inode
}
/*
- * Quota reservations for setattr(AT_UID|AT_GID).
+ * Quota reservations for setattr(AT_UID|AT_GID|AT_PROJID).
*/
int
xfs_qm_vop_chown_reserve(
{
int error;
xfs_mount_t *mp;
- uint delblks;
+ uint delblks, blkflags;
xfs_dquot_t *unresudq, *unresgdq, *delblksudq, *delblksgdq;
ASSERT(XFS_ISLOCKED_INODE(ip));
delblks = ip->i_delayed_blks;
delblksudq = delblksgdq = unresudq = unresgdq = NULL;
+ blkflags = XFS_IS_REALTIME_INODE(ip) ?
+ XFS_QMOPT_RES_RTBLKS : XFS_QMOPT_RES_REGBLKS;
if (XFS_IS_UQUOTA_ON(mp) && udqp &&
ip->i_d.di_uid != (uid_t)INT_GET(udqp->q_core.d_id, ARCH_CONVERT)) {
unresudq = ip->i_udquot;
}
}
- if (XFS_IS_GQUOTA_ON(ip->i_mount) && gdqp &&
- ip->i_d.di_gid != INT_GET(gdqp->q_core.d_id, ARCH_CONVERT)) {
- delblksgdq = gdqp;
- if (delblks) {
- ASSERT(ip->i_gdquot);
- unresgdq = ip->i_gdquot;
+ if (XFS_IS_OQUOTA_ON(ip->i_mount) && gdqp) {
+ if ((XFS_IS_GQUOTA_ON(ip->i_mount) && ip->i_d.di_gid !=
+ INT_GET(gdqp->q_core.d_id, ARCH_CONVERT)) ||
+ (XFS_IS_PQUOTA_ON(ip->i_mount) && ip->i_d.di_projid !=
+ INT_GET(gdqp->q_core.d_id, ARCH_CONVERT))) {
+ delblksgdq = gdqp;
+ if (delblks) {
+ ASSERT(ip->i_gdquot);
+ unresgdq = ip->i_gdquot;
+ }
}
}
if ((error = xfs_trans_reserve_quota_bydquots(tp, ip->i_mount,
delblksudq, delblksgdq, ip->i_d.di_nblocks, 1,
- flags | XFS_QMOPT_RES_REGBLKS)))
+ flags | blkflags)))
return (error);
/*
ASSERT(unresudq || unresgdq);
if ((error = xfs_trans_reserve_quota_bydquots(NULL, ip->i_mount,
delblksudq, delblksgdq, (xfs_qcnt_t)delblks, 0,
- flags | XFS_QMOPT_RES_REGBLKS)))
+ flags | blkflags)))
return (error);
xfs_trans_reserve_quota_bydquots(NULL, ip->i_mount,
unresudq, unresgdq, -((xfs_qcnt_t)delblks), 0,
- XFS_QMOPT_RES_REGBLKS);
+ blkflags);
}
return (0);
}
/* ------------- list stuff -----------------*/
-void
+STATIC void
xfs_qm_freelist_init(xfs_frlist_t *ql)
{
ql->qh_next = ql->qh_prev = (xfs_dquot_t *) ql;
ql->qh_nelems = 0;
}
-void
+STATIC void
xfs_qm_freelist_destroy(xfs_frlist_t *ql)
{
xfs_dquot_t *dqp, *nextdqp;
ASSERT(ql->qh_nelems == 0);
}
-void
+STATIC void
xfs_qm_freelist_insert(xfs_frlist_t *ql, xfs_dquot_t *dq)
{
dq->dq_flnext = ql->qh_next;
xfs_qm_freelist_insert((xfs_frlist_t *)ql->qh_prev, dq);
}
-int
+STATIC int
xfs_qm_dqhashlock_nowait(
xfs_dquot_t *dqp)
{
return (locked);
}
-int
+STATIC int
xfs_qm_mplist_nowait(
xfs_mount_t *mp)
{
/*
- * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved.
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
time_t qi_btimelimit; /* limit for blks timer */
time_t qi_itimelimit; /* limit for inodes timer */
time_t qi_rtbtimelimit;/* limit for rt blks timer */
- xfs_qwarncnt_t qi_bwarnlimit; /* limit for num warnings */
- xfs_qwarncnt_t qi_iwarnlimit; /* limit for num warnings */
+ xfs_qwarncnt_t qi_bwarnlimit; /* limit for blks warnings */
+ xfs_qwarncnt_t qi_iwarnlimit; /* limit for inodes warnings */
+ xfs_qwarncnt_t qi_rtbwarnlimit;/* limit for rt blks warnings */
mutex_t qi_quotaofflock;/* to serialize quotaoff */
xfs_filblks_t qi_dqchunklen; /* # BBs in a chunk of dqs */
uint qi_dqperchunk; /* # ondisk dqs in above chunk */
#define XFS_QM_BWARNLIMIT 5
#define XFS_QM_IWARNLIMIT 5
+#define XFS_QM_RTBWARNLIMIT 5
#define XFS_QM_LOCK(xqm) (mutex_lock(&xqm##_lock, PINOD))
#define XFS_QM_UNLOCK(xqm) (mutex_unlock(&xqm##_lock))
extern void xfs_mount_reset_sbqflags(xfs_mount_t *);
-extern int xfs_qm_init_quotainfo(xfs_mount_t *);
extern void xfs_qm_destroy_quotainfo(xfs_mount_t *);
extern int xfs_qm_mount_quotas(xfs_mount_t *, int);
extern void xfs_qm_mount_quotainit(xfs_mount_t *, uint);
/* vop stuff */
extern int xfs_qm_vop_dqalloc(xfs_mount_t *, xfs_inode_t *,
- uid_t, gid_t, uint,
+ uid_t, gid_t, prid_t, uint,
xfs_dquot_t **, xfs_dquot_t **);
extern void xfs_qm_vop_dqattach_and_dqmod_newinode(
xfs_trans_t *, xfs_inode_t *,
xfs_dquot_t *, xfs_dquot_t *, uint);
/* list stuff */
-extern void xfs_qm_freelist_init(xfs_frlist_t *);
-extern void xfs_qm_freelist_destroy(xfs_frlist_t *);
-extern void xfs_qm_freelist_insert(xfs_frlist_t *, xfs_dquot_t *);
extern void xfs_qm_freelist_append(xfs_frlist_t *, xfs_dquot_t *);
extern void xfs_qm_freelist_unlink(xfs_dquot_t *);
extern int xfs_qm_freelist_lock_nowait(xfs_qm_t *);
-extern int xfs_qm_mplist_nowait(xfs_mount_t *);
-extern int xfs_qm_dqhashlock_nowait(xfs_dquot_t *);
/* system call interface */
extern int xfs_qm_quotactl(bhv_desc_t *, int, int, xfs_caddr_t);
#define MNTOPT_NOQUOTA "noquota" /* no quotas */
#define MNTOPT_USRQUOTA "usrquota" /* user quota enabled */
#define MNTOPT_GRPQUOTA "grpquota" /* group quota enabled */
+#define MNTOPT_PRJQUOTA "prjquota" /* project quota enabled */
#define MNTOPT_UQUOTA "uquota" /* user quota (IRIX variant) */
#define MNTOPT_GQUOTA "gquota" /* group quota (IRIX variant) */
+#define MNTOPT_PQUOTA "pquota" /* project quota (IRIX variant) */
#define MNTOPT_UQUOTANOENF "uqnoenforce"/* user quota limit enforcement */
#define MNTOPT_GQUOTANOENF "gqnoenforce"/* group quota limit enforcement */
+#define MNTOPT_PQUOTANOENF "pqnoenforce"/* project quota limit enforcement */
#define MNTOPT_QUOTANOENF "qnoenforce" /* same as uqnoenforce */
STATIC int
args->flags |= XFSMNT_UQUOTA;
args->flags &= ~XFSMNT_UQUOTAENF;
referenced = 1;
+ } else if (!strcmp(this_char, MNTOPT_PQUOTA) ||
+ !strcmp(this_char, MNTOPT_PRJQUOTA)) {
+ args->flags |= XFSMNT_PQUOTA | XFSMNT_PQUOTAENF;
+ referenced = 1;
+ } else if (!strcmp(this_char, MNTOPT_PQUOTANOENF)) {
+ args->flags |= XFSMNT_PQUOTA;
+ args->flags &= ~XFSMNT_PQUOTAENF;
+ referenced = 1;
} else if (!strcmp(this_char, MNTOPT_GQUOTA) ||
!strcmp(this_char, MNTOPT_GRPQUOTA)) {
args->flags |= XFSMNT_GQUOTA | XFSMNT_GQUOTAENF;
*this_char++ = ',';
}
+ if ((args->flags & XFSMNT_GQUOTA) && (args->flags & XFSMNT_PQUOTA)) {
+ cmn_err(CE_WARN,
+ "XFS: cannot mount with both project and group quota");
+ return XFS_ERROR(EINVAL);
+ }
+
PVFS_PARSEARGS(BHV_NEXT(bhv), options, args, update, error);
if (!error && !referenced)
bhv_remove_vfsops(bhvtovfs(bhv), VFS_POSITION_QM);
seq_puts(m, "," MNTOPT_UQUOTANOENF);
}
+ if (mp->m_qflags & XFS_PQUOTA_ACCT) {
+ (mp->m_qflags & XFS_OQUOTA_ENFD) ?
+ seq_puts(m, "," MNTOPT_PRJQUOTA) :
+ seq_puts(m, "," MNTOPT_PQUOTANOENF);
+ }
+
if (mp->m_qflags & XFS_GQUOTA_ACCT) {
- (mp->m_qflags & XFS_GQUOTA_ENFD) ?
+ (mp->m_qflags & XFS_OQUOTA_ENFD) ?
seq_puts(m, "," MNTOPT_GRPQUOTA) :
seq_puts(m, "," MNTOPT_GQUOTANOENF);
}
- if (!(mp->m_qflags & (XFS_UQUOTA_ACCT|XFS_GQUOTA_ACCT)))
+ if (!(mp->m_qflags & XFS_ALL_QUOTA_ACCT))
seq_puts(m, "," MNTOPT_NOQUOTA);
PVFS_SHOWARGS(BHV_NEXT(bhv), m, error);
struct xfs_mount *mp = XFS_VFSTOM(vfsp);
int error;
- if (args->flags & (XFSMNT_UQUOTA | XFSMNT_GQUOTA))
+ if (args->flags & (XFSMNT_UQUOTA | XFSMNT_GQUOTA | XFSMNT_PQUOTA))
xfs_qm_mount_quotainit(mp, args->flags);
PVFS_MOUNT(BHV_NEXT(bhv), args, cr, error);
return error;
uint *quotaflags)
{
uint quotaondisk;
- uint uquotaondisk = 0, gquotaondisk = 0;
+ uint uquotaondisk = 0, gquotaondisk = 0, pquotaondisk = 0;
*quotaflags = 0;
*needquotamount = B_FALSE;
quotaondisk = XFS_SB_VERSION_HASQUOTA(&mp->m_sb) &&
- mp->m_sb.sb_qflags & (XFS_UQUOTA_ACCT|XFS_GQUOTA_ACCT);
+ (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_ACCT);
if (quotaondisk) {
uquotaondisk = mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT;
+ pquotaondisk = mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT;
gquotaondisk = mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT;
}
if (((uquotaondisk && !XFS_IS_UQUOTA_ON(mp)) ||
(!uquotaondisk && XFS_IS_UQUOTA_ON(mp)) ||
+ (pquotaondisk && !XFS_IS_PQUOTA_ON(mp)) ||
+ (!pquotaondisk && XFS_IS_PQUOTA_ON(mp)) ||
(gquotaondisk && !XFS_IS_GQUOTA_ON(mp)) ||
- (!gquotaondisk && XFS_IS_GQUOTA_ON(mp))) &&
+ (!gquotaondisk && XFS_IS_OQUOTA_ON(mp))) &&
xfs_dev_is_read_only(mp, "changing quota state")) {
cmn_err(CE_WARN,
- "XFS: please mount with%s%s%s.",
+ "XFS: please mount with%s%s%s%s.",
(!quotaondisk ? "out quota" : ""),
(uquotaondisk ? " usrquota" : ""),
+ (pquotaondisk ? " prjquota" : ""),
(gquotaondisk ? " grpquota" : ""));
return XFS_ERROR(EPERM);
}
}
-struct xfs_qmops xfs_qmcore_xfs = {
+STATIC struct xfs_qmops xfs_qmcore_xfs = {
.xfs_qminit = xfs_qm_newmount,
.xfs_qmdone = xfs_qm_unmount_quotadestroy,
.xfs_qmmount = xfs_qm_endmount,
* The following commands are valid even when quotaoff.
*/
switch (cmd) {
+ case Q_XQUOTARM:
/*
- * truncate quota files. quota must be off.
+ * Truncate quota files. quota must be off.
*/
- case Q_XQUOTARM:
if (XFS_IS_QUOTA_ON(mp) || addr == NULL)
return XFS_ERROR(EINVAL);
if (vfsp->vfs_flag & VFS_RDONLY)
return XFS_ERROR(EROFS);
return (xfs_qm_scall_trunc_qfiles(mp,
xfs_qm_import_qtype_flags(*(uint *)addr)));
+
+ case Q_XGETQSTAT:
/*
* Get quota status information.
*/
- case Q_XGETQSTAT:
return (xfs_qm_scall_getqstat(mp, (fs_quota_stat_t *)addr));
+ case Q_XQUOTAON:
/*
- * QUOTAON for root f/s and quota enforcement on others..
- * Quota accounting for non-root f/s's must be turned on
- * at mount time.
+ * QUOTAON - enabling quota enforcement.
+ * Quota accounting must be turned on at mount time.
*/
- case Q_XQUOTAON:
if (addr == NULL)
return XFS_ERROR(EINVAL);
if (vfsp->vfs_flag & VFS_RDONLY)
return XFS_ERROR(EROFS);
return (xfs_qm_scall_quotaon(mp,
xfs_qm_import_flags(*(uint *)addr)));
- case Q_XQUOTAOFF:
+
+ case Q_XQUOTAOFF:
if (vfsp->vfs_flag & VFS_RDONLY)
return XFS_ERROR(EROFS);
break;
- default:
+ default:
break;
}
return XFS_ERROR(ESRCH);
switch (cmd) {
- case Q_XQUOTAOFF:
+ case Q_XQUOTAOFF:
if (vfsp->vfs_flag & VFS_RDONLY)
return XFS_ERROR(EROFS);
error = xfs_qm_scall_quotaoff(mp,
B_FALSE);
break;
- /*
- * Defaults to XFS_GETUQUOTA.
- */
- case Q_XGETQUOTA:
+ case Q_XGETQUOTA:
error = xfs_qm_scall_getquota(mp, (xfs_dqid_t)id, XFS_DQ_USER,
(fs_disk_quota_t *)addr);
break;
- /*
- * Set limits, both hard and soft. Defaults to Q_SETUQLIM.
- */
- case Q_XSETQLIM:
+ case Q_XGETGQUOTA:
+ error = xfs_qm_scall_getquota(mp, (xfs_dqid_t)id, XFS_DQ_GROUP,
+ (fs_disk_quota_t *)addr);
+ break;
+ case Q_XGETPQUOTA:
+ error = xfs_qm_scall_getquota(mp, (xfs_dqid_t)id, XFS_DQ_PROJ,
+ (fs_disk_quota_t *)addr);
+ break;
+
+ case Q_XSETQLIM:
if (vfsp->vfs_flag & VFS_RDONLY)
return XFS_ERROR(EROFS);
error = xfs_qm_scall_setqlim(mp, (xfs_dqid_t)id, XFS_DQ_USER,
(fs_disk_quota_t *)addr);
break;
-
- case Q_XSETGQLIM:
+ case Q_XSETGQLIM:
if (vfsp->vfs_flag & VFS_RDONLY)
return XFS_ERROR(EROFS);
error = xfs_qm_scall_setqlim(mp, (xfs_dqid_t)id, XFS_DQ_GROUP,
(fs_disk_quota_t *)addr);
break;
-
-
- case Q_XGETGQUOTA:
- error = xfs_qm_scall_getquota(mp, (xfs_dqid_t)id, XFS_DQ_GROUP,
- (fs_disk_quota_t *)addr);
+ case Q_XSETPQLIM:
+ if (vfsp->vfs_flag & VFS_RDONLY)
+ return XFS_ERROR(EROFS);
+ error = xfs_qm_scall_setqlim(mp, (xfs_dqid_t)id, XFS_DQ_PROJ,
+ (fs_disk_quota_t *)addr);
break;
- /*
- * Quotas are entirely undefined after quotaoff in XFS quotas.
- * For instance, there's no way to set limits when quotaoff.
- */
-
- default:
+ default:
error = XFS_ERROR(EINVAL);
break;
}
}
if (flags & XFS_GQUOTA_ACCT) {
dqtype |= XFS_QMOPT_GQUOTA;
- flags |= (XFS_GQUOTA_CHKD | XFS_GQUOTA_ENFD);
+ flags |= (XFS_OQUOTA_CHKD | XFS_OQUOTA_ENFD);
inactivate_flags |= XFS_GQUOTA_ACTIVE;
+ } else if (flags & XFS_PQUOTA_ACCT) {
+ dqtype |= XFS_QMOPT_PQUOTA;
+ flags |= (XFS_OQUOTA_CHKD | XFS_OQUOTA_ENFD);
+ inactivate_flags |= XFS_PQUOTA_ACTIVE;
}
/*
/*
* If quotas is completely disabled, close shop.
*/
- if ((flags & XFS_MOUNT_QUOTA_ALL) == XFS_MOUNT_QUOTA_ALL) {
+ if (((flags & XFS_MOUNT_QUOTA_ALL) == XFS_MOUNT_QUOTA_SET1) ||
+ ((flags & XFS_MOUNT_QUOTA_ALL) == XFS_MOUNT_QUOTA_SET2)) {
mutex_unlock(&(XFS_QI_QOFFLOCK(mp)));
xfs_qm_destroy_quotainfo(mp);
return (0);
XFS_PURGE_INODE(XFS_QI_UQIP(mp));
XFS_QI_UQIP(mp) = NULL;
}
- if ((dqtype & XFS_QMOPT_GQUOTA) && XFS_QI_GQIP(mp)) {
+ if ((dqtype & (XFS_QMOPT_GQUOTA|XFS_QMOPT_PQUOTA)) && XFS_QI_GQIP(mp)) {
XFS_PURGE_INODE(XFS_QI_GQIP(mp));
XFS_QI_GQIP(mp) = NULL;
}
}
}
- if ((flags & XFS_DQ_GROUP) && mp->m_sb.sb_gquotino != NULLFSINO) {
+ if ((flags & (XFS_DQ_GROUP|XFS_DQ_PROJ)) &&
+ mp->m_sb.sb_gquotino != NULLFSINO) {
error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, 0, 0, &qip, 0);
if (! error) {
(void) xfs_truncate_file(mp, qip);
uint flags)
{
int error;
- unsigned long s;
+ unsigned long s;
uint qf;
uint accflags;
__int64_t sbflags;
(mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) == 0 &&
(flags & XFS_UQUOTA_ENFD))
||
+ ((flags & XFS_PQUOTA_ACCT) == 0 &&
+ (mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT) == 0 &&
+ (flags & XFS_OQUOTA_ENFD))
+ ||
((flags & XFS_GQUOTA_ACCT) == 0 &&
(mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) == 0 &&
- (flags & XFS_GQUOTA_ENFD))) {
+ (flags & XFS_OQUOTA_ENFD))) {
qdprintk("Can't enforce without acct, flags=%x sbflags=%x\n",
flags, mp->m_sb.sb_qflags);
return XFS_ERROR(EINVAL);
*/
if (((mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) !=
(mp->m_qflags & XFS_UQUOTA_ACCT)) ||
+ ((mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT) !=
+ (mp->m_qflags & XFS_PQUOTA_ACCT)) ||
+ ((mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) !=
+ (mp->m_qflags & XFS_GQUOTA_ACCT)) ||
(flags & XFS_ALL_QUOTA_ENFD) == 0)
return (0);
}
-
/*
* Return quota status information, such as uquota-off, enforcements, etc.
*/
if (!capable(CAP_SYS_ADMIN))
return XFS_ERROR(EPERM);
- if ((newlim->d_fieldmask & (FS_DQ_LIMIT_MASK|FS_DQ_TIMER_MASK)) == 0)
+ if ((newlim->d_fieldmask &
+ (FS_DQ_LIMIT_MASK|FS_DQ_TIMER_MASK|FS_DQ_WARNS_MASK)) == 0)
return (0);
tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SETQLIM);
qdprintk("ihard %Ld < isoft %Ld\n", hard, soft);
}
+ /*
+ * Update warnings counter(s) if requested
+ */
+ if (newlim->d_fieldmask & FS_DQ_BWARNS)
+ INT_SET(ddq->d_bwarns, ARCH_CONVERT, newlim->d_bwarns);
+ if (newlim->d_fieldmask & FS_DQ_IWARNS)
+ INT_SET(ddq->d_iwarns, ARCH_CONVERT, newlim->d_iwarns);
+ if (newlim->d_fieldmask & FS_DQ_RTBWARNS)
+ INT_SET(ddq->d_rtbwarns, ARCH_CONVERT, newlim->d_rtbwarns);
+
if (id == 0) {
/*
* Timelimits for the super user set the relative time
* the other users can be over quota for this file system.
* If it is zero a default is used. Ditto for the default
- * soft and hard limit values (already done, above).
+ * soft and hard limit values (already done, above), and
+ * for warnings.
*/
if (newlim->d_fieldmask & FS_DQ_BTIMER) {
mp->m_quotainfo->qi_btimelimit = newlim->d_btimer;
mp->m_quotainfo->qi_rtbtimelimit = newlim->d_rtbtimer;
INT_SET(ddq->d_rtbtimer, ARCH_CONVERT, newlim->d_rtbtimer);
}
- } else /* if (XFS_IS_QUOTA_ENFORCED(mp)) */ {
+ if (newlim->d_fieldmask & FS_DQ_BWARNS)
+ mp->m_quotainfo->qi_bwarnlimit = newlim->d_bwarns;
+ if (newlim->d_fieldmask & FS_DQ_IWARNS)
+ mp->m_quotainfo->qi_iwarnlimit = newlim->d_iwarns;
+ if (newlim->d_fieldmask & FS_DQ_RTBWARNS)
+ mp->m_quotainfo->qi_rtbwarnlimit = newlim->d_rtbwarns;
+ } else {
/*
* If the user is now over quota, start the timelimit.
* The user will not be 'warned'.
xfs_qoff_logitem_t *startqoff,
uint flags)
{
- xfs_trans_t *tp;
+ xfs_trans_t *tp;
int error;
- xfs_qoff_logitem_t *qoffi;
+ xfs_qoff_logitem_t *qoffi;
tp = xfs_trans_alloc(mp, XFS_TRANS_QM_QUOTAOFF_END);
STATIC uint
xfs_qm_import_qtype_flags(
- uint uflags)
+ uint uflags)
{
+ uint oflags = 0;
+
/*
- * Can't be both at the same time.
+ * Can't be more than one, or none.
*/
if (((uflags & (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) ==
- (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) ||
- ((uflags & (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) == 0))
+ (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) ||
+ ((uflags & (XFS_GROUP_QUOTA | XFS_PROJ_QUOTA)) ==
+ (XFS_GROUP_QUOTA | XFS_PROJ_QUOTA)) ||
+ ((uflags & (XFS_USER_QUOTA | XFS_PROJ_QUOTA)) ==
+ (XFS_USER_QUOTA | XFS_PROJ_QUOTA)) ||
+ ((uflags & (XFS_GROUP_QUOTA|XFS_USER_QUOTA|XFS_PROJ_QUOTA)) == 0))
return (0);
- return (uflags & XFS_USER_QUOTA) ?
- XFS_DQ_USER : XFS_DQ_GROUP;
+ oflags |= (uflags & XFS_USER_QUOTA) ? XFS_DQ_USER : 0;
+ oflags |= (uflags & XFS_PROJ_QUOTA) ? XFS_DQ_PROJ : 0;
+ oflags |= (uflags & XFS_GROUP_QUOTA) ? XFS_DQ_GROUP: 0;
+ return oflags;
}
STATIC uint
uint flags)
{
/*
- * Can't be both at the same time.
+ * Can't be more than one, or none.
*/
- ASSERT((flags & (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) !=
- (XFS_GROUP_QUOTA | XFS_USER_QUOTA));
- ASSERT((flags & (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) != 0);
+ ASSERT((flags & (XFS_PROJ_QUOTA | XFS_USER_QUOTA)) !=
+ (XFS_PROJ_QUOTA | XFS_USER_QUOTA));
+ ASSERT((flags & (XFS_PROJ_QUOTA | XFS_GROUP_QUOTA)) !=
+ (XFS_PROJ_QUOTA | XFS_GROUP_QUOTA));
+ ASSERT((flags & (XFS_USER_QUOTA | XFS_GROUP_QUOTA)) !=
+ (XFS_USER_QUOTA | XFS_GROUP_QUOTA));
+ ASSERT((flags & (XFS_PROJ_QUOTA|XFS_USER_QUOTA|XFS_GROUP_QUOTA)) != 0);
return (flags & XFS_DQ_USER) ?
- XFS_USER_QUOTA : XFS_GROUP_QUOTA;
+ XFS_USER_QUOTA : (flags & XFS_DQ_PROJ) ?
+ XFS_PROJ_QUOTA : XFS_GROUP_QUOTA;
}
STATIC uint
if (uflags & XFS_QUOTA_UDQ_ACCT)
flags |= XFS_UQUOTA_ACCT;
+ if (uflags & XFS_QUOTA_PDQ_ACCT)
+ flags |= XFS_PQUOTA_ACCT;
if (uflags & XFS_QUOTA_GDQ_ACCT)
flags |= XFS_GQUOTA_ACCT;
if (uflags & XFS_QUOTA_UDQ_ENFD)
flags |= XFS_UQUOTA_ENFD;
- if (uflags & XFS_QUOTA_GDQ_ENFD)
- flags |= XFS_GQUOTA_ENFD;
+ if (uflags & (XFS_QUOTA_PDQ_ENFD|XFS_QUOTA_GDQ_ENFD))
+ flags |= XFS_OQUOTA_ENFD;
return (flags);
}
uflags = 0;
if (flags & XFS_UQUOTA_ACCT)
uflags |= XFS_QUOTA_UDQ_ACCT;
+ if (flags & XFS_PQUOTA_ACCT)
+ uflags |= XFS_QUOTA_PDQ_ACCT;
if (flags & XFS_GQUOTA_ACCT)
uflags |= XFS_QUOTA_GDQ_ACCT;
if (flags & XFS_UQUOTA_ENFD)
uflags |= XFS_QUOTA_UDQ_ENFD;
- if (flags & XFS_GQUOTA_ENFD)
- uflags |= XFS_QUOTA_GDQ_ENFD;
+ if (flags & (XFS_OQUOTA_ENFD)) {
+ uflags |= (flags & XFS_GQUOTA_ACCT) ?
+ XFS_QUOTA_GDQ_ENFD : XFS_QUOTA_PDQ_ENFD;
+ }
return (uflags);
}
xfs_qm_dqrele(ip->i_udquot);
ip->i_udquot = NULL;
}
- if ((flags & XFS_GQUOTA_ACCT) && ip->i_gdquot) {
+ if (flags & (XFS_PQUOTA_ACCT|XFS_GQUOTA_ACCT) && ip->i_gdquot) {
xfs_qm_dqrele(ip->i_gdquot);
ip->i_gdquot = NULL;
}
{
cmn_err(CE_DEBUG, "-----------DQTEST DQUOT----------------");
cmn_err(CE_DEBUG, "---- dquot ID = %d", d->d_id);
- cmn_err(CE_DEBUG, "---- type = %s", XFS_QM_ISUDQ(d)? "USR" : "GRP");
cmn_err(CE_DEBUG, "---- fs = 0x%p", d->q_mount);
cmn_err(CE_DEBUG, "---- bcount = %Lu (0x%x)",
d->d_bcount, (int)d->d_bcount);
#ifdef QUOTADEBUG
if (!err) {
cmn_err(CE_DEBUG, "%d [%s] [0x%p] qchecked",
- d->d_id, XFS_QM_ISUDQ(d) ? "USR" : "GRP", d->q_mount);
+ d->d_id, DQFLAGTO_TYPESTR(d), d->q_mount);
}
#endif
return (err);
xfs_qm_internalqcheck_get_dquots(
xfs_mount_t *mp,
xfs_dqid_t uid,
+ xfs_dqid_t projid,
xfs_dqid_t gid,
xfs_dqtest_t **ud,
xfs_dqtest_t **gd)
xfs_qm_internalqcheck_dqget(mp, uid, XFS_DQ_USER, ud);
if (XFS_IS_GQUOTA_ON(mp))
xfs_qm_internalqcheck_dqget(mp, gid, XFS_DQ_GROUP, gd);
+ else if (XFS_IS_PQUOTA_ON(mp))
+ xfs_qm_internalqcheck_dqget(mp, projid, XFS_DQ_PROJ, gd);
}
}
xfs_qm_internalqcheck_get_dquots(mp,
(xfs_dqid_t) ip->i_d.di_uid,
+ (xfs_dqid_t) ip->i_d.di_projid,
(xfs_dqid_t) ip->i_d.di_gid,
&ud, &gd);
if (XFS_IS_UQUOTA_ON(mp)) {
ASSERT(ud);
xfs_qm_internalqcheck_dqadjust(ip, ud);
}
- if (XFS_IS_GQUOTA_ON(mp)) {
+ if (XFS_IS_OQUOTA_ON(mp)) {
ASSERT(gd);
xfs_qm_internalqcheck_dqadjust(ip, gd);
}
#define XFS_QI_RTBTIMELIMIT(mp) ((mp)->m_quotainfo->qi_rtbtimelimit)
#define XFS_QI_ITIMELIMIT(mp) ((mp)->m_quotainfo->qi_itimelimit)
#define XFS_QI_BWARNLIMIT(mp) ((mp)->m_quotainfo->qi_bwarnlimit)
+#define XFS_QI_RTBWARNLIMIT(mp) ((mp)->m_quotainfo->qi_rtbwarnlimit)
#define XFS_QI_IWARNLIMIT(mp) ((mp)->m_quotainfo->qi_iwarnlimit)
#define XFS_QI_QOFFLOCK(mp) ((mp)->m_quotainfo->qi_quotaofflock)
(xfs_Gqm->qm_grp_dqhtable + \
XFS_DQ_HASHVAL(mp, id)))
#define XFS_IS_DQTYPE_ON(mp, type) (type == XFS_DQ_USER ? \
- XFS_IS_UQUOTA_ON(mp):XFS_IS_GQUOTA_ON(mp))
+ XFS_IS_UQUOTA_ON(mp) : \
+ XFS_IS_OQUOTA_ON(mp))
#define XFS_IS_DQUOT_UNINITIALIZED(dqp) ( \
!dqp->q_core.d_blk_hardlimit && \
!dqp->q_core.d_blk_softlimit && \
(!((dqp)->q_core.d_id))
#define XFS_PURGE_INODE(ip) \
- { \
- vmap_t dqvmap; \
- vnode_t *dqvp; \
- dqvp = XFS_ITOV(ip); \
- VMAP(dqvp, dqvmap); \
- VN_RELE(dqvp); \
- }
+ IRELE(ip);
#define DQFLAGTO_TYPESTR(d) (((d)->dq_flags & XFS_DQ_USER) ? "USR" : \
- (((d)->dq_flags & XFS_DQ_GROUP) ? "GRP" : "???"))
+ (((d)->dq_flags & XFS_DQ_GROUP) ? "GRP" : \
+ (((d)->dq_flags & XFS_DQ_PROJ) ? "PRJ":"???")))
#define DQFLAGTO_DIRTYSTR(d) (XFS_DQ_IS_DIRTY(d) ? "DIRTY" : "NOTDIRTY")
#endif /* __XFS_QUOTA_PRIV_H__ */
/*
* Wrap around mod_dquot to account for both user and group quotas.
*/
-void
+STATIC void
xfs_trans_mod_dquot_byino(
xfs_trans_t *tp,
xfs_inode_t *ip,
if (tp->t_dqinfo == NULL)
xfs_trans_alloc_dqinfo(tp);
- if (XFS_IS_UQUOTA_ON(mp) && ip->i_udquot) {
+ if (XFS_IS_UQUOTA_ON(mp) && ip->i_udquot)
(void) xfs_trans_mod_dquot(tp, ip->i_udquot, field, delta);
- }
- if (XFS_IS_GQUOTA_ON(mp) && ip->i_gdquot) {
+ if (XFS_IS_OQUOTA_ON(mp) && ip->i_gdquot)
(void) xfs_trans_mod_dquot(tp, ip->i_gdquot, field, delta);
- }
}
STATIC xfs_dqtrx_t *
* Unreserve just the reservations done by this transaction.
* dquot is still left locked at exit.
*/
-void
+STATIC void
xfs_trans_apply_dquot_deltas(
xfs_trans_t *tp)
{
* Adjust the RT reservation.
*/
if (qtrx->qt_rtblk_res != 0) {
- if (qtrx->qt_blk_res != qtrx->qt_blk_res_used) {
+ if (qtrx->qt_rtblk_res != qtrx->qt_rtblk_res_used) {
if (qtrx->qt_rtblk_res >
qtrx->qt_rtblk_res_used)
dqp->q_res_rtbcount -= (xfs_qcnt_t)
(xfs_qcnt_t)qtrx->qt_icount_delta;
}
-
-#ifdef QUOTADEBUG
- if (qtrx->qt_rtblk_res != 0)
- cmn_err(CE_DEBUG, "RT res %d for 0x%p\n",
- (int) qtrx->qt_rtblk_res, dqp);
-#endif
ASSERT(dqp->q_res_bcount >=
INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT));
ASSERT(dqp->q_res_icount >=
int error;
xfs_qcnt_t hardlimit;
xfs_qcnt_t softlimit;
- time_t btimer;
+ time_t timer;
+ xfs_qwarncnt_t warns;
+ xfs_qwarncnt_t warnlimit;
+ xfs_qcnt_t count;
xfs_qcnt_t *resbcountp;
xfs_quotainfo_t *q = mp->m_quotainfo;
softlimit = INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT);
if (!softlimit)
softlimit = q->qi_bsoftlimit;
- btimer = INT_GET(dqp->q_core.d_btimer, ARCH_CONVERT);
+ timer = INT_GET(dqp->q_core.d_btimer, ARCH_CONVERT);
+ warns = INT_GET(dqp->q_core.d_bwarns, ARCH_CONVERT);
+ warnlimit = XFS_QI_BWARNLIMIT(dqp->q_mount);
resbcountp = &dqp->q_res_bcount;
} else {
ASSERT(flags & XFS_TRANS_DQ_RES_RTBLKS);
softlimit = INT_GET(dqp->q_core.d_rtb_softlimit, ARCH_CONVERT);
if (!softlimit)
softlimit = q->qi_rtbsoftlimit;
- btimer = INT_GET(dqp->q_core.d_rtbtimer, ARCH_CONVERT);
+ timer = INT_GET(dqp->q_core.d_rtbtimer, ARCH_CONVERT);
+ warns = INT_GET(dqp->q_core.d_rtbwarns, ARCH_CONVERT);
+ warnlimit = XFS_QI_RTBWARNLIMIT(dqp->q_mount);
resbcountp = &dqp->q_res_rtbcount;
}
error = 0;
* If timer or warnings has expired,
* return EDQUOT
*/
- if ((btimer != 0 && get_seconds() > btimer) ||
- (dqp->q_core.d_bwarns &&
- INT_GET(dqp->q_core.d_bwarns, ARCH_CONVERT) >=
- XFS_QI_BWARNLIMIT(dqp->q_mount))) {
+ if ((timer != 0 && get_seconds() > timer) ||
+ (warns != 0 && warns >= warnlimit)) {
error = EDQUOT;
goto error_return;
}
}
}
if (ninos > 0) {
- hardlimit = INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT);
+ count = INT_GET(dqp->q_core.d_icount, ARCH_CONVERT);
+ timer = INT_GET(dqp->q_core.d_itimer, ARCH_CONVERT);
+ warns = INT_GET(dqp->q_core.d_iwarns, ARCH_CONVERT);
+ warnlimit = XFS_QI_IWARNLIMIT(dqp->q_mount);
+ hardlimit = INT_GET(dqp->q_core.d_ino_hardlimit,
+ ARCH_CONVERT);
if (!hardlimit)
hardlimit = q->qi_ihardlimit;
- softlimit = INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT);
+ softlimit = INT_GET(dqp->q_core.d_ino_softlimit,
+ ARCH_CONVERT);
if (!softlimit)
softlimit = q->qi_isoftlimit;
- if (hardlimit > 0ULL &&
- INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) >= hardlimit) {
+ if (hardlimit > 0ULL && count >= hardlimit) {
error = EDQUOT;
goto error_return;
- } else if (softlimit > 0ULL &&
- INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) >= softlimit) {
+ } else if (softlimit > 0ULL && count >= softlimit) {
/*
* If timer or warnings has expired,
* return EDQUOT
*/
- if ((dqp->q_core.d_itimer &&
- get_seconds() > INT_GET(dqp->q_core.d_itimer, ARCH_CONVERT)) ||
- (dqp->q_core.d_iwarns &&
- INT_GET(dqp->q_core.d_iwarns, ARCH_CONVERT) >=
- XFS_QI_IWARNLIMIT(dqp->q_mount))) {
+ if ((timer != 0 && get_seconds() > timer) ||
+ (warns != 0 && warns >= warnlimit)) {
error = EDQUOT;
goto error_return;
}
#include <linux/sched.h>
#include <linux/kernel.h>
-int doass = 1;
static char message[256]; /* keep it off the stack */
static DEFINE_SPINLOCK(xfs_err_lock);
#endif
#ifdef DEBUG
-# ifdef lint
-# define ASSERT(EX) ((void)0) /* avoid "constant in conditional" babble */
-# else
-# define ASSERT(EX) ((!doass||(EX))?((void)0):assfail(#EX, __FILE__, __LINE__))
-# endif /* lint */
+# define ASSERT(EX) ((EX) ? ((void)0) : assfail(#EX, __FILE__, __LINE__))
#else
# define ASSERT(x) ((void)0)
#endif
-extern int doass; /* dynamically turn off asserts */
extern void assfail(char *, char *, int);
#ifdef DEBUG
extern unsigned long random(void);
#define XFSA_FIXUP_BNO_OK 1
#define XFSA_FIXUP_CNT_OK 2
-int
+STATIC int
xfs_alloc_search_busy(xfs_trans_t *tp,
xfs_agnumber_t agno,
xfs_agblock_t bno,
/*
* returns non-zero if any of (agno,bno):len is in a busy list
*/
-int
+STATIC int
xfs_alloc_search_busy(xfs_trans_t *tp,
xfs_agnumber_t agno,
xfs_agblock_t bno,
* Provide the external interfaces to manage attribute lists.
*/
+#define ATTR_SYSCOUNT 2
+STATIC struct attrnames posix_acl_access;
+STATIC struct attrnames posix_acl_default;
+STATIC struct attrnames *attr_system_names[ATTR_SYSCOUNT];
+
/*========================================================================
* Function prototypes for the kernel.
*========================================================================*/
/*
* Internal routines when attribute list is one block.
*/
+STATIC int xfs_attr_leaf_get(xfs_da_args_t *args);
STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args);
STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
STATIC int xfs_attr_leaf_list(xfs_attr_list_context_t *context);
/*
* Internal routines when attribute list is more than one block.
*/
+STATIC int xfs_attr_node_get(xfs_da_args_t *args);
STATIC int xfs_attr_node_addname(xfs_da_args_t *args);
STATIC int xfs_attr_node_removename(xfs_da_args_t *args);
STATIC int xfs_attr_node_list(xfs_attr_list_context_t *context);
* This leaf block cannot have a "remote" value, we only call this routine
* if bmap_one_block() says there is only one block (ie: no remote blks).
*/
-int
+STATIC int
xfs_attr_leaf_get(xfs_da_args_t *args)
{
xfs_dabuf_t *bp;
* block, ie: both true Btree attr lists and for single-leaf-blocks with
* "remote" values taking up more blocks.
*/
-int
+STATIC int
xfs_attr_node_get(xfs_da_args_t *args)
{
xfs_da_state_t *state;
return xfs_acl_vhasacl_default(vp);
}
-struct attrnames posix_acl_access = {
+STATIC struct attrnames posix_acl_access = {
.attr_name = "posix_acl_access",
.attr_namelen = sizeof("posix_acl_access") - 1,
.attr_get = posix_acl_access_get,
.attr_exists = posix_acl_access_exists,
};
-struct attrnames posix_acl_default = {
+STATIC struct attrnames posix_acl_default = {
.attr_name = "posix_acl_default",
.attr_namelen = sizeof("posix_acl_default") - 1,
.attr_get = posix_acl_default_get,
.attr_exists = posix_acl_default_exists,
};
-struct attrnames *attr_system_names[] =
+STATIC struct attrnames *attr_system_names[] =
{ &posix_acl_access, &posix_acl_default };
extern struct attrnames attr_trusted;
extern struct attrnames *attr_namespaces[ATTR_NAMECOUNT];
-#define ATTR_SYSCOUNT 2
-extern struct attrnames posix_acl_access;
-extern struct attrnames posix_acl_default;
-extern struct attrnames *attr_system_names[ATTR_SYSCOUNT];
-
extern attrnames_t *attr_lookup_namespace(char *, attrnames_t **, int);
extern int attr_generic_list(struct vnode *, void *, size_t, int, ssize_t *);
struct attrlist_cursor_kern *, struct cred *);
int xfs_attr_inactive(struct xfs_inode *dp);
-int xfs_attr_node_get(struct xfs_da_args *);
-int xfs_attr_leaf_get(struct xfs_da_args *);
int xfs_attr_shortform_getvalue(struct xfs_da_args *);
int xfs_attr_fetch(struct xfs_inode *, char *, int,
char *, int *, int, struct cred *);
/*
* Routines used for growing the Btree.
*/
+STATIC int xfs_attr_leaf_create(xfs_da_args_t *args, xfs_dablk_t which_block,
+ xfs_dabuf_t **bpp);
STATIC int xfs_attr_leaf_add_work(xfs_dabuf_t *leaf_buffer, xfs_da_args_t *args,
int freemap_index);
STATIC void xfs_attr_leaf_compact(xfs_trans_t *trans, xfs_dabuf_t *leaf_buffer);
int *number_entries_in_blk1,
int *number_usedbytes_in_blk1);
+/*
+ * Routines used for shrinking the Btree.
+ */
+STATIC int xfs_attr_node_inactive(xfs_trans_t **trans, xfs_inode_t *dp,
+ xfs_dabuf_t *bp, int level);
+STATIC int xfs_attr_leaf_inactive(xfs_trans_t **trans, xfs_inode_t *dp,
+ xfs_dabuf_t *bp);
+STATIC int xfs_attr_leaf_freextent(xfs_trans_t **trans, xfs_inode_t *dp,
+ xfs_dablk_t blkno, int blkcnt);
+
/*
* Utility routines.
*/
xfs_attr_leafblock_t *dst_leaf,
int dst_start, int move_count,
xfs_mount_t *mp);
+STATIC int xfs_attr_leaf_entsize(xfs_attr_leafblock_t *leaf, int index);
+STATIC int xfs_attr_put_listent(xfs_attr_list_context_t *context,
+ attrnames_t *, char *name, int namelen,
+ int valuelen);
/*========================================================================
* Create the initial contents of a leaf attribute list
* or a leaf in a node attribute list.
*/
-int
+STATIC int
xfs_attr_leaf_create(xfs_da_args_t *args, xfs_dablk_t blkno, xfs_dabuf_t **bpp)
{
xfs_attr_leafblock_t *leaf;
* Calculate the number of bytes used to store the indicated attribute
* (whether local or remote only calculate bytes in this block).
*/
-int
+STATIC int
xfs_attr_leaf_entsize(xfs_attr_leafblock_t *leaf, int index)
{
xfs_attr_leaf_name_local_t *name_loc;
* we may be reading them directly out of a user buffer.
*/
/*ARGSUSED*/
-int
+STATIC int
xfs_attr_put_listent(xfs_attr_list_context_t *context,
attrnames_t *namesp, char *name, int namelen, int valuelen)
{
* Recurse (gasp!) through the attribute nodes until we find leaves.
* We're doing a depth-first traversal in order to invalidate everything.
*/
-int
+STATIC int
xfs_attr_node_inactive(xfs_trans_t **trans, xfs_inode_t *dp, xfs_dabuf_t *bp,
int level)
{
* Note that we must release the lock on the buffer so that we are not
* caught holding something that the logging code wants to flush to disk.
*/
-int
+STATIC int
xfs_attr_leaf_inactive(xfs_trans_t **trans, xfs_inode_t *dp, xfs_dabuf_t *bp)
{
xfs_attr_leafblock_t *leaf;
* Look at all the extents for this logical region,
* invalidate any buffers that are incore/in transactions.
*/
-int
+STATIC int
xfs_attr_leaf_freextent(xfs_trans_t **trans, xfs_inode_t *dp,
xfs_dablk_t blkno, int blkcnt)
{
/*
* Routines used for growing the Btree.
*/
-int xfs_attr_leaf_create(struct xfs_da_args *args, xfs_dablk_t which_block,
- struct xfs_dabuf **bpp);
int xfs_attr_leaf_split(struct xfs_da_state *state,
struct xfs_da_state_blk *oldblk,
struct xfs_da_state_blk *newblk);
struct xfs_da_state_blk *drop_blk,
struct xfs_da_state_blk *save_blk);
int xfs_attr_root_inactive(struct xfs_trans **trans, struct xfs_inode *dp);
-int xfs_attr_node_inactive(struct xfs_trans **trans, struct xfs_inode *dp,
- struct xfs_dabuf *bp, int level);
-int xfs_attr_leaf_inactive(struct xfs_trans **trans, struct xfs_inode *dp,
- struct xfs_dabuf *bp);
-int xfs_attr_leaf_freextent(struct xfs_trans **trans, struct xfs_inode *dp,
- xfs_dablk_t blkno, int blkcnt);
/*
* Utility routines.
struct xfs_dabuf *leaf2_bp);
int xfs_attr_leaf_newentsize(struct xfs_da_args *args, int blocksize,
int *local);
-int xfs_attr_leaf_entsize(struct xfs_attr_leafblock *leaf, int index);
-int xfs_attr_put_listent(struct xfs_attr_list_context *context,
- struct attrnames *, char *name, int namelen,
- int valuelen);
int xfs_attr_rolltrans(struct xfs_trans **transp, struct xfs_inode *dp);
#endif /* __XFS_ATTR_LEAF_H__ */
/*
* Index of high bit number in byte, -1 for none set, 0..7 otherwise.
*/
-const char xfs_highbit[256] = {
+STATIC const char xfs_highbit[256] = {
-1, 0, 1, 1, 2, 2, 2, 2, /* 00 .. 07 */
3, 3, 3, 3, 3, 3, 3, 3, /* 08 .. 0f */
4, 4, 4, 4, 4, 4, 4, 4, /* 10 .. 17 */
xfs_bmbt_irec_t *gotp, /* out: extent entry found */
xfs_bmbt_irec_t *prevp); /* out: previous extent entry found */
+/*
+ * Check the last inode extent to determine whether this allocation will result
+ * in blocks being allocated at the end of the file. When we allocate new data
+ * blocks at the end of the file which do not start at the previous data block,
+ * we will try to align the new blocks at stripe unit boundaries.
+ */
+STATIC int /* error */
+xfs_bmap_isaeof(
+ xfs_inode_t *ip, /* incore inode pointer */
+ xfs_fileoff_t off, /* file offset in fsblocks */
+ int whichfork, /* data or attribute fork */
+ char *aeof); /* return value */
+
#ifdef XFS_BMAP_TRACE
/*
* Add a bmap trace buffer entry. Base routine for the others.
xfs_extlen_t alen; /* allocated extent length */
xfs_fileoff_t aoff; /* allocated file offset */
xfs_bmalloca_t bma; /* args for xfs_bmap_alloc */
- char contig; /* allocation must be one extent */
xfs_btree_cur_t *cur; /* bmap btree cursor */
- char delay; /* this request is for delayed alloc */
xfs_fileoff_t end; /* end of mapped file region */
int eof; /* we've hit the end of extent list */
+ char contig; /* allocation must be one extent */
+ char delay; /* this request is for delayed alloc */
+ char exact; /* don't do all of wasdelayed extent */
xfs_bmbt_rec_t *ep; /* extent list entry pointer */
int error; /* error return */
- char exact; /* don't do all of wasdelayed extent */
xfs_bmbt_irec_t got; /* current extent list record */
xfs_ifork_t *ifp; /* inode fork pointer */
xfs_extlen_t indlen; /* indirect blocks length */
- char inhole; /* current location is hole in file */
xfs_extnum_t lastx; /* last useful extent number */
int logflags; /* flags for transaction logging */
xfs_extlen_t minleft; /* min blocks left after allocation */
xfs_extnum_t nextents; /* number of extents in file */
xfs_fileoff_t obno; /* old block number (offset) */
xfs_bmbt_irec_t prev; /* previous extent list record */
- char stateless; /* ignore state flag set */
int tmp_logflags; /* temp flags holder */
+ int whichfork; /* data or attr fork */
+ char inhole; /* current location is hole in file */
+ char stateless; /* ignore state flag set */
char trim; /* output trimmed to match range */
char userdata; /* allocating non-metadata */
char wasdelay; /* old extent was delayed */
- int whichfork; /* data or attr fork */
char wr; /* this is a write request */
+ char rt; /* this is a realtime file */
char rsvd; /* OK to allocate reserved blocks */
#ifdef DEBUG
xfs_fileoff_t orig_bno; /* original block number value */
}
if (XFS_FORCED_SHUTDOWN(mp))
return XFS_ERROR(EIO);
+ rt = XFS_IS_REALTIME_INODE(ip);
ifp = XFS_IFORK_PTR(ip, whichfork);
ASSERT(ifp->if_ext_max ==
XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t));
}
minlen = contig ? alen : 1;
if (delay) {
- indlen = (xfs_extlen_t)
- xfs_bmap_worst_indlen(ip, alen);
- ASSERT(indlen > 0);
+ xfs_extlen_t extsz = 0;
+
+ /* Figure out the extent size, adjust alen */
+ if (rt) {
+ if (!(extsz = ip->i_d.di_extsize))
+ extsz = mp->m_sb.sb_rextsize;
+ alen = roundup(alen, extsz);
+ extsz = alen / mp->m_sb.sb_rextsize;
+ }
+
/*
* Make a transaction-less quota reservation for
* delayed allocation blocks. This number gets
* We return EDQUOT if we haven't allocated
* blks already inside this loop;
*/
- if (XFS_TRANS_RESERVE_BLKQUOTA(
- mp, NULL, ip, (long)alen)) {
+ if (XFS_TRANS_RESERVE_QUOTA_NBLKS(
+ mp, NULL, ip, (long)alen, 0,
+ rt ? XFS_QMOPT_RES_RTBLKS :
+ XFS_QMOPT_RES_REGBLKS)) {
if (n == 0) {
*nmap = 0;
ASSERT(cur == NULL);
* Split changing sb for alen and indlen since
* they could be coming from different places.
*/
- if (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) {
- xfs_extlen_t extsz;
- xfs_extlen_t ralen;
- if (!(extsz = ip->i_d.di_extsize))
- extsz = mp->m_sb.sb_rextsize;
- ralen = roundup(alen, extsz);
- ralen = ralen / mp->m_sb.sb_rextsize;
- if (xfs_mod_incore_sb(mp,
- XFS_SBS_FREXTENTS,
- -(ralen), rsvd)) {
- if (XFS_IS_QUOTA_ON(ip->i_mount))
- XFS_TRANS_UNRESERVE_BLKQUOTA(
- mp, NULL, ip,
- (long)alen);
- break;
- }
- } else {
- if (xfs_mod_incore_sb(mp,
- XFS_SBS_FDBLOCKS,
- -(alen), rsvd)) {
- if (XFS_IS_QUOTA_ON(ip->i_mount))
- XFS_TRANS_UNRESERVE_BLKQUOTA(
- mp, NULL, ip,
- (long)alen);
- break;
- }
- }
+ indlen = (xfs_extlen_t)
+ xfs_bmap_worst_indlen(ip, alen);
+ ASSERT(indlen > 0);
- if (xfs_mod_incore_sb(mp, XFS_SBS_FDBLOCKS,
- -(indlen), rsvd)) {
- XFS_TRANS_UNRESERVE_BLKQUOTA(
- mp, NULL, ip, (long)alen);
+ if (rt)
+ error = xfs_mod_incore_sb(mp,
+ XFS_SBS_FREXTENTS,
+ -(extsz), rsvd);
+ else
+ error = xfs_mod_incore_sb(mp,
+ XFS_SBS_FDBLOCKS,
+ -(alen), rsvd);
+ if (!error)
+ error = xfs_mod_incore_sb(mp,
+ XFS_SBS_FDBLOCKS,
+ -(indlen), rsvd);
+
+ if (error) {
+ if (XFS_IS_QUOTA_ON(ip->i_mount))
+ /* unreserve the blocks now */
+ XFS_TRANS_UNRESERVE_QUOTA_NBLKS(
+ mp, NULL, ip,
+ (long)alen, 0, rt ?
+ XFS_QMOPT_RES_RTBLKS :
+ XFS_QMOPT_RES_REGBLKS);
break;
}
+
ip->i_delayed_blks += alen;
abno = NULLSTARTBLOCK(indlen);
} else {
}
if (wasdel) {
ASSERT(STARTBLOCKVAL(del.br_startblock) > 0);
- xfs_mod_incore_sb(mp, XFS_SBS_FDBLOCKS,
- (int)del.br_blockcount, rsvd);
- /* Unreserve our quota space */
- XFS_TRANS_RESERVE_QUOTA_NBLKS(
- mp, NULL, ip, -((long)del.br_blockcount), 0,
- isrt ? XFS_QMOPT_RES_RTBLKS :
+ /* Update realtim/data freespace, unreserve quota */
+ if (isrt) {
+ xfs_filblks_t rtexts;
+
+ rtexts = XFS_FSB_TO_B(mp, del.br_blockcount);
+ do_div(rtexts, mp->m_sb.sb_rextsize);
+ xfs_mod_incore_sb(mp, XFS_SBS_FREXTENTS,
+ (int)rtexts, rsvd);
+ XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, NULL, ip,
+ -((long)del.br_blockcount), 0,
+ XFS_QMOPT_RES_RTBLKS);
+ } else {
+ xfs_mod_incore_sb(mp, XFS_SBS_FDBLOCKS,
+ (int)del.br_blockcount, rsvd);
+ XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, NULL, ip,
+ -((long)del.br_blockcount), 0,
XFS_QMOPT_RES_REGBLKS);
+ }
ip->i_delayed_blks -= del.br_blockcount;
if (cur)
cur->bc_private.b.flags |=
* blocks at the end of the file which do not start at the previous data block,
* we will try to align the new blocks at stripe unit boundaries.
*/
-int /* error */
+STATIC int /* error */
xfs_bmap_isaeof(
xfs_inode_t *ip, /* incore inode pointer */
xfs_fileoff_t off, /* file offset in fsblocks */
void __user *ap, /* pointer to user's array */
int iflags); /* interface flags */
-/*
- * Check the last inode extent to determine whether this allocation will result
- * in blocks being allocated at the end of the file. When we allocate new data
- * blocks at the end of the file which do not start at the previous data block,
- * we will try to align the new blocks at stripe unit boundaries.
- */
-int
-xfs_bmap_isaeof(
- struct xfs_inode *ip,
- xfs_fileoff_t off,
- int whichfork,
- char *aeof);
-
/*
* Check if the endoff is outside the last extent. If so the caller will grow
* the allocation to a stripe unit boundary
return xfs_bmbt_lookup(cur, XFS_LOOKUP_GE, stat);
}
-int /* error */
-xfs_bmbt_lookup_le(
- xfs_btree_cur_t *cur,
- xfs_fileoff_t off,
- xfs_fsblock_t bno,
- xfs_filblks_t len,
- int *stat) /* success/failure */
-{
- cur->bc_rec.b.br_startoff = off;
- cur->bc_rec.b.br_startblock = bno;
- cur->bc_rec.b.br_blockcount = len;
- return xfs_bmbt_lookup(cur, XFS_LOOKUP_LE, stat);
-}
-
/*
* Give the bmap btree a new root block. Copy the old broot contents
* down into a real block and make the broot point to it.
xfs_filblks_t,
int *);
-int
-xfs_bmbt_lookup_le(
- struct xfs_btree_cur *,
- xfs_fileoff_t,
- xfs_fsblock_t,
- xfs_filblks_t,
- int *);
-
/*
* Give the bmap btree a new root block. Copy the old broot contents
* down into a real block and make the broot point to it.
* Internal routines.
*/
+/*
+ * Retrieve the block pointer from the cursor at the given level.
+ * This may be a bmap btree root or from a buffer.
+ */
+STATIC xfs_btree_block_t * /* generic btree block pointer */
+xfs_btree_get_block(
+ xfs_btree_cur_t *cur, /* btree cursor */
+ int level, /* level in btree */
+ struct xfs_buf **bpp); /* buffer containing the block */
+
/*
* Checking routine: return maxrecs for the block.
*/
* Retrieve the block pointer from the cursor at the given level.
* This may be a bmap btree root or from a buffer.
*/
-xfs_btree_block_t * /* generic btree block pointer */
+STATIC xfs_btree_block_t * /* generic btree block pointer */
xfs_btree_get_block(
xfs_btree_cur_t *cur, /* btree cursor */
int level, /* level in btree */
xfs_btree_cur_t *cur, /* btree cursor */
int level); /* level to change */
-/*
- * Retrieve the block pointer from the cursor at the given level.
- * This may be a bmap btree root or from a buffer.
- */
-xfs_btree_block_t * /* generic btree block pointer */
-xfs_btree_get_block(
- xfs_btree_cur_t *cur, /* btree cursor */
- int level, /* level in btree */
- struct xfs_buf **bpp); /* buffer containing the block */
-
/*
* Get a buffer for the block, return it with no data read.
* Long-form addressing.
*
* If the XFS_BLI_STALE flag has been set, then log nothing.
*/
-uint
+STATIC uint
xfs_buf_item_size(
xfs_buf_log_item_t *bip)
{
* format structure, and the rest point to contiguous chunks
* within the buffer.
*/
-void
+STATIC void
xfs_buf_item_format(
xfs_buf_log_item_t *bip,
xfs_log_iovec_t *log_vector)
* item in memory so it cannot be written out. Simply call bpin()
* on the buffer to do this.
*/
-void
+STATIC void
xfs_buf_item_pin(
xfs_buf_log_item_t *bip)
{
* If the XFS_BLI_STALE flag is set and we are the last reference,
* then free up the buf log item and unlock the buffer.
*/
-void
+STATIC void
xfs_buf_item_unpin(
xfs_buf_log_item_t *bip,
int stale)
* so we need to free the item's descriptor (that points to the item)
* in the transaction.
*/
-void
+STATIC void
xfs_buf_item_unpin_remove(
xfs_buf_log_item_t *bip,
xfs_trans_t *tp)
* the lock right away, return 0. If we can get the lock, pull the
* buffer from the free list, mark it busy, and return 1.
*/
-uint
+STATIC uint
xfs_buf_item_trylock(
xfs_buf_log_item_t *bip)
{
* This is for support of xfs_trans_bhold(). Make sure the
* XFS_BLI_HOLD field is cleared if we don't free the item.
*/
-void
+STATIC void
xfs_buf_item_unlock(
xfs_buf_log_item_t *bip)
{
* by returning the original lsn of that transaction here rather than
* the current one.
*/
-xfs_lsn_t
+STATIC xfs_lsn_t
xfs_buf_item_committed(
xfs_buf_log_item_t *bip,
xfs_lsn_t lsn)
* and have aborted this transaction, we'll trap this buffer when it tries to
* get written out.
*/
-void
+STATIC void
xfs_buf_item_abort(
xfs_buf_log_item_t *bip)
{
* B_DELWRI set, then get it going out to disk with a call to bawrite().
* If not, then just release the buffer.
*/
-void
+STATIC void
xfs_buf_item_push(
xfs_buf_log_item_t *bip)
{
}
/* ARGSUSED */
-void
+STATIC void
xfs_buf_item_committing(xfs_buf_log_item_t *bip, xfs_lsn_t commit_lsn)
{
}
/*
* This is the ops vector shared by all buf log items.
*/
-struct xfs_item_ops xfs_buf_item_ops = {
+STATIC struct xfs_item_ops xfs_buf_item_ops = {
.iop_size = (uint(*)(xfs_log_item_t*))xfs_buf_item_size,
.iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*))
xfs_buf_item_format,
* user or group dquots and may require special recovery handling.
*/
#define XFS_BLI_UDQUOT_BUF 0x4
-/* #define XFS_BLI_PDQUOT_BUF 0x8 */
+#define XFS_BLI_PDQUOT_BUF 0x8
#define XFS_BLI_GDQUOT_BUF 0x10
#define XFS_BLI_CHUNK 128
STATIC uint xfs_da_node_lasthash(xfs_dabuf_t *bp, int *count);
STATIC int xfs_da_node_order(xfs_dabuf_t *node1_bp, xfs_dabuf_t *node2_bp);
STATIC xfs_dabuf_t *xfs_da_buf_make(int nbuf, xfs_buf_t **bps, inst_t *ra);
-
+STATIC int xfs_da_blk_unlink(xfs_da_state_t *state,
+ xfs_da_state_blk_t *drop_blk,
+ xfs_da_state_blk_t *save_blk);
+STATIC void xfs_da_state_kill_altpath(xfs_da_state_t *state);
/*========================================================================
* Routines used for growing the Btree.
/*
* Unlink a block from a doubly linked list of blocks.
*/
-int /* error */
+STATIC int /* error */
xfs_da_blk_unlink(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk,
xfs_da_state_blk_t *save_blk)
{
/*
* Kill the altpath contents of a da-state structure.
*/
-void
+STATIC void
xfs_da_state_kill_altpath(xfs_da_state_t *state)
{
int i;
/*
* Utility routines.
*/
-int xfs_da_blk_unlink(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk,
- xfs_da_state_blk_t *save_blk);
int xfs_da_blk_link(xfs_da_state_t *state, xfs_da_state_blk_t *old_blk,
xfs_da_state_blk_t *new_blk);
uint xfs_da_log2_roundup(uint i);
xfs_da_state_t *xfs_da_state_alloc(void);
void xfs_da_state_free(xfs_da_state_t *state);
-void xfs_da_state_kill_altpath(xfs_da_state_t *state);
void xfs_da_buf_done(xfs_dabuf_t *dabuf);
void xfs_da_log_buf(struct xfs_trans *tp, xfs_dabuf_t *dabuf, uint first,
goto error0;
}
- if (VN_CACHED(tvp) != 0)
- xfs_inval_cached_pages(XFS_ITOV(tip), &(tip->i_iocore),
- (xfs_off_t)0, 0, 0);
+ if (VN_CACHED(tvp) != 0) {
+ xfs_inval_cached_trace(&tip->i_iocore, 0, -1, 0, -1);
+ VOP_FLUSHINVAL_PAGES(tvp, 0, -1, FI_REMAPF_LOCKED);
+ }
/* Verify O_DIRECT for ftmp */
if (VN_CACHED(tvp) != 0) {
/*
* Remove a bestfree entry from the table.
*/
-void
+STATIC void
xfs_dir2_data_freeremove(
xfs_dir2_data_t *d, /* data block pointer */
xfs_dir2_data_free_t *dfp, /* bestfree entry pointer */
xfs_dir2_data_freeinsert(xfs_dir2_data_t *d,
xfs_dir2_data_unused_t *dup, int *loghead);
-extern void
- xfs_dir2_data_freeremove(xfs_dir2_data_t *d,
- xfs_dir2_data_free_t *dfp, int *loghead);
-
extern void
xfs_dir2_data_freescan(struct xfs_mount *mp, xfs_dir2_data_t *d,
int *loghead, char *aendp);
#endif
static int xfs_dir2_leaf_lookup_int(xfs_da_args_t *args, xfs_dabuf_t **lbpp,
int *indexp, xfs_dabuf_t **dbpp);
+static void xfs_dir2_leaf_log_bests(struct xfs_trans *tp, struct xfs_dabuf *bp,
+ int first, int last);
+static void xfs_dir2_leaf_log_tail(struct xfs_trans *tp, struct xfs_dabuf *bp);
+
/*
* Convert a block form directory to a leaf form directory.
/*
* Log the bests entries indicated from a leaf1 block.
*/
-void
+static void
xfs_dir2_leaf_log_bests(
xfs_trans_t *tp, /* transaction pointer */
xfs_dabuf_t *bp, /* leaf buffer */
/*
* Log the tail of the leaf1 block.
*/
-void
+STATIC void
xfs_dir2_leaf_log_tail(
xfs_trans_t *tp, /* transaction pointer */
xfs_dabuf_t *bp) /* leaf buffer */
xfs_dir2_leaf_log_ents(struct xfs_trans *tp, struct xfs_dabuf *bp,
int first, int last);
-extern void
- xfs_dir2_leaf_log_bests(struct xfs_trans *tp, struct xfs_dabuf *bp,
- int first, int last);
-
extern void
xfs_dir2_leaf_log_header(struct xfs_trans *tp, struct xfs_dabuf *bp);
-extern void
- xfs_dir2_leaf_log_tail(struct xfs_trans *tp, struct xfs_dabuf *bp);
-
extern int
xfs_dir2_leaf_lookup(struct xfs_da_args *args);
int *number_entries_in_blk1,
int *number_namebytes_in_blk1);
+STATIC int xfs_dir_leaf_create(struct xfs_da_args *args,
+ xfs_dablk_t which_block,
+ struct xfs_dabuf **bpp);
+
/*
* Utility routines.
*/
* Create the initial contents of a leaf directory
* or a leaf in a node directory.
*/
-int
+STATIC int
xfs_dir_leaf_create(xfs_da_args_t *args, xfs_dablk_t blkno, xfs_dabuf_t **bpp)
{
xfs_dir_leafblock_t *leaf;
/*
* Routines used for growing the Btree.
*/
-int xfs_dir_leaf_create(struct xfs_da_args *args, xfs_dablk_t which_block,
- struct xfs_dabuf **bpp);
int xfs_dir_leaf_split(struct xfs_da_state *state,
struct xfs_da_state_blk *oldblk,
struct xfs_da_state_blk *newblk);
#define DM_FLAGS_NDELAY 0x001 /* return EAGAIN after dm_pending() */
#define DM_FLAGS_UNWANTED 0x002 /* event not in fsys dm_eventset_t */
#define DM_FLAGS_ISEM 0x004 /* thread holds i_sem */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21)
-/* i_alloc_sem was added in 2.4.22-pre1 */
#define DM_FLAGS_IALLOCSEM_RD 0x010 /* thread holds i_alloc_sem rd */
#define DM_FLAGS_IALLOCSEM_WR 0x020 /* thread holds i_alloc_sem wr */
-#endif
-#endif
/*
* Based on IO_ISDIRECT, decide which i_ flag is set.
*/
-#ifdef DM_FLAGS_IALLOCSEM_RD
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)
+#define DM_SEM_FLAG_RD(ioflags) (((ioflags) & IO_ISDIRECT) ? \
+ DM_FLAGS_ISEM : 0)
+#define DM_SEM_FLAG_WR (DM_FLAGS_IALLOCSEM_WR | DM_FLAGS_ISEM)
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)) && \
+ (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,22))
#define DM_SEM_FLAG_RD(ioflags) (((ioflags) & IO_ISDIRECT) ? \
DM_FLAGS_IALLOCSEM_RD : DM_FLAGS_ISEM)
#define DM_SEM_FLAG_WR (DM_FLAGS_IALLOCSEM_WR | DM_FLAGS_ISEM)
-#else
+#endif
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,21)
#define DM_SEM_FLAG_RD(ioflags) (((ioflags) & IO_ISDIRECT) ? \
0 : DM_FLAGS_ISEM)
#define DM_SEM_FLAG_WR (DM_FLAGS_ISEM)
#endif
+
/*
* Macros to turn caller specified delay/block flags into
* dm_send_xxxx_event flag DM_FLAGS_NDELAY.
}
}
-void
+STATIC void
xfs_hex_dump(void *p, int length)
{
__uint8_t *uip = (__uint8_t*)p;
int linenum,
inst_t *ra);
-extern void
-xfs_hex_dump(void *p, int length);
-
#define XFS_ERROR_REPORT(e, lvl, mp) \
xfs_error_report(e, lvl, mp, __FILE__, __LINE__, __return_address)
#define XFS_CORRUPTION_ERROR(e, lvl, mp, mem) \
STATIC void xfs_efd_item_abort(xfs_efd_log_item_t *);
+void
+xfs_efi_item_free(xfs_efi_log_item_t *efip)
+{
+ int nexts = efip->efi_format.efi_nextents;
+
+ if (nexts > XFS_EFI_MAX_FAST_EXTENTS) {
+ kmem_free(efip, sizeof(xfs_efi_log_item_t) +
+ (nexts - 1) * sizeof(xfs_extent_t));
+ } else {
+ kmem_zone_free(xfs_efi_zone, efip);
+ }
+}
/*
* This returns the number of iovecs needed to log the given efi item.
STATIC void
xfs_efi_item_unpin(xfs_efi_log_item_t *efip, int stale)
{
- int nexts;
- int size;
xfs_mount_t *mp;
SPLDECL(s);
* xfs_trans_delete_ail() drops the AIL lock.
*/
xfs_trans_delete_ail(mp, (xfs_log_item_t *)efip, s);
-
- nexts = efip->efi_format.efi_nextents;
- if (nexts > XFS_EFI_MAX_FAST_EXTENTS) {
- size = sizeof(xfs_efi_log_item_t);
- size += (nexts - 1) * sizeof(xfs_extent_t);
- kmem_free(efip, size);
- } else {
- kmem_zone_free(xfs_efi_zone, efip);
- }
+ xfs_efi_item_free(efip);
} else {
efip->efi_flags |= XFS_EFI_COMMITTED;
AIL_UNLOCK(mp, s);
}
-
- return;
}
/*
STATIC void
xfs_efi_item_unpin_remove(xfs_efi_log_item_t *efip, xfs_trans_t *tp)
{
- int nexts;
- int size;
xfs_mount_t *mp;
xfs_log_item_desc_t *lidp;
SPLDECL(s);
* xfs_trans_delete_ail() drops the AIL lock.
*/
xfs_trans_delete_ail(mp, (xfs_log_item_t *)efip, s);
- /*
- * now free the item itself
- */
- nexts = efip->efi_format.efi_nextents;
- if (nexts > XFS_EFI_MAX_FAST_EXTENTS) {
- size = sizeof(xfs_efi_log_item_t);
- size += (nexts - 1) * sizeof(xfs_extent_t);
- kmem_free(efip, size);
- } else {
- kmem_zone_free(xfs_efi_zone, efip);
- }
+ xfs_efi_item_free(efip);
} else {
efip->efi_flags |= XFS_EFI_COMMITTED;
AIL_UNLOCK(mp, s);
}
-
- return;
}
/*
STATIC void
xfs_efi_item_abort(xfs_efi_log_item_t *efip)
{
- int nexts;
- int size;
-
- nexts = efip->efi_format.efi_nextents;
- if (nexts > XFS_EFI_MAX_FAST_EXTENTS) {
- size = sizeof(xfs_efi_log_item_t);
- size += (nexts - 1) * sizeof(xfs_extent_t);
- kmem_free(efip, size);
- } else {
- kmem_zone_free(xfs_efi_zone, efip);
- }
- return;
+ xfs_efi_item_free(efip);
}
/*
/*
* This is the ops vector shared by all efi log items.
*/
-struct xfs_item_ops xfs_efi_item_ops = {
+STATIC struct xfs_item_ops xfs_efi_item_ops = {
.iop_size = (uint(*)(xfs_log_item_t*))xfs_efi_item_size,
.iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*))
xfs_efi_item_format,
{
xfs_mount_t *mp;
int extents_left;
- uint size;
- int nexts;
SPLDECL(s);
mp = efip->efi_item.li_mountp;
* xfs_trans_delete_ail() drops the AIL lock.
*/
xfs_trans_delete_ail(mp, (xfs_log_item_t *)efip, s);
+ xfs_efi_item_free(efip);
} else {
AIL_UNLOCK(mp, s);
}
-
- if (extents_left == 0) {
- nexts = efip->efi_format.efi_nextents;
- if (nexts > XFS_EFI_MAX_FAST_EXTENTS) {
- size = sizeof(xfs_efi_log_item_t);
- size += (nexts - 1) * sizeof(xfs_extent_t);
- kmem_free(efip, size);
- } else {
- kmem_zone_free(xfs_efi_zone, efip);
- }
- }
}
/*
xfs_efi_cancel(
xfs_efi_log_item_t *efip)
{
- int nexts;
- int size;
xfs_mount_t *mp;
SPLDECL(s);
* xfs_trans_delete_ail() drops the AIL lock.
*/
xfs_trans_delete_ail(mp, (xfs_log_item_t *)efip, s);
-
- nexts = efip->efi_format.efi_nextents;
- if (nexts > XFS_EFI_MAX_FAST_EXTENTS) {
- size = sizeof(xfs_efi_log_item_t);
- size += (nexts - 1) * sizeof(xfs_extent_t);
- kmem_free(efip, size);
- } else {
- kmem_zone_free(xfs_efi_zone, efip);
- }
+ xfs_efi_item_free(efip);
} else {
efip->efi_flags |= XFS_EFI_CANCELED;
AIL_UNLOCK(mp, s);
}
-
- return;
}
+STATIC void
+xfs_efd_item_free(xfs_efd_log_item_t *efdp)
+{
+ int nexts = efdp->efd_format.efd_nextents;
-
-
+ if (nexts > XFS_EFD_MAX_FAST_EXTENTS) {
+ kmem_free(efdp, sizeof(xfs_efd_log_item_t) +
+ (nexts - 1) * sizeof(xfs_extent_t));
+ } else {
+ kmem_zone_free(xfs_efd_zone, efdp);
+ }
+}
/*
* This returns the number of iovecs needed to log the given efd item.
STATIC xfs_lsn_t
xfs_efd_item_committed(xfs_efd_log_item_t *efdp, xfs_lsn_t lsn)
{
- uint size;
- int nexts;
-
/*
* If we got a log I/O error, it's always the case that the LR with the
* EFI got unpinned and freed before the EFD got aborted.
if ((efdp->efd_item.li_flags & XFS_LI_ABORTED) == 0)
xfs_efi_release(efdp->efd_efip, efdp->efd_format.efd_nextents);
- nexts = efdp->efd_format.efd_nextents;
- if (nexts > XFS_EFD_MAX_FAST_EXTENTS) {
- size = sizeof(xfs_efd_log_item_t);
- size += (nexts - 1) * sizeof(xfs_extent_t);
- kmem_free(efdp, size);
- } else {
- kmem_zone_free(xfs_efd_zone, efdp);
- }
-
+ xfs_efd_item_free(efdp);
return (xfs_lsn_t)-1;
}
STATIC void
xfs_efd_item_abort(xfs_efd_log_item_t *efdp)
{
- int nexts;
- int size;
-
/*
* If we got a log I/O error, it's always the case that the LR with the
* EFI got unpinned and freed before the EFD got aborted. So don't
if ((efdp->efd_item.li_flags & XFS_LI_ABORTED) == 0)
xfs_efi_cancel(efdp->efd_efip);
- nexts = efdp->efd_format.efd_nextents;
- if (nexts > XFS_EFD_MAX_FAST_EXTENTS) {
- size = sizeof(xfs_efd_log_item_t);
- size += (nexts - 1) * sizeof(xfs_extent_t);
- kmem_free(efdp, size);
- } else {
- kmem_zone_free(xfs_efd_zone, efdp);
- }
- return;
+ xfs_efd_item_free(efdp);
}
/*
/*
* This is the ops vector shared by all efd log items.
*/
-struct xfs_item_ops xfs_efd_item_ops = {
+STATIC struct xfs_item_ops xfs_efd_item_ops = {
.iop_size = (uint(*)(xfs_log_item_t*))xfs_efd_item_size,
.iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*))
xfs_efd_item_format,
xfs_efd_log_item_t *xfs_efd_init(struct xfs_mount *, xfs_efi_log_item_t *,
uint);
+void xfs_efi_item_free(xfs_efi_log_item_t *);
+
#endif /* __KERNEL__ */
#endif /* __XFS_EXTFREE_ITEM_H__ */
__u32 fsx_xflags; /* xflags field value (get/set) */
__u32 fsx_extsize; /* extsize field value (get/set)*/
__u32 fsx_nextents; /* nextents field value (get) */
- unsigned char fsx_pad[16];
+ __u32 fsx_projid; /* project identifier (get/set) */
+ unsigned char fsx_pad[12];
};
#endif
return(0);
}
-void
-xfs_fs_log_dummy(xfs_mount_t *mp)
-{
- xfs_trans_t *tp;
- xfs_inode_t *ip;
-
-
- tp = _xfs_trans_alloc(mp, XFS_TRANS_DUMMY1);
- atomic_inc(&mp->m_active_trans);
- if (xfs_trans_reserve(tp, 0, XFS_ICHANGE_LOG_RES(mp), 0, 0, 0)) {
- xfs_trans_cancel(tp, 0);
- return;
- }
-
- ip = mp->m_rootip;
- xfs_ilock(ip, XFS_ILOCK_EXCL);
-
- xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
- xfs_trans_ihold(tp, ip);
- xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
- xfs_trans_set_sync(tp);
- xfs_trans_commit(tp, 0, NULL);
-
- xfs_iunlock(ip, XFS_ILOCK_EXCL);
-}
-
int
xfs_fs_goingdown(
xfs_mount_t *mp,
#endif
#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_IS_FREE)
int xfs_inobt_is_free(xfs_inobt_rec_t *rp, int i);
-#define XFS_INOBT_IS_FREE(rp,i) xfs_inobt_is_free(rp,i)
+#define XFS_INOBT_IS_FREE(rp,i) xfs_inobt_is_free(rp,i)
+#define XFS_INOBT_IS_FREE_DISK(rp,i) xfs_inobt_is_free_disk(rp,i)
#else
-#define XFS_INOBT_IS_FREE(rp,i) (((rp)->ir_free & XFS_INOBT_MASK(i)) != 0)
+#define XFS_INOBT_IS_FREE(rp,i) \
+ (((rp)->ir_free & XFS_INOBT_MASK(i)) != 0)
+#define XFS_INOBT_IS_FREE_DISK(rp,i) \
+ ((INT_GET((rp)->ir_free, ARCH_CONVERT) & XFS_INOBT_MASK(i)) != 0)
#endif
#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_SET_FREE)
void xfs_inobt_set_free(xfs_inobt_rec_t *rp, int i);
}
#endif
-/*
- * called from bwrite on xfs inode buffers
- */
-void
-xfs_inobp_bwcheck(xfs_buf_t *bp)
-{
- xfs_mount_t *mp;
- int i;
- int j;
- xfs_dinode_t *dip;
-
- ASSERT(XFS_BUF_FSPRIVATE3(bp, void *) != NULL);
-
- mp = XFS_BUF_FSPRIVATE3(bp, xfs_mount_t *);
-
-
- j = mp->m_inode_cluster_size >> mp->m_sb.sb_inodelog;
-
- for (i = 0; i < j; i++) {
- dip = (xfs_dinode_t *) xfs_buf_offset(bp,
- i * mp->m_sb.sb_inodesize);
- if (INT_GET(dip->di_core.di_magic, ARCH_CONVERT) != XFS_DINODE_MAGIC) {
- cmn_err(CE_WARN,
-"Bad magic # 0x%x in XFS inode buffer 0x%Lx, starting blockno %Ld, offset 0x%x",
- INT_GET(dip->di_core.di_magic, ARCH_CONVERT),
- (__uint64_t)(__psunsigned_t) bp,
- (__int64_t) XFS_BUF_ADDR(bp),
- xfs_buf_offset(bp, i * mp->m_sb.sb_inodesize));
- xfs_fs_cmn_err(CE_WARN, mp,
- "corrupt, unmount and run xfs_repair");
- }
- if (!dip->di_next_unlinked) {
- cmn_err(CE_WARN,
-"Bad next_unlinked field (0) in XFS inode buffer 0x%p, starting blockno %Ld, offset 0x%x",
- (__uint64_t)(__psunsigned_t) bp,
- (__int64_t) XFS_BUF_ADDR(bp),
- xfs_buf_offset(bp, i * mp->m_sb.sb_inodesize));
- xfs_fs_cmn_err(CE_WARN, mp,
- "corrupt, unmount and run xfs_repair");
- }
- }
-
- return;
-}
-
/*
* This routine is called to map an inode number within a file
* system to the buffer containing the on-disk version of the
* Use xfs_imap() to determine the size and location of the
* buffer to read from disk.
*/
-int
+STATIC int
xfs_inotobp(
xfs_mount_t *mp,
xfs_trans_t *tp,
case S_IFREG:
case S_IFDIR:
if (unlikely(pip->i_d.di_flags & XFS_DIFLAG_ANY)) {
- if (pip->i_d.di_flags & XFS_DIFLAG_RTINHERIT) {
- if ((mode & S_IFMT) == S_IFDIR) {
- ip->i_d.di_flags |= XFS_DIFLAG_RTINHERIT;
- } else {
- ip->i_d.di_flags |= XFS_DIFLAG_REALTIME;
+ uint di_flags = 0;
+
+ if ((mode & S_IFMT) == S_IFDIR) {
+ if (pip->i_d.di_flags & XFS_DIFLAG_RTINHERIT)
+ di_flags |= XFS_DIFLAG_RTINHERIT;
+ } else {
+ if (pip->i_d.di_flags & XFS_DIFLAG_RTINHERIT) {
+ di_flags |= XFS_DIFLAG_REALTIME;
ip->i_iocore.io_flags |= XFS_IOCORE_RT;
}
}
if ((pip->i_d.di_flags & XFS_DIFLAG_NOATIME) &&
xfs_inherit_noatime)
- ip->i_d.di_flags |= XFS_DIFLAG_NOATIME;
+ di_flags |= XFS_DIFLAG_NOATIME;
if ((pip->i_d.di_flags & XFS_DIFLAG_NODUMP) &&
xfs_inherit_nodump)
- ip->i_d.di_flags |= XFS_DIFLAG_NODUMP;
+ di_flags |= XFS_DIFLAG_NODUMP;
if ((pip->i_d.di_flags & XFS_DIFLAG_SYNC) &&
xfs_inherit_sync)
- ip->i_d.di_flags |= XFS_DIFLAG_SYNC;
+ di_flags |= XFS_DIFLAG_SYNC;
if ((pip->i_d.di_flags & XFS_DIFLAG_NOSYMLINKS) &&
xfs_inherit_nosymlinks)
- ip->i_d.di_flags |= XFS_DIFLAG_NOSYMLINKS;
+ di_flags |= XFS_DIFLAG_NOSYMLINKS;
+ if (pip->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)
+ di_flags |= XFS_DIFLAG_PROJINHERIT;
+ ip->i_d.di_flags |= di_flags;
}
/* FALLTHROUGH */
case S_IFLNK:
(ip->i_update_core == 0));
}
-void
+STATIC void
xfs_ifree_cluster(
xfs_inode_t *free_ip,
xfs_trans_t *tp,
* be subsequently pinned once someone is waiting for it to be
* unpinned.
*/
-void
+STATIC void
xfs_iunpin_wait(
xfs_inode_t *ip)
{
/*
- * Flush all inactive inodes in mp. Return true if no user references
- * were found, false otherwise.
+ * Flush all inactive inodes in mp.
*/
-int
+void
xfs_iflush_all(
- xfs_mount_t *mp,
- int flag)
+ xfs_mount_t *mp)
{
- int busy;
- int done;
- int purged;
xfs_inode_t *ip;
- vmap_t vmap;
vnode_t *vp;
- busy = done = 0;
- while (!done) {
- purged = 0;
- XFS_MOUNT_ILOCK(mp);
- ip = mp->m_inodes;
- if (ip == NULL) {
- break;
- }
- do {
- /* Make sure we skip markers inserted by sync */
- if (ip->i_mount == NULL) {
- ip = ip->i_mnext;
- continue;
- }
-
- /*
- * It's up to our caller to purge the root
- * and quota vnodes later.
- */
- vp = XFS_ITOV_NULL(ip);
-
- if (!vp) {
- XFS_MOUNT_IUNLOCK(mp);
- xfs_finish_reclaim(ip, 0, XFS_IFLUSH_ASYNC);
- purged = 1;
- break;
- }
+ again:
+ XFS_MOUNT_ILOCK(mp);
+ ip = mp->m_inodes;
+ if (ip == NULL)
+ goto out;
- if (vn_count(vp) != 0) {
- if (vn_count(vp) == 1 &&
- (ip == mp->m_rootip ||
- (mp->m_quotainfo &&
- (ip->i_ino == mp->m_sb.sb_uquotino ||
- ip->i_ino == mp->m_sb.sb_gquotino)))) {
+ do {
+ /* Make sure we skip markers inserted by sync */
+ if (ip->i_mount == NULL) {
+ ip = ip->i_mnext;
+ continue;
+ }
- ip = ip->i_mnext;
- continue;
- }
- if (!(flag & XFS_FLUSH_ALL)) {
- busy = 1;
- done = 1;
- break;
- }
- /*
- * Ignore busy inodes but continue flushing
- * others.
- */
- ip = ip->i_mnext;
- continue;
- }
- /*
- * Sample vp mapping while holding mp locked on MP
- * systems, so we don't purge a reclaimed or
- * nonexistent vnode. We break from the loop
- * since we know that we modify
- * it by pulling ourselves from it in xfs_reclaim()
- * called via vn_purge() below. Set ip to the next
- * entry in the list anyway so we'll know below
- * whether we reached the end or not.
- */
- VMAP(vp, vmap);
+ vp = XFS_ITOV_NULL(ip);
+ if (!vp) {
XFS_MOUNT_IUNLOCK(mp);
+ xfs_finish_reclaim(ip, 0, XFS_IFLUSH_ASYNC);
+ goto again;
+ }
- vn_purge(vp, &vmap);
+ ASSERT(vn_count(vp) == 0);
- purged = 1;
- break;
- } while (ip != mp->m_inodes);
- /*
- * We need to distinguish between when we exit the loop
- * after a purge and when we simply hit the end of the
- * list. We can't use the (ip == mp->m_inodes) test,
- * because when we purge an inode at the start of the list
- * the next inode on the list becomes mp->m_inodes. That
- * would cause such a test to bail out early. The purged
- * variable tells us how we got out of the loop.
- */
- if (!purged) {
- done = 1;
- }
- }
+ ip = ip->i_mnext;
+ } while (ip != mp->m_inodes);
+ out:
XFS_MOUNT_IUNLOCK(mp);
- return !busy;
}
-
/*
* xfs_iaccess: check accessibility of inode for mode.
*/
#define XFS_IFLUSH_ASYNC 4
#define XFS_IFLUSH_DELWRI 5
-/*
- * Flags for xfs_iflush_all.
- */
-#define XFS_FLUSH_ALL 0x1
-
/*
* Flags for xfs_itruncate_start().
*/
/*
* xfs_inode.c prototypes.
*/
-int xfs_inotobp(struct xfs_mount *, struct xfs_trans *, xfs_ino_t,
- xfs_dinode_t **, struct xfs_buf **, int *);
int xfs_itobp(struct xfs_mount *, struct xfs_trans *,
xfs_inode_t *, xfs_dinode_t **, struct xfs_buf **,
xfs_daddr_t);
void xfs_iunpin(xfs_inode_t *);
int xfs_iextents_copy(xfs_inode_t *, xfs_bmbt_rec_t *, int);
int xfs_iflush(xfs_inode_t *, uint);
-int xfs_iflush_all(struct xfs_mount *, int);
+void xfs_iflush_all(struct xfs_mount *);
int xfs_iaccess(xfs_inode_t *, mode_t, cred_t *);
uint xfs_iroundup(uint);
void xfs_ichgtime(xfs_inode_t *, int);
/*
* This is the ops vector shared by all buf log items.
*/
-struct xfs_item_ops xfs_inode_item_ops = {
+STATIC struct xfs_item_ops xfs_inode_item_ops = {
.iop_size = (uint(*)(xfs_log_item_t*))xfs_inode_item_size,
.iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*))
xfs_inode_item_format,
int nimaps, maps;
int error;
int bmapi_flag;
+ int quota_flag;
int rt;
xfs_trans_t *tp;
xfs_bmbt_irec_t imap[XFS_WRITE_IMAPS], *imapp;
xfs_bmap_free_t free_list;
int aeof;
- xfs_filblks_t datablocks;
+ xfs_filblks_t datablocks, qblocks, resblks;
int committed;
int numrtextents;
- uint resblks;
/*
* Make sure that the dquots are there. This doesn't hold
xfs_fileoff_t map_last_fsb;
map_last_fsb = ret_imap->br_blockcount + ret_imap->br_startoff;
-
if (map_last_fsb < last_fsb) {
last_fsb = map_last_fsb;
count_fsb = last_fsb - offset_fsb;
}
/*
- * determine if reserving space on
- * the data or realtime partition.
+ * Determine if reserving space on the data or realtime partition.
*/
if ((rt = XFS_IS_REALTIME_INODE(ip))) {
- int sbrtextsize, iprtextsize;
+ xfs_extlen_t extsz;
- sbrtextsize = mp->m_sb.sb_rextsize;
- iprtextsize =
- ip->i_d.di_extsize ? ip->i_d.di_extsize : sbrtextsize;
- numrtextents = (count_fsb + iprtextsize - 1);
- do_div(numrtextents, sbrtextsize);
+ if (!(extsz = ip->i_d.di_extsize))
+ extsz = mp->m_sb.sb_rextsize;
+ numrtextents = qblocks = (count_fsb + extsz - 1);
+ do_div(numrtextents, mp->m_sb.sb_rextsize);
+ quota_flag = XFS_QMOPT_RES_RTBLKS;
datablocks = 0;
} else {
- datablocks = count_fsb;
+ datablocks = qblocks = count_fsb;
+ quota_flag = XFS_QMOPT_RES_REGBLKS;
numrtextents = 0;
}
/*
- * allocate and setup the transaction
+ * Allocate and setup the transaction
*/
xfs_iunlock(ip, XFS_ILOCK_EXCL);
tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT);
-
resblks = XFS_DIOSTRAT_SPACE_RES(mp, datablocks);
-
error = xfs_trans_reserve(tp, resblks,
XFS_WRITE_LOG_RES(mp), numrtextents,
XFS_TRANS_PERM_LOG_RES,
XFS_WRITE_LOG_COUNT);
/*
- * check for running out of space
+ * Check for running out of space, note: need lock to return
*/
if (error)
- /*
- * Free the transaction structure.
- */
xfs_trans_cancel(tp, 0);
-
xfs_ilock(ip, XFS_ILOCK_EXCL);
-
if (error)
- goto error_out; /* Don't return in above if .. trans ..,
- need lock to return */
+ goto error_out;
- if (XFS_TRANS_RESERVE_BLKQUOTA(mp, tp, ip, resblks)) {
+ if (XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, tp, ip, qblocks, 0, quota_flag)) {
error = (EDQUOT);
goto error1;
}
- nimaps = 1;
bmapi_flag = XFS_BMAPI_WRITE;
xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
bmapi_flag |= XFS_BMAPI_PREALLOC;
/*
- * issue the bmapi() call to allocate the blocks
+ * Issue the bmapi() call to allocate the blocks
*/
XFS_BMAP_INIT(&free_list, &firstfsb);
+ nimaps = 1;
imapp = &imap[0];
error = xfs_bmapi(tp, ip, offset_fsb, count_fsb,
bmapi_flag, &firstfsb, 0, imapp, &nimaps, &free_list);
- if (error) {
+ if (error)
goto error0;
- }
/*
- * complete the transaction
+ * Complete the transaction
*/
-
error = xfs_bmap_finish(&tp, &free_list, firstfsb, &committed);
- if (error) {
+ if (error)
goto error0;
- }
-
error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
- if (error) {
+ if (error)
goto error_out;
- }
- /* copy any maps to caller's array and return any error. */
+ /*
+ * Copy any maps to caller's array and return any error.
+ */
if (nimaps == 0) {
error = (ENOSPC);
goto error_out;
}
return 0;
- error0: /* Cancel bmap, unlock inode, and cancel trans */
+error0: /* Cancel bmap, unlock inode, unreserve quota blocks, cancel trans */
xfs_bmap_cancel(&free_list);
+ XFS_TRANS_UNRESERVE_QUOTA_NBLKS(mp, tp, ip, qblocks, 0, quota_flag);
- error1: /* Just cancel transaction */
+error1: /* Just cancel transaction */
xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
*nmaps = 0; /* nothing set-up here */
#define xlog_verify_tail_lsn(a,b,c)
#endif
-int xlog_iclogs_empty(xlog_t *log);
+STATIC int xlog_iclogs_empty(xlog_t *log);
#ifdef DEBUG
int xlog_do_error = 0;
*
* State Change: DIRTY -> ACTIVE
*/
-void
+STATIC void
xlog_state_clean_log(xlog_t *log)
{
xlog_in_core_t *iclog;
return (retval);
}
-int
+STATIC int
xlog_iclogs_empty(xlog_t *log)
{
xlog_in_core_t *iclog;
/* common routines */
extern xfs_lsn_t xlog_assign_tail_lsn(struct xfs_mount *mp);
-extern int xlog_find_head(xlog_t *log, xfs_daddr_t *head_blk);
extern int xlog_find_tail(xlog_t *log,
xfs_daddr_t *head_blk,
xfs_daddr_t *tail_blk,
extern struct xfs_buf *xlog_get_bp(xlog_t *, int);
extern void xlog_put_bp(struct xfs_buf *);
extern int xlog_bread(xlog_t *, xfs_daddr_t, int, struct xfs_buf *);
-extern xfs_caddr_t xlog_align(xlog_t *, xfs_daddr_t, int, struct xfs_buf *);
/* iclog tracing */
#define XLOG_TRACE_GRAB_FLUSH 1
* The buffer is kept locked across the write and is returned locked.
* This can only be used for synchronous log writes.
*/
-int
+STATIC int
xlog_bwrite(
xlog_t *log,
xfs_daddr_t blk_no,
return error;
}
-xfs_caddr_t
+STATIC xfs_caddr_t
xlog_align(
xlog_t *log,
xfs_daddr_t blk_no,
*
* Return: zero if normal, non-zero if error.
*/
-int
+STATIC int
xlog_find_head(
xlog_t *log,
xfs_daddr_t *return_head_blk)
* probably a good thing to do for other buf types also.
*/
error = 0;
- if (buf_f->blf_flags & (XFS_BLI_UDQUOT_BUF|XFS_BLI_GDQUOT_BUF)) {
+ if (buf_f->blf_flags &
+ (XFS_BLI_UDQUOT_BUF|XFS_BLI_PDQUOT_BUF|XFS_BLI_GDQUOT_BUF)) {
error = xfs_qm_dqcheck((xfs_disk_dquot_t *)
item->ri_buf[i].i_addr,
-1, 0, XFS_QMOPT_DOWARN,
}
if (INT_GET(ddq->d_flags, ARCH_CONVERT) != XFS_DQ_USER &&
+ INT_GET(ddq->d_flags, ARCH_CONVERT) != XFS_DQ_PROJ &&
INT_GET(ddq->d_flags, ARCH_CONVERT) != XFS_DQ_GROUP) {
if (flags & XFS_QMOPT_DOWARN)
cmn_err(CE_ALERT,
type = 0;
if (buf_f->blf_flags & XFS_BLI_UDQUOT_BUF)
type |= XFS_DQ_USER;
+ if (buf_f->blf_flags & XFS_BLI_PDQUOT_BUF)
+ type |= XFS_DQ_PROJ;
if (buf_f->blf_flags & XFS_BLI_GDQUOT_BUF)
type |= XFS_DQ_GROUP;
/*
error = 0;
if (flags & XFS_BLI_INODE_BUF) {
error = xlog_recover_do_inode_buffer(mp, item, bp, buf_f);
- } else if (flags & (XFS_BLI_UDQUOT_BUF | XFS_BLI_GDQUOT_BUF)) {
+ } else if (flags &
+ (XFS_BLI_UDQUOT_BUF|XFS_BLI_PDQUOT_BUF|XFS_BLI_GDQUOT_BUF)) {
xlog_recover_do_dquot_buffer(mp, log, item, bp, buf_f);
} else {
xlog_recover_do_reg_buffer(mp, item, bp, buf_f);
* This type of quotas was turned off, so ignore this record.
*/
type = INT_GET(recddq->d_flags, ARCH_CONVERT) &
- (XFS_DQ_USER | XFS_DQ_GROUP);
+ (XFS_DQ_USER | XFS_DQ_PROJ | XFS_DQ_GROUP);
ASSERT(type);
if (log->l_quotaoffs_flag & type)
return (0);
xfs_efi_log_item_t *efip = NULL;
xfs_log_item_t *lip;
int gen;
- int nexts;
__uint64_t efi_id;
SPLDECL(s);
}
lip = xfs_trans_next_ail(mp, lip, &gen, NULL);
}
- if (lip == NULL) {
- AIL_UNLOCK(mp, s);
- }
/*
* If we found it, then free it up. If it wasn't there, it
* must have been overwritten in the log. Oh well.
*/
if (lip != NULL) {
- nexts = efip->efi_format.efi_nextents;
- if (nexts > XFS_EFI_MAX_FAST_EXTENTS) {
- kmem_free(lip, sizeof(xfs_efi_log_item_t) +
- ((nexts - 1) * sizeof(xfs_extent_t)));
- } else {
- kmem_zone_free(xfs_efi_zone, efip);
- }
+ xfs_efi_item_free(efip);
+ } else {
+ AIL_UNLOCK(mp, s);
}
}
{
return XFS_INOBT_IS_FREE(rp, i);
}
+int
+xfs_inobt_is_free_disk(xfs_inobt_rec_t *rp, int i)
+{
+ return XFS_INOBT_IS_FREE_DISK(rp, i);
+}
#endif
#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INOBT_IS_LAST_REC)
STATIC void xfs_mount_log_sbunit(xfs_mount_t *, __int64_t);
STATIC int xfs_uuid_mount(xfs_mount_t *);
STATIC void xfs_uuid_unmount(xfs_mount_t *mp);
+STATIC void xfs_unmountfs_wait(xfs_mount_t *);
static struct {
short offset;
* fields from the superblock associated with the given
* mount structure
*/
-void
+STATIC void
xfs_mount_common(xfs_mount_t *mp, xfs_sb_t *sbp)
{
int i;
int64_t fsid;
#endif
- xfs_iflush_all(mp, XFS_FLUSH_ALL);
+ xfs_iflush_all(mp);
XFS_QM_DQPURGEALL(mp,
XFS_QMOPT_UQUOTA | XFS_QMOPT_GQUOTA | XFS_QMOPT_UMOUNTING);
*/
ASSERT(mp->m_inodes == NULL);
- /*
- * We may have bufs that are in the process of getting written still.
- * We must wait for the I/O completion of those. The sync flag here
- * does a two pass iteration thru the bufcache.
- */
- if (XFS_FORCED_SHUTDOWN(mp)) {
- xfs_incore_relse(mp->m_ddev_targp, 0, 1); /* synchronous */
- }
-
xfs_unmountfs_close(mp, cr);
if ((mp->m_flags & XFS_MOUNT_NOUUID) == 0)
xfs_uuid_unmount(mp);
xfs_free_buftarg(mp->m_ddev_targp, 0);
}
-void
+STATIC void
xfs_unmountfs_wait(xfs_mount_t *mp)
{
if (mp->m_logdev_targp != mp->m_ddev_targp)
typedef void (*xfs_dqdetach_t)(struct xfs_inode *);
typedef int (*xfs_dqpurgeall_t)(struct xfs_mount *, uint);
typedef int (*xfs_dqvopalloc_t)(struct xfs_mount *,
- struct xfs_inode *, uid_t, gid_t, uint,
+ struct xfs_inode *, uid_t, gid_t, prid_t, uint,
struct xfs_dquot **, struct xfs_dquot **);
typedef void (*xfs_dqvopcreate_t)(struct xfs_trans *, struct xfs_inode *,
struct xfs_dquot *, struct xfs_dquot *);
(*(mp)->m_qm_ops.xfs_dqdetach)(ip)
#define XFS_QM_DQPURGEALL(mp, fl) \
(*(mp)->m_qm_ops.xfs_dqpurgeall)(mp, fl)
-#define XFS_QM_DQVOPALLOC(mp, ip, uid, gid, fl, dq1, dq2) \
- (*(mp)->m_qm_ops.xfs_dqvopalloc)(mp, ip, uid, gid, fl, dq1, dq2)
+#define XFS_QM_DQVOPALLOC(mp, ip, uid, gid, prid, fl, dq1, dq2) \
+ (*(mp)->m_qm_ops.xfs_dqvopalloc)(mp, ip, uid, gid, prid, fl, dq1, dq2)
#define XFS_QM_DQVOPCREATE(mp, tp, ip, dq1, dq2) \
(*(mp)->m_qm_ops.xfs_dqvopcreate)(tp, ip, dq1, dq2)
#define XFS_QM_DQVOPRENAME(mp, ip) \
extern int xfs_mountfs(struct vfs *, xfs_mount_t *mp, int);
extern int xfs_unmountfs(xfs_mount_t *, struct cred *);
-extern void xfs_unmountfs_wait(xfs_mount_t *);
extern void xfs_unmountfs_close(xfs_mount_t *, struct cred *);
extern int xfs_unmountfs_writesb(xfs_mount_t *);
extern int xfs_unmount_flush(xfs_mount_t *, int);
* flags for q_flags field in the dquot.
*/
#define XFS_DQ_USER 0x0001 /* a user quota */
-/* #define XFS_DQ_PROJ 0x0002 -- project quota (IRIX) */
+#define XFS_DQ_PROJ 0x0002 /* project quota */
#define XFS_DQ_GROUP 0x0004 /* a group quota */
#define XFS_DQ_FLOCKED 0x0008 /* flush lock taken */
#define XFS_DQ_DIRTY 0x0010 /* dquot is dirty */
#define XFS_DQ_INACTIVE 0x0040 /* dq off mplist & hashlist */
#define XFS_DQ_MARKER 0x0080 /* sentinel */
+#define XFS_DQ_ALLTYPES (XFS_DQ_USER|XFS_DQ_PROJ|XFS_DQ_GROUP)
+
/*
* In the worst case, when both user and group quotas are on,
* we can have a max of three dquots changing in a single transaction.
typedef struct xfs_dq_logformat {
__uint16_t qlf_type; /* dquot log item type */
__uint16_t qlf_size; /* size of this item */
- xfs_dqid_t qlf_id; /* usr/grp id number : 32 bits */
+ xfs_dqid_t qlf_id; /* usr/grp/proj id : 32 bits */
__int64_t qlf_blkno; /* blkno of dquot buffer */
__int32_t qlf_len; /* len of dquot buffer */
__uint32_t qlf_boffset; /* off of dquot in buffer */
#define XFS_UQUOTA_ACCT 0x0001 /* user quota accounting ON */
#define XFS_UQUOTA_ENFD 0x0002 /* user quota limits enforced */
#define XFS_UQUOTA_CHKD 0x0004 /* quotacheck run on usr quotas */
-#define XFS_PQUOTA_ACCT 0x0008 /* (IRIX) project quota accounting ON */
-#define XFS_GQUOTA_ENFD 0x0010 /* group quota limits enforced */
-#define XFS_GQUOTA_CHKD 0x0020 /* quotacheck run on grp quotas */
+#define XFS_PQUOTA_ACCT 0x0008 /* project quota accounting ON */
+#define XFS_OQUOTA_ENFD 0x0010 /* other (grp/prj) quota limits enforced */
+#define XFS_OQUOTA_CHKD 0x0020 /* quotacheck run on other (grp/prj) quotas */
#define XFS_GQUOTA_ACCT 0x0040 /* group quota accounting ON */
/*
* are in the process of getting turned off. These flags are in m_qflags but
* never in sb_qflags.
*/
-#define XFS_UQUOTA_ACTIVE 0x0080 /* uquotas are being turned off */
-#define XFS_GQUOTA_ACTIVE 0x0100 /* gquotas are being turned off */
+#define XFS_UQUOTA_ACTIVE 0x0100 /* uquotas are being turned off */
+#define XFS_PQUOTA_ACTIVE 0x0200 /* pquotas are being turned off */
+#define XFS_GQUOTA_ACTIVE 0x0400 /* gquotas are being turned off */
/*
* Checking XFS_IS_*QUOTA_ON() while holding any inode lock guarantees
* quota will be not be switched off as long as that inode lock is held.
*/
#define XFS_IS_QUOTA_ON(mp) ((mp)->m_qflags & (XFS_UQUOTA_ACTIVE | \
- XFS_GQUOTA_ACTIVE))
+ XFS_GQUOTA_ACTIVE | \
+ XFS_PQUOTA_ACTIVE))
+#define XFS_IS_OQUOTA_ON(mp) ((mp)->m_qflags & (XFS_GQUOTA_ACTIVE | \
+ XFS_PQUOTA_ACTIVE))
#define XFS_IS_UQUOTA_ON(mp) ((mp)->m_qflags & XFS_UQUOTA_ACTIVE)
#define XFS_IS_GQUOTA_ON(mp) ((mp)->m_qflags & XFS_GQUOTA_ACTIVE)
+#define XFS_IS_PQUOTA_ON(mp) ((mp)->m_qflags & XFS_PQUOTA_ACTIVE)
/*
* Flags to tell various functions what to do. Not all of these are meaningful
#define XFS_QMOPT_DQLOCK 0x0000001 /* dqlock */
#define XFS_QMOPT_DQALLOC 0x0000002 /* alloc dquot ondisk if needed */
#define XFS_QMOPT_UQUOTA 0x0000004 /* user dquot requested */
-#define XFS_QMOPT_GQUOTA 0x0000008 /* group dquot requested */
+#define XFS_QMOPT_PQUOTA 0x0000008 /* project dquot requested */
#define XFS_QMOPT_FORCE_RES 0x0000010 /* ignore quota limits */
#define XFS_QMOPT_DQSUSER 0x0000020 /* don't cache super users dquot */
#define XFS_QMOPT_SBVERSION 0x0000040 /* change superblock version num */
#define XFS_QMOPT_DOWARN 0x0000400 /* increase warning cnt if necessary */
#define XFS_QMOPT_ILOCKED 0x0000800 /* inode is already locked (excl) */
#define XFS_QMOPT_DQREPAIR 0x0001000 /* repair dquot, if damaged. */
+#define XFS_QMOPT_GQUOTA 0x0002000 /* group dquot requested */
/*
* flags to xfs_trans_mod_dquot to indicate which field needs to be
#define XFS_TRANS_DQ_DELRTBCOUNT XFS_QMOPT_DELRTBCOUNT
-#define XFS_QMOPT_QUOTALL (XFS_QMOPT_UQUOTA|XFS_QMOPT_GQUOTA)
+#define XFS_QMOPT_QUOTALL \
+ (XFS_QMOPT_UQUOTA | XFS_QMOPT_PQUOTA | XFS_QMOPT_GQUOTA)
#define XFS_QMOPT_RESBLK_MASK (XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_RES_RTBLKS)
#ifdef __KERNEL__
*/
#define XFS_NOT_DQATTACHED(mp, ip) ((XFS_IS_UQUOTA_ON(mp) &&\
(ip)->i_udquot == NULL) || \
- (XFS_IS_GQUOTA_ON(mp) && \
+ (XFS_IS_OQUOTA_ON(mp) && \
(ip)->i_gdquot == NULL))
-#define XFS_QM_NEED_QUOTACHECK(mp) ((XFS_IS_UQUOTA_ON(mp) && \
- (mp->m_sb.sb_qflags & \
- XFS_UQUOTA_CHKD) == 0) || \
- (XFS_IS_GQUOTA_ON(mp) && \
- (mp->m_sb.sb_qflags & \
- XFS_GQUOTA_CHKD) == 0))
+#define XFS_QM_NEED_QUOTACHECK(mp) \
+ ((XFS_IS_UQUOTA_ON(mp) && \
+ (mp->m_sb.sb_qflags & XFS_UQUOTA_CHKD) == 0) || \
+ (XFS_IS_GQUOTA_ON(mp) && \
+ ((mp->m_sb.sb_qflags & XFS_OQUOTA_CHKD) == 0 || \
+ (mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT))) || \
+ (XFS_IS_PQUOTA_ON(mp) && \
+ ((mp->m_sb.sb_qflags & XFS_OQUOTA_CHKD) == 0 || \
+ (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT))))
+
+#define XFS_MOUNT_QUOTA_SET1 (XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\
+ XFS_UQUOTA_CHKD|XFS_PQUOTA_ACCT|\
+ XFS_OQUOTA_ENFD|XFS_OQUOTA_CHKD)
+
+#define XFS_MOUNT_QUOTA_SET2 (XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\
+ XFS_UQUOTA_CHKD|XFS_GQUOTA_ACCT|\
+ XFS_OQUOTA_ENFD|XFS_OQUOTA_CHKD)
#define XFS_MOUNT_QUOTA_ALL (XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\
- XFS_UQUOTA_CHKD|XFS_GQUOTA_ACCT|\
- XFS_GQUOTA_ENFD|XFS_GQUOTA_CHKD)
+ XFS_UQUOTA_CHKD|XFS_PQUOTA_ACCT|\
+ XFS_OQUOTA_ENFD|XFS_OQUOTA_CHKD|\
+ XFS_GQUOTA_ACCT)
#define XFS_MOUNT_QUOTA_MASK (XFS_MOUNT_QUOTA_ALL | XFS_UQUOTA_ACTIVE | \
- XFS_GQUOTA_ACTIVE)
+ XFS_GQUOTA_ACTIVE | XFS_PQUOTA_ACTIVE)
/*
#define XFS_TRANS_UNRESERVE_AND_MOD_DQUOTS(mp, tp) \
XFS_DQTRXOP_VOID(mp, tp, qo_unreserve_and_mod_dquots)
-#define XFS_TRANS_RESERVE_BLKQUOTA(mp, tp, ip, nblks) \
- XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, tp, ip, nblks, 0, \
- XFS_QMOPT_RES_REGBLKS)
-#define XFS_TRANS_RESERVE_BLKQUOTA_FORCE(mp, tp, ip, nblks) \
- XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, tp, ip, nblks, 0, \
- XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES)
-#define XFS_TRANS_UNRESERVE_BLKQUOTA(mp, tp, ip, nblks) \
- XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, tp, ip, -(nblks), 0, \
- XFS_QMOPT_RES_REGBLKS)
+#define XFS_TRANS_UNRESERVE_QUOTA_NBLKS(mp, tp, ip, nblks, ninos, flags) \
+ XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, tp, ip, -(nblks), -(ninos), flags)
#define XFS_TRANS_RESERVE_QUOTA(mp, tp, ud, gd, nb, ni, f) \
XFS_TRANS_RESERVE_QUOTA_BYDQUOTS(mp, tp, ud, gd, nb, ni, \
f | XFS_QMOPT_RES_REGBLKS)
return 0;
}
-
-int rename_which_error_return = 0;
-
/*
* xfs_rename
*/
&num_inodes);
if (error) {
- rename_which_error_return = __LINE__;
/*
* We have nothing locked, no inode references, and
* no transaction, so just get out.
*/
if (target_ip == NULL && (src_dp != target_dp) &&
target_dp->i_d.di_nlink >= XFS_MAXLINK) {
- rename_which_error_return = __LINE__;
error = XFS_ERROR(EMLINK);
xfs_rename_unlock4(inodes, XFS_ILOCK_SHARED);
goto rele_return;
XFS_TRANS_PERM_LOG_RES, XFS_RENAME_LOG_COUNT);
}
if (error) {
- rename_which_error_return = __LINE__;
xfs_trans_cancel(tp, 0);
goto rele_return;
}
*/
if ((error = XFS_QM_DQVOPRENAME(mp, inodes))) {
xfs_trans_cancel(tp, cancel_flags);
- rename_which_error_return = __LINE__;
goto rele_return;
}
if (spaceres == 0 &&
(error = XFS_DIR_CANENTER(mp, tp, target_dp, target_name,
target_namelen))) {
- rename_which_error_return = __LINE__;
goto error_return;
}
/*
target_namelen, src_ip->i_ino,
&first_block, &free_list, spaceres);
if (error == ENOSPC) {
- rename_which_error_return = __LINE__;
goto error_return;
}
if (error) {
- rename_which_error_return = __LINE__;
goto abort_return;
}
xfs_ichgtime(target_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
if (new_parent && src_is_directory) {
error = xfs_bumplink(tp, target_dp);
if (error) {
- rename_which_error_return = __LINE__;
goto abort_return;
}
}
if (!(XFS_DIR_ISEMPTY(target_ip->i_mount, target_ip)) ||
(target_ip->i_d.di_nlink > 2)) {
error = XFS_ERROR(EEXIST);
- rename_which_error_return = __LINE__;
goto error_return;
}
}
target_namelen, src_ip->i_ino, &first_block,
&free_list, spaceres);
if (error) {
- rename_which_error_return = __LINE__;
goto abort_return;
}
xfs_ichgtime(target_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
*/
error = xfs_droplink(tp, target_ip);
if (error) {
- rename_which_error_return = __LINE__;
goto abort_return;
}
target_ip_dropped = 1;
*/
error = xfs_droplink(tp, target_ip);
if (error) {
- rename_which_error_return = __LINE__;
goto abort_return;
}
}
&free_list, spaceres);
ASSERT(error != EEXIST);
if (error) {
- rename_which_error_return = __LINE__;
goto abort_return;
}
xfs_ichgtime(src_ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
*/
error = xfs_droplink(tp, src_dp);
if (error) {
- rename_which_error_return = __LINE__;
goto abort_return;
}
}
error = XFS_DIR_REMOVENAME(mp, tp, src_dp, src_name, src_namelen,
src_ip->i_ino, &first_block, &free_list, spaceres);
if (error) {
- rename_which_error_return = __LINE__;
goto abort_return;
}
xfs_ichgtime(src_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
}
-/*
- * This is called to set the a callback to be called when the given
- * transaction is committed to disk. The transaction pointer and the
- * argument pointer will be passed to the callback routine.
- *
- * Only one callback can be associated with any single transaction.
- */
-void
-xfs_trans_callback(
- xfs_trans_t *tp,
- xfs_trans_callback_t callback,
- void *arg)
-{
- ASSERT(tp->t_callback == NULL);
- tp->t_callback = callback;
- tp->t_callarg = arg;
-}
-
-
/*
* Record the indicated change to the given field for application
* to the file system's superblock when the transaction commits.
*
* This is done efficiently with a single call to xfs_mod_incore_sb_batch().
*/
-void
+STATIC void
xfs_trans_unreserve_and_mod_sb(
xfs_trans_t *tp)
{
xfs_trans_t *xfs_trans_dup(xfs_trans_t *);
int xfs_trans_reserve(xfs_trans_t *, uint, uint, uint,
uint, uint);
-void xfs_trans_callback(xfs_trans_t *,
- void (*)(xfs_trans_t *, void *), void *);
void xfs_trans_mod_sb(xfs_trans_t *, uint, long);
struct xfs_buf *xfs_trans_get_buf(xfs_trans_t *, struct xfs_buftarg *, xfs_daddr_t,
int, uint);
xfs_ino_t , uint, uint, struct xfs_inode **);
void xfs_trans_ijoin(xfs_trans_t *, struct xfs_inode *, uint);
void xfs_trans_ihold(xfs_trans_t *, struct xfs_inode *);
-void xfs_trans_ihold_release(xfs_trans_t *, struct xfs_inode *);
void xfs_trans_log_buf(xfs_trans_t *, struct xfs_buf *, uint, uint);
void xfs_trans_log_inode(xfs_trans_t *, struct xfs_inode *, uint);
struct xfs_efi_log_item *xfs_trans_get_efi(xfs_trans_t *, uint);
ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp);
ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL);
ASSERT(type == XFS_BLI_UDQUOT_BUF ||
+ type == XFS_BLI_PDQUOT_BUF ||
type == XFS_BLI_GDQUOT_BUF);
bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *);
ip->i_itemp->ili_flags |= XFS_ILI_HOLD;
}
-/*
- * Cancel the previous inode hold request made on this inode
- * for this transaction.
- */
-/*ARGSUSED*/
-void
-xfs_trans_ihold_release(
- xfs_trans_t *tp,
- xfs_inode_t *ip)
-{
- ASSERT(ip->i_transp == tp);
- ASSERT(ip->i_itemp != NULL);
- ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE));
- ASSERT(ip->i_itemp->ili_flags & XFS_ILI_HOLD);
-
- ip->i_itemp->ili_flags &= ~XFS_ILI_HOLD;
-}
-
/*
* This is called to mark the fields indicated in fieldmask as needing
typedef unsigned long long int __uint64_t;
typedef enum { B_FALSE,B_TRUE } boolean_t;
-typedef __int64_t prid_t; /* project ID */
+typedef __uint32_t prid_t; /* project ID */
typedef __uint32_t inst_t; /* an instruction */
typedef __s64 xfs_off_t; /* <file offset> type */
if (ip->i_ino != mp->m_sb.sb_uquotino)
ASSERT(ip->i_udquot);
}
- if (XFS_IS_GQUOTA_ON(mp)) {
+ if (XFS_IS_OQUOTA_ON(mp)) {
if (ip->i_ino != mp->m_sb.sb_gquotino)
ASSERT(ip->i_gdquot);
}
return XFS_ERROR(EROFS);
}
- /*
- * disallow mount attempts with (IRIX) project quota enabled
- */
- if (XFS_SB_VERSION_HASQUOTA(&mp->m_sb) &&
- (mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT)) {
- cmn_err(CE_WARN,
- "XFS: cannot mount a filesystem with IRIX project quota enabled");
- return XFS_ERROR(ENOSYS);
- }
-
/*
* check for shared mount.
*/
return XFS_ERROR(error);
}
-#define REMOUNT_READONLY_FLAGS (SYNC_REMOUNT|SYNC_ATTR|SYNC_WAIT)
+STATIC int
+xfs_quiesce_fs(
+ xfs_mount_t *mp)
+{
+ int count = 0, pincount;
+
+ xfs_refcache_purge_mp(mp);
+ xfs_flush_buftarg(mp->m_ddev_targp, 0);
+ xfs_finish_reclaim_all(mp, 0);
+
+ /* This loop must run at least twice.
+ * The first instance of the loop will flush
+ * most meta data but that will generate more
+ * meta data (typically directory updates).
+ * Which then must be flushed and logged before
+ * we can write the unmount record.
+ */
+ do {
+ xfs_syncsub(mp, SYNC_REMOUNT|SYNC_ATTR|SYNC_WAIT, 0, NULL);
+ pincount = xfs_flush_buftarg(mp->m_ddev_targp, 1);
+ if (!pincount) {
+ delay(50);
+ count++;
+ }
+ } while (count < 2);
+
+ return 0;
+}
STATIC int
xfs_mntupdate(
{
struct vfs *vfsp = bhvtovfs(bdp);
xfs_mount_t *mp = XFS_BHVTOM(bdp);
- int pincount, error;
- int count = 0;
+ int error;
if (args->flags & XFSMNT_NOATIME)
mp->m_flags |= XFS_MOUNT_NOATIME;
}
if (*flags & MS_RDONLY) {
- xfs_refcache_purge_mp(mp);
- xfs_flush_buftarg(mp->m_ddev_targp, 0);
- xfs_finish_reclaim_all(mp, 0);
-
- /* This loop must run at least twice.
- * The first instance of the loop will flush
- * most meta data but that will generate more
- * meta data (typically directory updates).
- * Which then must be flushed and logged before
- * we can write the unmount record.
- */
- do {
- VFS_SYNC(vfsp, REMOUNT_READONLY_FLAGS, NULL, error);
- pincount = xfs_flush_buftarg(mp->m_ddev_targp, 1);
- if (!pincount) {
- delay(50);
- count++;
- }
- } while (count < 2);
+ xfs_quiesce_fs(mp);
/* Ok now write out an unmount record */
xfs_log_unmount_write(mp);
int flags,
cred_t *credp)
{
- xfs_mount_t *mp;
+ xfs_mount_t *mp = XFS_BHVTOM(bdp);
- mp = XFS_BHVTOM(bdp);
- return (xfs_syncsub(mp, flags, 0, NULL));
+ if (unlikely(flags == SYNC_QUIESCE))
+ return xfs_quiesce_fs(mp);
+ else
+ return xfs_syncsub(mp, flags, 0, NULL);
}
/*
return simple_strtoul(cp, endp, base) << shift_left_factor;
}
-int
+STATIC int
xfs_parseargs(
struct bhv_desc *bhv,
char *options,
return 0;
}
-int
+STATIC int
xfs_showargs(
struct bhv_desc *bhv,
struct seq_file *m)
/*
- * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved.
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* If the IDs do change before we take the ilock, we're covered
* because the i_*dquot fields will get updated anyway.
*/
- if (XFS_IS_QUOTA_ON(mp) && (mask & (XFS_AT_UID|XFS_AT_GID))) {
+ if (XFS_IS_QUOTA_ON(mp) &&
+ (mask & (XFS_AT_UID|XFS_AT_GID|XFS_AT_PROJID))) {
uint qflags = 0;
- if (mask & XFS_AT_UID) {
+ if ((mask & XFS_AT_UID) && XFS_IS_UQUOTA_ON(mp)) {
uid = vap->va_uid;
qflags |= XFS_QMOPT_UQUOTA;
} else {
uid = ip->i_d.di_uid;
}
- if (mask & XFS_AT_GID) {
+ if ((mask & XFS_AT_GID) && XFS_IS_GQUOTA_ON(mp)) {
gid = vap->va_gid;
qflags |= XFS_QMOPT_GQUOTA;
} else {
gid = ip->i_d.di_gid;
}
+ if ((mask & XFS_AT_PROJID) && XFS_IS_PQUOTA_ON(mp)) {
+ projid = vap->va_projid;
+ qflags |= XFS_QMOPT_PQUOTA;
+ } else {
+ projid = ip->i_d.di_projid;
+ }
/*
* We take a reference when we initialize udqp and gdqp,
* so it is important that we never blindly double trip on
*/
ASSERT(udqp == NULL);
ASSERT(gdqp == NULL);
- code = XFS_QM_DQVOPALLOC(mp, ip, uid,gid, qflags, &udqp, &gdqp);
+ code = XFS_QM_DQVOPALLOC(mp, ip, uid, gid, projid, qflags,
+ &udqp, &gdqp);
if (code)
return (code);
}
* that the group ID supplied to the chown() function
* shall be equal to either the group ID or one of the
* supplementary group IDs of the calling process.
- *
- * XXX: How does restricted_chown affect projid?
*/
if (restricted_chown &&
(iuid != uid || (igid != gid &&
goto error_return;
}
/*
- * Do a quota reservation only if uid or gid is actually
+ * Do a quota reservation only if uid/projid/gid is actually
* going to change.
*/
if ((XFS_IS_UQUOTA_ON(mp) && iuid != uid) ||
+ (XFS_IS_PQUOTA_ON(mp) && iprojid != projid) ||
(XFS_IS_GQUOTA_ON(mp) && igid != gid)) {
ASSERT(tp);
code = XFS_QM_DQVOPCHOWNRESV(mp, tp, ip, udqp, gdqp,
}
if (igid != gid) {
if (XFS_IS_GQUOTA_ON(mp)) {
+ ASSERT(!XFS_IS_PQUOTA_ON(mp));
ASSERT(mask & XFS_AT_GID);
ASSERT(gdqp);
olddquot2 = XFS_QM_DQVOPCHOWN(mp, tp, ip,
ip->i_d.di_gid = gid;
}
if (iprojid != projid) {
+ if (XFS_IS_PQUOTA_ON(mp)) {
+ ASSERT(!XFS_IS_GQUOTA_ON(mp));
+ ASSERT(mask & XFS_AT_PROJID);
+ ASSERT(gdqp);
+ olddquot2 = XFS_QM_DQVOPCHOWN(mp, tp, ip,
+ &ip->i_gdquot, gdqp);
+ }
ip->i_d.di_projid = projid;
/*
* We may have to rev the inode as well as
di_flags |= XFS_DIFLAG_NOATIME;
if (vap->va_xflags & XFS_XFLAG_NODUMP)
di_flags |= XFS_DIFLAG_NODUMP;
+ if (vap->va_xflags & XFS_XFLAG_PROJINHERIT)
+ di_flags |= XFS_DIFLAG_PROJINHERIT;
if ((ip->i_d.di_mode & S_IFMT) == S_IFDIR) {
if (vap->va_xflags & XFS_XFLAG_RTINHERIT)
di_flags |= XFS_DIFLAG_RTINHERIT;
/* Return through std_return after this point. */
udqp = gdqp = NULL;
- if (vap->va_mask & XFS_AT_PROJID)
+ if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)
+ prid = dp->i_d.di_projid;
+ else if (vap->va_mask & XFS_AT_PROJID)
prid = (xfs_prid_t)vap->va_projid;
else
prid = (xfs_prid_t)dfltprid;
* Make sure that we have allocated dquot(s) on disk.
*/
error = XFS_QM_DQVOPALLOC(mp, dp,
- current_fsuid(credp), current_fsgid(credp),
+ current_fsuid(credp), current_fsgid(credp), prid,
XFS_QMOPT_QUOTALL|XFS_QMOPT_INHERIT, &udqp, &gdqp);
if (error)
goto std_return;
if (src_vp->v_type == VDIR)
return XFS_ERROR(EPERM);
- /*
- * For now, manually find the XFS behavior descriptor for
- * the source vnode. If it doesn't exist then something
- * is wrong and we should just return an error.
- * Eventually we need to figure out how link is going to
- * work in the face of stacked vnodes.
- */
src_bdp = vn_bhv_lookup_unlocked(VN_BHV_HEAD(src_vp), &xfs_vnodeops);
- if (src_bdp == NULL) {
- return XFS_ERROR(EXDEV);
- }
sip = XFS_BHVTOI(src_bdp);
tdp = XFS_BHVTOI(target_dir_bdp);
mp = tdp->i_mount;
goto error_return;
}
+ /*
+ * If we are using project inheritance, we only allow hard link
+ * creation in our tree when the project IDs are the same; else
+ * the tree quota mechanism could be circumvented.
+ */
+ if (unlikely((tdp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) &&
+ (tdp->i_d.di_projid != sip->i_d.di_projid))) {
+ error = XFS_ERROR(EPERM);
+ goto error_return;
+ }
+
if (resblks == 0 &&
(error = XFS_DIR_CANENTER(mp, tp, tdp, target_name,
target_namelen)))
mp = dp->i_mount;
udqp = gdqp = NULL;
- if (vap->va_mask & XFS_AT_PROJID)
+ if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)
+ prid = dp->i_d.di_projid;
+ else if (vap->va_mask & XFS_AT_PROJID)
prid = (xfs_prid_t)vap->va_projid;
else
prid = (xfs_prid_t)dfltprid;
* Make sure that we have allocated dquot(s) on disk.
*/
error = XFS_QM_DQVOPALLOC(mp, dp,
- current_fsuid(credp), current_fsgid(credp),
+ current_fsuid(credp), current_fsgid(credp), prid,
XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp);
if (error)
goto std_return;
/* Return through std_return after this point. */
udqp = gdqp = NULL;
- if (vap->va_mask & XFS_AT_PROJID)
+ if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)
+ prid = dp->i_d.di_projid;
+ else if (vap->va_mask & XFS_AT_PROJID)
prid = (xfs_prid_t)vap->va_projid;
else
prid = (xfs_prid_t)dfltprid;
* Make sure that we have allocated dquot(s) on disk.
*/
error = XFS_QM_DQVOPALLOC(mp, dp,
- current_fsuid(credp), current_fsgid(credp),
+ current_fsuid(credp), current_fsgid(credp), prid,
XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp);
if (error)
goto std_return;
* errno on error
*
*/
-int
+STATIC int
xfs_alloc_file_space(
xfs_inode_t *ip,
xfs_off_t offset,
break;
}
xfs_ilock(ip, XFS_ILOCK_EXCL);
- error = XFS_TRANS_RESERVE_QUOTA_BYDQUOTS(mp, tp,
- ip->i_udquot, ip->i_gdquot, resblks, 0, rt ?
- XFS_QMOPT_RES_RTBLKS : XFS_QMOPT_RES_REGBLKS);
+ error = XFS_TRANS_RESERVE_QUOTA(mp, tp,
+ ip->i_udquot, ip->i_gdquot, resblks, 0, 0);
if (error)
goto error1;
xfs_off_t len,
int attr_flags)
{
+ vnode_t *vp;
int committed;
int done;
xfs_off_t end_dmi_offset;
xfs_trans_t *tp;
int need_iolock = 1;
- vn_trace_entry(XFS_ITOV(ip), __FUNCTION__, (inst_t *)__return_address);
+ vp = XFS_ITOV(ip);
mp = ip->i_mount;
+ vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address);
+
if ((error = XFS_QM_DQATTACH(mp, ip, 0)))
return error;
DM_EVENT_ENABLED(XFS_MTOVFS(mp), ip, DM_EVENT_WRITE)) {
if (end_dmi_offset > ip->i_d.di_size)
end_dmi_offset = ip->i_d.di_size;
- error = XFS_SEND_DATA(mp, DM_EVENT_WRITE, XFS_ITOV(ip),
+ error = XFS_SEND_DATA(mp, DM_EVENT_WRITE, vp,
offset, end_dmi_offset - offset,
AT_DELAY_FLAG(attr_flags), NULL);
if (error)
ioffset = offset & ~(rounding - 1);
if (ilen & (rounding - 1))
ilen = (ilen + rounding) & ~(rounding - 1);
- xfs_inval_cached_pages(XFS_ITOV(ip), &(ip->i_iocore), ioffset, 0, 0);
+
+ if (VN_CACHED(vp) != 0) {
+ xfs_inval_cached_trace(&ip->i_iocore, ioffset, -1,
+ ctooff(offtoct(ioffset)), -1);
+ VOP_FLUSHINVAL_PAGES(vp, ctooff(offtoct(ioffset)),
+ -1, FI_REMAPF_LOCKED);
+ }
+
/*
* Need to zero the stuff we're not freeing, on disk.
* If its a realtime file & can't use unwritten extents then we
#define PROC_CHANGE_PENALTY 20
#define hard_smp_processor_id() __hard_smp_processor_id()
-#define smp_processor_id() (current_thread_info()->cpu)
+#define raw_smp_processor_id() (current_thread_info()->cpu)
extern cpumask_t cpu_present_mask;
extern cpumask_t cpu_online_map;
#ifndef __ASM_ARCH_TPS65010_H
#define __ASM_ARCH_TPS65010_H
+/*
+ * ----------------------------------------------------------------------------
+ * Registers, all 8 bits
+ * ----------------------------------------------------------------------------
+ */
+
+#define TPS_CHGSTATUS 0x01
+# define TPS_CHG_USB (1 << 7)
+# define TPS_CHG_AC (1 << 6)
+# define TPS_CHG_THERM (1 << 5)
+# define TPS_CHG_TERM (1 << 4)
+# define TPS_CHG_TAPER_TMO (1 << 3)
+# define TPS_CHG_CHG_TMO (1 << 2)
+# define TPS_CHG_PRECHG_TMO (1 << 1)
+# define TPS_CHG_TEMP_ERR (1 << 0)
+#define TPS_REGSTATUS 0x02
+# define TPS_REG_ONOFF (1 << 7)
+# define TPS_REG_COVER (1 << 6)
+# define TPS_REG_UVLO (1 << 5)
+# define TPS_REG_NO_CHG (1 << 4) /* tps65013 */
+# define TPS_REG_PG_LD02 (1 << 3)
+# define TPS_REG_PG_LD01 (1 << 2)
+# define TPS_REG_PG_MAIN (1 << 1)
+# define TPS_REG_PG_CORE (1 << 0)
+#define TPS_MASK1 0x03
+#define TPS_MASK2 0x04
+#define TPS_ACKINT1 0x05
+#define TPS_ACKINT2 0x06
+#define TPS_CHGCONFIG 0x07
+# define TPS_CHARGE_POR (1 << 7) /* 65010/65012 */
+# define TPS65013_AUA (1 << 7) /* 65011/65013 */
+# define TPS_CHARGE_RESET (1 << 6)
+# define TPS_CHARGE_FAST (1 << 5)
+# define TPS_CHARGE_CURRENT (3 << 3)
+# define TPS_VBUS_500MA (1 << 2)
+# define TPS_VBUS_CHARGING (1 << 1)
+# define TPS_CHARGE_ENABLE (1 << 0)
+#define TPS_LED1_ON 0x08
+#define TPS_LED1_PER 0x09
+#define TPS_LED2_ON 0x0a
+#define TPS_LED2_PER 0x0b
+#define TPS_VDCDC1 0x0c
+# define TPS_ENABLE_LP (1 << 3)
+#define TPS_VDCDC2 0x0d
+#define TPS_VREGS1 0x0e
+# define TPS_LDO2_ENABLE (1 << 7)
+# define TPS_LDO2_OFF (1 << 6)
+# define TPS_VLDO2_3_0V (3 << 4)
+# define TPS_VLDO2_2_75V (2 << 4)
+# define TPS_VLDO2_2_5V (1 << 4)
+# define TPS_VLDO2_1_8V (0 << 4)
+# define TPS_LDO1_ENABLE (1 << 3)
+# define TPS_LDO1_OFF (1 << 2)
+# define TPS_VLDO1_3_0V (3 << 0)
+# define TPS_VLDO1_2_75V (2 << 0)
+# define TPS_VLDO1_2_5V (1 << 0)
+# define TPS_VLDO1_ADJ (0 << 0)
+#define TPS_MASK3 0x0f
+#define TPS_DEFGPIO 0x10
+
/*
* ----------------------------------------------------------------------------
* Macros used by exported functions
*/
extern int tps65010_set_led(unsigned led, unsigned mode);
+/* tps65010_set_vib parameter:
+ * value: ON or OFF
+ */
+extern int tps65010_set_vib(unsigned value);
+
/* tps65010_set_low_pwr parameter:
* mode: ON or OFF
*/
extern int tps65010_set_low_pwr(unsigned mode);
+/* tps65010_config_vregs1 parameter:
+ * value to be written to VREGS1 register
+ * Note: The complete register is written, set all bits you need
+ */
+extern int tps65010_config_vregs1(unsigned value);
+
+/* tps65013_set_low_pwr parameter:
+ * mode: ON or OFF
+ */
+extern int tps65013_set_low_pwr(unsigned mode);
+
#endif /* __ASM_ARCH_TPS65010_H */
# error "<asm-arm/smp.h> included in non-SMP build"
#endif
-#define smp_processor_id() (current_thread_info()->cpu)
+#define raw_smp_processor_id() (current_thread_info()->cpu)
extern cpumask_t cpu_present_mask;
#define cpu_possible_map cpu_present_mask
({ \
unsigned long flags; \
local_save_flags(flags); \
- flags & PSR_I_BIT; \
+ (int)(flags & PSR_I_BIT); \
})
#ifdef CONFIG_SMP
#ifndef __HAVE_ARCH_PAGE_TEST_AND_CLEAR_DIRTY
#define page_test_and_clear_dirty(page) (0)
+#define pte_maybe_dirty(pte) pte_dirty(pte)
+#else
+#define pte_maybe_dirty(pte) (1)
#endif
#ifndef __HAVE_ARCH_PAGE_TEST_AND_CLEAR_YOUNG
#define HPAGE_MASK (~(HPAGE_SIZE - 1))
#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT)
#define HAVE_ARCH_HUGETLB_UNMAPPED_AREA
+#define ARCH_HAS_HUGETLB_CLEAN_STALE_PGTABLE
#endif
#define pgd_val(x) ((x).pgd)
static inline pte_t pte_mkdirty(pte_t pte) { (pte).pte_low |= _PAGE_DIRTY; return pte; }
static inline pte_t pte_mkyoung(pte_t pte) { (pte).pte_low |= _PAGE_ACCESSED; return pte; }
static inline pte_t pte_mkwrite(pte_t pte) { (pte).pte_low |= _PAGE_RW; return pte; }
+static inline pte_t pte_mkhuge(pte_t pte) { (pte).pte_low |= _PAGE_PRESENT | _PAGE_PSE; return pte; }
#ifdef CONFIG_X86_PAE
# include <asm/pgtable-3level.h>
*/
#define mk_pte(page, pgprot) pfn_pte(page_to_pfn(page), (pgprot))
-#define mk_pte_huge(entry) ((entry).pte_low |= _PAGE_PRESENT | _PAGE_PSE)
static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
{
* from the initial startup. We map APIC_BASE very early in page_setup(),
* so this is correct in the x86 case.
*/
-#define __smp_processor_id() (current_thread_info()->cpu)
+#define raw_smp_processor_id() (current_thread_info()->cpu)
extern cpumask_t cpu_callout_map;
extern cpumask_t cpu_callin_map;
#define __NR_io_submit 248
#define __NR_io_cancel 249
#define __NR_fadvise64 250
-
+#define __NR_set_zone_reclaim 251
#define __NR_exit_group 252
#define __NR_lookup_dcookie 253
#define __NR_epoll_create 254
#include <asm/page.h>
#include <asm/meminit.h>
+static inline int pfn_to_nid(unsigned long pfn)
+{
+#ifdef CONFIG_NUMA
+ extern int paddr_to_nid(unsigned long);
+ int nid = paddr_to_nid(pfn << PAGE_SHIFT);
+ if (nid < 0)
+ return 0;
+ else
+ return nid;
+#else
+ return 0;
+#endif
+}
+
#ifdef CONFIG_DISCONTIGMEM
#ifdef CONFIG_IA64_DIG /* DIG systems are small */
#define pte_mkyoung(pte) (__pte(pte_val(pte) | _PAGE_A))
#define pte_mkclean(pte) (__pte(pte_val(pte) & ~_PAGE_D))
#define pte_mkdirty(pte) (__pte(pte_val(pte) | _PAGE_D))
+#define pte_mkhuge(pte) (__pte(pte_val(pte) | _PAGE_P))
/*
* Macro to a page protection value as "uncacheable". Note that "protection" is really a
#define SMP_IRQ_REDIRECTION (1 << 0)
#define SMP_IPI_REDIRECTION (1 << 1)
-#define smp_processor_id() (current_thread_info()->cpu)
+#define raw_smp_processor_id() (current_thread_info()->cpu)
extern struct smp_boot_data {
int cpu_count;
--- /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) 2001-2004 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#ifndef _ASM_IA64_SN_MSPEC_H
+#define _ASM_IA64_SN_MSPEC_H
+
+#define FETCHOP_VAR_SIZE 64 /* 64 byte per fetchop variable */
+
+#define FETCHOP_LOAD 0
+#define FETCHOP_INCREMENT 8
+#define FETCHOP_DECREMENT 16
+#define FETCHOP_CLEAR 24
+
+#define FETCHOP_STORE 0
+#define FETCHOP_AND 24
+#define FETCHOP_OR 32
+
+#define FETCHOP_CLEAR_CACHE 56
+
+#define FETCHOP_LOAD_OP(addr, op) ( \
+ *(volatile long *)((char*) (addr) + (op)))
+
+#define FETCHOP_STORE_OP(addr, op, x) ( \
+ *(volatile long *)((char*) (addr) + (op)) = (long) (x))
+
+#ifdef __KERNEL__
+
+/*
+ * Each Atomic Memory Operation (AMO formerly known as fetchop)
+ * variable is 64 bytes long. The first 8 bytes are used. The
+ * remaining 56 bytes are unaddressable due to the operation taking
+ * that portion of the address.
+ *
+ * NOTE: The AMO_t _MUST_ be placed in either the first or second half
+ * of the cache line. The cache line _MUST NOT_ be used for anything
+ * other than additional AMO_t entries. This is because there are two
+ * addresses which reference the same physical cache line. One will
+ * be a cached entry with the memory type bits all set. This address
+ * may be loaded into processor cache. The AMO_t will be referenced
+ * uncached via the memory special memory type. If any portion of the
+ * cached cache-line is modified, when that line is flushed, it will
+ * overwrite the uncached value in physical memory and lead to
+ * inconsistency.
+ */
+typedef struct {
+ u64 variable;
+ u64 unused[7];
+} AMO_t;
+
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_IA64_SN_MSPEC_H */
--- /dev/null
+/*
+ * Copyright (C) 2001-2005 Silicon Graphics, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * Prototypes for the uncached page allocator
+ */
+
+extern unsigned long uncached_alloc_page(int nid);
+extern void uncached_free_page(unsigned long);
#define __NR_add_key 1271
#define __NR_request_key 1272
#define __NR_keyctl 1273
+#define __NR_set_zone_reclaim 1276
#ifdef __KERNEL__
-#ifndef _ASM_M32R_DIV64
-#define _ASM_M32R_DIV64
-
-/* $Id$ */
-
-/* unsigned long long division.
- * Input:
- * unsigned long long n
- * unsigned long base
- * Output:
- * n = n / base;
- * return value = n % base;
- */
-#define do_div(n, base) \
-({ \
- unsigned long _res, _high, _mid, _low; \
- \
- _low = (n) & 0xffffffffUL; \
- _high = (n) >> 32; \
- if (_high) { \
- _mid = (_high % (unsigned long)(base)) << 16; \
- _high = _high / (unsigned long)(base); \
- _mid += _low >> 16; \
- _low &= 0x0000ffffUL; \
- _low += (_mid % (unsigned long)(base)) << 16; \
- _mid = _mid / (unsigned long)(base); \
- _res = _low % (unsigned long)(base); \
- _low = _low / (unsigned long)(base); \
- n = _low + ((long long)_mid << 16) + \
- ((long long)_high << 32); \
- } else { \
- _res = _low % (unsigned long)(base); \
- n = (_low / (unsigned long)(base)); \
- } \
- _res; \
-})
-
-#endif /* _ASM_M32R_DIV64 */
+#include <asm-generic/div64.h>
static __inline__ int ide_default_irq(unsigned long base)
{
switch (base) {
-#if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_MAPPI2)
+#if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_MAPPI2) || defined(CONFIG_PLAT_MAPPI3)
case 0x1f0: return PLD_IRQ_CFIREQ;
default:
return 0;
#define M32R_ICU_CR5_PORTL (0x210+M32R_ICU_OFFSET) /* INT4 */
#define M32R_ICU_CR6_PORTL (0x214+M32R_ICU_OFFSET) /* INT5 */
#define M32R_ICU_CR7_PORTL (0x218+M32R_ICU_OFFSET) /* INT6 */
+#define M32R_ICU_CR8_PORTL (0x219+M32R_ICU_OFFSET) /* INT7 */
#define M32R_ICU_CR16_PORTL (0x23C+M32R_ICU_OFFSET) /* MFT0 */
#define M32R_ICU_CR17_PORTL (0x240+M32R_ICU_OFFSET) /* MFT1 */
#define M32R_ICU_CR18_PORTL (0x244+M32R_ICU_OFFSET) /* MFT2 */
+++ /dev/null
-/* $Id$
- *
- * 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) 2000,2001 by Hiroyuki Kondo
- */
-
-#ifndef __ASSEMBLY__
-
-typedef void V;
-typedef char B;
-typedef short S;
-typedef int W;
-typedef long L;
-typedef float F;
-typedef double D;
-typedef unsigned char UB;
-typedef unsigned short US;
-typedef unsigned int UW;
-typedef unsigned long UL;
-typedef const unsigned int CUW;
-
-/*********************************
-
-M32102 ICU
-
-*********************************/
-#define ICUISTS (UW *)0xa0EFF004
-#define ICUIREQ0 (UW *)0xa0EFF008
-#define ICUIREQ1 (UW *)0xa0EFF00C
-
-#define ICUSBICR (UW *)0xa0EFF018
-#define ICUIMASK (UW *)0xa0EFF01C
-
-#define ICUCR1 (UW *)0xa0EFF200 /* INT0 */
-#define ICUCR2 (UW *)0xa0EFF204 /* INT1 */
-#define ICUCR3 (UW *)0xa0EFF208 /* INT2 */
-#define ICUCR4 (UW *)0xa0EFF20C /* INT3 */
-#define ICUCR5 (UW *)0xa0EFF210 /* INT4 */
-#define ICUCR6 (UW *)0xa0EFF214 /* INT5 */
-#define ICUCR7 (UW *)0xa0EFF218 /* INT6 */
-
-#define ICUCR16 (UW *)0xa0EFF23C /* MFT0 */
-#define ICUCR17 (UW *)0xa0EFF240 /* MFT1 */
-#define ICUCR18 (UW *)0xa0EFF244 /* MFT2 */
-#define ICUCR19 (UW *)0xa0EFF248 /* MFT3 */
-#define ICUCR20 (UW *)0xa0EFF24C /* MFT4 */
-#define ICUCR21 (UW *)0xa0EFF250 /* MFT5 */
-
-#define ICUCR32 (UW *)0xa0EFF27C /* DMA0 */
-#define ICUCR33 (UW *)0xa0EFF280 /* DMA1 */
-
-#define ICUCR48 (UW *)0xa0EFF2BC /* SIO0R */
-#define ICUCR49 (UW *)0xa0EFF2C0 /* SIO0S */
-#define ICUCR50 (UW *)0xa0EFF2C4 /* SIO1R */
-#define ICUCR51 (UW *)0xa0EFF2C8 /* SIO1S */
-#define ICUCR52 (UW *)0xa0EFF2CC /* SIO2R */
-#define ICUCR53 (UW *)0xa0EFF2D0 /* SIO2S */
-#define ICUCR54 (UW *)0xa0EFF2D4 /* SIO3R */
-#define ICUCR55 (UW *)0xa0EFF2D8 /* SIO3S */
-#define ICUCR56 (UW *)0xa0EFF2DC /* SIO4R */
-#define ICUCR57 (UW *)0xa0EFF2E0 /* SIO4S */
-
-/*********************************
-
-M32102 MFT
-
-*********************************/
-#define MFTCR (US *)0xa0EFC002
-#define MFTRPR (UB *)0xa0EFC006
-
-#define MFT0MOD (US *)0xa0EFC102
-#define MFT0BOS (US *)0xa0EFC106
-#define MFT0CUT (US *)0xa0EFC10A
-#define MFT0RLD (US *)0xa0EFC10E
-#define MFT0CRLD (US *)0xa0EFC112
-
-#define MFT1MOD (US *)0xa0EFC202
-#define MFT1BOS (US *)0xa0EFC206
-#define MFT1CUT (US *)0xa0EFC20A
-#define MFT1RLD (US *)0xa0EFC20E
-#define MFT1CRLD (US *)0xa0EFC212
-
-#define MFT2MOD (US *)0xa0EFC302
-#define MFT2BOS (US *)0xa0EFC306
-#define MFT2CUT (US *)0xa0EFC30A
-#define MFT2RLD (US *)0xa0EFC30E
-#define MFT2CRLD (US *)0xa0EFC312
-
-#define MFT3MOD (US *)0xa0EFC402
-#define MFT3CUT (US *)0xa0EFC40A
-#define MFT3RLD (US *)0xa0EFC40E
-#define MFT3CRLD (US *)0xa0EFC412
-
-#define MFT4MOD (US *)0xa0EFC502
-#define MFT4CUT (US *)0xa0EFC50A
-#define MFT4RLD (US *)0xa0EFC50E
-#define MFT4CRLD (US *)0xa0EFC512
-
-#define MFT5MOD (US *)0xa0EFC602
-#define MFT5CUT (US *)0xa0EFC60A
-#define MFT5RLD (US *)0xa0EFC60E
-#define MFT5CRLD (US *)0xa0EFC612
-
-/*********************************
-
-M32102 SIO
-
-*********************************/
-
-#define SIO0CR (volatile int *)0xa0efd000
-#define SIO0MOD0 (volatile int *)0xa0efd004
-#define SIO0MOD1 (volatile int *)0xa0efd008
-#define SIO0STS (volatile int *)0xa0efd00c
-#define SIO0IMASK (volatile int *)0xa0efd010
-#define SIO0BAUR (volatile int *)0xa0efd014
-#define SIO0RBAUR (volatile int *)0xa0efd018
-#define SIO0TXB (volatile int *)0xa0efd01c
-#define SIO0RXB (volatile int *)0xa0efd020
-
-#define SIO1CR (volatile int *)0xa0efd100
-#define SIO1MOD0 (volatile int *)0xa0efd104
-#define SIO1MOD1 (volatile int *)0xa0efd108
-#define SIO1STS (volatile int *)0xa0efd10c
-#define SIO1IMASK (volatile int *)0xa0efd110
-#define SIO1BAUR (volatile int *)0xa0efd114
-#define SIO1RBAUR (volatile int *)0xa0efd118
-#define SIO1TXB (volatile int *)0xa0efd11c
-#define SIO1RXB (volatile int *)0xa0efd120
-/*********************************
-
-M32102 PORT
-
-*********************************/
-#define PIEN (UB *)0xa0EF1003 /* input enable */
-
-#define P0DATA (UB *)0xa0EF1020 /* data */
-#define P1DATA (UB *)0xa0EF1021
-#define P2DATA (UB *)0xa0EF1022
-#define P3DATA (UB *)0xa0EF1023
-#define P4DATA (UB *)0xa0EF1024
-#define P5DATA (UB *)0xa0EF1025
-#define P6DATA (UB *)0xa0EF1026
-#define P7DATA (UB *)0xa0EF1027
-
-#define P0DIR (UB *)0xa0EF1040 /* direction */
-#define P1DIR (UB *)0xa0EF1041
-#define P2DIR (UB *)0xa0EF1042
-#define P3DIR (UB *)0xa0EF1043
-#define P4DIR (UB *)0xa0EF1044
-#define P5DIR (UB *)0xa0EF1045
-#define P6DIR (UB *)0xa0EF1046
-#define P7DIR (UB *)0xa0EF1047
-
-#define P0MOD (US *)0xa0EF1060 /* mode control */
-#define P1MOD (US *)0xa0EF1062
-#define P2MOD (US *)0xa0EF1064
-#define P3MOD (US *)0xa0EF1066
-#define P4MOD (US *)0xa0EF1068
-#define P5MOD (US *)0xa0EF106A
-#define P6MOD (US *)0xa0EF106C
-#define P7MOD (US *)0xa0EF106E
-
-#define P0ODCR (UB *)0xa0EF1080 /* open-drain control */
-#define P1ODCR (UB *)0xa0EF1081
-#define P2ODCR (UB *)0xa0EF1082
-#define P3ODCR (UB *)0xa0EF1083
-#define P4ODCR (UB *)0xa0EF1084
-#define P5ODCR (UB *)0xa0EF1085
-#define P6ODCR (UB *)0xa0EF1086
-#define P7ODCR (UB *)0xa0EF1087
-
-/*********************************
-
-M32102 Cache
-
-********************************/
-
-#define MCCR (US *)0xFFFFFFFE
-
-
-#else /* __ASSEMBLY__ */
-
-;;
-;; PIO 0x80ef1000
-;;
-
-#define PIEN 0xa0ef1000
-
-#define P0DATA 0xa0ef1020
-#define P1DATA 0xa0ef1021
-#define P2DATA 0xa0ef1022
-#define P3DATA 0xa0ef1023
-#define P4DATA 0xa0ef1024
-#define P5DATA 0xa0ef1025
-#define P6DATA 0xa0ef1026
-#define P7DATA 0xa0ef1027
-
-#define P0DIR 0xa0ef1040
-#define P1DIR 0xa0ef1041
-#define P2DIR 0xa0ef1042
-#define P3DIR 0xa0ef1043
-#define P4DIR 0xa0ef1044
-#define P5DIR 0xa0ef1045
-#define P6DIR 0xa0ef1046
-#define P7DIR 0xa0ef1047
-
-#define P0MOD 0xa0ef1060
-#define P1MOD 0xa0ef1062
-#define P2MOD 0xa0ef1064
-#define P3MOD 0xa0ef1066
-#define P4MOD 0xa0ef1068
-#define P5MOD 0xa0ef106a
-#define P6MOD 0xa0ef106c
-#define P7MOD 0xa0ef106e
-;
-#define P0ODCR 0xa0ef1080
-#define P1ODCR 0xa0ef1081
-#define P2ODCR 0xa0ef1082
-#define P3ODCR 0xa0ef1083
-#define P4ODCR 0xa0ef1084
-#define P5ODCR 0xa0ef1085
-#define P6ODCR 0xa0ef1086
-#define P7ODCR 0xa0ef1087
-
-;;
-;; WDT 0xa0ef2000
-;;
-
-#define WDTCR 0xa0ef2000
-
-
-;;
-;; CLK 0xa0ef4000
-;;
-
-#define CPUCLKCR 0xa0ef4000
-#define CLKMOD 0xa0ef4004
-#define PLLCR 0xa0ef4008
-
-
-;;
-;; BSEL 0xa0ef5000
-;;
-
-#define BSEL0CR 0xa0ef5000
-#define BSEL1CR 0xa0ef5004
-#define BSEL2CR 0xa0ef5008
-#define BSEL3CR 0xa0ef500c
-#define BSEL4CR 0xa0ef5010
-#define BSEL5CR 0xa0ef5014
-
-
-;;
-;; SDRAMC 0xa0ef6000
-;;
-
-#define SDRF0 0xa0ef6000
-#define SDRF1 0xa0ef6004
-#define SDIR0 0xa0ef6008
-#define SDIR1 0xa0ef600c
-#define SDBR 0xa0ef6010
-
-;; CH0
-#define SD0ADR 0xa0ef6020
-#define SD0SZ 0xa0ef6022
-#define SD0ER 0xa0ef6024
-#define SD0TR 0xa0ef6028
-#define SD0MOD 0xa0ef602c
-
-;; CH1
-#define SD1ADR 0xa0ef6040
-#define SD1SZ 0xa0ef6042
-#define SD1ER 0xa0ef6044
-#define SD1TR 0xa0ef6048
-#define SD1MOD 0xa0ef604c
-
-
-;;
-;; DMAC 0xa0ef8000
-;;
-
-#define DMAEN 0xa0ef8000
-#define DMAISTS 0xa0ef8004
-#define DMAEDET 0xa0ef8008
-#define DMAASTS 0xa0ef800c
-
-;; CH0
-#define DMA0CR0 0xa0ef8100
-#define DMA0CR1 0xa0ef8104
-#define DMA0CSA 0xa0ef8108
-#define DMA0RSA 0xa0ef810c
-#define DMA0CDA 0xa0ef8110
-#define DMA0RDA 0xa0ef8114
-#define DMA0CBCUT 0xa0ef8118
-#define DMA0RBCUT 0xa0ef811c
-
-;; CH1
-#define DMA1CR0 0xa0ef8200
-#define DMA1CR1 0xa0ef8204
-#define DMA1CSA 0xa0ef8208
-#define DMA1RSA 0xa0ef820c
-#define DMA1CDA 0xa0ef8210
-#define DMA1RDA 0xa0ef8214
-#define DMA1CBCUT 0xa0ef8218
-#define DMA1RBCUT 0xa0ef821c
-
-
-;;
-;; MFT 0xa0efc000
-;;
-
-#define MFTCR 0xa0efc000
-#define MFTRPR 0xa0efc004
-
-;; CH0
-#define MFT0MOD 0xa0efc100
-#define MFT0BOS 0xa0efc104
-#define MFT0CUT 0xa0efc108
-#define MFT0RLD 0xa0efc10c
-#define MFT0CMPRLD 0xa0efc110
-
-;; CH1
-#define MFT1MOD 0xa0efc200
-#define MFT1BOS 0xa0efc204
-#define MFT1CUT 0xa0efc208
-#define MFT1RLD 0xa0efc20c
-#define MFT1CMPRLD 0xa0efc210
-
-;; CH2
-#define MFT2MOD 0xa0efc300
-#define MFT2BOS 0xa0efc304
-#define MFT2CUT 0xa0efc308
-#define MFT2RLD 0xa0efc30c
-#define MFT2CMPRLD 0xa0efc310
-
-;; CH3
-#define MFT3MOD 0xa0efc400
-#define MFT3BOS 0xa0efc404
-#define MFT3CUT 0xa0efc408
-#define MFT3RLD 0xa0efc40c
-#define MFT3CMPRLD 0xa0efc410
-
-;; CH4
-#define MFT4MOD 0xa0efc500
-#define MFT4BOS 0xa0efc504
-#define MFT4CUT 0xa0efc508
-#define MFT4RLD 0xa0efc50c
-#define MFT4CMPRLD 0xa0efc510
-
-;; CH5
-#define MFT5MOD 0xa0efc600
-#define MFT5BOS 0xa0efc604
-#define MFT5CUT 0xa0efc608
-#define MFT5RLD 0xa0efc60c
-#define MFT5CMPRLD 0xa0efc610
-
-
-;;
-;; SIO 0xa0efd000
-;;
-
-;; CH0
-#define SIO0CR 0xa0efd000
-#define SIO0MOD0 0xa0efd004
-#define SIO0MOD1 0xa0efd008
-#define SIO0STS 0xa0efd00c
-#define SIO0IMASK 0xa0efd010
-#define SIO0BAUR 0xa0efd014
-#define SIO0RBAUR 0xa0efd018
-#define SIO0TXB 0xa0efd01c
-#define SIO0RXB 0xa0efd020
-
-;; CH1
-#define SIO1CR 0xa0efd100
-#define SIO1MOD0 0xa0efd104
-#define SIO1MOD1 0xa0efd108
-#define SIO1STS 0xa0efd10c
-#define SIO1IMASK 0xa0efd110
-#define SIO1BAUR 0xa0efd114
-#define SIO1RBAUR 0xa0efd118
-#define SIO1TXB 0xa0efd11c
-#define SIO1RXB 0xa0efd120
-
-;; CH2
-#define SIO2CR 0xa0efd200
-#define SIO2MOD0 0xa0efd204
-#define SIO2MOD1 0xa0efd208
-#define SIO2STS 0xa0efd20c
-#define SIO2IMASK 0xa0efd210
-#define SIO2BAUR 0xa0efd214
-#define SIO2RBAUR 0xa0efd218
-#define SIO2TXB 0xa0efd21c
-#define SIO2RXB 0xa0efd220
-
-;; CH3
-#define SIO3CR 0xa0efd300
-#define SIO3MOD0 0xa0efd304
-#define SIO3MOD1 0xa0efd308
-#define SIO3STS 0xa0efd30c
-#define SIO3IMASK 0xa0efd310
-#define SIO3BAUR 0xa0efd314
-#define SIO3RBAUR 0xa0efd318
-#define SIO3TXB 0xa0efd31c
-#define SIO3RXB 0xa0efd320
-
-;; CH4
-#define SIO4CR 0xa0efd400
-#define SIO4MOD0 0xa0efd404
-#define SIO4MOD1 0xa0efd408
-#define SIO4STS 0xa0efd40c
-#define SIO4IMASK 0xa0efd410
-#define SIO4BAUR 0xa0efd414
-#define SIO4RBAUR 0xa0efd418
-#define SIO4TXB 0xa0efd41c
-#define SIO4RXB 0xa0efd420
-
-
-;;
-;; ICU 0xa0eff000
-;;
-
-#define ICUISTS 0xa0eff004
-#define ICUIREQ0 0xa0eff008
-#define ICUIREQ1 0xa0eff00c
-
-#define ICUSBICR 0xa0eff018
-#define ICUIMASK 0xa0eff01c
-
-#define ICUCR1 0xa0eff200
-#define ICUCR2 0xa0eff204
-#define ICUCR3 0xa0eff208
-#define ICUCR4 0xa0eff20c
-#define ICUCR5 0xa0eff210
-#define ICUCR6 0xa0eff214
-#define ICUCR7 0xa0eff218
-
-#define ICUCR16 0xa0eff23c
-#define ICUCR17 0xa0eff240
-#define ICUCR18 0xa0eff244
-#define ICUCR19 0xa0eff248
-#define ICUCR20 0xa0eff24c
-#define ICUCR21 0xa0eff250
-
-#define ICUCR32 0xa0eff27c
-#define ICUCR33 0xa0eff280
-
-#define ICUCR48 0xa0eff2bc
-#define ICUCR49 0xa0eff2c0
-#define ICUCR50 0xa0eff2c4
-#define ICUCR51 0xa0eff2c8
-#define ICUCR52 0xa0eff2cc
-#define ICUCR53 0xa0eff2d0
-#define ICUCR54 0xa0eff2d4
-#define ICUCR55 0xa0eff2d8
-#define ICUCR56 0xa0eff2dc
-#define ICUCR57 0xa0eff2e0
-
-;;
-;; CACHE
-;;
-
-#define MCCR 0xfffffffc
-
-
-#endif /* __ASSEMBLY__ */
|| defined(CONFIG_CHIP_M32700) || defined(CONFIG_CHIP_M32102) \
|| defined(CONFIG_CHIP_OPSP)
#include <asm/m32102.h>
-#include <asm/m32102peri.h>
#endif
/* Platform type */
#include <asm/mappi2/mappi2_pld.h>
#endif /* CONFIG_PLAT_MAPPI2 */
+#if defined(CONFIG_PLAT_MAPPI3)
+#include <asm/mappi3/mappi3_pld.h>
+#endif /* CONFIG_PLAT_MAPPI3 */
+
#if defined(CONFIG_PLAT_USRV)
#include <asm/m32700ut/m32700ut_pld.h>
#endif
--- /dev/null
+/*
+ * include/asm/mappi3/mappi3_pld.h
+ *
+ * Definitions for Extended IO Logic on MAPPI3 board.
+ * based on m32700ut_pld.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.
+ *
+ */
+
+#ifndef _MAPPI3_PLD_H
+#define _MAPPI3_PLD_H
+
+#ifndef __ASSEMBLY__
+/* FIXME:
+ * Some C functions use non-cache address, so can't define non-cache address.
+ */
+#define PLD_BASE (0x1c000000 /* + NONCACHE_OFFSET */)
+#define __reg8 (volatile unsigned char *)
+#define __reg16 (volatile unsigned short *)
+#define __reg32 (volatile unsigned int *)
+#else
+#define PLD_BASE (0x1c000000 + NONCACHE_OFFSET)
+#define __reg8
+#define __reg16
+#define __reg32
+#endif /* __ASSEMBLY__ */
+
+/* CFC */
+#define PLD_CFRSTCR __reg16(PLD_BASE + 0x0000)
+#define PLD_CFSTS __reg16(PLD_BASE + 0x0002)
+#define PLD_CFIMASK __reg16(PLD_BASE + 0x0004)
+#define PLD_CFBUFCR __reg16(PLD_BASE + 0x0006)
+#define PLD_CFCR0 __reg16(PLD_BASE + 0x000a)
+#define PLD_CFCR1 __reg16(PLD_BASE + 0x000c)
+
+/* MMC */
+#define PLD_MMCCR __reg16(PLD_BASE + 0x4000)
+#define PLD_MMCMOD __reg16(PLD_BASE + 0x4002)
+#define PLD_MMCSTS __reg16(PLD_BASE + 0x4006)
+#define PLD_MMCBAUR __reg16(PLD_BASE + 0x400a)
+#define PLD_MMCCMDBCUT __reg16(PLD_BASE + 0x400c)
+#define PLD_MMCCDTBCUT __reg16(PLD_BASE + 0x400e)
+#define PLD_MMCDET __reg16(PLD_BASE + 0x4010)
+#define PLD_MMCWP __reg16(PLD_BASE + 0x4012)
+#define PLD_MMCWDATA __reg16(PLD_BASE + 0x5000)
+#define PLD_MMCRDATA __reg16(PLD_BASE + 0x6000)
+#define PLD_MMCCMDDATA __reg16(PLD_BASE + 0x7000)
+#define PLD_MMCRSPDATA __reg16(PLD_BASE + 0x7006)
+
+/* Power Control of MMC and CF */
+#define PLD_CPCR __reg16(PLD_BASE + 0x14000)
+
+
+/*==== ICU ====*/
+#define M32R_IRQ_PC104 (5) /* INT4(PC/104) */
+#define M32R_IRQ_I2C (28) /* I2C-BUS */
+#define PLD_IRQ_CFIREQ (6) /* INT5 CFC Card Interrupt */
+#define PLD_IRQ_CFC_INSERT (7) /* INT6 CFC Card Insert */
+#define PLD_IRQ_CFC_EJECT (8) /* INT7 CFC Card Eject */
+#define PLD_IRQ_MMCCARD (43) /* MMC Card Insert */
+#define PLD_IRQ_MMCIRQ (44) /* MMC Transfer Done */
+
+
+#if 0
+/* LED Control
+ *
+ * 1: DIP swich side
+ * 2: Reset switch side
+ */
+#define PLD_IOLEDCR __reg16(PLD_BASE + 0x14002)
+#define PLD_IOLED_1_ON 0x001
+#define PLD_IOLED_1_OFF 0x000
+#define PLD_IOLED_2_ON 0x002
+#define PLD_IOLED_2_OFF 0x000
+
+/* DIP Switch
+ * 0: Write-protect of Flash Memory (0:protected, 1:non-protected)
+ * 1: -
+ * 2: -
+ * 3: -
+ */
+#define PLD_IOSWSTS __reg16(PLD_BASE + 0x14004)
+#define PLD_IOSWSTS_IOSW2 0x0200
+#define PLD_IOSWSTS_IOSW1 0x0100
+#define PLD_IOSWSTS_IOWP0 0x0001
+
+#endif
+
+/* CRC */
+#define PLD_CRC7DATA __reg16(PLD_BASE + 0x18000)
+#define PLD_CRC7INDATA __reg16(PLD_BASE + 0x18002)
+#define PLD_CRC16DATA __reg16(PLD_BASE + 0x18004)
+#define PLD_CRC16INDATA __reg16(PLD_BASE + 0x18006)
+#define PLD_CRC16ADATA __reg16(PLD_BASE + 0x18008)
+#define PLD_CRC16AINDATA __reg16(PLD_BASE + 0x1800a)
+
+
+#if 0
+/* RTC */
+#define PLD_RTCCR __reg16(PLD_BASE + 0x1c000)
+#define PLD_RTCBAUR __reg16(PLD_BASE + 0x1c002)
+#define PLD_RTCWRDATA __reg16(PLD_BASE + 0x1c004)
+#define PLD_RTCRDDATA __reg16(PLD_BASE + 0x1c006)
+#define PLD_RTCRSTODT __reg16(PLD_BASE + 0x1c008)
+
+/* SIO0 */
+#define PLD_ESIO0CR __reg16(PLD_BASE + 0x20000)
+#define PLD_ESIO0CR_TXEN 0x0001
+#define PLD_ESIO0CR_RXEN 0x0002
+#define PLD_ESIO0MOD0 __reg16(PLD_BASE + 0x20002)
+#define PLD_ESIO0MOD0_CTSS 0x0040
+#define PLD_ESIO0MOD0_RTSS 0x0080
+#define PLD_ESIO0MOD1 __reg16(PLD_BASE + 0x20004)
+#define PLD_ESIO0MOD1_LMFS 0x0010
+#define PLD_ESIO0STS __reg16(PLD_BASE + 0x20006)
+#define PLD_ESIO0STS_TEMP 0x0001
+#define PLD_ESIO0STS_TXCP 0x0002
+#define PLD_ESIO0STS_RXCP 0x0004
+#define PLD_ESIO0STS_TXSC 0x0100
+#define PLD_ESIO0STS_RXSC 0x0200
+#define PLD_ESIO0STS_TXREADY (PLD_ESIO0STS_TXCP | PLD_ESIO0STS_TEMP)
+#define PLD_ESIO0INTCR __reg16(PLD_BASE + 0x20008)
+#define PLD_ESIO0INTCR_TXIEN 0x0002
+#define PLD_ESIO0INTCR_RXCEN 0x0004
+#define PLD_ESIO0BAUR __reg16(PLD_BASE + 0x2000a)
+#define PLD_ESIO0TXB __reg16(PLD_BASE + 0x2000c)
+#define PLD_ESIO0RXB __reg16(PLD_BASE + 0x2000e)
+
+/* SIM Card */
+#define PLD_SCCR __reg16(PLD_BASE + 0x38000)
+#define PLD_SCMOD __reg16(PLD_BASE + 0x38004)
+#define PLD_SCSTS __reg16(PLD_BASE + 0x38006)
+#define PLD_SCINTCR __reg16(PLD_BASE + 0x38008)
+#define PLD_SCBAUR __reg16(PLD_BASE + 0x3800a)
+#define PLD_SCTXB __reg16(PLD_BASE + 0x3800c)
+#define PLD_SCRXB __reg16(PLD_BASE + 0x3800e)
+
+#endif
+
+#endif /* _MAPPI3_PLD.H */
#define physid_to_cpu(physid) physid_2_cpu[physid]
#define cpu_to_physid(cpu_id) cpu_2_physid[cpu_id]
-#define smp_processor_id() (current_thread_info()->cpu)
+#define raw_smp_processor_id() (current_thread_info()->cpu)
extern cpumask_t cpu_callout_map;
#define cpu_possible_map cpu_callout_map
#include <linux/cpumask.h>
#include <asm/atomic.h>
-#define smp_processor_id() (current_thread_info()->cpu)
+#define raw_smp_processor_id() (current_thread_info()->cpu)
/* Map from cpu id to sequential logical cpu number. This will only
not be idempotent when cpus failed to come on-line. */
--- /dev/null
+/*
+ * Include file for NEC VR4100 series General-purpose I/O 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_GIU_H
+#define __NEC_VR41XX_GIU_H
+
+typedef enum {
+ IRQ_TRIGGER_LEVEL,
+ IRQ_TRIGGER_EDGE,
+ IRQ_TRIGGER_EDGE_FALLING,
+ IRQ_TRIGGER_EDGE_RISING,
+} irq_trigger_t;
+
+typedef enum {
+ IRQ_SIGNAL_THROUGH,
+ IRQ_SIGNAL_HOLD,
+} irq_signal_t;
+
+extern void vr41xx_set_irq_trigger(unsigned int pin, irq_trigger_t trigger, irq_signal_t signal);
+
+typedef enum {
+ IRQ_LEVEL_LOW,
+ IRQ_LEVEL_HIGH,
+} irq_level_t;
+
+extern void vr41xx_set_irq_level(unsigned int pin, irq_level_t level);
+
+typedef enum {
+ GPIO_DATA_LOW,
+ GPIO_DATA_HIGH,
+ GPIO_DATA_INVAL,
+} gpio_data_t;
+
+extern gpio_data_t vr41xx_gpio_get_pin(unsigned int pin);
+extern int vr41xx_gpio_set_pin(unsigned int pin, gpio_data_t data);
+
+typedef enum {
+ GPIO_INPUT,
+ GPIO_OUTPUT,
+ GPIO_OUTPUT_DISABLE,
+} gpio_direction_t;
+
+extern int vr41xx_gpio_set_direction(unsigned int pin, gpio_direction_t dir);
+
+typedef enum {
+ GPIO_PULL_DOWN,
+ GPIO_PULL_UP,
+ GPIO_PULL_DISABLE,
+} gpio_pull_t;
+
+extern int vr41xx_gpio_pullupdown(unsigned int pin, gpio_pull_t pull);
+
+#endif /* __NEC_VR41XX_GIU_H */
#define GIU_IRQ_BASE 40
#define GIU_IRQ(x) (GIU_IRQ_BASE + (x)) /* IRQ 40-71 */
#define GIU_IRQ_LAST GIU_IRQ(31)
-#define GIU_IRQ_TO_PIN(x) ((x) - GIU_IRQ_BASE) /* Pin 0-31 */
extern int vr41xx_set_intassign(unsigned int irq, unsigned char intassign);
extern int vr41xx_cascade_irq(unsigned int irq, int (*get_irq_number)(int irq));
extern void vr41xx_enable_bcuint(void);
extern void vr41xx_disable_bcuint(void);
-/*
- * General-Purpose I/O Unit
- */
-enum {
- TRIGGER_LEVEL,
- TRIGGER_EDGE,
- TRIGGER_EDGE_FALLING,
- TRIGGER_EDGE_RISING
-};
-
-enum {
- SIGNAL_THROUGH,
- SIGNAL_HOLD
-};
-
-extern void vr41xx_set_irq_trigger(int pin, int trigger, int hold);
-
-enum {
- LEVEL_LOW,
- LEVEL_HIGH
-};
-
-extern void vr41xx_set_irq_level(int pin, int level);
-
-enum {
- PIO_INPUT,
- PIO_OUTPUT
-};
-
-enum {
- DATA_LOW,
- DATA_HIGH
-};
-
#endif /* __NEC_VR41XX_H */
extern unsigned long cpu_present_mask;
-#define smp_processor_id() (current_thread_info()->cpu)
+#define raw_smp_processor_id() (current_thread_info()->cpu)
#endif /* CONFIG_SMP */
*/
#include <asm/mpc85xx.h>
-/* The MPC8560 openpic has 32 internal interrupts and 12 external
+/* The MPC8548 openpic has 48 internal interrupts and 12 external
* interrupts.
*
* We are "flattening" the interrupt vectors of the cascaded CPM
* single integer.
*/
#define NR_CPM_INTS 64
-#define NR_EPIC_INTS 44
+#define NR_EPIC_INTS 60
#ifndef NR_8259_INTS
#define NR_8259_INTS 0
#endif
#define MPC85xx_IRQ_RIO_RX (12 + MPC85xx_OPENPIC_IRQ_OFFSET)
#define MPC85xx_IRQ_TSEC1_TX (13 + MPC85xx_OPENPIC_IRQ_OFFSET)
#define MPC85xx_IRQ_TSEC1_RX (14 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_TSEC3_TX (15 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_TSEC3_RX (16 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_TSEC3_ERROR (17 + MPC85xx_OPENPIC_IRQ_OFFSET)
#define MPC85xx_IRQ_TSEC1_ERROR (18 + MPC85xx_OPENPIC_IRQ_OFFSET)
#define MPC85xx_IRQ_TSEC2_TX (19 + MPC85xx_OPENPIC_IRQ_OFFSET)
#define MPC85xx_IRQ_TSEC2_RX (20 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_TSEC4_TX (21 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_TSEC4_RX (22 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_TSEC4_ERROR (23 + MPC85xx_OPENPIC_IRQ_OFFSET)
#define MPC85xx_IRQ_TSEC2_ERROR (24 + MPC85xx_OPENPIC_IRQ_OFFSET)
#define MPC85xx_IRQ_FEC (25 + MPC85xx_OPENPIC_IRQ_OFFSET)
#define MPC85xx_IRQ_DUART (26 + MPC85xx_OPENPIC_IRQ_OFFSET)
#define MPC85xx_IRQ_CPM (30 + MPC85xx_OPENPIC_IRQ_OFFSET)
/* The 12 external interrupt lines */
-#define MPC85xx_IRQ_EXT0 (32 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_EXT1 (33 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_EXT2 (34 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_EXT3 (35 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_EXT4 (36 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_EXT5 (37 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_EXT6 (38 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_EXT7 (39 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_EXT8 (40 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_EXT9 (41 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_EXT10 (42 + MPC85xx_OPENPIC_IRQ_OFFSET)
-#define MPC85xx_IRQ_EXT11 (43 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_EXT0 (48 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_EXT1 (49 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_EXT2 (50 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_EXT3 (51 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_EXT4 (52 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_EXT5 (53 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_EXT6 (54 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_EXT7 (55 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_EXT8 (56 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_EXT9 (57 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_EXT10 (58 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_EXT11 (59 + MPC85xx_OPENPIC_IRQ_OFFSET)
/* CPM related interrupts */
#define SIU_INT_ERROR ((uint)0x00+CPM_IRQ_OFFSET)
#define MPC10X_MAPA_EUMB_BASE (ioremap_base - MPC10X_EUMB_SIZE)
#define MPC10X_MAPB_EUMB_BASE MPC10X_MAPA_EUMB_BASE
+enum ppc_sys_devices {
+ MPC10X_IIC1,
+ MPC10X_DMA0,
+ MPC10X_DMA1,
+ MPC10X_DUART,
+};
int mpc10x_bridge_init(struct pci_controller *hose,
uint current_map,
#ifdef CONFIG_MPC8540_ADS
#include <platforms/85xx/mpc8540_ads.h>
#endif
-#ifdef CONFIG_MPC8555_CDS
+#if defined(CONFIG_MPC8555_CDS) || defined(CONFIG_MPC8548_CDS)
#include <platforms/85xx/mpc8555_cds.h>
#endif
#ifdef CONFIG_MPC8560_ADS
#define MPC85xx_GUTS_OFFSET (0xe0000)
#define MPC85xx_GUTS_SIZE (0x01000)
#define MPC85xx_IIC1_OFFSET (0x03000)
-#define MPC85xx_IIC1_SIZE (0x01000)
+#define MPC85xx_IIC1_SIZE (0x00100)
#define MPC85xx_OPENPIC_OFFSET (0x40000)
#define MPC85xx_OPENPIC_SIZE (0x40000)
#define MPC85xx_PCI1_OFFSET (0x08000)
MPC85xx_CPM_MCC2,
MPC85xx_CPM_SMC1,
MPC85xx_CPM_SMC2,
+ MPC85xx_eTSEC1,
+ MPC85xx_eTSEC2,
+ MPC85xx_eTSEC3,
+ MPC85xx_eTSEC4,
+ MPC85xx_IIC2,
};
+/* Internal interrupts are all Level Sensitive, and Positive Polarity */
+#define MPC85XX_INTERNAL_IRQ_SENSES \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 0 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 1 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 2 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 3 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 4 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 5 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 6 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 7 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 8 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 9 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 10 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 11 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 12 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 13 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 14 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 15 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 16 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 17 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 18 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 19 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 20 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 21 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 22 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 23 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 24 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 25 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 26 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 27 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 28 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 29 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 30 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 31 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 32 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 33 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 34 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 35 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 36 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 37 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 38 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 39 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 40 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 41 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 42 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 43 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 44 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 45 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 46 */ \
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE) /* Internal 47 */
+
#endif /* CONFIG_85xx */
#endif /* __ASM_MPC85xx_H__ */
#endif /* __KERNEL__ */
#define _PMD_PRESENT_MASK (PAGE_MASK)
#define _PMD_BAD (~PAGE_MASK)
-#define NUM_TLBCAMS (16)
-
#elif defined(CONFIG_8xx)
/* Definitions for 8xx embedded chips. */
#define _PAGE_PRESENT 0x0001 /* Page is valid */
#include <asm/mpc85xx.h>
#elif defined(CONFIG_PPC_MPC52xx)
#include <asm/mpc52xx.h>
+#elif defined(CONFIG_MPC10X_BRIDGE)
+#include <asm/mpc10x.h>
#else
#error "need definition of ppc_sys_devices"
#endif
#define NO_PROC_ID 0xFF /* No processor magic marker */
#define PROC_CHANGE_PENALTY 20
-#define smp_processor_id() (current_thread_info()->cpu)
+#define raw_smp_processor_id() (current_thread_info()->cpu)
extern int __cpu_up(unsigned int cpu);
/* Doesn't really apply... */
#define MAX_DMA_ADDRESS (~0UL)
+#if !defined(CONFIG_PPC_ISERIES) || defined(CONFIG_PCI)
+
#define dma_outb outb
#define dma_inb inb
#else
#define isa_dma_bridge_buggy (0)
#endif
+#endif /* !defined(CONFIG_PPC_ISERIES) || defined(CONFIG_PCI) */
#endif /* _ASM_DMA_H */
/*
* HvCall.h
* Copyright (C) 2001 Mike Corrigan IBM Corporation
- *
+ *
* 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 contains the "hypervisor call" interface which is used to
-// drive the hypervisor from the OS.
-//
-//===========================================================================
+/*
+ * This file contains the "hypervisor call" interface which is used to
+ * drive the hypervisor from the OS.
+ */
#ifndef _HVCALL_H
#define _HVCALL_H
-//-------------------------------------------------------------------
-// Standard Includes
-//-------------------------------------------------------------------
#include <asm/iSeries/HvCallSc.h>
#include <asm/iSeries/HvTypes.h>
#include <asm/paca.h>
-/*
-enum HvCall_ReturnCode
-{
- HvCall_Good = 0,
- HvCall_Partial = 1,
- HvCall_NotOwned = 2,
- HvCall_NotFreed = 3,
- HvCall_UnspecifiedError = 4
-};
-
-enum HvCall_TypeOfSIT
-{
- HvCall_ReduceOnly = 0,
- HvCall_Unconditional = 1
-};
-
-enum HvCall_TypeOfYield
-{
- HvCall_YieldTimed = 0, // Yield until specified time
- HvCall_YieldToActive = 1, // Yield until all active procs have run
- HvCall_YieldToProc = 2 // Yield until the specified processor has run
-};
-
-enum HvCall_InterruptMasks
-{
- HvCall_MaskIPI = 0x00000001,
- HvCall_MaskLpEvent = 0x00000002,
- HvCall_MaskLpProd = 0x00000004,
- HvCall_MaskTimeout = 0x00000008
-};
-
-enum HvCall_VaryOffChunkRc
-{
- HvCall_VaryOffSucceeded = 0,
- HvCall_VaryOffWithdrawn = 1,
- HvCall_ChunkInLoadArea = 2,
- HvCall_ChunkInHPT = 3,
- HvCall_ChunkNotAccessible = 4,
- HvCall_ChunkInUse = 5
-};
-*/
-
/* Type of yield for HvCallBaseYieldProcessor */
-#define HvCall_YieldTimed 0 // Yield until specified time (tb)
-#define HvCall_YieldToActive 1 // Yield until all active procs have run
-#define HvCall_YieldToProc 2 // Yield until the specified processor has run
+#define HvCall_YieldTimed 0 /* Yield until specified time (tb) */
+#define HvCall_YieldToActive 1 /* Yield until all active procs have run */
+#define HvCall_YieldToProc 2 /* Yield until the specified processor has run */
/* interrupt masks for setEnabledInterrupts */
#define HvCall_MaskIPI 0x00000001
#define HvCall_MaskLpProd 0x00000004
#define HvCall_MaskTimeout 0x00000008
-/* Log buffer formats */
+/* Log buffer formats */
#define HvCall_LogBuffer_ASCII 0
#define HvCall_LogBuffer_EBCDIC 1
#define HvCallBaseGetHwPatch HvCallBase + 2
#define HvCallBaseReIplSpAttn HvCallBase + 3
#define HvCallBaseSetASR HvCallBase + 4
-#define HvCallBaseSetASRAndRfi HvCallBase + 5
+#define HvCallBaseSetASRAndRfi HvCallBase + 5
#define HvCallBaseSetIMR HvCallBase + 6
#define HvCallBaseSendIPI HvCallBase + 7
#define HvCallBaseTerminateMachine HvCallBase + 8
#define HvCallBaseGetLogBufferCodePage HvCallBase + 22
#define HvCallBaseGetLogBufferFormat HvCallBase + 23
#define HvCallBaseGetLogBufferLength HvCallBase + 24
-#define HvCallBaseReadLogBuffer HvCallBase + 25
+#define HvCallBaseReadLogBuffer HvCallBase + 25
#define HvCallBaseSetLogBufferFormatAndCodePage HvCallBase + 26
-#define HvCallBaseWriteLogBuffer HvCallBase + 27
+#define HvCallBaseWriteLogBuffer HvCallBase + 27
#define HvCallBaseRouter28 HvCallBase + 28
#define HvCallBaseRouter29 HvCallBase + 29
#define HvCallBaseRouter30 HvCallBase + 30
-#define HvCallBaseSetDebugBus HvCallBase + 31
+#define HvCallBaseSetDebugBus HvCallBase + 31
-#define HvCallCcSetDABR HvCallCc + 7
+#define HvCallCcSetDABR HvCallCc + 7
-//=====================================================================================
-static inline void HvCall_setVirtualDecr(void)
+static inline void HvCall_setVirtualDecr(void)
{
- /* Ignore any error return codes - most likely means that the target value for the
- * LP has been increased and this vary off would bring us below the new target. */
+ /*
+ * Ignore any error return codes - most likely means that the
+ * target value for the LP has been increased and this vary off
+ * would bring us below the new target.
+ */
HvCall0(HvCallBaseSetVirtualDecr);
}
-//=====================================================================
-static inline void HvCall_yieldProcessor(unsigned typeOfYield, u64 yieldParm)
-{
- HvCall2( HvCallBaseYieldProcessor, typeOfYield, yieldParm );
-}
-//=====================================================================
-static inline void HvCall_setEnabledInterrupts(u64 enabledInterrupts)
-{
- HvCall1(HvCallBaseSetEnabledInterrupts,enabledInterrupts);
-}
-
-//=====================================================================
-static inline void HvCall_clearLogBuffer(HvLpIndex lpindex)
-{
- HvCall1(HvCallBaseClearLogBuffer,lpindex);
-}
-
-//=====================================================================
-static inline u32 HvCall_getLogBufferCodePage(HvLpIndex lpindex)
-{
- u32 retVal = HvCall1(HvCallBaseGetLogBufferCodePage,lpindex);
- return retVal;
-}
-
-//=====================================================================
-static inline int HvCall_getLogBufferFormat(HvLpIndex lpindex)
-{
- int retVal = HvCall1(HvCallBaseGetLogBufferFormat,lpindex);
- return retVal;
-}
-
-//=====================================================================
-static inline u32 HvCall_getLogBufferLength(HvLpIndex lpindex)
-{
- u32 retVal = HvCall1(HvCallBaseGetLogBufferLength,lpindex);
- return retVal;
-}
-//=====================================================================
-static inline void HvCall_setLogBufferFormatAndCodepage(int format, u32 codePage)
+static inline void HvCall_yieldProcessor(unsigned typeOfYield, u64 yieldParm)
{
- HvCall2(HvCallBaseSetLogBufferFormatAndCodePage,format, codePage);
+ HvCall2(HvCallBaseYieldProcessor, typeOfYield, yieldParm);
}
-//=====================================================================
-int HvCall_readLogBuffer(HvLpIndex lpindex, void *buffer, u64 bufLen);
-void HvCall_writeLogBuffer(const void *buffer, u64 bufLen);
-
-//=====================================================================
-static inline void HvCall_sendIPI(struct paca_struct * targetPaca)
+static inline void HvCall_setEnabledInterrupts(u64 enabledInterrupts)
{
- HvCall1( HvCallBaseSendIPI, targetPaca->paca_index );
+ HvCall1(HvCallBaseSetEnabledInterrupts, enabledInterrupts);
}
-//=====================================================================
-static inline void HvCall_terminateMachineSrc(void)
+static inline void HvCall_setLogBufferFormatAndCodepage(int format,
+ u32 codePage)
{
- HvCall0( HvCallBaseTerminateMachineSrc );
+ HvCall2(HvCallBaseSetLogBufferFormatAndCodePage, format, codePage);
}
-static inline void HvCall_setDABR(unsigned long val)
-{
- HvCall1(HvCallCcSetDABR, val);
-}
+extern void HvCall_writeLogBuffer(const void *buffer, u64 bufLen);
-static inline void HvCall_setDebugBus(unsigned long val)
+static inline void HvCall_sendIPI(struct paca_struct *targetPaca)
{
- HvCall1(HvCallBaseSetDebugBus, val);
+ HvCall1(HvCallBaseSendIPI, targetPaca->paca_index);
}
#endif /* _HVCALL_H */
+++ /dev/null
-/*
- * HvCallCfg.h
- * Copyright (C) 2001 Mike Corrigan IBM Corporation
- *
- * 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 contains the "hypervisor call" interface which is used to
-// drive the hypervisor from the OS.
-//
-//=====================================================================================
-#ifndef _HVCALLCFG_H
-#define _HVCALLCFG_H
-
-//-------------------------------------------------------------------
-// Standard Includes
-//-------------------------------------------------------------------
-#include <asm/iSeries/HvCallSc.h>
-#include <asm/iSeries/HvTypes.h>
-
-//-------------------------------------------------------------------------------------
-// Constants
-//-------------------------------------------------------------------------------------
-
-enum HvCallCfg_ReqQual
-{
- HvCallCfg_Cur = 0,
- HvCallCfg_Init = 1,
- HvCallCfg_Max = 2,
- HvCallCfg_Min = 3
-};
-
-#define HvCallCfgGetLps HvCallCfg + 0
-#define HvCallCfgGetActiveLpMap HvCallCfg + 1
-#define HvCallCfgGetLpVrmIndex HvCallCfg + 2
-#define HvCallCfgGetLpMinSupportedPlicVrmIndex HvCallCfg + 3
-#define HvCallCfgGetLpMinCompatablePlicVrmIndex HvCallCfg + 4
-#define HvCallCfgGetLpVrmName HvCallCfg + 5
-#define HvCallCfgGetSystemPhysicalProcessors HvCallCfg + 6
-#define HvCallCfgGetPhysicalProcessors HvCallCfg + 7
-#define HvCallCfgGetSystemMsChunks HvCallCfg + 8
-#define HvCallCfgGetMsChunks HvCallCfg + 9
-#define HvCallCfgGetInteractivePercentage HvCallCfg + 10
-#define HvCallCfgIsBusDedicated HvCallCfg + 11
-#define HvCallCfgGetBusOwner HvCallCfg + 12
-#define HvCallCfgGetBusAllocation HvCallCfg + 13
-#define HvCallCfgGetBusUnitOwner HvCallCfg + 14
-#define HvCallCfgGetBusUnitAllocation HvCallCfg + 15
-#define HvCallCfgGetVirtualBusPool HvCallCfg + 16
-#define HvCallCfgGetBusUnitInterruptProc HvCallCfg + 17
-#define HvCallCfgGetConfiguredBusUnitsForIntProc HvCallCfg + 18
-#define HvCallCfgGetRioSanBusPool HvCallCfg + 19
-#define HvCallCfgGetSharedPoolIndex HvCallCfg + 20
-#define HvCallCfgGetSharedProcUnits HvCallCfg + 21
-#define HvCallCfgGetNumProcsInSharedPool HvCallCfg + 22
-#define HvCallCfgRouter23 HvCallCfg + 23
-#define HvCallCfgRouter24 HvCallCfg + 24
-#define HvCallCfgRouter25 HvCallCfg + 25
-#define HvCallCfgRouter26 HvCallCfg + 26
-#define HvCallCfgRouter27 HvCallCfg + 27
-#define HvCallCfgGetMinRuntimeMsChunks HvCallCfg + 28
-#define HvCallCfgSetMinRuntimeMsChunks HvCallCfg + 29
-#define HvCallCfgGetVirtualLanIndexMap HvCallCfg + 30
-#define HvCallCfgGetLpExecutionMode HvCallCfg + 31
-#define HvCallCfgGetHostingLpIndex HvCallCfg + 32
-
-//====================================================================
-static inline HvLpIndex HvCallCfg_getLps(void)
-{
- HvLpIndex retVal = HvCall0(HvCallCfgGetLps);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
- return retVal;
-}
-//====================================================================
-static inline int HvCallCfg_isBusDedicated(u64 busIndex)
-{
- int retVal = HvCall1(HvCallCfgIsBusDedicated,busIndex);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
- return retVal;
-}
-//====================================================================
-static inline HvLpIndex HvCallCfg_getBusOwner(u64 busIndex)
-{
- HvLpIndex retVal = HvCall1(HvCallCfgGetBusOwner,busIndex);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
- return retVal;
-}
-//====================================================================
-static inline HvLpIndexMap HvCallCfg_getBusAllocation(u64 busIndex)
-{
- HvLpIndexMap retVal = HvCall1(HvCallCfgGetBusAllocation,busIndex);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
- return retVal;
-}
-//====================================================================
-static inline HvLpIndexMap HvCallCfg_getActiveLpMap(void)
-{
- HvLpIndexMap retVal = HvCall0(HvCallCfgGetActiveLpMap);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
- return retVal;
-}
-//====================================================================
-static inline HvLpVirtualLanIndexMap HvCallCfg_getVirtualLanIndexMap(HvLpIndex lp)
-{
- // This is a new function in V5R1 so calls to this on older
- // hypervisors will return -1
- u64 retVal = HvCall1(HvCallCfgGetVirtualLanIndexMap, lp);
- if(retVal == -1)
- retVal = 0;
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
- return retVal;
-}
-//===================================================================
-static inline u64 HvCallCfg_getSystemMsChunks(void)
-{
- u64 retVal = HvCall0(HvCallCfgGetSystemMsChunks);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
- return retVal;
-}
-//===================================================================
-static inline u64 HvCallCfg_getMsChunks(HvLpIndex lp,enum HvCallCfg_ReqQual qual)
-{
- u64 retVal = HvCall2(HvCallCfgGetMsChunks,lp,qual);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
- return retVal;
-}
-//===================================================================
-static inline u64 HvCallCfg_getMinRuntimeMsChunks(HvLpIndex lp)
-{
- // NOTE: This function was added in v5r1 so older hypervisors will return a -1 value
- u64 retVal = HvCall1(HvCallCfgGetMinRuntimeMsChunks,lp);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
- return retVal;
-}
-//===================================================================
-static inline u64 HvCallCfg_setMinRuntimeMsChunks(u64 chunks)
-{
- u64 retVal = HvCall1(HvCallCfgSetMinRuntimeMsChunks,chunks);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
- return retVal;
-}
-//===================================================================
-static inline u64 HvCallCfg_getSystemPhysicalProcessors(void)
-{
- u64 retVal = HvCall0(HvCallCfgGetSystemPhysicalProcessors);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
- return retVal;
-}
-//===================================================================
-static inline u64 HvCallCfg_getPhysicalProcessors(HvLpIndex lp,enum HvCallCfg_ReqQual qual)
-{
- u64 retVal = HvCall2(HvCallCfgGetPhysicalProcessors,lp,qual);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
- return retVal;
-}
-//===================================================================
-static inline u64 HvCallCfg_getConfiguredBusUnitsForInterruptProc(HvLpIndex lp,
- u16 hvLogicalProcIndex)
-{
- u64 retVal = HvCall2(HvCallCfgGetConfiguredBusUnitsForIntProc,lp,hvLogicalProcIndex);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
- return retVal;
-
-}
-//==================================================================
-static inline HvLpSharedPoolIndex HvCallCfg_getSharedPoolIndex(HvLpIndex lp)
-{
- HvLpSharedPoolIndex retVal =
- HvCall1(HvCallCfgGetSharedPoolIndex,lp);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
- return retVal;
-
-}
-//==================================================================
-static inline u64 HvCallCfg_getSharedProcUnits(HvLpIndex lp,enum HvCallCfg_ReqQual qual)
-{
- u64 retVal = HvCall2(HvCallCfgGetSharedProcUnits,lp,qual);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
- return retVal;
-
-}
-//==================================================================
-static inline u64 HvCallCfg_getNumProcsInSharedPool(HvLpSharedPoolIndex sPI)
-{
- u16 retVal = HvCall1(HvCallCfgGetNumProcsInSharedPool,sPI);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
- return retVal;
-
-}
-//==================================================================
-static inline HvLpIndex HvCallCfg_getHostingLpIndex(HvLpIndex lp)
-{
- u64 retVal = HvCall1(HvCallCfgGetHostingLpIndex,lp);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
- return retVal;
-
-}
-
-#endif /* _HVCALLCFG_H */
/*
* HvCallEvent.h
* Copyright (C) 2001 Mike Corrigan IBM Corporation
- *
+ *
* 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 contains the "hypervisor call" interface which is used to
- * drive the hypervisor from the OS.
+ * This file contains the "hypervisor call" interface which is used to
+ * drive the hypervisor from the OS.
*/
#ifndef _HVCALLEVENT_H
#define _HVCALLEVENT_H
-/*
- * Standard Includes
- */
#include <asm/iSeries/HvCallSc.h>
#include <asm/iSeries/HvTypes.h>
#include <asm/abs_addr.h>
#define HvCallEventCloseLpEventPath HvCallEvent + 2
#define HvCallEventDmaBufList HvCallEvent + 3
#define HvCallEventDmaSingle HvCallEvent + 4
-#define HvCallEventDmaToSp HvCallEvent + 5
+#define HvCallEventDmaToSp HvCallEvent + 5
#define HvCallEventGetOverflowLpEvents HvCallEvent + 6
#define HvCallEventGetSourceLpInstanceId HvCallEvent + 7
#define HvCallEventGetTargetLpInstanceId HvCallEvent + 8
static inline void HvCallEvent_getOverflowLpEvents(u8 queueIndex)
{
- HvCall1(HvCallEventGetOverflowLpEvents,queueIndex);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
+ HvCall1(HvCallEventGetOverflowLpEvents, queueIndex);
}
static inline void HvCallEvent_setInterLpQueueIndex(u8 queueIndex)
{
- HvCall1(HvCallEventSetInterLpQueueIndex,queueIndex);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
+ HvCall1(HvCallEventSetInterLpQueueIndex, queueIndex);
}
static inline void HvCallEvent_setLpEventStack(u8 queueIndex,
abs_addr = virt_to_abs(eventStackAddr);
HvCall3(HvCallEventSetLpEventStack, queueIndex, abs_addr,
eventStackSize);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
}
static inline void HvCallEvent_setLpEventQueueInterruptProc(u8 queueIndex,
{
HvCall2(HvCallEventSetLpEventQueueInterruptProc, queueIndex,
lpLogicalProcIndex);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
}
static inline HvLpEvent_Rc HvCallEvent_signalLpEvent(struct HvLpEvent *event)
{
u64 abs_addr;
- HvLpEvent_Rc retVal;
#ifdef DEBUG_SENDEVENT
printk("HvCallEvent_signalLpEvent: *event = %016lx\n ",
(unsigned long)event);
#endif
abs_addr = virt_to_abs(event);
- retVal = (HvLpEvent_Rc)HvCall1(HvCallEventSignalLpEvent, abs_addr);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
- return retVal;
+ return HvCall1(HvCallEventSignalLpEvent, abs_addr);
}
static inline HvLpEvent_Rc HvCallEvent_signalLpEventFast(HvLpIndex targetLp,
u64 eventData1, u64 eventData2, u64 eventData3,
u64 eventData4, u64 eventData5)
{
- HvLpEvent_Rc retVal;
-
- // Pack the misc bits into a single Dword to pass to PLIC
+ /* Pack the misc bits into a single Dword to pass to PLIC */
union {
struct HvCallEvent_PackedParms parms;
u64 dword;
packed.parms.xSourceInstId = sourceInstanceId;
packed.parms.xTargetInstId = targetInstanceId;
- retVal = (HvLpEvent_Rc)HvCall7(HvCallEventSignalLpEventParms,
- packed.dword, correlationToken, eventData1,eventData2,
- eventData3,eventData4, eventData5);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
- return retVal;
+ return HvCall7(HvCallEventSignalLpEventParms, packed.dword,
+ correlationToken, eventData1, eventData2,
+ eventData3, eventData4, eventData5);
}
static inline HvLpEvent_Rc HvCallEvent_ackLpEvent(struct HvLpEvent *event)
{
u64 abs_addr;
- HvLpEvent_Rc retVal;
abs_addr = virt_to_abs(event);
- retVal = (HvLpEvent_Rc)HvCall1(HvCallEventAckLpEvent, abs_addr);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
- return retVal;
+ return HvCall1(HvCallEventAckLpEvent, abs_addr);
}
static inline HvLpEvent_Rc HvCallEvent_cancelLpEvent(struct HvLpEvent *event)
{
u64 abs_addr;
- HvLpEvent_Rc retVal;
abs_addr = virt_to_abs(event);
- retVal = (HvLpEvent_Rc)HvCall1(HvCallEventCancelLpEvent, abs_addr);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
- return retVal;
+ return HvCall1(HvCallEventCancelLpEvent, abs_addr);
}
static inline HvLpInstanceId HvCallEvent_getSourceLpInstanceId(
HvLpIndex targetLp, HvLpEvent_Type type)
{
- HvLpInstanceId retVal;
-
- retVal = HvCall2(HvCallEventGetSourceLpInstanceId, targetLp, type);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
- return retVal;
+ return HvCall2(HvCallEventGetSourceLpInstanceId, targetLp, type);
}
static inline HvLpInstanceId HvCallEvent_getTargetLpInstanceId(
HvLpIndex targetLp, HvLpEvent_Type type)
{
- HvLpInstanceId retVal;
-
- retVal = HvCall2(HvCallEventGetTargetLpInstanceId, targetLp, type);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
- return retVal;
+ return HvCall2(HvCallEventGetTargetLpInstanceId, targetLp, type);
}
static inline void HvCallEvent_openLpEventPath(HvLpIndex targetLp,
HvLpEvent_Type type)
{
HvCall2(HvCallEventOpenLpEventPath, targetLp, type);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
}
static inline void HvCallEvent_closeLpEventPath(HvLpIndex targetLp,
HvLpEvent_Type type)
{
HvCall2(HvCallEventCloseLpEventPath, targetLp, type);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
}
static inline HvLpDma_Rc HvCallEvent_dmaBufList(HvLpEvent_Type type,
/* Do these need to be converted to absolute addresses? */
u64 localBufList, u64 remoteBufList, u32 transferLength)
{
- HvLpDma_Rc retVal;
- // Pack the misc bits into a single Dword to pass to PLIC
+ /* Pack the misc bits into a single Dword to pass to PLIC */
union {
struct HvCallEvent_PackedDmaParms parms;
u64 dword;
packed.parms.xLocalInstId = localInstanceId;
packed.parms.xRemoteInstId = remoteInstanceId;
- retVal = (HvLpDma_Rc)HvCall4(HvCallEventDmaBufList,
- packed.dword, localBufList, remoteBufList,
- transferLength);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
- return retVal;
+ return HvCall4(HvCallEventDmaBufList, packed.dword, localBufList,
+ remoteBufList, transferLength);
}
static inline HvLpDma_Rc HvCallEvent_dmaSingle(HvLpEvent_Type type,
HvLpDma_AddressType remoteAddressType,
u64 localAddrOrTce, u64 remoteAddrOrTce, u32 transferLength)
{
- HvLpDma_Rc retVal;
- // Pack the misc bits into a single Dword to pass to PLIC
+ /* Pack the misc bits into a single Dword to pass to PLIC */
union {
struct HvCallEvent_PackedDmaParms parms;
u64 dword;
packed.parms.xLocalInstId = localInstanceId;
packed.parms.xRemoteInstId = remoteInstanceId;
- retVal = (HvLpDma_Rc)HvCall4(HvCallEventDmaSingle,
- packed.dword, localAddrOrTce, remoteAddrOrTce,
- transferLength);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
- return retVal;
+ return (HvLpDma_Rc)HvCall4(HvCallEventDmaSingle, packed.dword,
+ localAddrOrTce, remoteAddrOrTce, transferLength);
}
-static inline HvLpDma_Rc HvCallEvent_dmaToSp(void* local, u32 remote,
+static inline HvLpDma_Rc HvCallEvent_dmaToSp(void *local, u32 remote,
u32 length, HvLpDma_Direction dir)
{
u64 abs_addr;
- HvLpDma_Rc retVal;
abs_addr = virt_to_abs(local);
- retVal = (HvLpDma_Rc)HvCall4(HvCallEventDmaToSp, abs_addr, remote,
- length, dir);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
- return retVal;
+ return HvCall4(HvCallEventDmaToSp, abs_addr, remote, length, dir);
}
-
#endif /* _HVCALLEVENT_H */
/*
* HvCallHpt.h
* Copyright (C) 2001 Mike Corrigan IBM Corporation
- *
+ *
* 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 _HVCALLHPT_H
#define _HVCALLHPT_H
-//============================================================================
-//
-// This file contains the "hypervisor call" interface which is used to
-// drive the hypervisor from the OS.
-//
-//============================================================================
+/*
+ * This file contains the "hypervisor call" interface which is used to
+ * drive the hypervisor from the OS.
+ */
#include <asm/iSeries/HvCallSc.h>
#include <asm/iSeries/HvTypes.h>
#include <asm/mmu.h>
-//-----------------------------------------------------------------------------
-// Constants
-//-----------------------------------------------------------------------------
-
#define HvCallHptGetHptAddress HvCallHpt + 0
#define HvCallHptGetHptPages HvCallHpt + 1
#define HvCallHptSetPp HvCallHpt + 5
#define HvCallHptInvalidateSetSwBitsGet HvCallHpt + 18
-//============================================================================
-static inline u64 HvCallHpt_getHptAddress(void)
+static inline u64 HvCallHpt_getHptAddress(void)
{
- u64 retval = HvCall0(HvCallHptGetHptAddress);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
- return retval;
+ return HvCall0(HvCallHptGetHptAddress);
}
-//============================================================================
-static inline u64 HvCallHpt_getHptPages(void)
-{
- u64 retval = HvCall0(HvCallHptGetHptPages);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
- return retval;
+
+static inline u64 HvCallHpt_getHptPages(void)
+{
+ return HvCall0(HvCallHptGetHptPages);
}
-//=============================================================================
-static inline void HvCallHpt_setPp(u32 hpteIndex, u8 value)
+
+static inline void HvCallHpt_setPp(u32 hpteIndex, u8 value)
{
- HvCall2( HvCallHptSetPp, hpteIndex, value );
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
+ HvCall2(HvCallHptSetPp, hpteIndex, value);
}
-//=============================================================================
-static inline void HvCallHpt_setSwBits(u32 hpteIndex, u8 bitson, u8 bitsoff )
+
+static inline void HvCallHpt_setSwBits(u32 hpteIndex, u8 bitson, u8 bitsoff)
{
- HvCall3( HvCallHptSetSwBits, hpteIndex, bitson, bitsoff );
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
+ HvCall3(HvCallHptSetSwBits, hpteIndex, bitson, bitsoff);
}
-//=============================================================================
-static inline void HvCallHpt_invalidateNoSyncICache(u32 hpteIndex)
-
+
+static inline void HvCallHpt_invalidateNoSyncICache(u32 hpteIndex)
{
- HvCall1( HvCallHptInvalidateNoSyncICache, hpteIndex );
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
+ HvCall1(HvCallHptInvalidateNoSyncICache, hpteIndex);
}
-//=============================================================================
-static inline u64 HvCallHpt_invalidateSetSwBitsGet(u32 hpteIndex, u8 bitson, u8 bitsoff )
-
+
+static inline u64 HvCallHpt_invalidateSetSwBitsGet(u32 hpteIndex, u8 bitson,
+ u8 bitsoff)
{
u64 compressedStatus;
- compressedStatus = HvCall4( HvCallHptInvalidateSetSwBitsGet, hpteIndex, bitson, bitsoff, 1 );
- HvCall1( HvCallHptInvalidateNoSyncICache, hpteIndex );
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
+
+ compressedStatus = HvCall4(HvCallHptInvalidateSetSwBitsGet,
+ hpteIndex, bitson, bitsoff, 1);
+ HvCall1(HvCallHptInvalidateNoSyncICache, hpteIndex);
return compressedStatus;
}
-//=============================================================================
-static inline u64 HvCallHpt_findValid( HPTE *hpte, u64 vpn )
+
+static inline u64 HvCallHpt_findValid(HPTE *hpte, u64 vpn)
{
- u64 retIndex = HvCall3Ret16( HvCallHptFindValid, hpte, vpn, 0, 0 );
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
- return retIndex;
+ return HvCall3Ret16(HvCallHptFindValid, hpte, vpn, 0, 0);
}
-//=============================================================================
-static inline u64 HvCallHpt_findNextValid( HPTE *hpte, u32 hpteIndex, u8 bitson, u8 bitsoff )
+
+static inline u64 HvCallHpt_findNextValid(HPTE *hpte, u32 hpteIndex,
+ u8 bitson, u8 bitsoff)
{
- u64 retIndex = HvCall3Ret16( HvCallHptFindNextValid, hpte, hpteIndex, bitson, bitsoff );
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
- return retIndex;
+ return HvCall3Ret16(HvCallHptFindNextValid, hpte, hpteIndex,
+ bitson, bitsoff);
}
-//=============================================================================
-static inline void HvCallHpt_get( HPTE *hpte, u32 hpteIndex )
+
+static inline void HvCallHpt_get(HPTE *hpte, u32 hpteIndex)
{
- HvCall2Ret16( HvCallHptGet, hpte, hpteIndex, 0 );
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
+ HvCall2Ret16(HvCallHptGet, hpte, hpteIndex, 0);
}
-//============================================================================
-static inline void HvCallHpt_addValidate( u32 hpteIndex,
- u32 hBit,
- HPTE *hpte )
-
+
+static inline void HvCallHpt_addValidate(u32 hpteIndex, u32 hBit, HPTE *hpte)
{
- HvCall4( HvCallHptAddValidate, hpteIndex,
- hBit, (*((u64 *)hpte)), (*(((u64 *)hpte)+1)) );
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
+ HvCall4(HvCallHptAddValidate, hpteIndex, hBit, (*((u64 *)hpte)),
+ (*(((u64 *)hpte)+1)));
}
-
-//=============================================================================
-
#endif /* _HVCALLHPT_H */
-/************************************************************************/
-/* Provides the Hypervisor PCI calls for iSeries Linux Parition. */
-/* Copyright (C) 2001 <Wayne G Holm> <IBM Corporation> */
-/* */
-/* 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 */
-/************************************************************************/
-/* Change Activity: */
-/* Created, Jan 9, 2001 */
-/************************************************************************/
+/*
+ * Provides the Hypervisor PCI calls for iSeries Linux Parition.
+ * Copyright (C) 2001 <Wayne G Holm> <IBM Corporation>
+ *
+ * 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
+ *
+ * Change Activity:
+ * Created, Jan 9, 2001
+ */
#ifndef _HVCALLPCI_H
#define _HVCALLPCI_H
*/
struct HvCallPci_DsaAddr {
u16 busNumber; /* PHB index? */
- u8 subBusNumber; /* PCI bus number? */
- u8 deviceId; /* device and function? */
+ u8 subBusNumber; /* PCI bus number? */
+ u8 deviceId; /* device and function? */
u8 barNumber;
u8 reserved[3];
};
enum HvCallPci_DeviceType {
HvCallPci_NodeDevice = 1,
- HvCallPci_SpDevice = 2,
- HvCallPci_IopDevice = 3,
- HvCallPci_BridgeDevice = 4,
- HvCallPci_MultiFunctionDevice = 5,
- HvCallPci_IoaDevice = 6
+ HvCallPci_SpDevice = 2,
+ HvCallPci_IopDevice = 3,
+ HvCallPci_BridgeDevice = 4,
+ HvCallPci_MultiFunctionDevice = 5,
+ HvCallPci_IoaDevice = 6
};
struct HvCallPci_DeviceInfo {
- u32 deviceType; // See DeviceType enum for values
+ u32 deviceType; /* See DeviceType enum for values */
};
-
+
struct HvCallPci_BusUnitInfo {
- u32 sizeReturned; // length of data returned
- u32 deviceType; // see DeviceType enum for values
+ u32 sizeReturned; /* length of data returned */
+ u32 deviceType; /* see DeviceType enum for values */
};
struct HvCallPci_BridgeInfo {
- struct HvCallPci_BusUnitInfo busUnitInfo; // Generic bus unit info
- u8 subBusNumber; // Bus number of secondary bus
- u8 maxAgents; // Max idsels on secondary bus
- u8 maxSubBusNumber; // Max Sub Bus
- u8 logicalSlotNumber; // Logical Slot Number for IOA
+ struct HvCallPci_BusUnitInfo busUnitInfo; /* Generic bus unit info */
+ u8 subBusNumber; /* Bus number of secondary bus */
+ u8 maxAgents; /* Max idsels on secondary bus */
+ u8 maxSubBusNumber; /* Max Sub Bus */
+ u8 logicalSlotNumber; /* Logical Slot Number for IOA */
};
-
-// Maximum BusUnitInfo buffer size. Provided for clients so they can allocate
-// a buffer big enough for any type of bus unit. Increase as needed.
+
+/*
+ * Maximum BusUnitInfo buffer size. Provided for clients so
+ * they can allocate a buffer big enough for any type of bus
+ * unit. Increase as needed.
+ */
enum {HvCallPci_MaxBusUnitInfoSize = 128};
struct HvCallPci_BarParms {
u64 protectStart;
u64 protectEnd;
u64 relocationOffset;
- u64 pciAddress;
+ u64 pciAddress;
u64 reserved[3];
-};
+};
enum HvCallPci_VpdType {
- HvCallPci_BusVpd = 1,
+ HvCallPci_BusVpd = 1,
HvCallPci_BusAdapterVpd = 2
};
#define HvCallPciUnmaskInterrupts HvCallPci + 49
#define HvCallPciGetBusUnitInfo HvCallPci + 50
-//============================================================================
static inline u64 HvCallPci_configLoad8(u16 busNumber, u8 subBusNumber,
- u8 deviceId, u32 offset,
- u8 *value)
+ u8 deviceId, u32 offset, u8 *value)
{
struct HvCallPci_DsaAddr dsa;
struct HvCallPci_LoadReturn retVal;
- *((u64*)&dsa) = 0;
+ *((u64*)&dsa) = 0;
dsa.busNumber = busNumber;
dsa.subBusNumber = subBusNumber;
HvCall3Ret16(HvCallPciConfigLoad8, &retVal, *(u64 *)&dsa, offset, 0);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
-
*value = retVal.value;
return retVal.rc;
}
-//============================================================================
+
static inline u64 HvCallPci_configLoad16(u16 busNumber, u8 subBusNumber,
- u8 deviceId, u32 offset,
- u16 *value)
+ u8 deviceId, u32 offset, u16 *value)
{
struct HvCallPci_DsaAddr dsa;
struct HvCallPci_LoadReturn retVal;
- *((u64*)&dsa) = 0;
+ *((u64*)&dsa) = 0;
dsa.busNumber = busNumber;
dsa.subBusNumber = subBusNumber;
HvCall3Ret16(HvCallPciConfigLoad16, &retVal, *(u64 *)&dsa, offset, 0);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
-
*value = retVal.value;
return retVal.rc;
}
-//============================================================================
-static inline u64 HvCallPci_configLoad32(u16 busNumber, u8 subBusNumber,
- u8 deviceId, u32 offset,
- u32 *value)
+
+static inline u64 HvCallPci_configLoad32(u16 busNumber, u8 subBusNumber,
+ u8 deviceId, u32 offset, u32 *value)
{
struct HvCallPci_DsaAddr dsa;
struct HvCallPci_LoadReturn retVal;
- *((u64*)&dsa) = 0;
+ *((u64*)&dsa) = 0;
dsa.busNumber = busNumber;
dsa.subBusNumber = subBusNumber;
HvCall3Ret16(HvCallPciConfigLoad32, &retVal, *(u64 *)&dsa, offset, 0);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
-
*value = retVal.value;
return retVal.rc;
}
-//============================================================================
-static inline u64 HvCallPci_configStore8(u16 busNumber, u8 subBusNumber,
- u8 deviceId, u32 offset,
- u8 value)
+
+static inline u64 HvCallPci_configStore8(u16 busNumber, u8 subBusNumber,
+ u8 deviceId, u32 offset, u8 value)
{
struct HvCallPci_DsaAddr dsa;
- u64 retVal;
- *((u64*)&dsa) = 0;
+ *((u64*)&dsa) = 0;
dsa.busNumber = busNumber;
dsa.subBusNumber = subBusNumber;
dsa.deviceId = deviceId;
- retVal = HvCall4(HvCallPciConfigStore8, *(u64 *)&dsa, offset, value, 0);
-
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
-
- return retVal;
+ return HvCall4(HvCallPciConfigStore8, *(u64 *)&dsa, offset, value, 0);
}
-//============================================================================
-static inline u64 HvCallPci_configStore16(u16 busNumber, u8 subBusNumber,
- u8 deviceId, u32 offset,
- u16 value)
+
+static inline u64 HvCallPci_configStore16(u16 busNumber, u8 subBusNumber,
+ u8 deviceId, u32 offset, u16 value)
{
struct HvCallPci_DsaAddr dsa;
- u64 retVal;
- *((u64*)&dsa) = 0;
+ *((u64*)&dsa) = 0;
dsa.busNumber = busNumber;
dsa.subBusNumber = subBusNumber;
dsa.deviceId = deviceId;
- retVal = HvCall4(HvCallPciConfigStore16, *(u64 *)&dsa, offset, value, 0);
-
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
-
- return retVal;
+ return HvCall4(HvCallPciConfigStore16, *(u64 *)&dsa, offset, value, 0);
}
-//============================================================================
-static inline u64 HvCallPci_configStore32(u16 busNumber, u8 subBusNumber,
- u8 deviceId, u32 offset,
- u32 value)
+
+static inline u64 HvCallPci_configStore32(u16 busNumber, u8 subBusNumber,
+ u8 deviceId, u32 offset, u32 value)
{
struct HvCallPci_DsaAddr dsa;
- u64 retVal;
- *((u64*)&dsa) = 0;
+ *((u64*)&dsa) = 0;
dsa.busNumber = busNumber;
dsa.subBusNumber = subBusNumber;
dsa.deviceId = deviceId;
- retVal = HvCall4(HvCallPciConfigStore32, *(u64 *)&dsa, offset, value, 0);
-
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
-
- return retVal;
+ return HvCall4(HvCallPciConfigStore32, *(u64 *)&dsa, offset, value, 0);
}
-//============================================================================
-static inline u64 HvCallPci_barLoad8(u16 busNumberParm,
- u8 subBusParm,
- u8 deviceIdParm,
- u8 barNumberParm,
- u64 offsetParm,
- u8* valueParm)
+
+static inline u64 HvCallPci_barLoad8(u16 busNumberParm, u8 subBusParm,
+ u8 deviceIdParm, u8 barNumberParm, u64 offsetParm,
+ u8 *valueParm)
{
struct HvCallPci_DsaAddr dsa;
struct HvCallPci_LoadReturn retVal;
- *((u64*)&dsa) = 0;
+ *((u64*)&dsa) = 0;
dsa.busNumber = busNumberParm;
dsa.subBusNumber = subBusParm;
HvCall3Ret16(HvCallPciBarLoad8, &retVal, *(u64 *)&dsa, offsetParm, 0);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
-
*valueParm = retVal.value;
return retVal.rc;
}
-//============================================================================
-static inline u64 HvCallPci_barLoad16(u16 busNumberParm,
- u8 subBusParm,
- u8 deviceIdParm,
- u8 barNumberParm,
- u64 offsetParm,
- u16* valueParm)
+
+static inline u64 HvCallPci_barLoad16(u16 busNumberParm, u8 subBusParm,
+ u8 deviceIdParm, u8 barNumberParm, u64 offsetParm,
+ u16 *valueParm)
{
struct HvCallPci_DsaAddr dsa;
struct HvCallPci_LoadReturn retVal;
- *((u64*)&dsa) = 0;
+ *((u64*)&dsa) = 0;
dsa.busNumber = busNumberParm;
dsa.subBusNumber = subBusParm;
HvCall3Ret16(HvCallPciBarLoad16, &retVal, *(u64 *)&dsa, offsetParm, 0);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
-
*valueParm = retVal.value;
return retVal.rc;
}
-//============================================================================
-static inline u64 HvCallPci_barLoad32(u16 busNumberParm,
- u8 subBusParm,
- u8 deviceIdParm,
- u8 barNumberParm,
- u64 offsetParm,
- u32* valueParm)
+
+static inline u64 HvCallPci_barLoad32(u16 busNumberParm, u8 subBusParm,
+ u8 deviceIdParm, u8 barNumberParm, u64 offsetParm,
+ u32 *valueParm)
{
struct HvCallPci_DsaAddr dsa;
struct HvCallPci_LoadReturn retVal;
- *((u64*)&dsa) = 0;
+ *((u64*)&dsa) = 0;
dsa.busNumber = busNumberParm;
dsa.subBusNumber = subBusParm;
HvCall3Ret16(HvCallPciBarLoad32, &retVal, *(u64 *)&dsa, offsetParm, 0);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
-
*valueParm = retVal.value;
return retVal.rc;
}
-//============================================================================
-static inline u64 HvCallPci_barLoad64(u16 busNumberParm,
- u8 subBusParm,
- u8 deviceIdParm,
- u8 barNumberParm,
- u64 offsetParm,
- u64* valueParm)
+
+static inline u64 HvCallPci_barLoad64(u16 busNumberParm, u8 subBusParm,
+ u8 deviceIdParm, u8 barNumberParm, u64 offsetParm,
+ u64 *valueParm)
{
struct HvCallPci_DsaAddr dsa;
struct HvCallPci_LoadReturn retVal;
- *((u64*)&dsa) = 0;
+ *((u64*)&dsa) = 0;
dsa.busNumber = busNumberParm;
dsa.subBusNumber = subBusParm;
HvCall3Ret16(HvCallPciBarLoad64, &retVal, *(u64 *)&dsa, offsetParm, 0);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
-
*valueParm = retVal.value;
return retVal.rc;
}
-//============================================================================
-static inline u64 HvCallPci_barStore8(u16 busNumberParm,
- u8 subBusParm,
- u8 deviceIdParm,
- u8 barNumberParm,
- u64 offsetParm,
- u8 valueParm)
+
+static inline u64 HvCallPci_barStore8(u16 busNumberParm, u8 subBusParm,
+ u8 deviceIdParm, u8 barNumberParm, u64 offsetParm,
+ u8 valueParm)
{
struct HvCallPci_DsaAddr dsa;
- u64 retVal;
*((u64*)&dsa) = 0;
-
+
dsa.busNumber = busNumberParm;
dsa.subBusNumber = subBusParm;
dsa.deviceId = deviceIdParm;
dsa.barNumber = barNumberParm;
- retVal = HvCall4(HvCallPciBarStore8, *(u64 *)&dsa, offsetParm, valueParm, 0);
-
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
-
- return retVal;
+ return HvCall4(HvCallPciBarStore8, *(u64 *)&dsa, offsetParm,
+ valueParm, 0);
}
-//============================================================================
-static inline u64 HvCallPci_barStore16(u16 busNumberParm,
- u8 subBusParm,
- u8 deviceIdParm,
- u8 barNumberParm,
- u64 offsetParm,
- u16 valueParm)
+
+static inline u64 HvCallPci_barStore16(u16 busNumberParm, u8 subBusParm,
+ u8 deviceIdParm, u8 barNumberParm, u64 offsetParm,
+ u16 valueParm)
{
struct HvCallPci_DsaAddr dsa;
- u64 retVal;
*((u64*)&dsa) = 0;
-
+
dsa.busNumber = busNumberParm;
dsa.subBusNumber = subBusParm;
dsa.deviceId = deviceIdParm;
dsa.barNumber = barNumberParm;
- retVal = HvCall4(HvCallPciBarStore16, *(u64 *)&dsa, offsetParm, valueParm, 0);
-
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
-
- return retVal;
+ return HvCall4(HvCallPciBarStore16, *(u64 *)&dsa, offsetParm,
+ valueParm, 0);
}
-//============================================================================
-static inline u64 HvCallPci_barStore32(u16 busNumberParm,
- u8 subBusParm,
- u8 deviceIdParm,
- u8 barNumberParm,
- u64 offsetParm,
- u32 valueParm)
+
+static inline u64 HvCallPci_barStore32(u16 busNumberParm, u8 subBusParm,
+ u8 deviceIdParm, u8 barNumberParm, u64 offsetParm,
+ u32 valueParm)
{
struct HvCallPci_DsaAddr dsa;
- u64 retVal;
*((u64*)&dsa) = 0;
-
+
dsa.busNumber = busNumberParm;
dsa.subBusNumber = subBusParm;
dsa.deviceId = deviceIdParm;
dsa.barNumber = barNumberParm;
- retVal = HvCall4(HvCallPciBarStore32, *(u64 *)&dsa, offsetParm, valueParm, 0);
-
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
-
- return retVal;
+ return HvCall4(HvCallPciBarStore32, *(u64 *)&dsa, offsetParm,
+ valueParm, 0);
}
-//============================================================================
-static inline u64 HvCallPci_barStore64(u16 busNumberParm,
- u8 subBusParm,
- u8 deviceIdParm,
- u8 barNumberParm,
- u64 offsetParm,
- u64 valueParm)
+
+static inline u64 HvCallPci_barStore64(u16 busNumberParm, u8 subBusParm,
+ u8 deviceIdParm, u8 barNumberParm, u64 offsetParm,
+ u64 valueParm)
{
struct HvCallPci_DsaAddr dsa;
- u64 retVal;
*((u64*)&dsa) = 0;
-
+
dsa.busNumber = busNumberParm;
dsa.subBusNumber = subBusParm;
dsa.deviceId = deviceIdParm;
dsa.barNumber = barNumberParm;
- retVal = HvCall4(HvCallPciBarStore64, *(u64 *)&dsa, offsetParm, valueParm, 0);
-
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
-
- return retVal;
+ return HvCall4(HvCallPciBarStore64, *(u64 *)&dsa, offsetParm,
+ valueParm, 0);
}
-//============================================================================
-static inline u64 HvCallPci_eoi(u16 busNumberParm,
- u8 subBusParm,
- u8 deviceIdParm)
+
+static inline u64 HvCallPci_eoi(u16 busNumberParm, u8 subBusParm,
+ u8 deviceIdParm)
{
struct HvCallPci_DsaAddr dsa;
struct HvCallPci_LoadReturn retVal;
HvCall1Ret16(HvCallPciEoi, &retVal, *(u64*)&dsa);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
-
return retVal.rc;
}
-//============================================================================
-static inline u64 HvCallPci_getBarParms(u16 busNumberParm,
- u8 subBusParm,
- u8 deviceIdParm,
- u8 barNumberParm,
- u64 parms,
- u32 sizeofParms)
+
+static inline u64 HvCallPci_getBarParms(u16 busNumberParm, u8 subBusParm,
+ u8 deviceIdParm, u8 barNumberParm, u64 parms, u32 sizeofParms)
{
struct HvCallPci_DsaAddr dsa;
- u64 retVal;
*((u64*)&dsa) = 0;
dsa.deviceId = deviceIdParm;
dsa.barNumber = barNumberParm;
- retVal = HvCall3(HvCallPciGetBarParms, *(u64*)&dsa, parms, sizeofParms);
-
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
-
- return retVal;
+ return HvCall3(HvCallPciGetBarParms, *(u64*)&dsa, parms, sizeofParms);
}
-//============================================================================
-static inline u64 HvCallPci_maskFisr(u16 busNumberParm,
- u8 subBusParm,
- u8 deviceIdParm,
- u64 fisrMask)
+
+static inline u64 HvCallPci_maskFisr(u16 busNumberParm, u8 subBusParm,
+ u8 deviceIdParm, u64 fisrMask)
{
struct HvCallPci_DsaAddr dsa;
- u64 retVal;
- *((u64*)&dsa) = 0;
+ *((u64*)&dsa) = 0;
dsa.busNumber = busNumberParm;
dsa.subBusNumber = subBusParm;
dsa.deviceId = deviceIdParm;
- retVal = HvCall2(HvCallPciMaskFisr, *(u64*)&dsa, fisrMask);
-
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
-
- return retVal;
+ return HvCall2(HvCallPciMaskFisr, *(u64*)&dsa, fisrMask);
}
-//============================================================================
-static inline u64 HvCallPci_unmaskFisr(u16 busNumberParm,
- u8 subBusParm,
- u8 deviceIdParm,
- u64 fisrMask)
+
+static inline u64 HvCallPci_unmaskFisr(u16 busNumberParm, u8 subBusParm,
+ u8 deviceIdParm, u64 fisrMask)
{
struct HvCallPci_DsaAddr dsa;
- u64 retVal;
- *((u64*)&dsa) = 0;
+ *((u64*)&dsa) = 0;
dsa.busNumber = busNumberParm;
dsa.subBusNumber = subBusParm;
dsa.deviceId = deviceIdParm;
- retVal = HvCall2(HvCallPciUnmaskFisr, *(u64*)&dsa, fisrMask);
-
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
-
- return retVal;
+ return HvCall2(HvCallPciUnmaskFisr, *(u64*)&dsa, fisrMask);
}
-//============================================================================
-static inline u64 HvCallPci_setSlotReset(u16 busNumberParm,
- u8 subBusParm,
- u8 deviceIdParm,
- u64 onNotOff)
+
+static inline u64 HvCallPci_setSlotReset(u16 busNumberParm, u8 subBusParm,
+ u8 deviceIdParm, u64 onNotOff)
{
struct HvCallPci_DsaAddr dsa;
- u64 retVal;
*((u64*)&dsa) = 0;
dsa.subBusNumber = subBusParm;
dsa.deviceId = deviceIdParm;
- retVal = HvCall2(HvCallPciSetSlotReset, *(u64*)&dsa, onNotOff);
-
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
-
- return retVal;
+ return HvCall2(HvCallPciSetSlotReset, *(u64*)&dsa, onNotOff);
}
-//============================================================================
-static inline u64 HvCallPci_getDeviceInfo(u16 busNumberParm,
- u8 subBusParm,
- u8 deviceNumberParm,
- u64 parms,
- u32 sizeofParms)
+
+static inline u64 HvCallPci_getDeviceInfo(u16 busNumberParm, u8 subBusParm,
+ u8 deviceNumberParm, u64 parms, u32 sizeofParms)
{
struct HvCallPci_DsaAddr dsa;
- u64 retVal;
*((u64*)&dsa) = 0;
dsa.subBusNumber = subBusParm;
dsa.deviceId = deviceNumberParm << 4;
- retVal = HvCall3(HvCallPciGetDeviceInfo, *(u64*)&dsa, parms, sizeofParms);
-
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
-
- return retVal;
+ return HvCall3(HvCallPciGetDeviceInfo, *(u64*)&dsa, parms, sizeofParms);
}
-//============================================================================
-static inline u64 HvCallPci_maskInterrupts(u16 busNumberParm,
- u8 subBusParm,
- u8 deviceIdParm,
- u64 interruptMask)
+
+static inline u64 HvCallPci_maskInterrupts(u16 busNumberParm, u8 subBusParm,
+ u8 deviceIdParm, u64 interruptMask)
{
struct HvCallPci_DsaAddr dsa;
- u64 retVal;
- *((u64*)&dsa) = 0;
+ *((u64*)&dsa) = 0;
dsa.busNumber = busNumberParm;
dsa.subBusNumber = subBusParm;
dsa.deviceId = deviceIdParm;
- retVal = HvCall2(HvCallPciMaskInterrupts, *(u64*)&dsa, interruptMask);
-
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
-
- return retVal;
+ return HvCall2(HvCallPciMaskInterrupts, *(u64*)&dsa, interruptMask);
}
-//============================================================================
-static inline u64 HvCallPci_unmaskInterrupts(u16 busNumberParm,
- u8 subBusParm,
- u8 deviceIdParm,
- u64 interruptMask)
+
+static inline u64 HvCallPci_unmaskInterrupts(u16 busNumberParm, u8 subBusParm,
+ u8 deviceIdParm, u64 interruptMask)
{
struct HvCallPci_DsaAddr dsa;
- u64 retVal;
- *((u64*)&dsa) = 0;
+ *((u64*)&dsa) = 0;
dsa.busNumber = busNumberParm;
dsa.subBusNumber = subBusParm;
dsa.deviceId = deviceIdParm;
- retVal = HvCall2(HvCallPciUnmaskInterrupts, *(u64*)&dsa, interruptMask);
-
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
-
- return retVal;
+ return HvCall2(HvCallPciUnmaskInterrupts, *(u64*)&dsa, interruptMask);
}
-//============================================================================
-static inline u64 HvCallPci_getBusUnitInfo(u16 busNumberParm,
- u8 subBusParm,
- u8 deviceIdParm,
- u64 parms,
- u32 sizeofParms)
+static inline u64 HvCallPci_getBusUnitInfo(u16 busNumberParm, u8 subBusParm,
+ u8 deviceIdParm, u64 parms, u32 sizeofParms)
{
struct HvCallPci_DsaAddr dsa;
- u64 retVal;
- *((u64*)&dsa) = 0;
+ *((u64*)&dsa) = 0;
dsa.busNumber = busNumberParm;
dsa.subBusNumber = subBusParm;
dsa.deviceId = deviceIdParm;
- retVal = HvCall3(HvCallPciGetBusUnitInfo, *(u64*)&dsa, parms, sizeofParms);
-
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
-
- return retVal;
+ return HvCall3(HvCallPciGetBusUnitInfo, *(u64*)&dsa, parms,
+ sizeofParms);
}
-//============================================================================
-static inline int HvCallPci_getBusVpd(u16 busNumParm, u64 destParm, u16 sizeParm)
+static inline int HvCallPci_getBusVpd(u16 busNumParm, u64 destParm,
+ u16 sizeParm)
{
- int xRetSize;
- u64 xRc = HvCall4(HvCallPciGetCardVpd, busNumParm, destParm, sizeParm, HvCallPci_BusVpd);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
+ u64 xRc = HvCall4(HvCallPciGetCardVpd, busNumParm, destParm,
+ sizeParm, HvCallPci_BusVpd);
if (xRc == -1)
- xRetSize = -1;
+ return -1;
else
- xRetSize = xRc & 0xFFFF;
- return xRetSize;
+ return xRc & 0xFFFF;
}
-//============================================================================
-static inline int HvCallPci_getBusAdapterVpd(u16 busNumParm, u64 destParm, u16 sizeParm)
+static inline int HvCallPci_getBusAdapterVpd(u16 busNumParm, u64 destParm,
+ u16 sizeParm)
{
- int xRetSize;
- u64 xRc = HvCall4(HvCallPciGetCardVpd, busNumParm, destParm, sizeParm, HvCallPci_BusAdapterVpd);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
+ u64 xRc = HvCall4(HvCallPciGetCardVpd, busNumParm, destParm,
+ sizeParm, HvCallPci_BusAdapterVpd);
if (xRc == -1)
- xRetSize = -1;
+ return -1;
else
- xRetSize = xRc & 0xFFFF;
- return xRetSize;
+ return xRc & 0xFFFF;
}
-//============================================================================
+
#endif /* _HVCALLPCI_H */
/*
* HvCallSc.h
* Copyright (C) 2001 Mike Corrigan IBM Corporation
- *
+ *
* 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 _HVCALLSC_H
#define _HVCALLSC_H
-#include <asm/iSeries/HvTypes.h>
+#include <linux/types.h>
#define HvCallBase 0x8000000000000000ul
#define HvCallCc 0x8001000000000000ul
#define HvCallSm 0x8007000000000000ul
#define HvCallXm 0x8009000000000000ul
-u64 HvCall0( u64 );
-u64 HvCall1( u64, u64 );
-u64 HvCall2( u64, u64, u64 );
-u64 HvCall3( u64, u64, u64, u64 );
-u64 HvCall4( u64, u64, u64, u64, u64 );
-u64 HvCall5( u64, u64, u64, u64, u64, u64 );
-u64 HvCall6( u64, u64, u64, u64, u64, u64, u64 );
-u64 HvCall7( u64, u64, u64, u64, u64, u64, u64, u64 );
+extern u64 HvCall0(u64);
+extern u64 HvCall1(u64, u64);
+extern u64 HvCall2(u64, u64, u64);
+extern u64 HvCall3(u64, u64, u64, u64);
+extern u64 HvCall4(u64, u64, u64, u64, u64);
+extern u64 HvCall5(u64, u64, u64, u64, u64, u64);
+extern u64 HvCall6(u64, u64, u64, u64, u64, u64, u64);
+extern u64 HvCall7(u64, u64, u64, u64, u64, u64, u64, u64);
-u64 HvCall0Ret16( u64, void * );
-u64 HvCall1Ret16( u64, void *, u64 );
-u64 HvCall2Ret16( u64, void *, u64, u64 );
-u64 HvCall3Ret16( u64, void *, u64, u64, u64 );
-u64 HvCall4Ret16( u64, void *, u64, u64, u64, u64 );
-u64 HvCall5Ret16( u64, void *, u64, u64, u64, u64, u64 );
-u64 HvCall6Ret16( u64, void *, u64, u64, u64, u64, u64, u64 );
-u64 HvCall7Ret16( u64, void *, u64, u64 ,u64 ,u64 ,u64 ,u64 ,u64 );
+extern u64 HvCall0Ret16(u64, void *);
+extern u64 HvCall1Ret16(u64, void *, u64);
+extern u64 HvCall2Ret16(u64, void *, u64, u64);
+extern u64 HvCall3Ret16(u64, void *, u64, u64, u64);
+extern u64 HvCall4Ret16(u64, void *, u64, u64, u64, u64);
+extern u64 HvCall5Ret16(u64, void *, u64, u64, u64, u64, u64);
+extern u64 HvCall6Ret16(u64, void *, u64, u64, u64, u64, u64, u64);
+extern u64 HvCall7Ret16(u64, void *, u64, u64 ,u64 ,u64 ,u64 ,u64 ,u64);
#endif /* _HVCALLSC_H */
/*
* HvCallSm.h
* Copyright (C) 2001 Mike Corrigan IBM Corporation
- *
+ *
* 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 _HVCALLSM_H
#define _HVCALLSM_H
-//============================================================================
-//
-// This file contains the "hypervisor call" interface which is used to
-// drive the hypervisor from the OS.
-//
-//============================================================================
+/*
+ * This file contains the "hypervisor call" interface which is used to
+ * drive the hypervisor from the OS.
+ */
-//-------------------------------------------------------------------
-// Standard Includes
-//-------------------------------------------------------------------
#include <asm/iSeries/HvCallSc.h>
#include <asm/iSeries/HvTypes.h>
-//-----------------------------------------------------------------------------
-// Constants
-//-----------------------------------------------------------------------------
-
#define HvCallSmGet64BitsOfAccessMap HvCallSm + 11
-
-//============================================================================
-static inline u64 HvCallSm_get64BitsOfAccessMap(
- HvLpIndex lpIndex, u64 indexIntoBitMap )
+static inline u64 HvCallSm_get64BitsOfAccessMap(HvLpIndex lpIndex,
+ u64 indexIntoBitMap)
{
- u64 retval = HvCall2(HvCallSmGet64BitsOfAccessMap, lpIndex,
- indexIntoBitMap );
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
- return retval;
+ return HvCall2(HvCallSmGet64BitsOfAccessMap, lpIndex, indexIntoBitMap);
}
-//============================================================================
+
#endif /* _HVCALLSM_H */
-//============================================================================
-// Header File Id
-// Name______________: HvCallXm.H
-//
-// Description_______:
-//
-// This file contains the "hypervisor call" interface which is used to
-// drive the hypervisor from SLIC.
-//
-//============================================================================
+/*
+ * This file contains the "hypervisor call" interface which is used to
+ * drive the hypervisor from SLIC.
+ */
#ifndef _HVCALLXM_H
#define _HVCALLXM_H
-//-------------------------------------------------------------------
-// Forward declarations
-//-------------------------------------------------------------------
-
-//-------------------------------------------------------------------
-// Standard Includes
-//-------------------------------------------------------------------
#include <asm/iSeries/HvCallSc.h>
#include <asm/iSeries/HvTypes.h>
-//-----------------------------------------------------------------------------
-// Constants
-//-----------------------------------------------------------------------------
-
#define HvCallXmGetTceTableParms HvCallXm + 0
#define HvCallXmTestBus HvCallXm + 1
#define HvCallXmConnectBusUnit HvCallXm + 2
#define HvCallXmSetTce HvCallXm + 11
#define HvCallXmSetTces HvCallXm + 13
+/*
+ * Structure passed to HvCallXm_getTceTableParms
+ */
+struct iommu_table_cb {
+ unsigned long itc_busno; /* Bus number for this tce table */
+ unsigned long itc_start; /* Will be NULL for secondary */
+ unsigned long itc_totalsize; /* Size (in pages) of whole table */
+ unsigned long itc_offset; /* Index into real tce table of the
+ start of our section */
+ unsigned long itc_size; /* Size (in pages) of our section */
+ unsigned long itc_index; /* Index of this tce table */
+ unsigned short itc_maxtables; /* Max num of tables for partition */
+ unsigned char itc_virtbus; /* Flag to indicate virtual bus */
+ unsigned char itc_slotno; /* IOA Tce Slot Index */
+ unsigned char itc_rsvd[4];
+};
-
-//============================================================================
-static inline void HvCallXm_getTceTableParms(u64 cb)
+static inline void HvCallXm_getTceTableParms(u64 cb)
{
HvCall1(HvCallXmGetTceTableParms, cb);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
}
-//============================================================================
-static inline u64 HvCallXm_setTce(u64 tceTableToken, u64 tceOffset, u64 tce)
-{
- u64 retval = HvCall3(HvCallXmSetTce, tceTableToken, tceOffset, tce );
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
- return retval;
-}
-//============================================================================
-static inline u64 HvCallXm_setTces(u64 tceTableToken, u64 tceOffset, u64 numTces, u64 tce1, u64 tce2, u64 tce3, u64 tce4)
-{
- u64 retval = HvCall7(HvCallXmSetTces, tceTableToken, tceOffset, numTces,
- tce1, tce2, tce3, tce4 );
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
- return retval;
+
+static inline u64 HvCallXm_setTce(u64 tceTableToken, u64 tceOffset, u64 tce)
+{
+ return HvCall3(HvCallXmSetTce, tceTableToken, tceOffset, tce);
}
-//=============================================================================
-static inline u64 HvCallXm_testBus(u16 busNumber)
+
+static inline u64 HvCallXm_setTces(u64 tceTableToken, u64 tceOffset,
+ u64 numTces, u64 tce1, u64 tce2, u64 tce3, u64 tce4)
{
- u64 retVal = HvCall1(HvCallXmTestBus, busNumber);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
- return retVal;
+ return HvCall7(HvCallXmSetTces, tceTableToken, tceOffset, numTces,
+ tce1, tce2, tce3, tce4);
}
-//=====================================================================================
-static inline u64 HvCallXm_testBusUnit(u16 busNumber, u8 subBusNumber, u8 deviceId)
+
+static inline u64 HvCallXm_testBus(u16 busNumber)
{
- u64 busUnitNumber = (subBusNumber << 8) | deviceId;
- u64 retVal = HvCall2(HvCallXmTestBusUnit, busNumber, busUnitNumber);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
- return retVal;
+ return HvCall1(HvCallXmTestBus, busNumber);
}
-//=====================================================================================
-static inline u64 HvCallXm_connectBusUnit(u16 busNumber, u8 subBusNumber, u8 deviceId,
- u64 interruptToken)
+
+static inline u64 HvCallXm_testBusUnit(u16 busNumber, u8 subBusNumber,
+ u8 deviceId)
{
- u64 busUnitNumber = (subBusNumber << 8) | deviceId;
- u64 queueIndex = 0; // HvLpConfig::mapDsaToQueueIndex(HvLpDSA(busNumber, xBoard, xCard));
+ return HvCall2(HvCallXmTestBusUnit, busNumber,
+ (subBusNumber << 8) | deviceId);
+}
- u64 retVal = HvCall5(HvCallXmConnectBusUnit, busNumber, busUnitNumber,
- interruptToken, 0, queueIndex);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
- return retVal;
+static inline u64 HvCallXm_connectBusUnit(u16 busNumber, u8 subBusNumber,
+ u8 deviceId, u64 interruptToken)
+{
+ return HvCall5(HvCallXmConnectBusUnit, busNumber,
+ (subBusNumber << 8) | deviceId, interruptToken, 0,
+ 0 /* HvLpConfig::mapDsaToQueueIndex(HvLpDSA(busNumber, xBoard, xCard)) */);
}
-//=====================================================================================
-static inline u64 HvCallXm_loadTod(void)
+
+static inline u64 HvCallXm_loadTod(void)
{
- u64 retVal = HvCall0(HvCallXmLoadTod);
- // getPaca()->adjustHmtForNoOfSpinLocksHeld();
- return retVal;
+ return HvCall0(HvCallXmLoadTod);
}
-//=====================================================================================
#endif /* _HVCALLXM_H */
/*
* HvLpConfig.h
* Copyright (C) 2001 Mike Corrigan IBM Corporation
- *
+ *
* 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 _HVLPCONFIG_H
#define _HVLPCONFIG_H
-//===========================================================================
-//
-// This file contains the interface to the LPAR configuration data
-// to determine which resources should be allocated to each partition.
-//
-//===========================================================================
+/*
+ * This file contains the interface to the LPAR configuration data
+ * to determine which resources should be allocated to each partition.
+ */
-#include <asm/iSeries/HvCallCfg.h>
+#include <asm/iSeries/HvCallSc.h>
#include <asm/iSeries/HvTypes.h>
#include <asm/iSeries/ItLpNaca.h>
-#include <asm/iSeries/LparData.h>
-//-------------------------------------------------------------------
-// Constants
-//-------------------------------------------------------------------
+enum {
+ HvCallCfg_Cur = 0,
+ HvCallCfg_Init = 1,
+ HvCallCfg_Max = 2,
+ HvCallCfg_Min = 3
+};
+
+#define HvCallCfgGetSystemPhysicalProcessors HvCallCfg + 6
+#define HvCallCfgGetPhysicalProcessors HvCallCfg + 7
+#define HvCallCfgGetMsChunks HvCallCfg + 9
+#define HvCallCfgGetSharedPoolIndex HvCallCfg + 20
+#define HvCallCfgGetSharedProcUnits HvCallCfg + 21
+#define HvCallCfgGetNumProcsInSharedPool HvCallCfg + 22
+#define HvCallCfgGetVirtualLanIndexMap HvCallCfg + 30
+#define HvCallCfgGetHostingLpIndex HvCallCfg + 32
extern HvLpIndex HvLpConfig_getLpIndex_outline(void);
-//===================================================================
static inline HvLpIndex HvLpConfig_getLpIndex(void)
{
return itLpNaca.xLpIndex;
}
-//===================================================================
+
static inline HvLpIndex HvLpConfig_getPrimaryLpIndex(void)
{
return itLpNaca.xPrimaryLpIndex;
}
-//=================================================================
-static inline HvLpIndex HvLpConfig_getLps(void)
-{
- return HvCallCfg_getLps();
-}
-//=================================================================
-static inline HvLpIndexMap HvLpConfig_getActiveLpMap(void)
-{
- return HvCallCfg_getActiveLpMap();
-}
-//=================================================================
-static inline u64 HvLpConfig_getSystemMsMegs(void)
-{
- return HvCallCfg_getSystemMsChunks() / HVCHUNKSPERMEG;
-}
-//=================================================================
-static inline u64 HvLpConfig_getSystemMsChunks(void)
-{
- return HvCallCfg_getSystemMsChunks();
-}
-//=================================================================
-static inline u64 HvLpConfig_getSystemMsPages(void)
-{
- return HvCallCfg_getSystemMsChunks() * HVPAGESPERCHUNK;
-}
-//================================================================
-static inline u64 HvLpConfig_getMsMegs(void)
-{
- return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(),HvCallCfg_Cur) / HVCHUNKSPERMEG;
-}
-//================================================================
-static inline u64 HvLpConfig_getMsChunks(void)
-{
- return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(),HvCallCfg_Cur);
-}
-//================================================================
-static inline u64 HvLpConfig_getMsPages(void)
-{
- return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(),HvCallCfg_Cur) * HVPAGESPERCHUNK;
-}
-//================================================================
-static inline u64 HvLpConfig_getMinMsMegs(void)
-{
- return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(),HvCallCfg_Min) / HVCHUNKSPERMEG;
-}
-//================================================================
-static inline u64 HvLpConfig_getMinMsChunks(void)
-{
- return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(),HvCallCfg_Min);
-}
-//================================================================
-static inline u64 HvLpConfig_getMinMsPages(void)
-{
- return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(),HvCallCfg_Min) * HVPAGESPERCHUNK;
-}
-//================================================================
-static inline u64 HvLpConfig_getMinRuntimeMsMegs(void)
-{
- return HvCallCfg_getMinRuntimeMsChunks(HvLpConfig_getLpIndex()) / HVCHUNKSPERMEG;
-}
-//===============================================================
-static inline u64 HvLpConfig_getMinRuntimeMsChunks(void)
-{
- return HvCallCfg_getMinRuntimeMsChunks(HvLpConfig_getLpIndex());
-}
-//===============================================================
-static inline u64 HvLpConfig_getMinRuntimeMsPages(void)
-{
- return HvCallCfg_getMinRuntimeMsChunks(HvLpConfig_getLpIndex()) * HVPAGESPERCHUNK;
-}
-//===============================================================
-static inline u64 HvLpConfig_getMaxMsMegs(void)
-{
- return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(),HvCallCfg_Max) / HVCHUNKSPERMEG;
-}
-//===============================================================
-static inline u64 HvLpConfig_getMaxMsChunks(void)
-{
- return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(),HvCallCfg_Max);
-}
-//===============================================================
-static inline u64 HvLpConfig_getMaxMsPages(void)
-{
- return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(),HvCallCfg_Max) * HVPAGESPERCHUNK;
-}
-//===============================================================
-static inline u64 HvLpConfig_getInitMsMegs(void)
-{
- return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(),HvCallCfg_Init) / HVCHUNKSPERMEG;
-}
-//===============================================================
-static inline u64 HvLpConfig_getInitMsChunks(void)
-{
- return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(),HvCallCfg_Init);
-}
-//===============================================================
-static inline u64 HvLpConfig_getInitMsPages(void)
-{ return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(),HvCallCfg_Init) * HVPAGESPERCHUNK;
-}
-//===============================================================
-static inline u64 HvLpConfig_getSystemPhysicalProcessors(void)
-{
- return HvCallCfg_getSystemPhysicalProcessors();
-}
-//===============================================================
-static inline u64 HvLpConfig_getSystemLogicalProcessors(void)
-{
- return HvCallCfg_getSystemPhysicalProcessors() * (/*getPaca()->getSecondaryThreadCount() +*/ 1);
-}
-//===============================================================
-static inline u64 HvLpConfig_getNumProcsInSharedPool(HvLpSharedPoolIndex sPI)
-{
- return HvCallCfg_getNumProcsInSharedPool(sPI);
-}
-//===============================================================
-static inline u64 HvLpConfig_getPhysicalProcessors(void)
-{
- return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(),HvCallCfg_Cur);
-}
-//===============================================================
-static inline u64 HvLpConfig_getLogicalProcessors(void)
-{
- return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(),HvCallCfg_Cur) * (/*getPaca()->getSecondaryThreadCount() +*/ 1);
-}
-//===============================================================
-static inline HvLpSharedPoolIndex HvLpConfig_getSharedPoolIndex(void)
-{
- return HvCallCfg_getSharedPoolIndex(HvLpConfig_getLpIndex());
-}
-//===============================================================
-static inline u64 HvLpConfig_getSharedProcUnits(void)
-{
- return HvCallCfg_getSharedProcUnits(HvLpConfig_getLpIndex(),HvCallCfg_Cur);
-}
-//===============================================================
-static inline u64 HvLpConfig_getMinSharedProcUnits(void)
-{
- return HvCallCfg_getSharedProcUnits(HvLpConfig_getLpIndex(),HvCallCfg_Min);
-}
-//===============================================================
-static inline u64 HvLpConfig_getMaxSharedProcUnits(void)
-{
- return HvCallCfg_getSharedProcUnits(HvLpConfig_getLpIndex(),HvCallCfg_Max);
-}
-//===============================================================
-static inline u64 HvLpConfig_getMinPhysicalProcessors(void)
-{
- return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(),HvCallCfg_Min);
-}
-//===============================================================
-static inline u64 HvLpConfig_getMinLogicalProcessors(void)
-{
- return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(),HvCallCfg_Min) * (/*getPaca()->getSecondaryThreadCount() +*/ 1);
-}
-//===============================================================
-static inline u64 HvLpConfig_getMaxPhysicalProcessors(void)
-{
- return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(),HvCallCfg_Max);
-}
-//===============================================================
-static inline u64 HvLpConfig_getMaxLogicalProcessors(void)
-{
- return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(),HvCallCfg_Max) * (/*getPaca()->getSecondaryThreadCount() +*/ 1);
-}
-//===============================================================
-static inline u64 HvLpConfig_getInitPhysicalProcessors(void)
+
+static inline u64 HvLpConfig_getMsChunks(void)
{
- return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(),HvCallCfg_Init);
+ return HvCall2(HvCallCfgGetMsChunks, HvLpConfig_getLpIndex(),
+ HvCallCfg_Cur);
}
-//===============================================================
-static inline u64 HvLpConfig_getInitLogicalProcessors(void)
+
+static inline u64 HvLpConfig_getSystemPhysicalProcessors(void)
{
- return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(),HvCallCfg_Init) * (/*getPaca()->getSecondaryThreadCount() +*/ 1);
+ return HvCall0(HvCallCfgGetSystemPhysicalProcessors);
}
-//================================================================
-static inline HvLpVirtualLanIndexMap HvLpConfig_getVirtualLanIndexMap(void)
+
+static inline u64 HvLpConfig_getNumProcsInSharedPool(HvLpSharedPoolIndex sPI)
{
- return HvCallCfg_getVirtualLanIndexMap(HvLpConfig_getLpIndex_outline());
+ return (u16)HvCall1(HvCallCfgGetNumProcsInSharedPool, sPI);
}
-//===============================================================
-static inline HvLpVirtualLanIndexMap HvLpConfig_getVirtualLanIndexMapForLp(HvLpIndex lp)
+
+static inline u64 HvLpConfig_getPhysicalProcessors(void)
{
- return HvCallCfg_getVirtualLanIndexMap(lp);
+ return HvCall2(HvCallCfgGetPhysicalProcessors, HvLpConfig_getLpIndex(),
+ HvCallCfg_Cur);
}
-//================================================================
-static inline HvLpIndex HvLpConfig_getBusOwner(HvBusNumber busNumber)
+
+static inline HvLpSharedPoolIndex HvLpConfig_getSharedPoolIndex(void)
{
- return HvCallCfg_getBusOwner(busNumber);
+ return HvCall1(HvCallCfgGetSharedPoolIndex, HvLpConfig_getLpIndex());
}
-//===============================================================
-static inline int HvLpConfig_isBusDedicated(HvBusNumber busNumber)
+
+static inline u64 HvLpConfig_getSharedProcUnits(void)
{
- return HvCallCfg_isBusDedicated(busNumber);
+ return HvCall2(HvCallCfgGetSharedProcUnits, HvLpConfig_getLpIndex(),
+ HvCallCfg_Cur);
}
-//================================================================
-static inline HvLpIndexMap HvLpConfig_getBusAllocation(HvBusNumber busNumber)
+
+static inline u64 HvLpConfig_getMaxSharedProcUnits(void)
{
- return HvCallCfg_getBusAllocation(busNumber);
+ return HvCall2(HvCallCfgGetSharedProcUnits, HvLpConfig_getLpIndex(),
+ HvCallCfg_Max);
}
-//================================================================
-// returns the absolute real address of the load area
-static inline u64 HvLpConfig_getLoadAddress(void)
+
+static inline u64 HvLpConfig_getMaxPhysicalProcessors(void)
{
- return itLpNaca.xLoadAreaAddr & 0x7fffffffffffffff;
+ return HvCall2(HvCallCfgGetPhysicalProcessors, HvLpConfig_getLpIndex(),
+ HvCallCfg_Max);
}
-//================================================================
-static inline u64 HvLpConfig_getLoadPages(void)
-{
- return itLpNaca.xLoadAreaChunks * HVPAGESPERCHUNK;
+
+static inline HvLpVirtualLanIndexMap HvLpConfig_getVirtualLanIndexMapForLp(
+ HvLpIndex lp)
+{
+ /*
+ * This is a new function in V5R1 so calls to this on older
+ * hypervisors will return -1
+ */
+ u64 retVal = HvCall1(HvCallCfgGetVirtualLanIndexMap, lp);
+ if (retVal == -1)
+ retVal = 0;
+ return retVal;
}
-//================================================================
-static inline int HvLpConfig_isBusOwnedByThisLp(HvBusNumber busNumber)
+
+static inline HvLpVirtualLanIndexMap HvLpConfig_getVirtualLanIndexMap(void)
{
- HvLpIndex busOwner = HvLpConfig_getBusOwner(busNumber);
- return (busOwner == HvLpConfig_getLpIndex());
+ return HvLpConfig_getVirtualLanIndexMapForLp(
+ HvLpConfig_getLpIndex_outline());
}
-//================================================================
-static inline int HvLpConfig_doLpsCommunicateOnVirtualLan(HvLpIndex lp1, HvLpIndex lp2)
+
+static inline int HvLpConfig_doLpsCommunicateOnVirtualLan(HvLpIndex lp1,
+ HvLpIndex lp2)
{
- HvLpVirtualLanIndexMap virtualLanIndexMap1 = HvCallCfg_getVirtualLanIndexMap( lp1 );
- HvLpVirtualLanIndexMap virtualLanIndexMap2 = HvCallCfg_getVirtualLanIndexMap( lp2 );
+ HvLpVirtualLanIndexMap virtualLanIndexMap1 =
+ HvLpConfig_getVirtualLanIndexMapForLp(lp1);
+ HvLpVirtualLanIndexMap virtualLanIndexMap2 =
+ HvLpConfig_getVirtualLanIndexMapForLp(lp2);
return ((virtualLanIndexMap1 & virtualLanIndexMap2) != 0);
}
-//================================================================
-static inline HvLpIndex HvLpConfig_getHostingLpIndex(HvLpIndex lp)
+
+static inline HvLpIndex HvLpConfig_getHostingLpIndex(HvLpIndex lp)
{
- return HvCallCfg_getHostingLpIndex(lp);
+ return HvCall1(HvCallCfgGetHostingLpIndex, lp);
}
-//================================================================
#endif /* _HVLPCONFIG_H */
/*
* HvLpEvent.h
* Copyright (C) 2001 Mike Corrigan IBM Corporation
- *
+ *
* 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 contains the class for HV events in the system.
-//
-//=====================================================================
+/* This file contains the class for HV events in the system. */
+
#ifndef _HVLPEVENT_H
#define _HVLPEVENT_H
#include <asm/iSeries/HvTypes.h>
#include <asm/iSeries/HvCallEvent.h>
-//=====================================================================
-//
-// HvLpEvent is the structure for Lp Event messages passed between
-// partitions through PLIC.
-//
-//=====================================================================
-
-struct HvEventFlags
-{
- u8 xValid:1; // Indicates a valid request x00-x00
- u8 xRsvd1:4; // Reserved ...
- u8 xAckType:1; // Immediate or deferred ...
- u8 xAckInd:1; // Indicates if ACK required ...
- u8 xFunction:1; // Interrupt or Acknowledge ...
+/*
+ * HvLpEvent is the structure for Lp Event messages passed between
+ * partitions through PLIC.
+ */
+
+struct HvEventFlags {
+ u8 xValid:1; /* Indicates a valid request x00-x00 */
+ u8 xRsvd1:4; /* Reserved ... */
+ u8 xAckType:1; /* Immediate or deferred ... */
+ u8 xAckInd:1; /* Indicates if ACK required ... */
+ u8 xFunction:1; /* Interrupt or Acknowledge ... */
};
-struct HvLpEvent
-{
- struct HvEventFlags xFlags; // Event flags x00-x00
- u8 xType; // Type of message x01-x01
- u16 xSubtype; // Subtype for event x02-x03
- u8 xSourceLp; // Source LP x04-x04
- u8 xTargetLp; // Target LP x05-x05
- u8 xSizeMinus1; // Size of Derived class - 1 x06-x06
- u8 xRc; // RC for Ack flows x07-x07
- u16 xSourceInstanceId; // Source sides instance id x08-x09
- u16 xTargetInstanceId; // Target sides instance id x0A-x0B
+struct HvLpEvent {
+ struct HvEventFlags xFlags; /* Event flags x00-x00 */
+ u8 xType; /* Type of message x01-x01 */
+ u16 xSubtype; /* Subtype for event x02-x03 */
+ u8 xSourceLp; /* Source LP x04-x04 */
+ u8 xTargetLp; /* Target LP x05-x05 */
+ u8 xSizeMinus1; /* Size of Derived class - 1 x06-x06 */
+ u8 xRc; /* RC for Ack flows x07-x07 */
+ u16 xSourceInstanceId; /* Source sides instance id x08-x09 */
+ u16 xTargetInstanceId; /* Target sides instance id x0A-x0B */
union {
- u32 xSubtypeData; // Data usable by the subtype x0C-x0F
- u16 xSubtypeDataShort[2]; // Data as 2 shorts
- u8 xSubtypeDataChar[4]; // Data as 4 chars
+ u32 xSubtypeData; /* Data usable by the subtype x0C-x0F */
+ u16 xSubtypeDataShort[2]; /* Data as 2 shorts */
+ u8 xSubtypeDataChar[4]; /* Data as 4 chars */
} x;
- u64 xCorrelationToken; // Unique value for source/type x10-x17
+ u64 xCorrelationToken; /* Unique value for source/type x10-x17 */
};
-// Lp Event handler function
typedef void (*LpEventHandler)(struct HvLpEvent *, struct pt_regs *);
-// Register a handler for an event type
-// returns 0 on success
-extern int HvLpEvent_registerHandler( HvLpEvent_Type eventType, LpEventHandler hdlr);
-
-// Unregister a handler for an event type
-// This call will sleep until the handler being removed is guaranteed to
-// be no longer executing on any CPU. Do not call with locks held.
-//
-// returns 0 on success
-// Unregister will fail if there are any paths open for the type
-extern int HvLpEvent_unregisterHandler( HvLpEvent_Type eventType );
+/* Register a handler for an event type - returns 0 on success */
+extern int HvLpEvent_registerHandler(HvLpEvent_Type eventType,
+ LpEventHandler hdlr);
-// Open an Lp Event Path for an event type
-// returns 0 on success
-// openPath will fail if there is no handler registered for the event type.
-// The lpIndex specified is the partition index for the target partition
-// (for VirtualIo, VirtualLan and SessionMgr) other types specify zero)
-extern int HvLpEvent_openPath( HvLpEvent_Type eventType, HvLpIndex lpIndex );
+/*
+ * Unregister a handler for an event type
+ *
+ * This call will sleep until the handler being removed is guaranteed to
+ * be no longer executing on any CPU. Do not call with locks held.
+ *
+ * returns 0 on success
+ * Unregister will fail if there are any paths open for the type
+ */
+extern int HvLpEvent_unregisterHandler(HvLpEvent_Type eventType);
+/*
+ * Open an Lp Event Path for an event type
+ * returns 0 on success
+ * openPath will fail if there is no handler registered for the event type.
+ * The lpIndex specified is the partition index for the target partition
+ * (for VirtualIo, VirtualLan and SessionMgr) other types specify zero)
+ */
+extern int HvLpEvent_openPath(HvLpEvent_Type eventType, HvLpIndex lpIndex);
-// Close an Lp Event Path for a type and partition
-// returns 0 on sucess
-extern int HvLpEvent_closePath( HvLpEvent_Type eventType, HvLpIndex lpIndex );
+/*
+ * Close an Lp Event Path for a type and partition
+ * returns 0 on sucess
+ */
+extern int HvLpEvent_closePath(HvLpEvent_Type eventType, HvLpIndex lpIndex);
#define HvLpEvent_Type_Hypervisor 0
#define HvLpEvent_Type_MachineFac 1
#define HvLpDma_Rc_InvalidAddress 4
#define HvLpDma_Rc_InvalidLength 5
-#endif // _HVLPEVENT_H
+#endif /* _HVLPEVENT_H */
/*
* HvReleaseData.h
* Copyright (C) 2001 Mike Corrigan IBM Corporation
- *
+ *
* 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 _HVRELEASEDATA_H
#define _HVRELEASEDATA_H
-//=============================================================================
-//
-// This control block contains the critical information about the
-// release so that it can be changed in the future (ie, the virtual
-// address of the OS's NACA).
-//
+/*
+ * This control block contains the critical information about the
+ * release so that it can be changed in the future (ie, the virtual
+ * address of the OS's NACA).
+ */
#include <asm/types.h>
#include <asm/naca.h>
-//=============================================================================
-//
-// When we IPL a secondary partition, we will check if if the
-// secondary xMinPlicVrmIndex > the primary xVrmIndex.
-// If it is then this tells PLIC that this secondary is not
-// supported running on this "old" of a level of PLIC.
-//
-// Likewise, we will compare the primary xMinSlicVrmIndex to
-// the secondary xVrmIndex.
-// If the primary xMinSlicVrmDelta > secondary xVrmDelta then we
-// know that this PLIC does not support running an OS "that old".
-//
-//=============================================================================
+/*
+ * When we IPL a secondary partition, we will check if if the
+ * secondary xMinPlicVrmIndex > the primary xVrmIndex.
+ * If it is then this tells PLIC that this secondary is not
+ * supported running on this "old" of a level of PLIC.
+ *
+ * Likewise, we will compare the primary xMinSlicVrmIndex to
+ * the secondary xVrmIndex.
+ * If the primary xMinSlicVrmDelta > secondary xVrmDelta then we
+ * know that this PLIC does not support running an OS "that old".
+ */
-struct HvReleaseData
-{
- u32 xDesc; // Descriptor "HvRD" ebcdic x00-x03
- u16 xSize; // Size of this control block x04-x05
- u16 xVpdAreasPtrOffset; // Offset in NACA of ItVpdAreas x06-x07
- struct naca_struct * xSlicNacaAddr; // Virt addr of SLIC NACA x08-x0F
- u32 xMsNucDataOffset; // Offset of Linux Mapping Data x10-x13
- u32 xRsvd1; // Reserved x14-x17
- u16 xTagsMode:1; // 0 == tags active, 1 == tags inactive
- u16 xAddressSize:1; // 0 == 64-bit, 1 == 32-bit
- u16 xNoSharedProcs:1; // 0 == shared procs, 1 == no shared
- u16 xNoHMT:1; // 0 == allow HMT, 1 == no HMT
- u16 xRsvd2:12; // Reserved x18-x19
- u16 xVrmIndex; // VRM Index of OS image x1A-x1B
- u16 xMinSupportedPlicVrmIndex;// Min PLIC level (soft) x1C-x1D
- u16 xMinCompatablePlicVrmIndex;// Min PLIC levelP (hard) x1E-x1F
- char xVrmName[12]; // Displayable name x20-x2B
- char xRsvd3[20]; // Reserved x2C-x3F
+struct HvReleaseData {
+ u32 xDesc; /* Descriptor "HvRD" ebcdic x00-x03 */
+ u16 xSize; /* Size of this control block x04-x05 */
+ u16 xVpdAreasPtrOffset; /* Offset in NACA of ItVpdAreas x06-x07 */
+ struct naca_struct *xSlicNacaAddr; /* Virt addr of SLIC NACA x08-x0F */
+ u32 xMsNucDataOffset; /* Offset of Linux Mapping Data x10-x13 */
+ u32 xRsvd1; /* Reserved x14-x17 */
+ u16 xTagsMode:1; /* 0 == tags active, 1 == tags inactive */
+ u16 xAddressSize:1; /* 0 == 64-bit, 1 == 32-bit */
+ u16 xNoSharedProcs:1; /* 0 == shared procs, 1 == no shared */
+ u16 xNoHMT:1; /* 0 == allow HMT, 1 == no HMT */
+ u16 xRsvd2:12; /* Reserved x18-x19 */
+ u16 xVrmIndex; /* VRM Index of OS image x1A-x1B */
+ u16 xMinSupportedPlicVrmIndex; /* Min PLIC level (soft) x1C-x1D */
+ u16 xMinCompatablePlicVrmIndex; /* Min PLIC levelP (hard) x1E-x1F */
+ char xVrmName[12]; /* Displayable name x20-x2B */
+ char xRsvd3[20]; /* Reserved x2C-x3F */
};
+extern struct HvReleaseData hvReleaseData;
+
#endif /* _HVRELEASEDATA_H */
/*
* HvTypes.h
* Copyright (C) 2001 Mike Corrigan IBM Corporation
- *
+ *
* 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 _HVTYPES_H
#define _HVTYPES_H
-//===========================================================================
-// Header File Id
-// Name______________: HvTypes.H
-//
-// Description_______:
-//
-// General typedefs for the hypervisor.
-//
-// Declared Class(es):
-//
-//===========================================================================
+/*
+ * General typedefs for the hypervisor.
+ */
#include <asm/types.h>
-//-------------------------------------------------------------------
-// Typedefs
-//-------------------------------------------------------------------
typedef u8 HvLpIndex;
typedef u16 HvLpInstanceId;
-typedef u64 HvLpTOD;
-typedef u64 HvLpSystemSerialNum;
-typedef u8 HvLpDeviceSerialNum[12];
-typedef u16 HvLpSanHwSet;
-typedef u16 HvLpBus;
-typedef u16 HvLpBoard;
-typedef u16 HvLpCard;
-typedef u8 HvLpDeviceType[4];
-typedef u8 HvLpDeviceModel[3];
-typedef u64 HvIoToken;
-typedef u8 HvLpName[8];
+typedef u64 HvLpTOD;
+typedef u64 HvLpSystemSerialNum;
+typedef u8 HvLpDeviceSerialNum[12];
+typedef u16 HvLpSanHwSet;
+typedef u16 HvLpBus;
+typedef u16 HvLpBoard;
+typedef u16 HvLpCard;
+typedef u8 HvLpDeviceType[4];
+typedef u8 HvLpDeviceModel[3];
+typedef u64 HvIoToken;
+typedef u8 HvLpName[8];
typedef u32 HvIoId;
typedef u64 HvRealMemoryIndex;
-typedef u32 HvLpIndexMap; // Must hold HvMaxArchitectedLps bits!!!
+typedef u32 HvLpIndexMap; /* Must hold HVMAXARCHITECTEDLPS bits!!! */
typedef u16 HvLpVrmIndex;
typedef u32 HvXmGenerationId;
-typedef u8 HvLpBusPool;
-typedef u8 HvLpSharedPoolIndex;
+typedef u8 HvLpBusPool;
+typedef u8 HvLpSharedPoolIndex;
typedef u16 HvLpSharedProcUnitsX100;
typedef u8 HvLpVirtualLanIndex;
-typedef u16 HvLpVirtualLanIndexMap; // Must hold HvMaxArchitectedVirtualLans bits!!!
-typedef u16 HvBusNumber; // Hypervisor Bus Number
-typedef u8 HvSubBusNumber; // Hypervisor SubBus Number
-typedef u8 HvAgentId; // Hypervisor DevFn
+typedef u16 HvLpVirtualLanIndexMap; /* Must hold HVMAXARCHITECTEDVIRTUALLANS bits!!! */
+typedef u16 HvBusNumber; /* Hypervisor Bus Number */
+typedef u8 HvSubBusNumber; /* Hypervisor SubBus Number */
+typedef u8 HvAgentId; /* Hypervisor DevFn */
+
+#define HVMAXARCHITECTEDLPS 32
+#define HVMAXARCHITECTEDVIRTUALLANS 16
+#define HVMAXARCHITECTEDVIRTUALDISKS 32
+#define HVMAXARCHITECTEDVIRTUALCDROMS 8
+#define HVMAXARCHITECTEDVIRTUALTAPES 8
+#define HVCHUNKSIZE (256 * 1024)
+#define HVPAGESIZE (4 * 1024)
+#define HVLPMINMEGSPRIMARY 256
+#define HVLPMINMEGSSECONDARY 64
+#define HVCHUNKSPERMEG 4
+#define HVPAGESPERMEG 256
+#define HVPAGESPERCHUNK 64
-#define HVMAXARCHITECTEDLPS 32
-#define HVMAXARCHITECTEDVIRTUALLANS 16
-#define HVMAXARCHITECTEDVIRTUALDISKS 32
-#define HVMAXARCHITECTEDVIRTUALCDROMS 8
-#define HVMAXARCHITECTEDVIRTUALTAPES 8
-#define HVCHUNKSIZE 256 * 1024
-#define HVPAGESIZE 4 * 1024
-#define HVLPMINMEGSPRIMARY 256
-#define HVLPMINMEGSSECONDARY 64
-#define HVCHUNKSPERMEG 4
-#define HVPAGESPERMEG 256
-#define HVPAGESPERCHUNK 64
-
-#define HvMaxArchitectedLps ((HvLpIndex)HVMAXARCHITECTEDLPS)
-#define HvMaxArchitectedVirtualLans ((HvLpVirtualLanIndex)16)
#define HvLpIndexInvalid ((HvLpIndex)0xff)
-//--------------------------------------------------------------------
-// Enums for the sub-components under PLIC
-// Used in HvCall and HvPrimaryCall
-//--------------------------------------------------------------------
-enum HvCallCompIds
-{
+/*
+ * Enums for the sub-components under PLIC
+ * Used in HvCall and HvPrimaryCall
+ */
+enum {
HvCallCompId = 0,
HvCallCpuCtlsCompId = 1,
HvCallCfgCompId = 2,
HvCallSmCompId = 7,
HvCallSpdCompId = 8,
HvCallXmCompId = 9,
- HvCallRioCompId = 10,
+ HvCallRioCompId = 10,
HvCallRsvd3CompId = 11,
HvCallRsvd2CompId = 12,
HvCallRsvd1CompId = 13,
HvCallMaxCompId = 14,
- HvPrimaryCallCompId = 0,
+ HvPrimaryCallCompId = 0,
HvPrimaryCallCfgCompId = 1,
- HvPrimaryCallPciCompId = 2,
+ HvPrimaryCallPciCompId = 2,
HvPrimaryCallSmCompId = 3,
HvPrimaryCallSpdCompId = 4,
HvPrimaryCallXmCompId = 5,
- HvPrimaryCallRioCompId = 6,
+ HvPrimaryCallRioCompId = 6,
HvPrimaryCallRsvd7CompId = 7,
HvPrimaryCallRsvd6CompId = 8,
HvPrimaryCallRsvd5CompId = 9,
HvPrimaryCallRsvd3CompId = 11,
HvPrimaryCallRsvd2CompId = 12,
HvPrimaryCallRsvd1CompId = 13,
- HvPrimaryCallMaxCompId = HvCallMaxCompId
+ HvPrimaryCallMaxCompId = HvCallMaxCompId
};
struct HvLpBufferList {
/*
* IoHriMainStore.h
* Copyright (C) 2001 Mike Corrigan IBM Corporation
- *
+ *
* 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 _IOHRIMAINSTORE_H
/* Main Store Vpd for Condor,iStar,sStar */
-struct IoHriMainStoreSegment4 {
+struct IoHriMainStoreSegment4 {
u8 msArea0Exists:1;
u8 msArea1Exists:1;
u8 msArea2Exists:1;
u8 msArea1HasRiserVpd:1;
u8 msArea2HasRiserVpd:1;
u8 msArea3HasRiserVpd:1;
- u8 reserved5:4;
+ u8 reserved5:4;
u8 reserved6;
u16 reserved7;
};
struct IoHriMainStoreAdrRangeBlock {
- void * blockStart __attribute((packed));
- void * blockEnd __attribute((packed));
+ void *blockStart __attribute((packed));
+ void *blockEnd __attribute((packed));
u32 blockProcChipId __attribute((packed));
};
u32 procNodeId __attribute((packed));
u32 numAdrRangeBlocks __attribute((packed));
- struct IoHriMainStoreAdrRangeBlock xAdrRangeBlock[MaxAreaAdrRangeBlocks] __attribute((packed));
+ struct IoHriMainStoreAdrRangeBlock xAdrRangeBlock[MaxAreaAdrRangeBlocks] __attribute((packed));
struct IoHriMainStoreChipInfo1 chipInfo0 __attribute((packed));
struct IoHriMainStoreChipInfo1 chipInfo1 __attribute((packed));
struct IoHriMainStoreChipInfo1 chipInfo6 __attribute((packed));
struct IoHriMainStoreChipInfo1 chipInfo7 __attribute((packed));
- void * msRamAreaArray __attribute((packed));
+ void *msRamAreaArray __attribute((packed));
u32 msRamAreaArrayNumEntries __attribute((packed));
u32 msRamAreaArrayEntrySize __attribute((packed));
u32 numaDimmExists __attribute((packed));
u32 numaDimmFunctional __attribute((packed));
- void * numaDimmArray __attribute((packed));
+ void *numaDimmArray __attribute((packed));
u32 numaDimmArrayNumEntries __attribute((packed));
u32 numaDimmArrayEntrySize __attribute((packed));
- struct IoHriMainStoreVpdIdData idData __attribute((packed));
+ struct IoHriMainStoreVpdIdData idData __attribute((packed));
u64 powerData __attribute((packed));
u64 cardAssemblyPartNum __attribute((packed));
};
-struct IoHriMainStoreSegment5 {
+struct IoHriMainStoreSegment5 {
u16 reserved1;
u8 reserved2;
u8 msVpdFormat;
u32 totalMainStore;
u64 maxConfiguredMsAdr;
- struct IoHriMainStoreArea4* msAreaArray;
+ struct IoHriMainStoreArea4 *msAreaArray;
u32 msAreaArrayNumEntries;
u32 msAreaArrayEntrySize;
- u32 msAreaExists;
+ u32 msAreaExists;
u32 msAreaFunctional;
u64 reserved3;
};
+extern u64 xMsVpd[];
-
-#endif // _IOHRIMAINSTORE_H
-
+#endif /* _IOHRIMAINSTORE_H */
/*
* IoHriProcessorVpd.h
* Copyright (C) 2001 Mike Corrigan IBM Corporation
- *
+ *
* 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 _IOHRIPROCESSORVPD_H
#define _IOHRIPROCESSORVPD_H
-//===================================================================
-//
-// This struct maps Processor Vpd that is DMAd to SLIC by CSP
-//
-
#include <asm/types.h>
-struct IoHriProcessorVpd
-{
-
+/*
+ * This struct maps Processor Vpd that is DMAd to SLIC by CSP
+ */
+struct IoHriProcessorVpd {
u8 xFormat; // VPD format indicator x00-x00
u8 xProcStatus:8; // Processor State x01-x01
u8 xSecondaryThreadCount; // Secondary thread cnt x02-x02
u16 xRsvd2; // Reserved x06-x07
u32 xHwNodeId; // Hardware node id x08-x0B
u32 xHwProcId; // Hardware processor id x0C-x0F
-
+
u32 xTypeNum; // Card Type/CCIN number x10-x13
u32 xModelNum; // Model/Feature number x14-x17
u64 xSerialNum; // Serial number x18-x1F
- char xPartNum[12]; // Book Part or FPU number x20-x2B
- char xMfgID[4]; // Manufacturing ID x2C-x2F
+ char xPartNum[12]; // Book Part or FPU number x20-x2B
+ char xMfgID[4]; // Manufacturing ID x2C-x2F
u32 xProcFreq; // Processor Frequency x30-x33
u32 xTimeBaseFreq; // Time Base Frequency x34-x37
u32 xDataL3CacheSizeKB; // L3 data cache size in KB x80-x83
u32 xDataL3CacheLineSize; // L3 data cache block size x84-x87
u64 xRsvd6; // Reserved x88-x8F
-
+
u64 xFruLabel; // Card Location Label x90-x97
u8 xSlotsOnCard; // Slots on card (0=no slots) x98-x98
u8 xPartLocFlag; // Location flag (0-pluggable 1-imbedded) x99-x99
u8 xSmartCardPortNo; // Smart card port number x9C-x9C
u8 xRsvd7; // Reserved x9D-x9D
u16 xFrameIdAndRackUnit; // Frame ID and rack unit adr x9E-x9F
-
+
u8 xRsvd8[24]; // Reserved xA0-xB7
- char xProcSrc[72]; // CSP format SRC xB8-xFF
+ char xProcSrc[72]; // CSP format SRC xB8-xFF
};
+extern struct IoHriProcessorVpd xIoHriProcessorVpd[];
+
#endif /* _IOHRIPROCESSORVPD_H */
/*
* ItExtVpdPanel.h
* Copyright (C) 2002 Dave Boutcher IBM Corporation
- *
+ *
* 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 _ITEXTVPDPANEL_H
/*
- *
- * This struct maps the panel information
+ * This struct maps the panel information
*
* Warning:
* This data must match the architecture for the panel information
- *
*/
-
-/*-------------------------------------------------------------------
- * Standard Includes
- *-------------------------------------------------------------------
-*/
#include <asm/types.h>
-struct ItExtVpdPanel
-{
- // Definition of the Extended Vpd On Panel Data Area
- char systemSerial[8];
- char mfgID[4];
- char reserved1[24];
- char machineType[4];
- char systemID[6];
- char somUniqueCnt[4];
- char serialNumberCount;
- char reserved2[7];
- u16 bbu3;
- u16 bbu2;
- u16 bbu1;
- char xLocationLabel[8];
- u8 xRsvd1[6];
- u16 xFrameId;
- u8 xRsvd2[48];
+struct ItExtVpdPanel {
+ /* Definition of the Extended Vpd On Panel Data Area */
+ char systemSerial[8];
+ char mfgID[4];
+ char reserved1[24];
+ char machineType[4];
+ char systemID[6];
+ char somUniqueCnt[4];
+ char serialNumberCount;
+ char reserved2[7];
+ u16 bbu3;
+ u16 bbu2;
+ u16 bbu1;
+ char xLocationLabel[8];
+ u8 xRsvd1[6];
+ u16 xFrameId;
+ u8 xRsvd2[48];
};
-#endif /* _ITEXTVPDPANEL_H */
+extern struct ItExtVpdPanel xItExtVpdPanel;
+
+#endif /* _ITEXTVPDPANEL_H */
/*
* ItIplParmsReal.h
* Copyright (C) 2001 Mike Corrigan IBM Corporation
- *
+ *
* 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 _ITIPLPARMSREAL_H
#define _ITIPLPARMSREAL_H
-//==============================================================================
-//
-// This struct maps the IPL Parameters DMA'd from the SP.
-//
-// Warning:
-// This data must map in exactly 64 bytes and match the architecture for
-// the IPL parms
-//
-//=============================================================================
-
+/*
+ * This struct maps the IPL Parameters DMA'd from the SP.
+ *
+ * Warning:
+ * This data must map in exactly 64 bytes and match the architecture for
+ * the IPL parms
+ */
-//-------------------------------------------------------------------
-// Standard Includes
-//-------------------------------------------------------------------
#include <asm/types.h>
-struct ItIplParmsReal
-{
- u8 xFormat; // Defines format of IplParms x00-x00
- u8 xRsvd01:6; // Reserved x01-x01
- u8 xAlternateSearch:1; // Alternate search indicator ...
- u8 xUaSupplied:1; // UA Supplied on programmed IPL ...
- u8 xLsUaFormat; // Format byte for UA x02-x02
- u8 xRsvd02; // Reserved x03-x03
- u32 xLsUa; // LS UA x04-x07
- u32 xUnusedLsLid; // First OS LID to load x08-x0B
- u16 xLsBusNumber; // LS Bus Number x0C-x0D
- u8 xLsCardAdr; // LS Card Address x0E-x0E
- u8 xLsBoardAdr; // LS Board Address x0F-x0F
- u32 xRsvd03; // Reserved x10-x13
- u8 xSpcnPresent:1; // SPCN present x14-x14
- u8 xCpmPresent:1; // CPM present ...
- u8 xRsvd04:6; // Reserved ...
- u8 xRsvd05:4; // Reserved x15-x15
- u8 xKeyLock:4; // Keylock setting ...
- u8 xRsvd06:6; // Reserved x16-x16
- u8 xIplMode:2; // Ipl mode (A|B|C|D) ...
- u8 xHwIplType; // Fast v slow v slow EC HW IPL x17-x17
- u16 xCpmEnabledIpl:1; // CPM in effect when IPL initiated x18-x19
- u16 xPowerOnResetIpl:1; // Indicate POR condition ...
- u16 xMainStorePreserved:1; // Main Storage is preserved ...
- u16 xRsvd07:13; // Reserved ...
- u16 xIplSource:16; // Ipl source x1A-x1B
- u8 xIplReason:8; // Reason for this IPL x1C-x1C
- u8 xRsvd08; // Reserved x1D-x1D
- u16 xRsvd09; // Reserved x1E-x1F
- u16 xSysBoxType; // System Box Type x20-x21
- u16 xSysProcType; // System Processor Type x22-x23
- u32 xRsvd10; // Reserved x24-x27
- u64 xRsvd11; // Reserved x28-x2F
- u64 xRsvd12; // Reserved x30-x37
- u64 xRsvd13; // Reserved x38-x3F
+struct ItIplParmsReal {
+ u8 xFormat; // Defines format of IplParms x00-x00
+ u8 xRsvd01:6; // Reserved x01-x01
+ u8 xAlternateSearch:1; // Alternate search indicator ...
+ u8 xUaSupplied:1; // UA Supplied on programmed IPL...
+ u8 xLsUaFormat; // Format byte for UA x02-x02
+ u8 xRsvd02; // Reserved x03-x03
+ u32 xLsUa; // LS UA x04-x07
+ u32 xUnusedLsLid; // First OS LID to load x08-x0B
+ u16 xLsBusNumber; // LS Bus Number x0C-x0D
+ u8 xLsCardAdr; // LS Card Address x0E-x0E
+ u8 xLsBoardAdr; // LS Board Address x0F-x0F
+ u32 xRsvd03; // Reserved x10-x13
+ u8 xSpcnPresent:1; // SPCN present x14-x14
+ u8 xCpmPresent:1; // CPM present ...
+ u8 xRsvd04:6; // Reserved ...
+ u8 xRsvd05:4; // Reserved x15-x15
+ u8 xKeyLock:4; // Keylock setting ...
+ u8 xRsvd06:6; // Reserved x16-x16
+ u8 xIplMode:2; // Ipl mode (A|B|C|D) ...
+ u8 xHwIplType; // Fast v slow v slow EC HW IPL x17-x17
+ u16 xCpmEnabledIpl:1; // CPM in effect when IPL initiatedx18-x19
+ u16 xPowerOnResetIpl:1; // Indicate POR condition ...
+ u16 xMainStorePreserved:1; // Main Storage is preserved ...
+ u16 xRsvd07:13; // Reserved ...
+ u16 xIplSource:16; // Ipl source x1A-x1B
+ u8 xIplReason:8; // Reason for this IPL x1C-x1C
+ u8 xRsvd08; // Reserved x1D-x1D
+ u16 xRsvd09; // Reserved x1E-x1F
+ u16 xSysBoxType; // System Box Type x20-x21
+ u16 xSysProcType; // System Processor Type x22-x23
+ u32 xRsvd10; // Reserved x24-x27
+ u64 xRsvd11; // Reserved x28-x2F
+ u64 xRsvd12; // Reserved x30-x37
+ u64 xRsvd13; // Reserved x38-x3F
};
+extern struct ItIplParmsReal xItIplParmsReal;
+
#endif /* _ITIPLPARMSREAL_H */
/*
* ItLpNaca.h
* Copyright (C) 2001 Mike Corrigan IBM Corporation
- *
+ *
* 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 _ITLPNACA_H
#define _ITLPNACA_H
-//=============================================================================
-//
-// This control block contains the data that is shared between the
-// hypervisor (PLIC) and the OS.
-//
-//=============================================================================
+#include <linux/types.h>
-struct ItLpNaca
-{
-//=============================================================================
+/*
+ * This control block contains the data that is shared between the
+ * hypervisor (PLIC) and the OS.
+ */
+
+struct ItLpNaca {
// CACHE_LINE_1 0x0000 - 0x007F Contains read-only data
-//=============================================================================
u32 xDesc; // Eye catcher x00-x03
u16 xSize; // Size of this class x04-x05
u16 xIntHdlrOffset; // Offset to IntHdlr array x06-x07
u64 xLoadAreaAddr; // ER address of load area x28-x2F
u32 xLoadAreaChunks; // Chunks for the load area x30-x33
u32 xPaseSysCallCRMask; // Mask used to test CR before x34-x37
- // doing an ASR switch on PASE
- // system call.
- u64 xSlicSegmentTablePtr; // Pointer to Slic seg table. x38-x3f
- u8 xRsvd1_4[64]; // x40-x7F
-
-//=============================================================================
+ // doing an ASR switch on PASE
+ // system call.
+ u64 xSlicSegmentTablePtr; // Pointer to Slic seg table. x38-x3f
+ u8 xRsvd1_4[64]; // x40-x7F
+
// CACHE_LINE_2 0x0080 - 0x00FF Contains local read-write data
-//=============================================================================
u8 xRsvd2_0[128]; // Reserved x00-x7F
-//=============================================================================
// CACHE_LINE_3-6 0x0100 - 0x02FF Contains LP Queue indicators
-// NB: Padding required to keep xInterrruptHdlr at x300 which is required
+// NB: Padding required to keep xInterrruptHdlr at x300 which is required
// for v4r4 PLIC.
-//=============================================================================
u8 xOldLpQueue[128]; // LP Queue needed for v4r4 100-17F
u8 xRsvd3_0[384]; // Reserved 180-2FF
-//=============================================================================
+
// CACHE_LINE_7-8 0x0300 - 0x03FF Contains the address of the OS interrupt
// handlers
-//=============================================================================
u64 xInterruptHdlr[32]; // Interrupt handlers 300-x3FF
};
-//=============================================================================
+extern struct ItLpNaca itLpNaca;
#endif /* _ITLPNACA_H */
/*
* ItLpQueue.h
* Copyright (C) 2001 Mike Corrigan IBM Corporation
- *
+ *
* 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 _ITLPQUEUE_H
#define _ITLPQUEUE_H
-//=============================================================================
-//
-// This control block defines the simple LP queue structure that is
-// shared between the hypervisor (PLIC) and the OS in order to send
-// events to an LP.
-//
+/*
+ * This control block defines the simple LP queue structure that is
+ * shared between the hypervisor (PLIC) and the OS in order to send
+ * events to an LP.
+ */
#include <asm/types.h>
#include <asm/ptrace.h>
struct HvLpEvent;
-#define ITMaxLpQueues 8
+#define ITMaxLpQueues 8
#define NotUsed 0 // Queue will not be used by PLIC
#define DedicatedIo 1 // Queue dedicated to IO processor specified
#define DedicatedLp 2 // Queue dedicated to LP specified
#define Shared 3 // Queue shared for both IO and LP
-#define LpEventStackSize 4096
-#define LpEventMaxSize 256
-#define LpEventAlign 64
+#define LpEventStackSize 4096
+#define LpEventMaxSize 256
+#define LpEventAlign 64
-struct ItLpQueue
-{
-//
-// The xSlicCurEventPtr is the pointer to the next event stack entry that will
-// become valid. The OS must peek at this entry to determine if it is valid.
-// PLIC will set the valid indicator as the very last store into that entry.
-//
-// When the OS has completed processing of the event then it will mark the event
-// as invalid so that PLIC knows it can store into that event location again.
-//
-// If the event stack fills and there are overflow events, then PLIC will set
-// the xPlicOverflowIntPending flag in which case the OS will have to fetch the
-// additional LP events once they have drained the event stack.
-//
-// The first 16-bytes are known by both the OS and PLIC. The remainder of the
-// cache line is for use by the OS.
-//
-//=============================================================================
+struct ItLpQueue {
+/*
+ * The xSlicCurEventPtr is the pointer to the next event stack entry
+ * that will become valid. The OS must peek at this entry to determine
+ * if it is valid. PLIC will set the valid indicator as the very last
+ * store into that entry.
+ *
+ * When the OS has completed processing of the event then it will mark
+ * the event as invalid so that PLIC knows it can store into that event
+ * location again.
+ *
+ * If the event stack fills and there are overflow events, then PLIC
+ * will set the xPlicOverflowIntPending flag in which case the OS will
+ * have to fetch the additional LP events once they have drained the
+ * event stack.
+ *
+ * The first 16-bytes are known by both the OS and PLIC. The remainder
+ * of the cache line is for use by the OS.
+ */
u8 xPlicOverflowIntPending;// 0x00 Overflow events are pending
u8 xPlicStatus; // 0x01 DedicatedIo or DedicatedLp or NotUsed
u16 xSlicLogicalProcIndex; // 0x02 Logical Proc Index for correlation
u8 xPlicRsvd[12]; // 0x04
- char* xSlicCurEventPtr; // 0x10
- char* xSlicLastValidEventPtr; // 0x18
- char* xSlicEventStackPtr; // 0x20
+ char *xSlicCurEventPtr; // 0x10
+ char *xSlicLastValidEventPtr; // 0x18
+ char *xSlicEventStackPtr; // 0x20
u8 xIndex; // 0x28 unique sequential index.
u8 xSlicRsvd[3]; // 0x29-2b
u32 xInUseWord; // 0x2C
extern struct ItLpQueue xItLpQueue;
-extern struct HvLpEvent * ItLpQueue_getNextLpEvent( struct ItLpQueue * );
-extern int ItLpQueue_isLpIntPending( struct ItLpQueue * );
-extern unsigned ItLpQueue_process( struct ItLpQueue *, struct pt_regs * );
-extern void ItLpQueue_clearValid( struct HvLpEvent * );
-
-static __inline__ void process_iSeries_events( void )
-{
- __asm__ __volatile__ (
- " li 0,0x5555 \n\
- sc"
- : : : "r0", "r3" );
-}
+extern struct HvLpEvent *ItLpQueue_getNextLpEvent(struct ItLpQueue *);
+extern int ItLpQueue_isLpIntPending(struct ItLpQueue *);
+extern unsigned ItLpQueue_process(struct ItLpQueue *, struct pt_regs *);
+extern void ItLpQueue_clearValid(struct HvLpEvent *);
#endif /* _ITLPQUEUE_H */
/*
* ItLpRegSave.h
* Copyright (C) 2001 Mike Corrigan IBM Corporation
- *
+ *
* 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 _ITLPREGSAVE_H
#define _ITLPREGSAVE_H
-//=====================================================================================
-//
-// This control block contains the data that is shared between PLIC
-// and the OS
-//
-//
+/*
+ * This control block contains the data that is shared between PLIC
+ * and the OS
+ */
-struct ItLpRegSave
-{
+struct ItLpRegSave {
u32 xDesc; // Eye catcher "LpRS" ebcdic 000-003
u16 xSize; // Size of this class 004-005
u8 xInUse; // Area is live 006-007
- u8 xRsvd1[9]; // Reserved 007-00F
+ u8 xRsvd1[9]; // Reserved 007-00F
- u8 xFixedRegSave[352]; // Fixed Register Save Area 010-16F
+ u8 xFixedRegSave[352]; // Fixed Register Save Area 010-16F
u32 xCTRL; // Control Register 170-173
- u32 xDEC; // Decrementer 174-177
+ u32 xDEC; // Decrementer 174-177
u32 xFPSCR; // FP Status and Control Reg 178-17B
u32 xPVR; // Processor Version Number 17C-17F
-
+
u64 xMMCR0; // Monitor Mode Control Reg 0 180-187
u32 xPMC1; // Perf Monitor Counter 1 188-18B
u32 xPMC2; // Perf Monitor Counter 2 18C-18F
u32 xPMC3; // Perf Monitor Counter 3 190-193
u32 xPMC4; // Perf Monitor Counter 4 194-197
u32 xPIR; // Processor ID Reg 198-19B
-
+
u32 xMMCR1; // Monitor Mode Control Reg 1 19C-19F
u32 xMMCRA; // Monitor Mode Control Reg A 1A0-1A3
u32 xPMC5; // Perf Monitor Counter 5 1A4-1A7
u32 xRsvd; // Reserved 1BC-1BF
u64 xACCR; // Address Compare Control Reg 1C0-1C7
- u64 xIMR; // Instruction Match Register 1C8-1CF
- u64 xSDR1; // Storage Description Reg 1 1D0-1D7
+ u64 xIMR; // Instruction Match Register 1C8-1CF
+ u64 xSDR1; // Storage Description Reg 1 1D0-1D7
u64 xSPRG0; // Special Purpose Reg General0 1D8-1DF
u64 xSPRG1; // Special Purpose Reg General1 1E0-1E7
u64 xSPRG2; // Special Purpose Reg General2 1E8-1EF
u64 xSPRG3; // Special Purpose Reg General3 1F0-1F7
u64 xTB; // Time Base Register 1F8-1FF
-
+
u64 xFPR[32]; // Floating Point Registers 200-2FF
- u64 xMSR; // Machine State Register 300-307
+ u64 xMSR; // Machine State Register 300-307
u64 xNIA; // Next Instruction Address 308-30F
u64 xDABR; // Data Address Breakpoint Reg 310-317
u64 xHID0; // HW Implementation Dependent0 320-327
u64 xHID4; // HW Implementation Dependent4 328-32F
- u64 xSCOMd; // SCON Data Reg (SPRG4) 330-337
- u64 xSCOMc; // SCON Command Reg (SPRG5) 338-33F
+ u64 xSCOMd; // SCON Data Reg (SPRG4) 330-337
+ u64 xSCOMc; // SCON Command Reg (SPRG5) 338-33F
u64 xSDAR; // Sample Data Address Register 340-347
u64 xSIAR; // Sample Inst Address Register 348-34F
/*
* ItSpCommArea.h
* Copyright (C) 2001 Mike Corrigan IBM Corporation
- *
+ *
* 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 _ITSPCOMMAREA_H
#define _ITSPCOMMAREA_H
-struct SpCommArea
-{
+struct SpCommArea {
u32 xDesc; // Descriptor (only in new formats) 000-003
u8 xFormat; // Format (only in new formats) 004-004
u8 xRsvd1[11]; // Reserved 005-00F
/*
* ItVpdAreas.h
* Copyright (C) 2001 Mike Corrigan IBM Corporation
- *
+ *
* 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 _ITVPDAREAS_H
#define _ITVPDAREAS_H
-//=====================================================================================
-//
-// This file defines the address and length of all of the VPD area passed to
-// the OS from PLIC (most of which start from the SP).
-//
+/*
+ * This file defines the address and length of all of the VPD area passed to
+ * the OS from PLIC (most of which start from the SP).
+ */
#include <asm/types.h>
-// VPD Entry index is carved in stone - cannot be changed (easily).
-#define ItVpdCecVpd 0
-#define ItVpdDynamicSpace 1
-#define ItVpdExtVpd 2
-#define ItVpdExtVpdOnPanel 3
-#define ItVpdFirstPaca 4
-#define ItVpdIoVpd 5
-#define ItVpdIplParms 6
-#define ItVpdMsVpd 7
-#define ItVpdPanelVpd 8
-#define ItVpdLpNaca 9
-#define ItVpdBackplaneAndMaybeClockCardVpd 10
-#define ItVpdRecoveryLogBuffer 11
-#define ItVpdSpCommArea 12
-#define ItVpdSpLogBuffer 13
-#define ItVpdSpLogBufferSave 14
-#define ItVpdSpCardVpd 15
-#define ItVpdFirstProcVpd 16
-#define ItVpdApModelVpd 17
-#define ItVpdClockCardVpd 18
-#define ItVpdBusExtCardVpd 19
-#define ItVpdProcCapacityVpd 20
-#define ItVpdInteractiveCapacityVpd 21
-#define ItVpdFirstSlotLabel 22
-#define ItVpdFirstLpQueue 23
-#define ItVpdFirstL3CacheVpd 24
-#define ItVpdFirstProcFruVpd 25
-
-#define ItVpdMaxEntries 26
+/* VPD Entry index is carved in stone - cannot be changed (easily). */
+#define ItVpdCecVpd 0
+#define ItVpdDynamicSpace 1
+#define ItVpdExtVpd 2
+#define ItVpdExtVpdOnPanel 3
+#define ItVpdFirstPaca 4
+#define ItVpdIoVpd 5
+#define ItVpdIplParms 6
+#define ItVpdMsVpd 7
+#define ItVpdPanelVpd 8
+#define ItVpdLpNaca 9
+#define ItVpdBackplaneAndMaybeClockCardVpd 10
+#define ItVpdRecoveryLogBuffer 11
+#define ItVpdSpCommArea 12
+#define ItVpdSpLogBuffer 13
+#define ItVpdSpLogBufferSave 14
+#define ItVpdSpCardVpd 15
+#define ItVpdFirstProcVpd 16
+#define ItVpdApModelVpd 17
+#define ItVpdClockCardVpd 18
+#define ItVpdBusExtCardVpd 19
+#define ItVpdProcCapacityVpd 20
+#define ItVpdInteractiveCapacityVpd 21
+#define ItVpdFirstSlotLabel 22
+#define ItVpdFirstLpQueue 23
+#define ItVpdFirstL3CacheVpd 24
+#define ItVpdFirstProcFruVpd 25
+#define ItVpdMaxEntries 26
-#define ItDmaMaxEntries 10
+#define ItDmaMaxEntries 10
-#define ItVpdAreasMaxSlotLabels 192
+#define ItVpdAreasMaxSlotLabels 192
-struct SlicVpdAdrs {
- u32 pad1;
- void * vpdAddr;
+struct ItVpdAreas {
+ u32 xSlicDesc; // Descriptor 000-003
+ u16 xSlicSize; // Size of this control block 004-005
+ u16 xPlicAdjustVpdLens:1; // Flag to indicate new interface006-007
+ u16 xRsvd1:15; // Reserved bits ...
+ u16 xSlicVpdEntries; // Number of VPD entries 008-009
+ u16 xSlicDmaEntries; // Number of DMA entries 00A-00B
+ u16 xSlicMaxLogicalProcs; // Maximum logical processors 00C-00D
+ u16 xSlicMaxPhysicalProcs; // Maximum physical processors 00E-00F
+ u16 xSlicDmaToksOffset; // Offset into this of array 010-011
+ u16 xSlicVpdAdrsOffset; // Offset into this of array 012-013
+ u16 xSlicDmaLensOffset; // Offset into this of array 014-015
+ u16 xSlicVpdLensOffset; // Offset into this of array 016-017
+ u16 xSlicMaxSlotLabels; // Maximum number of slot labels018-019
+ u16 xSlicMaxLpQueues; // Maximum number of LP Queues 01A-01B
+ u8 xRsvd2[4]; // Reserved 01C-01F
+ u64 xRsvd3[12]; // Reserved 020-07F
+ u32 xPlicDmaLens[ItDmaMaxEntries];// Array of DMA lengths 080-0A7
+ u32 xPlicDmaToks[ItDmaMaxEntries];// Array of DMA tokens 0A8-0CF
+ u32 xSlicVpdLens[ItVpdMaxEntries];// Array of VPD lengths 0D0-12F
+ void *xSlicVpdAdrs[ItVpdMaxEntries];// Array of VPD buffers 130-1EF
};
-
-struct ItVpdAreas
-{
- u32 xSlicDesc; // Descriptor 000-003
- u16 xSlicSize; // Size of this control block 004-005
- u16 xPlicAdjustVpdLens:1; // Flag to indicate new interface 006-007
- u16 xRsvd1:15; // Reserved bits ...
- u16 xSlicVpdEntries; // Number of VPD entries 008-009
- u16 xSlicDmaEntries; // Number of DMA entries 00A-00B
- u16 xSlicMaxLogicalProcs; // Maximum logical processors 00C-00D
- u16 xSlicMaxPhysicalProcs; // Maximum physical processors 00E-00F
- u16 xSlicDmaToksOffset; // Offset into this of array 010-011
- u16 xSlicVpdAdrsOffset; // Offset into this of array 012-013
- u16 xSlicDmaLensOffset; // Offset into this of array 014-015
- u16 xSlicVpdLensOffset; // Offset into this of array 016-017
- u16 xSlicMaxSlotLabels; // Maximum number of slot labels 018-019
- u16 xSlicMaxLpQueues; // Maximum number of LP Queues 01A-01B
- u8 xRsvd2[4]; // Reserved 01C-01F
- u64 xRsvd3[12]; // Reserved 020-07F
- u32 xPlicDmaLens[ItDmaMaxEntries];// Array of DMA lengths 080-0A7
- u32 xPlicDmaToks[ItDmaMaxEntries];// Array of DMA tokens 0A8-0CF
- u32 xSlicVpdLens[ItVpdMaxEntries];// Array of VPD lengths 0D0-12F
- void * xSlicVpdAdrs[ItVpdMaxEntries];// Array of VPD buffers 130-1EF
-};
+extern struct ItVpdAreas itVpdAreas;
#endif /* _ITVPDAREAS_H */
+++ /dev/null
-/*
- * LparData.h
- * Copyright (C) 2001 Mike Corrigan IBM Corporation
- *
- * 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 _LPARDATA_H
-#define _LPARDATA_H
-
-#include <asm/types.h>
-#include <asm/page.h>
-#include <asm/abs_addr.h>
-
-#include <asm/iSeries/ItLpNaca.h>
-#include <asm/iSeries/ItLpRegSave.h>
-#include <asm/iSeries/HvReleaseData.h>
-#include <asm/iSeries/LparMap.h>
-#include <asm/iSeries/ItVpdAreas.h>
-#include <asm/iSeries/ItIplParmsReal.h>
-#include <asm/iSeries/ItExtVpdPanel.h>
-#include <asm/iSeries/ItLpQueue.h>
-#include <asm/iSeries/IoHriProcessorVpd.h>
-
-extern struct LparMap xLparMap;
-extern struct HvReleaseData hvReleaseData;
-extern struct ItLpNaca itLpNaca;
-extern struct ItIplParmsReal xItIplParmsReal;
-extern struct ItExtVpdPanel xItExtVpdPanel;
-extern struct IoHriProcessorVpd xIoHriProcessorVpd[];
-extern struct ItLpQueue xItLpQueue;
-extern struct ItVpdAreas itVpdAreas;
-extern u64 xMsVpd[];
-extern struct msChunks msChunks;
-
-
-#endif /* _LPARDATA_H */
/*
* LparMap.h
* Copyright (C) 2001 Mike Corrigan IBM Corporation
- *
+ *
* 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 <asm/types.h>
-/* The iSeries hypervisor will set up mapping for one or more
+/*
+ * The iSeries hypervisor will set up mapping for one or more
* ESID/VSID pairs (in SLB/segment registers) and will set up
* mappings of one or more ranges of pages to VAs.
* We will have the hypervisor set up the ESID->VSID mapping
* for the four kernel segments (C-F). With shared processors,
* the hypervisor will clear all segment registers and reload
- * these four whenever the processor is switched from one
+ * these four whenever the processor is switched from one
* partition to another.
*/
* need to be located within the load area (if the total partition size
* is 64 MB), but cannot be mapped. Typically, this should specify
* to map half (32 MB) of the load area.
- *
- * The hypervisor will set up page table entries for the number of
+ *
+ * The hypervisor will set up page table entries for the number of
* pages specified.
*
* In 32-bit mode, the hypervisor will load all four of the
- * segment registers (identified by the low-order four bits of the
+ * segment registers (identified by the low-order four bits of the
* Esid field. In 64-bit mode, the hypervisor will load one SLB
* entry to map the Esid to the Vsid.
*/
-// Hypervisor initially maps 32MB of the load area
-#define HvPagesToMap 8192
+/* Hypervisor initially maps 32MB of the load area */
+#define HvPagesToMap 8192
-struct LparMap
-{
- u64 xNumberEsids; // Number of ESID/VSID pairs (1)
- u64 xNumberRanges; // Number of VA ranges to map (1)
- u64 xSegmentTableOffs; // Page number within load area of seg table (0)
- u64 xRsvd[5]; // Reserved (0)
- u64 xKernelEsid; // Esid used to map kernel load (0x0C00000000)
- u64 xKernelVsid; // Vsid used to map kernel load (0x0C00000000)
- u64 xPages; // Number of pages to be mapped (8192)
- u64 xOffset; // Offset from start of load area (0)
- u64 xVPN; // Virtual Page Number (0x000C000000000000)
+struct LparMap {
+ u64 xNumberEsids; // Number of ESID/VSID pairs (1)
+ u64 xNumberRanges; // Number of VA ranges to map (1)
+ u64 xSegmentTableOffs; // Page number within load area of seg table (0)
+ u64 xRsvd[5];
+ u64 xKernelEsid; // Esid used to map kernel load (0x0C00000000)
+ u64 xKernelVsid; // Vsid used to map kernel load (0x0C00000000)
+ u64 xPages; // Number of pages to be mapped (8192)
+ u64 xOffset; // Offset from start of load area (0)
+ u64 xVPN; // Virtual Page Number (0x000C000000000000)
};
+extern struct LparMap xLparMap;
+
#endif /* _LPARMAP_H */
+++ /dev/null
-
-#ifndef __XMPCILPEVENT_H__
-#define __XMPCILPEVENT_H__
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-int XmPciLpEvent_init(void);
-void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __XMPCILPEVENT_H__ */
#ifdef CONFIG_PPC_ISERIES
#include <linux/types.h>
-/************************************************************************/
-/* File iSeries_io.h created by Allan Trautman on Thu Dec 28 2000. */
-/************************************************************************/
-/* Remaps the io.h for the iSeries Io */
-/* Copyright (C) 20yy Allan H Trautman, IBM Corporation */
-/* */
-/* 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 */
-/************************************************************************/
-/* Change Activity: */
-/* Created December 28, 2000 */
-/* End Change Activity */
-/************************************************************************/
+/*
+ * File iSeries_io.h created by Allan Trautman on Thu Dec 28 2000.
+ *
+ * Remaps the io.h for the iSeries Io
+ * Copyright (C) 2000 Allan H Trautman, IBM Corporation
+ *
+ * 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
+ *
+ * Change Activity:
+ * Created December 28, 2000
+ * End Change Activity
+ */
+
extern u8 iSeries_Read_Byte(const volatile void __iomem * IoAddress);
extern u16 iSeries_Read_Word(const volatile void __iomem * IoAddress);
extern u32 iSeries_Read_Long(const volatile void __iomem * IoAddress);
extern void iSeries_Write_Long(u32 IoData, volatile void __iomem * IoAddress);
extern void iSeries_memset_io(volatile void __iomem *dest, char x, size_t n);
-extern void iSeries_memcpy_toio(volatile void __iomem *dest, void *source, size_t n);
-extern void iSeries_memcpy_fromio(void *dest, const volatile void __iomem *source, size_t n);
+extern void iSeries_memcpy_toio(volatile void __iomem *dest, void *source,
+ size_t n);
+extern void iSeries_memcpy_fromio(void *dest,
+ const volatile void __iomem *source, size_t n);
#endif /* CONFIG_PPC_ISERIES */
#endif /* _ISERIES_IO_H */
#ifndef __ISERIES_IRQ_H__
#define __ISERIES_IRQ_H__
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void iSeries_init_IRQ(void);
-int iSeries_allocate_IRQ(HvBusNumber, HvSubBusNumber, HvAgentId);
-int iSeries_assign_IRQ(int, HvBusNumber, HvSubBusNumber, HvAgentId);
-void iSeries_activate_IRQs(void);
-
-int XmPciLpEvent_init(void);
-
-#ifdef __cplusplus
-}
-#endif
+extern void iSeries_init_IRQ(void);
+extern int iSeries_allocate_IRQ(HvBusNumber, HvSubBusNumber, HvAgentId);
+extern void iSeries_activate_IRQs(void);
#endif /* __ISERIES_IRQ_H__ */
#ifndef _ISERIES_64_PCI_H
#define _ISERIES_64_PCI_H
-/************************************************************************/
-/* File iSeries_pci.h created by Allan Trautman on Tue Feb 20, 2001. */
-/************************************************************************/
-/* Define some useful macros for the iSeries pci routines. */
-/* Copyright (C) 2001 Allan H Trautman, IBM Corporation */
-/* */
-/* 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 */
-/************************************************************************/
-/* Change Activity: */
-/* Created Feb 20, 2001 */
-/* Added device reset, March 22, 2001 */
-/* Ported to ppc64, May 25, 2001 */
-/* End Change Activity */
-/************************************************************************/
+/*
+ * File iSeries_pci.h created by Allan Trautman on Tue Feb 20, 2001.
+ *
+ * Define some useful macros for the iSeries pci routines.
+ * Copyright (C) 2001 Allan H Trautman, IBM Corporation
+ *
+ * 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
+ *
+ * Change Activity:
+ * Created Feb 20, 2001
+ * Added device reset, March 22, 2001
+ * Ported to ppc64, May 25, 2001
+ * End Change Activity
+ */
#include <asm/iSeries/HvCallPci.h>
#include <asm/abs_addr.h>
-struct pci_dev; /* For Forward Reference */
+struct pci_dev; /* For Forward Reference */
struct iSeries_Device_Node;
-/************************************************************************/
-/* Gets iSeries Bus, SubBus, DevFn using iSeries_Device_Node structure */
-/************************************************************************/
+/*
+ * Gets iSeries Bus, SubBus, DevFn using iSeries_Device_Node structure
+ */
#define ISERIES_BUS(DevPtr) DevPtr->DsaAddr.Dsa.busNumber
#define ISERIES_SUBBUS(DevPtr) DevPtr->DsaAddr.Dsa.subBusNumber
#define ISERIES_DEVICE(DevPtr) DevPtr->DsaAddr.Dsa.deviceId
#define ISERIES_DSA(DevPtr) DevPtr->DsaAddr.DsaAddr
-#define ISERIES_DEVFUN(DevPtr) DevPtr->DevFn
-#define ISERIES_DEVNODE(PciDev) ((struct iSeries_Device_Node*)PciDev->sysdata)
+#define ISERIES_DEVNODE(PciDev) ((struct iSeries_Device_Node *)PciDev->sysdata)
#define EADsMaxAgents 7
-/************************************************************************/
-/* Decodes Linux DevFn to iSeries DevFn, bridge device, or function. */
-/* For Linux, see PCI_SLOT and PCI_FUNC in include/linux/pci.h */
-/************************************************************************/
-
-#define ISERIES_PCI_AGENTID(idsel,func) ((idsel & 0x0F) << 4) | (func & 0x07)
-#define ISERIES_ENCODE_DEVICE(agentid) ((0x10) | ((agentid&0x20)>>2) | (agentid&07))
-
-#define ISERIES_GET_DEVICE_FROM_SUBBUS(subbus) ((subbus >> 5) & 0x7)
-#define ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus) ((subbus >> 2) & 0x7)
-
/*
- * N.B. the ISERIES_DECODE_* macros are not used anywhere, and I think
- * the 0x71 (at least) must be wrong - 0x78 maybe? -- paulus.
+ * Decodes Linux DevFn to iSeries DevFn, bridge device, or function.
+ * For Linux, see PCI_SLOT and PCI_FUNC in include/linux/pci.h
*/
-#define ISERIES_DECODE_DEVFN(linuxdevfn) (((linuxdevfn & 0x71) << 1) | (linuxdevfn & 0x07))
-#define ISERIES_DECODE_DEVICE(linuxdevfn) (((linuxdevfn & 0x38) >> 3) |(((linuxdevfn & 0x40) >> 2) + 0x10))
-#define ISERIES_DECODE_FUNCTION(linuxdevfn) (linuxdevfn & 0x07)
-/************************************************************************/
-/* Converts Virtual Address to Real Address for Hypervisor calls */
-/************************************************************************/
+#define ISERIES_PCI_AGENTID(idsel, func) \
+ (((idsel & 0x0F) << 4) | (func & 0x07))
+#define ISERIES_ENCODE_DEVICE(agentid) \
+ ((0x10) | ((agentid & 0x20) >> 2) | (agentid & 0x07))
-#define ISERIES_HV_ADDR(virtaddr) (0x8000000000000000 | virt_to_abs(virtaddr))
+#define ISERIES_GET_DEVICE_FROM_SUBBUS(subbus) ((subbus >> 5) & 0x7)
+#define ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus) ((subbus >> 2) & 0x7)
-/************************************************************************/
-/* iSeries Device Information */
-/************************************************************************/
+/*
+ * Converts Virtual Address to Real Address for Hypervisor calls
+ */
+#define ISERIES_HV_ADDR(virtaddr) \
+ (0x8000000000000000 | virt_to_abs(virtaddr))
+/*
+ * iSeries Device Information
+ */
struct iSeries_Device_Node {
struct list_head Device_List;
- struct pci_dev* PciDev; /* Pointer to pci_dev structure*/
- union HvDsaMap DsaAddr; /* Direct Select Address */
- /* busNumber,subBusNumber, */
- /* deviceId, barNumber */
- HvAgentId AgentId; /* Hypervisor DevFn */
- int DevFn; /* Linux devfn */
- int BarOffset;
- int Irq; /* Assigned IRQ */
- int ReturnCode; /* Return Code Holder */
- int IoRetry; /* Current Retry Count */
- int Flags; /* Possible flags(disable/bist)*/
- u16 Vendor; /* Vendor ID */
- u8 LogicalSlot; /* Hv Slot Index for Tces */
- struct iommu_table* iommu_table;/* Device TCE Table */
- u8 PhbId; /* Phb Card is on. */
- u16 Board; /* Board Number */
- u8 FrameId; /* iSeries spcn Frame Id */
- char CardLocation[4];/* Char format of planar vpd */
- char Location[20]; /* Frame 1, Card C10 */
+ struct pci_dev *PciDev;
+ union HvDsaMap DsaAddr; /* Direct Select Address */
+ /* busNumber, subBusNumber, */
+ /* deviceId, barNumber */
+ int DevFn; /* Linux devfn */
+ int Irq; /* Assigned IRQ */
+ int Flags; /* Possible flags(disable/bist)*/
+ u8 LogicalSlot; /* Hv Slot Index for Tces */
+ struct iommu_table *iommu_table;/* Device TCE Table */
};
-/************************************************************************/
-/* Functions */
-/************************************************************************/
-
-extern int iSeries_Device_Information(struct pci_dev*,char*, int);
-extern void iSeries_Get_Location_Code(struct iSeries_Device_Node*);
-extern int iSeries_Device_ToggleReset(struct pci_dev* PciDev, int AssertTime, int DelayTime);
+extern void iSeries_Device_Information(struct pci_dev*, int);
#endif /* _ISERIES_64_PCI_H */
+++ /dev/null
-/*
- * iSeries_proc.h
- * Copyright (C) 2001 Kyle A. Lucke IBM Corporation
- *
- * 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 _ISERIES_PROC_H
-#define _ISERIES_PROC_H
-
-extern void iSeries_proc_early_init(void);
-
-#endif /* _iSeries_PROC_H */
* all partitions in the iSeries. It also provides miscellaneous low-level
* machine facility type operations.
*
- *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
+ *
* 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
* Colin Devilbiss <devilbis@us.ibm.com>
*
* (C) Copyright 2000 IBM Corporation
- *
+ *
* This header file is used by the iSeries virtual I/O device
* drivers. It defines the interfaces to the common functions
* (implemented in drivers/char/viopath.h) as well as defining
- * common functions and structures. Currently (at the time I
+ * common functions and structures. Currently (at the time I
* wrote this comment) the iSeries virtual I/O device drivers
- * that use this are
- * drivers/block/viodasd.c
+ * that use this are
+ * drivers/block/viodasd.c
* drivers/char/viocons.c
* drivers/char/viotape.c
* drivers/cdrom/viocd.c
*
* The iSeries virtual ethernet support (veth.c) uses a whole
* different set of functions.
- *
+ *
* 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) anyu later version.
*
* This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * 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.
+ * General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
+ * 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 <asm/iSeries/HvTypes.h>
#include <asm/iSeries/HvLpEvent.h>
-/* iSeries virtual I/O events use the subtype field in
+/*
+ * iSeries virtual I/O events use the subtype field in
* HvLpEvent to figure out what kind of vio event is coming
* in. We use a table to route these, and this defines
* the maximum number of distinct subtypes
*/
#define VIO_MAX_SUBTYPES 8
-/* Each subtype can register a handler to process their events.
+/*
+ * Each subtype can register a handler to process their events.
* The handler must have this interface.
*/
typedef void (vio_event_handler_t) (struct HvLpEvent * event);
-int viopath_open(HvLpIndex remoteLp, int subtype, int numReq);
-int viopath_close(HvLpIndex remoteLp, int subtype, int numReq);
-int vio_setHandler(int subtype, vio_event_handler_t * beh);
-int vio_clearHandler(int subtype);
-int viopath_isactive(HvLpIndex lp);
-HvLpInstanceId viopath_sourceinst(HvLpIndex lp);
-HvLpInstanceId viopath_targetinst(HvLpIndex lp);
-void vio_set_hostlp(void);
-void *vio_get_event_buffer(int subtype);
-void vio_free_event_buffer(int subtype, void *buffer);
+extern int viopath_open(HvLpIndex remoteLp, int subtype, int numReq);
+extern int viopath_close(HvLpIndex remoteLp, int subtype, int numReq);
+extern int vio_setHandler(int subtype, vio_event_handler_t * beh);
+extern int vio_clearHandler(int subtype);
+extern int viopath_isactive(HvLpIndex lp);
+extern HvLpInstanceId viopath_sourceinst(HvLpIndex lp);
+extern HvLpInstanceId viopath_targetinst(HvLpIndex lp);
+extern void vio_set_hostlp(void);
+extern void *vio_get_event_buffer(int subtype);
+extern void vio_free_event_buffer(int subtype, void *buffer);
extern HvLpIndex viopath_hostLp;
extern HvLpIndex viopath_ourLp;
-#define VIOCHAR_MAX_DATA 200
+#define VIOCHAR_MAX_DATA 200
-#define VIOMAJOR_SUBTYPE_MASK 0xff00
-#define VIOMINOR_SUBTYPE_MASK 0x00ff
-#define VIOMAJOR_SUBTYPE_SHIFT 8
+#define VIOMAJOR_SUBTYPE_MASK 0xff00
+#define VIOMINOR_SUBTYPE_MASK 0x00ff
+#define VIOMAJOR_SUBTYPE_SHIFT 8
-#define VIOVERSION 0x0101
+#define VIOVERSION 0x0101
/*
* This is the general structure for VIO errors; each module should have
int errno;
const char *msg;
};
-const struct vio_error_entry *vio_lookup_rc(const struct vio_error_entry
- *local_table, u16 rc);
+extern const struct vio_error_entry *vio_lookup_rc(
+ const struct vio_error_entry *local_table, u16 rc);
enum viosubtypes {
viomajorsubtype_monitor = 0x0100,
viomajorsubtype_scsi = 0x0700
};
-
enum vioconfigsubtype {
vioconfigget = 0x0001,
};
/*
* Define the address range of the imalloc VM area.
*/
-#define PHBS_IO_BASE IOREGIONBASE
-#define IMALLOC_BASE (IOREGIONBASE + 0x80000000ul) /* Reserve 2 gigs for PHBs */
-#define IMALLOC_END (IOREGIONBASE + EADDR_MASK)
+#define PHBS_IO_BASE VMALLOC_END
+#define IMALLOC_BASE (PHBS_IO_BASE + 0x80000000ul) /* Reserve 2 gigs for PHBs */
+#define IMALLOC_END (VMALLOC_START + EADDR_MASK)
/* imalloc region types */
extern struct vm_struct * im_get_free_area(unsigned long size);
extern struct vm_struct * im_get_area(unsigned long v_addr, unsigned long size,
- int region_type);
-unsigned long im_free(void *addr);
+ int region_type);
+extern void im_free(void *addr);
+
+extern unsigned long ioremap_bot;
#endif /* _PPC64_IMALLOC_H */
unsigned long *it_map; /* A simple allocation bitmap for now */
};
-#ifdef CONFIG_PPC_ISERIES
-struct iommu_table_cb {
- unsigned long itc_busno; /* Bus number for this tce table */
- unsigned long itc_start; /* Will be NULL for secondary */
- unsigned long itc_totalsize; /* Size (in pages) of whole table */
- unsigned long itc_offset; /* Index into real tce table of the
- start of our section */
- unsigned long itc_size; /* Size (in pages) of our section */
- unsigned long itc_index; /* Index of this tce table */
- unsigned short itc_maxtables; /* Max num of tables for partition */
- unsigned char itc_virtbus; /* Flag to indicate virtual bus */
- unsigned char itc_slotno; /* IOA Tce Slot Index */
- unsigned char itc_rsvd[4];
-};
-
-extern struct iommu_table vio_tce_table; /* Tce table for virtual bus */
-#endif /* CONFIG_PPC_ISERIES */
-
struct scatterlist;
#ifdef CONFIG_PPC_MULTIPLATFORM
#ifdef CONFIG_PPC_ISERIES
-/* Walks all buses and creates iommu tables */
-extern void iommu_setup_iSeries(void);
-
/* Initializes tables for bio buses */
extern void __init iommu_vio_init(void);
extern void iommu_init_early_iSeries(void);
extern void iommu_init_early_u3(void);
+#ifdef CONFIG_PCI
extern void pci_iommu_init(void);
extern void pci_direct_iommu_init(void);
+#else
+static inline void pci_iommu_init(void) { }
+#endif
extern void alloc_u3_dart_table(void);
#include <asm/types.h>
#include <asm/lppaca.h>
#include <asm/iSeries/ItLpRegSave.h>
+#include <asm/iSeries/ItLpQueue.h>
#include <asm/mmu.h>
register struct paca_struct *local_paca asm("r13");
#define get_paca() local_paca
struct task_struct;
-struct ItLpQueue;
/*
* Defines the layout of the paca.
#define PAGE_OFFSET ASM_CONST(0xC000000000000000)
#define KERNELBASE PAGE_OFFSET
#define VMALLOCBASE ASM_CONST(0xD000000000000000)
-#define IOREGIONBASE ASM_CONST(0xE000000000000000)
-#define IO_REGION_ID (IOREGIONBASE >> REGION_SHIFT)
#define VMALLOC_REGION_ID (VMALLOCBASE >> REGION_SHIFT)
#define KERNEL_REGION_ID (KERNELBASE >> REGION_SHIFT)
#define USER_REGION_ID (0UL)
* Define the address range of the vmalloc VM area.
*/
#define VMALLOC_START (0xD000000000000000ul)
-#define VMALLOC_END (VMALLOC_START + EADDR_MASK)
+#define VMALLOC_SIZE (0x10000000000UL)
+#define VMALLOC_END (VMALLOC_START + VMALLOC_SIZE)
/*
* Bits in a linux-style PTE. These match the bits in the
/* This now only contains the vmalloc pages */
#define pgd_offset_k(address) pgd_offset(&init_mm, address)
-/* to find an entry in the ioremap page-table-directory */
-#define pgd_offset_i(address) (ioremap_pgd + pgd_index(address))
-
/*
* The following only work if pte_present() is true.
* Undefined behaviour if not..
#define __HAVE_ARCH_PTE_SAME
#define pte_same(A,B) (((pte_val(A) ^ pte_val(B)) & ~_PAGE_HPTEFLAGS) == 0)
-extern unsigned long ioremap_bot, ioremap_base;
-
#define pmd_ERROR(e) \
printk("%s:%d: bad pmd %08x.\n", __FILE__, __LINE__, pmd_val(e))
#define pgd_ERROR(e) \
printk("%s:%d: bad pgd %08x.\n", __FILE__, __LINE__, pgd_val(e))
extern pgd_t swapper_pg_dir[];
-extern pgd_t ioremap_dir[];
extern void paging_init(void);
.fpexc_mode = MSR_FE0|MSR_FE1, \
}
-/*
- * Note: the vm_start and vm_end fields here should *not*
- * be in kernel space. (Could vm_end == vm_start perhaps?)
- */
-#define IOREMAP_MMAP { &ioremap_mm, 0, 0x1000, NULL, \
- PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, \
- 1, NULL, NULL }
-
-extern struct mm_struct ioremap_mm;
-
/*
* Return saved PC of a blocked thread. For now, this is the "user" PC
*/
void generic_mach_cpu_die(void);
#endif
-#define __smp_processor_id() (get_paca()->paca_index)
+#define raw_smp_processor_id() (get_paca()->paca_index)
#define hard_smp_processor_id() (get_paca()->hw_cpu_id)
extern cpumask_t cpu_sibling_map[NR_CPUS];
#define PROC_CHANGE_PENALTY 20 /* Schedule penalty */
-#define smp_processor_id() (S390_lowcore.cpu_data.cpu_nr)
+#define raw_smp_processor_id() (S390_lowcore.cpu_data.cpu_nr)
extern int smp_get_cpu(cpumask_t cpu_map);
extern void smp_put_cpu(int cpu);
#define HPAGE_SIZE (1UL << HPAGE_SHIFT)
#define HPAGE_MASK (~(HPAGE_SIZE-1))
#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT-PAGE_SHIFT)
+#define ARCH_HAS_SETCLEAR_HUGE_PTE
#endif
#ifdef __KERNEL__
static inline pte_t pte_mkdirty(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_DIRTY)); return pte; }
static inline pte_t pte_mkyoung(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_ACCESSED)); return pte; }
static inline pte_t pte_mkwrite(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_RW)); return pte; }
+static inline pte_t pte_mkhuge(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_SZHUGE)); return pte; }
/*
* Macro and implementation to make a page protection as uncachable.
#define cpu_online(cpu) cpu_isset(cpu, cpu_online_map)
-#define smp_processor_id() (current_thread_info()->cpu)
+#define raw_smp_processor_id() (current_thread_info()->cpu)
/* I've no idea what the real meaning of this is */
#define PROC_CHANGE_PENALTY 20
#define HPAGE_SIZE (1UL << HPAGE_SHIFT)
#define HPAGE_MASK (~(HPAGE_SIZE-1))
#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT-PAGE_SHIFT)
+#define ARCH_HAS_SETCLEAR_HUGE_PTE
#endif
#ifdef __KERNEL__
extern inline pte_t pte_mkexec(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_EXECUTE)); return pte; }
extern inline pte_t pte_mkdirty(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_DIRTY)); return pte; }
extern inline pte_t pte_mkyoung(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_ACCESSED)); return pte; }
+extern inline pte_t pte_mkhuge(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_SZHUGE)); return pte; }
+
/*
* Conversion functions: convert a page and protection to a page entry.
}
#endif
-#define smp_processor_id() (current_thread_info()->cpu)
+#define raw_smp_processor_id() (current_thread_info()->cpu)
#define prof_multiplier(__cpu) cpu_data(__cpu).multiplier
#define prof_counter(__cpu) cpu_data(__cpu).counter
#define HPAGE_SIZE (_AC(1,UL) << HPAGE_SHIFT)
#define HPAGE_MASK (~(HPAGE_SIZE - 1UL))
#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT)
+#define ARCH_HAS_SETCLEAR_HUGE_PTE
+#define ARCH_HAS_HUGETLB_PREFAULT_HOOK
#endif
#define TASK_UNMAPPED_BASE (test_thread_flag(TIF_32BIT) ? \
#define pte_mkyoung(pte) (__pte(pte_val(pte) | _PAGE_ACCESSED | _PAGE_R))
#define pte_mkwrite(pte) (__pte(pte_val(pte) | _PAGE_WRITE))
#define pte_mkdirty(pte) (__pte(pte_val(pte) | _PAGE_MODIFIED | _PAGE_W))
+#define pte_mkhuge(pte) (__pte(pte_val(pte) | _PAGE_SZHUGE))
/* to find an entry in a page-table-directory. */
#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1))
#define cpu_relax() barrier()
+/* Prefetch support. This is tuned for UltraSPARC-III and later.
+ * UltraSPARC-I will treat these as nops, and UltraSPARC-II has
+ * a shallower prefetch queue than later chips.
+ */
+#define ARCH_HAS_PREFETCH
+#define ARCH_HAS_PREFETCHW
+#define ARCH_HAS_SPINLOCK_PREFETCH
+
+static inline void prefetch(const void *x)
+{
+ /* We do not use the read prefetch mnemonic because that
+ * prefetches into the prefetch-cache which only is accessible
+ * by floating point operations in UltraSPARC-III and later.
+ * By contrast, "#one_write" prefetches into the L2 cache
+ * in shared state.
+ */
+ __asm__ __volatile__("prefetch [%0], #one_write"
+ : /* no outputs */
+ : "r" (x));
+}
+
+static inline void prefetchw(const void *x)
+{
+ /* The most optimal prefetch to use for writes is
+ * "#n_writes". This brings the cacheline into the
+ * L2 cache in "owned" state.
+ */
+ __asm__ __volatile__("prefetch [%0], #n_writes"
+ : /* no outputs */
+ : "r" (x));
+}
+
+#define spin_lock_prefetch(x) prefetchw(x)
+
#endif /* !(__ASSEMBLY__) */
#endif /* !(__ASM_SPARC64_PROCESSOR_H) */
}
}
-#define smp_processor_id() (current_thread_info()->cpu)
+#define raw_smp_processor_id() (current_thread_info()->cpu)
#endif /* !(__ASSEMBLY__) */
#include "asm/current.h"
#include "linux/cpumask.h"
-#define smp_processor_id() (current_thread->cpu)
+#define raw_smp_processor_id() (current_thread->cpu)
+
#define cpu_logical_map(n) (n)
#define cpu_number_map(n) (n)
#define PROC_CHANGE_PENALTY 15 /* Pick a number, any number */
#ifdef __KERNEL__
#include <linux/thread_info.h>
-#define STACK_TOP (test_thread_flag(TIF_IA32) ? IA32_PAGE_OFFSET : TASK_SIZE)
+#define STACK_TOP TASK_SIZE
#endif
#endif /* __A_OUT_GNU_H__ */
#define HPAGE_SIZE ((1UL) << HPAGE_SHIFT)
#define HPAGE_MASK (~(HPAGE_SIZE - 1))
#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT)
+#define ARCH_HAS_HUGETLB_CLEAN_STALE_PGTABLE
#ifdef __KERNEL__
#ifndef __ASSEMBLY__
extern inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_RW; }
static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; }
+#define __LARGE_PTE (_PAGE_PSE|_PAGE_PRESENT)
extern inline pte_t pte_rdprotect(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_USER)); return pte; }
extern inline pte_t pte_exprotect(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_USER)); return pte; }
extern inline pte_t pte_mkclean(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_DIRTY)); return pte; }
extern inline pte_t pte_mkdirty(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_DIRTY)); return pte; }
extern inline pte_t pte_mkyoung(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_ACCESSED)); return pte; }
extern inline pte_t pte_mkwrite(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_RW)); return pte; }
+extern inline pte_t pte_mkhuge(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | __LARGE_PTE)); return pte; }
struct vm_area_struct;
*/
#define pgprot_noncached(prot) (__pgprot(pgprot_val(prot) | _PAGE_PCD | _PAGE_PWT))
-#define __LARGE_PTE (_PAGE_PSE|_PAGE_PRESENT)
static inline int pmd_large(pmd_t pte) {
return (pmd_val(pte) & __LARGE_PTE) == __LARGE_PTE;
}
/*
* User space process size. 47bits minus one guard page.
*/
-#define TASK_SIZE (0x800000000000UL - 4096)
+#define TASK_SIZE64 (0x800000000000UL - 4096)
/* This decides where the kernel will search for a free chunk of vm
* space during mmap's.
*/
#define IA32_PAGE_OFFSET ((current->personality & ADDR_LIMIT_3GB) ? 0xc0000000 : 0xFFFFe000)
-#define TASK_UNMAPPED_32 PAGE_ALIGN(IA32_PAGE_OFFSET/3)
-#define TASK_UNMAPPED_64 PAGE_ALIGN(TASK_SIZE/3)
-#define TASK_UNMAPPED_BASE \
- (test_thread_flag(TIF_IA32) ? TASK_UNMAPPED_32 : TASK_UNMAPPED_64)
+
+#define TASK_SIZE (test_thread_flag(TIF_IA32) ? IA32_PAGE_OFFSET : TASK_SIZE64)
+#define TASK_SIZE_OF(child) ((test_tsk_thread_flag(child, TIF_IA32)) ? IA32_PAGE_OFFSET : TASK_SIZE64)
+
+#define TASK_UNMAPPED_BASE PAGE_ALIGN(TASK_SIZE/3)
/*
* Size of io_bitmap.
return cpus_weight(cpu_callout_map);
}
-#define __smp_processor_id() read_pda(cpunumber)
+#define raw_smp_processor_id() read_pda(cpunumber)
extern __inline int hard_smp_processor_id(void)
{
--- /dev/null
+#ifndef __LINUX_ARCFB_H__
+#define __LINUX_ARCFB_H__
+
+#define FBIO_WAITEVENT _IO('F', 0x88)
+#define FBIO_GETCONTROL2 _IOR('F', 0x89, size_t)
+
+#endif
+
#define AUTOFS_MIN_PROTO_VERSION 3
#define AUTOFS_MAX_PROTO_VERSION 4
-#define AUTOFS_PROTO_SUBVERSION 6
+#define AUTOFS_PROTO_SUBVERSION 7
/* Mask for expire behaviour */
#define AUTOFS_EXP_IMMEDIATE 1
u32 offset; /* current offset to buffer */
u32 buf_align; /* byte alignment of each bitmap */
u32 scan_align; /* alignment per scanline */
- u32 access_align; /* alignment per read/write */
+ u32 access_align; /* alignment per read/write (bits) */
u32 flags; /* see FB_PIXMAP_* */
/* access methods */
- void (*outbuf)(struct fb_info *info, u8 *addr, u8 *src, unsigned int size);
- u8 (*inbuf) (struct fb_info *info, u8 *addr);
+ void (*writeio)(struct fb_info *info, void __iomem *dst, void *src, unsigned int size);
+ void (*readio) (struct fb_info *info, void *dst, void __iomem *src, unsigned int size);
};
extern int fb_prepare_logo(struct fb_info *fb_info);
extern int fb_show_logo(struct fb_info *fb_info);
extern char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size);
-extern void fb_iomove_buf_unaligned(struct fb_info *info, struct fb_pixmap *buf,
- u8 *dst, u32 d_pitch, u8 *src, u32 idx,
+extern void fb_pad_unaligned_buffer(u8 *dst, u32 d_pitch, u8 *src, u32 idx,
u32 height, u32 shift_high, u32 shift_low, u32 mod);
-extern void fb_iomove_buf_aligned(struct fb_info *info, struct fb_pixmap *buf,
- u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch,
- u32 height);
-extern void fb_sysmove_buf_unaligned(struct fb_info *info, struct fb_pixmap *buf,
- u8 *dst, u32 d_pitch, u8 *src, u32 idx,
- u32 height, u32 shift_high, u32 shift_low, u32 mod);
-extern void fb_sysmove_buf_aligned(struct fb_info *info, struct fb_pixmap *buf,
- u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch,
- u32 height);
+extern void fb_pad_aligned_buffer(u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch, u32 height);
extern void fb_set_suspend(struct fb_info *info, int state);
extern int fb_get_color_depth(struct fb_var_screeninfo *var);
extern int fb_get_options(char *name, char **option);
#define VGA8x16_IDX 1
#define PEARL8x8_IDX 2
#define VGA6x11_IDX 3
-#define SUN8x16_IDX 4
-#define SUN12x22_IDX 5
-#define ACORN8x8_IDX 6
-#define MINI4x6_IDX 7
+#define FONT7x14_IDX 4
+#define FONT10x18_IDX 5
+#define SUN8x16_IDX 6
+#define SUN12x22_IDX 7
+#define ACORN8x8_IDX 8
+#define MINI4x6_IDX 9
extern struct font_desc font_vga_8x8,
- font_vga_8x16,
- font_pearl_8x8,
- font_vga_6x11,
- font_sun_8x16,
- font_sun_12x22,
- font_acorn_8x8,
- font_mini_4x6;
+ font_vga_8x16,
+ font_pearl_8x8,
+ font_vga_6x11,
+ font_7x14,
+ font_10x18,
+ font_sun_8x16,
+ font_sun_12x22,
+ font_acorn_8x8,
+ font_mini_4x6;
/* Find a font with a specific name */
/* board specific information */
u32 board_flags;
+ u32 phy_flags;
u32 phyid;
u32 interruptPHY;
u8 mac_addr[6];
#define FSL_GIANFAR_DEV_HAS_COALESCE 0x00000002
#define FSL_GIANFAR_DEV_HAS_RMON 0x00000004
#define FSL_GIANFAR_DEV_HAS_MULTI_INTR 0x00000008
+#define FSL_GIANFAR_DEV_HAS_CSUM 0x00000010
+#define FSL_GIANFAR_DEV_HAS_VLAN 0x00000020
+#define FSL_GIANFAR_DEV_HAS_EXTENDED_HASH 0x00000040
+#define FSL_GIANFAR_DEV_HAS_PADDING 0x00000080
/* Flags in gianfar_platform_data */
-#define FSL_GIANFAR_BRD_HAS_PHY_INTR 0x00000001 /* if not set use a timer */
+#define FSL_GIANFAR_BRD_HAS_PHY_INTR 0x00000001 /* set or use a timer */
+#define FSL_GIANFAR_BRD_IS_REDUCED 0x00000002 /* Set if RGMII, RMII */
struct fsl_i2c_platform_data {
/* device specific information */
--- /dev/null
+/*
+ * Basic general purpose allocator for managing special purpose memory
+ * not managed by the regular kmalloc/kfree interface.
+ * Uses for this includes on-device special memory, uncached memory
+ * etc.
+ *
+ * This code is based on the buddy allocator found in the sym53c8xx_2
+ * driver, adapted for general purpose use.
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include <linux/spinlock.h>
+
+#define ALLOC_MIN_SHIFT 5 /* 32 bytes minimum */
+/*
+ * Link between free memory chunks of a given size.
+ */
+struct gen_pool_link {
+ struct gen_pool_link *next;
+};
+
+/*
+ * Memory pool descriptor.
+ */
+struct gen_pool {
+ spinlock_t lock;
+ unsigned long (*get_new_chunk)(struct gen_pool *);
+ struct gen_pool *next;
+ struct gen_pool_link *h;
+ unsigned long private;
+ int max_chunk_shift;
+};
+
+unsigned long gen_pool_alloc(struct gen_pool *poolp, int size);
+void gen_pool_free(struct gen_pool *mp, unsigned long ptr, int size);
+struct gen_pool *gen_pool_create(int nr_chunks, int max_chunk_shift,
+ unsigned long (*fp)(struct gen_pool *),
+ unsigned long data);
#define __GFP_COMP 0x4000u /* Add compound page metadata */
#define __GFP_ZERO 0x8000u /* Return zeroed page on success */
#define __GFP_NOMEMALLOC 0x10000u /* Don't use emergency reserves */
+#define __GFP_NORECLAIM 0x20000u /* No realy zone reclaim during allocation */
#define __GFP_BITS_SHIFT 20 /* Room for 20 __GFP_FOO bits */
#define __GFP_BITS_MASK ((1 << __GFP_BITS_SHIFT) - 1)
#define GFP_LEVEL_MASK (__GFP_WAIT|__GFP_HIGH|__GFP_IO|__GFP_FS| \
__GFP_COLD|__GFP_NOWARN|__GFP_REPEAT| \
__GFP_NOFAIL|__GFP_NORETRY|__GFP_NO_GROW|__GFP_COMP| \
- __GFP_NOMEMALLOC)
+ __GFP_NOMEMALLOC|__GFP_NORECLAIM)
#define GFP_ATOMIC (__GFP_HIGH)
#define GFP_NOIO (__GFP_WAIT)
#define free_page(addr) free_pages((addr),0)
void page_alloc_init(void);
+#ifdef CONFIG_NUMA
+void drain_remote_pages(void);
+#else
+static inline void drain_remote_pages(void) { };
+#endif
#endif /* __LINUX_GFP_H */
#ifdef CONFIG_HUGETLB_PAGE
#include <linux/mempolicy.h>
+#include <asm/tlbflush.h>
struct ctl_table;
int hugetlb_report_node_meminfo(int, char *);
int is_hugepage_mem_enough(size_t);
unsigned long hugetlb_total_pages(void);
-struct page *follow_huge_addr(struct mm_struct *mm, unsigned long address,
- int write);
-struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address,
- pmd_t *pmd, int write);
-int is_aligned_hugepage_range(unsigned long addr, unsigned long len);
-int pmd_huge(pmd_t pmd);
struct page *alloc_huge_page(void);
void free_huge_page(struct page *);
extern const unsigned long hugetlb_zero, hugetlb_infinity;
extern int sysctl_hugetlb_shm_group;
+/* arch callbacks */
+
+pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr);
+pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr);
+struct page *follow_huge_addr(struct mm_struct *mm, unsigned long address,
+ int write);
+struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address,
+ pmd_t *pmd, int write);
+int is_aligned_hugepage_range(unsigned long addr, unsigned long len);
+int pmd_huge(pmd_t pmd);
+
#ifndef ARCH_HAS_HUGEPAGE_ONLY_RANGE
#define is_hugepage_only_range(mm, addr, len) 0
#define hugetlb_free_pgd_range(tlb, addr, end, floor, ceiling) \
int prepare_hugepage_range(unsigned long addr, unsigned long len);
#endif
+#ifndef ARCH_HAS_SETCLEAR_HUGE_PTE
+#define set_huge_pte_at(mm, addr, ptep, pte) set_pte_at(mm, addr, ptep, pte)
+#define huge_ptep_get_and_clear(mm, addr, ptep) ptep_get_and_clear(mm, addr, ptep)
+#else
+void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t pte);
+pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep);
+#endif
+
+#ifndef ARCH_HAS_HUGETLB_PREFAULT_HOOK
+#define hugetlb_prefault_arch_hook(mm) do { } while (0)
+#else
+void hugetlb_prefault_arch_hook(struct mm_struct *mm);
+#endif
+
+#ifndef ARCH_HAS_HUGETLB_CLEAN_STALE_PGTABLE
+#define hugetlb_clean_stale_pgtable(pte) BUG()
+#else
+void hugetlb_clean_stale_pgtable(pte_t *pte);
+#endif
+
#else /* !CONFIG_HUGETLB_PAGE */
static inline int is_vm_hugetlb_page(struct vm_area_struct *vma)
--- /dev/null
+/*
+ * hwmon-sysfs.h - hardware monitoring chip driver sysfs defines
+ *
+ * Copyright (C) 2005 Yani Ioannou <yani.ioannou@gmail.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 _LINUX_HWMON_SYSFS_H
+#define _LINUX_HWMON_SYSFS_H
+
+struct sensor_device_attribute{
+ struct device_attribute dev_attr;
+ int index;
+};
+#define to_sensor_dev_attr(_dev_attr) \
+ container_of(_dev_attr, struct sensor_device_attribute, dev_attr)
+
+#define SENSOR_DEVICE_ATTR(_name,_mode,_show,_store,_index) \
+struct sensor_device_attribute sensor_dev_attr_##_name = { \
+ .dev_attr = __ATTR(_name,_mode,_show,_store), \
+ .index = _index, \
+}
+
+#endif /* _LINUX_HWMON_SYSFS_H */
#define I2C_DRIVERID_TDA7313 62 /* TDA7313 audio processor */
#define I2C_DRIVERID_MAX6900 63 /* MAX6900 real-time clock */
#define I2C_DRIVERID_SAA7114H 64 /* video decoder */
+#define I2C_DRIVERID_DS1374 65 /* DS1374 real time clock */
#define I2C_DRIVERID_EXP0 0xF0 /* experimental use id's */
+++ /dev/null
-/*
- * i2c-sysfs.h - i2c chip driver sysfs defines
- *
- * Copyright (C) 2005 Yani Ioannou <yani.ioannou@gmail.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 _LINUX_I2C_SYSFS_H
-#define _LINUX_I2C_SYSFS_H
-
-struct sensor_device_attribute{
- struct device_attribute dev_attr;
- int index;
-};
-#define to_sensor_dev_attr(_dev_attr) \
- container_of(_dev_attr, struct sensor_device_attribute, dev_attr)
-
-#define SENSOR_DEVICE_ATTR(_name,_mode,_show,_store,_index) \
-struct sensor_device_attribute sensor_dev_attr_##_name = { \
- .dev_attr = __ATTR(_name,_mode,_show,_store), \
- .index = _index, \
-}
-
-#endif /* _LINUX_I2C_SYSFS_H */
2050 - (val) * 50);
}
}
+
+static inline int vid_to_reg(int val, int vrm)
+{
+ switch (vrm) {
+ case 91: /* VRM 9.1 */
+ case 90: /* VRM 9.0 */
+ return ((val >= 1100) && (val <= 1850) ?
+ ((18499 - val * 10) / 25 + 5) / 10 : -1);
+ default:
+ return -1;
+ }
+}
*/
struct i2c_client_address_data {
unsigned short *normal_i2c;
- unsigned short *normal_i2c_range;
unsigned short *probe;
- unsigned short *probe_range;
unsigned short *ignore;
- unsigned short *ignore_range;
unsigned short *force;
};
#define I2C_CLIENT_INSMOD \
I2C_CLIENT_MODULE_PARM(probe, \
"List of adapter,address pairs to scan additionally"); \
- I2C_CLIENT_MODULE_PARM(probe_range, \
- "List of adapter,start-addr,end-addr triples to scan " \
- "additionally"); \
I2C_CLIENT_MODULE_PARM(ignore, \
"List of adapter,address pairs not to scan"); \
- I2C_CLIENT_MODULE_PARM(ignore_range, \
- "List of adapter,start-addr,end-addr triples not to " \
- "scan"); \
I2C_CLIENT_MODULE_PARM(force, \
"List of adapter,address pairs to boldly assume " \
"to be present"); \
static struct i2c_client_address_data addr_data = { \
.normal_i2c = normal_i2c, \
- .normal_i2c_range = normal_i2c_range, \
.probe = probe, \
- .probe_range = probe_range, \
.ignore = ignore, \
- .ignore_range = ignore_range, \
.force = force, \
}
--- /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 _LINUX_IOC4_H
+#define _LINUX_IOC4_H
+
+#include <linux/interrupt.h>
+
+/***************
+ * Definitions *
+ ***************/
+
+/* Miscellaneous values inherent to hardware */
+
+#define IOC4_EXTINT_COUNT_DIVISOR 520 /* PCI clocks per COUNT tick */
+
+/***********************************
+ * Structures needed by subdrivers *
+ ***********************************/
+
+/* This structure fully describes the IOC4 miscellaneous registers which
+ * appear at bar[0]+0x00000 through bar[0]+0x0005c. The corresponding
+ * PCI resource is managed by the main IOC4 driver because it contains
+ * registers of interest to many different IOC4 subdrivers.
+ */
+struct ioc4_misc_regs {
+ /* Miscellaneous IOC4 registers */
+ union ioc4_pci_err_addr_l {
+ uint32_t raw;
+ struct {
+ uint32_t valid:1; /* Address captured */
+ uint32_t master_id:4; /* Unit causing error
+ * 0/1: Serial port 0 TX/RX
+ * 2/3: Serial port 1 TX/RX
+ * 4/5: Serial port 2 TX/RX
+ * 6/7: Serial port 3 TX/RX
+ * 8: ATA/ATAPI
+ * 9-15: Undefined
+ */
+ uint32_t mul_err:1; /* Multiple errors occurred */
+ uint32_t addr:26; /* Bits 31-6 of error addr */
+ } fields;
+ } pci_err_addr_l;
+ uint32_t pci_err_addr_h; /* Bits 63-32 of error addr */
+ union ioc4_sio_int {
+ uint32_t raw;
+ struct {
+ uint8_t tx_mt:1; /* TX ring buffer empty */
+ uint8_t rx_full:1; /* RX ring buffer full */
+ uint8_t rx_high:1; /* RX high-water exceeded */
+ uint8_t rx_timer:1; /* RX timer has triggered */
+ uint8_t delta_dcd:1; /* DELTA_DCD seen */
+ uint8_t delta_cts:1; /* DELTA_CTS seen */
+ uint8_t intr_pass:1; /* Interrupt pass-through */
+ uint8_t tx_explicit:1; /* TX, MCW, or delay complete */
+ } fields[4];
+ } sio_ir; /* Serial interrupt state */
+ union ioc4_other_int {
+ uint32_t raw;
+ struct {
+ uint32_t ata_int:1; /* ATA port passthru */
+ uint32_t ata_memerr:1; /* ATA halted by mem error */
+ uint32_t memerr:4; /* Serial halted by mem err */
+ uint32_t kbd_int:1; /* kbd/mouse intr asserted */
+ uint32_t reserved:16; /* zero */
+ uint32_t rt_int:1; /* INT_OUT section latch */
+ uint32_t gen_int:8; /* Intr. from generic pins */
+ } fields;
+ } other_ir; /* Other interrupt state */
+ union ioc4_sio_int sio_ies; /* Serial interrupt enable set */
+ union ioc4_other_int other_ies; /* Other interrupt enable set */
+ union ioc4_sio_int sio_iec; /* Serial interrupt enable clear */
+ union ioc4_other_int other_iec; /* Other interrupt enable clear */
+ union ioc4_sio_cr {
+ uint32_t raw;
+ struct {
+ uint32_t cmd_pulse:4; /* Bytebus strobe width */
+ uint32_t arb_diag:3; /* PCI bus requester */
+ uint32_t sio_diag_idle:1; /* Active ser req? */
+ uint32_t ata_diag_idle:1; /* Active ATA req? */
+ uint32_t ata_diag_active:1; /* ATA req is winner */
+ uint32_t reserved:22; /* zero */
+ } fields;
+ } sio_cr;
+ uint32_t unused1;
+ union ioc4_int_out {
+ uint32_t raw;
+ struct {
+ uint32_t count:16; /* Period control */
+ uint32_t mode:3; /* Output signal shape */
+ uint32_t reserved:11; /* zero */
+ uint32_t diag:1; /* Timebase control */
+ uint32_t int_out:1; /* Current value */
+ } fields;
+ } int_out; /* External interrupt output control */
+ uint32_t unused2;
+ union ioc4_gpcr {
+ uint32_t raw;
+ struct {
+ uint32_t dir:8; /* Pin direction */
+ uint32_t edge:8; /* Edge/level mode */
+ uint32_t reserved1:4; /* zero */
+ uint32_t int_out_en:1; /* INT_OUT enable */
+ uint32_t reserved2:11; /* zero */
+ } fields;
+ } gpcr_s; /* Generic PIO control set */
+ union ioc4_gpcr gpcr_c; /* Generic PIO control clear */
+ union ioc4_gpdr {
+ uint32_t raw;
+ struct {
+ uint32_t gen_pin:8; /* State of pins */
+ uint32_t reserved:24;
+ } fields;
+ } gpdr; /* Generic PIO data */
+ uint32_t unused3;
+ union ioc4_gppr {
+ uint32_t raw;
+ struct {
+ uint32_t gen_pin:1; /* Single pin state */
+ uint32_t reserved:31;
+ } fields;
+ } gppr[8]; /* Generic PIO pins */
+};
+
+/* Masks for GPCR DIR pins */
+#define IOC4_GPCR_DIR_0 0x01 /* External interrupt output */
+#define IOC4_GPCR_DIR_1 0x02 /* External interrupt input */
+#define IOC4_GPCR_DIR_2 0x04
+#define IOC4_GPCR_DIR_3 0x08 /* Keyboard/mouse presence */
+#define IOC4_GPCR_DIR_4 0x10 /* Ser. port 0 xcvr select (0=232, 1=422) */
+#define IOC4_GPCR_DIR_5 0x20 /* Ser. port 1 xcvr select (0=232, 1=422) */
+#define IOC4_GPCR_DIR_6 0x40 /* Ser. port 2 xcvr select (0=232, 1=422) */
+#define IOC4_GPCR_DIR_7 0x80 /* Ser. port 3 xcvr select (0=232, 1=422) */
+
+/* Masks for GPCR EDGE pins */
+#define IOC4_GPCR_EDGE_0 0x01
+#define IOC4_GPCR_EDGE_1 0x02 /* External interrupt input */
+#define IOC4_GPCR_EDGE_2 0x04
+#define IOC4_GPCR_EDGE_3 0x08
+#define IOC4_GPCR_EDGE_4 0x10
+#define IOC4_GPCR_EDGE_5 0x20
+#define IOC4_GPCR_EDGE_6 0x40
+#define IOC4_GPCR_EDGE_7 0x80
+
+/* One of these per IOC4 */
+struct ioc4_driver_data {
+ struct list_head idd_list;
+ unsigned long idd_bar0;
+ struct pci_dev *idd_pdev;
+ const struct pci_device_id *idd_pci_id;
+ struct __iomem ioc4_misc_regs *idd_misc_regs;
+ unsigned long count_period;
+ void *idd_serial_data;
+};
+
+/* One per submodule */
+struct ioc4_submodule {
+ struct list_head is_list;
+ char *is_name;
+ struct module *is_owner;
+ int (*is_probe) (struct ioc4_driver_data *);
+ int (*is_remove) (struct ioc4_driver_data *);
+};
+
+#define IOC4_NUM_CARDS 8 /* max cards per partition */
+
+/**********************************
+ * Functions needed by submodules *
+ **********************************/
+
+extern int ioc4_register_submodule(struct ioc4_submodule *);
+extern void ioc4_unregister_submodule(struct ioc4_submodule *);
+
+#endif /* _LINUX_IOC4_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 _LINUX_IOC4_COMMON_H
-#define _LINUX_IOC4_COMMON_H
-
-/* prototypes */
-
-int ioc4_serial_init(void);
-
-int ioc4_serial_attach_one(struct pci_dev *pdev, const struct
- pci_device_id *pci_id);
-int ioc4_ide_attach_one(struct pci_dev *pdev, const struct
- pci_device_id *pci_id);
-
-#endif /* _LINUX_IOC4_COMMON_H */
void (*ack)(unsigned int irq);
void (*end)(unsigned int irq);
void (*set_affinity)(unsigned int irq, cpumask_t dest);
+ /* Currently used only by UML, might disappear one day.*/
+#ifdef CONFIG_IRQ_RELEASE_METHOD
+ void (*release)(unsigned int irq, void *dev_id);
+#endif
};
typedef struct hw_interrupt_type hw_irq_controller;
extern void si_meminfo(struct sysinfo * val);
extern void si_meminfo_node(struct sysinfo *val, int nid);
+#ifdef CONFIG_NUMA
+extern void setup_per_cpu_pageset(void);
+#else
+static inline void setup_per_cpu_pageset(void) {}
+#endif
+
/* prio_tree.c */
void vma_prio_tree_add(struct vm_area_struct *, struct vm_area_struct *old);
void vma_prio_tree_insert(struct vm_area_struct *, struct prio_tree_root *);
#endif
} ____cacheline_aligned_in_smp;
+#ifdef CONFIG_NUMA
+#define zone_pcp(__z, __cpu) ((__z)->pageset[(__cpu)])
+#else
+#define zone_pcp(__z, __cpu) (&(__z)->pageset[(__cpu)])
+#endif
+
#define ZONE_DMA 0
#define ZONE_NORMAL 1
#define ZONE_HIGHMEM 2
*/
unsigned long lowmem_reserve[MAX_NR_ZONES];
+#ifdef CONFIG_NUMA
+ struct per_cpu_pageset *pageset[NR_CPUS];
+#else
struct per_cpu_pageset pageset[NR_CPUS];
-
+#endif
/*
* free areas of different sizes
*/
unsigned long pages_scanned; /* since last reclaim */
int all_unreclaimable; /* All pages pinned */
+ /*
+ * Does the allocator try to reclaim pages from the zone as soon
+ * as it fails a watermark_ok() in __alloc_pages?
+ */
+ int reclaim_pages;
+ /* A count of how many reclaimers are scanning this zone */
+ atomic_t reclaim_in_progress;
+
/*
* prev_priority holds the scanning priority for this zone. It is
* defined as the scanning priority at which we achieved our reclaim
#include <linux/topology.h>
/* Returns the number of the current Node. */
-#define numa_node_id() (cpu_to_node(_smp_processor_id()))
+#define numa_node_id() (cpu_to_node(raw_smp_processor_id()))
#ifndef CONFIG_DISCONTIGMEM
#define PG_active 6
#define PG_slab 7 /* slab debug (Suparna wants this) */
-#define PG_highmem 8
-#define PG_checked 9 /* kill me in 2.5.<early>. */
-#define PG_arch_1 10
-#define PG_reserved 11
-
-#define PG_private 12 /* Has something at ->private */
-#define PG_writeback 13 /* Page is under writeback */
-#define PG_nosave 14 /* Used for system suspend/resume */
-#define PG_compound 15 /* Part of a compound page */
-
-#define PG_swapcache 16 /* Swap page: swp_entry_t in private */
-#define PG_mappedtodisk 17 /* Has blocks allocated on-disk */
-#define PG_reclaim 18 /* To be reclaimed asap */
-#define PG_nosave_free 19 /* Free, should not be written */
-#define PG_uncached 20 /* Page has been mapped as uncached */
+#define PG_checked 8 /* kill me in 2.5.<early>. */
+#define PG_arch_1 9
+#define PG_reserved 10
+#define PG_private 11 /* Has something at ->private */
+
+#define PG_writeback 12 /* Page is under writeback */
+#define PG_nosave 13 /* Used for system suspend/resume */
+#define PG_compound 14 /* Part of a compound page */
+#define PG_swapcache 15 /* Swap page: swp_entry_t in private */
+
+#define PG_mappedtodisk 16 /* Has blocks allocated on-disk */
+#define PG_reclaim 17 /* To be reclaimed asap */
+#define PG_nosave_free 18 /* Free, should not be written */
+#define PG_uncached 19 /* Page has been mapped as uncached */
/*
* Global page accounting. One instance per CPU. Only unsigned longs are
extern void get_page_state(struct page_state *ret);
extern void get_full_page_state(struct page_state *ret);
-extern unsigned long __read_page_state(unsigned offset);
-extern void __mod_page_state(unsigned offset, unsigned long delta);
+extern unsigned long __read_page_state(unsigned long offset);
+extern void __mod_page_state(unsigned long offset, unsigned long delta);
#define read_page_state(member) \
__read_page_state(offsetof(struct page_state, member))
#define TestSetPageSlab(page) test_and_set_bit(PG_slab, &(page)->flags)
#ifdef CONFIG_HIGHMEM
-#define PageHighMem(page) test_bit(PG_highmem, &(page)->flags)
+#define PageHighMem(page) is_highmem(page_zone(page))
#else
#define PageHighMem(page) 0 /* needed to optimize away at compile time */
#endif
static inline struct page *page_cache_alloc(struct address_space *x)
{
- return alloc_pages(mapping_gfp_mask(x), 0);
+ return alloc_pages(mapping_gfp_mask(x)|__GFP_NORECLAIM, 0);
}
static inline struct page *page_cache_alloc_cold(struct address_space *x)
{
- return alloc_pages(mapping_gfp_mask(x)|__GFP_COLD, 0);
+ return alloc_pages(mapping_gfp_mask(x)|__GFP_COLD|__GFP_NORECLAIM, 0);
}
typedef int filler_t(void *, struct page *);
#define PCI_DEVICE_ID_CT_65550 0x00e0
#define PCI_DEVICE_ID_CT_65554 0x00e4
#define PCI_DEVICE_ID_CT_65555 0x00e5
+#define PCI_DEVICE_ID_CT_69000 0x00c0
#define PCI_VENDOR_ID_MIRO 0x1031
#define PCI_DEVICE_ID_MIRO_36050 0x5601
--- /dev/null
+/*
+ * bitmap.h: Copyright (C) Peter T. Breuer (ptb@ot.uc3m.es) 2003
+ *
+ * additions: Copyright (C) 2003-2004, Paul Clements, SteelEye Technology, Inc.
+ */
+#ifndef BITMAP_H
+#define BITMAP_H 1
+
+#define BITMAP_MAJOR 3
+#define BITMAP_MINOR 38
+
+/*
+ * in-memory bitmap:
+ *
+ * Use 16 bit block counters to track pending writes to each "chunk".
+ * The 2 high order bits are special-purpose, the first is a flag indicating
+ * whether a resync is needed. The second is a flag indicating whether a
+ * resync is active.
+ * This means that the counter is actually 14 bits:
+ *
+ * +--------+--------+------------------------------------------------+
+ * | resync | resync | counter |
+ * | needed | active | |
+ * | (0-1) | (0-1) | (0-16383) |
+ * +--------+--------+------------------------------------------------+
+ *
+ * The "resync needed" bit is set when:
+ * a '1' bit is read from storage at startup.
+ * a write request fails on some drives
+ * a resync is aborted on a chunk with 'resync active' set
+ * It is cleared (and resync-active set) when a resync starts across all drives
+ * of the chunk.
+ *
+ *
+ * The "resync active" bit is set when:
+ * a resync is started on all drives, and resync_needed is set.
+ * resync_needed will be cleared (as long as resync_active wasn't already set).
+ * It is cleared when a resync completes.
+ *
+ * The counter counts pending write requests, plus the on-disk bit.
+ * When the counter is '1' and the resync bits are clear, the on-disk
+ * bit can be cleared aswell, thus setting the counter to 0.
+ * When we set a bit, or in the counter (to start a write), if the fields is
+ * 0, we first set the disk bit and set the counter to 1.
+ *
+ * If the counter is 0, the on-disk bit is clear and the stipe is clean
+ * Anything that dirties the stipe pushes the counter to 2 (at least)
+ * and sets the on-disk bit (lazily).
+ * If a periodic sweep find the counter at 2, it is decremented to 1.
+ * If the sweep find the counter at 1, the on-disk bit is cleared and the
+ * counter goes to zero.
+ *
+ * Also, we'll hijack the "map" pointer itself and use it as two 16 bit block
+ * counters as a fallback when "page" memory cannot be allocated:
+ *
+ * Normal case (page memory allocated):
+ *
+ * page pointer (32-bit)
+ *
+ * [ ] ------+
+ * |
+ * +-------> [ ][ ]..[ ] (4096 byte page == 2048 counters)
+ * c1 c2 c2048
+ *
+ * Hijacked case (page memory allocation failed):
+ *
+ * hijacked page pointer (32-bit)
+ *
+ * [ ][ ] (no page memory allocated)
+ * counter #1 (16-bit) counter #2 (16-bit)
+ *
+ */
+
+#ifdef __KERNEL__
+
+#define PAGE_BITS (PAGE_SIZE << 3)
+#define PAGE_BIT_SHIFT (PAGE_SHIFT + 3)
+
+typedef __u16 bitmap_counter_t;
+#define COUNTER_BITS 16
+#define COUNTER_BIT_SHIFT 4
+#define COUNTER_BYTE_RATIO (COUNTER_BITS / 8)
+#define COUNTER_BYTE_SHIFT (COUNTER_BIT_SHIFT - 3)
+
+#define NEEDED_MASK ((bitmap_counter_t) (1 << (COUNTER_BITS - 1)))
+#define RESYNC_MASK ((bitmap_counter_t) (1 << (COUNTER_BITS - 2)))
+#define COUNTER_MAX ((bitmap_counter_t) RESYNC_MASK - 1)
+#define NEEDED(x) (((bitmap_counter_t) x) & NEEDED_MASK)
+#define RESYNC(x) (((bitmap_counter_t) x) & RESYNC_MASK)
+#define COUNTER(x) (((bitmap_counter_t) x) & COUNTER_MAX)
+
+/* how many counters per page? */
+#define PAGE_COUNTER_RATIO (PAGE_BITS / COUNTER_BITS)
+/* same, except a shift value for more efficient bitops */
+#define PAGE_COUNTER_SHIFT (PAGE_BIT_SHIFT - COUNTER_BIT_SHIFT)
+/* same, except a mask value for more efficient bitops */
+#define PAGE_COUNTER_MASK (PAGE_COUNTER_RATIO - 1)
+
+#define BITMAP_BLOCK_SIZE 512
+#define BITMAP_BLOCK_SHIFT 9
+
+/* how many blocks per chunk? (this is variable) */
+#define CHUNK_BLOCK_RATIO(bitmap) ((bitmap)->chunksize >> BITMAP_BLOCK_SHIFT)
+#define CHUNK_BLOCK_SHIFT(bitmap) ((bitmap)->chunkshift - BITMAP_BLOCK_SHIFT)
+#define CHUNK_BLOCK_MASK(bitmap) (CHUNK_BLOCK_RATIO(bitmap) - 1)
+
+/* when hijacked, the counters and bits represent even larger "chunks" */
+/* there will be 1024 chunks represented by each counter in the page pointers */
+#define PAGEPTR_BLOCK_RATIO(bitmap) \
+ (CHUNK_BLOCK_RATIO(bitmap) << PAGE_COUNTER_SHIFT >> 1)
+#define PAGEPTR_BLOCK_SHIFT(bitmap) \
+ (CHUNK_BLOCK_SHIFT(bitmap) + PAGE_COUNTER_SHIFT - 1)
+#define PAGEPTR_BLOCK_MASK(bitmap) (PAGEPTR_BLOCK_RATIO(bitmap) - 1)
+
+/*
+ * on-disk bitmap:
+ *
+ * Use one bit per "chunk" (block set). We do the disk I/O on the bitmap
+ * file a page at a time. There's a superblock at the start of the file.
+ */
+
+/* map chunks (bits) to file pages - offset by the size of the superblock */
+#define CHUNK_BIT_OFFSET(chunk) ((chunk) + (sizeof(bitmap_super_t) << 3))
+
+#endif
+
+/*
+ * bitmap structures:
+ */
+
+#define BITMAP_MAGIC 0x6d746962
+
+/* use these for bitmap->flags and bitmap->sb->state bit-fields */
+enum bitmap_state {
+ BITMAP_ACTIVE = 0x001, /* the bitmap is in use */
+ BITMAP_STALE = 0x002 /* the bitmap file is out of date or had -EIO */
+};
+
+/* the superblock at the front of the bitmap file -- little endian */
+typedef struct bitmap_super_s {
+ __u32 magic; /* 0 BITMAP_MAGIC */
+ __u32 version; /* 4 the bitmap major for now, could change... */
+ __u8 uuid[16]; /* 8 128 bit uuid - must match md device uuid */
+ __u64 events; /* 24 event counter for the bitmap (1)*/
+ __u64 events_cleared;/*32 event counter when last bit cleared (2) */
+ __u64 sync_size; /* 40 the size of the md device's sync range(3) */
+ __u32 state; /* 48 bitmap state information */
+ __u32 chunksize; /* 52 the bitmap chunk size in bytes */
+ __u32 daemon_sleep; /* 56 seconds between disk flushes */
+
+ __u8 pad[256 - 60]; /* set to zero */
+} bitmap_super_t;
+
+/* notes:
+ * (1) This event counter is updated before the eventcounter in the md superblock
+ * When a bitmap is loaded, it is only accepted if this event counter is equal
+ * to, or one greater than, the event counter in the superblock.
+ * (2) This event counter is updated when the other one is *if*and*only*if* the
+ * array is not degraded. As bits are not cleared when the array is degraded,
+ * this represents the last time that any bits were cleared.
+ * If a device is being added that has an event count with this value or
+ * higher, it is accepted as conforming to the bitmap.
+ * (3)This is the number of sectors represented by the bitmap, and is the range that
+ * resync happens across. For raid1 and raid5/6 it is the size of individual
+ * devices. For raid10 it is the size of the array.
+ */
+
+#ifdef __KERNEL__
+
+/* the in-memory bitmap is represented by bitmap_pages */
+struct bitmap_page {
+ /*
+ * map points to the actual memory page
+ */
+ char *map;
+ /*
+ * in emergencies (when map cannot be alloced), hijack the map
+ * pointer and use it as two counters itself
+ */
+ unsigned int hijacked:1;
+ /*
+ * count of dirty bits on the page
+ */
+ unsigned int count:31;
+};
+
+/* keep track of bitmap file pages that have pending writes on them */
+struct page_list {
+ struct list_head list;
+ struct page *page;
+};
+
+/* the main bitmap structure - one per mddev */
+struct bitmap {
+ struct bitmap_page *bp;
+ unsigned long pages; /* total number of pages in the bitmap */
+ unsigned long missing_pages; /* number of pages not yet allocated */
+
+ mddev_t *mddev; /* the md device that the bitmap is for */
+
+ int counter_bits; /* how many bits per block counter */
+
+ /* bitmap chunksize -- how much data does each bit represent? */
+ unsigned long chunksize;
+ unsigned long chunkshift; /* chunksize = 2^chunkshift (for bitops) */
+ unsigned long chunks; /* total number of data chunks for the array */
+
+ /* We hold a count on the chunk currently being synced, and drop
+ * it when the last block is started. If the resync is aborted
+ * midway, we need to be able to drop that count, so we remember
+ * the counted chunk..
+ */
+ unsigned long syncchunk;
+
+ __u64 events_cleared;
+
+ /* bitmap spinlock */
+ spinlock_t lock;
+
+ long offset; /* offset from superblock if file is NULL */
+ struct file *file; /* backing disk file */
+ struct page *sb_page; /* cached copy of the bitmap file superblock */
+ struct page **filemap; /* list of cache pages for the file */
+ unsigned long *filemap_attr; /* attributes associated w/ filemap pages */
+ unsigned long file_pages; /* number of pages in the file */
+
+ unsigned long flags;
+
+ /*
+ * the bitmap daemon - periodically wakes up and sweeps the bitmap
+ * file, cleaning up bits and flushing out pages to disk as necessary
+ */
+ unsigned long daemon_lastrun; /* jiffies of last run */
+ unsigned long daemon_sleep; /* how many seconds between updates? */
+
+ /*
+ * bitmap_writeback_daemon waits for file-pages that have been written,
+ * as there is no way to get a call-back when a page write completes.
+ */
+ mdk_thread_t *writeback_daemon;
+ spinlock_t write_lock;
+ wait_queue_head_t write_wait;
+ struct list_head complete_pages;
+ mempool_t *write_pool;
+};
+
+/* the bitmap API */
+
+/* these are used only by md/bitmap */
+int bitmap_create(mddev_t *mddev);
+void bitmap_destroy(mddev_t *mddev);
+int bitmap_active(struct bitmap *bitmap);
+
+char *file_path(struct file *file, char *buf, int count);
+void bitmap_print_sb(struct bitmap *bitmap);
+int bitmap_update_sb(struct bitmap *bitmap);
+
+int bitmap_setallbits(struct bitmap *bitmap);
+void bitmap_write_all(struct bitmap *bitmap);
+
+/* these are exported */
+int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sectors);
+void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long sectors,
+ int success);
+int bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *blocks);
+void bitmap_end_sync(struct bitmap *bitmap, sector_t offset, int *blocks, int aborted);
+void bitmap_close_sync(struct bitmap *bitmap);
+
+int bitmap_unplug(struct bitmap *bitmap);
+int bitmap_daemon_work(struct bitmap *bitmap);
+#endif
+
+#endif
*/
#define MD_MAJOR_VERSION 0
#define MD_MINOR_VERSION 90
-#define MD_PATCHLEVEL_VERSION 1
+/*
+ * MD_PATCHLEVEL_VERSION indicates kernel functionality.
+ * >=1 means different superblock formats are selectable using SET_ARRAY_INFO
+ * and major_version/minor_version accordingly
+ * >=2 means that Internal bitmaps are supported by setting MD_SB_BITMAP_PRESENT
+ * in the super status byte
+ */
+#define MD_PATCHLEVEL_VERSION 2
extern int register_md_personality (int p_num, mdk_personality_t *p);
extern int unregister_md_personality (int p_num);
extern void md_unregister_thread (mdk_thread_t *thread);
extern void md_wakeup_thread(mdk_thread_t *thread);
extern void md_check_recovery(mddev_t *mddev);
-extern void md_write_start(mddev_t *mddev);
+extern void md_write_start(mddev_t *mddev, struct bio *bi);
extern void md_write_end(mddev_t *mddev);
extern void md_handle_safemode(mddev_t *mddev);
extern void md_done_sync(mddev_t *mddev, int blocks, int ok);
extern void md_print_devices (void);
+extern void md_super_write(mddev_t *mddev, mdk_rdev_t *rdev,
+ sector_t sector, int size, struct page *page);
+extern int sync_page_io(struct block_device *bdev, sector_t sector, int size,
+ struct page *page, int rw);
+
+
#define MD_BUG(x...) { printk("md: bug in file %s, line %d\n", __FILE__, __LINE__); md_print_devices(); }
#endif
#ifndef _MD_K_H
#define _MD_K_H
+/* and dm-bio-list.h is not under include/linux because.... ??? */
+#include "../../../drivers/md/dm-bio-list.h"
+
#define MD_RESERVED 0UL
#define LINEAR 1UL
#define RAID0 2UL
int desc_nr; /* descriptor index in the superblock */
int raid_disk; /* role of device in array */
+ int saved_raid_disk; /* role that device used to have in the
+ * array and could again if we did a partial
+ * resync from the bitmap
+ */
atomic_t nr_pending; /* number of pending requests.
* only maintained for arrays that
atomic_t recovery_active; /* blocks scheduled, but not written */
wait_queue_head_t recovery_wait;
sector_t recovery_cp;
+
+ spinlock_t write_lock;
+ wait_queue_head_t sb_wait; /* for waiting on superblock updates */
+ atomic_t pending_writes; /* number of active superblock writes */
+
unsigned int safemode; /* if set, update "clean" superblock
* when no writes pending.
*/
atomic_t writes_pending;
request_queue_t *queue; /* for plugging ... */
+ struct bitmap *bitmap; /* the bitmap for the device */
+ struct file *bitmap_file; /* the bitmap file */
+ long bitmap_offset; /* offset from superblock of
+ * start of bitmap. May be
+ * negative, but not '0'
+ */
+
struct list_head all_mddevs;
};
int (*hot_add_disk) (mddev_t *mddev, mdk_rdev_t *rdev);
int (*hot_remove_disk) (mddev_t *mddev, int number);
int (*spare_active) (mddev_t *mddev);
- int (*sync_request)(mddev_t *mddev, sector_t sector_nr, int go_faster);
+ sector_t (*sync_request)(mddev_t *mddev, sector_t sector_nr, int *skipped, int go_faster);
int (*resize) (mddev_t *mddev, sector_t sectors);
int (*reshape) (mddev_t *mddev, int raid_disks);
int (*reconfig) (mddev_t *mddev, int layout, int chunk_size);
unsigned long flags;
struct completion *event;
struct task_struct *tsk;
+ unsigned long timeout;
const char *name;
} mdk_thread_t;
#define MD_SB_CLEAN 0
#define MD_SB_ERRORS 1
+#define MD_SB_BITMAP_PRESENT 8 /* bitmap may be present nearby */
typedef struct mdp_superblock_s {
/*
* Constant generic information
/* constant array information - 128 bytes */
__u32 magic; /* MD_SB_MAGIC: 0xa92b4efc - little endian */
__u32 major_version; /* 1 */
- __u32 feature_map; /* 0 for now */
+ __u32 feature_map; /* bit 0 set if 'bitmap_offset' is meaningful */
__u32 pad0; /* always set to 0 when writing */
__u8 set_uuid[16]; /* user-space generated. */
__u32 chunksize; /* in 512byte sectors */
__u32 raid_disks;
- __u8 pad1[128-96]; /* set to 0 when written */
+ __u32 bitmap_offset; /* sectors after start of superblock that bitmap starts
+ * NOTE: signed, so bitmap can be before superblock
+ * only meaningful of feature_map[0] is set.
+ */
+ __u8 pad1[128-100]; /* set to 0 when written */
/* constant this-device information - 64 bytes */
__u64 data_offset; /* sector start of data, often 0 */
#define GET_DISK_INFO _IOR (MD_MAJOR, 0x12, mdu_disk_info_t)
#define PRINT_RAID_DEBUG _IO (MD_MAJOR, 0x13)
#define RAID_AUTORUN _IO (MD_MAJOR, 0x14)
+#define GET_BITMAP_FILE _IOR (MD_MAJOR, 0x15, mdu_bitmap_file_t)
/* configuration */
#define CLEAR_ARRAY _IO (MD_MAJOR, 0x20)
#define HOT_ADD_DISK _IO (MD_MAJOR, 0x28)
#define SET_DISK_FAULTY _IO (MD_MAJOR, 0x29)
#define HOT_GENERATE_ERROR _IO (MD_MAJOR, 0x2a)
+#define SET_BITMAP_FILE _IOW (MD_MAJOR, 0x2b, int)
/* usage */
#define RUN_ARRAY _IOW (MD_MAJOR, 0x30, mdu_param_t)
} mdu_start_info_t;
+typedef struct mdu_bitmap_file_s
+{
+ char pathname[4096];
+} mdu_bitmap_file_t;
+
typedef struct mdu_param_s
{
int personality; /* 1,2,3,4 */
spinlock_t device_lock;
struct list_head retry_list;
+ /* queue pending writes and submit them on unplug */
+ struct bio_list pending_bio_list;
+ /* queue of writes that have been unplugged */
+ struct bio_list flushing_bio_list;
+
/* for use when syncing mirrors: */
spinlock_t resync_lock;
- int nr_pending;
- int barrier;
+ int nr_pending;
+ int barrier;
sector_t next_resync;
+ int fullsync; /* set to 1 if a full sync is needed,
+ * (fresh device added).
+ * Cleared when a sync completes.
+ */
wait_queue_head_t wait_idle;
wait_queue_head_t wait_resume;
int read_disk;
struct list_head retry_list;
+ struct bitmap_update *bitmap_update;
/*
* if the IO is in WRITE direction, then multiple bios are used.
* We choose the number when they are allocated.
*/
struct bio *bios[0];
+ /* DO NOT PUT ANY NEW FIELDS HERE - bios array is contiguously alloced*/
};
/* bits for r1bio.state */
#define R1BIO_Uptodate 0
#define R1BIO_IsSync 1
+#define R1BIO_Degraded 2
#endif
arch_get_unmapped_area_topdown(struct file *filp, unsigned long addr,
unsigned long len, unsigned long pgoff,
unsigned long flags);
-extern void arch_unmap_area(struct vm_area_struct *area);
-extern void arch_unmap_area_topdown(struct vm_area_struct *area);
+extern void arch_unmap_area(struct mm_struct *, unsigned long);
+extern void arch_unmap_area_topdown(struct mm_struct *, unsigned long);
#define set_mm_counter(mm, member, value) (mm)->_##member = (value)
#define get_mm_counter(mm, member) ((mm)->_##member)
unsigned long (*get_unmapped_area) (struct file *filp,
unsigned long addr, unsigned long len,
unsigned long pgoff, unsigned long flags);
- void (*unmap_area) (struct vm_area_struct *area);
- unsigned long mmap_base; /* base of mmap area */
- unsigned long free_area_cache; /* first hole */
+ void (*unmap_area) (struct mm_struct *mm, unsigned long addr);
+ unsigned long mmap_base; /* base of mmap area */
+ unsigned long cached_hole_size; /* if non-zero, the largest hole below free_area_cache */
+ unsigned long free_area_cache; /* first hole of size cached_hole_size or larger */
pgd_t * pgd;
atomic_t mm_users; /* How many users with user space? */
atomic_t mm_count; /* How many references to "struct mm_struct" (users count as 1) */
/*
* These macros fold the SMP functionality into a single CPU system
*/
-
-#if !defined(__smp_processor_id) || !defined(CONFIG_PREEMPT)
-# define smp_processor_id() 0
-#endif
+#define raw_smp_processor_id() 0
#define hard_smp_processor_id() 0
#define smp_call_function(func,info,retry,wait) ({ 0; })
#define on_each_cpu(func,info,retry,wait) ({ func(info); 0; })
#endif /* !SMP */
/*
- * DEBUG_PREEMPT support: check whether smp_processor_id() is being
- * used in a preemption-safe way.
+ * smp_processor_id(): get the current CPU ID.
*
- * An architecture has to enable this debugging code explicitly.
- * It can do so by renaming the smp_processor_id() macro to
- * __smp_processor_id(). This should only be done after some minimal
- * testing, because usually there are a number of false positives
- * that an architecture will trigger.
+ * if DEBUG_PREEMPT is enabled the we check whether it is
+ * used in a preemption-safe way. (smp_processor_id() is safe
+ * if it's used in a preemption-off critical section, or in
+ * a thread that is bound to the current CPU.)
*
- * To fix a false positive (i.e. smp_processor_id() use that the
- * debugging code reports but which use for some reason is legal),
- * change the smp_processor_id() reference to _smp_processor_id(),
- * which is the nondebug variant. NOTE: don't use this to hack around
- * real bugs.
+ * NOTE: raw_smp_processor_id() is for internal use only
+ * (smp_processor_id() is the preferred variant), but in rare
+ * instances it might also be used to turn off false positives
+ * (i.e. smp_processor_id() use that the debugging code reports but
+ * which use for some reason is legal). Don't use this to hack around
+ * the warning message, as your code might not work under PREEMPT.
*/
-#ifdef __smp_processor_id
-# if defined(CONFIG_PREEMPT) && defined(CONFIG_DEBUG_PREEMPT)
- extern unsigned int smp_processor_id(void);
-# else
-# define smp_processor_id() __smp_processor_id()
-# endif
-# define _smp_processor_id() __smp_processor_id()
+#ifdef CONFIG_DEBUG_PREEMPT
+ extern unsigned int debug_smp_processor_id(void);
+# define smp_processor_id() debug_smp_processor_id()
#else
-# define _smp_processor_id() smp_processor_id()
+# define smp_processor_id() raw_smp_processor_id()
#endif
#define get_cpu() ({ preempt_disable(); smp_processor_id(); })
extern void swap_setup(void);
/* linux/mm/vmscan.c */
-extern int try_to_free_pages(struct zone **, unsigned int, unsigned int);
+extern int try_to_free_pages(struct zone **, unsigned int);
+extern int zone_reclaim(struct zone *, unsigned int, unsigned int);
extern int shrink_all_memory(int);
extern int vm_swappiness;
extern struct rt_cache_stat *rt_cache_stat;
#define RT_CACHE_STAT_INC(field) \
- (per_cpu_ptr(rt_cache_stat, _smp_processor_id())->field++)
+ (per_cpu_ptr(rt_cache_stat, raw_smp_processor_id())->field++)
extern struct ip_rt_acct *ip_rt_acct;
#define SNMP_STAT_USRPTR(name) (name[1])
#define SNMP_INC_STATS_BH(mib, field) \
- (per_cpu_ptr(mib[0], _smp_processor_id())->mibs[field]++)
+ (per_cpu_ptr(mib[0], raw_smp_processor_id())->mibs[field]++)
#define SNMP_INC_STATS_OFFSET_BH(mib, field, offset) \
- (per_cpu_ptr(mib[0], _smp_processor_id())->mibs[field + (offset)]++)
+ (per_cpu_ptr(mib[0], raw_smp_processor_id())->mibs[field + (offset)]++)
#define SNMP_INC_STATS_USER(mib, field) \
- (per_cpu_ptr(mib[1], _smp_processor_id())->mibs[field]++)
+ (per_cpu_ptr(mib[1], raw_smp_processor_id())->mibs[field]++)
#define SNMP_INC_STATS(mib, field) \
- (per_cpu_ptr(mib[!in_softirq()], _smp_processor_id())->mibs[field]++)
+ (per_cpu_ptr(mib[!in_softirq()], raw_smp_processor_id())->mibs[field]++)
#define SNMP_DEC_STATS(mib, field) \
- (per_cpu_ptr(mib[!in_softirq()], _smp_processor_id())->mibs[field]--)
+ (per_cpu_ptr(mib[!in_softirq()], raw_smp_processor_id())->mibs[field]--)
#define SNMP_ADD_STATS_BH(mib, field, addend) \
- (per_cpu_ptr(mib[0], _smp_processor_id())->mibs[field] += addend)
+ (per_cpu_ptr(mib[0], raw_smp_processor_id())->mibs[field] += addend)
#define SNMP_ADD_STATS_USER(mib, field, addend) \
- (per_cpu_ptr(mib[1], _smp_processor_id())->mibs[field] += addend)
+ (per_cpu_ptr(mib[1], raw_smp_processor_id())->mibs[field] += addend)
#endif
void (*suspend) (ac97_t *ac97);
void (*resume) (ac97_t *ac97);
#endif
+ void (*update_jacks) (ac97_t *ac97); /* for jack-sharing */
};
struct _snd_ac97_bus_ops {
} ad18xx;
unsigned int dev_flags; /* device specific */
} spec;
+ /* jack-sharing info */
+ unsigned char indep_surround;
+ unsigned char channel_mode;
};
/* conditions */
};
struct ac97_quirk {
- unsigned short vendor; /* PCI vendor id */
- unsigned short device; /* PCI device id */
+ unsigned short subvendor; /* PCI subsystem vendor id */
+ unsigned short subdevice; /* PCI sybsystem device id */
unsigned short mask; /* device id bit mask, 0 = accept all */
unsigned int codec_id; /* codec id (if any), 0 = accept all */
const char *name; /* name shown as info */
SNDRV_HWDEP_IFACE_BLUETOOTH, /* Bluetooth audio */
SNDRV_HWDEP_IFACE_USX2Y_PCM, /* Tascam US122, US224 & US428 rawusb pcm */
SNDRV_HWDEP_IFACE_PCXHR, /* Digigram PCXHR */
+ SNDRV_HWDEP_IFACE_SB_RC, /* SB Extigy/Audigy2NX remote control */
/* Don't forget to change the following: */
- SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_PCXHR
+ SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_SB_RC
};
struct sndrv_hwdep_info {
SNDRV_PCM_HW_PARAM_LAST_INTERVAL = SNDRV_PCM_HW_PARAM_TICK_TIME
};
-#define SNDRV_PCM_HW_PARAMS_RUNTIME (1<<0)
+#define SNDRV_PCM_HW_PARAMS_NORESAMPLE (1<<0) /* avoid rate resampling */
struct sndrv_interval {
unsigned int min, max;
* Timer section - /dev/snd/timer
*/
-#define SNDRV_TIMER_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 2)
+#define SNDRV_TIMER_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 4)
enum sndrv_timer_class {
SNDRV_TIMER_CLASS_NONE = -1,
SNDRV_TIMER_IOCTL_INFO = _IOR('T', 0x11, struct sndrv_timer_info),
SNDRV_TIMER_IOCTL_PARAMS = _IOW('T', 0x12, struct sndrv_timer_params),
SNDRV_TIMER_IOCTL_STATUS = _IOR('T', 0x14, struct sndrv_timer_status),
- SNDRV_TIMER_IOCTL_START = _IO('T', 0x20),
- SNDRV_TIMER_IOCTL_STOP = _IO('T', 0x21),
- SNDRV_TIMER_IOCTL_CONTINUE = _IO('T', 0x22),
- SNDRV_TIMER_IOCTL_PAUSE = _IO('T', 0x23),
+ /* The following four ioctls are changed since 1.0.9 due to confliction */
+ SNDRV_TIMER_IOCTL_START = _IO('T', 0xa0),
+ SNDRV_TIMER_IOCTL_STOP = _IO('T', 0xa1),
+ SNDRV_TIMER_IOCTL_CONTINUE = _IO('T', 0xa2),
+ SNDRV_TIMER_IOCTL_PAUSE = _IO('T', 0xa3),
};
struct sndrv_timer_read {
void snd_ctl_notify(snd_card_t * card, unsigned int mask, snd_ctl_elem_id_t * id);
snd_kcontrol_t *snd_ctl_new(snd_kcontrol_t * kcontrol, unsigned int access);
-snd_kcontrol_t *snd_ctl_new1(snd_kcontrol_new_t * kcontrolnew, void * private_data);
+snd_kcontrol_t *snd_ctl_new1(const snd_kcontrol_new_t * kcontrolnew, void * private_data);
void snd_ctl_free_one(snd_kcontrol_t * kcontrol);
int snd_ctl_add(snd_card_t * card, snd_kcontrol_t * kcontrol);
int snd_ctl_remove(snd_card_t * card, snd_kcontrol_t * kcontrol);
#define IPR 0x08 /* Global interrupt pending register */
/* Clear pending interrupts by writing a 1 to */
/* the relevant bits and zero to the other bits */
-
+#define IPR_P16V 0x80000000 /* Bit set when the CA0151 P16V chip wishes
+ to interrupt */
#define IPR_GPIOMSG 0x20000000 /* GPIO message interrupt (RE'd, still not sure
which INTE bits enable it) */
/* Assumes sample lock */
/* These three bitfields apply to CDSRCS, GPSRCS, and (except as noted) ZVSRCS. */
+#define SRCS_SPDIFVALID 0x04000000 /* SPDIF stream valid */
#define SRCS_SPDIFLOCKED 0x02000000 /* SPDIF stream locked */
#define SRCS_RATELOCKED 0x01000000 /* Sample rate locked */
#define SRCS_ESTSAMPLERATE 0x0007ffff /* Do not modify this field. */
#define A_FXWC2 0x75 /* Selects 0x9f-0x80 for FX recording */
#define A_SPDIF_SAMPLERATE 0x76 /* Set the sample rate of SPDIF output */
-#define A_SPDIF_RATE_MASK 0x000000c0
+#define A_SAMPLE_RATE 0x76 /* Various sample rate settings. */
+#define A_SAMPLE_RATE_NOT_USED 0x0ffc111e /* Bits that are not used and cannot be set. */
+#define A_SAMPLE_RATE_UNKNOWN 0xf0030001 /* Bits that can be set, but have unknown use. */
+#define A_SPDIF_RATE_MASK 0x000000e0 /* Any other values for rates, just use 48000 */
#define A_SPDIF_48000 0x00000000
-#define A_SPDIF_44100 0x00000080
+#define A_SPDIF_192000 0x00000020
#define A_SPDIF_96000 0x00000040
+#define A_SPDIF_44100 0x00000080
+
+#define A_I2S_CAPTURE_RATE_MASK 0x00000e00 /* This sets the capture PCM rate, but it is */
+#define A_I2S_CAPTURE_48000 0x00000000 /* unclear if this sets the ADC rate as well. */
+#define A_I2S_CAPTURE_192000 0x00000200
+#define A_I2S_CAPTURE_96000 0x00000400
+#define A_I2S_CAPTURE_44100 0x00000800
+
+#define A_PCM_RATE_MASK 0x0000e000 /* This sets the playback PCM rate on the P16V */
+#define A_PCM_48000 0x00000000
+#define A_PCM_192000 0x00002000
+#define A_PCM_96000 0x00004000
+#define A_PCM_44100 0x00008000
/* 0x77,0x78,0x79 "something i2s-related" - default to 0x01080000 on my audigy 2 ZS --rlrevell */
/* 0x7a, 0x7b - lookup tables */
u32 vendor;
u32 device;
u32 subsystem;
+ unsigned char revision;
unsigned char emu10k1_chip; /* Original SB Live. Not SB Live 24bit. */
unsigned char emu10k2_chip; /* Audigy 1 or Audigy 2. */
unsigned char ca0102_chip; /* Audigy 1 or Audigy 2. Not SB Audigy 2 Value. */
unsigned char ca0108_chip; /* Audigy 2 Value */
unsigned char ca0151_chip; /* P16V */
unsigned char spk71; /* Has 7.1 speakers */
+ unsigned char sblive51; /* SBLive! 5.1 - extout 0x11 -> center, 0x12 -> lfe */
unsigned char spdif_bug; /* Has Spdif phasing bug */
unsigned char ac97_chip; /* Has an AC97 chip */
unsigned char ecard; /* APS EEPROM */
- char * driver;
- char * name;
+ const char *driver;
+ const char *name;
+ const char *id; /* for backward compatibility - can be NULL if not needed */
} emu_chip_details_t;
struct _snd_emu10k1 {
int irq;
unsigned long port; /* I/O port number */
- unsigned int APS: 1, /* APS flag */
- no_ac97: 1, /* no AC'97 */
- tos_link: 1, /* tos link detected */
- rear_ac97: 1, /* rear channels are on AC'97 */
- spk71:1; /* 7.1 configuration (Audigy 2 ZS) */
+ unsigned int tos_link: 1, /* tos link detected */
+ rear_ac97: 1; /* rear channels are on AC'97 */
const emu_chip_details_t *card_capabilities; /* Contains profile of card capabilities */
unsigned int audigy; /* is Audigy? */
unsigned int revision; /* chip revision */
emu10k1_voice_t voices[NUM_G];
emu10k1_voice_t p16v_voices[4];
+ emu10k1_voice_t p16v_capture_voice;
int p16v_device_offset;
+ u32 p16v_capture_source;
+ u32 p16v_capture_channel;
emu10k1_pcm_mixer_t pcm_mixer[32];
emu10k1_pcm_mixer_t efx_pcm_mixer[NUM_EFX_PLAYBACK];
snd_kcontrol_t *ctl_send_routing;
#endif
typedef struct {
- unsigned int card; /* card type */
unsigned int internal_tram_size; /* in samples */
unsigned int external_tram_size; /* in samples */
char fxbus_names[16][32]; /* names of FXBUSes */
extern void snd_gf1_dram_addr(snd_gus_card_t * gus, unsigned int addr);
extern void snd_gf1_poke(snd_gus_card_t * gus, unsigned int addr, unsigned char data);
extern unsigned char snd_gf1_peek(snd_gus_card_t * gus, unsigned int addr);
-extern void snd_gf1_pokew(snd_gus_card_t * gus, unsigned int addr, unsigned short data);
-extern unsigned short snd_gf1_peekw(snd_gus_card_t * gus, unsigned int addr);
-extern void snd_gf1_dram_setmem(snd_gus_card_t * gus, unsigned int addr, unsigned short value, unsigned int count);
extern void snd_gf1_write_addr(snd_gus_card_t * gus, unsigned char reg, unsigned int addr, short w_16bit);
extern unsigned int snd_gf1_read_addr(snd_gus_card_t * gus, unsigned char reg, short w_16bit);
extern void snd_gf1_i_ctrl_stop(snd_gus_card_t * gus, unsigned char reg);
{
return snd_gf1_i_look16(gus, reg | 0x80);
}
-extern void snd_gf1_i_adlib_write(snd_gus_card_t * gus, unsigned char reg, unsigned char data);
-extern void snd_gf1_i_write_addr(snd_gus_card_t * gus, unsigned char reg, unsigned int addr, short w_16bit);
-extern unsigned int snd_gf1_i_read_addr(snd_gus_card_t * gus, unsigned char reg, short w_16bit);
extern void snd_gf1_select_active_voices(snd_gus_card_t * gus);
void snd_gf1_mem_lock(snd_gf1_mem_t * alloc, int xup);
int snd_gf1_mem_xfree(snd_gf1_mem_t * alloc, snd_gf1_mem_block_t * block);
-snd_gf1_mem_block_t *snd_gf1_mem_look(snd_gf1_mem_t * alloc,
- unsigned int address);
-snd_gf1_mem_block_t *snd_gf1_mem_share(snd_gf1_mem_t * alloc,
- unsigned int *share_id);
snd_gf1_mem_block_t *snd_gf1_mem_alloc(snd_gf1_mem_t * alloc, int owner,
char *name, int size, int w_16,
int align, unsigned int *share_id);
/* gus_volume.c */
unsigned short snd_gf1_lvol_to_gvol_raw(unsigned int vol);
-unsigned int snd_gf1_gvol_to_lvol_raw(unsigned short gf1_vol);
-unsigned int snd_gf1_calc_ramp_rate(snd_gus_card_t * gus,
- unsigned short start,
- unsigned short end,
- unsigned int us);
unsigned short snd_gf1_translate_freq(snd_gus_card_t * gus, unsigned int freq2);
-unsigned short snd_gf1_compute_pitchbend(unsigned short pitchbend, unsigned short sens);
-unsigned short snd_gf1_compute_freq(unsigned int freq,
- unsigned int rate,
- unsigned short mix_rate);
/* gus_reset.c */
void snd_gf1_set_default_handlers(snd_gus_card_t * gus, unsigned int what);
void snd_gf1_smart_stop_voice(snd_gus_card_t * gus, unsigned short voice);
void snd_gf1_stop_voice(snd_gus_card_t * gus, unsigned short voice);
-void snd_gf1_clear_voices(snd_gus_card_t * gus, unsigned short v_min, unsigned short v_max);
void snd_gf1_stop_voices(snd_gus_card_t * gus, unsigned short v_min, unsigned short v_max);
snd_gus_voice_t *snd_gf1_alloc_voice(snd_gus_card_t * gus, int type, int client, int port);
void snd_gf1_free_voice(snd_gus_card_t * gus, snd_gus_voice_t *voice);
#ifdef CONFIG_SND_DEBUG
extern void snd_gf1_print_voice_registers(snd_gus_card_t * gus);
-extern void snd_gf1_print_global_registers(snd_gus_card_t * gus);
-extern void snd_gf1_print_setup_registers(snd_gus_card_t * gus);
-extern void snd_gf1_peek_print_block(snd_gus_card_t * gus, unsigned int addr, int count, int w_16bit);
#endif
/* gus.c */
--- /dev/null
+#ifndef __SOUND_HDSPM_H /* -*- linux-c -*- */
+#define __SOUND_HDSPM_H
+/*
+ * Copyright (C) 2003 Winfried Ritsch (IEM)
+ * based on hdsp.h from Thomas Charbonnel (thomas@undata.org)
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Maximum channels is 64 even on 56Mode you have 64playbacks to matrix */
+#define HDSPM_MAX_CHANNELS 64
+
+/* -------------------- IOCTL Peak/RMS Meters -------------------- */
+
+typedef struct _snd_hdspm_peak_rms hdspm_peak_rms_t;
+
+/* peam rms level structure like we get from hardware
+
+ maybe in future we can memory map it so I just copy it
+ to user on ioctl call now an dont change anything
+ rms are made out of low and high values
+ where (long) ????_rms = (????_rms_l >> 8) + ((????_rms_h & 0xFFFFFF00)<<24)
+ (i asume so from the code)
+*/
+
+struct _snd_hdspm_peak_rms {
+
+ unsigned int level_offset[1024];
+
+ unsigned int input_peak[64];
+ unsigned int playback_peak[64];
+ unsigned int output_peak[64];
+ unsigned int xxx_peak[64]; /* not used */
+
+ unsigned int reserved[256]; /* not used */
+
+ unsigned int input_rms_l[64];
+ unsigned int playback_rms_l[64];
+ unsigned int output_rms_l[64];
+ unsigned int xxx_rms_l[64]; /* not used */
+
+ unsigned int input_rms_h[64];
+ unsigned int playback_rms_h[64];
+ unsigned int output_rms_h[64];
+ unsigned int xxx_rms_h[64]; /* not used */
+};
+
+struct sndrv_hdspm_peak_rms_ioctl {
+ hdspm_peak_rms_t *peak;
+};
+
+/* use indirect access due to the limit of ioctl bit size */
+#define SNDRV_HDSPM_IOCTL_GET_PEAK_RMS _IOR('H', 0x40, struct sndrv_hdspm_peak_rms_ioctl)
+
+/* ------------ CONFIG block IOCTL ---------------------- */
+
+typedef struct _snd_hdspm_config_info hdspm_config_info_t;
+
+struct _snd_hdspm_config_info {
+ unsigned char pref_sync_ref;
+ unsigned char wordclock_sync_check;
+ unsigned char madi_sync_check;
+ unsigned int system_sample_rate;
+ unsigned int autosync_sample_rate;
+ unsigned char system_clock_mode;
+ unsigned char clock_source;
+ unsigned char autosync_ref;
+ unsigned char line_out;
+ unsigned int passthru;
+ unsigned int analog_out;
+};
+
+#define SNDRV_HDSPM_IOCTL_GET_CONFIG_INFO _IOR('H', 0x41, hdspm_config_info_t)
+
+
+/* get Soundcard Version */
+
+typedef struct _snd_hdspm_version hdspm_version_t;
+
+struct _snd_hdspm_version {
+ unsigned short firmware_rev;
+};
+
+#define SNDRV_HDSPM_IOCTL_GET_VERSION _IOR('H', 0x43, hdspm_version_t)
+
+
+/* ------------- get Matrix Mixer IOCTL --------------- */
+
+/* MADI mixer: 64inputs+64playback in 64outputs = 8192 => *4Byte = 32768 Bytes */
+
+/* organisation is 64 channelfader in a continous memory block */
+/* equivalent to hardware definition, maybe for future feature of mmap of them */
+/* each of 64 outputs has 64 infader and 64 outfader:
+ Ins to Outs mixer[out].in[in], Outstreams to Outs mixer[out].pb[pb] */
+
+#define HDSPM_MIXER_CHANNELS HDSPM_MAX_CHANNELS
+
+typedef struct _snd_hdspm_channelfader snd_hdspm_channelfader_t;
+
+struct _snd_hdspm_channelfader {
+ unsigned int in[HDSPM_MIXER_CHANNELS];
+ unsigned int pb[HDSPM_MIXER_CHANNELS];
+};
+
+typedef struct _snd_hdspm_mixer hdspm_mixer_t;
+
+struct _snd_hdspm_mixer {
+ snd_hdspm_channelfader_t ch[HDSPM_MIXER_CHANNELS];
+};
+
+struct sndrv_hdspm_mixer_ioctl {
+ hdspm_mixer_t *mixer;
+};
+
+/* use indirect access due to the limit of ioctl bit size */
+#define SNDRV_HDSPM_IOCTL_GET_MIXER _IOR('H', 0x44, struct sndrv_hdspm_mixer_ioctl)
+
+#endif /* __SOUND_HDSPM_H */
void _snd_pcm_hw_params_any(snd_pcm_hw_params_t *params);
void _snd_pcm_hw_param_setempty(snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var);
-int snd_pcm_hw_param_min(snd_pcm_substream_t *substream,
- snd_pcm_hw_params_t *params,
- snd_pcm_hw_param_t var,
- unsigned int val, int *dir);
-int snd_pcm_hw_param_max(snd_pcm_substream_t *substream,
- snd_pcm_hw_params_t *params,
- snd_pcm_hw_param_t var,
- unsigned int val, int *dir);
-int snd_pcm_hw_param_setinteger(snd_pcm_substream_t *substream,
- snd_pcm_hw_params_t *params,
- snd_pcm_hw_param_t var);
-int snd_pcm_hw_param_first(snd_pcm_substream_t *substream,
- snd_pcm_hw_params_t *params,
- snd_pcm_hw_param_t var, int *dir);
-int snd_pcm_hw_param_last(snd_pcm_substream_t *substream,
- snd_pcm_hw_params_t *params,
- snd_pcm_hw_param_t var, int *dir);
int snd_pcm_hw_param_near(snd_pcm_substream_t *substream,
snd_pcm_hw_params_t *params,
snd_pcm_hw_param_t var,
int snd_pcm_hw_params_choose(snd_pcm_substream_t *substream, snd_pcm_hw_params_t *params);
int snd_pcm_hw_refine(snd_pcm_substream_t *substream, snd_pcm_hw_params_t *params);
-int snd_pcm_hw_params(snd_pcm_substream_t *substream, snd_pcm_hw_params_t *params);
int snd_pcm_hw_constraints_init(snd_pcm_substream_t *substream);
int snd_pcm_hw_constraints_complete(snd_pcm_substream_t *substream);
int snd_pcm_format_linear(snd_pcm_format_t format);
int snd_pcm_format_little_endian(snd_pcm_format_t format);
int snd_pcm_format_big_endian(snd_pcm_format_t format);
+/**
+ * snd_pcm_format_cpu_endian - Check the PCM format is CPU-endian
+ * @format: the format to check
+ *
+ * Returns 1 if the given PCM format is CPU-endian, 0 if
+ * opposite, or a negative error code if endian not specified.
+ */
+/* int snd_pcm_format_cpu_endian(snd_pcm_format_t format); */
+#ifdef SNDRV_LITTLE_ENDIAN
+#define snd_pcm_format_cpu_endian snd_pcm_format_little_endian
+#else
+#define snd_pcm_format_cpu_endian snd_pcm_format_big_endian
+#endif
int snd_pcm_format_width(snd_pcm_format_t format); /* in bits */
int snd_pcm_format_physical_width(snd_pcm_format_t format); /* in bits */
+ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples);
const unsigned char *snd_pcm_format_silence_64(snd_pcm_format_t format);
int snd_pcm_format_set_silence(snd_pcm_format_t format, void *buf, unsigned int frames);
snd_pcm_format_t snd_pcm_build_linear_format(int width, int unsignd, int big_endian);
};
int snd_midi_event_new(int bufsize, snd_midi_event_t **rdev);
-int snd_midi_event_resize_buffer(snd_midi_event_t *dev, int bufsize);
void snd_midi_event_free(snd_midi_event_t *dev);
-void snd_midi_event_init(snd_midi_event_t *dev);
void snd_midi_event_reset_encode(snd_midi_event_t *dev);
void snd_midi_event_reset_decode(snd_midi_event_t *dev);
void snd_midi_event_no_status(snd_midi_event_t *dev, int on);
#define SNDRV_VIRMIDI_SEQ_DISPATCH 2
int snd_virmidi_new(snd_card_t *card, int device, snd_rawmidi_t **rrmidi);
-int snd_virmidi_receive(snd_rawmidi_t *rmidi, snd_seq_event_t *ev);
#endif /* __SOUND_SEQ_VIRMIDI */
extern void snd_timer_interrupt(snd_timer_t * timer, unsigned long ticks_left);
-extern unsigned int snd_timer_system_resolution(void);
-
#endif /* __SOUND_TIMER_H */
/* include/version.h. Generated by configure. */
-#define CONFIG_SND_VERSION "1.0.9rc2"
-#define CONFIG_SND_DATE " (Thu Mar 24 10:33:39 2005 UTC)"
+#define CONFIG_SND_VERSION "1.0.9"
+#define CONFIG_SND_DATE " (Sun May 29 07:31:02 2005 UTC)"
vfs_caches_init_early();
mem_init();
kmem_cache_init();
+ setup_per_cpu_pageset();
numa_policy_init();
if (late_time_init)
late_time_init();
mm->mmap = NULL;
mm->mmap_cache = NULL;
mm->free_area_cache = oldmm->mmap_base;
+ mm->cached_hole_size = ~0UL;
mm->map_count = 0;
set_mm_counter(mm, rss, 0);
set_mm_counter(mm, anon_rss, 0);
/*
* Link in the new vma and copy the page table entries:
- * link in first so that swapoff can see swap entries,
- * and try_to_unmap_one's find_vma find the new vma.
+ * link in first so that swapoff can see swap entries.
+ * Note that, exceptionally, here the vma is inserted
+ * without holding mm->mmap_sem.
*/
spin_lock(&mm->page_table_lock);
*pprev = tmp;
mm->ioctx_list = NULL;
mm->default_kioctx = (struct kioctx)INIT_KIOCTX(mm->default_kioctx, *mm);
mm->free_area_cache = TASK_UNMAPPED_BASE;
+ mm->cached_hole_size = ~0UL;
if (likely(!mm_alloc_pgd(mm))) {
mm->def_flags = 0;
* This file contains driver APIs to the irq subsystem.
*/
+#include <linux/config.h>
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/random.h>
/* Found it - now remove it from the list of entries */
*pp = action->next;
+
+ /* Currently used only by UML, might disappear one day.*/
+#ifdef CONFIG_IRQ_RELEASE_METHOD
+ if (desc->handler->release)
+ desc->handler->release(irq, dev_id);
+#endif
+
if (!desc->action) {
desc->status |= IRQ_DISABLED;
if (desc->handler->shutdown)
for (i = 0; i < NR_CPUS; i++)
local_set(&mod->ref[i].count, 0);
/* Hold reference count during initialization. */
- local_set(&mod->ref[_smp_processor_id()].count, 1);
+ local_set(&mod->ref[raw_smp_processor_id()].count, 1);
/* Backwards compatibility macros put refcount during init. */
mod->waiter = current;
}
{
oldmask = current->cpus_allowed;
set_cpus_allowed(current, cpumask_of_cpu(0));
- printk("Freezing CPUs (at %d)", _smp_processor_id());
+ printk("Freezing CPUs (at %d)", raw_smp_processor_id());
current->state = TASK_INTERRUPTIBLE;
schedule_timeout(HZ);
printk("...");
- BUG_ON(_smp_processor_id() != 0);
+ BUG_ON(raw_smp_processor_id() != 0);
/* FIXME: for this to work, all the CPUs must be running
* "idle" thread (or we deadlock). Is that guaranteed? */
*/
void __sched io_schedule(void)
{
- struct runqueue *rq = &per_cpu(runqueues, _smp_processor_id());
+ struct runqueue *rq = &per_cpu(runqueues, raw_smp_processor_id());
atomic_inc(&rq->nr_iowait);
schedule();
long __sched io_schedule_timeout(long timeout)
{
- struct runqueue *rq = &per_cpu(runqueues, _smp_processor_id());
+ struct runqueue *rq = &per_cpu(runqueues, raw_smp_processor_id());
long ret;
atomic_inc(&rq->nr_iowait);
stopmachine_state = STOPMACHINE_WAIT;
for_each_online_cpu(i) {
- if (i == _smp_processor_id())
+ if (i == raw_smp_processor_id())
continue;
ret = kernel_thread(stopmachine, (void *)(long)i,CLONE_KERNEL);
if (ret < 0)
/* If they don't care which CPU fn runs on, bind to any online one. */
if (cpu == NR_CPUS)
- cpu = _smp_processor_id();
+ cpu = raw_smp_processor_id();
p = kthread_create(do_stop, &smdata, "kstopmachine");
if (!IS_ERR(p)) {
cond_syscall(sys_keyctl);
cond_syscall(compat_sys_keyctl);
cond_syscall(compat_sys_socketcall);
+cond_syscall(sys_set_zone_reclaim);
/* arch-specific weak syscall entries */
cond_syscall(sys_pciconfig_read);
config ZLIB_DEFLATE
tristate
+#
+# Generic allocator support is selected if needed
+#
+config GENERIC_ALLOCATOR
+ boolean
+
#
# reed solomon support is select'ed if needed
#
lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
lib-$(CONFIG_GENERIC_FIND_NEXT_BIT) += find_next_bit.o
obj-$(CONFIG_LOCK_KERNEL) += kernel_lock.o
+obj-$(CONFIG_DEBUG_PREEMPT) += smp_processor_id.o
ifneq ($(CONFIG_HAVE_DEC_LOCK),y)
lib-y += dec_and_lock.o
obj-$(CONFIG_CRC32) += crc32.o
obj-$(CONFIG_LIBCRC32C) += libcrc32c.o
obj-$(CONFIG_GENERIC_IOMAP) += iomap.o
+obj-$(CONFIG_GENERIC_ALLOCATOR) += genalloc.o
obj-$(CONFIG_ZLIB_INFLATE) += zlib_inflate/
obj-$(CONFIG_ZLIB_DEFLATE) += zlib_deflate/
--- /dev/null
+/*
+ * Basic general purpose allocator for managing special purpose memory
+ * not managed by the regular kmalloc/kfree interface.
+ * Uses for this includes on-device special memory, uncached memory
+ * etc.
+ *
+ * This code is based on the buddy allocator found in the sym53c8xx_2
+ * driver Copyright (C) 1999-2001 Gerard Roudier <groudier@free.fr>,
+ * and adapted for general purpose use.
+ *
+ * Copyright 2005 (C) Jes Sorensen <jes@trained-monkey.org>
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/spinlock.h>
+#include <linux/genalloc.h>
+
+#include <asm/page.h>
+
+
+struct gen_pool *gen_pool_create(int nr_chunks, int max_chunk_shift,
+ unsigned long (*fp)(struct gen_pool *),
+ unsigned long data)
+{
+ struct gen_pool *poolp;
+ unsigned long tmp;
+ int i;
+
+ /*
+ * This is really an arbitrary limit, +10 is enough for
+ * IA64_GRANULE_SHIFT, aka 16MB. If anyone needs a large limit
+ * this can be increased without problems.
+ */
+ if ((max_chunk_shift > (PAGE_SHIFT + 10)) ||
+ ((max_chunk_shift < ALLOC_MIN_SHIFT) && max_chunk_shift))
+ return NULL;
+
+ if (!max_chunk_shift)
+ max_chunk_shift = PAGE_SHIFT;
+
+ poolp = kmalloc(sizeof(struct gen_pool), GFP_KERNEL);
+ if (!poolp)
+ return NULL;
+ memset(poolp, 0, sizeof(struct gen_pool));
+ poolp->h = kmalloc(sizeof(struct gen_pool_link) *
+ (max_chunk_shift - ALLOC_MIN_SHIFT + 1),
+ GFP_KERNEL);
+ if (!poolp->h) {
+ printk(KERN_WARNING "gen_pool_alloc() failed to allocate\n");
+ kfree(poolp);
+ return NULL;
+ }
+ memset(poolp->h, 0, sizeof(struct gen_pool_link) *
+ (max_chunk_shift - ALLOC_MIN_SHIFT + 1));
+
+ spin_lock_init(&poolp->lock);
+ poolp->get_new_chunk = fp;
+ poolp->max_chunk_shift = max_chunk_shift;
+ poolp->private = data;
+
+ for (i = 0; i < nr_chunks; i++) {
+ tmp = poolp->get_new_chunk(poolp);
+ printk(KERN_INFO "allocated %lx\n", tmp);
+ if (!tmp)
+ break;
+ gen_pool_free(poolp, tmp, (1 << poolp->max_chunk_shift));
+ }
+
+ return poolp;
+}
+EXPORT_SYMBOL(gen_pool_create);
+
+
+/*
+ * Simple power of two buddy-like generic allocator.
+ * Provides naturally aligned memory chunks.
+ */
+unsigned long gen_pool_alloc(struct gen_pool *poolp, int size)
+{
+ int j, i, s, max_chunk_size;
+ unsigned long a, flags;
+ struct gen_pool_link *h = poolp->h;
+
+ max_chunk_size = 1 << poolp->max_chunk_shift;
+
+ if (size > max_chunk_size)
+ return 0;
+
+ i = 0;
+
+ size = max(size, 1 << ALLOC_MIN_SHIFT);
+ s = roundup_pow_of_two(size);
+
+ j = i;
+
+ spin_lock_irqsave(&poolp->lock, flags);
+ while (!h[j].next) {
+ if (s == max_chunk_size) {
+ struct gen_pool_link *ptr;
+ spin_unlock_irqrestore(&poolp->lock, flags);
+ ptr = (struct gen_pool_link *)poolp->get_new_chunk(poolp);
+ spin_lock_irqsave(&poolp->lock, flags);
+ h[j].next = ptr;
+ if (h[j].next)
+ h[j].next->next = NULL;
+ break;
+ }
+ j++;
+ s <<= 1;
+ }
+ a = (unsigned long) h[j].next;
+ if (a) {
+ h[j].next = h[j].next->next;
+ /*
+ * This should be split into a seperate function doing
+ * the chunk split in order to support custom
+ * handling memory not physically accessible by host
+ */
+ while (j > i) {
+ j -= 1;
+ s >>= 1;
+ h[j].next = (struct gen_pool_link *) (a + s);
+ h[j].next->next = NULL;
+ }
+ }
+ spin_unlock_irqrestore(&poolp->lock, flags);
+ return a;
+}
+EXPORT_SYMBOL(gen_pool_alloc);
+
+
+/*
+ * Counter-part of the generic allocator.
+ */
+void gen_pool_free(struct gen_pool *poolp, unsigned long ptr, int size)
+{
+ struct gen_pool_link *q;
+ struct gen_pool_link *h = poolp->h;
+ unsigned long a, b, flags;
+ int i, s, max_chunk_size;
+
+ max_chunk_size = 1 << poolp->max_chunk_shift;
+
+ if (size > max_chunk_size)
+ return;
+
+ i = 0;
+
+ size = max(size, 1 << ALLOC_MIN_SHIFT);
+ s = roundup_pow_of_two(size);
+
+ a = ptr;
+
+ spin_lock_irqsave(&poolp->lock, flags);
+ while (1) {
+ if (s == max_chunk_size) {
+ ((struct gen_pool_link *)a)->next = h[i].next;
+ h[i].next = (struct gen_pool_link *)a;
+ break;
+ }
+ b = a ^ s;
+ q = &h[i];
+
+ while (q->next && q->next != (struct gen_pool_link *)b)
+ q = q->next;
+
+ if (!q->next) {
+ ((struct gen_pool_link *)a)->next = h[i].next;
+ h[i].next = (struct gen_pool_link *)a;
+ break;
+ }
+ q->next = q->next->next;
+ a = a & b;
+ s <<= 1;
+ i++;
+ }
+ spin_unlock_irqrestore(&poolp->lock, flags);
+}
+EXPORT_SYMBOL(gen_pool_free);
* Add a new layer to the top of the tree if the requested
* id is larger than the currently allocated space.
*/
- while ((layers < MAX_LEVEL) && (id >= (1 << (layers*IDR_BITS)))) {
+ while ((layers < (MAX_LEVEL - 1)) && (id >= (1 << (layers*IDR_BITS)))) {
layers++;
if (!p->count)
continue;
#include <linux/module.h>
#include <linux/kallsyms.h>
-#if defined(CONFIG_PREEMPT) && defined(__smp_processor_id) && \
- defined(CONFIG_DEBUG_PREEMPT)
-
-/*
- * Debugging check.
- */
-unsigned int smp_processor_id(void)
-{
- unsigned long preempt_count = preempt_count();
- int this_cpu = __smp_processor_id();
- cpumask_t this_mask;
-
- if (likely(preempt_count))
- goto out;
-
- if (irqs_disabled())
- goto out;
-
- /*
- * Kernel threads bound to a single CPU can safely use
- * smp_processor_id():
- */
- this_mask = cpumask_of_cpu(this_cpu);
-
- if (cpus_equal(current->cpus_allowed, this_mask))
- goto out;
-
- /*
- * It is valid to assume CPU-locality during early bootup:
- */
- if (system_state != SYSTEM_RUNNING)
- goto out;
-
- /*
- * Avoid recursion:
- */
- preempt_disable();
-
- if (!printk_ratelimit())
- goto out_enable;
-
- printk(KERN_ERR "BUG: using smp_processor_id() in preemptible [%08x] code: %s/%d\n", preempt_count(), current->comm, current->pid);
- print_symbol("caller is %s\n", (long)__builtin_return_address(0));
- dump_stack();
-
-out_enable:
- preempt_enable_no_resched();
-out:
- return this_cpu;
-}
-
-EXPORT_SYMBOL(smp_processor_id);
-
-#endif /* PREEMPT && __smp_processor_id && DEBUG_PREEMPT */
-
#ifdef CONFIG_PREEMPT_BKL
/*
* The 'big kernel semaphore'
--- /dev/null
+/*
+ * lib/smp_processor_id.c
+ *
+ * DEBUG_PREEMPT variant of smp_processor_id().
+ */
+#include <linux/module.h>
+#include <linux/kallsyms.h>
+
+unsigned int debug_smp_processor_id(void)
+{
+ unsigned long preempt_count = preempt_count();
+ int this_cpu = raw_smp_processor_id();
+ cpumask_t this_mask;
+
+ if (likely(preempt_count))
+ goto out;
+
+ if (irqs_disabled())
+ goto out;
+
+ /*
+ * Kernel threads bound to a single CPU can safely use
+ * smp_processor_id():
+ */
+ this_mask = cpumask_of_cpu(this_cpu);
+
+ if (cpus_equal(current->cpus_allowed, this_mask))
+ goto out;
+
+ /*
+ * It is valid to assume CPU-locality during early bootup:
+ */
+ if (system_state != SYSTEM_RUNNING)
+ goto out;
+
+ /*
+ * Avoid recursion:
+ */
+ preempt_disable();
+
+ if (!printk_ratelimit())
+ goto out_enable;
+
+ printk(KERN_ERR "BUG: using smp_processor_id() in preemptible [%08x] code: %s/%d\n", preempt_count(), current->comm, current->pid);
+ print_symbol("caller is %s\n", (long)__builtin_return_address(0));
+ dump_stack();
+
+out_enable:
+ preempt_enable_no_resched();
+out:
+ return this_cpu;
+}
+
+EXPORT_SYMBOL(debug_smp_processor_id);
+
#include <linux/init.h>
#include <linux/module.h>
#include <linux/mm.h>
-#include <linux/hugetlb.h>
#include <linux/sysctl.h>
#include <linux/highmem.h>
#include <linux/nodemask.h>
+#include <linux/pagemap.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+#include <linux/hugetlb.h>
const unsigned long hugetlb_zero = 0, hugetlb_infinity = ~0UL;
static unsigned long nr_huge_pages, free_huge_pages;
.nopage = hugetlb_nopage,
};
+static pte_t make_huge_pte(struct vm_area_struct *vma, struct page *page)
+{
+ pte_t entry;
+
+ if (vma->vm_flags & VM_WRITE) {
+ entry =
+ pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
+ } else {
+ entry = pte_wrprotect(mk_pte(page, vma->vm_page_prot));
+ }
+ entry = pte_mkyoung(entry);
+ entry = pte_mkhuge(entry);
+
+ return entry;
+}
+
+int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
+ struct vm_area_struct *vma)
+{
+ pte_t *src_pte, *dst_pte, entry;
+ struct page *ptepage;
+ unsigned long addr = vma->vm_start;
+ unsigned long end = vma->vm_end;
+
+ while (addr < end) {
+ dst_pte = huge_pte_alloc(dst, addr);
+ if (!dst_pte)
+ goto nomem;
+ src_pte = huge_pte_offset(src, addr);
+ BUG_ON(!src_pte || pte_none(*src_pte)); /* prefaulted */
+ entry = *src_pte;
+ ptepage = pte_page(entry);
+ get_page(ptepage);
+ add_mm_counter(dst, rss, HPAGE_SIZE / PAGE_SIZE);
+ set_huge_pte_at(dst, addr, dst_pte, entry);
+ addr += HPAGE_SIZE;
+ }
+ return 0;
+
+nomem:
+ return -ENOMEM;
+}
+
+void unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start,
+ unsigned long end)
+{
+ struct mm_struct *mm = vma->vm_mm;
+ unsigned long address;
+ pte_t pte;
+ struct page *page;
+
+ WARN_ON(!is_vm_hugetlb_page(vma));
+ BUG_ON(start & ~HPAGE_MASK);
+ BUG_ON(end & ~HPAGE_MASK);
+
+ for (address = start; address < end; address += HPAGE_SIZE) {
+ pte = huge_ptep_get_and_clear(mm, address, huge_pte_offset(mm, address));
+ if (pte_none(pte))
+ continue;
+ page = pte_page(pte);
+ put_page(page);
+ }
+ add_mm_counter(mm, rss, -((end - start) >> PAGE_SHIFT));
+ flush_tlb_range(vma, start, end);
+}
+
void zap_hugepage_range(struct vm_area_struct *vma,
unsigned long start, unsigned long length)
{
unmap_hugepage_range(vma, start, start + length);
spin_unlock(&mm->page_table_lock);
}
+
+int hugetlb_prefault(struct address_space *mapping, struct vm_area_struct *vma)
+{
+ struct mm_struct *mm = current->mm;
+ unsigned long addr;
+ int ret = 0;
+
+ WARN_ON(!is_vm_hugetlb_page(vma));
+ BUG_ON(vma->vm_start & ~HPAGE_MASK);
+ BUG_ON(vma->vm_end & ~HPAGE_MASK);
+
+ hugetlb_prefault_arch_hook(mm);
+
+ spin_lock(&mm->page_table_lock);
+ for (addr = vma->vm_start; addr < vma->vm_end; addr += HPAGE_SIZE) {
+ unsigned long idx;
+ pte_t *pte = huge_pte_alloc(mm, addr);
+ struct page *page;
+
+ if (!pte) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ if (! pte_none(*pte))
+ hugetlb_clean_stale_pgtable(pte);
+
+ idx = ((addr - vma->vm_start) >> HPAGE_SHIFT)
+ + (vma->vm_pgoff >> (HPAGE_SHIFT - PAGE_SHIFT));
+ page = find_get_page(mapping, idx);
+ if (!page) {
+ /* charge the fs quota first */
+ if (hugetlb_get_quota(mapping)) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ page = alloc_huge_page();
+ if (!page) {
+ hugetlb_put_quota(mapping);
+ ret = -ENOMEM;
+ goto out;
+ }
+ ret = add_to_page_cache(page, mapping, idx, GFP_ATOMIC);
+ if (! ret) {
+ unlock_page(page);
+ } else {
+ hugetlb_put_quota(mapping);
+ free_huge_page(page);
+ goto out;
+ }
+ }
+ add_mm_counter(mm, rss, HPAGE_SIZE / PAGE_SIZE);
+ set_huge_pte_at(mm, addr, pte, make_huge_pte(vma, page));
+ }
+out:
+ spin_unlock(&mm->page_table_lock);
+ return ret;
+}
+
+int follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma,
+ struct page **pages, struct vm_area_struct **vmas,
+ unsigned long *position, int *length, int i)
+{
+ unsigned long vpfn, vaddr = *position;
+ int remainder = *length;
+
+ BUG_ON(!is_vm_hugetlb_page(vma));
+
+ vpfn = vaddr/PAGE_SIZE;
+ while (vaddr < vma->vm_end && remainder) {
+
+ if (pages) {
+ pte_t *pte;
+ struct page *page;
+
+ /* Some archs (sparc64, sh*) have multiple
+ * pte_ts to each hugepage. We have to make
+ * sure we get the first, for the page
+ * indexing below to work. */
+ pte = huge_pte_offset(mm, vaddr & HPAGE_MASK);
+
+ /* hugetlb should be locked, and hence, prefaulted */
+ WARN_ON(!pte || pte_none(*pte));
+
+ page = &pte_page(*pte)[vpfn % (HPAGE_SIZE/PAGE_SIZE)];
+
+ WARN_ON(!PageCompound(page));
+
+ get_page(page);
+ pages[i] = page;
+ }
+
+ if (vmas)
+ vmas[i] = vma;
+
+ vaddr += PAGE_SIZE;
+ ++vpfn;
+ --remainder;
+ ++i;
+ }
+
+ *length = remainder;
+ *position = vaddr;
+
+ return i;
+}
#include <linux/mman.h>
#include <linux/pagemap.h>
#include <linux/syscalls.h>
+#include <linux/mempolicy.h>
#include <linux/hugetlb.h>
/*
* We can potentially split a vm area into separate
* areas, each area with its own behavior.
*/
-static long madvise_behavior(struct vm_area_struct * vma, unsigned long start,
- unsigned long end, int behavior)
+static long madvise_behavior(struct vm_area_struct * vma,
+ struct vm_area_struct **prev,
+ unsigned long start, unsigned long end, int behavior)
{
struct mm_struct * mm = vma->vm_mm;
int error = 0;
+ pgoff_t pgoff;
+ int new_flags = vma->vm_flags & ~VM_READHINTMASK;
+
+ switch (behavior) {
+ case MADV_SEQUENTIAL:
+ new_flags |= VM_SEQ_READ;
+ break;
+ case MADV_RANDOM:
+ new_flags |= VM_RAND_READ;
+ break;
+ default:
+ break;
+ }
+
+ if (new_flags == vma->vm_flags) {
+ *prev = vma;
+ goto success;
+ }
+
+ pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT);
+ *prev = vma_merge(mm, *prev, start, end, new_flags, vma->anon_vma,
+ vma->vm_file, pgoff, vma_policy(vma));
+ if (*prev) {
+ vma = *prev;
+ goto success;
+ }
+
+ *prev = vma;
if (start != vma->vm_start) {
error = split_vma(mm, vma, start, 1);
* vm_flags is protected by the mmap_sem held in write mode.
*/
VM_ClearReadHint(vma);
-
- switch (behavior) {
- case MADV_SEQUENTIAL:
- vma->vm_flags |= VM_SEQ_READ;
- break;
- case MADV_RANDOM:
- vma->vm_flags |= VM_RAND_READ;
- break;
- default:
- break;
- }
+ vma->vm_flags = new_flags;
out:
if (error == -ENOMEM)
error = -EAGAIN;
+success:
return error;
}
* Schedule all required I/O operations. Do not wait for completion.
*/
static long madvise_willneed(struct vm_area_struct * vma,
+ struct vm_area_struct ** prev,
unsigned long start, unsigned long end)
{
struct file *file = vma->vm_file;
if (!file)
return -EBADF;
+ *prev = vma;
start = ((start - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
if (end > vma->vm_end)
end = vma->vm_end;
* dirty pages is already available as msync(MS_INVALIDATE).
*/
static long madvise_dontneed(struct vm_area_struct * vma,
+ struct vm_area_struct ** prev,
unsigned long start, unsigned long end)
{
+ *prev = vma;
if ((vma->vm_flags & VM_LOCKED) || is_vm_hugetlb_page(vma))
return -EINVAL;
return 0;
}
-static long madvise_vma(struct vm_area_struct * vma, unsigned long start,
- unsigned long end, int behavior)
+static long madvise_vma(struct vm_area_struct *vma, struct vm_area_struct **prev,
+ unsigned long start, unsigned long end, int behavior)
{
long error = -EBADF;
case MADV_NORMAL:
case MADV_SEQUENTIAL:
case MADV_RANDOM:
- error = madvise_behavior(vma, start, end, behavior);
+ error = madvise_behavior(vma, prev, start, end, behavior);
break;
case MADV_WILLNEED:
- error = madvise_willneed(vma, start, end);
+ error = madvise_willneed(vma, prev, start, end);
break;
case MADV_DONTNEED:
- error = madvise_dontneed(vma, start, end);
+ error = madvise_dontneed(vma, prev, start, end);
break;
default:
*/
asmlinkage long sys_madvise(unsigned long start, size_t len_in, int behavior)
{
- unsigned long end;
- struct vm_area_struct * vma;
+ unsigned long end, tmp;
+ struct vm_area_struct * vma, *prev;
int unmapped_error = 0;
int error = -EINVAL;
size_t len;
/*
* If the interval [start,end) covers some unmapped address
* ranges, just ignore them, but return -ENOMEM at the end.
+ * - different from the way of handling in mlock etc.
*/
- vma = find_vma(current->mm, start);
+ vma = find_vma_prev(current->mm, start, &prev);
+ if (!vma && prev)
+ vma = prev->vm_next;
for (;;) {
/* Still start < end. */
error = -ENOMEM;
if (!vma)
goto out;
- /* Here start < vma->vm_end. */
+ /* Here start < (end|vma->vm_end). */
if (start < vma->vm_start) {
unmapped_error = -ENOMEM;
start = vma->vm_start;
+ if (start >= end)
+ goto out;
}
- /* Here vma->vm_start <= start < vma->vm_end. */
- if (end <= vma->vm_end) {
- if (start < end) {
- error = madvise_vma(vma, start, end,
- behavior);
- if (error)
- goto out;
- }
- error = unmapped_error;
- goto out;
- }
+ /* Here vma->vm_start <= start < (end|vma->vm_end) */
+ tmp = vma->vm_end;
+ if (end < tmp)
+ tmp = end;
- /* Here vma->vm_start <= start < vma->vm_end < end. */
- error = madvise_vma(vma, start, vma->vm_end, behavior);
+ /* Here vma->vm_start <= start < tmp <= (end|vma->vm_end). */
+ error = madvise_vma(vma, &prev, start, tmp, behavior);
if (error)
goto out;
- start = vma->vm_end;
- vma = vma->vm_next;
+ start = tmp;
+ if (start < prev->vm_end)
+ start = prev->vm_end;
+ error = unmapped_error;
+ if (start >= end)
+ goto out;
+ vma = prev->vm_next;
}
-
out:
up_write(¤t->mm->mmap_sem);
return error;
{
return __follow_page(mm, address, /*read*/1, /*write*/0) != NULL;
}
-
EXPORT_SYMBOL(check_user_page_readable);
-/*
- * Given a physical address, is there a useful struct page pointing to
- * it? This may become more complex in the future if we start dealing
- * with IO-aperture pages for direct-IO.
- */
-
-static inline struct page *get_page_map(struct page *page)
-{
- if (!pfn_valid(page_to_pfn(page)))
- return NULL;
- return page;
-}
-
-
static inline int
untouched_anonymous_page(struct mm_struct* mm, struct vm_area_struct *vma,
unsigned long address)
return 0;
}
-
int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
unsigned long start, int len, int write, int force,
struct page **pages, struct vm_area_struct **vmas)
}
spin_lock(&mm->page_table_lock);
do {
- struct page *map;
+ struct page *page;
int lookup_write = write;
cond_resched_lock(&mm->page_table_lock);
- while (!(map = follow_page(mm, start, lookup_write))) {
+ while (!(page = follow_page(mm, start, lookup_write))) {
/*
* Shortcut for anonymous pages. We don't want
* to force the creation of pages tables for
- * insanly big anonymously mapped areas that
+ * insanely big anonymously mapped areas that
* nobody touched so far. This is important
* for doing a core dump for these mappings.
*/
if (!lookup_write &&
untouched_anonymous_page(mm,vma,start)) {
- map = ZERO_PAGE(start);
+ page = ZERO_PAGE(start);
break;
}
spin_unlock(&mm->page_table_lock);
spin_lock(&mm->page_table_lock);
}
if (pages) {
- pages[i] = get_page_map(map);
- if (!pages[i]) {
- spin_unlock(&mm->page_table_lock);
- while (i--)
- page_cache_release(pages[i]);
- i = -EFAULT;
- goto out;
- }
- flush_dcache_page(pages[i]);
- if (!PageReserved(pages[i]))
- page_cache_get(pages[i]);
+ pages[i] = page;
+ flush_dcache_page(page);
+ if (!PageReserved(page))
+ page_cache_get(page);
}
if (vmas)
vmas[i] = vma;
i++;
start += PAGE_SIZE;
len--;
- } while(len && start < vma->vm_end);
+ } while (len && start < vma->vm_end);
spin_unlock(&mm->page_table_lock);
- } while(len);
-out:
+ } while (len);
return i;
}
-
EXPORT_SYMBOL(get_user_pages);
static int zeromap_pte_range(struct mm_struct *mm, pmd_t *pmd,
}
old_page = pfn_to_page(pfn);
- if (!TestSetPageLocked(old_page)) {
+ if (PageAnon(old_page) && !TestSetPageLocked(old_page)) {
int reuse = can_share_swap_page(old_page);
unlock_page(old_page);
if (reuse) {
}
/* The page isn't present yet, go ahead with the fault. */
-
- swap_free(entry);
- if (vm_swap_full())
- remove_exclusive_swap_page(page);
inc_mm_counter(mm, rss);
pte = mk_pte(page, vma->vm_page_prot);
pte = maybe_mkwrite(pte_mkdirty(pte), vma);
write_access = 0;
}
- unlock_page(page);
flush_icache_page(vma, page);
set_pte_at(mm, address, page_table, pte);
page_add_anon_rmap(page, vma, address);
+ swap_free(entry);
+ if (vm_swap_full())
+ remove_exclusive_swap_page(page);
+ unlock_page(page);
+
if (write_access) {
if (do_wp_page(mm, vma, address,
page_table, pmd, pte) == VM_FAULT_OOM)
}
/* Ensure all existing pages follow the policy. */
-static int
-verify_pages(struct mm_struct *mm,
- unsigned long addr, unsigned long end, unsigned long *nodes)
+static int check_pte_range(struct mm_struct *mm, pmd_t *pmd,
+ unsigned long addr, unsigned long end, unsigned long *nodes)
{
- while (addr < end) {
- struct page *p;
- pte_t *pte;
- pmd_t *pmd;
- pud_t *pud;
- pgd_t *pgd;
- pgd = pgd_offset(mm, addr);
- if (pgd_none(*pgd)) {
- unsigned long next = (addr + PGDIR_SIZE) & PGDIR_MASK;
- if (next > addr)
- break;
- addr = next;
+ pte_t *orig_pte;
+ pte_t *pte;
+
+ spin_lock(&mm->page_table_lock);
+ orig_pte = pte = pte_offset_map(pmd, addr);
+ do {
+ unsigned long pfn;
+ unsigned int nid;
+
+ if (!pte_present(*pte))
continue;
- }
- pud = pud_offset(pgd, addr);
- if (pud_none(*pud)) {
- addr = (addr + PUD_SIZE) & PUD_MASK;
+ pfn = pte_pfn(*pte);
+ if (!pfn_valid(pfn))
continue;
- }
- pmd = pmd_offset(pud, addr);
- if (pmd_none(*pmd)) {
- addr = (addr + PMD_SIZE) & PMD_MASK;
+ nid = pfn_to_nid(pfn);
+ if (!test_bit(nid, nodes))
+ break;
+ } while (pte++, addr += PAGE_SIZE, addr != end);
+ pte_unmap(orig_pte);
+ spin_unlock(&mm->page_table_lock);
+ return addr != end;
+}
+
+static inline int check_pmd_range(struct mm_struct *mm, pud_t *pud,
+ unsigned long addr, unsigned long end, unsigned long *nodes)
+{
+ pmd_t *pmd;
+ unsigned long next;
+
+ pmd = pmd_offset(pud, addr);
+ do {
+ next = pmd_addr_end(addr, end);
+ if (pmd_none_or_clear_bad(pmd))
continue;
- }
- p = NULL;
- pte = pte_offset_map(pmd, addr);
- if (pte_present(*pte))
- p = pte_page(*pte);
- pte_unmap(pte);
- if (p) {
- unsigned nid = page_to_nid(p);
- if (!test_bit(nid, nodes))
- return -EIO;
- }
- addr += PAGE_SIZE;
- }
+ if (check_pte_range(mm, pmd, addr, next, nodes))
+ return -EIO;
+ } while (pmd++, addr = next, addr != end);
+ return 0;
+}
+
+static inline int check_pud_range(struct mm_struct *mm, pgd_t *pgd,
+ unsigned long addr, unsigned long end, unsigned long *nodes)
+{
+ pud_t *pud;
+ unsigned long next;
+
+ pud = pud_offset(pgd, addr);
+ do {
+ next = pud_addr_end(addr, end);
+ if (pud_none_or_clear_bad(pud))
+ continue;
+ if (check_pmd_range(mm, pud, addr, next, nodes))
+ return -EIO;
+ } while (pud++, addr = next, addr != end);
+ return 0;
+}
+
+static inline int check_pgd_range(struct mm_struct *mm,
+ unsigned long addr, unsigned long end, unsigned long *nodes)
+{
+ pgd_t *pgd;
+ unsigned long next;
+
+ pgd = pgd_offset(mm, addr);
+ do {
+ next = pgd_addr_end(addr, end);
+ if (pgd_none_or_clear_bad(pgd))
+ continue;
+ if (check_pud_range(mm, pgd, addr, next, nodes))
+ return -EIO;
+ } while (pgd++, addr = next, addr != end);
return 0;
}
if (prev && prev->vm_end < vma->vm_start)
return ERR_PTR(-EFAULT);
if ((flags & MPOL_MF_STRICT) && !is_vm_hugetlb_page(vma)) {
- err = verify_pages(vma->vm_mm,
+ err = check_pgd_range(vma->vm_mm,
vma->vm_start, vma->vm_end, nodes);
if (err) {
first = ERR_PTR(err);
zl = NODE_DATA(nid)->node_zonelists + (gfp & GFP_ZONEMASK);
page = __alloc_pages(gfp, order, zl);
if (page && page_zone(page) == zl->zones[0]) {
- zl->zones[0]->pageset[get_cpu()].interleave_hit++;
+ zone_pcp(zl->zones[0],get_cpu())->interleave_hit++;
put_cpu();
}
return page;
(!vma || addr + len <= vma->vm_start))
return addr;
}
- start_addr = addr = mm->free_area_cache;
+ if (len > mm->cached_hole_size) {
+ start_addr = addr = mm->free_area_cache;
+ } else {
+ start_addr = addr = TASK_UNMAPPED_BASE;
+ mm->cached_hole_size = 0;
+ }
full_search:
for (vma = find_vma(mm, addr); ; vma = vma->vm_next) {
* some holes.
*/
if (start_addr != TASK_UNMAPPED_BASE) {
- start_addr = addr = TASK_UNMAPPED_BASE;
+ addr = TASK_UNMAPPED_BASE;
+ start_addr = addr;
+ mm->cached_hole_size = 0;
goto full_search;
}
return -ENOMEM;
mm->free_area_cache = addr + len;
return addr;
}
+ if (addr + mm->cached_hole_size < vma->vm_start)
+ mm->cached_hole_size = vma->vm_start - addr;
addr = vma->vm_end;
}
}
#endif
-void arch_unmap_area(struct vm_area_struct *area)
+void arch_unmap_area(struct mm_struct *mm, unsigned long addr)
{
/*
* Is this a new hole at the lowest possible address?
*/
- if (area->vm_start >= TASK_UNMAPPED_BASE &&
- area->vm_start < area->vm_mm->free_area_cache)
- area->vm_mm->free_area_cache = area->vm_start;
+ if (addr >= TASK_UNMAPPED_BASE && addr < mm->free_area_cache) {
+ mm->free_area_cache = addr;
+ mm->cached_hole_size = ~0UL;
+ }
}
/*
return addr;
}
+ /* check if free_area_cache is useful for us */
+ if (len <= mm->cached_hole_size) {
+ mm->cached_hole_size = 0;
+ mm->free_area_cache = mm->mmap_base;
+ }
+
/* either no address requested or can't fit in requested address hole */
addr = mm->free_area_cache;
return (mm->free_area_cache = addr-len);
}
+ if (mm->mmap_base < len)
+ goto bottomup;
+
addr = mm->mmap_base-len;
do {
/* remember the address as a hint for next time */
return (mm->free_area_cache = addr);
+ /* remember the largest hole we saw so far */
+ if (addr + mm->cached_hole_size < vma->vm_start)
+ mm->cached_hole_size = vma->vm_start - addr;
+
/* try just below the current vma->vm_start */
addr = vma->vm_start-len;
} while (len < vma->vm_start);
+bottomup:
/*
* A failed mmap() very likely causes application failure,
* so fall back to the bottom-up function here. This scenario
* can happen with large stack limits and large mmap()
* allocations.
*/
- mm->free_area_cache = TASK_UNMAPPED_BASE;
+ mm->cached_hole_size = ~0UL;
+ mm->free_area_cache = TASK_UNMAPPED_BASE;
addr = arch_get_unmapped_area(filp, addr0, len, pgoff, flags);
/*
* Restore the topdown base:
*/
mm->free_area_cache = mm->mmap_base;
+ mm->cached_hole_size = ~0UL;
return addr;
}
#endif
-void arch_unmap_area_topdown(struct vm_area_struct *area)
+void arch_unmap_area_topdown(struct mm_struct *mm, unsigned long addr)
{
/*
* Is this a new hole at the highest possible address?
*/
- if (area->vm_end > area->vm_mm->free_area_cache)
- area->vm_mm->free_area_cache = area->vm_end;
+ if (addr > mm->free_area_cache)
+ mm->free_area_cache = addr;
/* dont allow allocations above current base */
- if (area->vm_mm->free_area_cache > area->vm_mm->mmap_base)
- area->vm_mm->free_area_cache = area->vm_mm->mmap_base;
+ if (mm->free_area_cache > mm->mmap_base)
+ mm->free_area_cache = mm->mmap_base;
}
unsigned long
if (area->vm_flags & VM_LOCKED)
area->vm_mm->locked_vm -= len >> PAGE_SHIFT;
vm_stat_unaccount(area);
- area->vm_mm->unmap_area(area);
remove_vm_struct(area);
}
{
struct vm_area_struct **insertion_point;
struct vm_area_struct *tail_vma = NULL;
+ unsigned long addr;
insertion_point = (prev ? &prev->vm_next : &mm->mmap);
do {
} while (vma && vma->vm_start < end);
*insertion_point = vma;
tail_vma->vm_next = NULL;
+ if (mm->unmap_area == arch_unmap_area)
+ addr = prev ? prev->vm_end : mm->mmap_base;
+ else
+ addr = vma ? vma->vm_start : mm->mmap_base;
+ mm->unmap_area(mm, addr);
mm->mmap_cache = NULL; /* Kill the cache. */
}
if (!pte_present(*pte))
continue;
+ if (!pte_maybe_dirty(*pte))
+ continue;
pfn = pte_pfn(*pte);
if (!pfn_valid(pfn))
continue;
return -ENOMEM;
}
-void arch_unmap_area(struct vm_area_struct *area)
+void arch_unmap_area(struct mm_struct *mm, unsigned long addr)
{
}
struct mm_struct *mm = NULL;
task_t * p;
+ printk("oom-killer: gfp_mask=0x%x\n", gfp_mask);
+ /* print memory stats */
+ show_mem();
+
read_lock(&tasklist_lock);
retry:
p = select_bad_process();
/* Found nothing?!?! Either we hang forever, or we panic. */
if (!p) {
read_unlock(&tasklist_lock);
- show_free_areas();
panic("Out of memory and no killable processes...\n");
}
- printk("oom-killer: gfp_mask=0x%x\n", gfp_mask);
- show_free_areas();
mm = oom_kill_process(p);
if (!mm)
goto retry;
printk(KERN_EMERG "Backtrace:\n");
dump_stack();
printk(KERN_EMERG "Trying to fix it up, but a reboot is needed\n");
- page->flags &= ~(1 << PG_private |
+ page->flags &= ~(1 << PG_lru |
+ 1 << PG_private |
1 << PG_locked |
- 1 << PG_lru |
1 << PG_active |
1 << PG_dirty |
+ 1 << PG_reclaim |
+ 1 << PG_slab |
1 << PG_swapcache |
1 << PG_writeback);
set_page_count(page, 0);
*/
static void prep_new_page(struct page *page, int order)
{
- if (page->mapping || page_mapcount(page) ||
- (page->flags & (
+ if ( page_mapcount(page) ||
+ page->mapping != NULL ||
+ page_count(page) != 0 ||
+ (page->flags & (
+ 1 << PG_lru |
1 << PG_private |
1 << PG_locked |
- 1 << PG_lru |
1 << PG_active |
1 << PG_dirty |
1 << PG_reclaim |
+ 1 << PG_slab |
1 << PG_swapcache |
1 << PG_writeback )))
bad_page(__FUNCTION__, page);
return allocated;
}
+#ifdef CONFIG_NUMA
+/* Called from the slab reaper to drain remote pagesets */
+void drain_remote_pages(void)
+{
+ struct zone *zone;
+ int i;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ for_each_zone(zone) {
+ struct per_cpu_pageset *pset;
+
+ /* Do not drain local pagesets */
+ if (zone->zone_pgdat->node_id == numa_node_id())
+ continue;
+
+ pset = zone->pageset[smp_processor_id()];
+ for (i = 0; i < ARRAY_SIZE(pset->pcp); i++) {
+ struct per_cpu_pages *pcp;
+
+ pcp = &pset->pcp[i];
+ if (pcp->count)
+ pcp->count -= free_pages_bulk(zone, pcp->count,
+ &pcp->list, 0);
+ }
+ }
+ local_irq_restore(flags);
+}
+#endif
+
#if defined(CONFIG_PM) || defined(CONFIG_HOTPLUG_CPU)
static void __drain_pages(unsigned int cpu)
{
for_each_zone(zone) {
struct per_cpu_pageset *pset;
- pset = &zone->pageset[cpu];
+ pset = zone_pcp(zone, cpu);
for (i = 0; i < ARRAY_SIZE(pset->pcp); i++) {
struct per_cpu_pages *pcp;
local_irq_save(flags);
cpu = smp_processor_id();
- p = &z->pageset[cpu];
+ p = zone_pcp(z,cpu);
if (pg == orig) {
- z->pageset[cpu].numa_hit++;
+ p->numa_hit++;
} else {
p->numa_miss++;
- zonelist->zones[0]->pageset[cpu].numa_foreign++;
+ zone_pcp(zonelist->zones[0], cpu)->numa_foreign++;
}
if (pg == NODE_DATA(numa_node_id()))
p->local_node++;
if (PageAnon(page))
page->mapping = NULL;
free_pages_check(__FUNCTION__, page);
- pcp = &zone->pageset[get_cpu()].pcp[cold];
+ pcp = &zone_pcp(zone, get_cpu())->pcp[cold];
local_irq_save(flags);
- if (pcp->count >= pcp->high)
- pcp->count -= free_pages_bulk(zone, pcp->batch, &pcp->list, 0);
list_add(&page->lru, &pcp->list);
pcp->count++;
+ if (pcp->count >= pcp->high)
+ pcp->count -= free_pages_bulk(zone, pcp->batch, &pcp->list, 0);
local_irq_restore(flags);
put_cpu();
}
if (order == 0) {
struct per_cpu_pages *pcp;
- pcp = &zone->pageset[get_cpu()].pcp[cold];
+ pcp = &zone_pcp(zone, get_cpu())->pcp[cold];
local_irq_save(flags);
if (pcp->count <= pcp->low)
pcp->count += rmqueue_bulk(zone, 0,
return 1;
}
+static inline int
+should_reclaim_zone(struct zone *z, unsigned int gfp_mask)
+{
+ if (!z->reclaim_pages)
+ return 0;
+ if (gfp_mask & __GFP_NORECLAIM)
+ return 0;
+ return 1;
+}
+
/*
* This is the 'heart' of the zoned buddy allocator.
*/
classzone_idx = zone_idx(zones[0]);
- restart:
+restart:
/* Go through the zonelist once, looking for a zone with enough free */
for (i = 0; (z = zones[i]) != NULL; i++) {
-
- if (!zone_watermark_ok(z, order, z->pages_low,
- classzone_idx, 0, 0))
- continue;
+ int do_reclaim = should_reclaim_zone(z, gfp_mask);
if (!cpuset_zone_allowed(z))
continue;
+ /*
+ * If the zone is to attempt early page reclaim then this loop
+ * will try to reclaim pages and check the watermark a second
+ * time before giving up and falling back to the next zone.
+ */
+zone_reclaim_retry:
+ if (!zone_watermark_ok(z, order, z->pages_low,
+ classzone_idx, 0, 0)) {
+ if (!do_reclaim)
+ continue;
+ else {
+ zone_reclaim(z, gfp_mask, order);
+ /* Only try reclaim once */
+ do_reclaim = 0;
+ goto zone_reclaim_retry;
+ }
+ }
+
page = buffered_rmqueue(z, order, gfp_mask);
if (page)
goto got_pg;
reclaim_state.reclaimed_slab = 0;
p->reclaim_state = &reclaim_state;
- did_some_progress = try_to_free_pages(zones, gfp_mask, order);
+ did_some_progress = try_to_free_pages(zones, gfp_mask);
p->reclaim_state = NULL;
p->flags &= ~PF_MEMALLOC;
" order:%d, mode:0x%x\n",
p->comm, order, gfp_mask);
dump_stack();
+ show_mem();
}
return NULL;
got_pg:
__get_page_state(ret, sizeof(*ret) / sizeof(unsigned long));
}
-unsigned long __read_page_state(unsigned offset)
+unsigned long __read_page_state(unsigned long offset)
{
unsigned long ret = 0;
int cpu;
return ret;
}
-void __mod_page_state(unsigned offset, unsigned long delta)
+void __mod_page_state(unsigned long offset, unsigned long delta)
{
unsigned long flags;
void* ptr;
if (!cpu_possible(cpu))
continue;
- pageset = zone->pageset + cpu;
+ pageset = zone_pcp(zone, cpu);
for (temperature = 0; temperature < 2; temperature++)
- printk("cpu %d %s: low %d, high %d, batch %d\n",
+ printk("cpu %d %s: low %d, high %d, batch %d used:%d\n",
cpu,
temperature ? "cold" : "hot",
pageset->pcp[temperature].low,
pageset->pcp[temperature].high,
- pageset->pcp[temperature].batch);
+ pageset->pcp[temperature].batch,
+ pageset->pcp[temperature].count);
}
}
get_page_state(&ps);
get_zone_counts(&active, &inactive, &free);
- printk("\nFree pages: %11ukB (%ukB HighMem)\n",
+ printk("Free pages: %11ukB (%ukB HighMem)\n",
K(nr_free_pages()),
K(nr_free_highpages()));
memmap_init_zone((size), (nid), (zone), (start_pfn))
#endif
+static int __devinit zone_batchsize(struct zone *zone)
+{
+ int batch;
+
+ /*
+ * The per-cpu-pages pools are set to around 1000th of the
+ * size of the zone. But no more than 1/4 of a meg - there's
+ * no point in going beyond the size of L2 cache.
+ *
+ * OK, so we don't know how big the cache is. So guess.
+ */
+ batch = zone->present_pages / 1024;
+ if (batch * PAGE_SIZE > 256 * 1024)
+ batch = (256 * 1024) / PAGE_SIZE;
+ batch /= 4; /* We effectively *= 4 below */
+ if (batch < 1)
+ batch = 1;
+
+ /*
+ * Clamp the batch to a 2^n - 1 value. Having a power
+ * of 2 value was found to be more likely to have
+ * suboptimal cache aliasing properties in some cases.
+ *
+ * For example if 2 tasks are alternately allocating
+ * batches of pages, one task can end up with a lot
+ * of pages of one half of the possible page colors
+ * and the other with pages of the other colors.
+ */
+ batch = (1 << fls(batch + batch/2)) - 1;
+ return batch;
+}
+
+inline void setup_pageset(struct per_cpu_pageset *p, unsigned long batch)
+{
+ struct per_cpu_pages *pcp;
+
+ pcp = &p->pcp[0]; /* hot */
+ pcp->count = 0;
+ pcp->low = 2 * batch;
+ pcp->high = 6 * batch;
+ pcp->batch = max(1UL, 1 * batch);
+ INIT_LIST_HEAD(&pcp->list);
+
+ pcp = &p->pcp[1]; /* cold*/
+ pcp->count = 0;
+ pcp->low = 0;
+ pcp->high = 2 * batch;
+ pcp->batch = max(1UL, 1 * batch);
+ INIT_LIST_HEAD(&pcp->list);
+}
+
+#ifdef CONFIG_NUMA
+/*
+ * Boot pageset table. One per cpu which is going to be used for all
+ * zones and all nodes. The parameters will be set in such a way
+ * that an item put on a list will immediately be handed over to
+ * the buddy list. This is safe since pageset manipulation is done
+ * with interrupts disabled.
+ *
+ * Some NUMA counter updates may also be caught by the boot pagesets.
+ * These will be discarded when bootup is complete.
+ */
+static struct per_cpu_pageset
+ boot_pageset[NR_CPUS] __initdata;
+
+/*
+ * Dynamically allocate memory for the
+ * per cpu pageset array in struct zone.
+ */
+static int __devinit process_zones(int cpu)
+{
+ struct zone *zone, *dzone;
+
+ for_each_zone(zone) {
+
+ zone->pageset[cpu] = kmalloc_node(sizeof(struct per_cpu_pageset),
+ GFP_KERNEL, cpu_to_node(cpu));
+ if (!zone->pageset[cpu])
+ goto bad;
+
+ setup_pageset(zone->pageset[cpu], zone_batchsize(zone));
+ }
+
+ return 0;
+bad:
+ for_each_zone(dzone) {
+ if (dzone == zone)
+ break;
+ kfree(dzone->pageset[cpu]);
+ dzone->pageset[cpu] = NULL;
+ }
+ return -ENOMEM;
+}
+
+static inline void free_zone_pagesets(int cpu)
+{
+#ifdef CONFIG_NUMA
+ struct zone *zone;
+
+ for_each_zone(zone) {
+ struct per_cpu_pageset *pset = zone_pcp(zone, cpu);
+
+ zone_pcp(zone, cpu) = NULL;
+ kfree(pset);
+ }
+#endif
+}
+
+static int __devinit pageset_cpuup_callback(struct notifier_block *nfb,
+ unsigned long action,
+ void *hcpu)
+{
+ int cpu = (long)hcpu;
+ int ret = NOTIFY_OK;
+
+ switch (action) {
+ case CPU_UP_PREPARE:
+ if (process_zones(cpu))
+ ret = NOTIFY_BAD;
+ break;
+#ifdef CONFIG_HOTPLUG_CPU
+ case CPU_DEAD:
+ free_zone_pagesets(cpu);
+ break;
+#endif
+ default:
+ break;
+ }
+ return ret;
+}
+
+static struct notifier_block pageset_notifier =
+ { &pageset_cpuup_callback, NULL, 0 };
+
+void __init setup_per_cpu_pageset()
+{
+ int err;
+
+ /* Initialize per_cpu_pageset for cpu 0.
+ * A cpuup callback will do this for every cpu
+ * as it comes online
+ */
+ err = process_zones(smp_processor_id());
+ BUG_ON(err);
+ register_cpu_notifier(&pageset_notifier);
+}
+
+#endif
+
/*
* Set up the zone data structures:
* - mark all pages reserved
zone->temp_priority = zone->prev_priority = DEF_PRIORITY;
- /*
- * The per-cpu-pages pools are set to around 1000th of the
- * size of the zone. But no more than 1/4 of a meg - there's
- * no point in going beyond the size of L2 cache.
- *
- * OK, so we don't know how big the cache is. So guess.
- */
- batch = zone->present_pages / 1024;
- if (batch * PAGE_SIZE > 256 * 1024)
- batch = (256 * 1024) / PAGE_SIZE;
- batch /= 4; /* We effectively *= 4 below */
- if (batch < 1)
- batch = 1;
-
- /*
- * Clamp the batch to a 2^n - 1 value. Having a power
- * of 2 value was found to be more likely to have
- * suboptimal cache aliasing properties in some cases.
- *
- * For example if 2 tasks are alternately allocating
- * batches of pages, one task can end up with a lot
- * of pages of one half of the possible page colors
- * and the other with pages of the other colors.
- */
- batch = (1 << fls(batch + batch/2)) - 1;
+ batch = zone_batchsize(zone);
for (cpu = 0; cpu < NR_CPUS; cpu++) {
- struct per_cpu_pages *pcp;
-
- pcp = &zone->pageset[cpu].pcp[0]; /* hot */
- pcp->count = 0;
- pcp->low = 2 * batch;
- pcp->high = 6 * batch;
- pcp->batch = 1 * batch;
- INIT_LIST_HEAD(&pcp->list);
-
- pcp = &zone->pageset[cpu].pcp[1]; /* cold */
- pcp->count = 0;
- pcp->low = 0;
- pcp->high = 2 * batch;
- pcp->batch = 1 * batch;
- INIT_LIST_HEAD(&pcp->list);
+#ifdef CONFIG_NUMA
+ /* Early boot. Slab allocator not functional yet */
+ zone->pageset[cpu] = &boot_pageset[cpu];
+ setup_pageset(&boot_pageset[cpu],0);
+#else
+ setup_pageset(zone_pcp(zone,cpu), batch);
+#endif
}
printk(KERN_DEBUG " %s zone: %lu pages, LIFO batch:%lu\n",
zone_names[j], realsize, batch);
zone->nr_scan_inactive = 0;
zone->nr_active = 0;
zone->nr_inactive = 0;
+ atomic_set(&zone->reclaim_in_progress, -1);
if (!size)
continue;
.show = frag_show,
};
+/*
+ * Output information about zones in @pgdat.
+ */
+static int zoneinfo_show(struct seq_file *m, void *arg)
+{
+ pg_data_t *pgdat = arg;
+ struct zone *zone;
+ struct zone *node_zones = pgdat->node_zones;
+ unsigned long flags;
+
+ for (zone = node_zones; zone - node_zones < MAX_NR_ZONES; zone++) {
+ int i;
+
+ if (!zone->present_pages)
+ continue;
+
+ spin_lock_irqsave(&zone->lock, flags);
+ seq_printf(m, "Node %d, zone %8s", pgdat->node_id, zone->name);
+ seq_printf(m,
+ "\n pages free %lu"
+ "\n min %lu"
+ "\n low %lu"
+ "\n high %lu"
+ "\n active %lu"
+ "\n inactive %lu"
+ "\n scanned %lu (a: %lu i: %lu)"
+ "\n spanned %lu"
+ "\n present %lu",
+ zone->free_pages,
+ zone->pages_min,
+ zone->pages_low,
+ zone->pages_high,
+ zone->nr_active,
+ zone->nr_inactive,
+ zone->pages_scanned,
+ zone->nr_scan_active, zone->nr_scan_inactive,
+ zone->spanned_pages,
+ zone->present_pages);
+ seq_printf(m,
+ "\n protection: (%lu",
+ zone->lowmem_reserve[0]);
+ for (i = 1; i < ARRAY_SIZE(zone->lowmem_reserve); i++)
+ seq_printf(m, ", %lu", zone->lowmem_reserve[i]);
+ seq_printf(m,
+ ")"
+ "\n pagesets");
+ for (i = 0; i < ARRAY_SIZE(zone->pageset); i++) {
+ struct per_cpu_pageset *pageset;
+ int j;
+
+ pageset = zone_pcp(zone, i);
+ for (j = 0; j < ARRAY_SIZE(pageset->pcp); j++) {
+ if (pageset->pcp[j].count)
+ break;
+ }
+ if (j == ARRAY_SIZE(pageset->pcp))
+ continue;
+ for (j = 0; j < ARRAY_SIZE(pageset->pcp); j++) {
+ seq_printf(m,
+ "\n cpu: %i pcp: %i"
+ "\n count: %i"
+ "\n low: %i"
+ "\n high: %i"
+ "\n batch: %i",
+ i, j,
+ pageset->pcp[j].count,
+ pageset->pcp[j].low,
+ pageset->pcp[j].high,
+ pageset->pcp[j].batch);
+ }
+#ifdef CONFIG_NUMA
+ seq_printf(m,
+ "\n numa_hit: %lu"
+ "\n numa_miss: %lu"
+ "\n numa_foreign: %lu"
+ "\n interleave_hit: %lu"
+ "\n local_node: %lu"
+ "\n other_node: %lu",
+ pageset->numa_hit,
+ pageset->numa_miss,
+ pageset->numa_foreign,
+ pageset->interleave_hit,
+ pageset->local_node,
+ pageset->other_node);
+#endif
+ }
+ seq_printf(m,
+ "\n all_unreclaimable: %u"
+ "\n prev_priority: %i"
+ "\n temp_priority: %i"
+ "\n start_pfn: %lu",
+ zone->all_unreclaimable,
+ zone->prev_priority,
+ zone->temp_priority,
+ zone->zone_start_pfn);
+ spin_unlock_irqrestore(&zone->lock, flags);
+ seq_putc(m, '\n');
+ }
+ return 0;
+}
+
+struct seq_operations zoneinfo_op = {
+ .start = frag_start, /* iterate over all zones. The same as in
+ * fragmentation. */
+ .next = frag_next,
+ .stop = frag_stop,
+ .show = zoneinfo_show,
+};
+
static char *vmstat_text[] = {
"nr_dirty",
"nr_writeback",
min_pages = 128;
zone->pages_min = min_pages;
} else {
- /* if it's a lowmem zone, reserve a number of pages
+ /* if it's a lowmem zone, reserve a number of pages
* proportionate to the zone's size.
*/
- zone->pages_min = (pages_min * zone->present_pages) /
+ zone->pages_min = (pages_min * zone->present_pages) /
lowmem_pages;
}
goto out_unmap;
}
- /*
- * Don't pull an anonymous page out from under get_user_pages.
- * GUP carefully breaks COW and raises page count (while holding
- * page_table_lock, as we have here) to make sure that the page
- * cannot be freed. If we unmap that page here, a user write
- * access to the virtual address will bring back the page, but
- * its raised count will (ironically) be taken to mean it's not
- * an exclusive swap page, do_wp_page will replace it by a copy
- * page, and the user never get to see the data GUP was holding
- * the original page for.
- *
- * This test is also useful for when swapoff (unuse_process) has
- * to drop page lock: its reference to the page stops existing
- * ptes from being unmapped, so swapoff can make progress.
- */
- if (PageSwapCache(page) &&
- page_count(page) != page_mapcount(page) + 2) {
- ret = SWAP_FAIL;
- goto out_unmap;
- }
-
/* Nuke the page table entry. */
flush_cache_page(vma, address, page_to_pfn(page));
pteval = ptep_clear_flush(vma, address, pte);
* 2000-2001 Christoph Rohland
* 2000-2001 SAP AG
* 2002 Red Hat Inc.
- * Copyright (C) 2002-2004 Hugh Dickins.
- * Copyright (C) 2002-2004 VERITAS Software Corporation.
+ * Copyright (C) 2002-2005 Hugh Dickins.
+ * Copyright (C) 2002-2005 VERITAS Software Corporation.
* Copyright (C) 2004 Andi Kleen, SuSE Labs
*
* Extended attribute support for tmpfs:
static void shmem_free_blocks(struct inode *inode, long pages)
{
struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
- if (sbinfo) {
+ if (sbinfo->max_blocks) {
spin_lock(&sbinfo->stat_lock);
sbinfo->free_blocks += pages;
inode->i_blocks -= pages*BLOCKS_PER_PAGE;
* page (and perhaps indirect index pages) yet to allocate:
* a waste to allocate index if we cannot allocate data.
*/
- if (sbinfo) {
+ if (sbinfo->max_blocks) {
spin_lock(&sbinfo->stat_lock);
if (sbinfo->free_blocks <= 1) {
spin_unlock(&sbinfo->stat_lock);
spin_unlock(&shmem_swaplist_lock);
}
}
- if (sbinfo) {
- BUG_ON(inode->i_blocks);
+ BUG_ON(inode->i_blocks);
+ if (sbinfo->max_inodes) {
spin_lock(&sbinfo->stat_lock);
sbinfo->free_inodes++;
spin_unlock(&sbinfo->stat_lock);
} else {
shmem_swp_unmap(entry);
sbinfo = SHMEM_SB(inode->i_sb);
- if (sbinfo) {
+ if (sbinfo->max_blocks) {
spin_lock(&sbinfo->stat_lock);
if (sbinfo->free_blocks == 0 ||
shmem_acct_block(info->flags)) {
struct shmem_inode_info *info;
struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
- if (sbinfo) {
+ if (sbinfo->max_inodes) {
spin_lock(&sbinfo->stat_lock);
if (!sbinfo->free_inodes) {
spin_unlock(&sbinfo->stat_lock);
mpol_shared_policy_init(&info->policy);
break;
}
- } else if (sbinfo) {
+ } else if (sbinfo->max_inodes) {
spin_lock(&sbinfo->stat_lock);
sbinfo->free_inodes++;
spin_unlock(&sbinfo->stat_lock);
}
#ifdef CONFIG_TMPFS
-
-static int shmem_set_size(struct shmem_sb_info *sbinfo,
- unsigned long max_blocks, unsigned long max_inodes)
-{
- int error;
- unsigned long blocks, inodes;
-
- spin_lock(&sbinfo->stat_lock);
- blocks = sbinfo->max_blocks - sbinfo->free_blocks;
- inodes = sbinfo->max_inodes - sbinfo->free_inodes;
- error = -EINVAL;
- if (max_blocks < blocks)
- goto out;
- if (max_inodes < inodes)
- goto out;
- error = 0;
- sbinfo->max_blocks = max_blocks;
- sbinfo->free_blocks = max_blocks - blocks;
- sbinfo->max_inodes = max_inodes;
- sbinfo->free_inodes = max_inodes - inodes;
-out:
- spin_unlock(&sbinfo->stat_lock);
- return error;
-}
-
static struct inode_operations shmem_symlink_inode_operations;
static struct inode_operations shmem_symlink_inline_operations;
buf->f_type = TMPFS_MAGIC;
buf->f_bsize = PAGE_CACHE_SIZE;
buf->f_namelen = NAME_MAX;
- if (sbinfo) {
- spin_lock(&sbinfo->stat_lock);
+ spin_lock(&sbinfo->stat_lock);
+ if (sbinfo->max_blocks) {
buf->f_blocks = sbinfo->max_blocks;
buf->f_bavail = buf->f_bfree = sbinfo->free_blocks;
+ }
+ if (sbinfo->max_inodes) {
buf->f_files = sbinfo->max_inodes;
buf->f_ffree = sbinfo->free_inodes;
- spin_unlock(&sbinfo->stat_lock);
}
/* else leave those fields 0 like simple_statfs */
+ spin_unlock(&sbinfo->stat_lock);
return 0;
}
* but each new link needs a new dentry, pinning lowmem, and
* tmpfs dentries cannot be pruned until they are unlinked.
*/
- if (sbinfo) {
+ if (sbinfo->max_inodes) {
spin_lock(&sbinfo->stat_lock);
if (!sbinfo->free_inodes) {
spin_unlock(&sbinfo->stat_lock);
if (inode->i_nlink > 1 && !S_ISDIR(inode->i_mode)) {
struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
- if (sbinfo) {
+ if (sbinfo->max_inodes) {
spin_lock(&sbinfo->stat_lock);
sbinfo->free_inodes++;
spin_unlock(&sbinfo->stat_lock);
static int shmem_remount_fs(struct super_block *sb, int *flags, char *data)
{
struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
- unsigned long max_blocks = 0;
- unsigned long max_inodes = 0;
+ unsigned long max_blocks = sbinfo->max_blocks;
+ unsigned long max_inodes = sbinfo->max_inodes;
+ unsigned long blocks;
+ unsigned long inodes;
+ int error = -EINVAL;
+
+ if (shmem_parse_options(data, NULL, NULL, NULL,
+ &max_blocks, &max_inodes))
+ return error;
- if (sbinfo) {
- max_blocks = sbinfo->max_blocks;
- max_inodes = sbinfo->max_inodes;
- }
- if (shmem_parse_options(data, NULL, NULL, NULL, &max_blocks, &max_inodes))
- return -EINVAL;
- /* Keep it simple: disallow limited <-> unlimited remount */
- if ((max_blocks || max_inodes) == !sbinfo)
- return -EINVAL;
- /* But allow the pointless unlimited -> unlimited remount */
- if (!sbinfo)
- return 0;
- return shmem_set_size(sbinfo, max_blocks, max_inodes);
+ spin_lock(&sbinfo->stat_lock);
+ blocks = sbinfo->max_blocks - sbinfo->free_blocks;
+ inodes = sbinfo->max_inodes - sbinfo->free_inodes;
+ if (max_blocks < blocks)
+ goto out;
+ if (max_inodes < inodes)
+ goto out;
+ /*
+ * Those tests also disallow limited->unlimited while any are in
+ * use, so i_blocks will always be zero when max_blocks is zero;
+ * but we must separately disallow unlimited->limited, because
+ * in that case we have no record of how much is already in use.
+ */
+ if (max_blocks && !sbinfo->max_blocks)
+ goto out;
+ if (max_inodes && !sbinfo->max_inodes)
+ goto out;
+
+ error = 0;
+ sbinfo->max_blocks = max_blocks;
+ sbinfo->free_blocks = max_blocks - blocks;
+ sbinfo->max_inodes = max_inodes;
+ sbinfo->free_inodes = max_inodes - inodes;
+out:
+ spin_unlock(&sbinfo->stat_lock);
+ return error;
}
#endif
uid_t uid = current->fsuid;
gid_t gid = current->fsgid;
int err = -ENOMEM;
-
-#ifdef CONFIG_TMPFS
+ struct shmem_sb_info *sbinfo;
unsigned long blocks = 0;
unsigned long inodes = 0;
+#ifdef CONFIG_TMPFS
/*
* Per default we only allow half of the physical ram per
* tmpfs instance, limiting inodes to one per page of lowmem;
inodes = totalram_pages - totalhigh_pages;
if (inodes > blocks)
inodes = blocks;
-
- if (shmem_parse_options(data, &mode,
- &uid, &gid, &blocks, &inodes))
+ if (shmem_parse_options(data, &mode, &uid, &gid,
+ &blocks, &inodes))
return -EINVAL;
}
-
- if (blocks || inodes) {
- struct shmem_sb_info *sbinfo;
- sbinfo = kmalloc(sizeof(struct shmem_sb_info), GFP_KERNEL);
- if (!sbinfo)
- return -ENOMEM;
- sb->s_fs_info = sbinfo;
- spin_lock_init(&sbinfo->stat_lock);
- sbinfo->max_blocks = blocks;
- sbinfo->free_blocks = blocks;
- sbinfo->max_inodes = inodes;
- sbinfo->free_inodes = inodes;
- }
- sb->s_xattr = shmem_xattr_handlers;
#else
sb->s_flags |= MS_NOUSER;
#endif
+ /* Round up to L1_CACHE_BYTES to resist false sharing */
+ sbinfo = kmalloc(max((int)sizeof(struct shmem_sb_info),
+ L1_CACHE_BYTES), GFP_KERNEL);
+ if (!sbinfo)
+ return -ENOMEM;
+
+ spin_lock_init(&sbinfo->stat_lock);
+ sbinfo->max_blocks = blocks;
+ sbinfo->free_blocks = blocks;
+ sbinfo->max_inodes = inodes;
+ sbinfo->free_inodes = inodes;
+
+ sb->s_fs_info = sbinfo;
sb->s_maxbytes = SHMEM_MAX_BYTES;
sb->s_blocksize = PAGE_CACHE_SIZE;
sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
sb->s_magic = TMPFS_MAGIC;
sb->s_op = &shmem_ops;
+ sb->s_xattr = shmem_xattr_handlers;
+
inode = shmem_get_inode(sb, S_IFDIR | mode, 0);
if (!inode)
goto failed;
}
check_irq_on();
up(&cache_chain_sem);
+ drain_remote_pages();
/* Setup the next iteration */
schedule_delayed_work(&__get_cpu_var(reap_work), REAPTIMEOUT_CPUC + smp_processor_id());
}
}
/*
- * Check if we're the only user of a swap page,
- * when the page is locked.
+ * How many references to page are currently swapped out?
*/
-static int exclusive_swap_page(struct page *page)
+static inline int page_swapcount(struct page *page)
{
- int retval = 0;
- struct swap_info_struct * p;
+ int count = 0;
+ struct swap_info_struct *p;
swp_entry_t entry;
entry.val = page->private;
p = swap_info_get(entry);
if (p) {
- /* Is the only swap cache user the cache itself? */
- if (p->swap_map[swp_offset(entry)] == 1) {
- /* Recheck the page count with the swapcache lock held.. */
- write_lock_irq(&swapper_space.tree_lock);
- if (page_count(page) == 2)
- retval = 1;
- write_unlock_irq(&swapper_space.tree_lock);
- }
+ /* Subtract the 1 for the swap cache itself */
+ count = p->swap_map[swp_offset(entry)] - 1;
swap_info_put(p);
}
- return retval;
+ return count;
}
/*
* We can use this swap cache entry directly
* if there are no other references to it.
- *
- * Here "exclusive_swap_page()" does the real
- * work, but we opportunistically check whether
- * we need to get all the locks first..
*/
int can_share_swap_page(struct page *page)
{
- int retval = 0;
+ int count;
- if (!PageLocked(page))
- BUG();
- switch (page_count(page)) {
- case 3:
- if (!PagePrivate(page))
- break;
- /* Fallthrough */
- case 2:
- if (!PageSwapCache(page))
- break;
- retval = exclusive_swap_page(page);
- break;
- case 1:
- if (PageReserved(page))
- break;
- retval = 1;
- }
- return retval;
+ BUG_ON(!PageLocked(page));
+ count = page_mapcount(page);
+ if (count <= 1 && PageSwapCache(page))
+ count += page_swapcount(page);
+ return count == 1;
}
/*
if (!down_read_trylock(&mm->mmap_sem)) {
/*
- * Our reference to the page stops try_to_unmap_one from
- * unmapping its ptes, so swapoff can make progress.
+ * Activate page so shrink_cache is unlikely to unmap its
+ * ptes while lock is dropped, so swapoff can make progress.
*/
+ activate_page(page);
unlock_page(page);
down_read(&mm->mmap_sem);
lock_page(page);
int may_writepage;
+ /* Can pages be swapped as part of reclaim? */
+ int may_swap;
+
/* This context's SWAP_CLUSTER_MAX. If freeing memory for
* suspend, we effectively ignore SWAP_CLUSTER_MAX.
* In this context, it doesn't matter that we scan the
* `lru_pages' represents the number of on-LRU pages in all the zones which
* are eligible for the caller's allocation attempt. It is used for balancing
* slab reclaim versus page reclaim.
+ *
+ * Returns the number of slab objects which we shrunk.
*/
static int shrink_slab(unsigned long scanned, unsigned int gfp_mask,
unsigned long lru_pages)
{
struct shrinker *shrinker;
+ int ret = 0;
if (scanned == 0)
scanned = SWAP_CLUSTER_MAX;
if (!down_read_trylock(&shrinker_rwsem))
- return 0;
+ return 1; /* Assume we'll be able to shrink next time */
list_for_each_entry(shrinker, &shrinker_list, list) {
unsigned long long delta;
while (total_scan >= SHRINK_BATCH) {
long this_scan = SHRINK_BATCH;
int shrink_ret;
+ int nr_before;
+ nr_before = (*shrinker->shrinker)(0, gfp_mask);
shrink_ret = (*shrinker->shrinker)(this_scan, gfp_mask);
if (shrink_ret == -1)
break;
+ if (shrink_ret < nr_before)
+ ret += nr_before - shrink_ret;
mod_page_state(slabs_scanned, this_scan);
total_scan -= this_scan;
shrinker->nr += total_scan;
}
up_read(&shrinker_rwsem);
- return 0;
+ return ret;
}
/* Called without lock on whether page is mapped, so answer is unstable */
* Anonymous process memory has backing store?
* Try to allocate it some swap space here.
*/
- if (PageAnon(page) && !PageSwapCache(page)) {
+ if (PageAnon(page) && !PageSwapCache(page) && sc->may_swap) {
if (!add_to_swap(page))
goto activate_locked;
}
if (zone->all_unreclaimable && sc->priority != DEF_PRIORITY)
continue; /* Let kswapd poll it */
+ atomic_inc(&zone->reclaim_in_progress);
shrink_zone(zone, sc);
+ atomic_dec(&zone->reclaim_in_progress);
}
}
* holds filesystem locks which prevent writeout this might not work, and the
* allocation attempt will fail.
*/
-int try_to_free_pages(struct zone **zones,
- unsigned int gfp_mask, unsigned int order)
+int try_to_free_pages(struct zone **zones, unsigned int gfp_mask)
{
int priority;
int ret = 0;
sc.gfp_mask = gfp_mask;
sc.may_writepage = 0;
+ sc.may_swap = 1;
inc_page_state(allocstall);
total_reclaimed = 0;
sc.gfp_mask = GFP_KERNEL;
sc.may_writepage = 0;
+ sc.may_swap = 1;
sc.nr_mapped = read_page_state(nr_mapped);
inc_page_state(pageoutrun);
*/
for (i = 0; i <= end_zone; i++) {
struct zone *zone = pgdat->node_zones + i;
+ int nr_slab;
if (zone->present_pages == 0)
continue;
sc.nr_reclaimed = 0;
sc.priority = priority;
sc.swap_cluster_max = nr_pages? nr_pages : SWAP_CLUSTER_MAX;
+ atomic_inc(&zone->reclaim_in_progress);
shrink_zone(zone, &sc);
+ atomic_dec(&zone->reclaim_in_progress);
reclaim_state->reclaimed_slab = 0;
- shrink_slab(sc.nr_scanned, GFP_KERNEL, lru_pages);
+ nr_slab = shrink_slab(sc.nr_scanned, GFP_KERNEL,
+ lru_pages);
sc.nr_reclaimed += reclaim_state->reclaimed_slab;
total_reclaimed += sc.nr_reclaimed;
total_scanned += sc.nr_scanned;
if (zone->all_unreclaimable)
continue;
- if (zone->pages_scanned >= (zone->nr_active +
- zone->nr_inactive) * 4)
+ if (nr_slab == 0 && zone->pages_scanned >=
+ (zone->nr_active + zone->nr_inactive) * 4)
zone->all_unreclaimable = 1;
/*
* If we've done a decent amount of scanning and
}
module_init(kswapd_init)
+
+
+/*
+ * Try to free up some pages from this zone through reclaim.
+ */
+int zone_reclaim(struct zone *zone, unsigned int gfp_mask, unsigned int order)
+{
+ struct scan_control sc;
+ int nr_pages = 1 << order;
+ int total_reclaimed = 0;
+
+ /* The reclaim may sleep, so don't do it if sleep isn't allowed */
+ if (!(gfp_mask & __GFP_WAIT))
+ return 0;
+ if (zone->all_unreclaimable)
+ return 0;
+
+ sc.gfp_mask = gfp_mask;
+ sc.may_writepage = 0;
+ sc.may_swap = 0;
+ sc.nr_mapped = read_page_state(nr_mapped);
+ sc.nr_scanned = 0;
+ sc.nr_reclaimed = 0;
+ /* scan at the highest priority */
+ sc.priority = 0;
+
+ if (nr_pages > SWAP_CLUSTER_MAX)
+ sc.swap_cluster_max = nr_pages;
+ else
+ sc.swap_cluster_max = SWAP_CLUSTER_MAX;
+
+ /* Don't reclaim the zone if there are other reclaimers active */
+ if (!atomic_inc_and_test(&zone->reclaim_in_progress))
+ goto out;
+
+ shrink_zone(zone, &sc);
+ total_reclaimed = sc.nr_reclaimed;
+
+ out:
+ atomic_dec(&zone->reclaim_in_progress);
+ return total_reclaimed;
+}
+
+asmlinkage long sys_set_zone_reclaim(unsigned int node, unsigned int zone,
+ unsigned int state)
+{
+ struct zone *z;
+ int i;
+
+ if (node >= MAX_NUMNODES || !node_online(node))
+ return -EINVAL;
+
+ /* This will break if we ever add more zones */
+ if (!(zone & (1<<ZONE_DMA|1<<ZONE_NORMAL|1<<ZONE_HIGHMEM)))
+ return -EINVAL;
+
+ for (i = 0; i < MAX_NR_ZONES; i++) {
+ if (!(zone & 1<<i))
+ continue;
+
+ z = &NODE_DATA(node)->node_zones[i];
+
+ if (state)
+ z->reclaim_pages = 1;
+ else
+ z->reclaim_pages = 0;
+ }
+
+ return 0;
+}
# IP configuration
#
choice
- prompt "Choose IP: FIB lookup""
+ prompt "Choose IP: FIB lookup"
depends on INET
default IP_FIB_HASH
} while (*in_end++);
copy_page(in_save, nosec_save);
+ free_page((unsigned long)nosec_save);
out:
return rc;
}
config SND
tristate "Advanced Linux Sound Architecture"
depends on SOUND
+ help
+ Say 'Y' or 'M' to enable ALSA (Advanced Linux Sound Architecture),
+ the new base sound system.
+
+ For more information, see <http://www.alsa-project.org/>
source "sound/core/Kconfig"
To compile this driver as a module, choose M here: the module
will be called snd-sa11xx-uda1341.
+config SND_ARMAACI
+ tristate "ARM PrimeCell PL041 AC Link support"
+ depends on SND && ARM_AMBA
+ select SND_PCM
+ select SND_AC97_CODEC
+
endmenu
# Toplevel Module Dependency
obj-$(CONFIG_SND_SA11XX_UDA1341) += snd-sa11xx-uda1341.o
+
+obj-$(CONFIG_SND_ARMAACI) += snd-aaci.o
+snd-aaci-objs := aaci.o devdma.o
--- /dev/null
+/*
+ * linux/sound/arm/aaci.c - ARM PrimeCell AACI PL041 driver
+ *
+ * Copyright (C) 2003 Deep Blue Solutions Ltd, All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Documentation: ARM DDI 0173B
+ */
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/hardware/amba.h>
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/ac97_codec.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+
+#include "aaci.h"
+#include "devdma.h"
+
+#define DRIVER_NAME "aaci-pl041"
+
+/*
+ * PM support is not complete. Turn it off.
+ */
+#undef CONFIG_PM
+
+static void aaci_ac97_select_codec(struct aaci *aaci, ac97_t *ac97)
+{
+ u32 v, maincr = aaci->maincr | MAINCR_SCRA(ac97->num);
+
+ /*
+ * Ensure that the slot 1/2 RX registers are empty.
+ */
+ v = readl(aaci->base + AACI_SLFR);
+ if (v & SLFR_2RXV)
+ readl(aaci->base + AACI_SL2RX);
+ if (v & SLFR_1RXV)
+ readl(aaci->base + AACI_SL1RX);
+
+ writel(maincr, aaci->base + AACI_MAINCR);
+}
+
+/*
+ * P29:
+ * The recommended use of programming the external codec through slot 1
+ * and slot 2 data is to use the channels during setup routines and the
+ * slot register at any other time. The data written into slot 1, slot 2
+ * and slot 12 registers is transmitted only when their corresponding
+ * SI1TxEn, SI2TxEn and SI12TxEn bits are set in the AACI_MAINCR
+ * register.
+ */
+static void aaci_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short val)
+{
+ struct aaci *aaci = ac97->private_data;
+ u32 v;
+
+ if (ac97->num >= 4)
+ return;
+
+ down(&aaci->ac97_sem);
+
+ aaci_ac97_select_codec(aaci, ac97);
+
+ /*
+ * P54: You must ensure that AACI_SL2TX is always written
+ * to, if required, before data is written to AACI_SL1TX.
+ */
+ writel(val << 4, aaci->base + AACI_SL2TX);
+ writel(reg << 12, aaci->base + AACI_SL1TX);
+
+ /*
+ * Wait for the transmission of both slots to complete.
+ */
+ do {
+ v = readl(aaci->base + AACI_SLFR);
+ } while (v & (SLFR_1TXB|SLFR_2TXB));
+
+ up(&aaci->ac97_sem);
+}
+
+/*
+ * Read an AC'97 register.
+ */
+static unsigned short aaci_ac97_read(ac97_t *ac97, unsigned short reg)
+{
+ struct aaci *aaci = ac97->private_data;
+ u32 v;
+
+ if (ac97->num >= 4)
+ return ~0;
+
+ down(&aaci->ac97_sem);
+
+ aaci_ac97_select_codec(aaci, ac97);
+
+ /*
+ * Write the register address to slot 1.
+ */
+ writel((reg << 12) | (1 << 19), aaci->base + AACI_SL1TX);
+
+ /*
+ * Wait for the transmission to complete.
+ */
+ do {
+ v = readl(aaci->base + AACI_SLFR);
+ } while (v & SLFR_1TXB);
+
+ /*
+ * Give the AC'97 codec more than enough time
+ * to respond. (42us = ~2 frames at 48kHz.)
+ */
+ udelay(42);
+
+ /*
+ * Wait for slot 2 to indicate data.
+ */
+ do {
+ cond_resched();
+ v = readl(aaci->base + AACI_SLFR) & (SLFR_1RXV|SLFR_2RXV);
+ } while (v != (SLFR_1RXV|SLFR_2RXV));
+
+ v = readl(aaci->base + AACI_SL1RX) >> 12;
+ if (v == reg) {
+ v = readl(aaci->base + AACI_SL2RX) >> 4;
+ } else {
+ dev_err(&aaci->dev->dev,
+ "wrong ac97 register read back (%x != %x)\n",
+ v, reg);
+ v = ~0;
+ }
+
+ up(&aaci->ac97_sem);
+ return v;
+}
+
+static inline void aaci_chan_wait_ready(struct aaci_runtime *aacirun)
+{
+ u32 val;
+ int timeout = 5000;
+
+ do {
+ val = readl(aacirun->base + AACI_SR);
+ } while (val & (SR_TXB|SR_RXB) && timeout--);
+}
+
+
+
+/*
+ * Interrupt support.
+ */
+static void aaci_fifo_irq(struct aaci *aaci, u32 mask)
+{
+ if (mask & ISR_URINTR) {
+ writel(ICLR_TXUEC1, aaci->base + AACI_INTCLR);
+ }
+
+ if (mask & ISR_TXINTR) {
+ struct aaci_runtime *aacirun = &aaci->playback;
+ void *ptr;
+
+ if (!aacirun->substream || !aacirun->start) {
+ dev_warn(&aaci->dev->dev, "TX interrupt???");
+ writel(0, aacirun->base + AACI_IE);
+ return;
+ }
+
+ ptr = aacirun->ptr;
+ do {
+ unsigned int len = aacirun->fifosz;
+ u32 val;
+
+ if (aacirun->bytes <= 0) {
+ aacirun->bytes += aacirun->period;
+ aacirun->ptr = ptr;
+ spin_unlock(&aaci->lock);
+ snd_pcm_period_elapsed(aacirun->substream);
+ spin_lock(&aaci->lock);
+ }
+ if (!(aacirun->cr & TXCR_TXEN))
+ break;
+
+ val = readl(aacirun->base + AACI_SR);
+ if (!(val & SR_TXHE))
+ break;
+ if (!(val & SR_TXFE))
+ len >>= 1;
+
+ aacirun->bytes -= len;
+
+ /* writing 16 bytes at a time */
+ for ( ; len > 0; len -= 16) {
+ asm(
+ "ldmia %0!, {r0, r1, r2, r3}\n\t"
+ "stmia %1, {r0, r1, r2, r3}"
+ : "+r" (ptr)
+ : "r" (aacirun->fifo)
+ : "r0", "r1", "r2", "r3", "cc");
+
+ if (ptr >= aacirun->end)
+ ptr = aacirun->start;
+ }
+ } while (1);
+
+ aacirun->ptr = ptr;
+ }
+}
+
+static irqreturn_t aaci_irq(int irq, void *devid, struct pt_regs *regs)
+{
+ struct aaci *aaci = devid;
+ u32 mask;
+ int i;
+
+ spin_lock(&aaci->lock);
+ mask = readl(aaci->base + AACI_ALLINTS);
+ if (mask) {
+ u32 m = mask;
+ for (i = 0; i < 4; i++, m >>= 7) {
+ if (m & 0x7f) {
+ aaci_fifo_irq(aaci, m);
+ }
+ }
+ }
+ spin_unlock(&aaci->lock);
+
+ return mask ? IRQ_HANDLED : IRQ_NONE;
+}
+
+
+
+/*
+ * ALSA support.
+ */
+
+struct aaci_stream {
+ unsigned char codec_idx;
+ unsigned char rate_idx;
+};
+
+static struct aaci_stream aaci_streams[] = {
+ [ACSTREAM_FRONT] = {
+ .codec_idx = 0,
+ .rate_idx = AC97_RATES_FRONT_DAC,
+ },
+ [ACSTREAM_SURROUND] = {
+ .codec_idx = 0,
+ .rate_idx = AC97_RATES_SURR_DAC,
+ },
+ [ACSTREAM_LFE] = {
+ .codec_idx = 0,
+ .rate_idx = AC97_RATES_LFE_DAC,
+ },
+};
+
+static inline unsigned int aaci_rate_mask(struct aaci *aaci, int streamid)
+{
+ struct aaci_stream *s = aaci_streams + streamid;
+ return aaci->ac97_bus->codec[s->codec_idx]->rates[s->rate_idx];
+}
+
+static unsigned int rate_list[] = {
+ 5512, 8000, 11025, 16000, 22050, 32000, 44100,
+ 48000, 64000, 88200, 96000, 176400, 192000
+};
+
+/*
+ * Double-rate rule: we can support double rate iff channels == 2
+ * (unimplemented)
+ */
+static int
+aaci_rule_rate_by_channels(snd_pcm_hw_params_t *p, snd_pcm_hw_rule_t *rule)
+{
+ struct aaci *aaci = rule->private;
+ unsigned int rate_mask = SNDRV_PCM_RATE_8000_48000|SNDRV_PCM_RATE_5512;
+ snd_interval_t *c = hw_param_interval(p, SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ switch (c->max) {
+ case 6:
+ rate_mask &= aaci_rate_mask(aaci, ACSTREAM_LFE);
+ case 4:
+ rate_mask &= aaci_rate_mask(aaci, ACSTREAM_SURROUND);
+ case 2:
+ rate_mask &= aaci_rate_mask(aaci, ACSTREAM_FRONT);
+ }
+
+ return snd_interval_list(hw_param_interval(p, rule->var),
+ ARRAY_SIZE(rate_list), rate_list,
+ rate_mask);
+}
+
+static snd_pcm_hardware_t aaci_hw_info = {
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_RESUME,
+
+ /*
+ * ALSA doesn't support 18-bit or 20-bit packed into 32-bit
+ * words. It also doesn't support 12-bit at all.
+ */
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+
+ /* should this be continuous or knot? */
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ .rate_max = 48000,
+ .rate_min = 4000,
+ .channels_min = 2,
+ .channels_max = 6,
+ .buffer_bytes_max = 64 * 1024,
+ .period_bytes_min = 256,
+ .period_bytes_max = PAGE_SIZE,
+ .periods_min = 4,
+ .periods_max = PAGE_SIZE / 16,
+};
+
+static int aaci_pcm_open(struct aaci *aaci, snd_pcm_substream_t *substream,
+ struct aaci_runtime *aacirun)
+{
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ int ret;
+
+ aacirun->substream = substream;
+ runtime->private_data = aacirun;
+ runtime->hw = aaci_hw_info;
+
+ /*
+ * FIXME: ALSA specifies fifo_size in bytes. If we're in normal
+ * mode, each 32-bit word contains one sample. If we're in
+ * compact mode, each 32-bit word contains two samples, effectively
+ * halving the FIFO size. However, we don't know for sure which
+ * we'll be using at this point. We set this to the lower limit.
+ */
+ runtime->hw.fifo_size = aaci->fifosize * 2;
+
+ /*
+ * Add rule describing hardware rate dependency
+ * on the number of channels.
+ */
+ ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+ aaci_rule_rate_by_channels, aaci,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ SNDRV_PCM_HW_PARAM_RATE, -1);
+ if (ret)
+ goto out;
+
+ ret = request_irq(aaci->dev->irq[0], aaci_irq, SA_SHIRQ|SA_INTERRUPT,
+ DRIVER_NAME, aaci);
+ if (ret)
+ goto out;
+
+ return 0;
+
+ out:
+ return ret;
+}
+
+
+/*
+ * Common ALSA stuff
+ */
+static int aaci_pcm_close(snd_pcm_substream_t *substream)
+{
+ struct aaci *aaci = substream->private_data;
+ struct aaci_runtime *aacirun = substream->runtime->private_data;
+
+ WARN_ON(aacirun->cr & TXCR_TXEN);
+
+ aacirun->substream = NULL;
+ free_irq(aaci->dev->irq[0], aaci);
+
+ return 0;
+}
+
+static int aaci_pcm_hw_free(snd_pcm_substream_t *substream)
+{
+ struct aaci_runtime *aacirun = substream->runtime->private_data;
+
+ /*
+ * This must not be called with the device enabled.
+ */
+ WARN_ON(aacirun->cr & TXCR_TXEN);
+
+ if (aacirun->pcm_open)
+ snd_ac97_pcm_close(aacirun->pcm);
+ aacirun->pcm_open = 0;
+
+ /*
+ * Clear out the DMA and any allocated buffers.
+ */
+ devdma_hw_free(NULL, substream);
+
+ return 0;
+}
+
+static int aaci_pcm_hw_params(snd_pcm_substream_t *substream,
+ struct aaci_runtime *aacirun,
+ snd_pcm_hw_params_t *params)
+{
+ int err;
+
+ aaci_pcm_hw_free(substream);
+
+ err = devdma_hw_alloc(NULL, substream,
+ params_buffer_bytes(params));
+ if (err < 0)
+ goto out;
+
+ err = snd_ac97_pcm_open(aacirun->pcm, params_rate(params),
+ params_channels(params),
+ aacirun->pcm->r[0].slots);
+ if (err)
+ goto out;
+
+ aacirun->pcm_open = 1;
+
+ out:
+ return err;
+}
+
+static int aaci_pcm_prepare(snd_pcm_substream_t *substream)
+{
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ struct aaci_runtime *aacirun = runtime->private_data;
+
+ aacirun->start = (void *)runtime->dma_area;
+ aacirun->end = aacirun->start + runtime->dma_bytes;
+ aacirun->ptr = aacirun->start;
+ aacirun->period =
+ aacirun->bytes = frames_to_bytes(runtime, runtime->period_size);
+
+ return 0;
+}
+
+static snd_pcm_uframes_t aaci_pcm_pointer(snd_pcm_substream_t *substream)
+{
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ struct aaci_runtime *aacirun = runtime->private_data;
+ ssize_t bytes = aacirun->ptr - aacirun->start;
+
+ return bytes_to_frames(runtime, bytes);
+}
+
+static int aaci_pcm_mmap(snd_pcm_substream_t *substream, struct vm_area_struct *vma)
+{
+ return devdma_mmap(NULL, substream, vma);
+}
+
+
+/*
+ * Playback specific ALSA stuff
+ */
+static const u32 channels_to_txmask[] = {
+ [2] = TXCR_TX3 | TXCR_TX4,
+ [4] = TXCR_TX3 | TXCR_TX4 | TXCR_TX7 | TXCR_TX8,
+ [6] = TXCR_TX3 | TXCR_TX4 | TXCR_TX7 | TXCR_TX8 | TXCR_TX6 | TXCR_TX9,
+};
+
+/*
+ * We can support two and four channel audio. Unfortunately
+ * six channel audio requires a non-standard channel ordering:
+ * 2 -> FL(3), FR(4)
+ * 4 -> FL(3), FR(4), SL(7), SR(8)
+ * 6 -> FL(3), FR(4), SL(7), SR(8), C(6), LFE(9) (required)
+ * FL(3), FR(4), C(6), SL(7), SR(8), LFE(9) (actual)
+ * This requires an ALSA configuration file to correct.
+ */
+static unsigned int channel_list[] = { 2, 4, 6 };
+
+static int
+aaci_rule_channels(snd_pcm_hw_params_t *p, snd_pcm_hw_rule_t *rule)
+{
+ struct aaci *aaci = rule->private;
+ unsigned int chan_mask = 1 << 0, slots;
+
+ /*
+ * pcms[0] is the our 5.1 PCM instance.
+ */
+ slots = aaci->ac97_bus->pcms[0].r[0].slots;
+ if (slots & (1 << AC97_SLOT_PCM_SLEFT)) {
+ chan_mask |= 1 << 1;
+ if (slots & (1 << AC97_SLOT_LFE))
+ chan_mask |= 1 << 2;
+ }
+
+ return snd_interval_list(hw_param_interval(p, rule->var),
+ ARRAY_SIZE(channel_list), channel_list,
+ chan_mask);
+}
+
+static int aaci_pcm_playback_open(snd_pcm_substream_t *substream)
+{
+ struct aaci *aaci = substream->private_data;
+ int ret;
+
+ /*
+ * Add rule describing channel dependency.
+ */
+ ret = snd_pcm_hw_rule_add(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ aaci_rule_channels, aaci,
+ SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+ if (ret)
+ return ret;
+
+ return aaci_pcm_open(aaci, substream, &aaci->playback);
+}
+
+static int aaci_pcm_playback_hw_params(snd_pcm_substream_t *substream,
+ snd_pcm_hw_params_t *params)
+{
+ struct aaci *aaci = substream->private_data;
+ struct aaci_runtime *aacirun = substream->runtime->private_data;
+ unsigned int channels = params_channels(params);
+ int ret;
+
+ WARN_ON(channels >= ARRAY_SIZE(channels_to_txmask) ||
+ !channels_to_txmask[channels]);
+
+ ret = aaci_pcm_hw_params(substream, aacirun, params);
+
+ /*
+ * Enable FIFO, compact mode, 16 bits per sample.
+ * FIXME: double rate slots?
+ */
+ if (ret >= 0) {
+ aacirun->cr = TXCR_FEN | TXCR_COMPACT | TXCR_TSZ16;
+ aacirun->cr |= channels_to_txmask[channels];
+
+ aacirun->fifosz = aaci->fifosize * 4;
+ if (aacirun->cr & TXCR_COMPACT)
+ aacirun->fifosz >>= 1;
+ }
+ return ret;
+}
+
+static void aaci_pcm_playback_stop(struct aaci_runtime *aacirun)
+{
+ u32 ie;
+
+ ie = readl(aacirun->base + AACI_IE);
+ ie &= ~(IE_URIE|IE_TXIE);
+ writel(ie, aacirun->base + AACI_IE);
+ aacirun->cr &= ~TXCR_TXEN;
+ aaci_chan_wait_ready(aacirun);
+ writel(aacirun->cr, aacirun->base + AACI_TXCR);
+}
+
+static void aaci_pcm_playback_start(struct aaci_runtime *aacirun)
+{
+ u32 ie;
+
+ aaci_chan_wait_ready(aacirun);
+ aacirun->cr |= TXCR_TXEN;
+
+ ie = readl(aacirun->base + AACI_IE);
+ ie |= IE_URIE | IE_TXIE;
+ writel(ie, aacirun->base + AACI_IE);
+ writel(aacirun->cr, aacirun->base + AACI_TXCR);
+}
+
+static int aaci_pcm_playback_trigger(snd_pcm_substream_t *substream, int cmd)
+{
+ struct aaci *aaci = substream->private_data;
+ struct aaci_runtime *aacirun = substream->runtime->private_data;
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&aaci->lock, flags);
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ aaci_pcm_playback_start(aacirun);
+ break;
+
+ case SNDRV_PCM_TRIGGER_RESUME:
+ aaci_pcm_playback_start(aacirun);
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ aaci_pcm_playback_stop(aacirun);
+ break;
+
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ aaci_pcm_playback_stop(aacirun);
+ break;
+
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ break;
+
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ break;
+
+ default:
+ ret = -EINVAL;
+ }
+ spin_unlock_irqrestore(&aaci->lock, flags);
+
+ return ret;
+}
+
+static snd_pcm_ops_t aaci_playback_ops = {
+ .open = aaci_pcm_playback_open,
+ .close = aaci_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = aaci_pcm_playback_hw_params,
+ .hw_free = aaci_pcm_hw_free,
+ .prepare = aaci_pcm_prepare,
+ .trigger = aaci_pcm_playback_trigger,
+ .pointer = aaci_pcm_pointer,
+ .mmap = aaci_pcm_mmap,
+};
+
+
+
+/*
+ * Power Management.
+ */
+#ifdef CONFIG_PM
+static int aaci_do_suspend(snd_card_t *card, unsigned int state)
+{
+ struct aaci *aaci = card->private_data;
+ if (aaci->card->power_state != SNDRV_CTL_POWER_D3cold) {
+ snd_pcm_suspend_all(aaci->pcm);
+ snd_power_change_state(aaci->card, SNDRV_CTL_POWER_D3cold);
+ }
+ return 0;
+}
+
+static int aaci_do_resume(snd_card_t *card, unsigned int state)
+{
+ struct aaci *aaci = card->private_data;
+ if (aaci->card->power_state != SNDRV_CTL_POWER_D0) {
+ snd_power_change_state(aaci->card, SNDRV_CTL_POWER_D0);
+ }
+ return 0;
+}
+
+static int aaci_suspend(struct amba_device *dev, u32 state)
+{
+ snd_card_t *card = amba_get_drvdata(dev);
+ return card ? aaci_do_suspend(card) : 0;
+}
+
+static int aaci_resume(struct amba_device *dev)
+{
+ snd_card_t *card = amba_get_drvdata(dev);
+ return card ? aaci_do_resume(card) : 0;
+}
+#else
+#define aaci_do_suspend NULL
+#define aaci_do_resume NULL
+#define aaci_suspend NULL
+#define aaci_resume NULL
+#endif
+
+
+static struct ac97_pcm ac97_defs[] __devinitdata = {
+ [0] = { /* Front PCM */
+ .exclusive = 1,
+ .r = {
+ [0] = {
+ .slots = (1 << AC97_SLOT_PCM_LEFT) |
+ (1 << AC97_SLOT_PCM_RIGHT) |
+ (1 << AC97_SLOT_PCM_CENTER) |
+ (1 << AC97_SLOT_PCM_SLEFT) |
+ (1 << AC97_SLOT_PCM_SRIGHT) |
+ (1 << AC97_SLOT_LFE),
+ },
+ },
+ },
+ [1] = { /* PCM in */
+ .stream = 1,
+ .exclusive = 1,
+ .r = {
+ [0] = {
+ .slots = (1 << AC97_SLOT_PCM_LEFT) |
+ (1 << AC97_SLOT_PCM_RIGHT),
+ },
+ },
+ },
+ [2] = { /* Mic in */
+ .stream = 1,
+ .exclusive = 1,
+ .r = {
+ [0] = {
+ .slots = (1 << AC97_SLOT_MIC),
+ },
+ },
+ }
+};
+
+static ac97_bus_ops_t aaci_bus_ops = {
+ .write = aaci_ac97_write,
+ .read = aaci_ac97_read,
+};
+
+static int __devinit aaci_probe_ac97(struct aaci *aaci)
+{
+ ac97_template_t ac97_template;
+ ac97_bus_t *ac97_bus;
+ ac97_t *ac97;
+ int ret;
+
+ /*
+ * Assert AACIRESET for 2us
+ */
+ writel(0, aaci->base + AACI_RESET);
+ udelay(2);
+ writel(RESET_NRST, aaci->base + AACI_RESET);
+
+ /*
+ * Give the AC'97 codec more than enough time
+ * to wake up. (42us = ~2 frames at 48kHz.)
+ */
+ udelay(42);
+
+ ret = snd_ac97_bus(aaci->card, 0, &aaci_bus_ops, aaci, &ac97_bus);
+ if (ret)
+ goto out;
+
+ ac97_bus->clock = 48000;
+ aaci->ac97_bus = ac97_bus;
+
+ memset(&ac97_template, 0, sizeof(ac97_template_t));
+ ac97_template.private_data = aaci;
+ ac97_template.num = 0;
+ ac97_template.scaps = AC97_SCAP_SKIP_MODEM;
+
+ ret = snd_ac97_mixer(ac97_bus, &ac97_template, &ac97);
+ if (ret)
+ goto out;
+
+ /*
+ * Disable AC97 PC Beep input on audio codecs.
+ */
+ if (ac97_is_audio(ac97))
+ snd_ac97_write_cache(ac97, AC97_PC_BEEP, 0x801e);
+
+ ret = snd_ac97_pcm_assign(ac97_bus, ARRAY_SIZE(ac97_defs), ac97_defs);
+ if (ret)
+ goto out;
+
+ aaci->playback.pcm = &ac97_bus->pcms[0];
+
+ out:
+ return ret;
+}
+
+static void aaci_free_card(snd_card_t *card)
+{
+ struct aaci *aaci = card->private_data;
+ if (aaci->base)
+ iounmap(aaci->base);
+}
+
+static struct aaci * __devinit aaci_init_card(struct amba_device *dev)
+{
+ struct aaci *aaci;
+ snd_card_t *card;
+
+ card = snd_card_new(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+ THIS_MODULE, sizeof(struct aaci));
+ if (card == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ card->private_free = aaci_free_card;
+ snd_card_set_pm_callback(card, aaci_do_suspend, aaci_do_resume, NULL);
+
+ strlcpy(card->driver, DRIVER_NAME, sizeof(card->driver));
+ strlcpy(card->shortname, "ARM AC'97 Interface", sizeof(card->shortname));
+ snprintf(card->longname, sizeof(card->longname),
+ "%s at 0x%08lx, irq %d",
+ card->shortname, dev->res.start, dev->irq[0]);
+
+ aaci = card->private_data;
+ init_MUTEX(&aaci->ac97_sem);
+ spin_lock_init(&aaci->lock);
+ aaci->card = card;
+ aaci->dev = dev;
+
+ /* Set MAINCR to allow slot 1 and 2 data IO */
+ aaci->maincr = MAINCR_IE | MAINCR_SL1RXEN | MAINCR_SL1TXEN |
+ MAINCR_SL2RXEN | MAINCR_SL2TXEN;
+
+ return aaci;
+}
+
+static int __devinit aaci_init_pcm(struct aaci *aaci)
+{
+ snd_pcm_t *pcm;
+ int ret;
+
+ ret = snd_pcm_new(aaci->card, "AACI AC'97", 0, 1, 0, &pcm);
+ if (ret == 0) {
+ aaci->pcm = pcm;
+ pcm->private_data = aaci;
+ pcm->info_flags = 0;
+
+ strlcpy(pcm->name, DRIVER_NAME, sizeof(pcm->name));
+
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &aaci_playback_ops);
+ }
+
+ return ret;
+}
+
+static unsigned int __devinit aaci_size_fifo(struct aaci *aaci)
+{
+ void *base = aaci->base + AACI_CSCH1;
+ int i;
+
+ writel(TXCR_FEN | TXCR_TSZ16 | TXCR_TXEN, base + AACI_TXCR);
+
+ for (i = 0; !(readl(base + AACI_SR) & SR_TXFF) && i < 4096; i++)
+ writel(0, aaci->base + AACI_DR1);
+
+ writel(0, base + AACI_TXCR);
+
+ /*
+ * Re-initialise the AACI after the FIFO depth test, to
+ * ensure that the FIFOs are empty. Unfortunately, merely
+ * disabling the channel doesn't clear the FIFO.
+ */
+ writel(aaci->maincr & ~MAINCR_IE, aaci->base + AACI_MAINCR);
+ writel(aaci->maincr, aaci->base + AACI_MAINCR);
+
+ /*
+ * If we hit 4096, we failed. Go back to the specified
+ * fifo depth.
+ */
+ if (i == 4096)
+ i = 8;
+
+ return i;
+}
+
+static int __devinit aaci_probe(struct amba_device *dev, void *id)
+{
+ struct aaci *aaci;
+ int ret, i;
+
+ ret = amba_request_regions(dev, NULL);
+ if (ret)
+ return ret;
+
+ aaci = aaci_init_card(dev);
+ if (IS_ERR(aaci)) {
+ ret = PTR_ERR(aaci);
+ goto out;
+ }
+
+ aaci->base = ioremap(dev->res.start, SZ_4K);
+ if (!aaci->base) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /*
+ * Playback uses AACI channel 0
+ */
+ aaci->playback.base = aaci->base + AACI_CSCH1;
+ aaci->playback.fifo = aaci->base + AACI_DR1;
+
+ for (i = 0; i < 4; i++) {
+ void *base = aaci->base + i * 0x14;
+
+ writel(0, base + AACI_IE);
+ writel(0, base + AACI_TXCR);
+ writel(0, base + AACI_RXCR);
+ }
+
+ writel(0x1fff, aaci->base + AACI_INTCLR);
+ writel(aaci->maincr, aaci->base + AACI_MAINCR);
+
+ /*
+ * Size the FIFOs.
+ */
+ aaci->fifosize = aaci_size_fifo(aaci);
+
+ ret = aaci_probe_ac97(aaci);
+ if (ret)
+ goto out;
+
+ ret = aaci_init_pcm(aaci);
+ if (ret)
+ goto out;
+
+ ret = snd_card_register(aaci->card);
+ if (ret == 0) {
+ dev_info(&dev->dev, "%s, fifo %d\n", aaci->card->longname,
+ aaci->fifosize);
+ amba_set_drvdata(dev, aaci->card);
+ return ret;
+ }
+
+ out:
+ if (aaci)
+ snd_card_free(aaci->card);
+ amba_release_regions(dev);
+ return ret;
+}
+
+static int __devexit aaci_remove(struct amba_device *dev)
+{
+ snd_card_t *card = amba_get_drvdata(dev);
+
+ amba_set_drvdata(dev, NULL);
+
+ if (card) {
+ struct aaci *aaci = card->private_data;
+ writel(0, aaci->base + AACI_MAINCR);
+
+ snd_card_free(card);
+ amba_release_regions(dev);
+ }
+
+ return 0;
+}
+
+static struct amba_id aaci_ids[] = {
+ {
+ .id = 0x00041041,
+ .mask = 0x000fffff,
+ },
+ { 0, 0 },
+};
+
+static struct amba_driver aaci_driver = {
+ .drv = {
+ .name = DRIVER_NAME,
+ },
+ .probe = aaci_probe,
+ .remove = __devexit_p(aaci_remove),
+ .suspend = aaci_suspend,
+ .resume = aaci_resume,
+ .id_table = aaci_ids,
+};
+
+static int __init aaci_init(void)
+{
+ return amba_driver_register(&aaci_driver);
+}
+
+static void __exit aaci_exit(void)
+{
+ amba_driver_unregister(&aaci_driver);
+}
+
+module_init(aaci_init);
+module_exit(aaci_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("ARM PrimeCell PL041 Advanced Audio CODEC Interface driver");
--- /dev/null
+/*
+ * linux/sound/arm/aaci.c - ARM PrimeCell AACI PL041 driver
+ *
+ * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef AACI_H
+#define AACI_H
+
+/*
+ * Control and status register offsets
+ * P39.
+ */
+#define AACI_CSCH1 0x000
+#define AACI_CSCH2 0x014
+#define AACI_CSCH3 0x028
+#define AACI_CSCH4 0x03c
+
+#define AACI_RXCR 0x000 /* 29 bits Control Rx FIFO */
+#define AACI_TXCR 0x004 /* 17 bits Control Tx FIFO */
+#define AACI_SR 0x008 /* 12 bits Status */
+#define AACI_ISR 0x00c /* 7 bits Int Status */
+#define AACI_IE 0x010 /* 7 bits Int Enable */
+
+/*
+ * Other registers
+ */
+#define AACI_SL1RX 0x050
+#define AACI_SL1TX 0x054
+#define AACI_SL2RX 0x058
+#define AACI_SL2TX 0x05c
+#define AACI_SL12RX 0x060
+#define AACI_SL12TX 0x064
+#define AACI_SLFR 0x068 /* slot flags */
+#define AACI_SLISTAT 0x06c /* slot interrupt status */
+#define AACI_SLIEN 0x070 /* slot interrupt enable */
+#define AACI_INTCLR 0x074 /* interrupt clear */
+#define AACI_MAINCR 0x078 /* main control */
+#define AACI_RESET 0x07c /* reset control */
+#define AACI_SYNC 0x080 /* sync control */
+#define AACI_ALLINTS 0x084 /* all fifo interrupt status */
+#define AACI_MAINFR 0x088 /* main flag register */
+#define AACI_DR1 0x090 /* data read/written fifo 1 */
+#define AACI_DR2 0x0b0 /* data read/written fifo 2 */
+#define AACI_DR3 0x0d0 /* data read/written fifo 3 */
+#define AACI_DR4 0x0f0 /* data read/written fifo 4 */
+
+/*
+ * transmit fifo control register. P48
+ */
+#define TXCR_FEN (1 << 16) /* fifo enable */
+#define TXCR_COMPACT (1 << 15) /* compact mode */
+#define TXCR_TSZ16 (0 << 13) /* 16 bits */
+#define TXCR_TSZ18 (1 << 13) /* 18 bits */
+#define TXCR_TSZ20 (2 << 13) /* 20 bits */
+#define TXCR_TSZ12 (3 << 13) /* 12 bits */
+#define TXCR_TX12 (1 << 12) /* transmits slot 12 */
+#define TXCR_TX11 (1 << 11) /* transmits slot 12 */
+#define TXCR_TX10 (1 << 10) /* transmits slot 12 */
+#define TXCR_TX9 (1 << 9) /* transmits slot 12 */
+#define TXCR_TX8 (1 << 8) /* transmits slot 12 */
+#define TXCR_TX7 (1 << 7) /* transmits slot 12 */
+#define TXCR_TX6 (1 << 6) /* transmits slot 12 */
+#define TXCR_TX5 (1 << 5) /* transmits slot 12 */
+#define TXCR_TX4 (1 << 4) /* transmits slot 12 */
+#define TXCR_TX3 (1 << 3) /* transmits slot 12 */
+#define TXCR_TX2 (1 << 2) /* transmits slot 12 */
+#define TXCR_TX1 (1 << 1) /* transmits slot 12 */
+#define TXCR_TXEN (1 << 0) /* transmit enable */
+
+/*
+ * status register bits. P49
+ */
+#define SR_RXTOFE (1 << 11) /* rx timeout fifo empty */
+#define SR_TXTO (1 << 10) /* rx timeout fifo nonempty */
+#define SR_TXU (1 << 9) /* tx underrun */
+#define SR_RXO (1 << 8) /* rx overrun */
+#define SR_TXB (1 << 7) /* tx busy */
+#define SR_RXB (1 << 6) /* rx busy */
+#define SR_TXFF (1 << 5) /* tx fifo full */
+#define SR_RXFF (1 << 4) /* rx fifo full */
+#define SR_TXHE (1 << 3) /* tx fifo half empty */
+#define SR_RXHF (1 << 2) /* rx fifo half full */
+#define SR_TXFE (1 << 1) /* tx fifo empty */
+#define SR_RXFE (1 << 0) /* rx fifo empty */
+
+/*
+ * interrupt status register bits.
+ */
+#define ISR_RXTOFEINTR (1 << 6) /* rx fifo empty */
+#define ISR_URINTR (1 << 5) /* tx underflow */
+#define ISR_ORINTR (1 << 4) /* rx overflow */
+#define ISR_RXINTR (1 << 3) /* rx fifo */
+#define ISR_TXINTR (1 << 2) /* tx fifo intr */
+#define ISR_RXTOINTR (1 << 1) /* tx timeout */
+#define ISR_TXCINTR (1 << 0) /* tx complete */
+
+/*
+ * interrupt enable register bits.
+ */
+#define IE_RXTOIE (1 << 6)
+#define IE_URIE (1 << 5)
+#define IE_ORIE (1 << 4)
+#define IE_RXIE (1 << 3)
+#define IE_TXIE (1 << 2)
+#define IE_RXTIE (1 << 1)
+#define IE_TXCIE (1 << 0)
+
+/*
+ * interrupt status. P51
+ */
+#define ISR_RXTOFE (1 << 6) /* rx timeout fifo empty */
+#define ISR_UR (1 << 5) /* tx fifo underrun */
+#define ISR_OR (1 << 4) /* rx fifo overrun */
+#define ISR_RX (1 << 3) /* rx interrupt status */
+#define ISR_TX (1 << 2) /* tx interrupt status */
+#define ISR_RXTO (1 << 1) /* rx timeout */
+#define ISR_TXC (1 << 0) /* tx complete */
+
+/*
+ * interrupt enable. P52
+ */
+#define IE_RXTOFE (1 << 6) /* rx timeout fifo empty */
+#define IE_UR (1 << 5) /* tx fifo underrun */
+#define IE_OR (1 << 4) /* rx fifo overrun */
+#define IE_RX (1 << 3) /* rx interrupt status */
+#define IE_TX (1 << 2) /* tx interrupt status */
+#define IE_RXTO (1 << 1) /* rx timeout */
+#define IE_TXC (1 << 0) /* tx complete */
+
+/*
+ * slot flag register bits. P56
+ */
+#define SLFR_RWIS (1 << 13) /* raw wake-up interrupt status */
+#define SLFR_RGPIOINTR (1 << 12) /* raw gpio interrupt */
+#define SLFR_12TXE (1 << 11) /* slot 12 tx empty */
+#define SLFR_12RXV (1 << 10) /* slot 12 rx valid */
+#define SLFR_2TXE (1 << 9) /* slot 2 tx empty */
+#define SLFR_2RXV (1 << 8) /* slot 2 rx valid */
+#define SLFR_1TXE (1 << 7) /* slot 1 tx empty */
+#define SLFR_1RXV (1 << 6) /* slot 1 rx valid */
+#define SLFR_12TXB (1 << 5) /* slot 12 tx busy */
+#define SLFR_12RXB (1 << 4) /* slot 12 rx busy */
+#define SLFR_2TXB (1 << 3) /* slot 2 tx busy */
+#define SLFR_2RXB (1 << 2) /* slot 2 rx busy */
+#define SLFR_1TXB (1 << 1) /* slot 1 tx busy */
+#define SLFR_1RXB (1 << 0) /* slot 1 rx busy */
+
+/*
+ * Interrupt clear register.
+ */
+#define ICLR_RXTOFEC4 (1 << 12)
+#define ICLR_RXTOFEC3 (1 << 11)
+#define ICLR_RXTOFEC2 (1 << 10)
+#define ICLR_RXTOFEC1 (1 << 9)
+#define ICLR_TXUEC4 (1 << 8)
+#define ICLR_TXUEC3 (1 << 7)
+#define ICLR_TXUEC2 (1 << 6)
+#define ICLR_TXUEC1 (1 << 5)
+#define ICLR_RXOEC4 (1 << 4)
+#define ICLR_RXOEC3 (1 << 3)
+#define ICLR_RXOEC2 (1 << 2)
+#define ICLR_RXOEC1 (1 << 1)
+#define ICLR_WISC (1 << 0)
+
+/*
+ * Main control register bits. P62
+ */
+#define MAINCR_SCRA(x) ((x) << 10) /* secondary codec reg access */
+#define MAINCR_DMAEN (1 << 9) /* dma enable */
+#define MAINCR_SL12TXEN (1 << 8) /* slot 12 transmit enable */
+#define MAINCR_SL12RXEN (1 << 7) /* slot 12 receive enable */
+#define MAINCR_SL2TXEN (1 << 6) /* slot 2 transmit enable */
+#define MAINCR_SL2RXEN (1 << 5) /* slot 2 receive enable */
+#define MAINCR_SL1TXEN (1 << 4) /* slot 1 transmit enable */
+#define MAINCR_SL1RXEN (1 << 3) /* slot 1 receive enable */
+#define MAINCR_LPM (1 << 2) /* low power mode */
+#define MAINCR_LOOPBK (1 << 1) /* loopback */
+#define MAINCR_IE (1 << 0) /* aaci interface enable */
+
+/*
+ * Reset register bits. P65
+ */
+#define RESET_NRST (1 << 0)
+
+/*
+ * Sync register bits. P65
+ */
+#define SYNC_FORCE (1 << 0)
+
+/*
+ * Main flag register bits. P66
+ */
+#define MAINFR_TXB (1 << 1) /* transmit busy */
+#define MAINFR_RXB (1 << 0) /* receive busy */
+
+
+
+struct aaci_runtime {
+ void *base;
+ void *fifo;
+
+ struct ac97_pcm *pcm;
+ int pcm_open;
+
+ u32 cr;
+ snd_pcm_substream_t *substream;
+
+ /*
+ * PIO support
+ */
+ void *start;
+ void *end;
+ void *ptr;
+ int bytes;
+ unsigned int period;
+ unsigned int fifosz;
+};
+
+struct aaci {
+ struct amba_device *dev;
+ snd_card_t *card;
+ void *base;
+ unsigned int fifosize;
+
+ /* AC'97 */
+ struct semaphore ac97_sem;
+ ac97_bus_t *ac97_bus;
+
+ u32 maincr;
+ spinlock_t lock;
+
+ struct aaci_runtime playback;
+ struct aaci_runtime capture;
+
+ snd_pcm_t *pcm;
+};
+
+#define ACSTREAM_FRONT 0
+#define ACSTREAM_SURROUND 1
+#define ACSTREAM_LFE 2
+
+#endif
--- /dev/null
+/*
+ * linux/sound/arm/devdma.c
+ *
+ * Copyright (C) 2003-2004 Russell King, All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * ARM DMA shim for ALSA.
+ */
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+
+#include "devdma.h"
+
+void devdma_hw_free(struct device *dev, snd_pcm_substream_t *substream)
+{
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_dma_buffer *buf = runtime->dma_buffer_p;
+
+ if (runtime->dma_area == NULL)
+ return;
+
+ if (buf != &substream->dma_buffer) {
+ dma_free_coherent(buf->dev.dev, buf->bytes, buf->area, buf->addr);
+ kfree(runtime->dma_buffer_p);
+ }
+
+ snd_pcm_set_runtime_buffer(substream, NULL);
+}
+
+int devdma_hw_alloc(struct device *dev, snd_pcm_substream_t *substream, size_t size)
+{
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_dma_buffer *buf = runtime->dma_buffer_p;
+ int ret = 0;
+
+ if (buf) {
+ if (buf->bytes >= size)
+ goto out;
+ devdma_hw_free(dev, substream);
+ }
+
+ if (substream->dma_buffer.area != NULL && substream->dma_buffer.bytes >= size) {
+ buf = &substream->dma_buffer;
+ } else {
+ buf = kmalloc(sizeof(struct snd_dma_buffer), GFP_KERNEL);
+ if (!buf)
+ goto nomem;
+
+ buf->dev.type = SNDRV_DMA_TYPE_DEV;
+ buf->dev.dev = dev;
+ buf->area = dma_alloc_coherent(dev, size, &buf->addr, GFP_KERNEL);
+ buf->bytes = size;
+ buf->private_data = NULL;
+
+ if (!buf->area)
+ goto free;
+ }
+ snd_pcm_set_runtime_buffer(substream, buf);
+ ret = 1;
+ out:
+ runtime->dma_bytes = size;
+ return ret;
+
+ free:
+ kfree(buf);
+ nomem:
+ return -ENOMEM;
+}
+
+int devdma_mmap(struct device *dev, snd_pcm_substream_t *substream, struct vm_area_struct *vma)
+{
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ return dma_mmap_coherent(dev, vma, runtime->dma_area, runtime->dma_addr, runtime->dma_bytes);
+}
--- /dev/null
+void devdma_hw_free(struct device *dev, snd_pcm_substream_t *substream);
+int devdma_hw_alloc(struct device *dev, snd_pcm_substream_t *substream, size_t size);
+int devdma_mmap(struct device *dev, snd_pcm_substream_t *substream, struct vm_area_struct *vma);
*
* Returns the pointer of the newly generated instance, or NULL on failure.
*/
-snd_kcontrol_t *snd_ctl_new1(snd_kcontrol_new_t * ncontrol, void *private_data)
+snd_kcontrol_t *snd_ctl_new1(const snd_kcontrol_new_t * ncontrol, void *private_data)
{
snd_kcontrol_t kctl;
unsigned int access;
}
}
up_read(&snd_ioctl_rwsem);
- snd_printd("unknown ioctl = 0x%x\n", cmd);
+ snd_printdd("unknown ioctl = 0x%x\n", cmd);
return -ENOTTY;
}
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/mm.h>
+#include <asm/uaccess.h>
#include <linux/dma-mapping.h>
#include <linux/moduleparam.h>
#include <asm/semaphore.h>
#define SNDRV_CARDS 8
#endif
-/* FIXME: so far only some PCI devices have the preallocation table */
-#ifdef CONFIG_PCI
-static int enable[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1};
-module_param_array(enable, bool, NULL, 0444);
-MODULE_PARM_DESC(enable, "Enable cards to allocate buffers.");
-#endif
-
/*
*/
list_for_each(p, &mem_list_head) {
mem = list_entry(p, struct snd_mem_list, list);
if (mem->id == id &&
- ! memcmp(&mem->buffer.dev, &dmab->dev, sizeof(dmab->dev))) {
+ (mem->buffer.dev.dev == NULL || dmab->dev.dev == NULL ||
+ ! memcmp(&mem->buffer.dev, &dmab->dev, sizeof(dmab->dev)))) {
+ struct device *dev = dmab->dev.dev;
list_del(p);
*dmab = mem->buffer;
+ if (dmab->dev.dev == NULL)
+ dmab->dev.dev = dev;
kfree(mem);
up(&list_mutex);
return dmab->bytes;
}
-
-/*
- * allocation of buffers for pre-defined devices
- */
-
-#ifdef CONFIG_PCI
-/* FIXME: for pci only - other bus? */
-struct prealloc_dev {
- unsigned short vendor;
- unsigned short device;
- unsigned long dma_mask;
- unsigned int size;
- unsigned int buffers;
-};
-
-#define HAMMERFALL_BUFFER_SIZE (16*1024*4*(26+1)+0x10000)
-
-static struct prealloc_dev prealloc_devices[] __initdata = {
- {
- /* hammerfall */
- .vendor = 0x10ee,
- .device = 0x3fc4,
- .dma_mask = 0xffffffff,
- .size = HAMMERFALL_BUFFER_SIZE,
- .buffers = 2
- },
- {
- /* HDSP */
- .vendor = 0x10ee,
- .device = 0x3fc5,
- .dma_mask = 0xffffffff,
- .size = HAMMERFALL_BUFFER_SIZE,
- .buffers = 2
- },
- { }, /* terminator */
-};
-
-static void __init preallocate_cards(void)
-{
- struct pci_dev *pci = NULL;
- int card;
-
- card = 0;
-
- while ((pci = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci)) != NULL) {
- struct prealloc_dev *dev;
- unsigned int i;
- if (card >= SNDRV_CARDS)
- break;
- for (dev = prealloc_devices; dev->vendor; dev++) {
- if (dev->vendor == pci->vendor && dev->device == pci->device)
- break;
- }
- if (! dev->vendor)
- continue;
- if (! enable[card++]) {
- printk(KERN_DEBUG "snd-page-alloc: skipping card %d, device %04x:%04x\n", card, pci->vendor, pci->device);
- continue;
- }
-
- if (pci_set_dma_mask(pci, dev->dma_mask) < 0 ||
- pci_set_consistent_dma_mask(pci, dev->dma_mask) < 0) {
- printk(KERN_ERR "snd-page-alloc: cannot set DMA mask %lx for pci %04x:%04x\n", dev->dma_mask, dev->vendor, dev->device);
- continue;
- }
- for (i = 0; i < dev->buffers; i++) {
- struct snd_dma_buffer dmab;
- memset(&dmab, 0, sizeof(dmab));
- if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
- dev->size, &dmab) < 0)
- printk(KERN_WARNING "snd-page-alloc: cannot allocate buffer pages (size = %d)\n", dev->size);
- else
- snd_dma_reserve_buf(&dmab, snd_dma_pci_buf_id(pci));
- }
- }
-}
-#else
-#define preallocate_cards() /* NOP */
-#endif
-
-
#ifdef CONFIG_PROC_FS
/*
* proc file interface
*/
+#define SND_MEM_PROC_FILE "driver/snd-page-alloc"
+struct proc_dir_entry *snd_mem_proc;
+
static int snd_mem_proc_read(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
up(&list_mutex);
return len;
}
+
+/* FIXME: for pci only - other bus? */
+#ifdef CONFIG_PCI
+#define gettoken(bufp) strsep(bufp, " \t\n")
+
+static int snd_mem_proc_write(struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ char buf[128];
+ char *token, *p;
+
+ if (count > ARRAY_SIZE(buf) - 1)
+ count = ARRAY_SIZE(buf) - 1;
+ if (copy_from_user(buf, buffer, count))
+ return -EFAULT;
+ buf[ARRAY_SIZE(buf) - 1] = '\0';
+
+ p = buf;
+ token = gettoken(&p);
+ if (! token || *token == '#')
+ return (int)count;
+ if (strcmp(token, "add") == 0) {
+ char *endp;
+ int vendor, device, size, buffers;
+ long mask;
+ int i, alloced;
+ struct pci_dev *pci;
+
+ if ((token = gettoken(&p)) == NULL ||
+ (vendor = simple_strtol(token, NULL, 0)) <= 0 ||
+ (token = gettoken(&p)) == NULL ||
+ (device = simple_strtol(token, NULL, 0)) <= 0 ||
+ (token = gettoken(&p)) == NULL ||
+ (mask = simple_strtol(token, NULL, 0)) < 0 ||
+ (token = gettoken(&p)) == NULL ||
+ (size = memparse(token, &endp)) < 64*1024 ||
+ size > 16*1024*1024 /* too big */ ||
+ (token = gettoken(&p)) == NULL ||
+ (buffers = simple_strtol(token, NULL, 0)) <= 0 ||
+ buffers > 4) {
+ printk(KERN_ERR "snd-page-alloc: invalid proc write format\n");
+ return (int)count;
+ }
+ vendor &= 0xffff;
+ device &= 0xffff;
+
+ alloced = 0;
+ pci = NULL;
+ while ((pci = pci_find_device(vendor, device, pci)) != NULL) {
+ if (mask > 0 && mask < 0xffffffff) {
+ if (pci_set_dma_mask(pci, mask) < 0 ||
+ pci_set_consistent_dma_mask(pci, mask) < 0) {
+ printk(KERN_ERR "snd-page-alloc: cannot set DMA mask %lx for pci %04x:%04x\n", mask, vendor, device);
+ return (int)count;
+ }
+ }
+ for (i = 0; i < buffers; i++) {
+ struct snd_dma_buffer dmab;
+ memset(&dmab, 0, sizeof(dmab));
+ if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
+ size, &dmab) < 0) {
+ printk(KERN_ERR "snd-page-alloc: cannot allocate buffer pages (size = %d)\n", size);
+ return (int)count;
+ }
+ snd_dma_reserve_buf(&dmab, snd_dma_pci_buf_id(pci));
+ }
+ alloced++;
+ }
+ if (! alloced) {
+ for (i = 0; i < buffers; i++) {
+ struct snd_dma_buffer dmab;
+ memset(&dmab, 0, sizeof(dmab));
+ /* FIXME: We can allocate only in ZONE_DMA
+ * without a device pointer!
+ */
+ if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, NULL,
+ size, &dmab) < 0) {
+ printk(KERN_ERR "snd-page-alloc: cannot allocate buffer pages (size = %d)\n", size);
+ break;
+ }
+ snd_dma_reserve_buf(&dmab, (unsigned int)((vendor << 16) | device));
+ }
+ }
+ } else if (strcmp(token, "erase") == 0)
+ /* FIXME: need for releasing each buffer chunk? */
+ free_all_reserved_pages();
+ else
+ printk(KERN_ERR "snd-page-alloc: invalid proc cmd\n");
+ return (int)count;
+}
+#endif /* CONFIG_PCI */
#endif /* CONFIG_PROC_FS */
/*
static int __init snd_mem_init(void)
{
#ifdef CONFIG_PROC_FS
- create_proc_read_entry("driver/snd-page-alloc", 0, NULL, snd_mem_proc_read, NULL);
+ snd_mem_proc = create_proc_entry(SND_MEM_PROC_FILE, 0644, NULL);
+ if (snd_mem_proc) {
+ snd_mem_proc->read_proc = snd_mem_proc_read;
+#ifdef CONFIG_PCI
+ snd_mem_proc->write_proc = snd_mem_proc_write;
+#endif
+ }
#endif
- preallocate_cards();
return 0;
}
static void __exit snd_mem_exit(void)
{
- remove_proc_entry("driver/snd-page-alloc", NULL);
+ if (snd_mem_proc)
+ remove_proc_entry(SND_MEM_PROC_FILE, NULL);
free_all_reserved_pages();
if (snd_allocated_pages > 0)
printk(KERN_ERR "snd-malloc: Memory leak? pages not freed = %li\n", snd_allocated_pages);
static long snd_pcm_oss_bytes(snd_pcm_substream_t *substream, long frames)
{
snd_pcm_runtime_t *runtime = substream->runtime;
- snd_pcm_uframes_t buffer_size = snd_pcm_lib_buffer_bytes(substream);
- frames = frames_to_bytes(runtime, frames);
+ long buffer_size = snd_pcm_lib_buffer_bytes(substream);
+ long bytes = frames_to_bytes(runtime, frames);
if (buffer_size == runtime->oss.buffer_bytes)
- return frames;
- return (runtime->oss.buffer_bytes * frames) / buffer_size;
+ return bytes;
+#if BITS_PER_LONG >= 64
+ return runtime->oss.buffer_bytes * bytes / buffer_size;
+#else
+ {
+ u64 bsize = (u64)runtime->oss.buffer_bytes * (u64)bytes;
+ u32 rem;
+ div64_32(&bsize, buffer_size, &rem);
+ return (long)bsize;
+ }
+#endif
}
static long snd_pcm_alsa_frames(snd_pcm_substream_t *substream, long bytes)
{
snd_pcm_runtime_t *runtime = substream->runtime;
- snd_pcm_uframes_t buffer_size = snd_pcm_lib_buffer_bytes(substream);
+ long buffer_size = snd_pcm_lib_buffer_bytes(substream);
if (buffer_size == runtime->oss.buffer_bytes)
return bytes_to_frames(runtime, bytes);
return bytes_to_frames(runtime, (buffer_size * bytes) / runtime->oss.buffer_bytes);
sw_params->tstamp_mode = SNDRV_PCM_TSTAMP_NONE;
sw_params->period_step = 1;
sw_params->sleep_min = 0;
- sw_params->avail_min = 1;
+ sw_params->avail_min = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+ 1 : runtime->period_size;
sw_params->xfer_align = 1;
if (atomic_read(&runtime->mmap_count) ||
(substream->oss.setup && substream->oss.setup->nosilence)) {
snd_pcm_oss_simulate_fill(substream, delay);
info.bytes = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr) & INT_MAX;
} else {
- delay = snd_pcm_oss_bytes(substream, delay) + fixup;
- info.blocks = delay / runtime->oss.period_bytes;
- if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ delay = snd_pcm_oss_bytes(substream, delay);
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ info.blocks = (runtime->oss.buffer_bytes - delay - fixup) / runtime->oss.period_bytes;
info.bytes = (runtime->oss.bytes - delay) & INT_MAX;
- else
+ } else {
+ delay += fixup;
+ info.blocks = delay / runtime->oss.period_bytes;
info.bytes = (runtime->oss.bytes + delay) & INT_MAX;
+ }
}
if (copy_to_user(_info, &info, sizeof(info)))
return -EFAULT;
bitset_t *dstmask = bs;
int err;
bitset_one(dstmask, schannels);
- if (plugin == NULL) {
- bitset_and(client_vmask, dstmask, schannels);
- return 0;
- }
+
while (1) {
err = plugin->src_channels_mask(plugin, dstmask, &srcmask);
if (err < 0)
entry->c.text.read = snd_pcm_xrun_debug_read;
entry->c.text.write_size = 64;
entry->c.text.write = snd_pcm_xrun_debug_write;
+ entry->mode |= S_IWUSR;
entry->private_data = pstr;
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
EXPORT_SYMBOL(snd_pcm_format_name);
/* pcm_native.c */
EXPORT_SYMBOL(snd_pcm_link_rwlock);
-EXPORT_SYMBOL(snd_pcm_start);
#ifdef CONFIG_PM
EXPORT_SYMBOL(snd_pcm_suspend);
EXPORT_SYMBOL(snd_pcm_suspend_all);
EXPORT_SYMBOL(snd_pcm_format_big_endian);
EXPORT_SYMBOL(snd_pcm_format_width);
EXPORT_SYMBOL(snd_pcm_format_physical_width);
+EXPORT_SYMBOL(snd_pcm_format_size);
EXPORT_SYMBOL(snd_pcm_format_silence_64);
EXPORT_SYMBOL(snd_pcm_format_set_silence);
EXPORT_SYMBOL(snd_pcm_build_linear_format);
#define INT_MIN ((int)((unsigned int)INT_MAX+1))
#endif
-void _snd_pcm_hw_param_any(snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var)
+static void _snd_pcm_hw_param_any(snd_pcm_hw_params_t *params,
+ snd_pcm_hw_param_t var)
{
if (hw_is_mask(var)) {
snd_mask_any(hw_param_mask(params, var));
snd_BUG();
}
+#if 0
/**
* snd_pcm_hw_param_any
*/
_snd_pcm_hw_param_any(params, var);
return snd_pcm_hw_refine(pcm, params);
}
+#endif /* 0 */
void _snd_pcm_hw_params_any(snd_pcm_hw_params_t *params)
{
params->info = ~0U;
}
+#if 0
/**
* snd_pcm_hw_params_any
*
_snd_pcm_hw_params_any(params);
return snd_pcm_hw_refine(pcm, params);
}
+#endif /* 0 */
/**
* snd_pcm_hw_param_value
* Return the value for field PAR if it's fixed in configuration space
* defined by PARAMS. Return -EINVAL otherwise
*/
-int snd_pcm_hw_param_value(const snd_pcm_hw_params_t *params,
- snd_pcm_hw_param_t var, int *dir)
+static int snd_pcm_hw_param_value(const snd_pcm_hw_params_t *params,
+ snd_pcm_hw_param_t var, int *dir)
{
if (hw_is_mask(var)) {
const snd_mask_t *mask = hw_param_mask_c(params, var);
return changed;
}
+#if 0
/**
* snd_pcm_hw_param_setinteger
*
}
return 0;
}
+#endif /* 0 */
-int _snd_pcm_hw_param_first(snd_pcm_hw_params_t *params,
- snd_pcm_hw_param_t var)
+static int _snd_pcm_hw_param_first(snd_pcm_hw_params_t *params,
+ snd_pcm_hw_param_t var)
{
int changed;
if (hw_is_mask(var))
* values > minimum. Reduce configuration space accordingly.
* Return the minimum.
*/
-int snd_pcm_hw_param_first(snd_pcm_t *pcm,
- snd_pcm_hw_params_t *params,
- snd_pcm_hw_param_t var, int *dir)
+static int snd_pcm_hw_param_first(snd_pcm_t *pcm,
+ snd_pcm_hw_params_t *params,
+ snd_pcm_hw_param_t var, int *dir)
{
int changed = _snd_pcm_hw_param_first(params, var);
if (changed < 0)
return snd_pcm_hw_param_value(params, var, dir);
}
-int _snd_pcm_hw_param_last(snd_pcm_hw_params_t *params,
- snd_pcm_hw_param_t var)
+static int _snd_pcm_hw_param_last(snd_pcm_hw_params_t *params,
+ snd_pcm_hw_param_t var)
{
int changed;
if (hw_is_mask(var))
* values < maximum. Reduce configuration space accordingly.
* Return the maximum.
*/
-int snd_pcm_hw_param_last(snd_pcm_t *pcm,
- snd_pcm_hw_params_t *params,
- snd_pcm_hw_param_t var, int *dir)
+static int snd_pcm_hw_param_last(snd_pcm_t *pcm,
+ snd_pcm_hw_params_t *params,
+ snd_pcm_hw_param_t var, int *dir)
{
int changed = _snd_pcm_hw_param_last(params, var);
if (changed < 0)
* values < VAL. Reduce configuration space accordingly.
* Return new minimum or -EINVAL if the configuration space is empty
*/
-int snd_pcm_hw_param_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
- snd_pcm_hw_param_t var, unsigned int val, int *dir)
+static int snd_pcm_hw_param_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+ snd_pcm_hw_param_t var, unsigned int val,
+ int *dir)
{
int changed = _snd_pcm_hw_param_min(params, var, val, dir ? *dir : 0);
if (changed < 0)
return snd_pcm_hw_param_value_min(params, var, dir);
}
-int _snd_pcm_hw_param_max(snd_pcm_hw_params_t *params,
- snd_pcm_hw_param_t var, unsigned int val, int dir)
+static int _snd_pcm_hw_param_max(snd_pcm_hw_params_t *params,
+ snd_pcm_hw_param_t var, unsigned int val,
+ int dir)
{
int changed;
int open = 0;
* values >= VAL + 1. Reduce configuration space accordingly.
* Return new maximum or -EINVAL if the configuration space is empty
*/
-int snd_pcm_hw_param_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
- snd_pcm_hw_param_t var, unsigned int val, int *dir)
+static int snd_pcm_hw_param_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+ snd_pcm_hw_param_t var, unsigned int val,
+ int *dir)
{
int changed = _snd_pcm_hw_param_max(params, var, val, dir ? *dir : 0);
if (changed < 0)
EXPORT_SYMBOL(snd_interval_refine);
EXPORT_SYMBOL(snd_interval_list);
EXPORT_SYMBOL(snd_interval_ratnum);
-EXPORT_SYMBOL(snd_interval_muldivk);
-EXPORT_SYMBOL(snd_interval_mulkdiv);
-EXPORT_SYMBOL(snd_interval_div);
EXPORT_SYMBOL(_snd_pcm_hw_params_any);
EXPORT_SYMBOL(_snd_pcm_hw_param_min);
EXPORT_SYMBOL(_snd_pcm_hw_param_set);
EXPORT_SYMBOL(snd_pcm_hw_param_near);
EXPORT_SYMBOL(snd_pcm_hw_param_set);
EXPORT_SYMBOL(snd_pcm_hw_refine);
-EXPORT_SYMBOL(snd_pcm_hw_params);
EXPORT_SYMBOL(snd_pcm_hw_constraints_init);
EXPORT_SYMBOL(snd_pcm_hw_constraints_complete);
EXPORT_SYMBOL(snd_pcm_hw_constraint_list);
entry->c.text.read = snd_pcm_lib_preallocate_proc_read;
entry->c.text.write_size = 64;
entry->c.text.write = snd_pcm_lib_preallocate_proc_write;
+ entry->mode |= S_IWUSR;
entry->private_data = substream;
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
return !val;
}
-/**
- * snd_pcm_format_cpu_endian - Check the PCM format is CPU-endian
- * @format: the format to check
- *
- * Returns 1 if the given PCM format is CPU-endian, 0 if
- * opposite, or a negative error code if endian not specified.
- */
-int snd_pcm_format_cpu_endian(snd_pcm_format_t format)
-{
-#ifdef SNDRV_LITTLE_ENDIAN
- return snd_pcm_format_little_endian(format);
-#else
- return snd_pcm_format_big_endian(format);
-#endif
-}
-
/**
* snd_pcm_format_width - return the bit-width of the format
* @format: the format to check
return err;
}
-int snd_pcm_hw_params(snd_pcm_substream_t *substream,
- snd_pcm_hw_params_t *params)
+static int snd_pcm_hw_params(snd_pcm_substream_t *substream,
+ snd_pcm_hw_params_t *params)
{
snd_pcm_runtime_t *runtime;
int err;
if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
return -EBADFD;
- down_read(&snd_pcm_link_rwsem);
snd_power_lock(card);
if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
result = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile);
- if (result < 0)
- goto _unlock;
+ if (result < 0) {
+ snd_power_unlock(card);
+ return result;
+ }
}
/* allocate temporary record for drain sync */
+ down_read(&snd_pcm_link_rwsem);
if (snd_pcm_stream_linked(substream)) {
drec = kmalloc(substream->group->count * sizeof(*drec), GFP_KERNEL);
if (! drec) {
- result = -ENOMEM;
- goto _unlock;
+ up_read(&snd_pcm_link_rwsem);
+ snd_power_unlock(card);
+ return -ENOMEM;
}
} else
drec = &drec_tmp;
- snd_pcm_stream_lock_irq(substream);
- /* resume pause */
- if (runtime->status->state == SNDRV_PCM_STATE_PAUSED)
- snd_pcm_pause(substream, 0);
-
- /* pre-start/stop - all running streams are changed to DRAINING state */
- result = snd_pcm_action(&snd_pcm_action_drain_init, substream, 0);
- if (result < 0)
- goto _end;
-
- /* check streams with PLAYBACK & DRAINING */
+ /* count only playback streams */
num_drecs = 0;
snd_pcm_group_for_each(pos, substream) {
snd_pcm_substream_t *s = snd_pcm_group_substream_entry(pos);
runtime = s->runtime;
- if (runtime->status->state != SNDRV_PCM_STATE_DRAINING) {
- runtime->status->state = SNDRV_PCM_STATE_SETUP;
- continue;
- }
if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) {
d = &drec[num_drecs++];
d->substream = s;
runtime->stop_threshold = runtime->buffer_size;
}
}
-
+ up_read(&snd_pcm_link_rwsem);
if (! num_drecs)
- goto _end;
+ goto _error;
+
+ snd_pcm_stream_lock_irq(substream);
+ /* resume pause */
+ if (runtime->status->state == SNDRV_PCM_STATE_PAUSED)
+ snd_pcm_pause(substream, 0);
+
+ /* pre-start/stop - all running streams are changed to DRAINING state */
+ result = snd_pcm_action(&snd_pcm_action_drain_init, substream, 0);
+ if (result < 0) {
+ snd_pcm_stream_unlock_irq(substream);
+ goto _error;
+ }
for (;;) {
long tout;
result = -ERESTARTSYS;
break;
}
+ /* all finished? */
+ for (i = 0; i < num_drecs; i++) {
+ runtime = drec[i].substream->runtime;
+ if (runtime->status->state == SNDRV_PCM_STATE_DRAINING)
+ break;
+ }
+ if (i == num_drecs)
+ break; /* yes, all drained */
+
set_current_state(TASK_INTERRUPTIBLE);
snd_pcm_stream_unlock_irq(substream);
snd_power_unlock(card);
}
break;
}
- /* all finished? */
- for (i = 0; i < num_drecs; i++) {
- runtime = drec[i].substream->runtime;
- if (runtime->status->state == SNDRV_PCM_STATE_DRAINING)
- break;
- }
- if (i == num_drecs)
- break;
}
+
+ snd_pcm_stream_unlock_irq(substream);
+
+ _error:
for (i = 0; i < num_drecs; i++) {
d = &drec[i];
runtime = d->substream->runtime;
runtime->stop_threshold = d->stop_threshold;
}
- _end:
- snd_pcm_stream_unlock_irq(substream);
if (drec != &drec_tmp)
kfree(drec);
- _unlock:
snd_power_unlock(card);
- up_read(&snd_pcm_link_rwsem);
return result;
}
}
snd_use_lock_free(&rec->use_lock);
}
- if (info->sysex) {
- kfree(info->sysex);
- info->sysex = NULL;
- }
- if (info->ch) {
- kfree(info->ch);
- info->ch = NULL;
- }
+ kfree(info->sysex);
+ info->sysex = NULL;
+ kfree(info->ch);
+ info->ch = NULL;
}
dp->synth_opened = 0;
dp->max_synthdev = 0;
dp->file_mode) < 0) {
midi_synth_dev.opened--;
info->opened = 0;
- if (info->sysex) {
- kfree(info->sysex);
- info->sysex = NULL;
- }
- if (info->ch) {
- kfree(info->ch);
- info->ch = NULL;
- }
+ kfree(info->sysex);
+ info->sysex = NULL;
+ kfree(info->ch);
+ info->ch = NULL;
}
return;
}
static void
dummy_free(void *private_data)
{
- snd_seq_dummy_port_t *p;
-
- p = private_data;
- kfree(p);
+ kfree(private_data);
}
/*
if (newclient)
synths[card->number] = client;
up(®ister_mutex);
+ kfree(info);
+ kfree(port);
return 0; /* success */
__nomem:
spin_unlock_irqrestore(&dev->lock, flags);
}
+#if 0
void snd_midi_event_init(snd_midi_event_t *dev)
{
snd_midi_event_reset_encode(dev);
snd_midi_event_reset_decode(dev);
}
+#endif /* 0 */
void snd_midi_event_no_status(snd_midi_event_t *dev, int on)
{
/*
* resize buffer
*/
+#if 0
int snd_midi_event_resize_buffer(snd_midi_event_t *dev, int bufsize)
{
unsigned char *new_buf, *old_buf;
kfree(old_buf);
return 0;
}
+#endif /* 0 */
/*
* read bytes and encode to sequencer event if finished
EXPORT_SYMBOL(snd_midi_event_new);
EXPORT_SYMBOL(snd_midi_event_free);
-EXPORT_SYMBOL(snd_midi_event_resize_buffer);
-EXPORT_SYMBOL(snd_midi_event_init);
EXPORT_SYMBOL(snd_midi_event_reset_encode);
EXPORT_SYMBOL(snd_midi_event_reset_decode);
EXPORT_SYMBOL(snd_midi_event_no_status);
* process a received queue-control event.
* this function is exported for seq_sync.c.
*/
-void snd_seq_queue_process_event(queue_t *q, snd_seq_event_t *ev, int atomic, int hop)
+static void snd_seq_queue_process_event(queue_t *q, snd_seq_event_t *ev,
+ int atomic, int hop)
{
switch (ev->type) {
case SNDRV_SEQ_EVENT_START:
int snd_seq_queue_is_used(int queueid, int client);
int snd_seq_control_queue(snd_seq_event_t *ev, int atomic, int hop);
-void snd_seq_queue_process_event(queue_t *q, snd_seq_event_t *ev, int atomic, int hop);
/*
* 64bit division - for sync stuff..
#define SKEW_BASE 0x10000 /* 16bit shift */
-void snd_seq_timer_set_tick_resolution(seq_timer_tick_t *tick, int tempo, int ppq, int nticks)
+static void snd_seq_timer_set_tick_resolution(seq_timer_tick_t *tick,
+ int tempo, int ppq, int nticks)
{
if (tempo < 1000000)
tick->resolution = (tempo * 1000) / ppq;
/* delete timer (destructor) */
extern void snd_seq_timer_delete(seq_timer_t **tmr);
-void snd_seq_timer_set_tick_resolution(seq_timer_tick_t *tick, int tempo, int ppq, int nticks);
-
/* */
static inline void snd_seq_timer_update_tick(seq_timer_tick_t *tick, unsigned long resolution)
{
* handler of a remote port which is attached to the virmidi via
* SNDRV_VIRMIDI_SEQ_ATTACH.
*/
-/* exported */
+#if 0
int snd_virmidi_receive(snd_rawmidi_t *rmidi, snd_seq_event_t *ev)
{
snd_virmidi_dev_t *rdev;
rdev = rmidi->private_data;
return snd_virmidi_dev_receive_event(rdev, ev);
}
+#endif /* 0 */
/*
* event handler of virmidi port
info->client = client;
info->type = KERNEL_CLIENT;
sprintf(info->name, "%s %d-%d", rdev->rmidi->name, rdev->card->number, rdev->device);
- snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, &info);
+ snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, info);
/* create a port */
memset(pinfo, 0, sizeof(*pinfo));
pcallbacks.unuse = snd_virmidi_unuse;
pcallbacks.event_input = snd_virmidi_event_input;
pinfo->kernel = &pcallbacks;
- err = snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_CREATE_PORT, &pinfo);
+ err = snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_CREATE_PORT, pinfo);
if (err < 0) {
snd_seq_delete_kernel_client(client);
rdev->client = -1;
module_exit(alsa_virmidi_exit)
EXPORT_SYMBOL(snd_virmidi_new);
-EXPORT_SYMBOL(snd_virmidi_receive);
EXPORT_SYMBOL(snd_device_new);
EXPORT_SYMBOL(snd_device_register);
EXPORT_SYMBOL(snd_device_free);
-EXPORT_SYMBOL(snd_device_free_all);
/* isadma.c */
#ifdef CONFIG_ISA
EXPORT_SYMBOL(snd_dma_program);
struct timespec tstamp; /* trigger tstamp */
wait_queue_head_t qchange_sleep;
struct fasync_struct *fasync;
+ struct semaphore tread_sem;
} snd_timer_user_t;
/* list of timers */
return 0;
}
-int snd_timer_unregister(snd_timer_t *timer)
+static int snd_timer_unregister(snd_timer_t *timer)
{
struct list_head *p, *n;
snd_timer_instance_t *ti;
unsigned long correction;
};
-unsigned int snd_timer_system_resolution(void)
-{
- return 1000000000L / HZ;
-}
-
static void snd_timer_s_function(unsigned long data)
{
snd_timer_t *timer = (snd_timer_t *)data;
return -ENOMEM;
spin_lock_init(&tu->qlock);
init_waitqueue_head(&tu->qchange_sleep);
+ init_MUTEX(&tu->tread_sem);
tu->ticks = 1;
tu->queue_size = 128;
tu->queue = (snd_timer_read_t *)kmalloc(tu->queue_size * sizeof(snd_timer_read_t), GFP_KERNEL);
snd_timer_user_t *tu;
snd_timer_select_t tselect;
char str[32];
- int err;
+ int err = 0;
tu = file->private_data;
- if (tu->timeri)
+ down(&tu->tread_sem);
+ if (tu->timeri) {
snd_timer_close(tu->timeri);
- if (copy_from_user(&tselect, _tselect, sizeof(tselect)))
- return -EFAULT;
+ tu->timeri = NULL;
+ }
+ if (copy_from_user(&tselect, _tselect, sizeof(tselect))) {
+ err = -EFAULT;
+ goto __err;
+ }
sprintf(str, "application %i", current->pid);
if (tselect.id.dev_class != SNDRV_TIMER_CLASS_SLAVE)
tselect.id.dev_sclass = SNDRV_TIMER_SCLASS_APPLICATION;
if ((err = snd_timer_open(&tu->timeri, str, &tselect.id, current->pid)) < 0)
- return err;
+ goto __err;
- if (tu->queue) {
- kfree(tu->queue);
- tu->queue = NULL;
- }
- if (tu->tqueue) {
- kfree(tu->tqueue);
- tu->tqueue = NULL;
- }
+ kfree(tu->queue);
+ tu->queue = NULL;
+ kfree(tu->tqueue);
+ tu->tqueue = NULL;
if (tu->tread) {
tu->tqueue = (snd_timer_tread_t *)kmalloc(tu->queue_size * sizeof(snd_timer_tread_t), GFP_KERNEL);
- if (tu->tqueue == NULL) {
- snd_timer_close(tu->timeri);
- return -ENOMEM;
- }
+ if (tu->tqueue == NULL)
+ err = -ENOMEM;
} else {
tu->queue = (snd_timer_read_t *)kmalloc(tu->queue_size * sizeof(snd_timer_read_t), GFP_KERNEL);
- if (tu->queue == NULL) {
- snd_timer_close(tu->timeri);
- return -ENOMEM;
- }
+ if (tu->queue == NULL)
+ err = -ENOMEM;
}
- tu->timeri->flags |= SNDRV_TIMER_IFLG_FAST;
- tu->timeri->callback = tu->tread ? snd_timer_user_tinterrupt : snd_timer_user_interrupt;
- tu->timeri->ccallback = snd_timer_user_ccallback;
- tu->timeri->callback_data = (void *)tu;
- return 0;
+ if (err < 0) {
+ snd_timer_close(tu->timeri);
+ tu->timeri = NULL;
+ } else {
+ tu->timeri->flags |= SNDRV_TIMER_IFLG_FAST;
+ tu->timeri->callback = tu->tread ? snd_timer_user_tinterrupt : snd_timer_user_interrupt;
+ tu->timeri->ccallback = snd_timer_user_ccallback;
+ tu->timeri->callback_data = (void *)tu;
+ }
+
+ __err:
+ up(&tu->tread_sem);
+ return err;
}
static int snd_timer_user_info(struct file *file, snd_timer_info_t __user *_info)
return (err = snd_timer_continue(tu->timeri)) < 0 ? err : 0;
}
+static int snd_timer_user_pause(struct file *file)
+{
+ int err;
+ snd_timer_user_t *tu;
+
+ tu = file->private_data;
+ snd_assert(tu->timeri != NULL, return -ENXIO);
+ return (err = snd_timer_pause(tu->timeri)) < 0 ? err : 0;
+}
+
+enum {
+ SNDRV_TIMER_IOCTL_START_OLD = _IO('T', 0x20),
+ SNDRV_TIMER_IOCTL_STOP_OLD = _IO('T', 0x21),
+ SNDRV_TIMER_IOCTL_CONTINUE_OLD = _IO('T', 0x22),
+ SNDRV_TIMER_IOCTL_PAUSE_OLD = _IO('T', 0x23),
+};
+
static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
snd_timer_user_t *tu;
{
int xarg;
- if (tu->timeri) /* too late */
+ down(&tu->tread_sem);
+ if (tu->timeri) { /* too late */
+ up(&tu->tread_sem);
return -EBUSY;
- if (get_user(xarg, p))
+ }
+ if (get_user(xarg, p)) {
+ up(&tu->tread_sem);
return -EFAULT;
+ }
tu->tread = xarg ? 1 : 0;
+ up(&tu->tread_sem);
return 0;
}
case SNDRV_TIMER_IOCTL_GINFO:
case SNDRV_TIMER_IOCTL_STATUS:
return snd_timer_user_status(file, argp);
case SNDRV_TIMER_IOCTL_START:
+ case SNDRV_TIMER_IOCTL_START_OLD:
return snd_timer_user_start(file);
case SNDRV_TIMER_IOCTL_STOP:
+ case SNDRV_TIMER_IOCTL_STOP_OLD:
return snd_timer_user_stop(file);
case SNDRV_TIMER_IOCTL_CONTINUE:
+ case SNDRV_TIMER_IOCTL_CONTINUE_OLD:
return snd_timer_user_continue(file);
+ case SNDRV_TIMER_IOCTL_PAUSE:
+ case SNDRV_TIMER_IOCTL_PAUSE_OLD:
+ return snd_timer_user_pause(file);
}
return -ENOTTY;
}
EXPORT_SYMBOL(snd_timer_global_register);
EXPORT_SYMBOL(snd_timer_global_unregister);
EXPORT_SYMBOL(snd_timer_interrupt);
-EXPORT_SYMBOL(snd_timer_system_resolution);
case SNDRV_TIMER_IOCTL_SELECT:
case SNDRV_TIMER_IOCTL_PARAMS:
case SNDRV_TIMER_IOCTL_START:
+ case SNDRV_TIMER_IOCTL_START_OLD:
case SNDRV_TIMER_IOCTL_STOP:
+ case SNDRV_TIMER_IOCTL_STOP_OLD:
case SNDRV_TIMER_IOCTL_CONTINUE:
+ case SNDRV_TIMER_IOCTL_CONTINUE_OLD:
+ case SNDRV_TIMER_IOCTL_PAUSE:
+ case SNDRV_TIMER_IOCTL_PAUSE_OLD:
case SNDRV_TIMER_IOCTL_NEXT_DEVICE:
return snd_timer_user_ioctl(file, cmd, (unsigned long)argp);
case SNDRV_TIMER_IOCTL_INFO32:
{
vx_core_t *chip = pcm->private_data;
chip->pcm[pcm->device] = NULL;
- if (chip->playback_pipes) {
- kfree(chip->playback_pipes);
- chip->playback_pipes = NULL;
- }
- if (chip->capture_pipes) {
- kfree(chip->capture_pipes);
- chip->capture_pipes = NULL;
- }
+ kfree(chip->playback_pipes);
+ chip->playback_pipes = NULL;
+ kfree(chip->capture_pipes);
+ chip->capture_pipes = NULL;
}
/*
static void snd_tea6330_free(snd_i2c_device_t *device)
{
- tea6330t_t *tea = device->private_data;
- kfree(tea);
+ kfree(device->private_data);
}
int snd_tea6330t_update_mixer(snd_card_t * card,
select SND_RAWMIDI
select SND_CS4231_LIB
select SND_GUS_SYNTH
+ select ISAPNP
help
Say Y here to include support for AMD InterWave based
soundcards with a TEA6330T bass and treble regulator
static struct pnp_card_device_id snd_ad1816a_pnpids[] = {
/* Analog Devices AD1815 */
{ .id = "ADS7150", .devs = { { .id = "ADS7150" }, { .id = "ADS7151" } } },
+ /* Analog Device AD1816? */
+ { .id = "ADS7180", .devs = { { .id = "ADS7180" }, { .id = "ADS7181" } } },
/* Analog Devices AD1816A - added by Kenneth Platz <kxp@atl.hp.com> */
{ .id = "ADS7181", .devs = { { .id = "ADS7180" }, { .id = "ADS7181" } } },
/* Analog Devices AD1816A - Aztech/Newcom SC-16 3D */
pnp_init_resource_table(cfg);
if (mpu_port[dev] != SNDRV_AUTO_PORT)
pnp_resource_change(&cfg->port_resource[0], mpu_port[dev], 2);
- if (mpu_irq[dev] != SNDRV_AUTO_IRQ && mpu_irq[dev] >= 0 &&
- pnp_irq_valid(pdev, 0))
+ if (mpu_irq[dev] != SNDRV_AUTO_IRQ && mpu_irq[dev] >= 0)
pnp_resource_change(&cfg->irq_resource[0], mpu_irq[dev], 1);
err = pnp_manual_config_dev(pdev, cfg, 0);
if (err < 0)
return res;
}
+#if 0
+
void snd_gf1_i_adlib_write(snd_gus_card_t * gus,
unsigned char reg,
unsigned char data)
spin_unlock_irqrestore(&gus->reg_lock, flags);
}
+#endif /* 0 */
+
unsigned int snd_gf1_i_read_addr(snd_gus_card_t * gus,
unsigned char reg, short w_16bit)
{
return res;
}
+#if 0
+
void snd_gf1_pokew(snd_gus_card_t * gus, unsigned int addr, unsigned short data)
{
unsigned long flags;
spin_unlock_irqrestore(&gus->reg_lock, flags);
}
-/*
-
- */
+#endif /* 0 */
void snd_gf1_select_active_voices(snd_gus_card_t * gus)
{
printk(" -%i- GF1 pan = 0x%x\n", voice, snd_gf1_i_read8(gus, 0x0c));
}
+#if 0
+
void snd_gf1_print_global_registers(snd_gus_card_t * gus)
{
unsigned char global_mode = 0x00;
}
}
+#endif /* 0 */
+
#endif
EXPORT_SYMBOL(snd_gf1_look16);
EXPORT_SYMBOL(snd_gf1_i_write8);
EXPORT_SYMBOL(snd_gf1_i_look8);
-EXPORT_SYMBOL(snd_gf1_i_write16);
EXPORT_SYMBOL(snd_gf1_i_look16);
EXPORT_SYMBOL(snd_gf1_dram_addr);
EXPORT_SYMBOL(snd_gf1_write_addr);
EXPORT_SYMBOL(snd_gf1_free_voice);
EXPORT_SYMBOL(snd_gf1_ctrl_stop);
EXPORT_SYMBOL(snd_gf1_stop_voice);
-EXPORT_SYMBOL(snd_gf1_start);
-EXPORT_SYMBOL(snd_gf1_stop);
/* gus_mixer.c */
EXPORT_SYMBOL(snd_gf1_new_mixer);
/* gus_pcm.c */
}
}
-snd_gf1_mem_block_t *snd_gf1_mem_xalloc(snd_gf1_mem_t * alloc,
- snd_gf1_mem_block_t * block)
+static snd_gf1_mem_block_t *snd_gf1_mem_xalloc(snd_gf1_mem_t * alloc,
+ snd_gf1_mem_block_t * block)
{
snd_gf1_mem_block_t *pblock, *nblock;
return 0;
}
-snd_gf1_mem_block_t *snd_gf1_mem_look(snd_gf1_mem_t * alloc,
- unsigned int address)
+static snd_gf1_mem_block_t *snd_gf1_mem_look(snd_gf1_mem_t * alloc,
+ unsigned int address)
{
snd_gf1_mem_block_t *block;
return NULL;
}
-snd_gf1_mem_block_t *snd_gf1_mem_share(snd_gf1_mem_t * alloc,
- unsigned int *share_id)
+static snd_gf1_mem_block_t *snd_gf1_mem_share(snd_gf1_mem_t * alloc,
+ unsigned int *share_id)
{
snd_gf1_mem_block_t *block;
static void snd_gf1_pcm_playback_free(snd_pcm_runtime_t *runtime)
{
- gus_pcm_private_t * pcmp = runtime->private_data;
- kfree(pcmp);
+ kfree(runtime->private_data);
}
static int snd_gf1_pcm_playback_open(snd_pcm_substream_t *substream)
#endif
}
-void snd_gf1_clear_voices(snd_gus_card_t * gus, unsigned short v_min, unsigned short v_max)
+static void snd_gf1_clear_voices(snd_gus_card_t * gus, unsigned short v_min,
+ unsigned short v_max)
{
unsigned long flags;
unsigned int daddr;
snd_seq_instr_list_free_cond(p->gus->gf1.ilist, &ifree, client, 0);
}
-int snd_gus_synth_event_input(snd_seq_event_t *ev, int direct, void *private_data, int atomic, int hop)
+static int snd_gus_synth_event_input(snd_seq_event_t *ev, int direct,
+ void *private_data, int atomic, int hop)
{
snd_gus_port_t * p = (snd_gus_port_t *) private_data;
#ifdef __GUS_TABLES_ALLOC__
+#if 0
+
unsigned int snd_gf1_scale_table[SNDRV_GF1_SCALE_TABLE_SIZE] =
{
8372, 8870, 9397, 9956, 10548, 11175,
12123977, 12844906
};
+#endif /* 0 */
+
unsigned short snd_gf1_atten_table[SNDRV_GF1_ATTEN_TABLE_SIZE] = {
4095 /* 0 */,1789 /* 1 */,1533 /* 2 */,1383 /* 3 */,1277 /* 4 */,
1195 /* 5 */,1127 /* 6 */,1070 /* 7 */,1021 /* 8 */,978 /* 9 */,
return (e << 8) | m;
}
+#if 0
+
unsigned int snd_gf1_gvol_to_lvol_raw(unsigned short gf1_vol)
{
unsigned int rvol;
return (range << 6) | (increment & 0x3f);
}
+#endif /* 0 */
+
unsigned short snd_gf1_translate_freq(snd_gus_card_t * gus, unsigned int freq16)
{
freq16 >>= 3;
return ((freq16 << 9) + (gus->gf1.playback_freq >> 1)) / gus->gf1.playback_freq;
}
+#if 0
+
short snd_gf1_compute_vibrato(short cents, unsigned short fc_register)
{
static short vibrato_table[] =
}
return (unsigned short) fc;
}
+
+#endif /* 0 */
struct page* page, *last_page;
page = virt_to_page(buf);
- last_page = virt_to_page(buf + (1 << pg));
+ last_page = page + (1 << pg);
DBG(printk("setting reserved bit\n"));
while (page < last_page) {
SetPageReserved(page);
To compile this driver as a module, choose M here: the module
will be called snd-hdsp.
+config SND_HDSPM
+ tristate "RME Hammerfall DSP MADI"
+ depends on SND
+ select SND_HWDEP
+ select SND_RAWMIDI
+ select SND_PCM
+ help
+ Say Y here to include support for RME Hammerfall DSP MADI
+ soundcards.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-hdspm.
+
config SND_TRIDENT
tristate "Trident 4D-Wave DX/NX; SiS 7018"
depends on SND
{ 0x414c4770, 0xfffffff0, "ALC203", NULL, NULL },
{ 0x434d4941, 0xffffffff, "CMI9738", patch_cm9738, NULL },
{ 0x434d4961, 0xffffffff, "CMI9739", patch_cm9739, NULL },
+{ 0x434d4969, 0xffffffff, "CMI9780", patch_cm9780, NULL },
{ 0x434d4978, 0xffffffff, "CMI9761", patch_cm9761, NULL },
{ 0x434d4982, 0xffffffff, "CMI9761", patch_cm9761, NULL },
{ 0x434d4983, 0xffffffff, "CMI9761", patch_cm9761, NULL },
{ 0x4e534331, 0xffffffff, "LM4549", NULL, NULL },
{ 0x4e534350, 0xffffffff, "LM4550", NULL, NULL },
{ 0x50534304, 0xffffffff, "UCB1400", NULL, NULL },
-{ 0x53494c20, 0xffffffe0, "Si3036,8", NULL, mpatch_si3036 },
+{ 0x53494c20, 0xffffffe0, "Si3036,8", mpatch_si3036, mpatch_si3036, AC97_MODEM_PATCH },
{ 0x54524102, 0xffffffff, "TR28022", NULL, NULL },
{ 0x54524106, 0xffffffff, "TR28026", NULL, NULL },
{ 0x54524108, 0xffffffff, "TR28028", patch_tritech_tr28028, NULL }, // added by xin jin [07/09/99]
{
ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
struct ac97_enum *e = (struct ac97_enum *)kcontrol->private_value;
- unsigned short val;
+ unsigned short val, bitmask;
+ for (bitmask = 1; bitmask < e->mask; bitmask <<= 1)
+ ;
val = snd_ac97_read_cache(ac97, e->reg);
- ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (e->mask - 1);
+ ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (bitmask - 1);
if (e->shift_l != e->shift_r)
- ucontrol->value.enumerated.item[1] = (val >> e->shift_r) & (e->mask - 1);
+ ucontrol->value.enumerated.item[1] = (val >> e->shift_r) & (bitmask - 1);
return 0;
}
ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
struct ac97_enum *e = (struct ac97_enum *)kcontrol->private_value;
unsigned short val;
- unsigned short mask;
+ unsigned short mask, bitmask;
+ for (bitmask = 1; bitmask < e->mask; bitmask <<= 1)
+ ;
if (ucontrol->value.enumerated.item[0] > e->mask - 1)
return -EINVAL;
val = ucontrol->value.enumerated.item[0] << e->shift_l;
- mask = (e->mask - 1) << e->shift_l;
+ mask = (bitmask - 1) << e->shift_l;
if (e->shift_l != e->shift_r) {
if (ucontrol->value.enumerated.item[1] > e->mask - 1)
return -EINVAL;
val |= ucontrol->value.enumerated.item[1] << e->shift_r;
- mask |= (e->mask - 1) << e->shift_r;
+ mask |= (bitmask - 1) << e->shift_r;
}
return snd_ac97_update_bits(ac97, e->reg, mask, val);
}
AC97_SINGLE("LFE Playback Volume", AC97_CENTER_LFE_MASTER, 8, 31, 1)
};
-static const snd_kcontrol_new_t snd_ac97_controls_surround[2] = {
-AC97_DOUBLE("Surround Playback Switch", AC97_SURROUND_MASTER, 15, 7, 1, 1),
-AC97_DOUBLE("Surround Playback Volume", AC97_SURROUND_MASTER, 8, 0, 31, 1),
-};
-
static const snd_kcontrol_new_t snd_ac97_control_eapd =
AC97_SINGLE("External Amplifier", AC97_POWERDOWN, 15, 1, 1);
+static const snd_kcontrol_new_t snd_ac97_controls_modem_switches[2] = {
+AC97_SINGLE("Off-hook Switch", AC97_GPIO_STATUS, 0, 1, 0),
+AC97_SINGLE("Caller ID Switch", AC97_GPIO_STATUS, 2, 1, 0)
+};
+
/* change the existing EAPD control as inverted */
static void set_inv_eapd(ac97_t *ac97, snd_kcontrol_t *kctl)
{
unsigned short val;
snd_ac97_write(ac97, reg, 0x8080 | cbit[i] | (cbit[i] << 8));
val = snd_ac97_read(ac97, reg);
- if (! *lo_max && (val & cbit[i]))
+ if (! *lo_max && (val & 0x7f) == cbit[i])
*lo_max = max[i];
- if (! *hi_max && (val & (cbit[i] << 8)))
+ if (! *hi_max && ((val >> 8) & 0x7f) == cbit[i])
*hi_max = max[i];
if (*lo_max && *hi_max)
break;
static int snd_ac97_modem_build(snd_card_t * card, ac97_t * ac97)
{
- /* TODO */
+ int err, idx;
+
//printk("AC97_GPIO_CFG = %x\n",snd_ac97_read(ac97,AC97_GPIO_CFG));
snd_ac97_write(ac97, AC97_GPIO_CFG, 0xffff & ~(AC97_GPIO_LINE1_OH));
snd_ac97_write(ac97, AC97_GPIO_POLARITY, 0xffff & ~(AC97_GPIO_LINE1_OH));
snd_ac97_write(ac97, AC97_GPIO_STICKY, 0xffff);
snd_ac97_write(ac97, AC97_GPIO_WAKEUP, 0x0);
snd_ac97_write(ac97, AC97_MISC_AFE, 0x0);
+
+ /* build modem switches */
+ for (idx = 0; idx < ARRAY_SIZE(snd_ac97_controls_modem_switches); idx++)
+ if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_modem_switches[idx], ac97))) < 0)
+ return err;
+
+ /* build chip specific controls */
+ if (ac97->build_ops->build_specific)
+ if ((err = ac97->build_ops->build_specific(ac97)) < 0)
+ return err;
+
return 0;
}
goto __access_ok;
}
- snd_ac97_write(ac97, AC97_RESET, 0); /* reset to defaults */
+ /* reset to defaults */
+ if (!(ac97->scaps & AC97_SCAP_SKIP_AUDIO))
+ snd_ac97_write(ac97, AC97_RESET, 0);
+ if (!(ac97->scaps & AC97_SCAP_SKIP_MODEM))
+ snd_ac97_write(ac97, AC97_EXTENDED_MID, 0);
if (bus->ops->wait)
bus->ops->wait(ac97);
else {
/* note: it's important to set the rate at first */
tmp = AC97_MEA_GPIO;
if (ac97->ext_mid & AC97_MEI_LINE1) {
- snd_ac97_write_cache(ac97, AC97_LINE1_RATE, 12000);
+ snd_ac97_write_cache(ac97, AC97_LINE1_RATE, 8000);
tmp |= AC97_MEA_ADC1 | AC97_MEA_DAC1;
}
if (ac97->ext_mid & AC97_MEI_LINE2) {
- snd_ac97_write_cache(ac97, AC97_LINE2_RATE, 12000);
+ snd_ac97_write_cache(ac97, AC97_LINE2_RATE, 8000);
tmp |= AC97_MEA_ADC2 | AC97_MEA_DAC2;
}
if (ac97->ext_mid & AC97_MEI_HANDSET) {
- snd_ac97_write_cache(ac97, AC97_HANDSET_RATE, 12000);
+ snd_ac97_write_cache(ac97, AC97_HANDSET_RATE, 8000);
tmp |= AC97_MEA_HADC | AC97_MEA_HDAC;
}
- snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0xff00 & ~(tmp << 8));
+ snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0);
udelay(100);
/* nothing should be in powerdown mode */
- snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0xff00 & ~(tmp << 8));
+ snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0);
end_time = jiffies + (HZ / 10);
do {
if ((snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS) & tmp) == tmp)
return result;
}
- for (; quirk->vendor; quirk++) {
- if (quirk->vendor != ac97->subsystem_vendor)
+ for (; quirk->subvendor; quirk++) {
+ if (quirk->subvendor != ac97->subsystem_vendor)
continue;
- if ((! quirk->mask && quirk->device == ac97->subsystem_device) ||
- quirk->device == (quirk->mask & ac97->subsystem_device)) {
+ if ((! quirk->mask && quirk->subdevice == ac97->subsystem_device) ||
+ quirk->subdevice == (quirk->mask & ac97->subsystem_device)) {
if (quirk->codec_id && quirk->codec_id != ac97->id)
continue;
snd_printdd("ac97 quirk for %s (%04x:%04x)\n", quirk->name, ac97->subsystem_vendor, ac97->subsystem_device);
return ret;
}
+/*
+ * shared line-in/mic controls
+ */
+static int ac97_enum_text_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo,
+ const char **texts, unsigned int nums)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = nums;
+ if (uinfo->value.enumerated.item > nums - 1)
+ uinfo->value.enumerated.item = nums - 1;
+ strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+static int ac97_surround_jack_mode_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+ static const char *texts[] = { "Shared", "Independent" };
+ return ac97_enum_text_info(kcontrol, uinfo, texts, 2);
+}
+
+static int ac97_surround_jack_mode_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+ ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.enumerated.item[0] = ac97->indep_surround;
+ return 0;
+}
+
+static int ac97_surround_jack_mode_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+ ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+ unsigned char indep = !!ucontrol->value.enumerated.item[0];
+
+ if (indep != ac97->indep_surround) {
+ ac97->indep_surround = indep;
+ if (ac97->build_ops->update_jacks)
+ ac97->build_ops->update_jacks(ac97);
+ return 1;
+ }
+ return 0;
+}
+
+static int ac97_channel_mode_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+ static const char *texts[] = { "2ch", "4ch", "6ch" };
+ if (kcontrol->private_value)
+ return ac97_enum_text_info(kcontrol, uinfo, texts, 2); /* 4ch only */
+ return ac97_enum_text_info(kcontrol, uinfo, texts, 3);
+}
+
+static int ac97_channel_mode_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+ ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.enumerated.item[0] = ac97->channel_mode;
+ return 0;
+}
+
+static int ac97_channel_mode_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+ ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+ unsigned char mode = ucontrol->value.enumerated.item[0];
+
+ if (mode != ac97->channel_mode) {
+ ac97->channel_mode = mode;
+ if (ac97->build_ops->update_jacks)
+ ac97->build_ops->update_jacks(ac97);
+ return 1;
+ }
+ return 0;
+}
+
+#define AC97_SURROUND_JACK_MODE_CTL \
+ { \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = "Surround Jack Mode", \
+ .info = ac97_surround_jack_mode_info, \
+ .get = ac97_surround_jack_mode_get, \
+ .put = ac97_surround_jack_mode_put, \
+ }
+#define AC97_CHANNEL_MODE_CTL \
+ { \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = "Channel Mode", \
+ .info = ac97_channel_mode_info, \
+ .get = ac97_channel_mode_get, \
+ .put = ac97_channel_mode_put, \
+ }
+#define AC97_CHANNEL_MODE_4CH_CTL \
+ { \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = "Channel Mode", \
+ .info = ac97_channel_mode_info, \
+ .get = ac97_channel_mode_get, \
+ .put = ac97_channel_mode_put, \
+ .private_value = 1, \
+ }
+
+static inline int is_shared_linein(ac97_t *ac97)
+{
+ return ! ac97->indep_surround && ac97->channel_mode >= 1;
+}
+
+static inline int is_shared_micin(ac97_t *ac97)
+{
+ return ! ac97->indep_surround && ac97->channel_mode >= 2;
+}
+
+
/* The following snd_ac97_ymf753_... items added by David Shust (dshust@shustring.com) */
/* It is possible to indicate to the Yamaha YMF753 the type of speakers being used. */
AC97_AD198X_DMIX0 | AC97_AD198X_DMIX1, val);
}
+static void ad1888_update_jacks(ac97_t *ac97)
+{
+ /* shared Line-In */
+ snd_ac97_update_bits(ac97, AC97_AD_MISC, 1 << 12,
+ is_shared_linein(ac97) ? 0 : 1 << 12);
+ /* shared Mic */
+ snd_ac97_update_bits(ac97, AC97_AD_MISC, 1 << 11,
+ is_shared_micin(ac97) ? 0 : 1 << 11);
+}
+
static const snd_kcontrol_new_t snd_ac97_ad1888_controls[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.get = snd_ac97_ad1888_downmix_get,
.put = snd_ac97_ad1888_downmix_put
},
- AC97_SINGLE("Surround Jack as Input", AC97_AD_MISC, 12, 1, 0),
- AC97_SINGLE("Center/LFE Jack as Input", AC97_AD_MISC, 11, 1, 0),
+ AC97_SURROUND_JACK_MODE_CTL,
+ AC97_CHANNEL_MODE_CTL,
};
static int patch_ad1888_specific(ac97_t *ac97)
.build_post_spdif = patch_ad198x_post_spdif,
.build_specific = patch_ad1888_specific,
#ifdef CONFIG_PM
- .resume = ad18xx_resume
+ .resume = ad18xx_resume,
#endif
+ .update_jacks = ad1888_update_jacks,
};
int patch_ad1888(ac97_t * ac97)
.build_post_spdif = patch_ad198x_post_spdif,
.build_specific = patch_ad1980_specific,
#ifdef CONFIG_PM
- .resume = ad18xx_resume
+ .resume = ad18xx_resume,
#endif
+ .update_jacks = ad1888_update_jacks,
};
int patch_ad1980(ac97_t * ac97)
}
static const snd_kcontrol_new_t snd_ac97_ad1985_controls[] = {
- AC97_SINGLE("Center/LFE Jack as Mic", AC97_AD_SERIAL_CFG, 9, 1, 0),
AC97_SINGLE("Exchange Center/LFE", AC97_AD_SERIAL_CFG, 3, 1, 0)
};
+static void ad1985_update_jacks(ac97_t *ac97)
+{
+ /* shared Line-In */
+ snd_ac97_update_bits(ac97, AC97_AD_MISC, 1 << 12,
+ is_shared_linein(ac97) ? 0 : 1 << 12);
+ /* shared Mic */
+ snd_ac97_update_bits(ac97, AC97_AD_MISC, 1 << 11,
+ is_shared_micin(ac97) ? 0 : 1 << 11);
+ snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 1 << 9,
+ is_shared_micin(ac97) ? 0 : 1 << 9);
+}
+
static int patch_ad1985_specific(ac97_t *ac97)
{
int err;
.build_post_spdif = patch_ad198x_post_spdif,
.build_specific = patch_ad1985_specific,
#ifdef CONFIG_PM
- .resume = ad18xx_resume
+ .resume = ad18xx_resume,
#endif
+ .update_jacks = ad1985_update_jacks,
};
int patch_ad1985(ac97_t * ac97)
/*
* realtek ALC65x/850 codecs
*/
-static int snd_ac97_alc650_mic_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol)
-{
- ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
- ucontrol->value.integer.value[0] = (ac97->regs[AC97_ALC650_MULTICH] >> 10) & 1;
- return 0;
-}
-
-static int snd_ac97_alc650_mic_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol)
+static void alc650_update_jacks(ac97_t *ac97)
{
- ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
- int change, val;
- val = !!(snd_ac97_read(ac97, AC97_ALC650_MULTICH) & (1 << 10));
- change = (ucontrol->value.integer.value[0] != val);
- if (change) {
- /* disable/enable vref */
- snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12,
- ucontrol->value.integer.value[0] ? (1 << 12) : 0);
- /* turn on/off center-on-mic */
- snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 10,
- ucontrol->value.integer.value[0] ? (1 << 10) : 0);
- /* GPIO0 high for mic */
- snd_ac97_update_bits(ac97, AC97_ALC650_GPIO_STATUS, 0x100,
- ucontrol->value.integer.value[0] ? 0 : 0x100);
- }
- return change;
+ int shared;
+
+ /* shared Line-In */
+ shared = is_shared_linein(ac97);
+ snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 9,
+ shared ? (1 << 9) : 0);
+ /* update shared Mic */
+ shared = is_shared_micin(ac97);
+ /* disable/enable vref */
+ snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12,
+ shared ? (1 << 12) : 0);
+ /* turn on/off center-on-mic */
+ snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 10,
+ shared ? (1 << 10) : 0);
+ /* GPIO0 high for mic */
+ snd_ac97_update_bits(ac97, AC97_ALC650_GPIO_STATUS, 0x100,
+ shared ? 0 : 0x100);
}
static const snd_kcontrol_new_t snd_ac97_controls_alc650[] = {
/* 6: Independent Master Volume Right */
/* 7: Independent Master Volume Left */
/* 8: reserved */
- AC97_SINGLE("Line-In As Surround", AC97_ALC650_MULTICH, 9, 1, 0),
- /* 10: mic, see below */
+ /* 9: Line-In/Surround share */
+ /* 10: Mic/CLFE share */
/* 11-13: in IEC958 controls */
AC97_SINGLE("Swap Surround Slot", AC97_ALC650_MULTICH, 14, 1, 0),
#if 0 /* always set in patch_alc650 */
AC97_SINGLE("Center/LFE DAC Switch", AC97_ALC650_LFE_DAC_VOL, 15, 1, 1),
AC97_DOUBLE("Center/LFE DAC Volume", AC97_ALC650_LFE_DAC_VOL, 8, 0, 31, 1),
#endif
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Mic As Center/LFE",
- .info = snd_ac97_info_volsw,
- .get = snd_ac97_alc650_mic_get,
- .put = snd_ac97_alc650_mic_put,
- .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */
- },
+ AC97_SURROUND_JACK_MODE_CTL,
+ AC97_CHANNEL_MODE_CTL,
};
static const snd_kcontrol_new_t snd_ac97_spdif_controls_alc650[] = {
}
static struct snd_ac97_build_ops patch_alc650_ops = {
- .build_specific = patch_alc650_specific
+ .build_specific = patch_alc650_specific,
+ .update_jacks = alc650_update_jacks
};
int patch_alc650(ac97_t * ac97)
return 0;
}
-static int snd_ac97_alc655_mic_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol)
-{
- ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
- ucontrol->value.integer.value[0] = (ac97->regs[AC97_ALC650_MULTICH] >> 10) & 1;
- return 0;
-}
-
-static int snd_ac97_alc655_mic_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol)
+static void alc655_update_jacks(ac97_t *ac97)
{
- ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
-
+ int shared;
+
+ /* shared Line-In */
+ shared = is_shared_linein(ac97);
+ ac97_update_bits_page(ac97, AC97_ALC650_MULTICH, 1 << 9,
+ shared ? (1 << 9) : 0, 0);
+ /* update shared mic */
+ shared = is_shared_micin(ac97);
/* misc control; vrefout disable */
snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12,
- ucontrol->value.integer.value[0] ? (1 << 12) : 0);
- return ac97_update_bits_page(ac97, AC97_ALC650_MULTICH, 1 << 10,
- ucontrol->value.integer.value[0] ? (1 << 10) : 0,
- 0);
+ shared ? (1 << 12) : 0);
+ ac97_update_bits_page(ac97, AC97_ALC650_MULTICH, 1 << 10,
+ shared ? (1 << 10) : 0, 0);
}
-
static const snd_kcontrol_new_t snd_ac97_controls_alc655[] = {
AC97_PAGE_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0, 0),
- AC97_PAGE_SINGLE("Line-In As Surround", AC97_ALC650_MULTICH, 9, 1, 0, 0),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Mic As Center/LFE",
- .info = snd_ac97_info_volsw,
- .get = snd_ac97_alc655_mic_get,
- .put = snd_ac97_alc655_mic_put,
- .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */
- },
+ AC97_SURROUND_JACK_MODE_CTL,
+ AC97_CHANNEL_MODE_CTL,
};
static int alc655_iec958_route_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
}
static struct snd_ac97_build_ops patch_alc655_ops = {
- .build_specific = patch_alc655_specific
+ .build_specific = patch_alc655_specific,
+ .update_jacks = alc655_update_jacks
};
int patch_alc655(ac97_t * ac97)
#define AC97_ALC850_JACK_SELECT 0x76
#define AC97_ALC850_MISC1 0x7a
-static int ac97_alc850_surround_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol)
-{
- ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
- ucontrol->value.integer.value[0] = ((ac97->regs[AC97_ALC850_JACK_SELECT] >> 12) & 7) == 2;
- return 0;
-}
-
-static int ac97_alc850_surround_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol)
+static void alc850_update_jacks(ac97_t *ac97)
{
- ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
-
+ int shared;
+
+ /* shared Line-In */
+ shared = is_shared_linein(ac97);
/* SURR 1kOhm (bit4), Amp (bit5) */
snd_ac97_update_bits(ac97, AC97_ALC850_MISC1, (1<<4)|(1<<5),
- ucontrol->value.integer.value[0] ? (1<<5) : (1<<4));
+ shared ? (1<<5) : (1<<4));
/* LINE-IN = 0, SURROUND = 2 */
- return snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 12,
- ucontrol->value.integer.value[0] ? (2<<12) : (0<<12));
-}
-
-static int ac97_alc850_mic_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol)
-{
- ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
- ucontrol->value.integer.value[0] = ((ac97->regs[AC97_ALC850_JACK_SELECT] >> 4) & 7) == 2;
- return 0;
-}
-
-static int ac97_alc850_mic_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol)
-{
- ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
-
+ snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 12,
+ shared ? (2<<12) : (0<<12));
+ /* update shared mic */
+ shared = is_shared_micin(ac97);
/* Vref disable (bit12), 1kOhm (bit13) */
snd_ac97_update_bits(ac97, AC97_ALC850_MISC1, (1<<12)|(1<<13),
- ucontrol->value.integer.value[0] ? (1<<12) : (1<<13));
+ shared ? (1<<12) : (1<<13));
/* MIC-IN = 1, CENTER-LFE = 2 */
- return snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 4,
- ucontrol->value.integer.value[0] ? (2<<4) : (1<<4));
+ snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 4,
+ shared ? (2<<4) : (1<<4));
}
static const snd_kcontrol_new_t snd_ac97_controls_alc850[] = {
AC97_PAGE_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0, 0),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Line-In As Surround",
- .info = snd_ac97_info_volsw,
- .get = ac97_alc850_surround_get,
- .put = ac97_alc850_surround_put,
- .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */
- },
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Mic As Center/LFE",
- .info = snd_ac97_info_volsw,
- .get = ac97_alc850_mic_get,
- .put = ac97_alc850_mic_put,
- .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */
- },
-
+ AC97_SINGLE("Mic Front Input Switch", AC97_ALC850_JACK_SELECT, 15, 1, 1),
+ AC97_SURROUND_JACK_MODE_CTL,
+ AC97_CHANNEL_MODE_CTL,
};
static int patch_alc850_specific(ac97_t *ac97)
}
static struct snd_ac97_build_ops patch_alc850_ops = {
- .build_specific = patch_alc850_specific
+ .build_specific = patch_alc850_specific,
+ .update_jacks = alc850_update_jacks
};
int patch_alc850(ac97_t *ac97)
/*
* C-Media CM97xx codecs
*/
+static void cm9738_update_jacks(ac97_t *ac97)
+{
+ /* shared Line-In */
+ snd_ac97_update_bits(ac97, AC97_CM9738_VENDOR_CTRL, 1 << 10,
+ is_shared_linein(ac97) ? (1 << 10) : 0);
+}
+
static const snd_kcontrol_new_t snd_ac97_cm9738_controls[] = {
- AC97_SINGLE("Line-In As Surround", AC97_CM9738_VENDOR_CTRL, 10, 1, 0),
AC97_SINGLE("Duplicate Front", AC97_CM9738_VENDOR_CTRL, 13, 1, 0),
+ AC97_SURROUND_JACK_MODE_CTL,
+ AC97_CHANNEL_MODE_4CH_CTL,
};
static int patch_cm9738_specific(ac97_t * ac97)
}
static struct snd_ac97_build_ops patch_cm9738_ops = {
- .build_specific = patch_cm9738_specific
+ .build_specific = patch_cm9738_specific,
+ .update_jacks = cm9738_update_jacks
};
int patch_cm9738(ac97_t * ac97)
/* BIT 8: SPD32 - 32bit SPDIF - not supported yet */
};
-static int snd_ac97_cm9739_center_mic_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
-{
- ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
- if (ac97->regs[AC97_CM9739_MULTI_CHAN] & 0x1000)
- ucontrol->value.integer.value[0] = 1;
- else
- ucontrol->value.integer.value[0] = 0;
- return 0;
-}
-
-static int snd_ac97_cm9739_center_mic_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+static void cm9739_update_jacks(ac97_t *ac97)
{
- ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
- return snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 0x3000,
- ucontrol->value.integer.value[0] ?
- 0x1000 : 0x2000);
+ /* shared Line-In */
+ snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 1 << 10,
+ is_shared_linein(ac97) ? (1 << 10) : 0);
+ /* shared Mic */
+ snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 0x3000,
+ is_shared_micin(ac97) ? 0x1000 : 0x2000);
}
static const snd_kcontrol_new_t snd_ac97_cm9739_controls[] = {
- AC97_SINGLE("Line-In As Surround", AC97_CM9739_MULTI_CHAN, 10, 1, 0),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Mic As Center/LFE",
- .info = snd_ac97_info_volsw,
- .get = snd_ac97_cm9739_center_mic_get,
- .put = snd_ac97_cm9739_center_mic_put,
- .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */
- },
+ AC97_SURROUND_JACK_MODE_CTL,
+ AC97_CHANNEL_MODE_CTL,
};
static int patch_cm9739_specific(ac97_t * ac97)
static struct snd_ac97_build_ops patch_cm9739_ops = {
.build_specific = patch_cm9739_specific,
- .build_post_spdif = patch_cm9739_post_spdif
+ .build_post_spdif = patch_cm9739_post_spdif,
+ .update_jacks = cm9739_update_jacks
};
int patch_cm9739(ac97_t * ac97)
}
#define AC97_CM9761_MULTI_CHAN 0x64
+#define AC97_CM9761_FUNC 0x66
#define AC97_CM9761_SPDIF_CTRL 0x6c
-static int snd_ac97_cm9761_linein_rear_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
-{
- ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
- if (ac97->regs[AC97_CM9739_MULTI_CHAN] & 0x0400)
- ucontrol->value.integer.value[0] = 1;
- else
- ucontrol->value.integer.value[0] = 0;
- return 0;
-}
-
-static int snd_ac97_cm9761_linein_rear_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+static void cm9761_update_jacks(ac97_t *ac97)
{
- ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
- unsigned short vals[2][2] = {
+ unsigned short surr_vals[2][2] = {
{ 0x0008, 0x0400 }, /* off, on */
{ 0x0000, 0x0408 }, /* off, on (9761-82 rev.B) */
};
- return snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 0x0408,
- vals[ac97->spec.dev_flags][!!ucontrol->value.integer.value[0]]);
+ unsigned short clfe_vals[2][2] = {
+ { 0x2000, 0x1880 }, /* off, on */
+ { 0x1000, 0x2880 }, /* off, on (9761-82 rev.B) */
+ };
+
+ /* shared Line-In */
+ snd_ac97_update_bits(ac97, AC97_CM9761_MULTI_CHAN, 0x0408,
+ surr_vals[ac97->spec.dev_flags][is_shared_linein(ac97)]);
+ /* shared Mic */
+ snd_ac97_update_bits(ac97, AC97_CM9761_MULTI_CHAN, 0x3880,
+ clfe_vals[ac97->spec.dev_flags][is_shared_micin(ac97)]);
+}
+
+static const snd_kcontrol_new_t snd_ac97_cm9761_controls[] = {
+ AC97_SURROUND_JACK_MODE_CTL,
+ AC97_CHANNEL_MODE_CTL,
+};
+
+static int cm9761_spdif_out_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+ static char *texts[] = { "AC-Link", "ADC", "SPDIF-In" };
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 3;
+ if (uinfo->value.enumerated.item > 2)
+ uinfo->value.enumerated.item = 2;
+ strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+ return 0;
}
-static int snd_ac97_cm9761_center_mic_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+static int cm9761_spdif_out_source_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
{
ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
- if (ac97->regs[AC97_CM9739_MULTI_CHAN] & 0x1000)
- ucontrol->value.integer.value[0] = 1;
+
+ if (ac97->regs[AC97_CM9761_FUNC] & 0x1)
+ ucontrol->value.enumerated.item[0] = 2; /* SPDIF-loopback */
+ else if (ac97->regs[AC97_CM9761_SPDIF_CTRL] & 0x2)
+ ucontrol->value.enumerated.item[0] = 1; /* ADC loopback */
else
- ucontrol->value.integer.value[0] = 0;
- if (ac97->spec.dev_flags) /* 9761-82 rev.B */
- ucontrol->value.integer.value[0] = !ucontrol->value.integer.value[0];
+ ucontrol->value.enumerated.item[0] = 0; /* AC-link */
return 0;
}
-static int snd_ac97_cm9761_center_mic_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+static int cm9761_spdif_out_source_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
{
ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
- unsigned short vals[2][2] = {
- { 0x2000, 0x1880 }, /* off, on */
- { 0x1000, 0x2880 }, /* off, on (9761-82 rev.B) */
- };
- return snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 0x3880,
- vals[ac97->spec.dev_flags][!!ucontrol->value.integer.value[0]]);
+
+ if (ucontrol->value.enumerated.item[0] == 2)
+ return snd_ac97_update_bits(ac97, AC97_CM9761_FUNC, 0x1, 0x1);
+ snd_ac97_update_bits(ac97, AC97_CM9761_FUNC, 0x1, 0);
+ return snd_ac97_update_bits(ac97, AC97_CM9761_SPDIF_CTRL, 0x2,
+ ucontrol->value.enumerated.item[0] == 1 ? 0x2 : 0);
}
-static const snd_kcontrol_new_t snd_ac97_cm9761_controls[] = {
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Line-In As Surround",
- .info = snd_ac97_info_volsw,
- .get = snd_ac97_cm9761_linein_rear_get,
- .put = snd_ac97_cm9761_linein_rear_put,
- .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */
- },
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Mic As Center/LFE",
- .info = snd_ac97_info_volsw,
- .get = snd_ac97_cm9761_center_mic_get,
- .put = snd_ac97_cm9761_center_mic_put,
- .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */
+static const char *cm9761_dac_clock[] = { "AC-Link", "SPDIF-In", "Both" };
+static const struct ac97_enum cm9761_dac_clock_enum =
+ AC97_ENUM_SINGLE(AC97_CM9761_SPDIF_CTRL, 9, 3, cm9761_dac_clock);
+
+static const snd_kcontrol_new_t snd_ac97_cm9761_controls_spdif[] = {
+ { /* BIT 1: SPDIFS */
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
+ .info = cm9761_spdif_out_source_info,
+ .get = cm9761_spdif_out_source_get,
+ .put = cm9761_spdif_out_source_put,
},
+ /* BIT 2: IG_SPIV */
+ AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Valid Switch", AC97_CM9761_SPDIF_CTRL, 2, 1, 0),
+ /* BIT 3: SPI2F */
+ AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Monitor", AC97_CM9761_SPDIF_CTRL, 3, 1, 0),
+ /* BIT 4: SPI2SDI */
+ AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), AC97_CM9761_SPDIF_CTRL, 4, 1, 0),
+ /* BIT 9-10: DAC_CTL */
+ AC97_ENUM("DAC Clock Source", cm9761_dac_clock_enum),
};
+static int patch_cm9761_post_spdif(ac97_t * ac97)
+{
+ return patch_build_controls(ac97, snd_ac97_cm9761_controls_spdif, ARRAY_SIZE(snd_ac97_cm9761_controls_spdif));
+}
+
static int patch_cm9761_specific(ac97_t * ac97)
{
return patch_build_controls(ac97, snd_ac97_cm9761_controls, ARRAY_SIZE(snd_ac97_cm9761_controls));
static struct snd_ac97_build_ops patch_cm9761_ops = {
.build_specific = patch_cm9761_specific,
- .build_post_spdif = patch_cm9739_post_spdif /* hope it's identical... */
+ .build_post_spdif = patch_cm9761_post_spdif,
+ .update_jacks = cm9761_update_jacks
};
int patch_cm9761(ac97_t *ac97)
/* to be sure: we overwrite the ext status bits */
snd_ac97_write_cache(ac97, AC97_EXTENDED_STATUS, 0x05c0);
/* Don't set 0x0200 here. This results in the silent analog output */
- snd_ac97_write_cache(ac97, AC97_CM9761_SPDIF_CTRL, 0x0009);
+ snd_ac97_write_cache(ac97, AC97_CM9761_SPDIF_CTRL, 0x0001); /* enable spdif-in */
ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_48000; /* 48k only */
/* set-up multi channel */
/* bit 15: pc master beep off
- * bit 14: ??
+ * bit 14: pin47 = EAPD/SPDIF
* bit 13: vref ctl [= cm9739]
- * bit 12: center/mic [= cm9739] (reverted on rev B)
- * bit 11: ?? (mic/center/lfe) (reverted on rev B)
- * bit 10: suddound/line [= cm9739]
- * bit 9: mix 2 surround
- * bit 8: ?
- * bit 7: ?? (mic/center/lfe)
- * bit 4: ?? (front)
- * bit 3: ?? (line-in/rear share) (revereted with rev B)
- * bit 2: ?? (surround)
- * bit 1: front mic
- * bit 0: mic boost
+ * bit 12: CLFE control (reverted on rev B)
+ * bit 11: Mic/center share (reverted on rev B)
+ * bit 10: suddound/line share
+ * bit 9: Analog-in mix -> surround
+ * bit 8: Analog-in mix -> CLFE
+ * bit 7: Mic/LFE share (mic/center/lfe)
+ * bit 5: vref select (9761A)
+ * bit 4: front control
+ * bit 3: surround control (revereted with rev B)
+ * bit 2: front mic
+ * bit 1: stereo mic
+ * bit 0: mic boost level (0=20dB, 1=30dB)
*/
#if 0
return 0;
}
+#define AC97_CM9780_SIDE 0x60
+#define AC97_CM9780_JACK 0x62
+#define AC97_CM9780_MIXER 0x64
+#define AC97_CM9780_MULTI_CHAN 0x66
+#define AC97_CM9780_SPDIF 0x6c
+
+static const char *cm9780_ch_select[] = { "Front", "Side", "Center/LFE", "Rear" };
+static const struct ac97_enum cm9780_ch_select_enum =
+ AC97_ENUM_SINGLE(AC97_CM9780_MULTI_CHAN, 6, 4, cm9780_ch_select);
+static const snd_kcontrol_new_t cm9780_controls[] = {
+ AC97_DOUBLE("Side Playback Switch", AC97_CM9780_SIDE, 15, 7, 1, 1),
+ AC97_DOUBLE("Side Playback Volume", AC97_CM9780_SIDE, 8, 0, 31, 0),
+ AC97_ENUM("Side Playback Route", cm9780_ch_select_enum),
+};
+
+static int patch_cm9780_specific(ac97_t *ac97)
+{
+ return patch_build_controls(ac97, cm9780_controls, ARRAY_SIZE(cm9780_controls));
+}
+
+static struct snd_ac97_build_ops patch_cm9780_ops = {
+ .build_specific = patch_cm9780_specific,
+ .build_post_spdif = patch_cm9761_post_spdif /* identical with CM9761 */
+};
+
+int patch_cm9780(ac97_t *ac97)
+{
+ unsigned short val;
+
+ ac97->build_ops = &patch_cm9780_ops;
+
+ /* enable spdif */
+ if (ac97->ext_id & AC97_EI_SPDIF) {
+ ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_48000; /* 48k only */
+ val = snd_ac97_read(ac97, AC97_CM9780_SPDIF);
+ val |= 0x1; /* SPDI_EN */
+ snd_ac97_write_cache(ac97, AC97_CM9780_SPDIF, val);
+ }
+
+ return 0;
+}
/*
* VIA VT1616 codec
return 0;
}
+/*
+ */
+static void it2646_update_jacks(ac97_t *ac97)
+{
+ /* shared Line-In */
+ snd_ac97_update_bits(ac97, 0x76, 1 << 9,
+ is_shared_linein(ac97) ? (1<<9) : 0);
+ /* shared Mic */
+ snd_ac97_update_bits(ac97, 0x76, 1 << 10,
+ is_shared_micin(ac97) ? (1<<10) : 0);
+}
+
static const snd_kcontrol_new_t snd_ac97_controls_it2646[] = {
- AC97_SINGLE("Line-In As Surround", 0x76, 9, 1, 0),
- AC97_SINGLE("Mic As Center/LFE", 0x76, 10, 1, 0),
+ AC97_SURROUND_JACK_MODE_CTL,
+ AC97_CHANNEL_MODE_CTL,
};
static const snd_kcontrol_new_t snd_ac97_spdif_controls_it2646[] = {
}
static struct snd_ac97_build_ops patch_it2646_ops = {
- .build_specific = patch_it2646_specific
+ .build_specific = patch_it2646_specific,
+ .update_jacks = it2646_update_jacks
};
int patch_it2646(ac97_t * ac97)
return 0;
}
-/* Si3036/8 specific registers */
+/*
+ * Si3036 codec
+ */
+
#define AC97_SI3036_CHIP_ID 0x5a
+#define AC97_SI3036_LINE_CFG 0x5c
+
+static const snd_kcontrol_new_t snd_ac97_controls_si3036[] = {
+AC97_DOUBLE("Modem Speaker Volume", 0x5c, 14, 12, 3, 1)
+};
+
+static int patch_si3036_specific(ac97_t * ac97)
+{
+ return patch_build_controls(ac97, snd_ac97_controls_si3036, ARRAY_SIZE(snd_ac97_controls_si3036));
+}
+
+static struct snd_ac97_build_ops patch_si3036_ops = {
+ .build_specific = patch_si3036_specific,
+};
int mpatch_si3036(ac97_t * ac97)
{
- //printk("mpatch_si3036: chip id = %x\n", snd_ac97_read(ac97, 0x5a));
+ ac97->build_ops = &patch_si3036_ops;
snd_ac97_write_cache(ac97, 0x5c, 0xf210 );
snd_ac97_write_cache(ac97, 0x68, 0);
return 0;
int patch_cm9738(ac97_t * ac97);
int patch_cm9739(ac97_t * ac97);
int patch_cm9761(ac97_t * ac97);
+int patch_cm9780(ac97_t * ac97);
int patch_vt1616(ac97_t * ac97);
int patch_it2646(ac97_t * ac97);
int mpatch_si3036(ac97_t * ac97);
#define ALI_LEF_CHANNEL 23
#define ALI_SURR_LEFT_CHANNEL 26
#define ALI_SURR_RIGHT_CHANNEL 25
+#define ALI_MODEM_IN_CHANNEL 21
+#define ALI_MODEM_OUT_CHANNEL 20
#define SNDRV_ALI_VOICE_TYPE_PCM 01
#define SNDRV_ALI_VOICE_TYPE_OTH 02
#define ALI_SCTRL 0x48
#define ALI_SPDIF_OUT_ENABLE 0x20
+#define ALI_SCTRL_LINE_IN2 (1 << 9)
+#define ALI_SCTRL_GPIO_IN2 (1 << 13)
+#define ALI_SCTRL_LINE_OUT_EN (1 << 20)
+#define ALI_SCTRL_GPIO_OUT_EN (1 << 23)
+#define ALI_SCTRL_CODEC1_READY (1 << 24)
+#define ALI_SCTRL_CODEC2_READY (1 << 25)
#define ALI_AC97_GPIO 0x4c
+#define ALI_AC97_GPIO_ENABLE 0x8000
+#define ALI_AC97_GPIO_DATA_SHIFT 16
#define ALI_SPDIF_CS 0x70
#define ALI_SPDIF_CTRL 0x74
#define ALI_SPDIF_IN_FUNC_ENABLE 0x02
#define TARGET_REACHED 0x00008000
#define MIXER_OVERFLOW 0x00000800
#define MIXER_UNDERFLOW 0x00000400
+ #define GPIO_IRQ 0x01000000
#define ALI_SBBL_SBCL 0xc0
#define ALI_SBCTRL_SBE2R_SBDD 0xc4
#define ALI_STIMER 0xc8
#define ALI_REG(codec, x) ((codec)->port + x)
+#define MAX_CODECS 2
+
+
typedef struct snd_stru_ali ali_t;
typedef struct snd_ali_stru_voice snd_ali_voice_t;
struct pci_dev *pci_m7101;
snd_card_t *card;
- snd_pcm_t *pcm;
+ snd_pcm_t *pcm[MAX_CODECS];
alidev_t synth;
snd_ali_channel_control_t chregs;
unsigned int spurious_irq_count;
unsigned int spurious_irq_max_delta;
+ unsigned int num_of_codecs;
+
ac97_bus_t *ac97_bus;
- ac97_t *ac97;
+ ac97_t *ac97[MAX_CODECS];
unsigned short ac97_ext_id;
unsigned short ac97_ext_status;
ali_t *codec = ac97->private_data;
snd_ali_printk("codec_write: reg=%xh data=%xh.\n", reg, val);
- snd_ali_codec_poke(codec, 0, reg, val);
+ if(reg == AC97_GPIO_STATUS) {
+ outl((val << ALI_AC97_GPIO_DATA_SHIFT)|ALI_AC97_GPIO_ENABLE,
+ ALI_REG(codec, ALI_AC97_GPIO));
+ return;
+ }
+ snd_ali_codec_poke(codec, ac97->num, reg, val);
return ;
}
ali_t *codec = ac97->private_data;
snd_ali_printk("codec_read reg=%xh.\n", reg);
- return (snd_ali_codec_peek(codec, 0, reg));
+ return (snd_ali_codec_peek(codec, ac97->num, reg));
}
/*
}
-static snd_ali_voice_t *snd_ali_alloc_voice(ali_t * codec, int type, int rec)
+static snd_ali_voice_t *snd_ali_alloc_voice(ali_t * codec, int type, int rec, int channel)
{
snd_ali_voice_t *pvoice = NULL;
unsigned long flags;
spin_lock_irqsave(&codec->voice_alloc, flags);
if (type == SNDRV_ALI_VOICE_TYPE_PCM) {
- idx = snd_ali_find_free_channel(codec,rec);
+ idx = channel > 0 ? snd_ali_alloc_pcm_channel(codec, channel) :
+ snd_ali_find_free_channel(codec,rec);
if(idx < 0) {
snd_printk("ali_alloc_voice: err.\n");
spin_unlock_irqrestore(&codec->voice_alloc, flags);
if (params_buffer_size(hw_params)/2 != params_period_size(hw_params)) {
if (evoice == NULL) {
- evoice = snd_ali_alloc_voice(codec, SNDRV_ALI_VOICE_TYPE_PCM, 0);
+ evoice = snd_ali_alloc_voice(codec, SNDRV_ALI_VOICE_TYPE_PCM, 0, -1);
if (evoice == NULL)
return -ENOMEM;
pvoice->extra = evoice;
return 0;
}
-static int snd_ali_capture_hw_params(snd_pcm_substream_t * substream,
+static int snd_ali_hw_params(snd_pcm_substream_t * substream,
snd_pcm_hw_params_t * hw_params)
{
return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
}
-static int snd_ali_capture_hw_free(snd_pcm_substream_t * substream)
+static int snd_ali_hw_free(snd_pcm_substream_t * substream)
{
return snd_pcm_lib_free_pages(substream);
}
}
-static int snd_ali_capture_prepare(snd_pcm_substream_t * substream)
+static int snd_ali_prepare(snd_pcm_substream_t * substream)
{
ali_t *codec = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
spin_lock_irqsave(&codec->reg_lock, flags);
- snd_ali_printk("capture_prepare...\n");
+ snd_ali_printk("ali_prepare...\n");
snd_ali_enable_special_channel(codec,pvoice->number);
- Delta = snd_ali_convert_rate(runtime->rate, 1);
+ Delta = (pvoice->number == ALI_MODEM_IN_CHANNEL ||
+ pvoice->number == ALI_MODEM_OUT_CHANNEL) ?
+ 0x1000 : snd_ali_convert_rate(runtime->rate, pvoice->mode);
// Prepare capture intr channel
if (pvoice->number == ALI_SPDIF_IN_CHANNEL) {
}
-static snd_pcm_uframes_t snd_ali_capture_pointer(snd_pcm_substream_t *substream)
+static snd_pcm_uframes_t snd_ali_pointer(snd_pcm_substream_t *substream)
{
ali_t *codec = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
}
}
-static int snd_ali_playback_open(snd_pcm_substream_t * substream)
+static int snd_ali_open(snd_pcm_substream_t * substream, int rec, int channel,
+ snd_pcm_hardware_t *phw)
{
ali_t *codec = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
unsigned long flags = 0;
spin_lock_irqsave(&codec->reg_lock, flags);
- pvoice = snd_ali_alloc_voice(codec, SNDRV_ALI_VOICE_TYPE_PCM, 0);
+ pvoice = snd_ali_alloc_voice(codec, SNDRV_ALI_VOICE_TYPE_PCM, rec, channel);
if (pvoice == NULL) {
spin_unlock_irqrestore(&codec->reg_lock, flags);
return -EAGAIN;
runtime->private_data = pvoice;
runtime->private_free = snd_ali_pcm_free_substream;
- runtime->hw = snd_ali_playback;
+ runtime->hw = *phw;
snd_pcm_set_sync(substream);
snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 64*1024);
return 0;
}
+static int snd_ali_playback_open(snd_pcm_substream_t * substream)
+{
+ return snd_ali_open(substream, 0, -1, &snd_ali_playback);
+}
static int snd_ali_capture_open(snd_pcm_substream_t * substream)
{
- ali_t *codec = snd_pcm_substream_chip(substream);
- snd_pcm_runtime_t *runtime = substream->runtime;
- snd_ali_voice_t *pvoice;
- unsigned long flags;
-
- spin_lock_irqsave(&codec->reg_lock, flags);
- pvoice = snd_ali_alloc_voice(codec, SNDRV_ALI_VOICE_TYPE_PCM, 1);
- if (pvoice == NULL) {
- spin_unlock_irqrestore(&codec->reg_lock, flags);
- return -EAGAIN;
- }
- pvoice->codec = codec;
- spin_unlock_irqrestore(&codec->reg_lock, flags);
-
- pvoice->substream = substream;
- runtime->private_data = pvoice;
- runtime->private_free = snd_ali_pcm_free_substream;
- runtime->hw = snd_ali_capture;
- snd_pcm_set_sync(substream);
- snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 64*1024);
- return 0;
+ return snd_ali_open(substream, 1, -1, &snd_ali_capture);
}
-
static int snd_ali_playback_close(snd_pcm_substream_t * substream)
{
return 0;
}
-static int snd_ali_capture_close(snd_pcm_substream_t * substream)
+static int snd_ali_close(snd_pcm_substream_t * substream)
{
ali_t *codec = snd_pcm_substream_chip(substream);
- snd_pcm_runtime_t *runtime = substream->runtime;
- snd_ali_voice_t *pvoice = (snd_ali_voice_t *) runtime->private_data;
+ snd_ali_voice_t *pvoice = (snd_ali_voice_t *) substream->runtime->private_data;
snd_ali_disable_special_channel(codec,pvoice->number);
static snd_pcm_ops_t snd_ali_capture_ops = {
.open = snd_ali_capture_open,
- .close = snd_ali_capture_close,
+ .close = snd_ali_close,
.ioctl = snd_ali_ioctl,
- .hw_params = snd_ali_capture_hw_params,
- .hw_free = snd_ali_capture_hw_free,
- .prepare = snd_ali_capture_prepare,
+ .hw_params = snd_ali_hw_params,
+ .hw_free = snd_ali_hw_free,
+ .prepare = snd_ali_prepare,
+ .trigger = snd_ali_trigger,
+ .pointer = snd_ali_pointer,
+};
+
+/*
+ * Modem PCM
+ */
+
+static int snd_ali_modem_hw_params(snd_pcm_substream_t * substream,
+ snd_pcm_hw_params_t * hw_params)
+{
+ ali_t *chip = snd_pcm_substream_chip(substream);
+ unsigned int modem_num = chip->num_of_codecs - 1;
+ snd_ac97_write(chip->ac97[modem_num], AC97_LINE1_RATE, params_rate(hw_params));
+ snd_ac97_write(chip->ac97[modem_num], AC97_LINE1_LEVEL, 0);
+ return snd_ali_hw_params(substream, hw_params);
+}
+
+static snd_pcm_hardware_t snd_ali_modem =
+{
+ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_RESUME |
+ SNDRV_PCM_INFO_SYNC_START),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SNDRV_PCM_RATE_KNOT|SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000,
+ .rate_min = 8000,
+ .rate_max = 16000,
+ .channels_min = 1,
+ .channels_max = 1,
+ .buffer_bytes_max = (256*1024),
+ .period_bytes_min = 64,
+ .period_bytes_max = (256*1024),
+ .periods_min = 1,
+ .periods_max = 1024,
+ .fifo_size = 0,
+};
+
+static int snd_ali_modem_open(snd_pcm_substream_t * substream, int rec, int channel)
+{
+ static unsigned int rates [] = {8000,9600,12000,16000};
+ static snd_pcm_hw_constraint_list_t hw_constraint_rates = {
+ .count = ARRAY_SIZE(rates),
+ .list = rates,
+ .mask = 0,
+ };
+ int err = snd_ali_open(substream, rec, channel, &snd_ali_modem);
+ if (err)
+ return err;
+ return snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE, &hw_constraint_rates);
+}
+
+static int snd_ali_modem_playback_open(snd_pcm_substream_t * substream)
+{
+ return snd_ali_modem_open(substream, 0, ALI_MODEM_OUT_CHANNEL);
+}
+
+static int snd_ali_modem_capture_open(snd_pcm_substream_t * substream)
+{
+ return snd_ali_modem_open(substream, 1, ALI_MODEM_IN_CHANNEL);
+}
+
+static snd_pcm_ops_t snd_ali_modem_playback_ops = {
+ .open = snd_ali_modem_playback_open,
+ .close = snd_ali_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_ali_modem_hw_params,
+ .hw_free = snd_ali_hw_free,
+ .prepare = snd_ali_prepare,
+ .trigger = snd_ali_trigger,
+ .pointer = snd_ali_pointer,
+};
+
+static snd_pcm_ops_t snd_ali_modem_capture_ops = {
+ .open = snd_ali_modem_capture_open,
+ .close = snd_ali_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_ali_modem_hw_params,
+ .hw_free = snd_ali_hw_free,
+ .prepare = snd_ali_prepare,
.trigger = snd_ali_trigger,
- .pointer = snd_ali_capture_pointer,
+ .pointer = snd_ali_pointer,
+};
+
+
+struct ali_pcm_description {
+ char *name;
+ unsigned int playback_num;
+ unsigned int capture_num;
+ snd_pcm_ops_t *playback_ops;
+ snd_pcm_ops_t *capture_ops;
};
static void snd_ali_pcm_free(snd_pcm_t *pcm)
{
ali_t *codec = pcm->private_data;
- codec->pcm = NULL;
+ codec->pcm[pcm->device] = NULL;
}
-static int __devinit snd_ali_pcm(ali_t * codec, int device, snd_pcm_t ** rpcm)
+
+static int __devinit snd_ali_pcm(ali_t * codec, int device, struct ali_pcm_description *desc)
{
snd_pcm_t *pcm;
int err;
- if (rpcm) *rpcm = NULL;
- err = snd_pcm_new(codec->card, "ALI 5451", device, ALI_CHANNELS, 1, &pcm);
+ err = snd_pcm_new(codec->card, desc->name, device,
+ desc->playback_num, desc->capture_num, &pcm);
if (err < 0) {
snd_printk("snd_ali_pcm: err called snd_pcm_new.\n");
return err;
pcm->private_data = codec;
pcm->private_free = snd_ali_pcm_free;
pcm->info_flags = 0;
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ali_playback_ops);
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ali_capture_ops);
+ if (desc->playback_ops)
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, desc->playback_ops);
+ if (desc->capture_ops)
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, desc->capture_ops);
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(codec->pci), 64*1024, 128*1024);
pcm->info_flags = 0;
pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;
- strcpy(pcm->name, "ALI 5451");
- codec->pcm = pcm;
- if (rpcm) *rpcm = pcm;
+ strcpy(pcm->name, desc->name);
+ codec->pcm[0] = pcm;
return 0;
}
+struct ali_pcm_description ali_pcms[] = {
+ { "ALI 5451", ALI_CHANNELS, 1, &snd_ali_playback_ops, &snd_ali_capture_ops },
+ { "ALI 5451 modem", 1, 1, &snd_ali_modem_playback_ops, &snd_ali_modem_capture_ops }
+};
+
+static int __devinit snd_ali_build_pcms(ali_t *codec)
+{
+ int i, err;
+ for(i = 0 ; i < codec->num_of_codecs && i < ARRAY_SIZE(ali_pcms) ; i++)
+ if((err = snd_ali_pcm(codec, i, &ali_pcms[i])) < 0)
+ return err;
+ return 0;
+}
+
+
#define ALI5451_SPDIF(xname, xindex, value) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\
.info = snd_ali5451_spdif_info, .get = snd_ali5451_spdif_get, \
static void snd_ali_mixer_free_ac97(ac97_t *ac97)
{
ali_t *codec = ac97->private_data;
- codec->ac97 = NULL;
+ codec->ac97[ac97->num] = NULL;
}
static int __devinit snd_ali_mixer(ali_t * codec)
{
ac97_template_t ac97;
unsigned int idx;
- int err;
+ int i, err;
static ac97_bus_ops_t ops = {
.write = snd_ali_codec_write,
.read = snd_ali_codec_read,
memset(&ac97, 0, sizeof(ac97));
ac97.private_data = codec;
ac97.private_free = snd_ali_mixer_free_ac97;
- if ((err = snd_ac97_mixer(codec->ac97_bus, &ac97, &codec->ac97)) < 0) {
- snd_printk("ali mixer creating error.\n");
+
+ for ( i = 0 ; i < codec->num_of_codecs ; i++) {
+ ac97.num = i;
+ if ((err = snd_ac97_mixer(codec->ac97_bus, &ac97, &codec->ac97[i])) < 0) {
+ snd_printk("ali mixer %d creating error.\n", i);
+ if(i == 0)
return err;
}
+ }
+
if (codec->spdif_support) {
for(idx = 0; idx < ARRAY_SIZE(snd_ali5451_mixer_spdif); idx++) {
err=snd_ctl_add(codec->card, snd_ctl_new1(&snd_ali5451_mixer_spdif[idx], codec));
if (! im)
return 0;
- snd_pcm_suspend_all(chip->pcm);
- snd_ac97_suspend(chip->ac97);
+ for(i = 0 ; i < chip->num_of_codecs ; i++) {
+ if (chip->pcm[i])
+ snd_pcm_suspend_all(chip->pcm[i]);
+ if(chip->ac97[i])
+ snd_ac97_suspend(chip->ac97[i]);
+ }
spin_lock_irq(&chip->reg_lock);
spin_unlock_irq(&chip->reg_lock);
- snd_ac97_resume(chip->ac97);
+ for(i = 0 ; i < chip->num_of_codecs ; i++)
+ if(chip->ac97[i])
+ snd_ac97_resume(chip->ac97[i]);
return 0;
}
codec->spdif_mask = 0x00000002;
}
+ codec->num_of_codecs = 1;
+
+ /* secondary codec - modem */
+ if (inl(ALI_REG(codec, ALI_SCTRL)) & ALI_SCTRL_CODEC2_READY) {
+ codec->num_of_codecs++;
+ outl(inl(ALI_REG(codec, ALI_SCTRL)) |
+ (ALI_SCTRL_LINE_IN2|ALI_SCTRL_GPIO_IN2|ALI_SCTRL_LINE_OUT_EN),
+ ALI_REG(codec, ALI_SCTRL));
+ }
+
snd_ali_printk("chip initialize succeed.\n");
return 0;
}
+/* proc for register dump */
+static void snd_ali_proc_read(snd_info_entry_t *entry, snd_info_buffer_t *buf)
+{
+ ali_t *codec = entry->private_data;
+ int i;
+ for(i = 0 ; i < 256 ; i+= 4)
+ snd_iprintf(buf, "%02x: %08x\n", i, inl(ALI_REG(codec, i)));
+}
+
+static void __devinit snd_ali_proc_init(ali_t *codec)
+{
+ snd_info_entry_t *entry;
+ if(!snd_card_proc_new(codec->card, "ali5451", &entry))
+ snd_info_set_text_ops(entry, codec, 1024, snd_ali_proc_read);
+}
+
static int __devinit snd_ali_resources(ali_t *codec)
{
int err;
}
snd_ali_printk("pcm building ...\n");
- if ((err = snd_ali_pcm(codec, 0, NULL)) < 0) {
+ if ((err = snd_ali_build_pcms(codec)) < 0) {
snd_card_free(card);
return err;
}
+ snd_ali_proc_init(codec);
+
strcpy(card->driver, "ALI5451");
strcpy(card->shortname, "ALI 5451");
static int __init alsa_card_ali_init(void)
{
- return pci_module_init(&driver);
+ return pci_register_driver(&driver);
}
static void __exit alsa_card_ali_exit(void)
if ((gcr_status & 0x40) && (chip->capture_substream)) /* capturing */
snd_pcm_period_elapsed(chip->capture_substream);
if ((gcr_status & 0x10) && (chip->rmidi)) /* MPU401 interrupt */
- snd_mpu401_uart_interrupt(irq, chip->rmidi, regs);
+ snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs);
/* release the gcr */
outb(gcr_status, chip->alt_port + 0xe);
static int __init alsa_card_als4000_init(void)
{
- return pci_module_init(&driver);
+ return pci_register_driver(&driver);
}
static void __exit alsa_card_als4000_exit(void)
static struct ac97_quirk ac97_quirks[] __devinitdata = {
{
- .vendor = 0x103c,
- .device = 0x006b,
+ .subvendor = 0x103c,
+ .subdevice = 0x006b,
.name = "HP Pavilion ZV5030US",
.type = AC97_TUNE_MUTE_LED
},
static int __init alsa_card_atiixp_init(void)
{
- return pci_module_init(&driver);
+ return pci_register_driver(&driver);
}
static void __exit alsa_card_atiixp_exit(void)
static void snd_atiixp_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short val)
{
atiixp_t *chip = ac97->private_data;
+ if (reg == AC97_GPIO_STATUS) {
+ atiixp_write(chip, MODEM_OUT_GPIO,
+ (val << ATI_REG_MODEM_OUT_GPIO_DATA_SHIFT) | ATI_REG_MODEM_OUT_GPIO_EN);
+ return;
+ }
snd_atiixp_codec_write(chip, ac97->num, reg, val);
}
{
atiixp_t *chip = snd_pcm_substream_chip(substream);
atiixp_dma_t *dma = (atiixp_dma_t *)substream->runtime->private_data;
- unsigned int reg = 0;
- int i;
+ int err = 0;
snd_assert(dma->ops->enable_transfer && dma->ops->flush_dma, return -EINVAL);
- if (cmd != SNDRV_PCM_TRIGGER_START && cmd != SNDRV_PCM_TRIGGER_STOP)
- return -EINVAL;
-
spin_lock(&chip->reg_lock);
-
- /* hook off/on: via GPIO_OUT */
- for (i = 0; i < NUM_ATI_CODECS; i++) {
- if (chip->ac97[i]) {
- reg = snd_ac97_read(chip->ac97[i], AC97_GPIO_STATUS);
- break;
- }
- }
- if(cmd == SNDRV_PCM_TRIGGER_START)
- reg |= AC97_GPIO_LINE1_OH;
- else
- reg &= ~AC97_GPIO_LINE1_OH;
- reg = (reg << ATI_REG_MODEM_OUT_GPIO_DATA_SHIFT) | ATI_REG_MODEM_OUT_GPIO_EN ;
- atiixp_write(chip, MODEM_OUT_GPIO, reg);
-
- if (cmd == SNDRV_PCM_TRIGGER_START) {
+ switch(cmd) {
+ case SNDRV_PCM_TRIGGER_START:
dma->ops->enable_transfer(chip, 1);
dma->running = 1;
- } else {
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
dma->ops->enable_transfer(chip, 0);
dma->running = 0;
+ break;
+ default:
+ err = -EINVAL;
+ break;
}
+ if (! err) {
snd_atiixp_check_bus_busy(chip);
if (cmd == SNDRV_PCM_TRIGGER_STOP) {
dma->ops->flush_dma(chip);
snd_atiixp_check_bus_busy(chip);
}
+ }
spin_unlock(&chip->reg_lock);
- return 0;
+ return err;
}
static int __init alsa_card_atiixp_init(void)
{
- return pci_module_init(&driver);
+ return pci_register_driver(&driver);
}
static void __exit alsa_card_atiixp_exit(void)
// initialization of the module
static int __init alsa_card_vortex_init(void)
{
- return pci_module_init(&driver);
+ return pci_register_driver(&driver);
}
// clean up the module
{
int err;
snd_azf3328_dbgcallenter();
- err = pci_module_init(&driver);
+ err = pci_register_driver(&driver);
snd_azf3328_dbgcallleave();
return err;
}
{
if (load_all)
driver.id_table = snd_bt87x_default_ids;
- return pci_module_init(&driver);
+ return pci_register_driver(&driver);
}
static void __exit alsa_card_bt87x_exit(void)
/*
* Copyright (c) 2004 James Courtier-Dutton <James@superbug.demon.co.uk>
* Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit
- * Version: 0.0.20
+ * Version: 0.0.21
*
* FEATURES currently supported:
* See ca0106_main.c for features.
* Added I2C and SPI registers. Filled in interrupt enable.
* 0.0.20
* Added GPIO info for SB Live 24bit.
+ * 0.0.21
+ * Implement support for Line-in capture on SB Live 24bit.
*
*
* This code was initally based on code from ALSA's emu10k1x.c which is:
* bit 9 0 = Mute / 1 = Analog out.
* bit 10 0 = Line-in / 1 = Mic-in.
* bit 11 0 = ? / 1 = ?
- * bit 12 0 = ? / 1 = ?
+ * bit 12 0 = 48 Khz / 1 = 96 Khz Analog out on SB Live 24bit.
* bit 13 0 = ? / 1 = ?
* bit 14 0 = Mute / 1 = Analog out
* bit 15 0 = ? / 1 = ?
/* Causes interrupts based on timer intervals. */
#define SPI 0x7a /* SPI: Serial Interface Register */
#define I2C_A 0x7b /* I2C Address. 32 bit */
-#define I2C_0 0x7c /* I2C Data Port 0. 32 bit */
-#define I2C_1 0x7d /* I2C Data Port 1. 32 bit */
+#define I2C_D0 0x7c /* I2C Data Port 0. 32 bit */
+#define I2C_D1 0x7d /* I2C Data Port 1. 32 bit */
+//I2C values
+#define I2C_A_ADC_ADD_MASK 0x000000fe //The address is a 7 bit address
+#define I2C_A_ADC_RW_MASK 0x00000001 //bit mask for R/W
+#define I2C_A_ADC_TRANS_MASK 0x00000010 //Bit mask for I2c address DAC value
+#define I2C_A_ADC_ABORT_MASK 0x00000020 //Bit mask for I2C transaction abort flag
+#define I2C_A_ADC_LAST_MASK 0x00000040 //Bit mask for Last word transaction
+#define I2C_A_ADC_BYTE_MASK 0x00000080 //Bit mask for Byte Mode
+#define I2C_A_ADC_ADD 0x00000034 //This is the Device address for ADC
+#define I2C_A_ADC_READ 0x00000001 //To perform a read operation
+#define I2C_A_ADC_START 0x00000100 //Start I2C transaction
+#define I2C_A_ADC_ABORT 0x00000200 //I2C transaction abort
+#define I2C_A_ADC_LAST 0x00000400 //I2C last transaction
+#define I2C_A_ADC_BYTE 0x00000800 //I2C one byte mode
+
+#define I2C_D_ADC_REG_MASK 0xfe000000 //ADC address register
+#define I2C_D_ADC_DAT_MASK 0x01ff0000 //ADC data register
+
+#define ADC_TIMEOUT 0x00000007 //ADC Timeout Clock Disable
+#define ADC_IFC_CTRL 0x0000000b //ADC Interface Control
+#define ADC_MASTER 0x0000000c //ADC Master Mode Control
+#define ADC_POWER 0x0000000d //ADC PowerDown Control
+#define ADC_ATTEN_ADCL 0x0000000e //ADC Attenuation ADCL
+#define ADC_ATTEN_ADCR 0x0000000f //ADC Attenuation ADCR
+#define ADC_ALC_CTRL1 0x00000010 //ADC ALC Control 1
+#define ADC_ALC_CTRL2 0x00000011 //ADC ALC Control 2
+#define ADC_ALC_CTRL3 0x00000012 //ADC ALC Control 3
+#define ADC_NOISE_CTRL 0x00000013 //ADC Noise Gate Control
+#define ADC_LIMIT_CTRL 0x00000014 //ADC Limiter Control
+#define ADC_MUX 0x00000015 //ADC Mux offset
+
+#if 0
+/* FIXME: Not tested yet. */
+#define ADC_GAIN_MASK 0x000000ff //Mask for ADC Gain
+#define ADC_ZERODB 0x000000cf //Value to set ADC to 0dB
+#define ADC_MUTE_MASK 0x000000c0 //Mask for ADC mute
+#define ADC_MUTE 0x000000c0 //Value to mute ADC
+#define ADC_OSR 0x00000008 //Mask for ADC oversample rate select
+#define ADC_TIMEOUT_DISABLE 0x00000008 //Value and mask to disable Timeout clock
+#define ADC_HPF_DISABLE 0x00000100 //Value and mask to disable High pass filter
+#define ADC_TRANWIN_MASK 0x00000070 //Mask for Length of Transient Window
+#endif
+
+#define ADC_MUX_MASK 0x0000000f //Mask for ADC Mux
+#define ADC_MUX_MIC 0x00000002 //Value to select Mic at ADC Mux
+#define ADC_MUX_LINEIN 0x00000004 //Value to select LineIn at ADC Mux
+#define ADC_MUX_PHONE 0x00000001 //Value to select TAD at ADC Mux (Not used)
+#define ADC_MUX_AUX 0x00000008 //Value to select Aux at ADC Mux
#define SET_CHANNEL 0 /* Testing channel outputs 0=Front, 1=Center/LFE, 2=Unknown, 3=Rear */
#define PCM_FRONT_CHANNEL 0
unsigned short running;
};
+typedef struct {
+ u32 serial;
+ char * name;
+ int ac97;
+ int gpio_type;
+ int i2c_adc;
+} ca0106_details_t;
+
// definition of the chip-specific record
struct snd_ca0106 {
snd_card_t *card;
+ ca0106_details_t *details;
struct pci_dev *pci;
unsigned long port;
u32 spdif_bits[4]; /* s/pdif out setup */
int spdif_enable;
int capture_source;
+ int capture_mic_line_in;
struct snd_dma_buffer buffer;
};
unsigned int chn,
unsigned int data);
+int snd_ca0106_i2c_write(ca0106_t *emu, u32 reg, u32 value);
+
+
/*
* Copyright (c) 2004 James Courtier-Dutton <James@superbug.demon.co.uk>
* Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit
- * Version: 0.0.22
+ * Version: 0.0.23
*
* FEATURES currently supported:
* Front, Rear and Center/LFE.
* Add SPDIF capture using optional digital I/O module for SB Live 24bit. (Analog capture does not yet work.)
* 0.0.22
* Add support for MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97. From kiksen, bug #901
+ * 0.0.23
+ * Implement support for Line-in capture on SB Live 24bit.
*
* BUGS:
* Some stability problems when unloading the snd-ca0106 kernel module.
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/moduleparam.h>
+#include <linux/dma-mapping.h>
#include <sound/core.h>
#include <sound/initval.h>
#include <sound/pcm.h>
#include "ca0106.h"
-typedef struct {
- u32 serial;
- char * name;
-} ca0106_names_t;
-
-static ca0106_names_t ca0106_chip_names[] = {
- { 0x10021102, "AudigyLS [SB0310]"} ,
- { 0x10051102, "AudigyLS [SB0310b]"} , /* Unknown AudigyLS that also says SB0310 on it */
- { 0x10061102, "Live! 7.1 24bit [SB0410]"} , /* New Sound Blaster Live! 7.1 24bit. This does not have an AC97. 53SB041000001 */
- { 0x10071102, "Live! 7.1 24bit [SB0413]"} , /* New Dell Sound Blaster Live! 7.1 24bit. This does not have an AC97. */
- { 0x10091462, "MSI K8N Diamond MB [SB0438]"}, /* MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97 */
- { 0, "AudigyLS [Unknown]" }
+static ca0106_details_t ca0106_chip_details[] = {
+ /* AudigyLS[SB0310] */
+ { .serial = 0x10021102,
+ .name = "AudigyLS [SB0310]",
+ .ac97 = 1 } ,
+ /* Unknown AudigyLS that also says SB0310 on it */
+ { .serial = 0x10051102,
+ .name = "AudigyLS [SB0310b]",
+ .ac97 = 1 } ,
+ /* New Sound Blaster Live! 7.1 24bit. This does not have an AC97. 53SB041000001 */
+ { .serial = 0x10061102,
+ .name = "Live! 7.1 24bit [SB0410]",
+ .gpio_type = 1,
+ .i2c_adc = 1 } ,
+ /* New Dell Sound Blaster Live! 7.1 24bit. This does not have an AC97. */
+ { .serial = 0x10071102,
+ .name = "Live! 7.1 24bit [SB0413]",
+ .gpio_type = 1,
+ .i2c_adc = 1 } ,
+ /* MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97 */
+ { .serial = 0x10091462,
+ .name = "MSI K8N Diamond MB [SB0438]",
+ .gpio_type = 1,
+ .i2c_adc = 1 } ,
+ { .serial = 0,
+ .name = "AudigyLS [Unknown]" }
};
/* hardware definition */
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID),
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- .rates = SNDRV_PCM_RATE_48000,
- .rate_min = 48000,
- .rate_max = 48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
+ .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000,
+ .rate_min = 44100,
+ .rate_max = 192000,
.channels_min = 2,
.channels_max = 2,
.buffer_bytes_max = ((65536 - 64) * 8),
spin_unlock_irqrestore(&emu->emu_lock, flags);
}
+int snd_ca0106_i2c_write(ca0106_t *emu,
+ u32 reg,
+ u32 value)
+{
+ u32 tmp;
+ int timeout=0;
+ int status;
+ int retry;
+ if ((reg > 0x7f) || (value > 0x1ff))
+ {
+ snd_printk("i2c_write: invalid values.\n");
+ return -EINVAL;
+ }
+
+ tmp = reg << 25 | value << 16;
+ /* Not sure what this I2C channel controls. */
+ /* snd_ca0106_ptr_write(emu, I2C_D0, 0, tmp); */
+
+ /* This controls the I2C connected to the WM8775 ADC Codec */
+ snd_ca0106_ptr_write(emu, I2C_D1, 0, tmp);
+
+ for(retry=0;retry<10;retry++)
+ {
+ /* Send the data to i2c */
+ tmp = snd_ca0106_ptr_read(emu, I2C_A, 0);
+ tmp = tmp & ~(I2C_A_ADC_READ|I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD_MASK);
+ tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD);
+ snd_ca0106_ptr_write(emu, I2C_A, 0, tmp);
+
+ /* Wait till the transaction ends */
+ while(1)
+ {
+ status = snd_ca0106_ptr_read(emu, I2C_A, 0);
+ //snd_printk("I2C:status=0x%x\n", status);
+ timeout++;
+ if((status & I2C_A_ADC_START)==0)
+ break;
+
+ if(timeout>1000)
+ break;
+ }
+ //Read back and see if the transaction is successful
+ if((status & I2C_A_ADC_ABORT)==0)
+ break;
+ }
+
+ if(retry==10)
+ {
+ snd_printk("Writing to ADC failed!\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+
static void snd_ca0106_intr_enable(ca0106_t *emu, unsigned int intrenb)
{
unsigned long flags;
static void snd_ca0106_pcm_free_substream(snd_pcm_runtime_t *runtime)
{
- ca0106_pcm_t *epcm = runtime->private_data;
-
- if (epcm) {
- kfree(epcm);
- }
+ kfree(runtime->private_data);
}
/* open_playback callback */
snd_pcm_runtime_t *runtime = substream->runtime;
ca0106_pcm_t *epcm = runtime->private_data;
int channel = epcm->channel_id;
+ u32 hcfg_mask = HCFG_CAPTURE_S32_LE;
+ u32 hcfg_set = 0x00000000;
+ u32 hcfg;
+ u32 over_sampling=0x2;
+ u32 reg71_mask = 0x0000c000 ; /* Global. Set ADC rate. */
+ u32 reg71_set = 0;
+ u32 reg71;
+
+ //snd_printk("prepare:channel_number=%d, rate=%d, format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, periods=%u, frames_to_bytes=%d\n",channel, runtime->rate, runtime->format, runtime->channels, runtime->buffer_size, runtime->period_size, runtime->periods, frames_to_bytes(runtime, 1));
+ //snd_printk("dma_addr=%x, dma_area=%p, table_base=%p\n",runtime->dma_addr, runtime->dma_area, table_base);
+ //snd_printk("dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n",emu->buffer.addr, emu->buffer.area, emu->buffer.bytes);
+ /* reg71 controls ADC rate. */
+ switch (runtime->rate) {
+ case 44100:
+ reg71_set = 0x00004000;
+ break;
+ case 48000:
+ reg71_set = 0;
+ break;
+ case 96000:
+ reg71_set = 0x00008000;
+ over_sampling=0xa;
+ break;
+ case 192000:
+ reg71_set = 0x0000c000;
+ over_sampling=0xa;
+ break;
+ default:
+ reg71_set = 0;
+ break;
+ }
+ /* Format is a global setting */
+ /* FIXME: Only let the first channel accessed set this. */
+ switch (runtime->format) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ hcfg_set = 0;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ hcfg_set = HCFG_CAPTURE_S32_LE;
+ break;
+ default:
+ hcfg_set = 0;
+ break;
+ }
+ hcfg = inl(emu->port + HCFG) ;
+ hcfg = (hcfg & ~hcfg_mask) | hcfg_set;
+ outl(hcfg, emu->port + HCFG);
+ reg71 = snd_ca0106_ptr_read(emu, 0x71, 0);
+ reg71 = (reg71 & ~reg71_mask) | reg71_set;
+ snd_ca0106_ptr_write(emu, 0x71, 0, reg71);
+ if (emu->details->i2c_adc == 1) { /* The SB0410 and SB0413 use I2C to control ADC. */
+ snd_ca0106_i2c_write(emu, ADC_MASTER, over_sampling); /* Adjust the over sampler to better suit the capture rate. */
+ }
+
+
//printk("prepare:channel_number=%d, rate=%d, format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, frames_to_bytes=%d\n",channel, runtime->rate, runtime->format, runtime->channels, runtime->buffer_size, runtime->period_size, frames_to_bytes(runtime, 1));
snd_ca0106_ptr_write(emu, 0x13, channel, 0);
snd_ca0106_ptr_write(emu, CAPTURE_DMA_ADDR, channel, runtime->dma_addr);
memset(&ac97, 0, sizeof(ac97));
ac97.private_data = chip;
+ ac97.scaps = AC97_SCAP_NO_SPDIF;
return snd_ac97_mixer(pbus, &ac97, &chip->ac97);
}
ca0106_t **rchip)
{
ca0106_t *chip;
+ ca0106_details_t *c;
int err;
int ch;
static snd_device_ops_t ops = {
if ((err = pci_enable_device(pci)) < 0)
return err;
- if (pci_set_dma_mask(pci, 0xffffffffUL) < 0 ||
- pci_set_consistent_dma_mask(pci, 0xffffffffUL) < 0) {
+ if (pci_set_dma_mask(pci, DMA_32BIT_MASK) < 0 ||
+ pci_set_consistent_dma_mask(pci, DMA_32BIT_MASK) < 0) {
printk(KERN_ERR "error to set 32bit mask DMA\n");
pci_disable_device(pci);
return -ENXIO;
printk(KERN_INFO "Model %04x Rev %08x Serial %08x\n", chip->model,
chip->revision, chip->serial);
#endif
+ strcpy(card->driver, "CA0106");
+ strcpy(card->shortname, "CA0106");
+
+ for (c=ca0106_chip_details; c->serial; c++) {
+ if (c->serial == chip->serial) break;
+ }
+ chip->details = c;
+ sprintf(card->longname, "%s at 0x%lx irq %i",
+ c->name, chip->port, chip->irq);
outl(0, chip->port + INTE);
//snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0xf0f003f); /* OSS drivers set this. */
/* Analog or Digital output */
snd_ca0106_ptr_write(chip, SPDIF_SELECT1, 0, 0xf);
- snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0x000b0000); /* 0x0b000000 for digital, 0x000b0000 for analog, from win2000 drivers */
+ snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0x000f0000); /* 0x0b000000 for digital, 0x000b0000 for analog, from win2000 drivers. Use 0x000f0000 for surround71 */
chip->spdif_enable = 0; /* Set digital SPDIF output off */
chip->capture_source = 3; /* Set CAPTURE_SOURCE */
//snd_ca0106_ptr_write(chip, 0x45, 0, 0); /* Analogue out */
snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4); /* Select MIC, Line in, TAD in, AUX in */
chip->capture_source = 3; /* Set CAPTURE_SOURCE */
- if ((chip->serial == 0x10061102) ||
- (chip->serial == 0x10071102) ||
- (chip->serial == 0x10091462)) { /* The SB0410 and SB0413 use GPIO differently. */
+ if (chip->details->gpio_type == 1) { /* The SB0410 and SB0413 use GPIO differently. */
/* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */
outl(0x0, chip->port+GPIO);
//outl(0x00f0e000, chip->port+GPIO); /* Analog */
- outl(0x005f4300, chip->port+GPIO); /* Analog */
+ outl(0x005f5301, chip->port+GPIO); /* Analog */
} else {
outl(0x0, chip->port+GPIO);
outl(0x005f03a3, chip->port+GPIO); /* Analog */
//outl(0x00000009, chip->port+HCFG);
outl(HCFG_AC97 | HCFG_AUDIOENABLE, chip->port+HCFG); /* AC97 2.0, Enable outputs. */
+ if (chip->details->i2c_adc == 1) { /* The SB0410 and SB0413 use I2C to control ADC. */
+ snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); /* Enable Line-in capture. MIC in currently untested. */
+ }
+
if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL,
chip, &ops)) < 0) {
snd_ca0106_free(chip);
static int dev;
snd_card_t *card;
ca0106_t *chip;
- ca0106_names_t *c;
int err;
if (dev >= SNDRV_CARDS)
snd_card_free(card);
return err;
}
- if ((chip->serial != 0x10061102) &&
- (chip->serial != 0x10071102) &&
- (chip->serial != 0x10091462) ) { /* The SB0410 and SB0413 do not have an ac97 chip. */
+ if (chip->details->ac97 == 1) { /* The SB0410 and SB0413 do not have an AC97 chip. */
if ((err = snd_ca0106_ac97(chip)) < 0) {
snd_card_free(card);
return err;
snd_ca0106_proc_init(chip);
- strcpy(card->driver, "CA0106");
- strcpy(card->shortname, "CA0106");
-
- for (c=ca0106_chip_names; c->serial; c++) {
- if (c->serial == chip->serial) break;
- }
- sprintf(card->longname, "%s at 0x%lx irq %i",
- c->name, chip->port, chip->irq);
-
if ((err = snd_card_register(card)) < 0) {
snd_card_free(card);
return err;
{
int err;
- if ((err = pci_module_init(&driver)) > 0)
+ if ((err = pci_register_driver(&driver)) > 0)
return err;
return 0;
/*
* Copyright (c) 2004 James Courtier-Dutton <James@superbug.demon.co.uk>
* Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit
- * Version: 0.0.16
+ * Version: 0.0.17
*
* FEATURES currently supported:
* See ca0106_main.c for features.
* Separated ca0106.c into separate functional .c files.
* 0.0.16
* Modified Copyright message.
+ * 0.0.17
+ * Implement Mic and Line in Capture.
*
* This code was initally based on code from ALSA's emu10k1x.c which is:
* Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com>
} else {
/* Analog */
snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf);
- snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x000b0000);
+ snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x000f0000);
snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0,
snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) | 0x1000);
mask = inl(emu->port + GPIO) | 0x101;
.put = snd_ca0106_capture_source_put
};
+static int snd_ca0106_capture_mic_line_in_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+ static char *texts[2] = { "Line in", "Mic in" };
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 2;
+ if (uinfo->value.enumerated.item > 1)
+ uinfo->value.enumerated.item = 1;
+ strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+static int snd_ca0106_capture_mic_line_in_get(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_value_t * ucontrol)
+{
+ ca0106_t *emu = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.enumerated.item[0] = emu->capture_mic_line_in;
+ return 0;
+}
+
+static int snd_ca0106_capture_mic_line_in_put(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_value_t * ucontrol)
+{
+ ca0106_t *emu = snd_kcontrol_chip(kcontrol);
+ unsigned int val;
+ int change = 0;
+ u32 tmp;
+
+ val = ucontrol->value.enumerated.item[0] ;
+ change = (emu->capture_mic_line_in != val);
+ if (change) {
+ emu->capture_mic_line_in = val;
+ if (val) {
+ snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_PHONE); /* Mute input */
+ tmp = inl(emu->port+GPIO) & ~0x400;
+ tmp = tmp | 0x400;
+ outl(tmp, emu->port+GPIO);
+ snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_MIC);
+ } else {
+ snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_PHONE); /* Mute input */
+ tmp = inl(emu->port+GPIO) & ~0x400;
+ outl(tmp, emu->port+GPIO);
+ snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_LINEIN);
+ }
+ }
+ return change;
+}
+
+static snd_kcontrol_new_t snd_ca0106_capture_mic_line_in __devinitdata =
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Mic/Line in Capture",
+ .info = snd_ca0106_capture_mic_line_in_info,
+ .get = snd_ca0106_capture_mic_line_in_get,
+ .put = snd_ca0106_capture_mic_line_in_put
+};
+
static int snd_ca0106_spdif_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
static snd_kcontrol_new_t snd_ca0106_volume_control_analog_unknown =
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Analog Unknown Volume",
+ .name = "Analog Side Volume",
.info = snd_ca0106_volume_info,
.get = snd_ca0106_volume_get_analog_unknown,
.put = snd_ca0106_volume_put_analog_unknown
return -ENOMEM;
if ((err = snd_ctl_add(card, kctl)))
return err;
- if ((kctl = ctl_find(card, SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT))) != NULL) {
- /* already defined by ac97, remove it */
- /* FIXME: or do we need both controls? */
- remove_ctl(card, SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT));
+ if (emu->details->i2c_adc == 1) {
+ if ((kctl = snd_ctl_new1(&snd_ca0106_capture_mic_line_in, emu)) == NULL)
+ return -ENOMEM;
+ if ((err = snd_ctl_add(card, kctl)))
+ return err;
}
if ((kctl = snd_ctl_new1(&snd_ca0106_spdif_control, emu)) == NULL)
return -ENOMEM;
/*
* Copyright (c) 2004 James Courtier-Dutton <James@superbug.demon.co.uk>
* Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit
- * Version: 0.0.17
+ * Version: 0.0.18
*
* FEATURES currently supported:
* See ca0106_main.c for features.
* Modified Copyright message.
* 0.0.17
* Add iec958 file in proc file system to show status of SPDIF in.
- *
+ * 0.0.18
+ * Implement support for Line-in capture on SB Live 24bit.
+ *
* This code was initally based on code from ALSA's emu10k1x.c which is:
* Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com>
*
};
-void snd_ca0106_proc_dump_iec958( snd_info_buffer_t *buffer, u32 value)
+static void snd_ca0106_proc_dump_iec958( snd_info_buffer_t *buffer, u32 value)
{
int i;
u32 status[4];
}
}
+static void snd_ca0106_proc_i2c_write(snd_info_entry_t *entry,
+ snd_info_buffer_t * buffer)
+{
+ ca0106_t *emu = entry->private_data;
+ char line[64];
+ unsigned int reg, val;
+ while (!snd_info_get_line(buffer, line, sizeof(line))) {
+ if (sscanf(line, "%x %x", ®, &val) != 2)
+ continue;
+ if ((reg <= 0x7f) || (val <= 0x1ff)) {
+ snd_ca0106_i2c_write(emu, reg, val);
+ }
+ }
+}
int __devinit snd_ca0106_proc_init(ca0106_t * emu)
{
snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_reg_read32);
entry->c.text.write_size = 64;
entry->c.text.write = snd_ca0106_proc_reg_write32;
+ entry->mode |= S_IWUSR;
}
if(! snd_card_proc_new(emu->card, "ca0106_reg16", &entry))
snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_reg_read16);
snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_reg_read1);
entry->c.text.write_size = 64;
entry->c.text.write = snd_ca0106_proc_reg_write;
+ entry->mode |= S_IWUSR;
+// entry->private_data = emu;
+ }
+ if(! snd_card_proc_new(emu->card, "ca0106_i2c", &entry)) {
+ snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_i2c_write);
+ entry->c.text.write_size = 64;
+ entry->c.text.write = snd_ca0106_proc_i2c_write;
+ entry->mode |= S_IWUSR;
// entry->private_data = emu;
}
if(! snd_card_proc_new(emu->card, "ca0106_regs2", &entry))
}
/* bit operations for dword register */
-static void snd_cmipci_set_bit(cmipci_t *cm, unsigned int cmd, unsigned int flag)
+static int snd_cmipci_set_bit(cmipci_t *cm, unsigned int cmd, unsigned int flag)
{
- unsigned int val;
- val = inl(cm->iobase + cmd);
+ unsigned int val, oval;
+ val = oval = inl(cm->iobase + cmd);
val |= flag;
+ if (val == oval)
+ return 0;
outl(val, cm->iobase + cmd);
+ return 1;
}
-static void snd_cmipci_clear_bit(cmipci_t *cm, unsigned int cmd, unsigned int flag)
+static int snd_cmipci_clear_bit(cmipci_t *cm, unsigned int cmd, unsigned int flag)
{
- unsigned int val;
- val = inl(cm->iobase + cmd);
+ unsigned int val, oval;
+ val = oval = inl(cm->iobase + cmd);
val &= ~flag;
+ if (val == oval)
+ return 0;
outl(val, cm->iobase + cmd);
+ return 1;
}
-#if 0 // not used
/* bit operations for byte register */
-static void snd_cmipci_set_bit_b(cmipci_t *cm, unsigned int cmd, unsigned char flag)
+static int snd_cmipci_set_bit_b(cmipci_t *cm, unsigned int cmd, unsigned char flag)
{
- unsigned char val;
- val = inb(cm->iobase + cmd);
+ unsigned char val, oval;
+ val = oval = inb(cm->iobase + cmd);
val |= flag;
+ if (val == oval)
+ return 0;
outb(val, cm->iobase + cmd);
+ return 1;
}
-static void snd_cmipci_clear_bit_b(cmipci_t *cm, unsigned int cmd, unsigned char flag)
+static int snd_cmipci_clear_bit_b(cmipci_t *cm, unsigned int cmd, unsigned char flag)
{
- unsigned char val;
- val = inb(cm->iobase + cmd);
+ unsigned char val, oval;
+ val = oval = inb(cm->iobase + cmd);
val &= ~flag;
+ if (val == oval)
+ return 0;
outb(val, cm->iobase + cmd);
+ return 1;
}
-#endif
/*
DEFINE_SWITCH_ARG(exchange_dac, CM_REG_MISC_CTRL, CM_XCHGDAC, CM_XCHGDAC, 0, 0);
#endif
DEFINE_BIT_SWITCH_ARG(fourch, CM_REG_MISC_CTRL, CM_N4SPK3D, 0, 0);
-DEFINE_BIT_SWITCH_ARG(line_rear, CM_REG_MIXER1, CM_SPK4, 1, 0);
-DEFINE_BIT_SWITCH_ARG(line_bass, CM_REG_LEGACY_CTRL, CM_LINE_AS_BASS, 0, 0);
+// DEFINE_BIT_SWITCH_ARG(line_rear, CM_REG_MIXER1, CM_SPK4, 1, 0);
+// DEFINE_BIT_SWITCH_ARG(line_bass, CM_REG_LEGACY_CTRL, CM_LINE_AS_BASS, 0, 0);
// DEFINE_BIT_SWITCH_ARG(joystick, CM_REG_FUNCTRL1, CM_JYSTK_EN, 0, 0); /* now module option */
DEFINE_SWITCH_ARG(modem, CM_REG_MISC_CTRL, CM_FLINKON|CM_FLINKOFF, CM_FLINKON, 0, 0);
}
+static int snd_cmipci_line_in_mode_info(snd_kcontrol_t *kcontrol,
+ snd_ctl_elem_info_t *uinfo)
+{
+ cmipci_t *cm = snd_kcontrol_chip(kcontrol);
+ static char *texts[3] = { "Line-In", "Rear Output", "Bass Output" };
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = cm->chip_version >= 39 ? 3 : 2;
+ if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+ uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
+ strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+static inline unsigned int get_line_in_mode(cmipci_t *cm)
+{
+ unsigned int val;
+ if (cm->chip_version >= 39) {
+ val = snd_cmipci_read(cm, CM_REG_LEGACY_CTRL);
+ if (val & CM_LINE_AS_BASS)
+ return 2;
+ }
+ val = snd_cmipci_read_b(cm, CM_REG_MIXER1);
+ if (val & CM_SPK4)
+ return 1;
+ return 0;
+}
+
+static int snd_cmipci_line_in_mode_get(snd_kcontrol_t *kcontrol,
+ snd_ctl_elem_value_t *ucontrol)
+{
+ cmipci_t *cm = snd_kcontrol_chip(kcontrol);
+
+ spin_lock_irq(&cm->reg_lock);
+ ucontrol->value.enumerated.item[0] = get_line_in_mode(cm);
+ spin_unlock_irq(&cm->reg_lock);
+ return 0;
+}
+
+static int snd_cmipci_line_in_mode_put(snd_kcontrol_t *kcontrol,
+ snd_ctl_elem_value_t *ucontrol)
+{
+ cmipci_t *cm = snd_kcontrol_chip(kcontrol);
+ int change;
+
+ spin_lock_irq(&cm->reg_lock);
+ if (ucontrol->value.enumerated.item[0] == 2)
+ change = snd_cmipci_set_bit(cm, CM_REG_LEGACY_CTRL, CM_LINE_AS_BASS);
+ else
+ change = snd_cmipci_clear_bit(cm, CM_REG_LEGACY_CTRL, CM_LINE_AS_BASS);
+ if (ucontrol->value.enumerated.item[0] == 1)
+ change |= snd_cmipci_set_bit_b(cm, CM_REG_MIXER1, CM_SPK4);
+ else
+ change |= snd_cmipci_clear_bit_b(cm, CM_REG_MIXER1, CM_SPK4);
+ spin_unlock_irq(&cm->reg_lock);
+ return change;
+}
+
+static int snd_cmipci_mic_in_mode_info(snd_kcontrol_t *kcontrol,
+ snd_ctl_elem_info_t *uinfo)
+{
+ static char *texts[2] = { "Mic-In", "Center/LFE Output" };
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 2;
+ if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+ uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
+ strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+static int snd_cmipci_mic_in_mode_get(snd_kcontrol_t *kcontrol,
+ snd_ctl_elem_value_t *ucontrol)
+{
+ cmipci_t *cm = snd_kcontrol_chip(kcontrol);
+ /* same bit as spdi_phase */
+ spin_lock_irq(&cm->reg_lock);
+ ucontrol->value.enumerated.item[0] =
+ (snd_cmipci_read_b(cm, CM_REG_MISC) & CM_SPDIF_INVERSE) ? 1 : 0;
+ spin_unlock_irq(&cm->reg_lock);
+ return 0;
+}
+
+static int snd_cmipci_mic_in_mode_put(snd_kcontrol_t *kcontrol,
+ snd_ctl_elem_value_t *ucontrol)
+{
+ cmipci_t *cm = snd_kcontrol_chip(kcontrol);
+ int change;
+
+ spin_lock_irq(&cm->reg_lock);
+ if (ucontrol->value.enumerated.item[0])
+ change = snd_cmipci_set_bit_b(cm, CM_REG_MISC, CM_SPDIF_INVERSE);
+ else
+ change = snd_cmipci_clear_bit_b(cm, CM_REG_MISC, CM_SPDIF_INVERSE);
+ spin_unlock_irq(&cm->reg_lock);
+ return change;
+}
+
/* both for CM8338/8738 */
static snd_kcontrol_new_t snd_cmipci_mixer_switches[] __devinitdata = {
DEFINE_MIXER_SWITCH("Four Channel Mode", fourch),
- DEFINE_MIXER_SWITCH("Line-In As Rear", line_rear),
+ {
+ .name = "Line-In Mode",
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .info = snd_cmipci_line_in_mode_info,
+ .get = snd_cmipci_line_in_mode_get,
+ .put = snd_cmipci_line_in_mode_put,
+ },
};
/* for non-multichannel chips */
/* only for model 039 or later */
static snd_kcontrol_new_t snd_cmipci_extra_mixer_switches[] __devinitdata = {
- DEFINE_MIXER_SWITCH("Line-In As Bass", line_bass),
DEFINE_MIXER_SWITCH("IEC958 In Select", spdif_in_sel2),
DEFINE_MIXER_SWITCH("IEC958 In Phase Inverse", spdi_phase2),
- DEFINE_MIXER_SWITCH("Mic As Center/LFE", spdi_phase), /* same bit as spdi_phase */
+ {
+ .name = "Mic-In Mode",
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .info = snd_cmipci_mic_in_mode_info,
+ .get = snd_cmipci_mic_in_mode_get,
+ .put = snd_cmipci_mic_in_mode_put,
+ }
};
/* card control switches */
static int __init alsa_card_cmipci_init(void)
{
- return pci_module_init(&driver);
+ return pci_register_driver(&driver);
}
static void __exit alsa_card_cmipci_exit(void)
#define BA0_PMCS 0x0344 /* Power Management Control/Status */
#define BA0_CWPR 0x03e0 /* Configuration Write Protect */
+
#define BA0_EPPMC 0x03e4 /* Extended PCI Power Management Control */
+#define BA0_EPPMC_FPDN (1<<14) /* Full Power DowN */
+
#define BA0_GPIOR 0x03e8 /* GPIO Pin Interface Register */
#define BA0_SPMC 0x03ec /* Serial Port Power Management Control (& ASDIN2 enable) */
int timeout;
int retry_count = 2;
+ /* Having EPPMC.FPDN=1 prevent proper chip initialisation */
+ tmp = snd_cs4281_peekBA0(chip, BA0_EPPMC);
+ if (tmp & BA0_EPPMC_FPDN)
+ snd_cs4281_pokeBA0(chip, BA0_EPPMC, tmp & ~BA0_EPPMC_FPDN);
+
__retry:
tmp = snd_cs4281_peekBA0(chip, BA0_CFLR);
if (tmp != BA0_CFLR_DEFAULT) {
static int __init alsa_card_cs4281_init(void)
{
- return pci_module_init(&driver);
+ return pci_register_driver(&driver);
}
static void __exit alsa_card_cs4281_exit(void)
static int __init alsa_card_cs46xx_init(void)
{
- return pci_module_init(&driver);
+ return pci_register_driver(&driver);
}
static void __exit alsa_card_cs46xx_exit(void)
static void snd_cs46xx_pcm_free_substream(snd_pcm_runtime_t *runtime)
{
- cs46xx_pcm_t * cpcm = runtime->private_data;
- kfree(cpcm);
+ kfree(runtime->private_data);
}
static int _cs46xx_playback_open_channel (snd_pcm_substream_t * substream,int pcm_channel_id)
static int __init alsa_card_emu10k1_init(void)
{
- return pci_module_init(&driver);
+ return pci_register_driver(&driver);
}
static void __exit alsa_card_emu10k1_exit(void)
SPCS_GENERATIONSTATUS | 0x00001200 |
0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT);
- if (emu->audigy && emu->revision == 4) { /* audigy2 */
+ if (emu->card_capabilities->ca0151_chip) { /* audigy2 */
/* Hacks for Alice3 to work independent of haP16V driver */
u32 tmp;
/* Enabled Phased (8-channel) P16V playback */
outl(0x0201, emu->port + HCFG2);
/* Set playback routing. */
- snd_emu10k1_ptr_write(emu, CAPTURE_P16V_SOURCE, 0, 78e4);
+ snd_emu10k1_ptr20_write(emu, CAPTURE_P16V_SOURCE, 0, 0x78e4);
}
if (emu->audigy && (emu->serial == 0x10011102) ) { /* audigy2 Value */
/* Hacks for Alice3 to work independent of haP16V driver */
if (emu->port)
pci_release_regions(emu->pci);
pci_disable_device(emu->pci);
- if (emu->audigy && emu->revision == 4) /* P16V */
+ if (emu->card_capabilities->ca0151_chip) /* P16V */
snd_p16v_free(emu);
kfree(emu);
return 0;
return snd_emu10k1_free(emu);
}
-/* vendor, device, subsystem, emu10k1_chip, emu10k2_chip, ca0102_chip, ca0108_chip, ca0151_chip, spk71, spdif_bug, ac97_chip, ecard, driver, name */
-
static emu_chip_details_t emu_chip_details[] = {
/* Audigy 2 Value AC3 out does not work yet. Need to find out how to turn off interpolators.*/
{.vendor = 0x1102, .device = 0x0008, .subsystem = 0x10011102,
.driver = "Audigy2", .name = "Audigy 2 Value [SB0400]",
+ .id = "Audigy2",
.emu10k2_chip = 1,
.ca0108_chip = 1,
- .spk71 = 1} ,
+ .spk71 = 1,
+ .ac97_chip = 1} ,
{.vendor = 0x1102, .device = 0x0008,
.driver = "Audigy2", .name = "Audigy 2 Value [Unknown]",
+ .id = "Audigy2",
.emu10k2_chip = 1,
- .ca0108_chip = 1} ,
+ .ca0108_chip = 1,
+ .ac97_chip = 1} ,
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20071102,
.driver = "Audigy2", .name = "Audigy 4 PRO [SB0380]",
+ .id = "Audigy2",
.emu10k2_chip = 1,
.ca0102_chip = 1,
.ca0151_chip = 1,
.ac97_chip = 1} ,
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20021102,
.driver = "Audigy2", .name = "Audigy 2 ZS [SB0350]",
+ .id = "Audigy2",
.emu10k2_chip = 1,
.ca0102_chip = 1,
.ca0151_chip = 1,
.ac97_chip = 1} ,
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20011102,
.driver = "Audigy2", .name = "Audigy 2 ZS [2001]",
+ .id = "Audigy2",
.emu10k2_chip = 1,
.ca0102_chip = 1,
.ca0151_chip = 1,
.ac97_chip = 1} ,
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10071102,
.driver = "Audigy2", .name = "Audigy 2 [SB0240]",
+ .id = "Audigy2",
.emu10k2_chip = 1,
.ca0102_chip = 1,
.ca0151_chip = 1,
.ac97_chip = 1} ,
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10051102,
.driver = "Audigy2", .name = "Audigy 2 EX [1005]",
+ .id = "Audigy2",
.emu10k2_chip = 1,
.ca0102_chip = 1,
.ca0151_chip = 1,
.spdif_bug = 1} ,
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10021102,
.driver = "Audigy2", .name = "Audigy 2 Platinum [SB0240P]",
+ .id = "Audigy2",
.emu10k2_chip = 1,
.ca0102_chip = 1,
.ca0151_chip = 1,
.spk71 = 1,
.spdif_bug = 1,
.ac97_chip = 1} ,
+ {.vendor = 0x1102, .device = 0x0004, .revision = 0x04,
+ .driver = "Audigy2", .name = "Audigy 2 [Unknown]",
+ .id = "Audigy2",
+ .emu10k2_chip = 1,
+ .ca0102_chip = 1,
+ .ca0151_chip = 1,
+ .spdif_bug = 1,
+ .ac97_chip = 1} ,
+ {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10020052,
+ .driver = "Audigy", .name = "Audigy 1 ES [SB0160]",
+ .id = "Audigy",
+ .emu10k2_chip = 1,
+ .ca0102_chip = 1,
+ .spdif_bug = 1,
+ .ac97_chip = 1} ,
+ {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x00531102,
+ .driver = "Audigy", .name = "Audigy 1 [SB0090]",
+ .id = "Audigy",
+ .emu10k2_chip = 1,
+ .ca0102_chip = 1,
+ .ac97_chip = 1} ,
+ {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x00511102,
+ .driver = "Audigy", .name = "Audigy 1 [SB0090]",
+ .id = "Audigy",
+ .emu10k2_chip = 1,
+ .ca0102_chip = 1,
+ .ac97_chip = 1} ,
{.vendor = 0x1102, .device = 0x0004,
- .driver = "Audigy", .name = "Audigy 1 or 2 [Unknown]",
+ .driver = "Audigy", .name = "Audigy 1 [Unknown]",
+ .id = "Audigy",
.emu10k2_chip = 1,
.ca0102_chip = 1,
- .spdif_bug = 1} ,
+ .ac97_chip = 1} ,
{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x40011102,
.driver = "EMU10K1", .name = "E-mu APS [4001]",
+ .id = "APS",
.emu10k1_chip = 1,
.ecard = 1} ,
+ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80611102,
+ .driver = "EMU10K1", .name = "SBLive! Player 5.1 [SB0060]",
+ .id = "Live",
+ .emu10k1_chip = 1,
+ .ac97_chip = 1,
+ .sblive51 = 1} ,
{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80641102,
.driver = "EMU10K1", .name = "SB Live 5.1",
+ .id = "Live",
+ .emu10k1_chip = 1,
+ .ac97_chip = 1,
+ .sblive51 = 1} ,
+ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80401102,
+ .driver = "EMU10K1", .name = "SBLive! Platinum [CT4760P]",
+ .id = "Live",
.emu10k1_chip = 1,
.ac97_chip = 1} ,
+ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x00211102,
+ .driver = "EMU10K1", .name = "SBLive! [CT4620]",
+ .id = "Live",
+ .emu10k1_chip = 1,
+ .ac97_chip = 1,
+ .sblive51 = 1} ,
+ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x00201102,
+ .driver = "EMU10K1", .name = "SBLive! Value [CT4670]",
+ .id = "Live",
+ .emu10k1_chip = 1,
+ .ac97_chip = 1,
+ .sblive51 = 1} ,
+ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80221102,
+ .driver = "EMU10K1", .name = "SBLive! Value [CT4780]",
+ .id = "Live",
+ .emu10k1_chip = 1,
+ .ac97_chip = 1,
+ .sblive51 = 1} ,
+ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80231102,
+ .driver = "EMU10K1", .name = "SB PCI512 [CT4790]",
+ .id = "Live",
+ .emu10k1_chip = 1,
+ .ac97_chip = 1,
+ .sblive51 = 1} ,
+ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80261102,
+ .driver = "EMU10K1", .name = "SBLive! Value [CT4830]",
+ .id = "Live",
+ .emu10k1_chip = 1,
+ .ac97_chip = 1,
+ .sblive51 = 1} ,
+ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80311102,
+ .driver = "EMU10K1", .name = "SBLive! Value [CT4831]",
+ .id = "Live",
+ .emu10k1_chip = 1,
+ .ac97_chip = 1,
+ .sblive51 = 1} ,
+ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80271102,
+ .driver = "EMU10K1", .name = "SBLive! Value [CT4832]",
+ .id = "Live",
+ .emu10k1_chip = 1,
+ .ac97_chip = 1,
+ .sblive51 = 1} ,
+ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80511102,
+ .driver = "EMU10K1", .name = "SBLive! Value [CT4850]",
+ .id = "Live",
+ .emu10k1_chip = 1,
+ .ac97_chip = 1,
+ .sblive51 = 1} ,
+ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80281102,
+ .driver = "EMU10K1", .name = "SBLive! Value [CT4870]",
+ .id = "Live",
+ .emu10k1_chip = 1,
+ .ac97_chip = 1,
+ .sblive51 = 1} ,
+ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80321102,
+ .driver = "EMU10K1", .name = "SBLive! Value [CT4871]",
+ .id = "Live",
+ .emu10k1_chip = 1,
+ .ac97_chip = 1,
+ .sblive51 = 1} ,
+ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80611102,
+ .driver = "EMU10K1", .name = "SBLive! Value [SB0060]",
+ .id = "Live",
+ .emu10k1_chip = 1,
+ .ac97_chip = 1,
+ .sblive51 = 1} ,
+ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80691102,
+ .driver = "EMU10K1", .name = "SBLive! Value [SB0101]",
+ .id = "Live",
+ .emu10k1_chip = 1,
+ .ac97_chip = 1,
+ .sblive51 = 1} ,
+ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x806A1102,
+ .driver = "EMU10K1", .name = "SBLive! Value [SB0103]",
+ .id = "Live",
+ .emu10k1_chip = 1,
+ .ac97_chip = 1,
+ .sblive51 = 1} ,
+ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x806B1102,
+ .driver = "EMU10K1", .name = "SBLive! [SB0105]",
+ .id = "Live",
+ .emu10k1_chip = 1,
+ .ac97_chip = 1,
+ .sblive51 = 1} ,
{.vendor = 0x1102, .device = 0x0002,
.driver = "EMU10K1", .name = "SB Live [Unknown]",
+ .id = "Live",
.emu10k1_chip = 1,
- .ac97_chip = 1} ,
+ .ac97_chip = 1,
+ .sblive51 = 1} ,
{ } /* terminator */
};
emu->revision = revision;
pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &emu->serial);
pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &emu->model);
- emu->card_type = EMU10K1_CARD_CREATIVE;
snd_printdd("vendor=0x%x, device=0x%x, subsystem_vendor_id=0x%x, subsystem_id=0x%x\n",pci->vendor, pci->device, emu->serial, emu->model);
for (c = emu_chip_details; c->vendor; c++) {
if (c->vendor == pci->vendor && c->device == pci->device) {
- if (c->subsystem == emu->serial) break;
- if (c->subsystem == 0) break;
+ if (c->subsystem && c->subsystem != emu->serial)
+ continue;
+ if (c->revision && c->revision != emu->revision)
+ continue;
+ break;
}
}
if (c->vendor == 0) {
else
snd_printdd("Sound card name=%s, vendor=0x%x, device=0x%x, subsystem=0x%x\n", c->name, pci->vendor, pci->device, emu->serial);
+ if (!*card->id && c->id) {
+ int i, n = 0;
+ strlcpy(card->id, c->id, sizeof(card->id));
+ for (;;) {
+ for (i = 0; i < snd_ecards_limit; i++) {
+ if (snd_cards[i] && !strcmp(snd_cards[i]->id, card->id))
+ break;
+ }
+ if (i >= snd_ecards_limit)
+ break;
+ n++;
+ if (n >= SNDRV_CARDS)
+ break;
+ snprintf(card->id, sizeof(card->id), "%s_%d", c->id, n);
+ }
+ }
+
is_audigy = emu->audigy = c->emu10k2_chip;
/* set the DMA transfer mask */
pci_set_master(pci);
- if (c->ecard) {
- emu->card_type = EMU10K1_CARD_EMUAPS;
- emu->APS = 1;
- }
- if (! c->ac97_chip)
- emu->no_ac97 = 1;
-
- emu->spk71 = c->spk71;
-
emu->fx8010.fxbus_mask = 0x303f;
if (extin_mask == 0)
extin_mask = 0x3fcf;
emu->fx8010.extin_mask = extin_mask;
emu->fx8010.extout_mask = extout_mask;
- if (emu->APS) {
+ if (emu->card_capabilities->ecard) {
if ((err = snd_emu10k1_ecard_init(emu)) < 0) {
snd_emu10k1_free(emu);
return err;
static void snd_emu10k1x_pcm_free_substream(snd_pcm_runtime_t *runtime)
{
- emu10k1x_pcm_t *epcm = runtime->private_data;
-
- if (epcm)
- kfree(epcm);
+ kfree(runtime->private_data);
}
static void snd_emu10k1x_pcm_interrupt(emu10k1x_t *emu, emu10k1x_voice_t *voice)
snd_info_set_text_ops(entry, emu, 1024, snd_emu10k1x_proc_reg_read);
entry->c.text.write_size = 64;
entry->c.text.write = snd_emu10k1x_proc_reg_write;
+ entry->mode |= S_IWUSR;
entry->private_data = emu;
}
{
int err;
- if ((err = pci_module_init(&driver)) > 0)
+ if ((err = pci_register_driver(&driver)) > 0)
return err;
return 0;
gpr += 2;
/* PCM Side Playback (independent from stereo mix) */
- if (emu->spk71) {
+ if (emu->card_capabilities->spk71) {
A_OP(icode, &ptr, iMAC0, A_GPR(playback+6), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_SIDE));
A_OP(icode, &ptr, iMAC0, A_GPR(playback+7), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_SIDE));
snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Side Playback Volume", gpr, 100);
A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_SPDIF_CD_L);
A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_SPDIF_CD_R);
snd_emu10k1_init_stereo_control(&controls[nctl++],
- emu->no_ac97 ? "CD Playback Volume" : "Audigy CD Playback Volume",
+ emu->card_capabilities->ac97_chip ? "Audigy CD Playback Volume" : "CD Playback Volume",
gpr, 0);
gpr += 2;
/* Audigy CD Capture Volume */
A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_SPDIF_CD_L);
A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_SPDIF_CD_R);
snd_emu10k1_init_stereo_control(&controls[nctl++],
- emu->no_ac97 ? "CD Capture Volume" : "Audigy CD Capture Volume",
+ emu->card_capabilities->ac97_chip ? "Audigy CD Capture Volume" : "CD Capture Volume",
gpr, 0);
gpr += 2;
A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_LINE2_L);
A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_LINE2_R);
snd_emu10k1_init_stereo_control(&controls[nctl++],
- emu->no_ac97 ? "Line Playback Volume" : "Line2 Playback Volume",
+ emu->card_capabilities->ac97_chip ? "Line2 Playback Volume" : "Line Playback Volume",
gpr, 0);
gpr += 2;
/* Line2 Capture Volume */
A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_LINE2_L);
A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_LINE2_R);
snd_emu10k1_init_stereo_control(&controls[nctl++],
- emu->no_ac97 ? "Line Capture Volume" : "Line2 Capture Volume",
+ emu->card_capabilities->ac97_chip ? "Line2 Capture Volume" : "Line Capture Volume",
gpr, 0);
gpr += 2;
A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AUX2_L);
A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AUX2_R);
snd_emu10k1_init_stereo_control(&controls[nctl++],
- emu->no_ac97 ? "Aux Playback Volume" : "Aux2 Playback Volume",
+ emu->card_capabilities->ac97_chip ? "Aux2 Playback Volume" : "Aux Playback Volume",
gpr, 0);
gpr += 2;
/* Aux2 Capture Volume */
A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_AUX2_L);
A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_AUX2_R);
snd_emu10k1_init_stereo_control(&controls[nctl++],
- emu->no_ac97 ? "Aux Capture Volume" : "Aux2 Capture Volume",
+ emu->card_capabilities->ac97_chip ? "Aux2 Capture Volume" : "Aux Capture Volume",
gpr, 0);
gpr += 2;
snd_emu10k1_init_mono_control(&controls[nctl++], "LFE Playback Volume", gpr, 0);
gpr++;
- if (emu->spk71) {
+ if (emu->card_capabilities->spk71) {
/* Stereo Mix Side Playback */
A_OP(icode, &ptr, iMAC0, A_GPR(playback+6), A_GPR(playback+6), A_GPR(gpr), A_GPR(stereo_mix));
A_OP(icode, &ptr, iMAC0, A_GPR(playback+7), A_GPR(playback+7), A_GPR(gpr+1), A_GPR(stereo_mix+1));
A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 3), A_GPR(playback + 3), A_C_00000000, A_C_00000000); /* rear right */
A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), A_GPR(playback + 4), A_C_00000000, A_C_00000000); /* center */
A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), A_GPR(playback + 5), A_C_00000000, A_C_00000000); /* LFE */
- if (emu->spk71) {
+ if (emu->card_capabilities->spk71) {
A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 6), A_GPR(playback + 6), A_C_00000000, A_C_00000000); /* side left */
A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 7), A_GPR(playback + 7), A_C_00000000, A_C_00000000); /* side right */
}
A_PUT_STEREO_OUTPUT(A_EXTOUT_AREAR_L, A_EXTOUT_AREAR_R, playback+2 + SND_EMU10K1_PLAYBACK_CHANNELS);
A_PUT_OUTPUT(A_EXTOUT_ACENTER, playback+4 + SND_EMU10K1_PLAYBACK_CHANNELS);
A_PUT_OUTPUT(A_EXTOUT_ALFE, playback+5 + SND_EMU10K1_PLAYBACK_CHANNELS);
- if (emu->spk71)
+ if (emu->card_capabilities->spk71)
A_PUT_STEREO_OUTPUT(A_EXTOUT_ASIDE_L, A_EXTOUT_ASIDE_R, playback+6 + SND_EMU10K1_PLAYBACK_CHANNELS);
/* headphone */
OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_MIC_CAP), GPR(capture + 2), C_00000000, C_00000000);
/* EFX capture - capture the 16 EXTINS */
- OP(icode, &ptr, iACC3, FXBUS2(14), C_00000000, C_00000000, EXTIN(0));
- OP(icode, &ptr, iACC3, FXBUS2(15), C_00000000, C_00000000, EXTIN(1));
- OP(icode, &ptr, iACC3, FXBUS2(0), C_00000000, C_00000000, EXTIN(2));
- OP(icode, &ptr, iACC3, FXBUS2(3), C_00000000, C_00000000, EXTIN(3));
- /* Dont connect anything to FXBUS2 1 and 2. These are shared with
- * Center/LFE on the SBLive 5.1. The kX driver only changes the
- * routing when it detects an SBLive 5.1.
- *
- * Since only 14 of the 16 EXTINs are used, this is not a big problem.
- * We route AC97L and R to FX capture 14 and 15, SPDIF CD in to FX capture
- * 0 and 3, then the rest of the EXTINs to the corresponding FX capture
- * channel.
- */
- for (z = 4; z < 14; z++) {
- OP(icode, &ptr, iACC3, FXBUS2(z), C_00000000, C_00000000, EXTIN(z));
+ if (emu->card_capabilities->sblive51) {
+ /* On the Live! 5.1, FXBUS2(1) and FXBUS(2) are shared with EXTOUT_ACENTER
+ * and EXTOUT_ALFE, so we can't connect inputs to them for multitrack recording.
+ *
+ * Since only 14 of the 16 EXTINs are used, this is not a big problem.
+ * We route AC97L and R to FX capture 14 and 15, SPDIF CD in to FX capture
+ * 0 and 3, then the rest of the EXTINs to the corresponding FX capture
+ * channel. Multitrack recorders will still see the center/lfe output signal
+ * on the second and third channels.
+ */
+ OP(icode, &ptr, iACC3, FXBUS2(14), C_00000000, C_00000000, EXTIN(0));
+ OP(icode, &ptr, iACC3, FXBUS2(15), C_00000000, C_00000000, EXTIN(1));
+ OP(icode, &ptr, iACC3, FXBUS2(0), C_00000000, C_00000000, EXTIN(2));
+ OP(icode, &ptr, iACC3, FXBUS2(3), C_00000000, C_00000000, EXTIN(3));
+ for (z = 4; z < 14; z++)
+ OP(icode, &ptr, iACC3, FXBUS2(z), C_00000000, C_00000000, EXTIN(z));
+ } else {
+ for (z = 0; z < 16; z++)
+ OP(icode, &ptr, iACC3, FXBUS2(z), C_00000000, C_00000000, EXTIN(z));
}
+
if (gpr > tmp) {
snd_BUG();
int res;
memset(info, 0, sizeof(info));
- info->card = emu->card_type;
info->internal_tram_size = emu->fx8010.itram_size;
info->external_tram_size = emu->fx8010.etram_pages.bytes / 2;
fxbus = fxbuses;
return 0;
}
+#if 0
static int snd_audigy_spdif_output_rate_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
{
static char *texts[] = {"44100", "48000", "96000"};
.get = snd_audigy_spdif_output_rate_get,
.put = snd_audigy_spdif_output_rate_put
};
+#endif
static int snd_emu10k1_spdif_put(snd_kcontrol_t * kcontrol,
snd_ctl_elem_value_t * ucontrol)
NULL
};
- if (!emu->no_ac97) {
+ if (emu->card_capabilities->ac97_chip) {
ac97_bus_t *pbus;
ac97_template_t ac97;
static ac97_bus_ops_t ops = {
for (; *c; c++)
remove_ctl(card, *c);
} else {
- if (emu->APS)
+ if (emu->card_capabilities->ecard)
strcpy(emu->card->mixername, "EMU APS");
else if (emu->audigy)
strcpy(emu->card->mixername, "SB Audigy");
mix->attn[0] = 0xffff;
}
- if (! emu->APS) { /* FIXME: APS has these controls? */
+ if (! emu->card_capabilities->ecard) { /* FIXME: APS has these controls? */
/* sb live! and audigy */
if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu)) == NULL)
return -ENOMEM;
return -ENOMEM;
if ((err = snd_ctl_add(card, kctl)))
return err;
+#if 0
if ((kctl = snd_ctl_new1(&snd_audigy_spdif_output_rate, emu)) == NULL)
return -ENOMEM;
if ((err = snd_ctl_add(card, kctl)))
return err;
- } else if (! emu->APS) {
+#endif
+ } else if (! emu->card_capabilities->ecard) {
/* sb live! */
if ((kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu)) == NULL)
return -ENOMEM;
if ((err = snd_ctl_add(card, kctl)))
return err;
}
- if (emu->audigy && emu->revision == 4) { /* P16V */
+ if (emu->card_capabilities->ca0151_chip) { /* P16V */
if ((err = snd_p16v_mixer(emu)))
return err;
}
*
* returns: cache invalidate size in samples
*/
-static int inline emu10k1_ccis(int stereo, int w_16)
+static inline int emu10k1_ccis(int stereo, int w_16)
{
if (w_16) {
return stereo ? 24 : 26;
static void snd_emu10k1_pcm_free_substream(snd_pcm_runtime_t *runtime)
{
- emu10k1_pcm_t *epcm = runtime->private_data;
-
- kfree(epcm);
+ kfree(runtime->private_data);
}
static int snd_emu10k1_efx_playback_close(snd_pcm_substream_t * substream)
#include <linux/init.h>
#include <sound/core.h>
#include <sound/emu10k1.h>
+#include "p16v.h"
static void snd_emu10k1_proc_spdif_status(emu10k1_t * emu,
snd_info_buffer_t * buffer,
unsigned int status, rate = 0;
status = snd_emu10k1_ptr_read(emu, status_reg, 0);
- if (rate_reg > 0)
- rate = snd_emu10k1_ptr_read(emu, rate_reg, 0);
snd_iprintf(buffer, "\n%s\n", title);
- snd_iprintf(buffer, "Professional Mode : %s\n", (status & SPCS_PROFESSIONAL) ? "yes" : "no");
- snd_iprintf(buffer, "Not Audio Data : %s\n", (status & SPCS_NOTAUDIODATA) ? "yes" : "no");
- snd_iprintf(buffer, "Copyright : %s\n", (status & SPCS_COPYRIGHT) ? "yes" : "no");
- snd_iprintf(buffer, "Emphasis : %s\n", emphasis[(status & SPCS_EMPHASISMASK) >> 3]);
- snd_iprintf(buffer, "Mode : %i\n", (status & SPCS_MODEMASK) >> 6);
- snd_iprintf(buffer, "Category Code : 0x%x\n", (status & SPCS_CATEGORYCODEMASK) >> 8);
- snd_iprintf(buffer, "Generation Status : %s\n", status & SPCS_GENERATIONSTATUS ? "original" : "copy");
- snd_iprintf(buffer, "Source Mask : %i\n", (status & SPCS_SOURCENUMMASK) >> 16);
- snd_iprintf(buffer, "Channel Number : %s\n", channel[(status & SPCS_CHANNELNUMMASK) >> 20]);
- snd_iprintf(buffer, "Sample Rate : %iHz\n", samplerate[(status & SPCS_SAMPLERATEMASK) >> 24]);
- snd_iprintf(buffer, "Clock Accuracy : %s\n", clkaccy[(status & SPCS_CLKACCYMASK) >> 28]);
-
- if (rate_reg > 0) {
- snd_iprintf(buffer, "S/PDIF Locked : %s\n", rate & SRCS_SPDIFLOCKED ? "on" : "off");
- snd_iprintf(buffer, "Rate Locked : %s\n", rate & SRCS_RATELOCKED ? "on" : "off");
- snd_iprintf(buffer, "Estimated Sample Rate : 0x%x\n", rate & SRCS_ESTSAMPLERATE);
+ if (status != 0xffffffff) {
+ snd_iprintf(buffer, "Professional Mode : %s\n", (status & SPCS_PROFESSIONAL) ? "yes" : "no");
+ snd_iprintf(buffer, "Not Audio Data : %s\n", (status & SPCS_NOTAUDIODATA) ? "yes" : "no");
+ snd_iprintf(buffer, "Copyright : %s\n", (status & SPCS_COPYRIGHT) ? "yes" : "no");
+ snd_iprintf(buffer, "Emphasis : %s\n", emphasis[(status & SPCS_EMPHASISMASK) >> 3]);
+ snd_iprintf(buffer, "Mode : %i\n", (status & SPCS_MODEMASK) >> 6);
+ snd_iprintf(buffer, "Category Code : 0x%x\n", (status & SPCS_CATEGORYCODEMASK) >> 8);
+ snd_iprintf(buffer, "Generation Status : %s\n", status & SPCS_GENERATIONSTATUS ? "original" : "copy");
+ snd_iprintf(buffer, "Source Mask : %i\n", (status & SPCS_SOURCENUMMASK) >> 16);
+ snd_iprintf(buffer, "Channel Number : %s\n", channel[(status & SPCS_CHANNELNUMMASK) >> 20]);
+ snd_iprintf(buffer, "Sample Rate : %iHz\n", samplerate[(status & SPCS_SAMPLERATEMASK) >> 24]);
+ snd_iprintf(buffer, "Clock Accuracy : %s\n", clkaccy[(status & SPCS_CLKACCYMASK) >> 28]);
+
+ if (rate_reg > 0) {
+ rate = snd_emu10k1_ptr_read(emu, rate_reg, 0);
+ snd_iprintf(buffer, "S/PDIF Valid : %s\n", rate & SRCS_SPDIFVALID ? "on" : "off");
+ snd_iprintf(buffer, "S/PDIF Locked : %s\n", rate & SRCS_SPDIFLOCKED ? "on" : "off");
+ snd_iprintf(buffer, "Rate Locked : %s\n", rate & SRCS_RATELOCKED ? "on" : "off");
+ /* From ((Rate * 48000 ) / 262144); */
+ snd_iprintf(buffer, "Estimated Sample Rate : %d\n", ((rate & 0xFFFFF ) * 375) >> 11);
+ }
+ } else {
+ snd_iprintf(buffer, "No signal detected.\n");
}
+
}
static void snd_emu10k1_proc_read(snd_info_entry_t *entry,
snd_iprintf(buffer, "EMU10K1\n\n");
snd_iprintf(buffer, "Card : %s\n",
- emu->audigy ? "Audigy" : (emu->APS ? "EMU APS" : "Creative"));
+ emu->audigy ? "Audigy" : (emu->card_capabilities->ecard ? "EMU APS" : "Creative"));
snd_iprintf(buffer, "Internal TRAM (words) : 0x%x\n", emu->fx8010.itram_size);
snd_iprintf(buffer, "External TRAM (words) : 0x%x\n", (int)emu->fx8010.etram_pages.bytes / 2);
snd_iprintf(buffer, "\n");
snd_iprintf(buffer, "\nAll FX Outputs :\n");
for (idx = 0; idx < (emu->audigy ? 64 : 32); idx++)
snd_iprintf(buffer, " Output %02i [%s]\n", idx, outputs[idx]);
- snd_emu10k1_proc_spdif_status(emu, buffer, "S/PDIF Output 0", SPCS0, -1);
- snd_emu10k1_proc_spdif_status(emu, buffer, "S/PDIF Output 1", SPCS1, -1);
- snd_emu10k1_proc_spdif_status(emu, buffer, "S/PDIF Output 2/3", SPCS2, -1);
- snd_emu10k1_proc_spdif_status(emu, buffer, "CD-ROM S/PDIF", CDCS, CDSRCS);
- snd_emu10k1_proc_spdif_status(emu, buffer, "General purpose S/PDIF", GPSCS, GPSRCS);
+}
+
+static void snd_emu10k1_proc_spdif_read(snd_info_entry_t *entry,
+ snd_info_buffer_t * buffer)
+{
+ emu10k1_t *emu = entry->private_data;
+ snd_emu10k1_proc_spdif_status(emu, buffer, "CD-ROM S/PDIF In", CDCS, CDSRCS);
+ snd_emu10k1_proc_spdif_status(emu, buffer, "Optical or Coax S/PDIF In", GPSCS, GPSRCS);
+#if 0
val = snd_emu10k1_ptr_read(emu, ZVSRCS, 0);
snd_iprintf(buffer, "\nZoomed Video\n");
snd_iprintf(buffer, "Rate Locked : %s\n", val & SRCS_RATELOCKED ? "on" : "off");
snd_iprintf(buffer, "Estimated Sample Rate : 0x%x\n", val & SRCS_ESTSAMPLERATE);
+#endif
+}
+
+static void snd_emu10k1_proc_rates_read(snd_info_entry_t *entry,
+ snd_info_buffer_t * buffer)
+{
+ static int samplerate[8] = { 44100, 48000, 96000, 192000, 4, 5, 6, 7 };
+ emu10k1_t *emu = entry->private_data;
+ unsigned int val, tmp, n;
+ val = snd_emu10k1_ptr20_read(emu, CAPTURE_RATE_STATUS, 0);
+ tmp = (val >> 16) & 0x8;
+ for (n=0;n<4;n++) {
+ tmp = val >> (16 + (n*4));
+ if (tmp & 0x8) snd_iprintf(buffer, "Channel %d: Rate=%d\n", n, samplerate[tmp & 0x7]);
+ else snd_iprintf(buffer, "Channel %d: No input\n", n);
+ }
}
static void snd_emu10k1_proc_acode_read(snd_info_entry_t *entry,
snd_info_set_text_ops(entry, emu, 1024, snd_emu_proc_io_reg_read);
entry->c.text.write_size = 64;
entry->c.text.write = snd_emu_proc_io_reg_write;
+ entry->mode |= S_IWUSR;
}
if (! snd_card_proc_new(emu->card, "ptr_regs00a", &entry)) {
snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read00a);
entry->c.text.write_size = 64;
entry->c.text.write = snd_emu_proc_ptr_reg_write00;
+ entry->mode |= S_IWUSR;
}
if (! snd_card_proc_new(emu->card, "ptr_regs00b", &entry)) {
snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read00b);
entry->c.text.write_size = 64;
entry->c.text.write = snd_emu_proc_ptr_reg_write00;
+ entry->mode |= S_IWUSR;
}
if (! snd_card_proc_new(emu->card, "ptr_regs20a", &entry)) {
snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read20a);
entry->c.text.write_size = 64;
entry->c.text.write = snd_emu_proc_ptr_reg_write20;
+ entry->mode |= S_IWUSR;
}
if (! snd_card_proc_new(emu->card, "ptr_regs20b", &entry)) {
snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read20b);
entry->c.text.write_size = 64;
entry->c.text.write = snd_emu_proc_ptr_reg_write20;
+ entry->mode |= S_IWUSR;
}
#endif
if (! snd_card_proc_new(emu->card, "emu10k1", &entry))
snd_info_set_text_ops(entry, emu, 2048, snd_emu10k1_proc_read);
+ if (emu->card_capabilities->emu10k2_chip) {
+ if (! snd_card_proc_new(emu->card, "spdif-in", &entry))
+ snd_info_set_text_ops(entry, emu, 2048, snd_emu10k1_proc_spdif_read);
+ }
+ if (emu->card_capabilities->ca0151_chip) {
+ if (! snd_card_proc_new(emu->card, "capture-rates", &entry))
+ snd_info_set_text_ops(entry, emu, 2048, snd_emu10k1_proc_rates_read);
+ }
+
if (! snd_card_proc_new(emu->card, "voices", &entry))
snd_info_set_text_ops(entry, emu, 2048, snd_emu10k1_proc_voices_read);
int handled = 0;
while ((status = inl(emu->port + IPR)) != 0) {
- // printk("irq - status = 0x%x\n", status);
+ //printk("emu10k1 irq - status = 0x%x\n", status);
orig_status = status;
handled = 1;
if (status & IPR_PCIERROR) {
snd_emu10k1_intr_disable(emu, INTE_FXDSPENABLE);
status &= ~IPR_FXDSP;
}
+ if (status & IPR_P16V) {
+ while ((status2 = inl(emu->port + IPR2)) != 0) {
+ u32 mask = INTE2_PLAYBACK_CH_0_LOOP; /* Full Loop */
+ emu10k1_voice_t *pvoice = &(emu->p16v_voices[0]);
+ emu10k1_voice_t *cvoice = &(emu->p16v_capture_voice);
+
+ //printk(KERN_INFO "status2=0x%x\n", status2);
+ orig_status2 = status2;
+ if(status2 & mask) {
+ if(pvoice->use) {
+ snd_pcm_period_elapsed(pvoice->epcm->substream);
+ } else {
+ snd_printk(KERN_ERR "p16v: status: 0x%08x, mask=0x%08x, pvoice=%p, use=%d\n", status2, mask, pvoice, pvoice->use);
+ }
+ }
+ if(status2 & 0x110000) {
+ //printk(KERN_INFO "capture int found\n");
+ if(cvoice->use) {
+ //printk(KERN_INFO "capture period_elapsed\n");
+ snd_pcm_period_elapsed(cvoice->epcm->substream);
+ }
+ }
+ outl(orig_status2, emu->port + IPR2); /* ack all */
+ }
+ status &= ~IPR_P16V;
+ }
+
if (status) {
unsigned int bits;
- //snd_printk(KERN_ERR "emu10k1: unhandled interrupt: 0x%08x\n", status);
+ snd_printk(KERN_ERR "emu10k1: unhandled interrupt: 0x%08x\n", status);
//make sure any interrupts we don't handle are disabled:
bits = INTE_FXDSPENABLE |
INTE_PCIERRORENABLE |
}
outl(orig_status, emu->port + IPR); /* ack all */
}
- if (emu->audigy && emu->revision == 4) { /* P16V */
- while ((status2 = inl(emu->port + IPR2)) != 0) {
- u32 mask = INTE2_PLAYBACK_CH_0_LOOP; /* Full Loop */
- emu10k1_voice_t *pvoice = &(emu->p16v_voices[0]);
- orig_status2 = status2;
- if(status2 & mask) {
- if(pvoice->use) {
- snd_pcm_period_elapsed(pvoice->epcm->substream);
- } else {
- snd_printk(KERN_ERR "p16v: status: 0x%08x, mask=0x%08x, pvoice=%p, use=%d\n", status2, mask, pvoice, pvoice->use);
- }
- }
- outl(orig_status2, emu->port + IPR2); /* ack all */
- }
- }
return IRQ_RETVAL(handled);
}
/*
* Copyright (c) by James Courtier-Dutton <James@superbug.demon.co.uk>
* Driver p16v chips
- * Version: 0.22
+ * Version: 0.25
*
* FEATURES currently supported:
* Output fixed at S32_LE, 2 channel to hw:0,0
* Integrated with snd-emu10k1 driver.
* 0.22
* Removed #if 0 ... #endif
- *
+ * 0.23
+ * Implement different capture rates.
+ * 0.24
+ * Implement different capture source channels.
+ * e.g. When HD Capture source is set to SPDIF,
+ * setting HD Capture channel to 0 captures from CDROM digital input.
+ * setting HD Capture channel to 1 captures from SPDIF in.
+ * 0.25
+ * Include capture buffer sizes.
*
* BUGS:
* Some stability problems when unloading the snd-p16v kernel module.
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID),
.formats = SNDRV_PCM_FMTBIT_S32_LE, /* Only supports 24-bit samples padded to 32 bits. */
- .rates = SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_48000 ,
- .rate_min = 48000,
+ .rates = SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_44100,
+ .rate_min = 44100,
.rate_max = 192000,
.channels_min = 8,
.channels_max = 8,
- .buffer_bytes_max = (32*1024),
+ .buffer_bytes_max = ((65536 - 64) * 8),
.period_bytes_min = 64,
- .period_bytes_max = (16*1024),
+ .period_bytes_max = (65536 - 64),
.periods_min = 2,
.periods_max = 8,
.fifo_size = 0,
};
+static snd_pcm_hardware_t snd_p16v_capture_hw = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID),
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,
+ .rates = SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_44100,
+ .rate_min = 44100,
+ .rate_max = 192000,
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = (65536 - 64),
+ .period_bytes_min = 64,
+ .period_bytes_max = (65536 - 128) >> 1, /* size has to be N*64 bytes */
+ .periods_min = 2,
+ .periods_max = 2,
+ .fifo_size = 0,
+};
+
static void snd_p16v_pcm_free_substream(snd_pcm_runtime_t *runtime)
{
- snd_pcm_t *epcm = runtime->private_data;
+ emu10k1_pcm_t *epcm = runtime->private_data;
if (epcm) {
//snd_printk("epcm free: %p\n", epcm);
return 0;
}
+/* open_capture callback */
+static int snd_p16v_pcm_open_capture_channel(snd_pcm_substream_t *substream, int channel_id)
+{
+ emu10k1_t *emu = snd_pcm_substream_chip(substream);
+ emu10k1_voice_t *channel = &(emu->p16v_capture_voice);
+ emu10k1_pcm_t *epcm;
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ int err;
+
+ epcm = kcalloc(1, sizeof(*epcm), GFP_KERNEL);
+ //snd_printk("epcm kcalloc: %p\n", epcm);
+
+ if (epcm == NULL)
+ return -ENOMEM;
+ epcm->emu = emu;
+ epcm->substream = substream;
+ //snd_printk("epcm device=%d, channel_id=%d\n", substream->pcm->device, channel_id);
+
+ runtime->private_data = epcm;
+ runtime->private_free = snd_p16v_pcm_free_substream;
+
+ runtime->hw = snd_p16v_capture_hw;
+
+ channel->emu = emu;
+ channel->number = channel_id;
+
+ channel->use=1;
+ //snd_printk("p16v: open channel_id=%d, channel=%p, use=0x%x\n", channel_id, channel, channel->use);
+ //printk("open:channel_id=%d, chip=%p, channel=%p\n",channel_id, chip, channel);
+ //channel->interrupt = snd_p16v_pcm_channel_interrupt;
+ channel->epcm=epcm;
+ if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
+ return err;
+
+ return 0;
+}
+
/* close callback */
static int snd_p16v_pcm_close_playback(snd_pcm_substream_t *substream)
{
emu10k1_t *emu = snd_pcm_substream_chip(substream);
//snd_pcm_runtime_t *runtime = substream->runtime;
- //emu10k1_pcm_t *epcm = runtime->private_data;
- emu->p16v_voices[substream->pcm->device - emu->p16v_device_offset].use=0;
-/* FIXME: maybe zero others */
+ //emu10k1_pcm_t *epcm = runtime->private_data;
+ emu->p16v_voices[substream->pcm->device - emu->p16v_device_offset].use=0;
+ /* FIXME: maybe zero others */
+ return 0;
+}
+
+/* close callback */
+static int snd_p16v_pcm_close_capture(snd_pcm_substream_t *substream)
+{
+ emu10k1_t *emu = snd_pcm_substream_chip(substream);
+ //snd_pcm_runtime_t *runtime = substream->runtime;
+ //emu10k1_pcm_t *epcm = runtime->private_data;
+ emu->p16v_capture_voice.use=0;
+ /* FIXME: maybe zero others */
return 0;
}
return snd_p16v_pcm_open_playback_channel(substream, PCM_FRONT_CHANNEL);
}
+static int snd_p16v_pcm_open_capture(snd_pcm_substream_t *substream)
+{
+ // Only using channel 0 for now, but the card has 2 channels.
+ return snd_p16v_pcm_open_capture_channel(substream, 0);
+}
+
/* hw_params callback */
static int snd_p16v_pcm_hw_params_playback(snd_pcm_substream_t *substream,
snd_pcm_hw_params_t * hw_params)
{
int result;
- //snd_printk("hw_params alloc: substream=%p\n", substream);
result = snd_pcm_lib_malloc_pages(substream,
params_buffer_bytes(hw_params));
- //snd_printk("hw_params alloc: result=%d\n", result);
- //dump_stack();
return result;
}
+/* hw_params callback */
+static int snd_p16v_pcm_hw_params_capture(snd_pcm_substream_t *substream,
+ snd_pcm_hw_params_t * hw_params)
+{
+ int result;
+ result = snd_pcm_lib_malloc_pages(substream,
+ params_buffer_bytes(hw_params));
+ return result;
+}
+
+
/* hw_free callback */
static int snd_p16v_pcm_hw_free_playback(snd_pcm_substream_t *substream)
{
int result;
- //snd_printk("hw_params free: substream=%p\n", substream);
result = snd_pcm_lib_free_pages(substream);
- //snd_printk("hw_params free: result=%d\n", result);
- //dump_stack();
return result;
}
+/* hw_free callback */
+static int snd_p16v_pcm_hw_free_capture(snd_pcm_substream_t *substream)
+{
+ int result;
+ result = snd_pcm_lib_free_pages(substream);
+ return result;
+}
+
+
/* prepare playback callback */
static int snd_p16v_pcm_prepare_playback(snd_pcm_substream_t *substream)
{
emu10k1_t *emu = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
- //emu10k1_pcm_t *epcm = runtime->private_data;
int channel = substream->pcm->device - emu->p16v_device_offset;
u32 *table_base = (u32 *)(emu->p16v_buffer.area+(8*16*channel));
u32 period_size_bytes = frames_to_bytes(runtime, runtime->period_size);
tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, channel);
switch (runtime->rate) {
case 44100:
- snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe000) | 0x8000); /* FIXME: This will change the capture rate as well! */
- break;
- case 48000:
- snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe000) | 0x0000); /* FIXME: This will change the capture rate as well! */
+ snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe0e0) | 0x8080);
break;
case 96000:
- snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe000) | 0x4000); /* FIXME: This will change the capture rate as well! */
+ snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe0e0) | 0x4040);
break;
case 192000:
- snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe000) | 0x2000); /* FIXME: This will change the capture rate as well! */
+ snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe0e0) | 0x2020);
break;
+ case 48000:
default:
- snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, 0x0000); /* FIXME: This will change the capture rate as well! */
+ snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe0e0) | 0x0000);
break;
}
/* FIXME: Check emu->buffer.size before actually writing to it. */
- for(i=0; i < runtime->periods; i++) {
+ for(i=0; i < runtime->periods; i++) {
table_base[i*2]=runtime->dma_addr+(i*period_size_bytes);
table_base[(i*2)+1]=period_size_bytes<<16;
}
snd_emu10k1_ptr20_write(emu, PLAYBACK_LIST_SIZE, channel, (runtime->periods - 1) << 19);
snd_emu10k1_ptr20_write(emu, PLAYBACK_LIST_PTR, channel, 0);
snd_emu10k1_ptr20_write(emu, PLAYBACK_DMA_ADDR, channel, runtime->dma_addr);
- snd_emu10k1_ptr20_write(emu, PLAYBACK_PERIOD_SIZE, channel, frames_to_bytes(runtime, runtime->period_size)<<16); // buffer size in bytes
+ //snd_emu10k1_ptr20_write(emu, PLAYBACK_PERIOD_SIZE, channel, frames_to_bytes(runtime, runtime->period_size)<<16); // buffer size in bytes
+ snd_emu10k1_ptr20_write(emu, PLAYBACK_PERIOD_SIZE, channel, 0); // buffer size in bytes
snd_emu10k1_ptr20_write(emu, PLAYBACK_POINTER, channel, 0);
snd_emu10k1_ptr20_write(emu, 0x07, channel, 0x0);
snd_emu10k1_ptr20_write(emu, 0x08, channel, 0);
return 0;
}
+/* prepare capture callback */
+static int snd_p16v_pcm_prepare_capture(snd_pcm_substream_t *substream)
+{
+ emu10k1_t *emu = snd_pcm_substream_chip(substream);
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ int channel = substream->pcm->device - emu->p16v_device_offset;
+ u32 tmp;
+ //printk("prepare capture:channel_number=%d, rate=%d, format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, frames_to_bytes=%d\n",channel, runtime->rate, runtime->format, runtime->channels, runtime->buffer_size, runtime->period_size, frames_to_bytes(runtime, 1));
+ tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, channel);
+ switch (runtime->rate) {
+ case 44100:
+ snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0x0e00) | 0x0800);
+ break;
+ case 96000:
+ snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0x0e00) | 0x0400);
+ break;
+ case 192000:
+ snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0x0e00) | 0x0200);
+ break;
+ case 48000:
+ default:
+ snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0x0e00) | 0x0000);
+ break;
+ }
+ /* FIXME: Check emu->buffer.size before actually writing to it. */
+ snd_emu10k1_ptr20_write(emu, 0x13, channel, 0);
+ snd_emu10k1_ptr20_write(emu, CAPTURE_DMA_ADDR, channel, runtime->dma_addr);
+ snd_emu10k1_ptr20_write(emu, CAPTURE_BUFFER_SIZE, channel, frames_to_bytes(runtime, runtime->buffer_size)<<16); // buffer size in bytes
+ snd_emu10k1_ptr20_write(emu, CAPTURE_POINTER, channel, 0);
+ //snd_emu10k1_ptr20_write(emu, CAPTURE_SOURCE, 0x0, 0x333300e4); /* Select MIC or Line in */
+ //snd_emu10k1_ptr20_write(emu, EXTENDED_INT_MASK, 0, snd_emu10k1_ptr20_read(emu, EXTENDED_INT_MASK, 0) | (0x110000<<channel));
+
+ return 0;
+}
+
static void snd_p16v_intr_enable(emu10k1_t *emu, unsigned int intrenb)
{
unsigned long flags;
return result;
}
+/* trigger_capture callback */
+static int snd_p16v_pcm_trigger_capture(snd_pcm_substream_t *substream,
+ int cmd)
+{
+ emu10k1_t *emu = snd_pcm_substream_chip(substream);
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ emu10k1_pcm_t *epcm = runtime->private_data;
+ int channel = 0;
+ int result = 0;
+ u32 inte = INTE2_CAPTURE_CH_0_LOOP | INTE2_CAPTURE_CH_0_HALF_LOOP;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ snd_p16v_intr_enable(emu, inte);
+ snd_emu10k1_ptr20_write(emu, BASIC_INTERRUPT, 0, snd_emu10k1_ptr20_read(emu, BASIC_INTERRUPT, 0)|(0x100<<channel));
+ epcm->running = 1;
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ snd_emu10k1_ptr20_write(emu, BASIC_INTERRUPT, 0, snd_emu10k1_ptr20_read(emu, BASIC_INTERRUPT, 0) & ~(0x100<<channel));
+ snd_p16v_intr_disable(emu, inte);
+ //snd_emu10k1_ptr20_write(emu, EXTENDED_INT_MASK, 0, snd_emu10k1_ptr20_read(emu, EXTENDED_INT_MASK, 0) & ~(0x110000<<channel));
+ epcm->running = 0;
+ break;
+ default:
+ result = -EINVAL;
+ break;
+ }
+ return result;
+}
+
/* pointer_playback callback */
static snd_pcm_uframes_t
snd_p16v_pcm_pointer_playback(snd_pcm_substream_t *substream)
return ptr;
}
+/* pointer_capture callback */
+static snd_pcm_uframes_t
+snd_p16v_pcm_pointer_capture(snd_pcm_substream_t *substream)
+{
+ emu10k1_t *emu = snd_pcm_substream_chip(substream);
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ emu10k1_pcm_t *epcm = runtime->private_data;
+ snd_pcm_uframes_t ptr, ptr1, ptr2 = 0;
+ int channel = 0;
+
+ if (!epcm->running)
+ return 0;
+
+ ptr1 = snd_emu10k1_ptr20_read(emu, CAPTURE_POINTER, channel);
+ ptr2 = bytes_to_frames(runtime, ptr1);
+ ptr=ptr2;
+ if (ptr >= runtime->buffer_size) {
+ ptr -= runtime->buffer_size;
+ printk("buffer capture limited!\n");
+ }
+ //printk("ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n", ptr1, ptr2, ptr, (int)runtime->buffer_size, (int)runtime->period_size, (int)runtime->frame_bits, (int)runtime->rate);
+
+ return ptr;
+}
+
/* operators */
static snd_pcm_ops_t snd_p16v_playback_front_ops = {
.open = snd_p16v_pcm_open_playback_front,
.pointer = snd_p16v_pcm_pointer_playback,
};
+static snd_pcm_ops_t snd_p16v_capture_ops = {
+ .open = snd_p16v_pcm_open_capture,
+ .close = snd_p16v_pcm_close_capture,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_p16v_pcm_hw_params_capture,
+ .hw_free = snd_p16v_pcm_hw_free_capture,
+ .prepare = snd_p16v_pcm_prepare_capture,
+ .trigger = snd_p16v_pcm_trigger_capture,
+ .pointer = snd_p16v_pcm_pointer_capture,
+};
+
+
int snd_p16v_free(emu10k1_t *chip)
{
// release the data
snd_pcm_t *pcm;
snd_pcm_substream_t *substream;
int err;
- int capture=0;
+ int capture=1;
//snd_printk("snd_p16v_pcm called. device=%d\n", device);
emu->p16v_device_offset = device;
if (rpcm)
*rpcm = NULL;
- //if (device == 0) capture=1;
+
if ((err = snd_pcm_new(emu->card, "p16v", device, 1, capture, &pcm)) < 0)
return err;
pcm->private_data = emu;
pcm->private_free = snd_p16v_pcm_free;
-
+ // Single playback 8 channel device.
+ // Single capture 2 channel device.
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_p16v_playback_front_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_p16v_capture_ops);
pcm->info_flags = 0;
pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;
if ((err = snd_pcm_lib_preallocate_pages(substream,
SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(emu->pci),
- 64*1024, 64*1024)) < 0) /* FIXME: 32*1024 for sound buffer, between 32and64 for Periods table. */
+ ((65536 - 64) * 8), ((65536 - 64) * 8))) < 0)
return err;
//snd_printk("preallocate playback substream: err=%d\n", err);
}
if ((err = snd_pcm_lib_preallocate_pages(substream,
SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(emu->pci),
- 64*1024, 64*1024)) < 0)
+ 65536 - 64, 65536 - 64)) < 0)
return err;
//snd_printk("preallocate capture substream: err=%d\n", err);
}
.put = snd_p16v_volume_put_spdif_rear
};
+static int snd_p16v_capture_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+ static char *texts[8] = { "SPDIF", "I2S", "SRC48", "SRCMulti_SPDIF", "SRCMulti_I2S", "CDIF", "FX", "AC97" };
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 8;
+ if (uinfo->value.enumerated.item > 7)
+ uinfo->value.enumerated.item = 7;
+ strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+static int snd_p16v_capture_source_get(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_value_t * ucontrol)
+{
+ emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.enumerated.item[0] = emu->p16v_capture_source;
+ return 0;
+}
+
+static int snd_p16v_capture_source_put(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_value_t * ucontrol)
+{
+ emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
+ unsigned int val;
+ int change = 0;
+ u32 mask;
+ u32 source;
+
+ val = ucontrol->value.enumerated.item[0] ;
+ change = (emu->p16v_capture_source != val);
+ if (change) {
+ emu->p16v_capture_source = val;
+ source = (val << 28) | (val << 24) | (val << 20) | (val << 16);
+ mask = snd_emu10k1_ptr20_read(emu, BASIC_INTERRUPT, 0) & 0xffff;
+ snd_emu10k1_ptr20_write(emu, BASIC_INTERRUPT, 0, source | mask);
+ }
+ return change;
+}
+
+static snd_kcontrol_new_t snd_p16v_capture_source __devinitdata =
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "HD Capture source",
+ .info = snd_p16v_capture_source_info,
+ .get = snd_p16v_capture_source_get,
+ .put = snd_p16v_capture_source_put
+};
+
+static int snd_p16v_capture_channel_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+ static char *texts[4] = { "0", "1", "2", "3", };
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 4;
+ if (uinfo->value.enumerated.item > 3)
+ uinfo->value.enumerated.item = 3;
+ strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+static int snd_p16v_capture_channel_get(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_value_t * ucontrol)
+{
+ emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.enumerated.item[0] = emu->p16v_capture_channel;
+ return 0;
+}
+
+static int snd_p16v_capture_channel_put(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_value_t * ucontrol)
+{
+ emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
+ unsigned int val;
+ int change = 0;
+ u32 tmp;
+
+ val = ucontrol->value.enumerated.item[0] ;
+ change = (emu->p16v_capture_channel != val);
+ if (change) {
+ emu->p16v_capture_channel = val;
+ tmp = snd_emu10k1_ptr20_read(emu, CAPTURE_P16V_SOURCE, 0) & 0xfffc;
+ snd_emu10k1_ptr20_write(emu, CAPTURE_P16V_SOURCE, 0, tmp | val);
+ }
+ return change;
+}
+
+static snd_kcontrol_new_t snd_p16v_capture_channel __devinitdata =
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "HD Capture channel",
+ .info = snd_p16v_capture_channel_info,
+ .get = snd_p16v_capture_channel_get,
+ .put = snd_p16v_capture_channel_put
+};
+
int snd_p16v_mixer(emu10k1_t *emu)
{
int err;
return -ENOMEM;
if ((err = snd_ctl_add(card, kctl)))
return err;
+ if ((kctl = snd_ctl_new1(&snd_p16v_capture_source, emu)) == NULL)
+ return -ENOMEM;
+ if ((err = snd_ctl_add(card, kctl)))
+ return err;
+ if ((kctl = snd_ctl_new1(&snd_p16v_capture_channel, emu)) == NULL)
+ return -ENOMEM;
+ if ((err = snd_ctl_add(card, kctl)))
+ return err;
return 0;
}
static int __init alsa_card_ens137x_init(void)
{
- return pci_module_init(&driver);
+ return pci_register_driver(&driver);
}
static void __exit alsa_card_ens137x_exit(void)
static int __init alsa_card_es1938_init(void)
{
- return pci_module_init(&driver);
+ return pci_register_driver(&driver);
}
static void __exit alsa_card_es1938_exit(void)
{ TYPE_MAESTRO2E, 0x103c },
{ TYPE_MAESTRO2E, 0x1179 },
{ TYPE_MAESTRO2E, 0x14c0 }, /* HP omnibook 4150 */
+ { TYPE_MAESTRO2E, 0x1558 },
};
static struct ess_device_list mpu_blacklist[] __devinitdata = {
static int __init alsa_card_es1968_init(void)
{
- return pci_module_init(&driver);
+ return pci_register_driver(&driver);
}
static void __exit alsa_card_es1968_exit(void)
static struct pci_device_id snd_fm801_ids[] = {
{ 0x1319, 0x0801, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0, }, /* FM801 */
+ { 0x5213, 0x0510, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0, }, /* Gallant Odyssey Sound 4 */
{ 0, }
};
static int __init alsa_card_fm801_init(void)
{
- return pci_module_init(&driver);
+ return pci_register_driver(&driver);
}
static void __exit alsa_card_fm801_exit(void)
snd-hda-intel-objs := hda_intel.o
-snd-hda-codec-objs := hda_codec.o hda_generic.o patch_realtek.o patch_cmedia.o patch_analog.o
+snd-hda-codec-objs := hda_codec.o hda_generic.o patch_realtek.o patch_cmedia.o patch_analog.o patch_sigmatel.o
ifdef CONFIG_PROC_FS
snd-hda-codec-objs += hda_proc.o
endif
/* codec vendor labels */
static struct hda_vendor_id hda_vendor_ids[] = {
{ 0x10ec, "Realtek" },
+ { 0x11d4, "Analog Devices" },
{ 0x13f6, "C-Media" },
{ 0x434d, "C-Media" },
+ { 0x8384, "SigmaTel" },
{} /* terminator */
};
/* FIXME: support for multiple AFGs? */
codec->afg = look_for_afg_node(codec);
if (! codec->afg) {
- snd_printk(KERN_ERR "hda_codec: no AFG node found\n");
+ snd_printdd("hda_codec: no AFG node found\n");
snd_hda_codec_free(codec);
return -ENODEV;
}
void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, u32 stream_tag,
int channel_id, int format)
{
+ if (! nid)
+ return;
+
snd_printdd("hda_codec_setup_stream: NID=0x%x, stream=0x%x, channel=%d, format=0x%x\n",
nid, stream_tag, channel_id, format);
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID,
* amp access functions
*/
-#define HDA_HASH_KEY(nid,dir,idx) (u32)((nid) + (idx) * 32 + (dir) * 64)
+/* FIXME: more better hash key? */
+#define HDA_HASH_KEY(nid,dir,idx) (u32)((nid) + ((idx) << 16) + ((dir) << 24))
#define INFO_AMP_CAPS (1<<0)
-#define INFO_AMP_VOL (1<<1)
+#define INFO_AMP_VOL(ch) (1 << (1 + (ch)))
/* initialize the hash table */
static void init_amp_hash(struct hda_codec *codec)
/*
* read the current volume to info
- * if the cache exists, read from the cache.
+ * if the cache exists, read the cache value.
*/
-static void get_vol_mute(struct hda_codec *codec, struct hda_amp_info *info,
+static unsigned int get_vol_mute(struct hda_codec *codec, struct hda_amp_info *info,
hda_nid_t nid, int ch, int direction, int index)
{
u32 val, parm;
- if (info->status & (INFO_AMP_VOL << ch))
- return;
+ if (info->status & INFO_AMP_VOL(ch))
+ return info->vol[ch];
parm = ch ? AC_AMP_GET_RIGHT : AC_AMP_GET_LEFT;
parm |= direction == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT;
parm |= index;
val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, parm);
info->vol[ch] = val & 0xff;
- info->status |= INFO_AMP_VOL << ch;
+ info->status |= INFO_AMP_VOL(ch);
+ return info->vol[ch];
}
/*
- * write the current volume in info to the h/w
+ * write the current volume in info to the h/w and update the cache
*/
-static void put_vol_mute(struct hda_codec *codec,
+static void put_vol_mute(struct hda_codec *codec, struct hda_amp_info *info,
hda_nid_t nid, int ch, int direction, int index, int val)
{
u32 parm;
parm |= index << AC_AMP_SET_INDEX_SHIFT;
parm |= val;
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, parm);
+ info->vol[ch] = val;
}
/*
- * read/write AMP value. The volume is between 0 to 0x7f, 0x80 = mute bit.
+ * read AMP value. The volume is between 0 to 0x7f, 0x80 = mute bit.
*/
-int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int index)
+static int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int index)
{
struct hda_amp_info *info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, index));
if (! info)
return 0;
- get_vol_mute(codec, info, nid, ch, direction, index);
- return info->vol[ch];
+ return get_vol_mute(codec, info, nid, ch, direction, index);
}
-int snd_hda_codec_amp_write(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int idx, int val)
+/*
+ * update the AMP value, mask = bit mask to set, val = the value
+ */
+static int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int idx, int mask, int val)
{
struct hda_amp_info *info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, idx));
+
if (! info)
return 0;
- get_vol_mute(codec, info, nid, ch, direction, idx);
+ val &= mask;
+ val |= get_vol_mute(codec, info, nid, ch, direction, idx) & ~mask;
if (info->vol[ch] == val && ! codec->in_resume)
return 0;
- put_vol_mute(codec, nid, ch, direction, idx, val);
- info->vol[ch] = val;
+ put_vol_mute(codec, info, nid, ch, direction, idx, val);
return 1;
}
int chs = get_amp_channels(kcontrol);
int dir = get_amp_direction(kcontrol);
int idx = get_amp_index(kcontrol);
- int val;
long *valp = ucontrol->value.integer.value;
int change = 0;
- if (chs & 1) {
- val = *valp & 0x7f;
- val |= snd_hda_codec_amp_read(codec, nid, 0, dir, idx) & 0x80;
- change = snd_hda_codec_amp_write(codec, nid, 0, dir, idx, val);
- valp++;
- }
- if (chs & 2) {
- val = *valp & 0x7f;
- val |= snd_hda_codec_amp_read(codec, nid, 1, dir, idx) & 0x80;
- change |= snd_hda_codec_amp_write(codec, nid, 1, dir, idx, val);
- }
+ if (chs & 1)
+ change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx,
+ 0x7f, *valp);
+ if (chs & 2)
+ change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx,
+ 0x7f, valp[1]);
return change;
}
int chs = get_amp_channels(kcontrol);
int dir = get_amp_direction(kcontrol);
int idx = get_amp_index(kcontrol);
- int val;
long *valp = ucontrol->value.integer.value;
int change = 0;
- if (chs & 1) {
- val = snd_hda_codec_amp_read(codec, nid, 0, dir, idx) & 0x7f;
- val |= *valp ? 0 : 0x80;
- change = snd_hda_codec_amp_write(codec, nid, 0, dir, idx, val);
- valp++;
- }
- if (chs & 2) {
- val = snd_hda_codec_amp_read(codec, nid, 1, dir, idx) & 0x7f;
- val |= *valp ? 0 : 0x80;
- change = snd_hda_codec_amp_write(codec, nid, 1, dir, idx, val);
- }
+ if (chs & 1)
+ change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx,
+ 0x80, *valp ? 0 : 0x80);
+ if (chs & 2)
+ change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx,
+ 0x80, valp[1] ? 0 : 0x80);
return change;
}
snd_assert(info->nid, return -EINVAL);
info->ops.prepare = hda_pcm_default_prepare;
}
- if (info->ops.prepare == NULL) {
- snd_assert(info->nid, return -EINVAL);
- info->ops.prepare = hda_pcm_default_prepare;
- }
if (info->ops.cleanup == NULL) {
snd_assert(info->nid, return -EINVAL);
info->ops.cleanup = hda_pcm_default_cleanup;
*
* If no entries are matching, the function returns a negative value.
*/
-int snd_hda_check_board_config(struct hda_codec *codec, struct hda_board_config *tbl)
+int snd_hda_check_board_config(struct hda_codec *codec, const struct hda_board_config *tbl)
{
- struct hda_board_config *c;
+ const struct hda_board_config *c;
if (codec->bus->modelname) {
- for (c = tbl; c->modelname || c->pci_vendor; c++) {
+ for (c = tbl; c->modelname || c->pci_subvendor; c++) {
if (c->modelname &&
! strcmp(codec->bus->modelname, c->modelname)) {
snd_printd(KERN_INFO "hda_codec: model '%s' is selected\n", c->modelname);
u16 subsystem_vendor, subsystem_device;
pci_read_config_word(codec->bus->pci, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor);
pci_read_config_word(codec->bus->pci, PCI_SUBSYSTEM_ID, &subsystem_device);
- for (c = tbl; c->modelname || c->pci_vendor; c++) {
- if (c->pci_vendor == subsystem_vendor &&
- c->pci_device == subsystem_device)
+ for (c = tbl; c->modelname || c->pci_subvendor; c++) {
+ if (c->pci_subvendor == subsystem_vendor &&
+ (! c->pci_subdevice /* all match */||
+ (c->pci_subdevice == subsystem_device)))
return c->config;
}
}
snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag, 0, format);
/* surrounds */
for (i = 1; i < mout->num_dacs; i++) {
- if (i == HDA_REAR && chs == 2) /* copy front to rear */
- snd_hda_codec_setup_stream(codec, nids[i], stream_tag, 0, format);
- else if (chs >= (i + 1) * 2) /* independent out */
+ if (chs >= (i + 1) * 2) /* independent out */
snd_hda_codec_setup_stream(codec, nids[i], stream_tag, i * 2,
format);
+ else /* copy front */
+ snd_hda_codec_setup_stream(codec, nids[i], stream_tag, 0,
+ format);
}
return 0;
}
return 0;
}
+/*
+ * Helper for automatic ping configuration
+ */
+/* parse all pin widgets and store the useful pin nids to cfg */
+int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *cfg)
+{
+ hda_nid_t nid, nid_start;
+ int i, j, nodes;
+ short seq, sequences[4], assoc_line_out;
+
+ memset(cfg, 0, sizeof(*cfg));
+
+ memset(sequences, 0, sizeof(sequences));
+ assoc_line_out = 0;
+
+ nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid_start);
+ for (nid = nid_start; nid < nodes + nid_start; nid++) {
+ unsigned int wid_caps = snd_hda_param_read(codec, nid,
+ AC_PAR_AUDIO_WIDGET_CAP);
+ unsigned int wid_type = (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+ unsigned int def_conf;
+ short assoc, loc;
+
+ /* read all default configuration for pin complex */
+ if (wid_type != AC_WID_PIN)
+ continue;
+ def_conf = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
+ if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
+ continue;
+ loc = get_defcfg_location(def_conf);
+ switch (get_defcfg_device(def_conf)) {
+ case AC_JACK_LINE_OUT:
+ case AC_JACK_SPEAKER:
+ seq = get_defcfg_sequence(def_conf);
+ assoc = get_defcfg_association(def_conf);
+ if (! assoc)
+ continue;
+ if (! assoc_line_out)
+ assoc_line_out = assoc;
+ else if (assoc_line_out != assoc)
+ continue;
+ if (cfg->line_outs >= ARRAY_SIZE(cfg->line_out_pins))
+ continue;
+ cfg->line_out_pins[cfg->line_outs] = nid;
+ sequences[cfg->line_outs] = seq;
+ cfg->line_outs++;
+ break;
+ case AC_JACK_HP_OUT:
+ cfg->hp_pin = nid;
+ break;
+ case AC_JACK_MIC_IN:
+ if (loc == AC_JACK_LOC_FRONT)
+ cfg->input_pins[AUTO_PIN_FRONT_MIC] = nid;
+ else
+ cfg->input_pins[AUTO_PIN_MIC] = nid;
+ break;
+ case AC_JACK_LINE_IN:
+ if (loc == AC_JACK_LOC_FRONT)
+ cfg->input_pins[AUTO_PIN_FRONT_LINE] = nid;
+ else
+ cfg->input_pins[AUTO_PIN_LINE] = nid;
+ break;
+ case AC_JACK_CD:
+ cfg->input_pins[AUTO_PIN_CD] = nid;
+ break;
+ case AC_JACK_AUX:
+ cfg->input_pins[AUTO_PIN_AUX] = nid;
+ break;
+ case AC_JACK_SPDIF_OUT:
+ cfg->dig_out_pin = nid;
+ break;
+ case AC_JACK_SPDIF_IN:
+ cfg->dig_in_pin = nid;
+ break;
+ }
+ }
+
+ /* sort by sequence */
+ for (i = 0; i < cfg->line_outs; i++)
+ for (j = i + 1; j < cfg->line_outs; j++)
+ if (sequences[i] > sequences[j]) {
+ seq = sequences[i];
+ sequences[i] = sequences[j];
+ sequences[j] = seq;
+ nid = cfg->line_out_pins[i];
+ cfg->line_out_pins[i] = cfg->line_out_pins[j];
+ cfg->line_out_pins[j] = nid;
+ }
+
+ /* Swap surround and CLFE: the association order is front/CLFE/surr/back */
+ if (cfg->line_outs >= 3) {
+ nid = cfg->line_out_pins[1];
+ cfg->line_out_pins[1] = cfg->line_out_pins[2];
+ cfg->line_out_pins[2] = nid;
+ }
+
+ return 0;
+}
+
#ifdef CONFIG_PM
/*
* power management
#define AC_VERB_GET_DIGI_CONVERT 0x0f0d
#define AC_VERB_GET_VOLUME_KNOB_CONTROL 0x0f0f
/* f10-f1a: GPIO */
+#define AC_VERB_GET_GPIO_DATA 0x0f15
+#define AC_VERB_GET_GPIO_MASK 0x0f16
+#define AC_VERB_GET_GPIO_DIRECTION 0x0f17
#define AC_VERB_GET_CONFIG_DEFAULT 0x0f1c
/*
#define AC_VERB_SET_DIGI_CONVERT_1 0x70d
#define AC_VERB_SET_DIGI_CONVERT_2 0x70e
#define AC_VERB_SET_VOLUME_KNOB_CONTROL 0x70f
+#define AC_VERB_SET_GPIO_DATA 0x715
+#define AC_VERB_SET_GPIO_MASK 0x716
+#define AC_VERB_SET_GPIO_DIRECTION 0x717
#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 0x71c
#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_1 0x71d
#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_2 0x71e
#define AC_PINCAP_OUT (1<<4) /* output capable */
#define AC_PINCAP_IN (1<<5) /* input capable */
#define AC_PINCAP_BALANCE (1<<6) /* balanced I/O capable */
-#define AC_PINCAP_VREF (7<<8)
+#define AC_PINCAP_VREF (0x37<<8)
#define AC_PINCAP_VREF_SHIFT 8
#define AC_PINCAP_EAPD (1<<16) /* EAPD capable */
-/* Vref status (used in pin cap and pin ctl) */
-#define AC_PIN_VREF_HIZ (1<<0) /* Hi-Z */
-#define AC_PIN_VREF_50 (1<<1) /* 50% */
-#define AC_PIN_VREF_GRD (1<<2) /* ground */
-#define AC_PIN_VREF_80 (1<<4) /* 80% */
-#define AC_PIN_VREF_100 (1<<5) /* 100% */
-
+/* Vref status (used in pin cap) */
+#define AC_PINCAP_VREF_HIZ (1<<0) /* Hi-Z */
+#define AC_PINCAP_VREF_50 (1<<1) /* 50% */
+#define AC_PINCAP_VREF_GRD (1<<2) /* ground */
+#define AC_PINCAP_VREF_80 (1<<4) /* 80% */
+#define AC_PINCAP_VREF_100 (1<<5) /* 100% */
/* Amplifier capabilities */
#define AC_AMPCAP_OFFSET (0x7f<<0) /* 0dB offset */
/* Pin widget control - 8bit */
#define AC_PINCTL_VREFEN (0x7<<0)
+#define AC_PINCTL_VREF_HIZ 0 /* Hi-Z */
+#define AC_PINCTL_VREF_50 1 /* 50% */
+#define AC_PINCTL_VREF_GRD 2 /* ground */
+#define AC_PINCTL_VREF_80 4 /* 80% */
+#define AC_PINCTL_VREF_100 5 /* 100% */
#define AC_PINCTL_IN_EN (1<<5)
#define AC_PINCTL_OUT_EN (1<<6)
#define AC_PINCTL_HP_EN (1<<7)
/* configuration default - 32bit */
#define AC_DEFCFG_SEQUENCE (0xf<<0)
#define AC_DEFCFG_DEF_ASSOC (0xf<<4)
+#define AC_DEFCFG_ASSOC_SHIFT 4
#define AC_DEFCFG_MISC (0xf<<8)
+#define AC_DEFCFG_MISC_SHIFT 8
#define AC_DEFCFG_COLOR (0xf<<12)
#define AC_DEFCFG_COLOR_SHIFT 12
#define AC_DEFCFG_CONN_TYPE (0xf<<16)
/* codec linked list */
struct list_head codec_list;
- struct hda_codec *caddr_tbl[HDA_MAX_CODEC_ADDRESS]; /* caddr -> codec */
+ struct hda_codec *caddr_tbl[HDA_MAX_CODEC_ADDRESS + 1]; /* caddr -> codec */
struct semaphore cmd_mutex;
struct list_head list;
};
-/* pathc-specific record */
+/* patch-specific record */
struct hda_gspec {
struct hda_gnode *dac_node; /* DAC node */
struct hda_gnode *out_pin_node; /* Output pin (Line-Out) node */
/*
* retrieve the default device type from the default config value
*/
-#define get_defcfg_type(node) (((node)->def_cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT)
-#define get_defcfg_location(node) (((node)->def_cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT)
+#define defcfg_type(node) (((node)->def_cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT)
+#define defcfg_location(node) (((node)->def_cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT)
/*
* destructor
if (! (node->pin_caps & AC_PINCAP_OUT))
continue;
if (jack_type >= 0) {
- if (jack_type != get_defcfg_type(node))
+ if (jack_type != defcfg_type(node))
continue;
if (node->wid_caps & AC_WCAP_DIGITAL)
continue; /* skip SPDIF */
*/
static const char *get_input_type(struct hda_gnode *node, unsigned int *pinctl)
{
- unsigned int location = get_defcfg_location(node);
- switch (get_defcfg_type(node)) {
+ unsigned int location = defcfg_location(node);
+ switch (defcfg_type(node)) {
case AC_JACK_LINE_IN:
if ((location & 0x0f) == AC_JACK_LOC_FRONT)
return "Front Line";
return "Line";
case AC_JACK_CD:
if (pinctl)
- *pinctl |= AC_PIN_VREF_GRD;
+ *pinctl |= AC_PINCTL_VREF_GRD;
return "CD";
case AC_JACK_AUX:
if ((location & 0x0f) == AC_JACK_LOC_FRONT)
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
static char *model[SNDRV_CARDS];
+static int position_fix[SNDRV_CARDS];
module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for Intel HD audio interface.");
MODULE_PARM_DESC(enable, "Enable Intel HD audio interface.");
module_param_array(model, charp, NULL, 0444);
MODULE_PARM_DESC(model, "Use the given board model.");
+module_param_array(position_fix, int, NULL, 0444);
+MODULE_PARM_DESC(position_fix, "Fix DMA pointer (0 = FIFO size, 1 = none, 2 = POSBUF).");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
"{Intel, ICH6M},"
"{Intel, ICH7},"
- "{Intel, ESB2}}");
+ "{Intel, ESB2},"
+ "{ATI, SB450},"
+ "{VIA, VT8251},"
+ "{VIA, VT8237A}}");
MODULE_DESCRIPTION("Intel HDA driver");
#define SFX "hda-intel: "
/* STATESTS int mask: SD2,SD1,SD0 */
#define STATESTS_INT_MASK 0x07
-#define AZX_MAX_CODECS 3
+#define AZX_MAX_CODECS 4
/* SD_CTL bits */
#define SD_CTL_STREAM_RESET 0x01 /* stream reset bit */
#define ICH6_MAX_CORB_ENTRIES 256
#define ICH6_MAX_RIRB_ENTRIES 256
+/* position fix mode */
+enum {
+ POS_FIX_FIFO,
+ POS_FIX_NONE,
+ POS_FIX_POSBUF
+};
+
+/* Defines for ATI HD Audio support in SB450 south bridge */
+#define ATI_SB450_HDAUDIO_PCI_DEVICE_ID 0x437b
+#define ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR 0x42
+#define ATI_SB450_HDAUDIO_ENABLE_SNOOP 0x02
+
/*
* Use CORB/RIRB for communication from/to codecs.
*/
#define USE_CORB_RIRB
-/*
- * Define this if use the position buffer instead of reading SD_LPIB
- * It's not used as default since SD_LPIB seems to give more accurate position
- */
-/* #define USE_POSBUF */
-
/*
*/
struct snd_dma_buffer bdl;
struct snd_dma_buffer rb;
struct snd_dma_buffer posbuf;
+
+ /* flags */
+ int position_fix;
+ unsigned int initialized: 1;
};
/*
*/
static void azx_init_chip(azx_t *chip)
{
- unsigned char tcsel_reg;
+ unsigned char tcsel_reg, ati_misc_cntl2;
/* Clear bits 0-2 of PCI register TCSEL (at offset 0x44)
* TCSEL == Traffic Class Select Register, which sets PCI express QOS
/* initialize the codec command I/O */
azx_init_cmd_io(chip);
-#ifdef USE_POSBUF
- /* program the position buffer */
- azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr);
- azx_writel(chip, DPUBASE, upper_32bit(chip->posbuf.addr));
-#endif
+ if (chip->position_fix == POS_FIX_POSBUF) {
+ /* program the position buffer */
+ azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr);
+ azx_writel(chip, DPUBASE, upper_32bit(chip->posbuf.addr));
+ }
+
+ /* For ATI SB450 azalia HD audio, we need to enable snoop */
+ if (chip->pci->vendor == PCI_VENDOR_ID_ATI &&
+ chip->pci->device == ATI_SB450_HDAUDIO_PCI_DEVICE_ID) {
+ pci_read_config_byte(chip->pci, ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR,
+ &ati_misc_cntl2);
+ pci_write_config_byte(chip->pci, ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR,
+ (ati_misc_cntl2 & 0xf8) | ATI_SB450_HDAUDIO_ENABLE_SNOOP);
+ }
}
/* upper BDL address */
azx_sd_writel(azx_dev, SD_BDLPU, upper_32bit(azx_dev->bdl_addr));
-#ifdef USE_POSBUF
- /* enable the position buffer */
- if (! (azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE))
- azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE);
-#endif
+ if (chip->position_fix == POS_FIX_POSBUF) {
+ /* enable the position buffer */
+ if (! (azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE))
+ azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE);
+ }
+
/* set the interrupt enable bits in the descriptor control register */
azx_sd_writel(azx_dev, SD_CTL, azx_sd_readl(azx_dev, SD_CTL) | SD_INT_MASK);
static snd_pcm_uframes_t azx_pcm_pointer(snd_pcm_substream_t *substream)
{
+ struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
+ azx_t *chip = apcm->chip;
azx_dev_t *azx_dev = get_azx_dev(substream);
unsigned int pos;
-#ifdef USE_POSBUF
- /* use the position buffer */
- pos = *azx_dev->posbuf;
-#else
- /* read LPIB */
- pos = azx_sd_readl(azx_dev, SD_LPIB) + azx_dev->fifo_size;
-#endif
+ if (chip->position_fix == POS_FIX_POSBUF) {
+ /* use the position buffer */
+ pos = *azx_dev->posbuf;
+ } else {
+ /* read LPIB */
+ pos = azx_sd_readl(azx_dev, SD_LPIB);
+ if (chip->position_fix == POS_FIX_FIFO)
+ pos += azx_dev->fifo_size;
+ }
if (pos >= azx_dev->bufsize)
pos = 0;
return bytes_to_frames(substream->runtime, pos);
azx_dev_t *azx_dev = &chip->azx_dev[i];
azx_dev->bdl = (u32 *)(chip->bdl.area + off);
azx_dev->bdl_addr = chip->bdl.addr + off;
-#ifdef USE_POSBUF
- azx_dev->posbuf = (volatile u32 *)(chip->posbuf.area + i * 8);
-#endif
+ if (chip->position_fix == POS_FIX_POSBUF)
+ azx_dev->posbuf = (volatile u32 *)(chip->posbuf.area + i * 8);
/* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */
azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80);
/* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */
*/
static int azx_free(azx_t *chip)
{
- if (chip->remap_addr) {
+ if (chip->initialized) {
int i;
for (i = 0; i < MAX_ICH6_DEV; i++)
snd_dma_free_pages(&chip->bdl);
if (chip->rb.area)
snd_dma_free_pages(&chip->rb);
-#ifdef USE_POSBUF
if (chip->posbuf.area)
snd_dma_free_pages(&chip->posbuf);
-#endif
pci_release_regions(chip->pci);
pci_disable_device(chip->pci);
kfree(chip);
/*
* constructor
*/
-static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci, azx_t **rchip)
+static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci,
+ int posfix, azx_t **rchip)
{
azx_t *chip;
int err = 0;
chip->pci = pci;
chip->irq = -1;
+ chip->position_fix = posfix;
+
if ((err = pci_request_regions(pci, "ICH HD audio")) < 0) {
kfree(chip);
pci_disable_device(pci);
snd_printk(KERN_ERR SFX "cannot allocate BDL\n");
goto errout;
}
-#ifdef USE_POSBUF
- /* allocate memory for the position buffer */
- if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),
- MAX_ICH6_DEV * 8, &chip->posbuf)) < 0) {
- snd_printk(KERN_ERR SFX "cannot allocate posbuf\n");
- goto errout;
+ if (chip->position_fix == POS_FIX_POSBUF) {
+ /* allocate memory for the position buffer */
+ if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),
+ MAX_ICH6_DEV * 8, &chip->posbuf)) < 0) {
+ snd_printk(KERN_ERR SFX "cannot allocate posbuf\n");
+ goto errout;
+ }
}
-#endif
/* allocate CORB/RIRB */
if ((err = azx_alloc_cmd_io(chip)) < 0)
goto errout;
/* initialize chip */
azx_init_chip(chip);
+ chip->initialized = 1;
+
/* codec detection */
if (! chip->codec_mask) {
snd_printk(KERN_ERR SFX "no codecs found!\n");
return -ENOMEM;
}
- if ((err = azx_create(card, pci, &chip)) < 0) {
+ if ((err = azx_create(card, pci, position_fix[dev], &chip)) < 0) {
snd_card_free(card);
return err;
}
{ 0x8086, 0x2668, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ICH6 */
{ 0x8086, 0x27d8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ICH7 */
{ 0x8086, 0x269a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ESB2 */
+ { 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ATI SB450 */
+ { 0x1106, 0x3288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* VIA VT8251/VT8237A */
+ { 0x10b9, 0x5461, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ALI 5461? */
{ 0, }
};
MODULE_DEVICE_TABLE(pci, azx_ids);
static int __init alsa_card_azx_init(void)
{
- return pci_module_init(&driver);
+ return pci_register_driver(&driver);
}
static void __exit alsa_card_azx_exit(void)
struct hda_board_config {
const char *modelname;
int config;
- unsigned short pci_vendor;
- unsigned short pci_device;
+ unsigned short pci_subvendor;
+ unsigned short pci_subdevice;
};
-int snd_hda_check_board_config(struct hda_codec *codec, struct hda_board_config *tbl);
+int snd_hda_check_board_config(struct hda_codec *codec, const struct hda_board_config *tbl);
int snd_hda_add_new_ctls(struct hda_codec *codec, snd_kcontrol_new_t *knew);
/*
struct work_struct work;
};
+/*
+ * Helper for automatic ping configuration
+ */
+
+enum {
+ AUTO_PIN_MIC,
+ AUTO_PIN_FRONT_MIC,
+ AUTO_PIN_LINE,
+ AUTO_PIN_FRONT_LINE,
+ AUTO_PIN_CD,
+ AUTO_PIN_AUX,
+ AUTO_PIN_LAST
+};
+
+struct auto_pin_cfg {
+ int line_outs;
+ hda_nid_t line_out_pins[4]; /* sorted in the order of Front/Surr/CLFE/Side */
+ hda_nid_t hp_pin;
+ hda_nid_t input_pins[AUTO_PIN_LAST];
+ hda_nid_t dig_out_pin;
+ hda_nid_t dig_in_pin;
+};
+
+#define get_defcfg_connect(cfg) ((cfg & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT)
+#define get_defcfg_association(cfg) ((cfg & AC_DEFCFG_DEF_ASSOC) >> AC_DEFCFG_ASSOC_SHIFT)
+#define get_defcfg_location(cfg) ((cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT)
+#define get_defcfg_sequence(cfg) (cfg & AC_DEFCFG_SEQUENCE)
+#define get_defcfg_device(cfg) ((cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT)
+
+int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *cfg);
+
#endif /* __SOUND_HDA_LOCAL_H */
extern struct hda_codec_preset snd_hda_preset_cmedia[];
/* Analog Devices codecs */
extern struct hda_codec_preset snd_hda_preset_analog[];
+/* SigmaTel codecs */
+extern struct hda_codec_preset snd_hda_preset_sigmatel[];
static const struct hda_codec_preset *hda_preset_tables[] = {
snd_hda_preset_realtek,
snd_hda_preset_cmedia,
snd_hda_preset_analog,
+ snd_hda_preset_sigmatel,
NULL
};
static void print_amp_vals(snd_info_buffer_t *buffer,
struct hda_codec *codec, hda_nid_t nid,
- int dir, int stereo)
+ int dir, int stereo, int indices)
{
unsigned int val;
- if (stereo) {
+ int i;
+
+ if (dir == HDA_OUTPUT)
+ dir = AC_AMP_GET_OUTPUT;
+ else
+ dir = AC_AMP_GET_INPUT;
+ for (i = 0; i < indices; i++) {
+ snd_iprintf(buffer, " [");
+ if (stereo) {
+ val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE,
+ AC_AMP_GET_LEFT | dir | i);
+ snd_iprintf(buffer, "0x%02x ", val);
+ }
val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE,
- AC_AMP_GET_LEFT |
- (dir == HDA_OUTPUT ? AC_AMP_GET_OUTPUT :
- AC_AMP_GET_INPUT));
- snd_iprintf(buffer, "0x%02x ", val);
+ AC_AMP_GET_RIGHT | dir | i);
+ snd_iprintf(buffer, "0x%02x]", val);
}
- val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE,
- AC_AMP_GET_RIGHT |
- (dir == HDA_OUTPUT ? AC_AMP_GET_OUTPUT :
- AC_AMP_GET_INPUT));
- snd_iprintf(buffer, "0x%02x\n", val);
+ snd_iprintf(buffer, "\n");
}
static void print_pcm_caps(snd_info_buffer_t *buffer,
static void print_pin_caps(snd_info_buffer_t *buffer,
struct hda_codec *codec, hda_nid_t nid)
{
+ static char *jack_conns[4] = { "Jack", "N/A", "Fixed", "Both" };
static char *jack_types[16] = {
"Line Out", "Speaker", "HP Out", "CD",
"SPDIF Out", "Digital Out", "Modem Line", "Modem Hand",
snd_iprintf(buffer, " HP");
snd_iprintf(buffer, "\n");
caps = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
- snd_iprintf(buffer, " Pin Default 0x%08x: %s at %s %s\n", caps,
+ snd_iprintf(buffer, " Pin Default 0x%08x: [%s] %s at %s %s\n", caps,
+ jack_conns[(caps & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT],
jack_types[(caps & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT],
jack_locations[(caps >> (AC_DEFCFG_LOCATION_SHIFT + 4)) & 3],
get_jack_location(caps));
unsigned int wid_caps = snd_hda_param_read(codec, nid,
AC_PAR_AUDIO_WIDGET_CAP);
unsigned int wid_type = (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+ int conn_len = 0;
+ hda_nid_t conn[HDA_MAX_CONNECTIONS];
+
snd_iprintf(buffer, "Node 0x%02x [%s] wcaps 0x%x:", nid,
get_wid_type_name(wid_type), wid_caps);
if (wid_caps & AC_WCAP_STEREO)
snd_iprintf(buffer, " Amp-Out");
snd_iprintf(buffer, "\n");
+ if (wid_caps & AC_WCAP_CONN_LIST)
+ conn_len = snd_hda_get_connections(codec, nid, conn,
+ HDA_MAX_CONNECTIONS);
+
if (wid_caps & AC_WCAP_IN_AMP) {
snd_iprintf(buffer, " Amp-In caps: ");
print_amp_caps(buffer, codec, nid, HDA_INPUT);
snd_iprintf(buffer, " Amp-In vals: ");
print_amp_vals(buffer, codec, nid, HDA_INPUT,
- wid_caps & AC_WCAP_STEREO);
+ wid_caps & AC_WCAP_STEREO, conn_len);
}
if (wid_caps & AC_WCAP_OUT_AMP) {
snd_iprintf(buffer, " Amp-Out caps: ");
print_amp_caps(buffer, codec, nid, HDA_OUTPUT);
snd_iprintf(buffer, " Amp-Out vals: ");
print_amp_vals(buffer, codec, nid, HDA_OUTPUT,
- wid_caps & AC_WCAP_STEREO);
+ wid_caps & AC_WCAP_STEREO, 1);
}
if (wid_type == AC_WID_PIN) {
}
if (wid_caps & AC_WCAP_CONN_LIST) {
- hda_nid_t conn[HDA_MAX_CONNECTIONS];
- int c, conn_len;
- conn_len = snd_hda_get_connections(codec, nid, conn,
- HDA_MAX_CONNECTIONS);
+ int c, curr = -1;
+ if (conn_len > 1 && wid_type != AC_WID_AUD_MIX)
+ curr = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_CONNECT_SEL, 0);
snd_iprintf(buffer, " Connection: %d\n", conn_len);
snd_iprintf(buffer, " ");
- for (c = 0; c < conn_len; c++)
+ for (c = 0; c < conn_len; c++) {
snd_iprintf(buffer, " 0x%02x", conn[c]);
+ if (c == curr)
+ snd_iprintf(buffer, "*");
+ }
snd_iprintf(buffer, "\n");
}
}
/*
- * HD audio interface patch for AD1986A
+ * HD audio interface patch for AD1981HD, AD1983, AD1986A
*
* Copyright (c) 2005 Takashi Iwai <tiwai@suse.de>
*
#include "hda_codec.h"
#include "hda_local.h"
-struct ad1986a_spec {
+struct ad198x_spec {
struct semaphore amp_mutex; /* PCM volume/mute control mutex */
struct hda_multi_out multiout; /* playback */
+ hda_nid_t adc_nid;
+ const struct hda_input_mux *input_mux;
unsigned int cur_mux; /* capture source */
+ unsigned int spdif_route;
+ snd_kcontrol_new_t *mixers;
+ const struct hda_verb *init_verbs;
struct hda_pcm pcm_rec[2]; /* PCM information */
};
+/*
+ * input MUX handling (common part)
+ */
+static int ad198x_mux_enum_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct ad198x_spec *spec = codec->spec;
+
+ return snd_hda_input_mux_info(spec->input_mux, uinfo);
+}
+
+static int ad198x_mux_enum_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct ad198x_spec *spec = codec->spec;
+
+ ucontrol->value.enumerated.item[0] = spec->cur_mux;
+ return 0;
+}
+
+static int ad198x_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct ad198x_spec *spec = codec->spec;
+
+ return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
+ spec->adc_nid, &spec->cur_mux);
+}
+
+/*
+ * initialization (common callbacks)
+ */
+static int ad198x_init(struct hda_codec *codec)
+{
+ struct ad198x_spec *spec = codec->spec;
+ snd_hda_sequence_write(codec, spec->init_verbs);
+ return 0;
+}
+
+static int ad198x_build_controls(struct hda_codec *codec)
+{
+ struct ad198x_spec *spec = codec->spec;
+ int err;
+
+ err = snd_hda_add_new_ctls(codec, spec->mixers);
+ 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;
+ return 0;
+}
+
+/*
+ * Analog playback callbacks
+ */
+static int ad198x_playback_pcm_open(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ snd_pcm_substream_t *substream)
+{
+ struct ad198x_spec *spec = codec->spec;
+ return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
+}
+
+static int ad198x_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 ad198x_spec *spec = codec->spec;
+ return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag,
+ format, substream);
+}
+
+static int ad198x_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ snd_pcm_substream_t *substream)
+{
+ struct ad198x_spec *spec = codec->spec;
+ return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
+}
+
+/*
+ * Digital out
+ */
+static int ad198x_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ snd_pcm_substream_t *substream)
+{
+ struct ad198x_spec *spec = codec->spec;
+ return snd_hda_multi_out_dig_open(codec, &spec->multiout);
+}
+
+static int ad198x_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ snd_pcm_substream_t *substream)
+{
+ struct ad198x_spec *spec = codec->spec;
+ return snd_hda_multi_out_dig_close(codec, &spec->multiout);
+}
+
+/*
+ * Analog capture
+ */
+static int ad198x_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 ad198x_spec *spec = codec->spec;
+ snd_hda_codec_setup_stream(codec, spec->adc_nid, stream_tag, 0, format);
+ return 0;
+}
+
+static int ad198x_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ snd_pcm_substream_t *substream)
+{
+ struct ad198x_spec *spec = codec->spec;
+ snd_hda_codec_setup_stream(codec, spec->adc_nid, 0, 0, 0);
+ return 0;
+}
+
+
+/*
+ */
+static struct hda_pcm_stream ad198x_pcm_analog_playback = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 6,
+ .nid = 0, /* fill later */
+ .ops = {
+ .open = ad198x_playback_pcm_open,
+ .prepare = ad198x_playback_pcm_prepare,
+ .cleanup = ad198x_playback_pcm_cleanup
+ },
+};
+
+static struct hda_pcm_stream ad198x_pcm_analog_capture = {
+ .substreams = 2,
+ .channels_min = 2,
+ .channels_max = 2,
+ .nid = 0, /* fill later */
+ .ops = {
+ .prepare = ad198x_capture_pcm_prepare,
+ .cleanup = ad198x_capture_pcm_cleanup
+ },
+};
+
+static struct hda_pcm_stream ad198x_pcm_digital_playback = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 2,
+ .nid = 0, /* fill later */
+ .ops = {
+ .open = ad198x_dig_playback_pcm_open,
+ .close = ad198x_dig_playback_pcm_close
+ },
+};
+
+static int ad198x_build_pcms(struct hda_codec *codec)
+{
+ struct ad198x_spec *spec = codec->spec;
+ struct hda_pcm *info = spec->pcm_rec;
+
+ codec->num_pcms = 1;
+ codec->pcm_info = info;
+
+ info->name = "AD198x Analog";
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_analog_playback;
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->multiout.max_channels;
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
+ info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_analog_capture;
+ info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nid;
+
+ if (spec->multiout.dig_out_nid) {
+ info++;
+ codec->num_pcms++;
+ info->name = "AD198x Digital";
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_digital_playback;
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
+ }
+
+ return 0;
+}
+
+static void ad198x_free(struct hda_codec *codec)
+{
+ kfree(codec->spec);
+}
+
+#ifdef CONFIG_PM
+static int ad198x_resume(struct hda_codec *codec)
+{
+ struct ad198x_spec *spec = codec->spec;
+
+ ad198x_init(codec);
+ snd_hda_resume_ctls(codec, spec->mixers);
+ snd_hda_resume_spdif_out(codec);
+ return 0;
+}
+#endif
+
+static struct hda_codec_ops ad198x_patch_ops = {
+ .build_controls = ad198x_build_controls,
+ .build_pcms = ad198x_build_pcms,
+ .init = ad198x_init,
+ .free = ad198x_free,
+#ifdef CONFIG_PM
+ .resume = ad198x_resume,
+#endif
+};
+
+
+/*
+ * AD1986A specific
+ */
+
#define AD1986A_SPDIF_OUT 0x02
#define AD1986A_FRONT_DAC 0x03
#define AD1986A_SURR_DAC 0x04
static int ad1986a_pcm_amp_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct ad1986a_spec *ad = codec->spec;
+ struct ad198x_spec *ad = codec->spec;
down(&ad->amp_mutex);
snd_hda_mixer_amp_volume_get(kcontrol, ucontrol);
static int ad1986a_pcm_amp_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct ad1986a_spec *ad = codec->spec;
+ struct ad198x_spec *ad = codec->spec;
int i, change = 0;
down(&ad->amp_mutex);
return change;
}
-#define ad1986a_pcm_amp_sw_info snd_hda_mixer_amp_volume_info
+#define ad1986a_pcm_amp_sw_info snd_hda_mixer_amp_switch_info
static int ad1986a_pcm_amp_sw_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct ad1986a_spec *ad = codec->spec;
+ struct ad198x_spec *ad = codec->spec;
down(&ad->amp_mutex);
snd_hda_mixer_amp_switch_get(kcontrol, ucontrol);
static int ad1986a_pcm_amp_sw_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct ad1986a_spec *ad = codec->spec;
+ struct ad198x_spec *ad = codec->spec;
int i, change = 0;
down(&ad->amp_mutex);
return change;
}
-/*
- * input MUX handling
- */
-static int ad1986a_mux_enum_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
-{
- return snd_hda_input_mux_info(&ad1986a_capture_source, uinfo);
-}
-
-static int ad1986a_mux_enum_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct ad1986a_spec *spec = codec->spec;
-
- ucontrol->value.enumerated.item[0] = spec->cur_mux;
- return 0;
-}
-
-static int ad1986a_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct ad1986a_spec *spec = codec->spec;
-
- return snd_hda_input_mux_put(codec, &ad1986a_capture_source, ucontrol,
- AD1986A_ADC, &spec->cur_mux);
-}
-
/*
* mixers
*/
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Capture Source",
- .info = ad1986a_mux_enum_info,
- .get = ad1986a_mux_enum_get,
- .put = ad1986a_mux_enum_put,
+ .info = ad198x_mux_enum_info,
+ .get = ad198x_mux_enum_get,
+ .put = ad198x_mux_enum_put,
},
HDA_CODEC_MUTE("Stereo Downmix Switch", 0x09, 0x0, HDA_OUTPUT),
{ } /* end */
{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
{0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
{0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+ /* HP Pin */
+ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
+ /* Front, Surround, CLFE Pins */
+ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+ {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+ {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+ /* Mono Pin */
+ {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+ /* Mic Pin */
+ {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+ /* Line, Aux, CD, Beep-In Pin */
+ {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
+ {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
+ {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
+ {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
+ {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
{ } /* end */
};
-static int ad1986a_init(struct hda_codec *codec)
+static int patch_ad1986a(struct hda_codec *codec)
{
- snd_hda_sequence_write(codec, ad1986a_init_verbs);
- return 0;
-}
+ struct ad198x_spec *spec;
-static int ad1986a_build_controls(struct hda_codec *codec)
-{
- int err;
+ spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+ if (spec == NULL)
+ return -ENOMEM;
+
+ init_MUTEX(&spec->amp_mutex);
+ codec->spec = spec;
+
+ spec->multiout.max_channels = 6;
+ spec->multiout.num_dacs = ARRAY_SIZE(ad1986a_dac_nids);
+ spec->multiout.dac_nids = ad1986a_dac_nids;
+ spec->multiout.dig_out_nid = AD1986A_SPDIF_OUT;
+ spec->adc_nid = AD1986A_ADC;
+ spec->input_mux = &ad1986a_capture_source;
+ spec->mixers = ad1986a_mixers;
+ spec->init_verbs = ad1986a_init_verbs;
+
+ codec->patch_ops = ad198x_patch_ops;
- err = snd_hda_add_new_ctls(codec, ad1986a_mixers);
- if (err < 0)
- return err;
- err = snd_hda_create_spdif_out_ctls(codec, AD1986A_SPDIF_OUT);
- if (err < 0)
- return err;
return 0;
}
/*
- * Analog playback callbacks
+ * AD1983 specific
*/
-static int ad1986a_playback_pcm_open(struct hda_pcm_stream *hinfo,
- struct hda_codec *codec,
- snd_pcm_substream_t *substream)
-{
- struct ad1986a_spec *spec = codec->spec;
- return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
-}
-static int ad1986a_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 ad1986a_spec *spec = codec->spec;
- return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag,
- format, substream);
-}
+#define AD1983_SPDIF_OUT 0x02
+#define AD1983_DAC 0x03
+#define AD1983_ADC 0x04
-static int ad1986a_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
- struct hda_codec *codec,
- snd_pcm_substream_t *substream)
-{
- struct ad1986a_spec *spec = codec->spec;
- return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
-}
+static hda_nid_t ad1983_dac_nids[1] = { AD1983_DAC };
+
+static struct hda_input_mux ad1983_capture_source = {
+ .num_items = 4,
+ .items = {
+ { "Mic", 0x0 },
+ { "Line", 0x1 },
+ { "Mix", 0x2 },
+ { "Mix Mono", 0x3 },
+ },
+};
/*
- * Digital out
+ * SPDIF playback route
*/
-static int ad1986a_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
- struct hda_codec *codec,
- snd_pcm_substream_t *substream)
+static int ad1983_spdif_route_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
{
- struct ad1986a_spec *spec = codec->spec;
- return snd_hda_multi_out_dig_open(codec, &spec->multiout);
+ static char *texts[] = { "PCM", "ADC" };
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 2;
+ if (uinfo->value.enumerated.item > 1)
+ uinfo->value.enumerated.item = 1;
+ strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+ return 0;
}
-static int ad1986a_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
- struct hda_codec *codec,
- snd_pcm_substream_t *substream)
+static int ad1983_spdif_route_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
{
- struct ad1986a_spec *spec = codec->spec;
- return snd_hda_multi_out_dig_close(codec, &spec->multiout);
-}
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct ad198x_spec *spec = codec->spec;
-/*
- * Analog capture
- */
-static int ad1986a_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
- struct hda_codec *codec,
- unsigned int stream_tag,
- unsigned int format,
- snd_pcm_substream_t *substream)
-{
- snd_hda_codec_setup_stream(codec, AD1986A_ADC, stream_tag, 0, format);
+ ucontrol->value.enumerated.item[0] = spec->spdif_route;
return 0;
}
-static int ad1986a_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
- struct hda_codec *codec,
- snd_pcm_substream_t *substream)
+static int ad1983_spdif_route_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
{
- snd_hda_codec_setup_stream(codec, AD1986A_ADC, 0, 0, 0);
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct ad198x_spec *spec = codec->spec;
+
+ if (spec->spdif_route != ucontrol->value.enumerated.item[0]) {
+ spec->spdif_route = ucontrol->value.enumerated.item[0];
+ snd_hda_codec_write(codec, spec->multiout.dig_out_nid, 0,
+ AC_VERB_SET_CONNECT_SEL, spec->spdif_route);
+ return 1;
+ }
return 0;
}
-
-/*
- */
-static struct hda_pcm_stream ad1986a_pcm_analog_playback = {
- .substreams = 1,
- .channels_min = 2,
- .channels_max = 6,
- .nid = AD1986A_FRONT_DAC, /* NID to query formats and rates */
- .ops = {
- .open = ad1986a_playback_pcm_open,
- .prepare = ad1986a_playback_pcm_prepare,
- .cleanup = ad1986a_playback_pcm_cleanup
+static snd_kcontrol_new_t ad1983_mixers[] = {
+ HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME_MONO("PC Speaker Playback Volume", 0x10, 1, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE_MONO("PC Speaker Playback Switch", 0x10, 1, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Mic Boost", 0x0c, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Capture Source",
+ .info = ad198x_mux_enum_info,
+ .get = ad198x_mux_enum_get,
+ .put = ad198x_mux_enum_put,
},
-};
-
-static struct hda_pcm_stream ad1986a_pcm_analog_capture = {
- .substreams = 2,
- .channels_min = 2,
- .channels_max = 2,
- .nid = AD1986A_ADC, /* NID to query formats and rates */
- .ops = {
- .prepare = ad1986a_capture_pcm_prepare,
- .cleanup = ad1986a_capture_pcm_cleanup
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "IEC958 Playback Route",
+ .info = ad1983_spdif_route_info,
+ .get = ad1983_spdif_route_get,
+ .put = ad1983_spdif_route_put,
},
+ { } /* end */
};
-static struct hda_pcm_stream ad1986a_pcm_digital_playback = {
- .substreams = 1,
- .channels_min = 2,
- .channels_max = 2,
- .nid = AD1986A_SPDIF_OUT,
- .ops = {
- .open = ad1986a_dig_playback_pcm_open,
- .close = ad1986a_dig_playback_pcm_close
- },
+static struct hda_verb ad1983_init_verbs[] = {
+ /* Front, HP, Mono; mute as default */
+ {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+ {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+ /* Beep, PCM, Mic, Line-In: mute */
+ {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+ {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+ {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+ {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+ /* Front, HP selectors; from Mix */
+ {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
+ {0x06, AC_VERB_SET_CONNECT_SEL, 0x01},
+ /* Mono selector; from Mix */
+ {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03},
+ /* Mic selector; Mic */
+ {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
+ /* Line-in selector: Line-in */
+ {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
+ /* Mic boost: 0dB */
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+ /* Record selector: mic */
+ {0x15, AC_VERB_SET_CONNECT_SEL, 0x0},
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+ /* SPDIF route: PCM */
+ {0x02, AC_VERB_SET_CONNECT_SEL, 0x0},
+ /* Front Pin */
+ {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+ /* HP Pin */
+ {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
+ /* Mono Pin */
+ {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+ /* Mic Pin */
+ {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+ /* Line Pin */
+ {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
+ { } /* end */
};
-static int ad1986a_build_pcms(struct hda_codec *codec)
+static int patch_ad1983(struct hda_codec *codec)
{
- struct ad1986a_spec *spec = codec->spec;
- struct hda_pcm *info = spec->pcm_rec;
+ struct ad198x_spec *spec;
- codec->num_pcms = 2;
- codec->pcm_info = info;
+ spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+ if (spec == NULL)
+ return -ENOMEM;
- info->name = "AD1986A Analog";
- info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad1986a_pcm_analog_playback;
- info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad1986a_pcm_analog_capture;
- info++;
+ init_MUTEX(&spec->amp_mutex);
+ codec->spec = spec;
+
+ spec->multiout.max_channels = 2;
+ spec->multiout.num_dacs = ARRAY_SIZE(ad1983_dac_nids);
+ spec->multiout.dac_nids = ad1983_dac_nids;
+ spec->multiout.dig_out_nid = AD1983_SPDIF_OUT;
+ spec->adc_nid = AD1983_ADC;
+ spec->input_mux = &ad1983_capture_source;
+ spec->mixers = ad1983_mixers;
+ spec->init_verbs = ad1983_init_verbs;
+ spec->spdif_route = 0;
- info->name = "AD1986A Digital";
- info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad1986a_pcm_digital_playback;
+ codec->patch_ops = ad198x_patch_ops;
return 0;
}
-static void ad1986a_free(struct hda_codec *codec)
-{
- kfree(codec->spec);
-}
-#ifdef CONFIG_PM
-static int ad1986a_resume(struct hda_codec *codec)
-{
- ad1986a_init(codec);
- snd_hda_resume_ctls(codec, ad1986a_mixers);
- snd_hda_resume_spdif_out(codec);
- return 0;
-}
-#endif
+/*
+ * AD1981 HD specific
+ */
-static struct hda_codec_ops ad1986a_patch_ops = {
- .build_controls = ad1986a_build_controls,
- .build_pcms = ad1986a_build_pcms,
- .init = ad1986a_init,
- .free = ad1986a_free,
-#ifdef CONFIG_PM
- .resume = ad1986a_resume,
-#endif
+#define AD1981_SPDIF_OUT 0x02
+#define AD1981_DAC 0x03
+#define AD1981_ADC 0x04
+
+static hda_nid_t ad1981_dac_nids[1] = { AD1981_DAC };
+
+/* 0x0c, 0x09, 0x0e, 0x0f, 0x19, 0x05, 0x18, 0x17 */
+static struct hda_input_mux ad1981_capture_source = {
+ .num_items = 7,
+ .items = {
+ { "Front Mic", 0x0 },
+ { "Line", 0x1 },
+ { "Mix", 0x2 },
+ { "Mix Mono", 0x3 },
+ { "CD", 0x4 },
+ { "Mic", 0x6 },
+ { "Aux", 0x7 },
+ },
};
-static int patch_ad1986a(struct hda_codec *codec)
+static snd_kcontrol_new_t ad1981_mixers[] = {
+ HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Front Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Aux Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Aux Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME_MONO("PC Speaker Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE_MONO("PC Speaker Playback Switch", 0x0d, 1, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost", 0x08, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Capture Source",
+ .info = ad198x_mux_enum_info,
+ .get = ad198x_mux_enum_get,
+ .put = ad198x_mux_enum_put,
+ },
+ /* identical with AD1983 */
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "IEC958 Playback Route",
+ .info = ad1983_spdif_route_info,
+ .get = ad1983_spdif_route_get,
+ .put = ad1983_spdif_route_put,
+ },
+ { } /* end */
+};
+
+static struct hda_verb ad1981_init_verbs[] = {
+ /* Front, HP, Mono; mute as default */
+ {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+ {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+ /* Beep, PCM, Front Mic, Line, Rear Mic, Aux, CD-In: mute */
+ {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+ {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+ {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+ {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+ {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+ {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+ {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+ /* Front, HP selectors; from Mix */
+ {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
+ {0x06, AC_VERB_SET_CONNECT_SEL, 0x01},
+ /* Mono selector; from Mix */
+ {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03},
+ /* Mic Mixer; select Front Mic */
+ {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+ {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+ /* Mic boost: 0dB */
+ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+ /* Record selector: Front mic */
+ {0x15, AC_VERB_SET_CONNECT_SEL, 0x0},
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+ /* SPDIF route: PCM */
+ {0x02, AC_VERB_SET_CONNECT_SEL, 0x0},
+ /* Front Pin */
+ {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+ /* HP Pin */
+ {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
+ /* Mono Pin */
+ {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+ /* Front & Rear Mic Pins */
+ {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+ /* Line Pin */
+ {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
+ /* Digital Beep */
+ {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
+ /* Line-Out as Input: disabled */
+ {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+ { } /* end */
+};
+
+static int patch_ad1981(struct hda_codec *codec)
{
- struct ad1986a_spec *spec;
+ struct ad198x_spec *spec;
spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
if (spec == NULL)
init_MUTEX(&spec->amp_mutex);
codec->spec = spec;
- spec->multiout.max_channels = 6;
- spec->multiout.num_dacs = ARRAY_SIZE(ad1986a_dac_nids);
- spec->multiout.dac_nids = ad1986a_dac_nids;
- spec->multiout.dig_out_nid = AD1986A_SPDIF_OUT;
+ spec->multiout.max_channels = 2;
+ spec->multiout.num_dacs = ARRAY_SIZE(ad1981_dac_nids);
+ spec->multiout.dac_nids = ad1981_dac_nids;
+ spec->multiout.dig_out_nid = AD1981_SPDIF_OUT;
+ spec->adc_nid = AD1981_ADC;
+ spec->input_mux = &ad1981_capture_source;
+ spec->mixers = ad1981_mixers;
+ spec->init_verbs = ad1981_init_verbs;
+ spec->spdif_route = 0;
- codec->patch_ops = ad1986a_patch_ops;
+ codec->patch_ops = ad198x_patch_ops;
return 0;
}
+
/*
* patch entries
*/
struct hda_codec_preset snd_hda_preset_analog[] = {
+ { .id = 0x11d41981, .name = "AD1981", .patch = patch_ad1981 },
+ { .id = 0x11d41983, .name = "AD1983", .patch = patch_ad1983 },
{ .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a },
{} /* terminator */
};
#include <sound/core.h>
#include "hda_codec.h"
#include "hda_local.h"
+#define NUM_PINS 11
/* board config type */
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 */
+ CMI_AUTO, /* let driver guess it */
};
struct cmi_spec {
/* playback */
struct hda_multi_out multiout;
+ hda_nid_t dac_nids[4]; /* NID for each DAC */
+ int num_dacs;
/* capture */
hda_nid_t *adc_nids;
const struct cmi_channel_mode *channel_modes;
struct hda_pcm pcm_rec[2]; /* PCM information */
+
+ /* pin deafault configuration */
+ hda_nid_t pin_nid[NUM_PINS];
+ unsigned int def_conf[NUM_PINS];
+ unsigned int pin_def_confs;
+
+ /* multichannel pins */
+ hda_nid_t multich_pin[4]; /* max 8-channel */
+ struct hda_verb multi_init[9]; /* 2 verbs for each pin + terminator */
};
+/* amp values */
+#define AMP_IN_MUTE(idx) (0x7080 | ((idx)<<8))
+#define AMP_IN_UNMUTE(idx) (0x7000 | ((idx)<<8))
+#define AMP_OUT_MUTE 0xb080
+#define AMP_OUT_UNMUTE 0xb000
+#define AMP_OUT_ZERO 0xb000
+/* pinctl values */
+#define PIN_IN 0x20
+#define PIN_VREF80 0x24
+#define PIN_VREF50 0x21
+#define PIN_OUT 0x40
+#define PIN_HP 0xc0
+
/*
* input MUX
*/
/* 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 },
+ { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
/* set mic PIN for input, also enable vref */
- { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+ { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
/* 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 },
+ { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
/* set mic PIN for output */
- { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+ { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
/* 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 },
+ { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
/* set mic PIN for output */
- { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+ { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
/* route rear-surround PCM (DAC4) to HP */
{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x03 },
{}
*/
static struct hda_verb cmi9880_basic_init[] = {
/* port-D for line out (rear panel) */
- { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
+ { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
/* port-E for HP out (front panel) */
- { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
+ { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
/* 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 },
+ { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
/* port-G for CLFE (rear panel) */
- { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
+ { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
+ { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x02 },
/* port-H for side (rear panel) */
- { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
+ { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
+ { 0x20, AC_VERB_SET_CONNECT_SEL, 0x01 },
/* port-C for line-in (rear panel) */
- { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
+ { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
/* port-B for mic-in (rear panel) with vref */
- { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+ { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
/* port-F for mic-in (front panel) with vref */
- { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+ { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
/* CD-in */
- { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
+ { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
/* route front mic to ADC1/2 */
{ 0x08, AC_VERB_SET_CONNECT_SEL, 0x05 },
{ 0x09, AC_VERB_SET_CONNECT_SEL, 0x05 },
static struct hda_verb cmi9880_allout_init[] = {
/* port-D for line out (rear panel) */
- { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
+ { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
/* port-E for HP out (front panel) */
- { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
+ { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
/* 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 },
+ { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
/* port-G for CLFE (rear panel) */
- { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
+ { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
+ { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x02 },
+ /* port-H for side (rear panel) */
+ { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
+ { 0x20, AC_VERB_SET_CONNECT_SEL, 0x01 },
/* port-C for surround (rear panel) */
- { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
+ { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
/* port-B for mic-in (rear panel) with vref */
- { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+ { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
/* port-F for mic-in (front panel) with vref */
- { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+ { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
/* CD-in */
- { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
+ { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
/* route front mic to ADC1/2 */
{ 0x08, AC_VERB_SET_CONNECT_SEL, 0x05 },
{ 0x09, AC_VERB_SET_CONNECT_SEL, 0x05 },
return 0;
}
+/* fill in the multi_dac_nids table, which will decide
+ which audio widget to use for each channel */
+static int cmi9880_fill_multi_dac_nids(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
+{
+ struct cmi_spec *spec = codec->spec;
+ hda_nid_t nid;
+ int assigned[4];
+ int i, j;
+
+ /* clear the table, only one c-media dac assumed here */
+ memset(spec->dac_nids, 0, sizeof(spec->dac_nids));
+ memset(assigned, 0, sizeof(assigned));
+ /* check the pins we found */
+ for (i = 0; i < cfg->line_outs; i++) {
+ nid = cfg->line_out_pins[i];
+ /* nid 0x0b~0x0e is hardwired to audio widget 0x3~0x6 */
+ if (nid >= 0x0b && nid <= 0x0e) {
+ spec->dac_nids[i] = (nid - 0x0b) + 0x03;
+ assigned[nid - 0x0b] = 1;
+ }
+ }
+ /* left pin can be connect to any audio widget */
+ for (i = 0; i < cfg->line_outs; i++) {
+ nid = cfg->line_out_pins[i];
+ if (nid <= 0x0e)
+ continue;
+ /* search for an empty channel */
+ for (j = 0; j < cfg->line_outs; j++) {
+ if (! assigned[j]) {
+ spec->dac_nids[i] = i + 0x03;
+ assigned[j] = 1;
+ break;
+ }
+ }
+ }
+ spec->num_dacs = cfg->line_outs;
+ return 0;
+}
+
+/* create multi_init table, which is used for multichannel initialization */
+static int cmi9880_fill_multi_init(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
+{
+ struct cmi_spec *spec = codec->spec;
+ hda_nid_t nid;
+ int i, j, k, len;
+
+ /* clear the table, only one c-media dac assumed here */
+ memset(spec->multi_init, 0, sizeof(spec->multi_init));
+ for (j = 0, i = 0; i < cfg->line_outs; i++) {
+ hda_nid_t conn[4];
+ nid = cfg->line_out_pins[i];
+ /* set as output */
+ spec->multi_init[j].nid = nid;
+ spec->multi_init[j].verb = AC_VERB_SET_PIN_WIDGET_CONTROL;
+ spec->multi_init[j].param = PIN_OUT;
+ j++;
+ if (nid > 0x0e) {
+ /* set connection */
+ spec->multi_init[j].nid = nid;
+ spec->multi_init[j].verb = AC_VERB_SET_CONNECT_SEL;
+ spec->multi_init[j].param = 0;
+ /* find the index in connect list */
+ len = snd_hda_get_connections(codec, nid, conn, 4);
+ for (k = 0; k < len; k++)
+ if (conn[k] == spec->dac_nids[i]) {
+ spec->multi_init[j].param = j;
+ break;
+ }
+ j++;
+ break;
+ }
+ }
+ return 0;
+}
+
static int cmi9880_init(struct hda_codec *codec)
{
struct cmi_spec *spec = codec->spec;
snd_hda_sequence_write(codec, cmi9880_allout_init);
else
snd_hda_sequence_write(codec, cmi9880_basic_init);
+ if (spec->board_config == CMI_AUTO)
+ snd_hda_sequence_write(codec, spec->multi_init);
return 0;
}
{ .modelname = "full", .config = CMI_FULL },
{ .modelname = "full_dig", .config = CMI_FULL_DIG },
{ .modelname = "allout", .config = CMI_ALLOUT },
+ { .modelname = "auto", .config = CMI_AUTO },
{} /* terminator */
};
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 */
+ snd_printdd(KERN_INFO "hda_codec: Unknown model for CMI9880\n");
+ spec->board_config = CMI_AUTO; /* try everything */
}
+ /* copy default DAC NIDs */
+ memcpy(spec->dac_nids, cmi9880_dac_nids, sizeof(spec->dac_nids));
+ spec->num_dacs = 4;
+
switch (spec->board_config) {
case CMI_MINIMAL:
case CMI_MIN_FP:
spec->input_mux = &cmi9880_no_line_mux;
spec->multiout.dig_out_nid = CMI_DIG_OUT_NID;
break;
+ case CMI_AUTO:
+ {
+ unsigned int port_e, port_f, port_g, port_h;
+ unsigned int port_spdifi, port_spdifo;
+ struct auto_pin_cfg cfg;
+
+ /* collect pin default configuration */
+ port_e = snd_hda_codec_read(codec, 0x0f, 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
+ port_f = snd_hda_codec_read(codec, 0x10, 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
+ spec->front_panel = 1;
+ if (get_defcfg_connect(port_e) == AC_JACK_PORT_NONE ||
+ get_defcfg_connect(port_f) == AC_JACK_PORT_NONE) {
+ port_g = snd_hda_codec_read(codec, 0x1f, 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
+ port_h = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
+ spec->surr_switch = 1;
+ /* no front panel */
+ if (get_defcfg_connect(port_g) == AC_JACK_PORT_NONE ||
+ get_defcfg_connect(port_h) == AC_JACK_PORT_NONE) {
+ /* no optional rear panel */
+ spec->board_config = CMI_MINIMAL;
+ spec->front_panel = 0;
+ spec->num_ch_modes = 2;
+ } else {
+ spec->board_config = CMI_MIN_FP;
+ spec->num_ch_modes = 3;
+ }
+ spec->channel_modes = cmi9880_channel_modes;
+ spec->input_mux = &cmi9880_basic_mux;
+ spec->multiout.max_channels = cmi9880_channel_modes[0].channels;
+ } else {
+ spec->input_mux = &cmi9880_basic_mux;
+ port_spdifi = snd_hda_codec_read(codec, 0x13, 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
+ port_spdifo = snd_hda_codec_read(codec, 0x12, 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
+ if (get_defcfg_connect(port_spdifo) != AC_JACK_PORT_NONE)
+ spec->multiout.dig_out_nid = CMI_DIG_OUT_NID;
+ if (get_defcfg_connect(port_spdifi) != AC_JACK_PORT_NONE)
+ spec->dig_in_nid = CMI_DIG_IN_NID;
+ spec->multiout.max_channels = 8;
+ }
+ snd_hda_parse_pin_def_config(codec, &cfg);
+ if (cfg.line_outs) {
+ spec->multiout.max_channels = cfg.line_outs * 2;
+ cmi9880_fill_multi_dac_nids(codec, &cfg);
+ cmi9880_fill_multi_init(codec, &cfg);
+ } else
+ snd_printd("patch_cmedia: cannot detect association in defcfg\n");
+ break;
+ }
}
- spec->multiout.num_dacs = 4;
- spec->multiout.dac_nids = cmi9880_dac_nids;
+ spec->multiout.num_dacs = spec->num_dacs;
+ spec->multiout.dac_nids = spec->dac_nids;
spec->adc_nids = cmi9880_adc_nids;
/* ALC880 board config type */
enum {
- ALC880_MINIMAL,
ALC880_3ST,
ALC880_3ST_DIG,
ALC880_5ST,
ALC880_5ST_DIG,
ALC880_W810,
+ ALC880_Z71V,
+ ALC880_AUTO,
+ ALC880_6ST_DIG,
+ ALC880_F1734,
+ ALC880_ASUS,
+ ALC880_ASUS_DIG,
+ ALC880_ASUS_W1V,
+ ALC880_UNIWILL_DIG,
+#ifdef CONFIG_SND_DEBUG
+ ALC880_TEST,
+#endif
+ ALC880_MODEL_LAST /* last tag */
+};
+
+/* ALC260 models */
+enum {
+ ALC260_BASIC,
+ ALC260_HP,
+ ALC260_MODEL_LAST /* last tag */
};
+/* amp values */
+#define AMP_IN_MUTE(idx) (0x7080 | ((idx)<<8))
+#define AMP_IN_UNMUTE(idx) (0x7000 | ((idx)<<8))
+#define AMP_OUT_MUTE 0xb080
+#define AMP_OUT_UNMUTE 0xb000
+#define AMP_OUT_ZERO 0xb000
+/* pinctl values */
+#define PIN_IN 0x20
+#define PIN_VREF80 0x24
+#define PIN_VREF50 0x21
+#define PIN_OUT 0x40
+#define PIN_HP 0xc0
+
struct alc_spec {
/* codec parameterization */
- unsigned int front_panel: 1;
-
- snd_kcontrol_new_t* mixers[2];
+ snd_kcontrol_new_t *mixers[3]; /* mixer arrays */
unsigned int num_mixers;
- struct hda_verb *init_verbs;
+ const struct hda_verb *init_verbs[3]; /* initialization verbs
+ * don't forget NULL termination!
+ */
+ unsigned int num_init_verbs;
- char* stream_name_analog;
+ char *stream_name_analog; /* analog PCM stream */
struct hda_pcm_stream *stream_analog_playback;
struct hda_pcm_stream *stream_analog_capture;
- char* stream_name_digital;
+ char *stream_name_digital; /* digital PCM stream */
struct hda_pcm_stream *stream_digital_playback;
struct hda_pcm_stream *stream_digital_capture;
/* playback */
- struct hda_multi_out multiout;
+ struct hda_multi_out multiout; /* playback set-up
+ * max_channels, dacs must be set
+ * dig_out_nid and hp_nid are optional
+ */
/* capture */
unsigned int num_adc_nids;
hda_nid_t *adc_nids;
- hda_nid_t dig_in_nid;
+ hda_nid_t dig_in_nid; /* digital-in NID; optional */
/* capture source */
const struct hda_input_mux *input_mux;
int num_channel_mode;
/* PCM information */
- struct hda_pcm pcm_rec[2];
-};
-
-/* DAC/ADC assignment */
-
-static hda_nid_t alc880_dac_nids[4] = {
- /* front, rear, clfe, rear_surr */
- 0x02, 0x05, 0x04, 0x03
-};
-
-static hda_nid_t alc880_w810_dac_nids[3] = {
- /* front, rear/surround, clfe */
- 0x02, 0x03, 0x04
-};
-
-static hda_nid_t alc880_adc_nids[3] = {
- /* ADC0-2 */
- 0x07, 0x08, 0x09,
-};
-
-#define ALC880_DIGOUT_NID 0x06
-#define ALC880_DIGIN_NID 0x0a
-
-static hda_nid_t alc260_dac_nids[1] = {
- /* front */
- 0x02,
-};
-
-static hda_nid_t alc260_adc_nids[2] = {
- /* ADC0-1 */
- 0x04, 0x05,
-};
+ struct hda_pcm pcm_rec[2]; /* used in alc_build_pcms() */
-#define ALC260_DIGOUT_NID 0x03
-#define ALC260_DIGIN_NID 0x06
+ struct semaphore bind_mutex; /* for bound controls */
-static struct hda_input_mux alc880_capture_source = {
- .num_items = 4,
- .items = {
- { "Mic", 0x0 },
- { "Front Mic", 0x3 },
- { "Line", 0x2 },
- { "CD", 0x4 },
- },
+ /* dynamic controls, init_verbs and input_mux */
+ struct auto_pin_cfg autocfg;
+ unsigned int num_kctl_alloc, num_kctl_used;
+ snd_kcontrol_new_t *kctl_alloc;
+ struct hda_input_mux private_imux;
};
-static struct hda_input_mux alc260_capture_source = {
- .num_items = 4,
- .items = {
- { "Mic", 0x0 },
- { "Front Mic", 0x1 },
- { "Line", 0x2 },
- { "CD", 0x4 },
- },
-};
/*
* input MUX handling
spec->adc_nids[adc_idx], &spec->cur_mux[adc_idx]);
}
+
/*
* channel mode setting
*/
const struct hda_verb *sequence;
};
-
-/*
- * channel source setting (2/6 channel selection for 3-stack)
- */
-
-/*
- * set the path ways for 2 channel output
- * need to set the codec line out and mic 1 pin widgets to inputs
- */
-static struct hda_verb alc880_threestack_ch2_init[] = {
- /* set pin widget 1Ah (line in) for input */
- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
- /* set pin widget 18h (mic1) for input, for mic also enable the vref */
- { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
- /* mute the output for Line In PW */
- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
- /* mute for Mic1 PW */
- { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
- { } /* end */
-};
-
-/*
- * 6ch mode
- * need to set the codec line out and mic 1 pin widgets to outputs
- */
-static struct hda_verb alc880_threestack_ch6_init[] = {
- /* set pin widget 1Ah (line in) for output */
- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
- /* set pin widget 18h (mic1) for output */
- { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
- /* unmute the output for Line In PW */
- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000 },
- /* unmute for Mic1 PW */
- { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000 },
- /* for rear channel output using Line In 1
- * set select widget connection (nid = 0x12) - to summer node
- * for rear NID = 0x0f...offset 3 in connection list
- */
- { 0x12, AC_VERB_SET_CONNECT_SEL, 0x3 },
- /* for Mic1 - retask for center/lfe */
- /* set select widget connection (nid = 0x10) - to summer node for
- * front CLFE NID = 0x0e...offset 2 in connection list
- */
- { 0x10, AC_VERB_SET_CONNECT_SEL, 0x2 },
- { } /* end */
-};
-
-static struct alc_channel_mode alc880_threestack_modes[2] = {
- { 2, alc880_threestack_ch2_init },
- { 6, alc880_threestack_ch6_init },
-};
-
-
-/*
- * channel source setting (6/8 channel selection for 5-stack)
- */
-
-/* set the path ways for 6 channel output
- * need to set the codec line out and mic 1 pin widgets to inputs
- */
-static struct hda_verb alc880_fivestack_ch6_init[] = {
- /* set pin widget 1Ah (line in) for input */
- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
- /* mute the output for Line In PW */
- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
- { } /* end */
-};
-
-/* need to set the codec line out and mic 1 pin widgets to outputs */
-static struct hda_verb alc880_fivestack_ch8_init[] = {
- /* set pin widget 1Ah (line in) for output */
- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
- /* unmute the output for Line In PW */
- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000 },
- /* output for surround channel output using Line In 1 */
- /* set select widget connection (nid = 0x12) - to summer node
- * for surr_rear NID = 0x0d...offset 1 in connection list
- */
- { 0x12, AC_VERB_SET_CONNECT_SEL, 0x1 },
- { } /* end */
-};
-
-static struct alc_channel_mode alc880_fivestack_modes[2] = {
- { 6, alc880_fivestack_ch6_init },
- { 8, alc880_fivestack_ch8_init },
-};
-
-/*
- * channel source setting for W810 system
- *
- * W810 has rear IO for:
- * Front (DAC 02)
- * Surround (DAC 03)
- * Center/LFE (DAC 04)
- * Digital out (06)
- *
- * The system also has a pair of internal speakers, and a headphone jack.
- * These are both connected to Line2 on the codec, hence to DAC 02.
- *
- * There is a variable resistor to control the speaker or headphone
- * volume. This is a hardware-only device without a software API.
- *
- * Plugging headphones in will disable the internal speakers. This is
- * implemented in hardware, not via the driver using jack sense. In
- * a similar fashion, plugging into the rear socket marked "front" will
- * disable both the speakers and headphones.
- *
- * For input, there's a microphone jack, and an "audio in" jack.
- * These may not do anything useful with this driver yet, because I
- * haven't setup any initialization verbs for these yet...
- */
-
-static struct alc_channel_mode alc880_w810_modes[1] = {
- { 6, NULL }
-};
-
-/*
- */
static int alc880_ch_mode_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct alc_spec *spec = codec->spec;
+ int items = kcontrol->private_value ? (int)kcontrol->private_value : 2;
snd_assert(spec->channel_mode, return -ENXIO);
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item >= 2)
- uinfo->value.enumerated.item = 1;
+ uinfo->value.enumerated.items = items;
+ if (uinfo->value.enumerated.item >= items)
+ uinfo->value.enumerated.item = items - 1;
sprintf(uinfo->value.enumerated.name, "%dch",
spec->channel_mode[uinfo->value.enumerated.item].channels);
return 0;
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct alc_spec *spec = codec->spec;
+ int items = kcontrol->private_value ? (int)kcontrol->private_value : 2;
+ int i;
snd_assert(spec->channel_mode, return -ENXIO);
- ucontrol->value.enumerated.item[0] =
- (spec->multiout.max_channels == spec->channel_mode[0].channels) ? 0 : 1;
+ for (i = 0; i < items; i++) {
+ if (spec->multiout.max_channels == spec->channel_mode[i].channels) {
+ ucontrol->value.enumerated.item[0] = i;
+ break;
+ }
+ }
return 0;
}
/*
+ * bound volume controls
+ *
+ * bind multiple volumes (# indices, from 0)
+ */
+
+#define AMP_VAL_IDX_SHIFT 19
+#define AMP_VAL_IDX_MASK (0x0f<<19)
+
+static int alc_bind_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct alc_spec *spec = codec->spec;
+ unsigned long pval;
+
+ down(&spec->bind_mutex);
+ pval = kcontrol->private_value;
+ kcontrol->private_value = pval & ~AMP_VAL_IDX_MASK; /* index 0 */
+ snd_hda_mixer_amp_switch_info(kcontrol, uinfo);
+ kcontrol->private_value = pval;
+ up(&spec->bind_mutex);
+ return 0;
+}
+
+static int alc_bind_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct alc_spec *spec = codec->spec;
+ unsigned long pval;
+
+ down(&spec->bind_mutex);
+ pval = kcontrol->private_value;
+ kcontrol->private_value = pval & ~AMP_VAL_IDX_MASK; /* index 0 */
+ snd_hda_mixer_amp_switch_get(kcontrol, ucontrol);
+ kcontrol->private_value = pval;
+ up(&spec->bind_mutex);
+ return 0;
+}
+
+static int alc_bind_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct alc_spec *spec = codec->spec;
+ unsigned long pval;
+ int i, indices, change = 0;
+
+ down(&spec->bind_mutex);
+ pval = kcontrol->private_value;
+ indices = (pval & AMP_VAL_IDX_MASK) >> AMP_VAL_IDX_SHIFT;
+ for (i = 0; i < indices; i++) {
+ kcontrol->private_value = (pval & ~AMP_VAL_IDX_MASK) | (i << AMP_VAL_IDX_SHIFT);
+ change |= snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
+ }
+ kcontrol->private_value = pval;
+ up(&spec->bind_mutex);
+ return change;
+}
+
+#define ALC_BIND_MUTE_MONO(xname, nid, channel, indices, direction) \
+ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
+ .info = alc_bind_switch_info, \
+ .get = alc_bind_switch_get, \
+ .put = alc_bind_switch_put, \
+ .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, indices, direction) }
+
+#define ALC_BIND_MUTE(xname,nid,indices,dir) ALC_BIND_MUTE_MONO(xname,nid,3,indices,dir)
+
+
+/*
+ * ALC880 3-stack model
+ *
+ * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e)
+ * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18, F-Mic = 0x1b
+ * HP = 0x19
*/
-/* 3-stack mode
- * Pin assignment: Front=0x14, Line-In/Rear=0x1a, Mic/CLFE=0x18, F-Mic=0x1b
- * HP=0x19
+static hda_nid_t alc880_dac_nids[4] = {
+ /* front, rear, clfe, rear_surr */
+ 0x02, 0x05, 0x04, 0x03
+};
+
+static hda_nid_t alc880_adc_nids[3] = {
+ /* ADC0-2 */
+ 0x07, 0x08, 0x09,
+};
+
+/* The datasheet says the node 0x07 is connected from inputs,
+ * but it shows zero connection in the real implementation on some devices.
*/
-static snd_kcontrol_new_t alc880_base_mixer[] = {
+static hda_nid_t alc880_adc_nids_alt[2] = {
+ /* ADC1-2 */
+ 0x08, 0x09,
+};
+
+#define ALC880_DIGOUT_NID 0x06
+#define ALC880_DIGIN_NID 0x0a
+
+static struct hda_input_mux alc880_capture_source = {
+ .num_items = 4,
+ .items = {
+ { "Mic", 0x0 },
+ { "Front Mic", 0x3 },
+ { "Line", 0x2 },
+ { "CD", 0x4 },
+ },
+};
+
+/* channel source setting (2/6 channel selection for 3-stack) */
+/* 2ch mode */
+static struct hda_verb alc880_threestack_ch2_init[] = {
+ /* set line-in to input, mute it */
+ { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+ { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+ /* set mic-in to input vref 80%, mute it */
+ { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+ { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+ { } /* end */
+};
+
+/* 6ch mode */
+static struct hda_verb alc880_threestack_ch6_init[] = {
+ /* set line-in to output, unmute it */
+ { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+ /* set mic-in to output, unmute it */
+ { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+ { } /* end */
+};
+
+static struct alc_channel_mode alc880_threestack_modes[2] = {
+ { 2, alc880_threestack_ch2_init },
+ { 6, alc880_threestack_ch6_init },
+};
+
+static snd_kcontrol_new_t alc880_three_stack_mixer[] = {
HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+ ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Surround Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
+ ALC_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x18, 1, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x18, 2, 0x0, HDA_OUTPUT),
+ ALC_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+ ALC_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
- HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
- {
- .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 = alc_mux_enum_info,
- .get = alc_mux_enum_get,
- .put = alc_mux_enum_put,
- },
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Channel Mode",
{ } /* end */
};
-/* 5-stack mode
- * Pin assignment: Front=0x14, Rear=0x17, CLFE=0x16
- * Line-In/Side=0x1a, Mic=0x18, F-Mic=0x1b, HP=0x19
- */
-static snd_kcontrol_new_t alc880_five_stack_mixer[] = {
- HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Surround Playback Switch", 0x17, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x16, 1, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Side Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
- HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
- HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
- HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
- HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
- HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
- HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
- HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
+/* capture mixer elements */
+static snd_kcontrol_new_t alc880_capture_mixer[] = {
HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT),
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
/* The multiple "Capture Source" controls confuse alsamixer
*/
/* .name = "Capture Source", */
.name = "Input Source",
- .count = 2,
+ .count = 3,
.info = alc_mux_enum_info,
.get = alc_mux_enum_get,
.put = alc_mux_enum_put,
},
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Channel Mode",
- .info = alc880_ch_mode_info,
- .get = alc880_ch_mode_get,
- .put = alc880_ch_mode_put,
- },
{ } /* end */
};
-static snd_kcontrol_new_t alc880_w810_base_mixer[] = {
- HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x16, 1, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT),
+/* capture mixer elements (in case NID 0x07 not available) */
+static snd_kcontrol_new_t alc880_capture_alt_mixer[] = {
+ HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
/* The multiple "Capture Source" controls confuse alsamixer
*/
/* .name = "Capture Source", */
.name = "Input Source",
- .count = 3,
+ .count = 2,
.info = alc_mux_enum_info,
.get = alc_mux_enum_get,
.put = alc_mux_enum_put,
{ } /* end */
};
-/*
+
+
+/*
+ * ALC880 5-stack model
+ *
+ * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d), Side = 0x02 (0xd)
+ * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16
+ * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19
+ */
+
+/* additional mixers to alc880_three_stack_mixer */
+static snd_kcontrol_new_t alc880_five_stack_mixer[] = {
+ HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+ ALC_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT),
+ { } /* end */
+};
+
+/* channel source setting (6/8 channel selection for 5-stack) */
+/* 6ch mode */
+static struct hda_verb alc880_fivestack_ch6_init[] = {
+ /* set line-in to input, mute it */
+ { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+ { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+ { } /* end */
+};
+
+/* 8ch mode */
+static struct hda_verb alc880_fivestack_ch8_init[] = {
+ /* set line-in to output, unmute it */
+ { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+ { } /* end */
+};
+
+static struct alc_channel_mode alc880_fivestack_modes[2] = {
+ { 6, alc880_fivestack_ch6_init },
+ { 8, alc880_fivestack_ch8_init },
+};
+
+
+/*
+ * ALC880 6-stack model
+ *
+ * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e), Side = 0x05 (0x0f)
+ * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17,
+ * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b
+ */
+
+static hda_nid_t alc880_6st_dac_nids[4] = {
+ /* front, rear, clfe, rear_surr */
+ 0x02, 0x03, 0x04, 0x05
+};
+
+static struct hda_input_mux alc880_6stack_capture_source = {
+ .num_items = 4,
+ .items = {
+ { "Mic", 0x0 },
+ { "Front Mic", 0x1 },
+ { "Line", 0x2 },
+ { "CD", 0x4 },
+ },
+};
+
+/* fixed 8-channels */
+static struct alc_channel_mode alc880_sixstack_modes[1] = {
+ { 8, NULL },
+};
+
+static snd_kcontrol_new_t alc880_six_stack_mixer[] = {
+ HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+ ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+ ALC_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+ ALC_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+ ALC_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
+ ALC_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+ HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
+ HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Channel Mode",
+ .info = alc880_ch_mode_info,
+ .get = alc880_ch_mode_get,
+ .put = alc880_ch_mode_put,
+ },
+ { } /* end */
+};
+
+
+/*
+ * ALC880 W810 model
+ *
+ * W810 has rear IO for:
+ * Front (DAC 02)
+ * Surround (DAC 03)
+ * Center/LFE (DAC 04)
+ * Digital out (06)
+ *
+ * The system also has a pair of internal speakers, and a headphone jack.
+ * These are both connected to Line2 on the codec, hence to DAC 02.
+ *
+ * There is a variable resistor to control the speaker or headphone
+ * volume. This is a hardware-only device without a software API.
+ *
+ * Plugging headphones in will disable the internal speakers. This is
+ * implemented in hardware, not via the driver using jack sense. In
+ * a similar fashion, plugging into the rear socket marked "front" will
+ * disable both the speakers and headphones.
+ *
+ * For input, there's a microphone jack, and an "audio in" jack.
+ * These may not do anything useful with this driver yet, because I
+ * haven't setup any initialization verbs for these yet...
+ */
+
+static hda_nid_t alc880_w810_dac_nids[3] = {
+ /* front, rear/surround, clfe */
+ 0x02, 0x03, 0x04
+};
+
+/* fixed 6 channels */
+static struct alc_channel_mode alc880_w810_modes[1] = {
+ { 6, NULL }
+};
+
+/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */
+static snd_kcontrol_new_t alc880_w810_base_mixer[] = {
+ HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+ ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+ ALC_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+ ALC_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+ ALC_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
+ HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+ { } /* end */
+};
+
+
+/*
+ * Z710V model
+ *
+ * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d)
+ * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?), Line = 0x1a
+ */
+
+static hda_nid_t alc880_z71v_dac_nids[1] = {
+ 0x02
+};
+#define ALC880_Z71V_HP_DAC 0x03
+
+/* fixed 2 channels */
+static struct alc_channel_mode alc880_2_jack_modes[1] = {
+ { 2, NULL }
+};
+
+static snd_kcontrol_new_t alc880_z71v_mixer[] = {
+ HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+ ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+ ALC_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+ { } /* end */
+};
+
+
+/* FIXME! */
+/*
+ * ALC880 F1734 model
+ *
+ * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d)
+ * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18
+ */
+
+static hda_nid_t alc880_f1734_dac_nids[1] = {
+ 0x03
+};
+#define ALC880_F1734_HP_DAC 0x02
+
+static snd_kcontrol_new_t alc880_f1734_mixer[] = {
+ HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+ ALC_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+ ALC_BIND_MUTE("Internal Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+ { } /* end */
+};
+
+
+/* FIXME! */
+/*
+ * ALC880 ASUS model
+ *
+ * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
+ * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
+ * Mic = 0x18, Line = 0x1a
+ */
+
+#define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */
+#define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */
+
+static snd_kcontrol_new_t alc880_asus_mixer[] = {
+ HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+ ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+ ALC_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+ ALC_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+ ALC_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+ HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Channel Mode",
+ .info = alc880_ch_mode_info,
+ .get = alc880_ch_mode_get,
+ .put = alc880_ch_mode_put,
+ },
+ { } /* end */
+};
+
+/* FIXME! */
+/*
+ * ALC880 ASUS W1V model
+ *
+ * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
+ * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
+ * Mic = 0x18, Line = 0x1a, Line2 = 0x1b
+ */
+
+/* additional mixers to alc880_asus_mixer */
+static snd_kcontrol_new_t alc880_asus_w1v_mixer[] = {
+ HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT),
+ HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT),
+ { } /* end */
+};
+
+
+/*
+ * build control elements
*/
static int alc_build_controls(struct hda_codec *codec)
{
return 0;
}
+
/*
* initialize the codec volumes, etc
*/
-static struct hda_verb alc880_init_verbs_three_stack[] = {
- /* Line In pin widget for input */
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
- /* CD pin widget for input */
- {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
- /* Mic1 (rear panel) pin widget for input and vref at 80% */
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
- /* Mic2 (front panel) pin widget for input and vref at 80% */
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
- /* unmute amp left and right */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
- /* set connection select to line in (default select for this ADC) */
- {0x07, AC_VERB_SET_CONNECT_SEL, 0x02},
- /* unmute front mixer amp left (volume = 0) */
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
- /* mute pin widget amp left and right (no gain on this amp) */
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
- /* unmute rear mixer amp left and right (volume = 0) */
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
- /* mute pin widget amp left and right (no gain on this amp) */
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
- /* unmute rear mixer amp left and right (volume = 0) */
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
- /* mute pin widget amp left and right (no gain on this amp) */
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
-
- /* using rear surround as the path for headphone output */
- /* unmute rear surround mixer amp left and right (volume = 0) */
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
- /* PASD 3 stack boards use the Mic 2 as the headphone output */
- /* need to program the selector associated with the Mic 2 pin widget to
- * surround path (index 0x01) for headphone output */
- {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
- /* mute pin widget amp left and right (no gain on this amp) */
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
- /* need to retask the Mic 2 pin widget to output */
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
-
- /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) for mixer widget(nid=0x0B)
- * to support the input path of analog loopback
+/*
+ * generic initialization of ADC, input mixers and output mixers
+ */
+static struct hda_verb alc880_volume_init_verbs[] = {
+ /*
+ * Unmute ADC0-2 and set the default input to mic-in
+ */
+ {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
+ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
+ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
+ {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+ /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
+ * mixer widget
* Note: PASD motherboards uses the Line In 2 as the input for front panel
* mic (mic 2)
*/
- /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03 */
- /* unmute CD */
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
- /* unmute Line In */
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
- /* unmute Mic 1 */
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
- /* unmute Line In 2 (for PASD boards Mic 2) */
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
-
- /* Unmute input amps for the line out paths to support the output path of
- * analog loopback
- * the mixers on the output path has 2 inputs, one from the DAC and one
- * from the mixer
+ /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
+ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
+
+ /*
+ * Set up output mixers (0x0c - 0x0f)
*/
- /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
- /* Unmute Front out path */
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
- /* Unmute Surround (used as HP) out path */
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
- /* Unmute C/LFE out path */
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))}, /* mute */
- /* Unmute rear Surround out path */
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+ /* set vol=0 to output mixers */
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ /* set up input amps for analog loopback */
+ /* Amp Indices: DAC = 0, mixer = 1 */
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
{ }
};
-static struct hda_verb alc880_init_verbs_five_stack[] = {
- /* Line In pin widget for input */
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
- /* CD pin widget for input */
- {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
- /* Mic1 (rear panel) pin widget for input and vref at 80% */
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
- /* Mic2 (front panel) pin widget for input and vref at 80% */
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
- /* unmute amp left and right */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
- /* set connection select to line in (default select for this ADC) */
- {0x07, AC_VERB_SET_CONNECT_SEL, 0x02},
- /* unmute front mixer amp left and right (volume = 0) */
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
- /* mute pin widget amp left and right (no gain on this amp) */
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
- /* five rear and clfe */
- /* unmute rear mixer amp left and right (volume = 0) */
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
- /* mute pin widget amp left and right (no gain on this amp) */
- {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
- /* unmute clfe mixer amp left and right (volume = 0) */
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
- /* mute pin widget amp left and right (no gain on this amp) */
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
-
- /* using rear surround as the path for headphone output */
- /* unmute rear surround mixer amp left and right (volume = 0) */
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
- /* PASD 3 stack boards use the Mic 2 as the headphone output */
- /* need to program the selector associated with the Mic 2 pin widget to
- * surround path (index 0x01) for headphone output
- */
- {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
- /* mute pin widget amp left and right (no gain on this amp) */
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
- /* need to retask the Mic 2 pin widget to output */
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
-
- /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) for mixer
- * widget(nid=0x0B) to support the input path of analog loopback
+/*
+ * 3-stack pin configuration:
+ * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
+ */
+static struct hda_verb alc880_pin_3stack_init_verbs[] = {
+ /*
+ * preset connection lists of input pins
+ * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
*/
- /* Note: PASD motherboards uses the Line In 2 as the input for front panel mic (mic 2) */
- /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03*/
- /* unmute CD */
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
- /* unmute Line In */
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
- /* unmute Mic 1 */
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
- /* unmute Line In 2 (for PASD boards Mic 2) */
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
-
- /* Unmute input amps for the line out paths to support the output path of
- * analog loopback
- * the mixers on the output path has 2 inputs, one from the DAC and
- * one from the mixer
+ {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
+ {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
+ {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
+
+ /*
+ * Set pin mode and muting
*/
- /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
- /* Unmute Front out path */
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
- /* Unmute Surround (used as HP) out path */
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
- /* Unmute C/LFE out path */
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))}, /* mute */
- /* Unmute rear Surround out path */
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+ /* set front pin widgets 0x14 for output */
+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ /* Mic1 (rear panel) pin widget for input and vref at 80% */
+ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ /* Mic2 (as headphone out) for HP output */
+ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ /* Line In pin widget for input */
+ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+ {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ /* Line2 (as front mic) pin widget for input and vref at 80% */
+ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ /* CD pin widget for input */
+ {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
{ }
};
-static struct hda_verb alc880_w810_init_verbs[] = {
- /* front channel selector/amp: input 0: DAC: unmuted, (no volume selection) */
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
-
- /* front channel selector/amp: input 1: capture mix: muted, (no volume selection) */
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7180},
-
- /* front channel selector/amp: output 0: unmuted, max volume */
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
-
- /* front out pin: muted, (no volume selection) */
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-
- /* front out pin: NOT headphone enable, out enable, vref disabled */
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+/*
+ * 5-stack pin configuration:
+ * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19,
+ * line-in/side = 0x1a, f-mic = 0x1b
+ */
+static struct hda_verb alc880_pin_5stack_init_verbs[] = {
+ /*
+ * preset connection lists of input pins
+ * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
+ */
+ {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
+ {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */
+ /*
+ * Set pin mode and muting
+ */
+ /* set pin widgets 0x14-0x17 for output */
+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ /* unmute pins for output (no gain on this amp) */
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- /* surround channel selector/amp: input 0: DAC: unmuted, (no volume selection) */
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
+ /* Mic1 (rear panel) pin widget for input and vref at 80% */
+ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ /* Mic2 (as headphone out) for HP output */
+ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ /* Line In pin widget for input */
+ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+ {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ /* Line2 (as front mic) pin widget for input and vref at 80% */
+ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ /* CD pin widget for input */
+ {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- /* surround channel selector/amp: input 1: capture mix: muted, (no volume selection) */
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7180},
+ { }
+};
- /* surround channel selector/amp: output 0: unmuted, max volume */
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+/*
+ * W810 pin configuration:
+ * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b
+ */
+static struct hda_verb alc880_pin_w810_init_verbs[] = {
+ /* hphone/speaker input selector: front DAC */
+ {0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
- /* surround out pin: muted, (no volume selection) */
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- /* surround out pin: NOT headphone enable, out enable, vref disabled */
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ { }
+};
- /* c/lfe channel selector/amp: input 0: DAC: unmuted, (no volume selection) */
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
+/*
+ * Z71V pin configuration:
+ * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?)
+ */
+static struct hda_verb alc880_pin_z71v_init_verbs[] = {
+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- /* c/lfe channel selector/amp: input 1: capture mix: muted, (no volume selection) */
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0x7180},
+ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- /* c/lfe channel selector/amp: output 0: unmuted, max volume */
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+ { }
+};
- /* c/lfe out pin: muted, (no volume selection) */
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+/*
+ * 6-stack pin configuration:
+ * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18, f-mic = 0x19,
+ * line = 0x1a, HP = 0x1b
+ */
+static struct hda_verb alc880_pin_6stack_init_verbs[] = {
+ {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
+
+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+
+ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+ {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+
+ { }
+};
- /* c/lfe out pin: NOT headphone enable, out enable, vref disabled */
- {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+/* FIXME! */
+/*
+ * F1734 pin configuration:
+ * HP = 0x14, speaker-out = 0x15, mic = 0x18
+ */
+static struct hda_verb alc880_pin_f1734_init_verbs[] = {
+ {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
+ {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
+ {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
+ {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+
+ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+ { }
+};
- /* hphone/speaker input selector: front DAC */
- {0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
+/* FIXME! */
+/*
+ * ASUS pin configuration:
+ * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a
+ */
+static struct hda_verb alc880_pin_asus_init_verbs[] = {
+ {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
+ {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
+ {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
+ {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+
+ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+
+ { }
+};
- /* hphone/speaker out pin: muted, (no volume selection) */
- {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+/* Enable GPIO mask and set output */
+static struct hda_verb alc880_gpio1_init_verbs[] = {
+ {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
+ {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
+ {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
+};
- /* hphone/speaker out pin: NOT headphone enable, out enable, vref disabled */
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+/* Enable GPIO mask and set output */
+static struct hda_verb alc880_gpio2_init_verbs[] = {
+ {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
+ {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
+ {0x01, AC_VERB_SET_GPIO_DATA, 0x02},
+};
- { }
-};
+/*
+ */
static int alc_init(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
- snd_hda_sequence_write(codec, spec->init_verbs);
+ unsigned int i;
+
+ for (i = 0; i < spec->num_init_verbs; i++)
+ snd_hda_sequence_write(codec, spec->init_verbs[i]);
return 0;
}
int i;
alc_init(codec);
- for (i = 0; i < spec->num_mixers; i++) {
+ for (i = 0; i < spec->num_mixers; i++)
snd_hda_resume_ctls(codec, spec->mixers[i]);
- }
if (spec->multiout.dig_out_nid)
snd_hda_resume_spdif_out(codec);
if (spec->dig_in_nid)
return 0;
}
-static int alc880_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
- struct hda_codec *codec,
- snd_pcm_substream_t *substream)
+static int alc880_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ snd_pcm_substream_t *substream)
+{
+ struct alc_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 alc880_pcm_analog_playback = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 8,
+ /* NID is set in alc_build_pcms */
+ .ops = {
+ .open = alc880_playback_pcm_open,
+ .prepare = alc880_playback_pcm_prepare,
+ .cleanup = alc880_playback_pcm_cleanup
+ },
+};
+
+static struct hda_pcm_stream alc880_pcm_analog_capture = {
+ .substreams = 2,
+ .channels_min = 2,
+ .channels_max = 2,
+ /* NID is set in alc_build_pcms */
+ .ops = {
+ .prepare = alc880_capture_pcm_prepare,
+ .cleanup = alc880_capture_pcm_cleanup
+ },
+};
+
+static struct hda_pcm_stream alc880_pcm_digital_playback = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 2,
+ /* NID is set in alc_build_pcms */
+ .ops = {
+ .open = alc880_dig_playback_pcm_open,
+ .close = alc880_dig_playback_pcm_close
+ },
+};
+
+static struct hda_pcm_stream alc880_pcm_digital_capture = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 2,
+ /* NID is set in alc_build_pcms */
+};
+
+static int alc_build_pcms(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ struct hda_pcm *info = spec->pcm_rec;
+ int i;
+
+ codec->num_pcms = 1;
+ codec->pcm_info = info;
+
+ info->name = spec->stream_name_analog;
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
+ info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
+ info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
+
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0;
+ for (i = 0; i < spec->num_channel_mode; i++) {
+ if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) {
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels;
+ }
+ }
+
+ if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
+ codec->num_pcms++;
+ info++;
+ info->name = spec->stream_name_digital;
+ if (spec->multiout.dig_out_nid) {
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_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] = *(spec->stream_digital_capture);
+ info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
+ }
+ }
+
+ return 0;
+}
+
+static void alc_free(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ unsigned int i;
+
+ if (! spec)
+ return;
+
+ if (spec->kctl_alloc) {
+ for (i = 0; i < spec->num_kctl_used; i++)
+ kfree(spec->kctl_alloc[i].name);
+ kfree(spec->kctl_alloc);
+ }
+ kfree(spec);
+}
+
+/*
+ */
+static struct hda_codec_ops alc_patch_ops = {
+ .build_controls = alc_build_controls,
+ .build_pcms = alc_build_pcms,
+ .init = alc_init,
+ .free = alc_free,
+#ifdef CONFIG_PM
+ .resume = alc_resume,
+#endif
+};
+
+
+/*
+ * Test configuration for debugging
+ *
+ * Almost all inputs/outputs are enabled. I/O pins can be configured via
+ * enum controls.
+ */
+#ifdef CONFIG_SND_DEBUG
+static hda_nid_t alc880_test_dac_nids[4] = {
+ 0x02, 0x03, 0x04, 0x05
+};
+
+static struct hda_input_mux alc880_test_capture_source = {
+ .num_items = 5,
+ .items = {
+ { "In-1", 0x0 },
+ { "In-2", 0x1 },
+ { "In-3", 0x2 },
+ { "In-4", 0x3 },
+ { "CD", 0x4 },
+ },
+};
+
+static struct alc_channel_mode alc880_test_modes[4] = {
+ { 2, NULL },
+ { 4, NULL },
+ { 6, NULL },
+ { 8, NULL },
+};
+
+static int alc_test_pin_ctl_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+ static char *texts[] = {
+ "N/A", "Line Out", "HP Out",
+ "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%"
+ };
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 8;
+ if (uinfo->value.enumerated.item >= 8)
+ uinfo->value.enumerated.item = 7;
+ strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+static int alc_test_pin_ctl_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
+ unsigned int pin_ctl, item = 0;
+
+ pin_ctl = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+ if (pin_ctl & AC_PINCTL_OUT_EN) {
+ if (pin_ctl & AC_PINCTL_HP_EN)
+ item = 2;
+ else
+ item = 1;
+ } else if (pin_ctl & AC_PINCTL_IN_EN) {
+ switch (pin_ctl & AC_PINCTL_VREFEN) {
+ case AC_PINCTL_VREF_HIZ: item = 3; break;
+ case AC_PINCTL_VREF_50: item = 4; break;
+ case AC_PINCTL_VREF_GRD: item = 5; break;
+ case AC_PINCTL_VREF_80: item = 6; break;
+ case AC_PINCTL_VREF_100: item = 7; break;
+ }
+ }
+ ucontrol->value.enumerated.item[0] = item;
+ return 0;
+}
+
+static int alc_test_pin_ctl_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
+ static unsigned int ctls[] = {
+ 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN,
+ AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ,
+ AC_PINCTL_IN_EN | AC_PINCTL_VREF_50,
+ AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD,
+ AC_PINCTL_IN_EN | AC_PINCTL_VREF_80,
+ AC_PINCTL_IN_EN | AC_PINCTL_VREF_100,
+ };
+ unsigned int old_ctl, new_ctl;
+
+ old_ctl = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+ new_ctl = ctls[ucontrol->value.enumerated.item[0]];
+ if (old_ctl != new_ctl) {
+ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, new_ctl);
+ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+ ucontrol->value.enumerated.item[0] >= 3 ? 0xb080 : 0xb000);
+ return 1;
+ }
+ return 0;
+}
+
+static int alc_test_pin_src_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+ static char *texts[] = {
+ "Front", "Surround", "CLFE", "Side"
+ };
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 4;
+ if (uinfo->value.enumerated.item >= 4)
+ uinfo->value.enumerated.item = 3;
+ strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+static int alc_test_pin_src_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
+ unsigned int sel;
+
+ sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0);
+ ucontrol->value.enumerated.item[0] = sel & 3;
+ return 0;
+}
+
+static int alc_test_pin_src_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
+ unsigned int sel;
+
+ sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3;
+ if (ucontrol->value.enumerated.item[0] != sel) {
+ sel = ucontrol->value.enumerated.item[0] & 3;
+ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, sel);
+ return 1;
+ }
+ return 0;
+}
+
+#define PIN_CTL_TEST(xname,nid) { \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .info = alc_test_pin_ctl_info, \
+ .get = alc_test_pin_ctl_get, \
+ .put = alc_test_pin_ctl_put, \
+ .private_value = nid \
+ }
+
+#define PIN_SRC_TEST(xname,nid) { \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .info = alc_test_pin_src_info, \
+ .get = alc_test_pin_src_get, \
+ .put = alc_test_pin_src_put, \
+ .private_value = nid \
+ }
+
+static snd_kcontrol_new_t alc880_test_mixer[] = {
+ HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
+ ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+ ALC_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
+ ALC_BIND_MUTE("CLFE Playback Volume", 0x0e, 2, HDA_INPUT),
+ ALC_BIND_MUTE("Side Playback Volume", 0x0f, 2, HDA_INPUT),
+ PIN_CTL_TEST("Front Pin Mode", 0x14),
+ PIN_CTL_TEST("Surround Pin Mode", 0x15),
+ PIN_CTL_TEST("CLFE Pin Mode", 0x16),
+ PIN_CTL_TEST("Side Pin Mode", 0x17),
+ PIN_CTL_TEST("In-1 Pin Mode", 0x18),
+ PIN_CTL_TEST("In-2 Pin Mode", 0x19),
+ PIN_CTL_TEST("In-3 Pin Mode", 0x1a),
+ PIN_CTL_TEST("In-4 Pin Mode", 0x1b),
+ PIN_SRC_TEST("In-1 Pin Source", 0x18),
+ PIN_SRC_TEST("In-2 Pin Source", 0x19),
+ PIN_SRC_TEST("In-3 Pin Source", 0x1a),
+ PIN_SRC_TEST("In-4 Pin Source", 0x1b),
+ HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT),
+ HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT),
+ HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT),
+ HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT),
+ HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT),
+ HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT),
+ HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Input Source",
+ .count = 2,
+ .info = alc_mux_enum_info,
+ .get = alc_mux_enum_get,
+ .put = alc_mux_enum_put,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Channel Mode",
+ .info = alc880_ch_mode_info,
+ .get = alc880_ch_mode_get,
+ .put = alc880_ch_mode_put,
+ },
+ { } /* end */
+};
+
+static struct hda_verb alc880_test_init_verbs[] = {
+ /* Unmute inputs of 0x0c - 0x0f */
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ /* Vol output for 0x0c-0x0f */
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ /* Set output pins 0x14-0x17 */
+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ /* Unmute output pins 0x14-0x17 */
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ /* Set input pins 0x18-0x1c */
+ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+ {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+ /* Mute input pins 0x18-0x1b */
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ /* ADC set up */
+ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
+ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
+ {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
+ /* Analog input/passthru */
+ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+ { }
+};
+#endif
+
+/*
+ */
+
+static struct hda_board_config alc880_cfg_tbl[] = {
+ /* Back 3 jack, front 2 jack */
+ { .modelname = "3stack", .config = ALC880_3ST },
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0xe200, .config = ALC880_3ST },
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0xe201, .config = ALC880_3ST },
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0xe202, .config = ALC880_3ST },
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0xe203, .config = ALC880_3ST },
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0xe204, .config = ALC880_3ST },
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0xe205, .config = ALC880_3ST },
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0xe206, .config = ALC880_3ST },
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0xe207, .config = ALC880_3ST },
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0xe208, .config = ALC880_3ST },
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0xe209, .config = ALC880_3ST },
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20a, .config = ALC880_3ST },
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20b, .config = ALC880_3ST },
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20c, .config = ALC880_3ST },
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20d, .config = ALC880_3ST },
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20e, .config = ALC880_3ST },
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20f, .config = ALC880_3ST },
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0xe210, .config = ALC880_3ST },
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0xe211, .config = ALC880_3ST },
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0xe214, .config = ALC880_3ST },
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0xe302, .config = ALC880_3ST },
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0xe303, .config = ALC880_3ST },
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0xe304, .config = ALC880_3ST },
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0xe306, .config = ALC880_3ST },
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0xe307, .config = ALC880_3ST },
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0xe404, .config = ALC880_3ST },
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0xa101, .config = ALC880_3ST },
+ { .pci_subvendor = 0x107b, .pci_subdevice = 0x3031, .config = ALC880_3ST },
+ { .pci_subvendor = 0x107b, .pci_subdevice = 0x4036, .config = ALC880_3ST },
+ { .pci_subvendor = 0x107b, .pci_subdevice = 0x4037, .config = ALC880_3ST },
+ { .pci_subvendor = 0x107b, .pci_subdevice = 0x4038, .config = ALC880_3ST },
+ { .pci_subvendor = 0x107b, .pci_subdevice = 0x4040, .config = ALC880_3ST },
+ { .pci_subvendor = 0x107b, .pci_subdevice = 0x4041, .config = ALC880_3ST },
+
+ /* Back 3 jack, front 2 jack (Internal add Aux-In) */
+ { .pci_subvendor = 0x1025, .pci_subdevice = 0xe310, .config = ALC880_3ST },
+ { .pci_subvendor = 0x104d, .pci_subdevice = 0x81d6, .config = ALC880_3ST },
+
+ /* Back 3 jack plus 1 SPDIF out jack, front 2 jack */
+ { .modelname = "3stack-digout", .config = ALC880_3ST_DIG },
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0xe308, .config = ALC880_3ST_DIG },
+
+ /* Back 3 jack plus 1 SPDIF out jack, front 2 jack (Internal add Aux-In)*/
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0xe305, .config = ALC880_3ST_DIG },
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0xd402, .config = ALC880_3ST_DIG },
+ { .pci_subvendor = 0x1025, .pci_subdevice = 0xe309, .config = ALC880_3ST_DIG },
+
+ /* Back 5 jack, front 2 jack */
+ { .modelname = "5stack", .config = ALC880_5ST },
+ { .pci_subvendor = 0x107b, .pci_subdevice = 0x3033, .config = ALC880_5ST },
+ { .pci_subvendor = 0x107b, .pci_subdevice = 0x4039, .config = ALC880_5ST },
+ { .pci_subvendor = 0x107b, .pci_subdevice = 0x3032, .config = ALC880_5ST },
+ { .pci_subvendor = 0x103c, .pci_subdevice = 0x2a09, .config = ALC880_5ST },
+ { .pci_subvendor = 0x1043, .pci_subdevice = 0x814e, .config = ALC880_5ST },
+
+ /* Back 5 jack plus 1 SPDIF out jack, front 2 jack */
+ { .modelname = "5stack-digout", .config = ALC880_5ST_DIG },
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0xe224, .config = ALC880_5ST_DIG },
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0xe400, .config = ALC880_5ST_DIG },
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0xe401, .config = ALC880_5ST_DIG },
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0xe402, .config = ALC880_5ST_DIG },
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0xd400, .config = ALC880_5ST_DIG },
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0xd401, .config = ALC880_5ST_DIG },
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0xa100, .config = ALC880_5ST_DIG },
+ { .pci_subvendor = 0x1565, .pci_subdevice = 0x8202, .config = ALC880_5ST_DIG },
+ { .pci_subvendor = 0x1019, .pci_subdevice = 0xa880, .config = ALC880_5ST_DIG },
+ { .pci_subvendor = 0x1019, .pci_subdevice = 0xa884, .config = ALC880_5ST_DIG },
+ { .pci_subvendor = 0x1695, .pci_subdevice = 0x400d, .config = ALC880_5ST_DIG },
+ { .pci_subvendor = 0x0000, .pci_subdevice = 0x8086, .config = ALC880_5ST_DIG },
+
+ { .modelname = "w810", .config = ALC880_W810 },
+ { .pci_subvendor = 0x161f, .pci_subdevice = 0x203d, .config = ALC880_W810 },
+
+ { .modelname = "z71v", .config = ALC880_Z71V },
+ { .pci_subvendor = 0x1043, .pci_subdevice = 0x1964, .config = ALC880_Z71V },
+
+ { .modelname = "6statack-digout", .config = ALC880_6ST_DIG },
+ { .pci_subvendor = 0x2668, .pci_subdevice = 0x8086, .config = ALC880_6ST_DIG },
+ { .pci_subvendor = 0x8086, .pci_subdevice = 0x2668, .config = ALC880_6ST_DIG },
+ { .pci_subvendor = 0x1462, .pci_subdevice = 0x1150, .config = ALC880_6ST_DIG },
+ { .pci_subvendor = 0xe803, .pci_subdevice = 0x1019, .config = ALC880_6ST_DIG },
+
+ { .modelname = "asus", .config = ALC880_ASUS },
+ { .pci_subvendor = 0x1043, .pci_subdevice = 0x1964, .config = ALC880_ASUS_DIG },
+ { .pci_subvendor = 0x1043, .pci_subdevice = 0x1973, .config = ALC880_ASUS_DIG },
+ { .pci_subvendor = 0x1043, .pci_subdevice = 0x19b3, .config = ALC880_ASUS_DIG },
+ { .pci_subvendor = 0x1043, .pci_subdevice = 0x1113, .config = ALC880_ASUS_DIG },
+ { .pci_subvendor = 0x1043, .pci_subdevice = 0x1993, .config = ALC880_ASUS },
+ { .pci_subvendor = 0x1043, .pci_subdevice = 0x10c3, .config = ALC880_ASUS_DIG },
+ { .pci_subvendor = 0x1043, .pci_subdevice = 0x1133, .config = ALC880_ASUS },
+ { .pci_subvendor = 0x1043, .pci_subdevice = 0x1123, .config = ALC880_ASUS_DIG },
+ { .pci_subvendor = 0x1043, .pci_subdevice = 0x1143, .config = ALC880_ASUS },
+ { .pci_subvendor = 0x1043, .pci_subdevice = 0x10b3, .config = ALC880_ASUS_W1V },
+
+ { .modelname = "uniwill", .config = ALC880_UNIWILL_DIG },
+ { .pci_subvendor = 0x1584, .pci_subdevice = 0x9050, .config = ALC880_UNIWILL_DIG },
+
+ { .modelname = "F1734", .config = ALC880_F1734 },
+ { .pci_subvendor = 0x1734, .pci_subdevice = 0x107c, .config = ALC880_F1734 },
+
+#ifdef CONFIG_SND_DEBUG
+ { .modelname = "test", .config = ALC880_TEST },
+#endif
+
+ {}
+};
+
+/*
+ * configuration template - to be copied to the spec instance
+ */
+struct alc_config_preset {
+ snd_kcontrol_new_t *mixers[4];
+ const struct hda_verb *init_verbs[4];
+ unsigned int num_dacs;
+ hda_nid_t *dac_nids;
+ hda_nid_t dig_out_nid; /* optional */
+ hda_nid_t hp_nid; /* optional */
+ unsigned int num_adc_nids;
+ hda_nid_t *adc_nids;
+ unsigned int num_channel_mode;
+ const struct alc_channel_mode *channel_mode;
+ const struct hda_input_mux *input_mux;
+};
+
+static struct alc_config_preset alc880_presets[] = {
+ [ALC880_3ST] = {
+ .mixers = { alc880_three_stack_mixer },
+ .init_verbs = { alc880_volume_init_verbs, alc880_pin_3stack_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc880_dac_nids),
+ .dac_nids = alc880_dac_nids,
+ .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
+ .channel_mode = alc880_threestack_modes,
+ .input_mux = &alc880_capture_source,
+ },
+ [ALC880_3ST_DIG] = {
+ .mixers = { alc880_three_stack_mixer },
+ .init_verbs = { alc880_volume_init_verbs, alc880_pin_3stack_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc880_dac_nids),
+ .dac_nids = alc880_dac_nids,
+ .dig_out_nid = ALC880_DIGOUT_NID,
+ .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
+ .channel_mode = alc880_threestack_modes,
+ .input_mux = &alc880_capture_source,
+ },
+ [ALC880_5ST] = {
+ .mixers = { alc880_three_stack_mixer, alc880_five_stack_mixer},
+ .init_verbs = { alc880_volume_init_verbs, alc880_pin_5stack_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc880_dac_nids),
+ .dac_nids = alc880_dac_nids,
+ .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
+ .channel_mode = alc880_fivestack_modes,
+ .input_mux = &alc880_capture_source,
+ },
+ [ALC880_5ST_DIG] = {
+ .mixers = { alc880_three_stack_mixer, alc880_five_stack_mixer },
+ .init_verbs = { alc880_volume_init_verbs, alc880_pin_5stack_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc880_dac_nids),
+ .dac_nids = alc880_dac_nids,
+ .dig_out_nid = ALC880_DIGOUT_NID,
+ .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
+ .channel_mode = alc880_fivestack_modes,
+ .input_mux = &alc880_capture_source,
+ },
+ [ALC880_6ST_DIG] = {
+ .mixers = { alc880_six_stack_mixer },
+ .init_verbs = { alc880_volume_init_verbs, alc880_pin_6stack_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
+ .dac_nids = alc880_6st_dac_nids,
+ .dig_out_nid = ALC880_DIGOUT_NID,
+ .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
+ .channel_mode = alc880_sixstack_modes,
+ .input_mux = &alc880_6stack_capture_source,
+ },
+ [ALC880_W810] = {
+ .mixers = { alc880_w810_base_mixer },
+ .init_verbs = { alc880_volume_init_verbs, alc880_pin_w810_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids),
+ .dac_nids = alc880_w810_dac_nids,
+ .dig_out_nid = ALC880_DIGOUT_NID,
+ .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
+ .channel_mode = alc880_w810_modes,
+ .input_mux = &alc880_capture_source,
+ },
+ [ALC880_Z71V] = {
+ .mixers = { alc880_z71v_mixer },
+ .init_verbs = { alc880_volume_init_verbs, alc880_pin_z71v_init_verbs,
+ alc880_gpio2_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids),
+ .dac_nids = alc880_z71v_dac_nids,
+ .dig_out_nid = ALC880_DIGOUT_NID,
+ .hp_nid = 0x03,
+ .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
+ .channel_mode = alc880_2_jack_modes,
+ .input_mux = &alc880_capture_source,
+ },
+ [ALC880_F1734] = {
+ .mixers = { alc880_f1734_mixer },
+ .init_verbs = { alc880_volume_init_verbs, alc880_pin_f1734_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids),
+ .dac_nids = alc880_f1734_dac_nids,
+ .hp_nid = 0x02,
+ .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
+ .channel_mode = alc880_2_jack_modes,
+ .input_mux = &alc880_capture_source,
+ },
+ [ALC880_ASUS] = {
+ .mixers = { alc880_asus_mixer },
+ .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs,
+ alc880_gpio1_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
+ .dac_nids = alc880_asus_dac_nids,
+ .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
+ .channel_mode = alc880_asus_modes,
+ .input_mux = &alc880_capture_source,
+ },
+ [ALC880_ASUS_DIG] = {
+ .mixers = { alc880_asus_mixer },
+ .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs,
+ alc880_gpio1_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
+ .dac_nids = alc880_asus_dac_nids,
+ .dig_out_nid = ALC880_DIGOUT_NID,
+ .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
+ .channel_mode = alc880_asus_modes,
+ .input_mux = &alc880_capture_source,
+ },
+ [ALC880_ASUS_W1V] = {
+ .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer },
+ .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs,
+ alc880_gpio1_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
+ .dac_nids = alc880_asus_dac_nids,
+ .dig_out_nid = ALC880_DIGOUT_NID,
+ .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
+ .channel_mode = alc880_asus_modes,
+ .input_mux = &alc880_capture_source,
+ },
+ [ALC880_UNIWILL_DIG] = {
+ .mixers = { alc880_asus_mixer },
+ .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
+ .dac_nids = alc880_asus_dac_nids,
+ .dig_out_nid = ALC880_DIGOUT_NID,
+ .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
+ .channel_mode = alc880_asus_modes,
+ .input_mux = &alc880_capture_source,
+ },
+#ifdef CONFIG_SND_DEBUG
+ [ALC880_TEST] = {
+ .mixers = { alc880_test_mixer },
+ .init_verbs = { alc880_test_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc880_test_dac_nids),
+ .dac_nids = alc880_test_dac_nids,
+ .dig_out_nid = ALC880_DIGOUT_NID,
+ .num_channel_mode = ARRAY_SIZE(alc880_test_modes),
+ .channel_mode = alc880_test_modes,
+ .input_mux = &alc880_test_capture_source,
+ },
+#endif
+};
+
+/*
+ * Automatic parse of I/O pins from the BIOS configuration
+ */
+
+#define NUM_CONTROL_ALLOC 32
+#define NUM_VERB_ALLOC 32
+
+enum {
+ ALC_CTL_WIDGET_VOL,
+ ALC_CTL_WIDGET_MUTE,
+ ALC_CTL_BIND_MUTE,
+};
+static snd_kcontrol_new_t alc880_control_templates[] = {
+ HDA_CODEC_VOLUME(NULL, 0, 0, 0),
+ HDA_CODEC_MUTE(NULL, 0, 0, 0),
+ ALC_BIND_MUTE(NULL, 0, 0, 0),
+};
+
+/* add dynamic controls */
+static int add_control(struct alc_spec *spec, int type, const char *name, unsigned long val)
+{
+ snd_kcontrol_new_t *knew;
+
+ if (spec->num_kctl_used >= spec->num_kctl_alloc) {
+ int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
+
+ knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */
+ if (! knew)
+ return -ENOMEM;
+ if (spec->kctl_alloc) {
+ memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc);
+ kfree(spec->kctl_alloc);
+ }
+ spec->kctl_alloc = knew;
+ spec->num_kctl_alloc = num;
+ }
+
+ knew = &spec->kctl_alloc[spec->num_kctl_used];
+ *knew = alc880_control_templates[type];
+ knew->name = snd_kmalloc_strdup(name, GFP_KERNEL);
+ if (! knew->name)
+ return -ENOMEM;
+ knew->private_value = val;
+ spec->num_kctl_used++;
+ return 0;
+}
+
+#define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17)
+#define alc880_fixed_pin_idx(nid) ((nid) - 0x14)
+#define alc880_is_multi_pin(nid) ((nid) >= 0x18)
+#define alc880_multi_pin_idx(nid) ((nid) - 0x18)
+#define alc880_is_input_pin(nid) ((nid) >= 0x18)
+#define alc880_input_pin_idx(nid) ((nid) - 0x18)
+#define alc880_idx_to_dac(nid) ((nid) + 0x02)
+#define alc880_dac_to_idx(nid) ((nid) - 0x02)
+#define alc880_idx_to_mixer(nid) ((nid) + 0x0c)
+#define alc880_idx_to_selector(nid) ((nid) + 0x10)
+#define ALC880_PIN_CD_NID 0x1c
+
+/* fill in the dac_nids table from the parsed pin configuration */
+static int alc880_auto_fill_dac_nids(struct alc_spec *spec, const struct auto_pin_cfg *cfg)
+{
+ hda_nid_t nid;
+ int assigned[4];
+ int i, j;
+
+ memset(assigned, 0, sizeof(assigned));
+
+ /* check the pins hardwired to audio widget */
+ for (i = 0; i < cfg->line_outs; i++) {
+ nid = cfg->line_out_pins[i];
+ if (alc880_is_fixed_pin(nid)) {
+ int idx = alc880_fixed_pin_idx(nid);
+ spec->multiout.dac_nids[i] = alc880_dac_to_idx(idx);
+ assigned[idx] = 1;
+ }
+ }
+ /* left pins can be connect to any audio widget */
+ for (i = 0; i < cfg->line_outs; i++) {
+ nid = cfg->line_out_pins[i];
+ if (alc880_is_fixed_pin(nid))
+ continue;
+ /* search for an empty channel */
+ for (j = 0; j < cfg->line_outs; j++) {
+ if (! assigned[j]) {
+ spec->multiout.dac_nids[i] = alc880_idx_to_dac(j);
+ assigned[j] = 1;
+ break;
+ }
+ }
+ }
+ spec->multiout.num_dacs = cfg->line_outs;
+ return 0;
+}
+
+/* add playback controls from the parsed DAC table */
+static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg)
{
- struct alc_spec *spec = codec->spec;
+ char name[32];
+ static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" };
+ hda_nid_t nid;
+ int i, err;
+
+ for (i = 0; i < cfg->line_outs; i++) {
+ if (! spec->multiout.dac_nids[i])
+ continue;
+ nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i]));
+ if (i == 2) {
+ /* Center/LFE */
+ if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Center Playback Volume",
+ HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT))) < 0)
+ return err;
+ if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "LFE Playback Volume",
+ HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0)
+ return err;
+ if ((err = add_control(spec, ALC_CTL_BIND_MUTE, "Center Playback Switch",
+ HDA_COMPOSE_AMP_VAL(nid, 1, 2, HDA_INPUT))) < 0)
+ return err;
+ if ((err = add_control(spec, ALC_CTL_BIND_MUTE, "LFE Playback Switch",
+ HDA_COMPOSE_AMP_VAL(nid, 2, 2, HDA_INPUT))) < 0)
+ return err;
+ } else {
+ sprintf(name, "%s Playback Volume", chname[i]);
+ if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
+ HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0)
+ return err;
+ sprintf(name, "%s Playback Switch", chname[i]);
+ if ((err = add_control(spec, ALC_CTL_BIND_MUTE, name,
+ HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT))) < 0)
+ return err;
+ }
+ }
- snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 0, 0, 0);
return 0;
}
+/* add playback controls for HP output */
+static int alc880_auto_create_hp_ctls(struct alc_spec *spec, hda_nid_t pin)
+{
+ hda_nid_t nid;
+ int err;
-/*
- */
-static struct hda_pcm_stream alc880_pcm_analog_playback = {
- .substreams = 1,
- .channels_min = 2,
- .channels_max = 8,
- .nid = 0x02, /* NID to query formats and rates */
- .ops = {
- .open = alc880_playback_pcm_open,
- .prepare = alc880_playback_pcm_prepare,
- .cleanup = alc880_playback_pcm_cleanup
- },
-};
+ if (! pin)
+ return 0;
-static struct hda_pcm_stream alc880_pcm_analog_capture = {
- .substreams = 2,
- .channels_min = 2,
- .channels_max = 2,
- .nid = 0x07, /* NID to query formats and rates */
- .ops = {
- .prepare = alc880_capture_pcm_prepare,
- .cleanup = alc880_capture_pcm_cleanup
- },
-};
+ if (alc880_is_fixed_pin(pin)) {
+ nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
+ if (! spec->multiout.dac_nids[0]) {
+ /* use this as the primary output */
+ spec->multiout.dac_nids[0] = nid;
+ if (! spec->multiout.num_dacs)
+ spec->multiout.num_dacs = 1;
+ } else
+ /* specify the DAC as the extra HP output */
+ spec->multiout.hp_nid = nid;
+ /* control HP volume/switch on the output mixer amp */
+ nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin));
+ if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Headphone Playback Volume",
+ HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0)
+ return err;
+ if ((err = add_control(spec, ALC_CTL_BIND_MUTE, "Headphone Playback Switch",
+ HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT))) < 0)
+ return err;
+ } else if (alc880_is_multi_pin(pin)) {
+ /* set manual connection */
+ if (! spec->multiout.dac_nids[0]) {
+ /* use this as the primary output */
+ spec->multiout.dac_nids[0] = alc880_idx_to_dac(alc880_multi_pin_idx(pin));
+ if (! spec->multiout.num_dacs)
+ spec->multiout.num_dacs = 1;
+ }
+ /* we have only a switch on HP-out PIN */
+ if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, "Headphone Playback Switch",
+ HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT))) < 0)
+ return err;
+ }
+ return 0;
+}
-static struct hda_pcm_stream alc880_pcm_digital_playback = {
- .substreams = 1,
- .channels_min = 2,
- .channels_max = 2,
- /* NID is set in alc_build_pcms */
- .ops = {
- .open = alc880_dig_playback_pcm_open,
- .close = alc880_dig_playback_pcm_close
- },
-};
+/* create input playback/capture controls for the given pin */
+static int new_analog_input(struct alc_spec *spec, hda_nid_t pin, const char *ctlname)
+{
+ char name[32];
+ int err, idx;
+
+ sprintf(name, "%s Playback Volume", ctlname);
+ idx = alc880_input_pin_idx(pin);
+ if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
+ HDA_COMPOSE_AMP_VAL(0x0b, 3, idx, HDA_INPUT))) < 0)
+ return err;
+ sprintf(name, "%s Playback Switch", ctlname);
+ if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
+ HDA_COMPOSE_AMP_VAL(0x0b, 3, idx, HDA_INPUT))) < 0)
+ return err;
+ return 0;
+}
-static struct hda_pcm_stream alc880_pcm_digital_capture = {
- .substreams = 1,
- .channels_min = 2,
- .channels_max = 2,
- /* NID is set in alc_build_pcms */
-};
+/* create playback/capture controls for input pins */
+static int alc880_auto_create_analog_input_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg)
+{
+ static char *labels[AUTO_PIN_LAST] = {
+ "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux"
+ };
+ struct hda_input_mux *imux = &spec->private_imux;
+ int i, err;
+
+ for (i = 0; i < AUTO_PIN_LAST; i++) {
+ if (alc880_is_input_pin(cfg->input_pins[i])) {
+ err = new_analog_input(spec, cfg->input_pins[i], labels[i]);
+ if (err < 0)
+ return err;
+ imux->items[imux->num_items].label = labels[i];
+ imux->items[imux->num_items].index = alc880_input_pin_idx(cfg->input_pins[i]);
+ imux->num_items++;
+ }
+ }
+ return 0;
+}
-static int alc_build_pcms(struct hda_codec *codec)
+static void alc880_auto_set_output_and_unmute(struct hda_codec *codec, hda_nid_t nid, int pin_type,
+ int dac_idx)
+{
+ /* set as output */
+ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
+ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+ /* need the manual connection? */
+ if (alc880_is_multi_pin(nid)) {
+ struct alc_spec *spec = codec->spec;
+ int idx = alc880_multi_pin_idx(nid);
+ snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
+ AC_VERB_SET_CONNECT_SEL,
+ alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
+ }
+}
+
+static void alc880_auto_init_multi_out(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
- struct hda_pcm *info = spec->pcm_rec;
int i;
- codec->num_pcms = 1;
- codec->pcm_info = info;
-
- info->name = spec->stream_name_analog;
- info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
- info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
-
- info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0;
- for (i = 0; i < spec->num_channel_mode; i++) {
- if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) {
- info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels;
- }
+ for (i = 0; i < spec->autocfg.line_outs; i++) {
+ hda_nid_t nid = spec->autocfg.line_out_pins[i];
+ alc880_auto_set_output_and_unmute(codec, nid, PIN_OUT, i);
}
+}
- if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
- codec->num_pcms++;
- info++;
- info->name = spec->stream_name_digital;
- if (spec->multiout.dig_out_nid) {
- info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_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] = *(spec->stream_digital_capture);
- info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
- }
- }
+static void alc880_auto_init_hp_out(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ hda_nid_t pin;
- return 0;
+ pin = spec->autocfg.hp_pin;
+ if (pin) /* connect to front */
+ alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
}
-static void alc_free(struct hda_codec *codec)
+static void alc880_auto_init_analog_input(struct hda_codec *codec)
{
- kfree(codec->spec);
+ struct alc_spec *spec = codec->spec;
+ int i;
+
+ for (i = 0; i < AUTO_PIN_LAST; i++) {
+ hda_nid_t nid = spec->autocfg.input_pins[i];
+ if (alc880_is_input_pin(nid)) {
+ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+ i <= AUTO_PIN_FRONT_MIC ? PIN_VREF80 : PIN_IN);
+ if (nid != ALC880_PIN_CD_NID)
+ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+ AMP_OUT_MUTE);
+ }
+ }
}
-/*
- */
-static struct hda_codec_ops alc_patch_ops = {
- .build_controls = alc_build_controls,
- .build_pcms = alc_build_pcms,
- .init = alc_init,
- .free = alc_free,
-#ifdef CONFIG_PM
- .resume = alc_resume,
-#endif
-};
+/* parse the BIOS configuration and set up the alc_spec */
+/* return 1 if successful, 0 if the proper config is not found, or a negative error code */
+static int alc880_parse_auto_config(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ int err;
-/*
- */
+ if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg)) < 0)
+ return err;
+ if ((err = alc880_auto_fill_dac_nids(spec, &spec->autocfg)) < 0)
+ return err;
+ if (! spec->autocfg.line_outs && ! spec->autocfg.hp_pin)
+ return 0; /* can't find valid BIOS pin config */
+ if ((err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 ||
+ (err = alc880_auto_create_hp_ctls(spec, spec->autocfg.hp_pin)) < 0 ||
+ (err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0)
+ return err;
-static struct hda_board_config alc880_cfg_tbl[] = {
- /* Back 3 jack, front 2 jack */
- { .modelname = "3stack", .config = ALC880_3ST },
- { .pci_vendor = 0x8086, .pci_device = 0xe200, .config = ALC880_3ST },
- { .pci_vendor = 0x8086, .pci_device = 0xe201, .config = ALC880_3ST },
- { .pci_vendor = 0x8086, .pci_device = 0xe202, .config = ALC880_3ST },
- { .pci_vendor = 0x8086, .pci_device = 0xe203, .config = ALC880_3ST },
- { .pci_vendor = 0x8086, .pci_device = 0xe204, .config = ALC880_3ST },
- { .pci_vendor = 0x8086, .pci_device = 0xe205, .config = ALC880_3ST },
- { .pci_vendor = 0x8086, .pci_device = 0xe206, .config = ALC880_3ST },
- { .pci_vendor = 0x8086, .pci_device = 0xe207, .config = ALC880_3ST },
- { .pci_vendor = 0x8086, .pci_device = 0xe208, .config = ALC880_3ST },
- { .pci_vendor = 0x8086, .pci_device = 0xe209, .config = ALC880_3ST },
- { .pci_vendor = 0x8086, .pci_device = 0xe20a, .config = ALC880_3ST },
- { .pci_vendor = 0x8086, .pci_device = 0xe20b, .config = ALC880_3ST },
- { .pci_vendor = 0x8086, .pci_device = 0xe20c, .config = ALC880_3ST },
- { .pci_vendor = 0x8086, .pci_device = 0xe20d, .config = ALC880_3ST },
- { .pci_vendor = 0x8086, .pci_device = 0xe20e, .config = ALC880_3ST },
- { .pci_vendor = 0x8086, .pci_device = 0xe20f, .config = ALC880_3ST },
- { .pci_vendor = 0x8086, .pci_device = 0xe210, .config = ALC880_3ST },
- { .pci_vendor = 0x8086, .pci_device = 0xe211, .config = ALC880_3ST },
- { .pci_vendor = 0x8086, .pci_device = 0xe214, .config = ALC880_3ST },
- { .pci_vendor = 0x8086, .pci_device = 0xe302, .config = ALC880_3ST },
- { .pci_vendor = 0x8086, .pci_device = 0xe303, .config = ALC880_3ST },
- { .pci_vendor = 0x8086, .pci_device = 0xe304, .config = ALC880_3ST },
- { .pci_vendor = 0x8086, .pci_device = 0xe306, .config = ALC880_3ST },
- { .pci_vendor = 0x8086, .pci_device = 0xe307, .config = ALC880_3ST },
- { .pci_vendor = 0x8086, .pci_device = 0xe404, .config = ALC880_3ST },
- { .pci_vendor = 0x8086, .pci_device = 0xa101, .config = ALC880_3ST },
- { .pci_vendor = 0x107b, .pci_device = 0x3031, .config = ALC880_3ST },
- { .pci_vendor = 0x107b, .pci_device = 0x4036, .config = ALC880_3ST },
- { .pci_vendor = 0x107b, .pci_device = 0x4037, .config = ALC880_3ST },
- { .pci_vendor = 0x107b, .pci_device = 0x4038, .config = ALC880_3ST },
- { .pci_vendor = 0x107b, .pci_device = 0x4040, .config = ALC880_3ST },
- { .pci_vendor = 0x107b, .pci_device = 0x4041, .config = ALC880_3ST },
+ spec->multiout.max_channels = spec->multiout.num_dacs * 2;
- /* Back 3 jack, front 2 jack (Internal add Aux-In) */
- { .pci_vendor = 0x1025, .pci_device = 0xe310, .config = ALC880_3ST },
+ if (spec->autocfg.dig_out_pin)
+ spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
+ if (spec->autocfg.dig_in_pin)
+ spec->dig_in_nid = ALC880_DIGIN_NID;
- /* Back 3 jack plus 1 SPDIF out jack, front 2 jack */
- { .modelname = "3stack-digout", .config = ALC880_3ST_DIG },
- { .pci_vendor = 0x8086, .pci_device = 0xe308, .config = ALC880_3ST_DIG },
+ if (spec->kctl_alloc)
+ spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
- /* Back 3 jack plus 1 SPDIF out jack, front 2 jack (Internal add Aux-In)*/
- { .pci_vendor = 0x8086, .pci_device = 0xe305, .config = ALC880_3ST_DIG },
- { .pci_vendor = 0x8086, .pci_device = 0xd402, .config = ALC880_3ST_DIG },
- { .pci_vendor = 0x1025, .pci_device = 0xe309, .config = ALC880_3ST_DIG },
+ spec->init_verbs[spec->num_init_verbs++] = alc880_volume_init_verbs;
- /* Back 5 jack, front 2 jack */
- { .modelname = "5stack", .config = ALC880_5ST },
- { .pci_vendor = 0x107b, .pci_device = 0x3033, .config = ALC880_5ST },
- { .pci_vendor = 0x107b, .pci_device = 0x4039, .config = ALC880_5ST },
- { .pci_vendor = 0x107b, .pci_device = 0x3032, .config = ALC880_5ST },
- { .pci_vendor = 0x103c, .pci_device = 0x2a09, .config = ALC880_5ST },
+ spec->input_mux = &spec->private_imux;
- /* Back 5 jack plus 1 SPDIF out jack, front 2 jack */
- { .modelname = "5stack-digout", .config = ALC880_5ST_DIG },
- { .pci_vendor = 0x8086, .pci_device = 0xe224, .config = ALC880_5ST_DIG },
- { .pci_vendor = 0x8086, .pci_device = 0xe400, .config = ALC880_5ST_DIG },
- { .pci_vendor = 0x8086, .pci_device = 0xe401, .config = ALC880_5ST_DIG },
- { .pci_vendor = 0x8086, .pci_device = 0xe402, .config = ALC880_5ST_DIG },
- { .pci_vendor = 0x8086, .pci_device = 0xd400, .config = ALC880_5ST_DIG },
- { .pci_vendor = 0x8086, .pci_device = 0xd401, .config = ALC880_5ST_DIG },
- { .pci_vendor = 0x8086, .pci_device = 0xa100, .config = ALC880_5ST_DIG },
- { .pci_vendor = 0x1565, .pci_device = 0x8202, .config = ALC880_5ST_DIG },
+ return 1;
+}
- { .modelname = "w810", .config = ALC880_W810 },
- { .pci_vendor = 0x161f, .pci_device = 0x203d, .config = ALC880_W810 },
+/* init callback for auto-configuration model -- overriding the default init */
+static int alc880_auto_init(struct hda_codec *codec)
+{
+ alc_init(codec);
+ alc880_auto_init_multi_out(codec);
+ alc880_auto_init_hp_out(codec);
+ alc880_auto_init_analog_input(codec);
+ return 0;
+}
- {}
-};
+/*
+ * OK, here we have finally the patch for ALC880
+ */
static int patch_alc880(struct hda_codec *codec)
{
struct alc_spec *spec;
int board_config;
+ int i, err;
spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
if (spec == NULL)
return -ENOMEM;
+ init_MUTEX(&spec->bind_mutex);
codec->spec = spec;
board_config = snd_hda_check_board_config(codec, alc880_cfg_tbl);
- if (board_config < 0) {
- snd_printd(KERN_INFO "hda_codec: Unknown model for ALC880\n");
- board_config = ALC880_MINIMAL;
+ if (board_config < 0 || board_config >= ALC880_MODEL_LAST) {
+ printk(KERN_INFO "hda_codec: Unknown model for ALC880, trying auto-probe from BIOS...\n");
+ board_config = ALC880_AUTO;
}
- switch (board_config) {
- case ALC880_W810:
- spec->mixers[spec->num_mixers] = alc880_w810_base_mixer;
- spec->num_mixers++;
- break;
- case ALC880_5ST:
- case ALC880_5ST_DIG:
- spec->mixers[spec->num_mixers] = alc880_five_stack_mixer;
- spec->num_mixers++;
- break;
- default:
- spec->mixers[spec->num_mixers] = alc880_base_mixer;
- spec->num_mixers++;
- break;
+ if (board_config == ALC880_AUTO) {
+ /* automatic parse from the BIOS config */
+ err = alc880_parse_auto_config(codec);
+ if (err < 0) {
+ alc_free(codec);
+ return err;
+ } else if (! err) {
+ printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS. Using 3-stack mode...\n");
+ board_config = ALC880_3ST;
+ }
}
- switch (board_config) {
- case ALC880_3ST_DIG:
- case ALC880_5ST_DIG:
- case ALC880_W810:
- spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
- break;
- default:
- break;
- }
+ if (board_config != ALC880_AUTO) {
+ /* set up from the preset table */
+ const struct alc_config_preset *preset;
- switch (board_config) {
- case ALC880_3ST:
- case ALC880_3ST_DIG:
- case ALC880_5ST:
- case ALC880_5ST_DIG:
- case ALC880_W810:
- spec->front_panel = 1;
- break;
- default:
- break;
- }
+ preset = &alc880_presets[board_config];
- switch (board_config) {
- case ALC880_5ST:
- case ALC880_5ST_DIG:
- spec->init_verbs = alc880_init_verbs_five_stack;
- spec->channel_mode = alc880_fivestack_modes;
- spec->num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes);
- break;
- case ALC880_W810:
- spec->init_verbs = alc880_w810_init_verbs;
- spec->channel_mode = alc880_w810_modes;
- spec->num_channel_mode = ARRAY_SIZE(alc880_w810_modes);
- break;
- default:
- spec->init_verbs = alc880_init_verbs_three_stack;
- spec->channel_mode = alc880_threestack_modes;
- spec->num_channel_mode = ARRAY_SIZE(alc880_threestack_modes);
- break;
+ for (i = 0; preset->mixers[i]; i++) {
+ snd_assert(spec->num_mixers < ARRAY_SIZE(spec->mixers), break);
+ spec->mixers[spec->num_mixers++] = preset->mixers[i];
+ }
+ for (i = 0; preset->init_verbs[i]; i++) {
+ snd_assert(spec->num_init_verbs < ARRAY_SIZE(spec->init_verbs), break);
+ spec->init_verbs[spec->num_init_verbs++] = preset->init_verbs[i];
+ }
+
+ spec->channel_mode = preset->channel_mode;
+ spec->num_channel_mode = preset->num_channel_mode;
+
+ spec->multiout.max_channels = spec->channel_mode[0].channels;
+
+ spec->multiout.num_dacs = preset->num_dacs;
+ spec->multiout.dac_nids = preset->dac_nids;
+ spec->multiout.dig_out_nid = preset->dig_out_nid;
+ spec->multiout.hp_nid = preset->hp_nid;
+
+ spec->input_mux = preset->input_mux;
+
+ spec->num_adc_nids = preset->num_adc_nids;
+ spec->adc_nids = preset->adc_nids;
}
spec->stream_name_analog = "ALC880 Analog";
spec->stream_digital_playback = &alc880_pcm_digital_playback;
spec->stream_digital_capture = &alc880_pcm_digital_capture;
- spec->multiout.max_channels = spec->channel_mode[0].channels;
-
- switch (board_config) {
- case ALC880_W810:
- spec->multiout.num_dacs = ARRAY_SIZE(alc880_w810_dac_nids);
- spec->multiout.dac_nids = alc880_w810_dac_nids;
- // No dedicated headphone socket - it's shared with built-in speakers.
- break;
- default:
- spec->multiout.num_dacs = ARRAY_SIZE(alc880_dac_nids);
- spec->multiout.dac_nids = alc880_dac_nids;
- spec->multiout.hp_nid = 0x03; /* rear-surround NID */
- break;
+ if (! spec->adc_nids && spec->input_mux) {
+ /* check whether NID 0x07 is valid */
+ unsigned int wcap = snd_hda_param_read(codec, alc880_adc_nids[0],
+ AC_PAR_AUDIO_WIDGET_CAP);
+ wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; /* get type */
+ if (wcap != AC_WID_AUD_IN) {
+ spec->adc_nids = alc880_adc_nids_alt;
+ spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt);
+ spec->mixers[spec->num_mixers] = alc880_capture_alt_mixer;
+ spec->num_mixers++;
+ } else {
+ spec->adc_nids = alc880_adc_nids;
+ spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids);
+ spec->mixers[spec->num_mixers] = alc880_capture_mixer;
+ spec->num_mixers++;
+ }
}
- spec->input_mux = &alc880_capture_source;
- spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids);
- spec->adc_nids = alc880_adc_nids;
-
codec->patch_ops = alc_patch_ops;
+ if (board_config == ALC880_AUTO)
+ codec->patch_ops.init = alc880_auto_init;
return 0;
}
+
/*
* ALC260 support
*/
+static hda_nid_t alc260_dac_nids[1] = {
+ /* front */
+ 0x02,
+};
+
+static hda_nid_t alc260_adc_nids[1] = {
+ /* ADC0 */
+ 0x04,
+};
+
+static hda_nid_t alc260_hp_adc_nids[1] = {
+ /* ADC1 */
+ 0x05,
+};
+
+#define ALC260_DIGOUT_NID 0x03
+#define ALC260_DIGIN_NID 0x06
+
+static struct hda_input_mux alc260_capture_source = {
+ .num_items = 4,
+ .items = {
+ { "Mic", 0x0 },
+ { "Front Mic", 0x1 },
+ { "Line", 0x2 },
+ { "CD", 0x4 },
+ },
+};
+
/*
* This is just place-holder, so there's something for alc_build_pcms to look
* at when it calculates the maximum number of channels. ALC260 has no mixer
{ 2, NULL },
};
-snd_kcontrol_new_t alc260_base_mixer[] = {
+static snd_kcontrol_new_t alc260_base_mixer[] = {
HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
- /* use LINE2 for the output */
- /* HDA_CODEC_MUTE("Front Playback Switch", 0x0f, 0x0, HDA_OUTPUT), */
- HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+ ALC_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x07, 0x05, HDA_INPUT),
HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x07, 0x05, HDA_INPUT),
HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT),
+ ALC_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT),
+ ALC_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_OUTPUT),
HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("Capture Switch", 0x04, 0x0, HDA_INPUT),
{
{ } /* end */
};
+static snd_kcontrol_new_t alc260_hp_mixer[] = {
+ HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
+ ALC_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
+ HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
+ HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
+ HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT),
+ HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT),
+ HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
+ ALC_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
+ ALC_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Capture Volume", 0x05, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x05, 0x0, HDA_INPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Capture Source",
+ .info = alc_mux_enum_info,
+ .get = alc_mux_enum_get,
+ .put = alc_mux_enum_put,
+ },
+ { } /* end */
+};
+
static struct hda_verb alc260_init_verbs[] = {
/* Line In pin widget for input */
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
/* CD pin widget for input */
- {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+ {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
/* Mic1 (rear panel) pin widget for input and vref at 80% */
- {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+ {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
/* Mic2 (front panel) pin widget for input and vref at 80% */
- {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+ {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
/* LINE-2 is used for line-out in rear */
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
/* select line-out */
{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
/* LINE-OUT pin */
- {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+ {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
/* enable HP */
- {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+ {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
/* enable Mono */
- {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
- /* unmute amp left and right */
- {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
+ {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ /* mute capture amp left and right */
+ {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
/* set connection select to line in (default select for this ADC) */
{0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
- /* unmute Line-Out mixer amp left and right (volume = 0) */
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
- /* mute pin widget amp left and right (no gain on this amp) */
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
- /* unmute HP mixer amp left and right (volume = 0) */
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
- /* mute pin widget amp left and right (no gain on this amp) */
- {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
- /* unmute Mono mixer amp left and right (volume = 0) */
- {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
- /* mute pin widget amp left and right (no gain on this amp) */
- {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
- /* mute LINE-2 out */
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+ /* mute capture amp left and right */
+ {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ /* set connection select to line in (default select for this ADC) */
+ {0x05, AC_VERB_SET_CONNECT_SEL, 0x02},
+ /* set vol=0 Line-Out mixer amp left and right */
+ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ /* unmute pin widget amp left and right (no gain on this amp) */
+ {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ /* set vol=0 HP mixer amp left and right */
+ {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ /* unmute pin widget amp left and right (no gain on this amp) */
+ {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ /* set vol=0 Mono mixer amp left and right */
+ {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ /* unmute pin widget amp left and right (no gain on this amp) */
+ {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ /* unmute LINE-2 out pin */
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
/* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03 */
- /* unmute CD */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
- /* unmute Line In */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
- /* unmute Mic */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+ /* mute CD */
+ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
+ /* mute Line In */
+ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+ /* mute Mic */
+ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
/* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
- /* Unmute Front out path */
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
- /* Unmute Headphone out path */
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
- /* Unmute Mono out path */
- {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
- {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+ /* mute Front out path */
+ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ /* mute Headphone out path */
+ {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ /* mute Mono out path */
+ {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
{ }
};
.substreams = 1,
.channels_min = 2,
.channels_max = 2,
- .nid = 0x2,
};
static struct hda_pcm_stream alc260_pcm_analog_capture = {
.substreams = 1,
.channels_min = 2,
.channels_max = 2,
- .nid = 0x4,
+};
+
+static struct hda_board_config alc260_cfg_tbl[] = {
+ { .modelname = "hp", .config = ALC260_HP },
+ { .pci_subvendor = 0x103c, .config = ALC260_HP },
+ {}
};
static int patch_alc260(struct hda_codec *codec)
{
struct alc_spec *spec;
+ int board_config;
spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
if (spec == NULL)
return -ENOMEM;
+ init_MUTEX(&spec->bind_mutex);
codec->spec = spec;
- spec->mixers[spec->num_mixers] = alc260_base_mixer;
- spec->num_mixers++;
+ board_config = snd_hda_check_board_config(codec, alc260_cfg_tbl);
+ if (board_config < 0 || board_config >= ALC260_MODEL_LAST) {
+ snd_printd(KERN_INFO "hda_codec: Unknown model for ALC260\n");
+ board_config = ALC260_BASIC;
+ }
+
+ switch (board_config) {
+ case ALC260_HP:
+ spec->mixers[spec->num_mixers] = alc260_hp_mixer;
+ spec->num_mixers++;
+ break;
+ default:
+ spec->mixers[spec->num_mixers] = alc260_base_mixer;
+ spec->num_mixers++;
+ break;
+ }
+
+ spec->init_verbs[0] = alc260_init_verbs;
+ spec->num_init_verbs = 1;
- spec->init_verbs = alc260_init_verbs;
spec->channel_mode = alc260_modes;
spec->num_channel_mode = ARRAY_SIZE(alc260_modes);
spec->multiout.dac_nids = alc260_dac_nids;
spec->input_mux = &alc260_capture_source;
- spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids);
- spec->adc_nids = alc260_adc_nids;
+ switch (board_config) {
+ case ALC260_HP:
+ spec->num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids);
+ spec->adc_nids = alc260_hp_adc_nids;
+ break;
+ default:
+ spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids);
+ spec->adc_nids = alc260_adc_nids;
+ break;
+ }
codec->patch_ops = alc_patch_ops;
return 0;
}
+
/*
* ALC882 support
*
*/
static snd_kcontrol_new_t alc882_base_mixer[] = {
HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+ ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+ ALC_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x16, 1, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
+ ALC_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+ ALC_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_OUTPUT),
HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Side Playback Switch", 0x17, 0x0, HDA_OUTPUT),
+ ALC_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
static struct hda_verb alc882_init_verbs[] = {
/* Front mixer: unmute input/output amp left and right (volume = 0) */
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
/* Rear mixer */
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+ {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
/* CLFE mixer */
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
/* Side mixer */
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
-
- /* Front Pin: to output mode */
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
- /* Front Pin: mute amp left and right (no volume) */
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
- /* select Front mixer (0x0c, index 0) */
+ {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+
+ /* Front Pin: output 0 (0x0c) */
+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
{0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
- /* Rear Pin */
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
- /* Rear Pin: mute amp left and right (no volume) */
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
- /* select Rear mixer (0x0d, index 1) */
+ /* Rear Pin: output 1 (0x0d) */
+ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
- /* CLFE Pin */
- {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
- /* CLFE Pin: mute amp left and right (no volume) */
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
- /* select CLFE mixer (0x0e, index 2) */
+ /* CLFE Pin: output 2 (0x0e) */
+ {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
{0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
- /* Side Pin */
- {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
- /* Side Pin: mute amp left and right (no volume) */
- {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
- /* select Side mixer (0x0f, index 3) */
+ /* Side Pin: output 3 (0x0f) */
+ {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
{0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
- /* Headphone Pin */
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
- /* Headphone Pin: mute amp left and right (no volume) */
- {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
- /* select Front mixer (0x0c, index 0) */
+ /* Mic (rear) pin: input vref at 80% */
+ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ /* Front Mic pin: input vref at 80% */
+ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ /* Line In pin: input */
+ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+ {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ /* Line-2 In: Headphone output (output 0 - 0x0c) */
+ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
{0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
- /* Mic (rear) pin widget for input and vref at 80% */
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
- /* Front Mic pin widget for input and vref at 80% */
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
- /* Line In pin widget for input */
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
/* CD pin widget for input */
- {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+ {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
/* FIXME: use matrix-type input source selection */
/* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
/* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
+ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
/* Input mixer2 */
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
+ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
/* Input mixer3 */
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
- /* ADC1: unmute amp left and right */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
- /* ADC2: unmute amp left and right */
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
- /* ADC3: unmute amp left and right */
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
-
- /* Unmute front loopback */
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
- /* Unmute rear loopback */
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
- /* Mute CLFE loopback */
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
- /* Unmute side loopback */
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+ /* ADC1: mute amp left and right */
+ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
+ /* ADC2: mute amp left and right */
+ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
+ /* ADC3: mute amp left and right */
+ {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
{ }
};
if (spec == NULL)
return -ENOMEM;
+ init_MUTEX(&spec->bind_mutex);
codec->spec = spec;
spec->mixers[spec->num_mixers] = alc882_base_mixer;
spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
spec->dig_in_nid = ALC880_DIGIN_NID;
- spec->front_panel = 1;
- spec->init_verbs = alc882_init_verbs;
+ spec->init_verbs[0] = alc882_init_verbs;
+ spec->num_init_verbs = 1;
+
spec->channel_mode = alc882_ch_modes;
spec->num_channel_mode = ARRAY_SIZE(alc882_ch_modes);
--- /dev/null
+/*
+ * Universal Interface for Intel High Definition Audio Codec
+ *
+ * HD audio interface patch for SigmaTel STAC92xx
+ *
+ * Copyright (c) 2005 Embedded Alley Solutions, Inc.
+ * <matt@embeddedalley.com>
+ *
+ * Based on patch_cmedia.c and patch_realtek.c
+ * 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"
+
+#undef STAC_TEST
+
+struct sigmatel_spec {
+ /* playback */
+ struct hda_multi_out multiout;
+ hda_nid_t playback_nid;
+
+ /* capture */
+ hda_nid_t *adc_nids;
+ unsigned int num_adcs;
+ hda_nid_t *mux_nids;
+ unsigned int num_muxes;
+ hda_nid_t capture_nid;
+ hda_nid_t dig_in_nid;
+
+ /* power management*/
+ hda_nid_t *pstate_nids;
+ unsigned int num_pstates;
+
+ /* pin widgets */
+ hda_nid_t *pin_nids;
+ unsigned int num_pins;
+#ifdef STAC_TEST
+ unsigned int *pin_configs;
+#endif
+
+ /* codec specific stuff */
+ struct hda_verb *init;
+ snd_kcontrol_new_t *mixer;
+
+ /* capture source */
+ struct hda_input_mux input_mux;
+ char input_labels[HDA_MAX_NUM_INPUTS][16];
+ unsigned int cur_mux[2];
+
+ /* channel mode */
+ unsigned int num_ch_modes;
+ unsigned int cur_ch_mode;
+ const struct sigmatel_channel_mode *channel_modes;
+
+ struct hda_pcm pcm_rec[1]; /* PCM information */
+};
+
+static hda_nid_t stac9200_adc_nids[1] = {
+ 0x03,
+};
+
+static hda_nid_t stac9200_mux_nids[1] = {
+ 0x0c,
+};
+
+static hda_nid_t stac9200_dac_nids[1] = {
+ 0x02,
+};
+
+static hda_nid_t stac9200_pstate_nids[3] = {
+ 0x01, 0x02, 0x03,
+};
+
+static hda_nid_t stac9200_pin_nids[8] = {
+ 0x08, 0x09, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
+};
+
+static hda_nid_t stac922x_adc_nids[2] = {
+ 0x06, 0x07,
+};
+
+static hda_nid_t stac922x_mux_nids[2] = {
+ 0x12, 0x13,
+};
+
+static hda_nid_t stac922x_dac_nids[4] = {
+ 0x02, 0x03, 0x04, 0x05,
+};
+
+static hda_nid_t stac922x_pstate_nids[8] = {
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x11,
+};
+
+static hda_nid_t stac922x_pin_nids[10] = {
+ 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
+ 0x0f, 0x10, 0x11, 0x15, 0x1b,
+};
+
+static int stac92xx_mux_enum_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct sigmatel_spec *spec = codec->spec;
+ return snd_hda_input_mux_info(&spec->input_mux, uinfo);
+}
+
+static int stac92xx_mux_enum_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct sigmatel_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 stac92xx_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct sigmatel_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->mux_nids[adc_idx], &spec->cur_mux[adc_idx]);
+}
+
+static struct hda_verb stac9200_ch2_init[] = {
+ /* set dac0mux for dac converter */
+ { 0x07, 0x701, 0x00},
+ {}
+};
+
+static struct hda_verb stac922x_ch2_init[] = {
+ /* set master volume and direct control */
+ { 0x16, 0x70f, 0xff},
+ {}
+};
+
+struct sigmatel_channel_mode {
+ unsigned int channels;
+ const struct hda_verb *sequence;
+};
+
+static snd_kcontrol_new_t stac9200_mixer[] = {
+ HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Input Source",
+ .count = 1,
+ .info = stac92xx_mux_enum_info,
+ .get = stac92xx_mux_enum_get,
+ .put = stac92xx_mux_enum_put,
+ },
+ HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Input Mux Volume", 0x0c, 0, HDA_OUTPUT),
+ { } /* end */
+};
+
+static snd_kcontrol_new_t stac922x_mixer[] = {
+ HDA_CODEC_VOLUME("PCM Playback Volume", 0x2, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("PCM Playback Switch", 0x2, 0x0, HDA_OUTPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Input Source",
+ .count = 1,
+ .info = stac92xx_mux_enum_info,
+ .get = stac92xx_mux_enum_get,
+ .put = stac92xx_mux_enum_put,
+ },
+ HDA_CODEC_VOLUME("Capture Volume", 0x17, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x17, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mux Capture Volume", 0x12, 0x0, HDA_OUTPUT),
+ { } /* end */
+};
+
+static int stac92xx_build_controls(struct hda_codec *codec)
+{
+ struct sigmatel_spec *spec = codec->spec;
+ int err;
+
+ err = snd_hda_add_new_ctls(codec, spec->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;
+}
+
+#ifdef STAC_TEST
+static unsigned int stac9200_pin_configs[8] = {
+ 0x01c47010, 0x01447010, 0x0221401f, 0x01114010,
+ 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
+};
+
+static unsigned int stac922x_pin_configs[14] = {
+ 0x40000100, 0x40000100, 0x40000100, 0x01114010,
+ 0x01813122, 0x40000100, 0x01447010, 0x01c47010,
+ 0x40000100, 0x40000100,
+};
+
+static void stac92xx_set_config_regs(struct hda_codec *codec)
+{
+ int i;
+ struct sigmatel_spec *spec = codec->spec;
+ unsigned int pin_cfg;
+
+ for (i=0; i < spec->num_pins; i++) {
+ snd_hda_codec_write(codec, spec->pin_nids[i], 0,
+ AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
+ spec->pin_configs[i] & 0x000000ff);
+ snd_hda_codec_write(codec, spec->pin_nids[i], 0,
+ AC_VERB_SET_CONFIG_DEFAULT_BYTES_1,
+ (spec->pin_configs[i] & 0x0000ff00) >> 8);
+ snd_hda_codec_write(codec, spec->pin_nids[i], 0,
+ AC_VERB_SET_CONFIG_DEFAULT_BYTES_2,
+ (spec->pin_configs[i] & 0x00ff0000) >> 16);
+ snd_hda_codec_write(codec, spec->pin_nids[i], 0,
+ AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
+ spec->pin_configs[i] >> 24);
+ pin_cfg = snd_hda_codec_read(codec, spec->pin_nids[i], 0,
+ AC_VERB_GET_CONFIG_DEFAULT,
+ 0x00);
+ printk("pin nid %2.2x pin config %8.8x\n", spec->pin_nids[i], pin_cfg);
+ }
+}
+#endif
+
+static int stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid, unsigned int value)
+{
+ unsigned int pin_ctl;
+
+ pin_ctl = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_PIN_WIDGET_CONTROL,
+ 0x00);
+ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+ pin_ctl | value);
+
+ return 0;
+}
+
+static int stac92xx_set_vref(struct hda_codec *codec, hda_nid_t nid)
+{
+ unsigned int vref_caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP) >> AC_PINCAP_VREF_SHIFT;
+ unsigned int vref_ctl = AC_PINCTL_VREF_HIZ;
+
+ if (vref_caps & AC_PINCAP_VREF_100)
+ vref_ctl = AC_PINCTL_VREF_100;
+ else if (vref_caps & AC_PINCAP_VREF_80)
+ vref_ctl = AC_PINCTL_VREF_80;
+ else if (vref_caps & AC_PINCAP_VREF_50)
+ vref_ctl = AC_PINCTL_VREF_50;
+ else if (vref_caps & AC_PINCAP_VREF_GRD)
+ vref_ctl = AC_PINCTL_VREF_GRD;
+
+ stac92xx_set_pinctl(codec, nid, vref_ctl);
+
+ return 0;
+}
+
+/*
+ * retrieve the default device type from the default config value
+ */
+#define get_defcfg_type(cfg) ((cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT)
+#define get_defcfg_location(cfg) ((cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT)
+
+static int stac92xx_config_pin(struct hda_codec *codec, hda_nid_t nid, unsigned int pin_cfg)
+{
+ struct sigmatel_spec *spec = codec->spec;
+ u32 location = get_defcfg_location(pin_cfg);
+ char *label;
+ const char *type = NULL;
+ int ainput = 0;
+
+ switch(get_defcfg_type(pin_cfg)) {
+ case AC_JACK_HP_OUT:
+ /* Enable HP amp */
+ stac92xx_set_pinctl(codec, nid, AC_PINCTL_HP_EN);
+ /* Fall through */
+ case AC_JACK_SPDIF_OUT:
+ case AC_JACK_LINE_OUT:
+ case AC_JACK_SPEAKER:
+ /* Enable output */
+ stac92xx_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
+ break;
+ case AC_JACK_SPDIF_IN:
+ stac92xx_set_pinctl(codec, nid, AC_PINCTL_IN_EN);
+ break;
+ case AC_JACK_MIC_IN:
+ if ((location & 0x0f) == AC_JACK_LOC_FRONT)
+ type = "Front Mic";
+ else
+ type = "Mic";
+ ainput = 1;
+ /* Set vref */
+ stac92xx_set_vref(codec, nid);
+ stac92xx_set_pinctl(codec, nid, AC_PINCTL_IN_EN);
+ break;
+ case AC_JACK_CD:
+ type = "CD";
+ ainput = 1;
+ stac92xx_set_pinctl(codec, nid, AC_PINCTL_IN_EN);
+ break;
+ case AC_JACK_LINE_IN:
+ if ((location & 0x0f) == AC_JACK_LOC_FRONT)
+ type = "Front Line";
+ else
+ type = "Line";
+ ainput = 1;
+ stac92xx_set_pinctl(codec, nid, AC_PINCTL_IN_EN);
+ break;
+ case AC_JACK_AUX:
+ if ((location & 0x0f) == AC_JACK_LOC_FRONT)
+ type = "Front Aux";
+ else
+ type = "Aux";
+ ainput = 1;
+ stac92xx_set_pinctl(codec, nid, AC_PINCTL_IN_EN);
+ break;
+ }
+
+ if (ainput) {
+ hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
+ int i, j, num_cons, index = -1;
+ if (!type)
+ type = "Input";
+ label = spec->input_labels[spec->input_mux.num_items];
+ strcpy(label, type);
+ spec->input_mux.items[spec->input_mux.num_items].label = label;
+ for (i=0; i<spec->num_muxes; i++) {
+ num_cons = snd_hda_get_connections(codec, spec->mux_nids[i], con_lst, HDA_MAX_NUM_INPUTS);
+ for (j=0; j<num_cons; j++)
+ if (con_lst[j] == nid) {
+ index = j;
+ break;
+ }
+ if (index >= 0)
+ break;
+ }
+ spec->input_mux.items[spec->input_mux.num_items].index = index;
+ spec->input_mux.num_items++;
+ }
+
+ return 0;
+}
+
+static int stac92xx_config_pins(struct hda_codec *codec)
+{
+ struct sigmatel_spec *spec = codec->spec;
+ int i;
+ unsigned int pin_cfg;
+
+ for (i=0; i < spec->num_pins; i++) {
+ /* Default to disabled */
+ snd_hda_codec_write(codec, spec->pin_nids[i], 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL,
+ 0x00);
+
+ pin_cfg = snd_hda_codec_read(codec, spec->pin_nids[i], 0,
+ AC_VERB_GET_CONFIG_DEFAULT,
+ 0x00);
+ if (((pin_cfg & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT) == AC_JACK_PORT_NONE)
+ continue; /* Move on */
+
+ stac92xx_config_pin(codec, spec->pin_nids[i], pin_cfg);
+ }
+
+ return 0;
+}
+
+static int stac92xx_init(struct hda_codec *codec)
+{
+ struct sigmatel_spec *spec = codec->spec;
+ int i;
+
+ for (i=0; i < spec->num_pstates; i++)
+ snd_hda_codec_write(codec, spec->pstate_nids[i], 0,
+ AC_VERB_SET_POWER_STATE, 0x00);
+
+ mdelay(100);
+
+ snd_hda_sequence_write(codec, spec->init);
+
+#ifdef STAC_TEST
+ stac92xx_set_config_regs(codec);
+#endif
+
+ stac92xx_config_pins(codec);
+
+ return 0;
+}
+
+/*
+ * Analog playback callbacks
+ */
+static int stac92xx_playback_pcm_open(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ snd_pcm_substream_t *substream)
+{
+ struct sigmatel_spec *spec = codec->spec;
+ return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
+}
+
+static int stac92xx_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 sigmatel_spec *spec = codec->spec;
+ return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag,
+ format, substream);
+}
+
+static int stac92xx_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ snd_pcm_substream_t *substream)
+{
+ struct sigmatel_spec *spec = codec->spec;
+ return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
+}
+
+/*
+ * Digital playback callbacks
+ */
+static int stac92xx_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ snd_pcm_substream_t *substream)
+{
+ struct sigmatel_spec *spec = codec->spec;
+ return snd_hda_multi_out_dig_open(codec, &spec->multiout);
+}
+
+static int stac92xx_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ snd_pcm_substream_t *substream)
+{
+ struct sigmatel_spec *spec = codec->spec;
+ return snd_hda_multi_out_dig_close(codec, &spec->multiout);
+}
+
+
+/*
+ * Analog capture callbacks
+ */
+static int stac92xx_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 sigmatel_spec *spec = codec->spec;
+
+ snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
+ stream_tag, 0, format);
+ return 0;
+}
+
+static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ snd_pcm_substream_t *substream)
+{
+ struct sigmatel_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 stac92xx_pcm_digital_playback = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 2,
+ /* NID is set in stac92xx_build_pcms */
+ .ops = {
+ .open = stac92xx_dig_playback_pcm_open,
+ .close = stac92xx_dig_playback_pcm_close
+ },
+};
+
+static struct hda_pcm_stream stac92xx_pcm_digital_capture = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 2,
+ /* NID is set in stac92xx_build_pcms */
+};
+
+static struct hda_pcm_stream stac92xx_pcm_analog_playback = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 2,
+ .nid = 0x02, /* NID to query formats and rates */
+ .ops = {
+ .open = stac92xx_playback_pcm_open,
+ .prepare = stac92xx_playback_pcm_prepare,
+ .cleanup = stac92xx_playback_pcm_cleanup
+ },
+};
+
+static struct hda_pcm_stream stac92xx_pcm_analog_capture = {
+ .substreams = 2,
+ .channels_min = 2,
+ .channels_max = 2,
+ .nid = 0x06, /* NID to query formats and rates */
+ .ops = {
+ .prepare = stac92xx_capture_pcm_prepare,
+ .cleanup = stac92xx_capture_pcm_cleanup
+ },
+};
+
+static int stac92xx_build_pcms(struct hda_codec *codec)
+{
+ struct sigmatel_spec *spec = codec->spec;
+ struct hda_pcm *info = spec->pcm_rec;
+
+ codec->num_pcms = 1;
+ codec->pcm_info = info;
+
+ info->name = "STAC92xx";
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback;
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->playback_nid;
+ info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture;
+ info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->capture_nid;
+
+ if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
+ codec->num_pcms++;
+ info++;
+ info->name = "STAC92xx Digital";
+ if (spec->multiout.dig_out_nid) {
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_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] = stac92xx_pcm_digital_capture;
+ info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
+ }
+ }
+
+ return 0;
+}
+
+static void stac92xx_free(struct hda_codec *codec)
+{
+ kfree(codec->spec);
+}
+
+static struct hda_codec_ops stac92xx_patch_ops = {
+ .build_controls = stac92xx_build_controls,
+ .build_pcms = stac92xx_build_pcms,
+ .init = stac92xx_init,
+ .free = stac92xx_free,
+};
+
+static int patch_stac9200(struct hda_codec *codec)
+{
+ struct sigmatel_spec *spec;
+
+ spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+ if (spec == NULL)
+ return -ENOMEM;
+
+ codec->spec = spec;
+
+ spec->multiout.max_channels = 2;
+ spec->multiout.num_dacs = 1;
+ spec->multiout.dac_nids = stac9200_dac_nids;
+ spec->multiout.dig_out_nid = 0x05;
+ spec->dig_in_nid = 0x04;
+ spec->adc_nids = stac9200_adc_nids;
+ spec->mux_nids = stac9200_mux_nids;
+ spec->num_muxes = 1;
+ spec->input_mux.num_items = 0;
+ spec->pstate_nids = stac9200_pstate_nids;
+ spec->num_pstates = 3;
+ spec->pin_nids = stac9200_pin_nids;
+#ifdef STAC_TEST
+ spec->pin_configs = stac9200_pin_configs;
+#endif
+ spec->num_pins = 8;
+ spec->init = stac9200_ch2_init;
+ spec->mixer = stac9200_mixer;
+ spec->playback_nid = 0x02;
+ spec->capture_nid = 0x03;
+
+ codec->patch_ops = stac92xx_patch_ops;
+
+ return 0;
+}
+
+static int patch_stac922x(struct hda_codec *codec)
+{
+ struct sigmatel_spec *spec;
+
+ spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+ if (spec == NULL)
+ return -ENOMEM;
+
+ codec->spec = spec;
+
+ spec->multiout.max_channels = 2;
+ spec->multiout.num_dacs = 4;
+ spec->multiout.dac_nids = stac922x_dac_nids;
+ spec->multiout.dig_out_nid = 0x08;
+ spec->dig_in_nid = 0x09;
+ spec->adc_nids = stac922x_adc_nids;
+ spec->mux_nids = stac922x_mux_nids;
+ spec->num_muxes = 2;
+ spec->input_mux.num_items = 0;
+ spec->pstate_nids = stac922x_pstate_nids;
+ spec->num_pstates = 8;
+ spec->pin_nids = stac922x_pin_nids;
+#ifdef STAC_TEST
+ spec->pin_configs = stac922x_pin_configs;
+#endif
+ spec->num_pins = 10;
+ spec->init = stac922x_ch2_init;
+ spec->mixer = stac922x_mixer;
+ spec->playback_nid = 0x02;
+ spec->capture_nid = 0x06;
+
+ codec->patch_ops = stac92xx_patch_ops;
+
+ return 0;
+}
+
+/*
+ * patch entries
+ */
+struct hda_codec_preset snd_hda_preset_sigmatel[] = {
+ { .id = 0x83847690, .name = "STAC9200", .patch = patch_stac9200 },
+ { .id = 0x83847882, .name = "STAC9220 A1", .patch = patch_stac922x },
+ { .id = 0x83847680, .name = "STAC9221 A1", .patch = patch_stac922x },
+ { .id = 0x83847880, .name = "STAC9220 A2", .patch = patch_stac922x },
+ { .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = patch_stac922x },
+ { .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x },
+ { .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x },
+ {} /* terminator */
+};
#include <sound/core.h>
#include "ice1712.h"
+#include "envy24ht.h"
#include "amp.h"
+static void wm_put(ice1712_t *ice, int reg, unsigned short val)
+{
+ unsigned short cval;
+ cval = (reg << 9) | val;
+ snd_vt1724_write_i2c(ice, WM_DEV, cval >> 8, cval & 0xff);
+}
static int __devinit snd_vt1724_amp_init(ice1712_t *ice)
{
+ static unsigned short wm_inits[] = {
+ WM_ATTEN_L, 0x0000, /* 0 db */
+ WM_ATTEN_R, 0x0000, /* 0 db */
+ WM_DAC_CTRL, 0x0008, /* 24bit I2S */
+ WM_INT_CTRL, 0x0001, /* 24bit I2S */
+ };
+
+ unsigned int i;
+
/* only use basic functionality for now */
ice->num_total_dacs = 2; /* only PSDOUT0 is connected */
ice->num_total_adcs = 2;
+ /* Chaintech AV-710 has another codecs, which need initialization */
+ /* initialize WM8728 codec */
+ if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AV710) {
+ for (i = 0; i < ARRAY_SIZE(wm_inits); i += 2)
+ wm_put(ice, wm_inits[i], wm_inits[i+1]);
+ }
+
return 0;
}
/* entry point */
struct snd_ice1712_card_info snd_vt1724_amp_cards[] __devinitdata = {
+ {
+ .subvendor = VT1724_SUBDEVICE_AV710,
+ .name = "Chaintech AV-710",
+ .model = "av710",
+ .chip_init = snd_vt1724_amp_init,
+ .build_controls = snd_vt1724_amp_add_controls,
+ },
{
.subvendor = VT1724_SUBDEVICE_AUDIO2000,
.name = "AMP Ltd AUDIO2000",
*
*/
-#define AMP_AUDIO2000_DEVICE_DESC "{AMP Ltd,AUDIO2000},"
+#define AMP_AUDIO2000_DEVICE_DESC "{AMP Ltd,AUDIO2000},"\
+ "{Chaintech,AV-710},"
+#if 0
#define VT1724_SUBDEVICE_AUDIO2000 0x12142417 /* Advanced Micro Peripherals Ltd AUDIO2000 */
+#else
+#define VT1724_SUBDEVICE_AUDIO2000 0x00030003 /* a dummy ID for AMP Audio2000 */
+#endif
+#define VT1724_SUBDEVICE_AV710 0x12142417 /* AV710 - the same ID with Audio2000! */
+
+/* WM8728 on I2C for AV710 */
+#define WM_DEV 0x36
+
+#define WM_ATTEN_L 0x00
+#define WM_ATTEN_R 0x01
+#define WM_DAC_CTRL 0x02
+#define WM_INT_CTRL 0x03
extern struct snd_ice1712_card_info snd_vt1724_amp_cards[];
static int __init alsa_card_ice1712_init(void)
{
- return pci_module_init(&driver);
+ return pci_register_driver(&driver);
}
static void __exit alsa_card_ice1712_exit(void)
unsigned short master[2];
unsigned short vol[8];
} aureon;
+ /* AC97 register cache for Phase28 */
+ struct phase28_spec {
+ unsigned short master[2];
+ unsigned short vol[8];
+ } phase28;
/* Hoontech-specific setting */
struct hoontech_spec {
unsigned char boxbits[4];
static int __init alsa_card_ice1724_init(void)
{
- return pci_module_init(&driver);
+ return pci_register_driver(&driver);
}
static void __exit alsa_card_ice1724_exit(void)
#include "envy24ht.h"
#include "phase.h"
+/* WM8770 registers */
+#define WM_DAC_ATTEN 0x00 /* DAC1-8 analog attenuation */
+#define WM_DAC_MASTER_ATTEN 0x08 /* DAC master analog attenuation */
+#define WM_DAC_DIG_ATTEN 0x09 /* DAC1-8 digital attenuation */
+#define WM_DAC_DIG_MASTER_ATTEN 0x11 /* DAC master digital attenuation */
+#define WM_PHASE_SWAP 0x12 /* DAC phase */
+#define WM_DAC_CTRL1 0x13 /* DAC control bits */
+#define WM_MUTE 0x14 /* mute controls */
+#define WM_DAC_CTRL2 0x15 /* de-emphasis and zefo-flag */
+#define WM_INT_CTRL 0x16 /* interface control */
+#define WM_MASTER 0x17 /* master clock and mode */
+#define WM_POWERDOWN 0x18 /* power-down controls */
+#define WM_ADC_GAIN 0x19 /* ADC gain L(19)/R(1a) */
+#define WM_ADC_MUX 0x1b /* input MUX */
+#define WM_OUT_MUX1 0x1c /* output MUX */
+#define WM_OUT_MUX2 0x1e /* output MUX */
+#define WM_RESET 0x1f /* software reset */
+
+
+/*
+ * Logarithmic volume values for WM8770
+ * Computed as 20 * Log10(255 / x)
+ */
+static unsigned char wm_vol[256] = {
+ 127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24, 24, 23,
+ 23, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17,
+ 17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13,
+ 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0
+};
+
+#define WM_VOL_MAX (sizeof(wm_vol) - 1)
+#define WM_VOL_MUTE 0x8000
+
static akm4xxx_t akm_phase22 __devinitdata = {
.type = SND_AK4524,
.num_dacs = 2,
0x00, /* GPIO_STATE2 */
};
+static unsigned char phase28_eeprom[] __devinitdata = {
+ 0x0b, /* SYSCONF: clock 512, spdif-in/ADC, 4DACs */
+ 0x80, /* ACLINK: I2S */
+ 0xfc, /* I2S: vol, 96k, 24bit, 192k */
+ 0xc3, /* SPDIF: out-en, out-int, spdif-in */
+ 0xff, /* GPIO_DIR */
+ 0xff, /* GPIO_DIR1 */
+ 0x5f, /* GPIO_DIR2 */
+ 0x00, /* GPIO_MASK */
+ 0x00, /* GPIO_MASK1 */
+ 0x00, /* GPIO_MASK2 */
+ 0x00, /* GPIO_STATE */
+ 0x00, /* GPIO_STATE1 */
+ 0x00, /* GPIO_STATE2 */
+};
+
+/*
+ * write data in the SPI mode
+ */
+static void phase28_spi_write(ice1712_t *ice, unsigned int cs, unsigned int data, int bits)
+{
+ unsigned int tmp;
+ int i;
+
+ tmp = snd_ice1712_gpio_read(ice);
+
+ snd_ice1712_gpio_set_mask(ice, ~(PHASE28_WM_RW|PHASE28_SPI_MOSI|PHASE28_SPI_CLK|
+ PHASE28_WM_CS));
+ tmp |= PHASE28_WM_RW;
+ tmp &= ~cs;
+ snd_ice1712_gpio_write(ice, tmp);
+ udelay(1);
+
+ for (i = bits - 1; i >= 0; i--) {
+ tmp &= ~PHASE28_SPI_CLK;
+ snd_ice1712_gpio_write(ice, tmp);
+ udelay(1);
+ if (data & (1 << i))
+ tmp |= PHASE28_SPI_MOSI;
+ else
+ tmp &= ~PHASE28_SPI_MOSI;
+ snd_ice1712_gpio_write(ice, tmp);
+ udelay(1);
+ tmp |= PHASE28_SPI_CLK;
+ snd_ice1712_gpio_write(ice, tmp);
+ udelay(1);
+ }
+
+ tmp &= ~PHASE28_SPI_CLK;
+ tmp |= cs;
+ snd_ice1712_gpio_write(ice, tmp);
+ udelay(1);
+ tmp |= PHASE28_SPI_CLK;
+ snd_ice1712_gpio_write(ice, tmp);
+ udelay(1);
+}
+
+/*
+ * get the current register value of WM codec
+ */
+static unsigned short wm_get(ice1712_t *ice, int reg)
+{
+ reg <<= 1;
+ return ((unsigned short)ice->akm[0].images[reg] << 8) |
+ ice->akm[0].images[reg + 1];
+}
+
+/*
+ * set the register value of WM codec
+ */
+static void wm_put_nocache(ice1712_t *ice, int reg, unsigned short val)
+{
+ phase28_spi_write(ice, PHASE28_WM_CS, (reg << 9) | (val & 0x1ff), 16);
+}
+
+/*
+ * set the register value of WM codec and remember it
+ */
+static void wm_put(ice1712_t *ice, int reg, unsigned short val)
+{
+ wm_put_nocache(ice, reg, val);
+ reg <<= 1;
+ ice->akm[0].images[reg] = val >> 8;
+ ice->akm[0].images[reg + 1] = val;
+}
+
+static void wm_set_vol(ice1712_t *ice, unsigned int index, unsigned short vol, unsigned short master)
+{
+ unsigned char nvol;
+
+ if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE))
+ nvol = 0;
+ else
+ nvol = 127 - wm_vol[(((vol & ~WM_VOL_MUTE) * (master & ~WM_VOL_MUTE)) / 127) & WM_VOL_MAX];
+
+ wm_put(ice, index, nvol);
+ wm_put_nocache(ice, index, 0x180 | nvol);
+}
+
+/*
+ * DAC mute control
+ */
+#define wm_pcm_mute_info phase28_mono_bool_info
+
+static int wm_pcm_mute_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+ ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+
+ down(&ice->gpio_mutex);
+ ucontrol->value.integer.value[0] = (wm_get(ice, WM_MUTE) & 0x10) ? 0 : 1;
+ up(&ice->gpio_mutex);
+ return 0;
+}
+
+static int wm_pcm_mute_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+ ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+ unsigned short nval, oval;
+ int change;
+
+ snd_ice1712_save_gpio_status(ice);
+ oval = wm_get(ice, WM_MUTE);
+ nval = (oval & ~0x10) | (ucontrol->value.integer.value[0] ? 0 : 0x10);
+ if ((change = (nval != oval)))
+ wm_put(ice, WM_MUTE, nval);
+ snd_ice1712_restore_gpio_status(ice);
+
+ return change;
+}
+
+/*
+ * Master volume attenuation mixer control
+ */
+static int wm_master_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 2;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = WM_VOL_MAX;
+ return 0;
+}
+
+static int wm_master_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+ ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+ int i;
+ for (i=0; i<2; i++)
+ ucontrol->value.integer.value[i] = ice->spec.phase28.master[i] & ~WM_VOL_MUTE;
+ return 0;
+}
+
+static int wm_master_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+ ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+ int ch, change = 0;
+
+ snd_ice1712_save_gpio_status(ice);
+ for (ch = 0; ch < 2; ch++) {
+ if (ucontrol->value.integer.value[ch] != ice->spec.phase28.master[ch]) {
+ int dac;
+ ice->spec.phase28.master[ch] &= WM_VOL_MUTE;
+ ice->spec.phase28.master[ch] |= ucontrol->value.integer.value[ch];
+ for (dac = 0; dac < ice->num_total_dacs; dac += 2)
+ wm_set_vol(ice, WM_DAC_ATTEN + dac + ch,
+ ice->spec.phase28.vol[dac + ch],
+ ice->spec.phase28.master[ch]);
+ change = 1;
+ }
+ }
+ snd_ice1712_restore_gpio_status(ice);
+ return change;
+}
+
+static int __devinit phase28_init(ice1712_t *ice)
+{
+ static unsigned short wm_inits_phase28[] = {
+ /* These come first to reduce init pop noise */
+ 0x1b, 0x044, /* ADC Mux (AC'97 source) */
+ 0x1c, 0x00B, /* Out Mux1 (VOUT1 = DAC+AUX, VOUT2 = DAC) */
+ 0x1d, 0x009, /* Out Mux2 (VOUT2 = DAC, VOUT3 = DAC) */
+
+ 0x18, 0x000, /* All power-up */
+
+ 0x16, 0x122, /* I2S, normal polarity, 24bit */
+ 0x17, 0x022, /* 256fs, slave mode */
+ 0x00, 0, /* DAC1 analog mute */
+ 0x01, 0, /* DAC2 analog mute */
+ 0x02, 0, /* DAC3 analog mute */
+ 0x03, 0, /* DAC4 analog mute */
+ 0x04, 0, /* DAC5 analog mute */
+ 0x05, 0, /* DAC6 analog mute */
+ 0x06, 0, /* DAC7 analog mute */
+ 0x07, 0, /* DAC8 analog mute */
+ 0x08, 0x100, /* master analog mute */
+ 0x09, 0xff, /* DAC1 digital full */
+ 0x0a, 0xff, /* DAC2 digital full */
+ 0x0b, 0xff, /* DAC3 digital full */
+ 0x0c, 0xff, /* DAC4 digital full */
+ 0x0d, 0xff, /* DAC5 digital full */
+ 0x0e, 0xff, /* DAC6 digital full */
+ 0x0f, 0xff, /* DAC7 digital full */
+ 0x10, 0xff, /* DAC8 digital full */
+ 0x11, 0x1ff, /* master digital full */
+ 0x12, 0x000, /* phase normal */
+ 0x13, 0x090, /* unmute DAC L/R */
+ 0x14, 0x000, /* all unmute */
+ 0x15, 0x000, /* no deemphasis, no ZFLG */
+ 0x19, 0x000, /* -12dB ADC/L */
+ 0x1a, 0x000, /* -12dB ADC/R */
+ (unsigned short)-1
+ };
+
+ unsigned int tmp;
+ akm4xxx_t *ak;
+ unsigned short *p;
+ int i;
+
+ ice->num_total_dacs = 8;
+ ice->num_total_adcs = 2;
+
+ // Initialize analog chips
+ ak = ice->akm = kcalloc(1, sizeof(akm4xxx_t), GFP_KERNEL);
+ if (!ak)
+ return -ENOMEM;
+ ice->akm_codecs = 1;
+
+ snd_ice1712_gpio_set_dir(ice, 0x5fffff); /* fix this for the time being */
+
+ /* reset the wm codec as the SPI mode */
+ snd_ice1712_save_gpio_status(ice);
+ snd_ice1712_gpio_set_mask(ice, ~(PHASE28_WM_RESET|PHASE28_WM_CS|PHASE28_HP_SEL));
+
+ tmp = snd_ice1712_gpio_read(ice);
+ tmp &= ~PHASE28_WM_RESET;
+ snd_ice1712_gpio_write(ice, tmp);
+ udelay(1);
+ tmp |= PHASE28_WM_CS;
+ snd_ice1712_gpio_write(ice, tmp);
+ udelay(1);
+ tmp |= PHASE28_WM_RESET;
+ snd_ice1712_gpio_write(ice, tmp);
+ udelay(1);
+
+ p = wm_inits_phase28;
+ for (; *p != (unsigned short)-1; p += 2)
+ wm_put(ice, p[0], p[1]);
+
+ snd_ice1712_restore_gpio_status(ice);
+
+ ice->spec.phase28.master[0] = WM_VOL_MUTE;
+ ice->spec.phase28.master[1] = WM_VOL_MUTE;
+ for (i = 0; i < ice->num_total_dacs; i++) {
+ ice->spec.phase28.vol[i] = WM_VOL_MUTE;
+ wm_set_vol(ice, i, ice->spec.phase28.vol[i], ice->spec.phase28.master[i % 2]);
+ }
+
+ return 0;
+}
+
+/*
+ * DAC volume attenuation mixer control
+ */
+static int wm_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+ int voices = kcontrol->private_value >> 8;
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = voices;
+ uinfo->value.integer.min = 0; /* mute (-101dB) */
+ uinfo->value.integer.max = 0x7F; /* 0dB */
+ return 0;
+}
+
+static int wm_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+ ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+ int i, ofs, voices;
+
+ voices = kcontrol->private_value >> 8;
+ ofs = kcontrol->private_value & 0xff;
+ for (i = 0; i < voices; i++)
+ ucontrol->value.integer.value[i] = ice->spec.phase28.vol[ofs+i] & ~WM_VOL_MUTE;
+ return 0;
+}
+
+static int wm_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+ ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+ int i, idx, ofs, voices;
+ int change = 0;
+
+ voices = kcontrol->private_value >> 8;
+ ofs = kcontrol->private_value & 0xff;
+ snd_ice1712_save_gpio_status(ice);
+ for (i = 0; i < voices; i++) {
+ idx = WM_DAC_ATTEN + ofs + i;
+ if (ucontrol->value.integer.value[i] != ice->spec.phase28.vol[ofs+i]) {
+ ice->spec.phase28.vol[ofs+i] &= WM_VOL_MUTE;
+ ice->spec.phase28.vol[ofs+i] |= ucontrol->value.integer.value[i];
+ wm_set_vol(ice, idx, ice->spec.phase28.vol[ofs+i],
+ ice->spec.phase28.master[i]);
+ change = 1;
+ }
+ }
+ snd_ice1712_restore_gpio_status(ice);
+ return change;
+}
+
+/*
+ * WM8770 mute control
+ */
+static int wm_mute_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) {
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = kcontrol->private_value >> 8;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+static int wm_mute_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+ ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+ int voices, ofs, i;
+
+ voices = kcontrol->private_value >> 8;
+ ofs = kcontrol->private_value & 0xFF;
+
+ for (i = 0; i < voices; i++)
+ ucontrol->value.integer.value[i] = (ice->spec.phase28.vol[ofs+i] & WM_VOL_MUTE) ? 0 : 1;
+ return 0;
+}
+
+static int wm_mute_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+ ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+ int change = 0, voices, ofs, i;
+
+ voices = kcontrol->private_value >> 8;
+ ofs = kcontrol->private_value & 0xFF;
+
+ snd_ice1712_save_gpio_status(ice);
+ for (i = 0; i < voices; i++) {
+ int val = (ice->spec.phase28.vol[ofs + i] & WM_VOL_MUTE) ? 0 : 1;
+ if (ucontrol->value.integer.value[i] != val) {
+ ice->spec.phase28.vol[ofs + i] &= ~WM_VOL_MUTE;
+ ice->spec.phase28.vol[ofs + i] |=
+ ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE;
+ wm_set_vol(ice, ofs + i, ice->spec.phase28.vol[ofs + i],
+ ice->spec.phase28.master[i]);
+ change = 1;
+ }
+ }
+ snd_ice1712_restore_gpio_status(ice);
+
+ return change;
+}
+
+/*
+ * WM8770 master mute control
+ */
+static int wm_master_mute_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) {
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 2;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+static int wm_master_mute_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+ ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.integer.value[0] = (ice->spec.phase28.master[0] & WM_VOL_MUTE) ? 0 : 1;
+ ucontrol->value.integer.value[1] = (ice->spec.phase28.master[1] & WM_VOL_MUTE) ? 0 : 1;
+ return 0;
+}
+
+static int wm_master_mute_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+ ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+ int change = 0, i;
+
+ snd_ice1712_save_gpio_status(ice);
+ for (i = 0; i < 2; i++) {
+ int val = (ice->spec.phase28.master[i] & WM_VOL_MUTE) ? 0 : 1;
+ if (ucontrol->value.integer.value[i] != val) {
+ int dac;
+ ice->spec.phase28.master[i] &= ~WM_VOL_MUTE;
+ ice->spec.phase28.master[i] |=
+ ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE;
+ for (dac = 0; dac < ice->num_total_dacs; dac += 2)
+ wm_set_vol(ice, WM_DAC_ATTEN + dac + i,
+ ice->spec.phase28.vol[dac + i],
+ ice->spec.phase28.master[i]);
+ change = 1;
+ }
+ }
+ snd_ice1712_restore_gpio_status(ice);
+
+ return change;
+}
+
+/* digital master volume */
+#define PCM_0dB 0xff
+#define PCM_RES 128 /* -64dB */
+#define PCM_MIN (PCM_0dB - PCM_RES)
+static int wm_pcm_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0; /* mute (-64dB) */
+ uinfo->value.integer.max = PCM_RES; /* 0dB */
+ return 0;
+}
+
+static int wm_pcm_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+ ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+ unsigned short val;
+
+ down(&ice->gpio_mutex);
+ val = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
+ val = val > PCM_MIN ? (val - PCM_MIN) : 0;
+ ucontrol->value.integer.value[0] = val;
+ up(&ice->gpio_mutex);
+ return 0;
+}
+
+static int wm_pcm_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+ ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+ unsigned short ovol, nvol;
+ int change = 0;
+
+ snd_ice1712_save_gpio_status(ice);
+ nvol = ucontrol->value.integer.value[0];
+ nvol = (nvol ? (nvol + PCM_MIN) : 0) & 0xff;
+ ovol = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
+ if (ovol != nvol) {
+ wm_put(ice, WM_DAC_DIG_MASTER_ATTEN, nvol); /* prelatch */
+ wm_put_nocache(ice, WM_DAC_DIG_MASTER_ATTEN, nvol | 0x100); /* update */
+ change = 1;
+ }
+ snd_ice1712_restore_gpio_status(ice);
+ return change;
+}
+
+/*
+ */
+static int phase28_mono_bool_info(snd_kcontrol_t *k, snd_ctl_elem_info_t *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+/*
+ * Deemphasis
+ */
+#define phase28_deemp_info phase28_mono_bool_info
+
+static int phase28_deemp_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+ ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+ ucontrol->value.integer.value[0] = (wm_get(ice, WM_DAC_CTRL2) & 0xf) == 0xf;
+ return 0;
+}
+
+static int phase28_deemp_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+ ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+ int temp, temp2;
+ temp2 = temp = wm_get(ice, WM_DAC_CTRL2);
+ if (ucontrol->value.integer.value[0])
+ temp |= 0xf;
+ else
+ temp &= ~0xf;
+ if (temp != temp2) {
+ wm_put(ice, WM_DAC_CTRL2, temp);
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * ADC Oversampling
+ */
+static int phase28_oversampling_info(snd_kcontrol_t *k, snd_ctl_elem_info_t *uinfo)
+{
+ static char *texts[2] = { "128x", "64x" };
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 2;
+
+ if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+ uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
+ strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+
+ return 0;
+}
+
+static int phase28_oversampling_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+ ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+ ucontrol->value.enumerated.item[0] = (wm_get(ice, WM_MASTER) & 0x8) == 0x8;
+ return 0;
+}
+
+static int phase28_oversampling_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+ int temp, temp2;
+ ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+
+ temp2 = temp = wm_get(ice, WM_MASTER);
+
+ if (ucontrol->value.enumerated.item[0])
+ temp |= 0x8;
+ else
+ temp &= ~0x8;
+
+ if (temp != temp2) {
+ wm_put(ice, WM_MASTER, temp);
+ return 1;
+ }
+ return 0;
+}
+
+static snd_kcontrol_new_t phase28_dac_controls[] __devinitdata = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Master Playback Switch",
+ .info = wm_master_mute_info,
+ .get = wm_master_mute_get,
+ .put = wm_master_mute_put
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Master Playback Volume",
+ .info = wm_master_vol_info,
+ .get = wm_master_vol_get,
+ .put = wm_master_vol_put
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Front Playback Switch",
+ .info = wm_mute_info,
+ .get = wm_mute_get,
+ .put = wm_mute_put,
+ .private_value = (2 << 8) | 0
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Front Playback Volume",
+ .info = wm_vol_info,
+ .get = wm_vol_get,
+ .put = wm_vol_put,
+ .private_value = (2 << 8) | 0
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Rear Playback Switch",
+ .info = wm_mute_info,
+ .get = wm_mute_get,
+ .put = wm_mute_put,
+ .private_value = (2 << 8) | 2
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Rear Playback Volume",
+ .info = wm_vol_info,
+ .get = wm_vol_get,
+ .put = wm_vol_put,
+ .private_value = (2 << 8) | 2
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Center Playback Switch",
+ .info = wm_mute_info,
+ .get = wm_mute_get,
+ .put = wm_mute_put,
+ .private_value = (1 << 8) | 4
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Center Playback Volume",
+ .info = wm_vol_info,
+ .get = wm_vol_get,
+ .put = wm_vol_put,
+ .private_value = (1 << 8) | 4
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "LFE Playback Switch",
+ .info = wm_mute_info,
+ .get = wm_mute_get,
+ .put = wm_mute_put,
+ .private_value = (1 << 8) | 5
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "LFE Playback Volume",
+ .info = wm_vol_info,
+ .get = wm_vol_get,
+ .put = wm_vol_put,
+ .private_value = (1 << 8) | 5
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Side Playback Switch",
+ .info = wm_mute_info,
+ .get = wm_mute_get,
+ .put = wm_mute_put,
+ .private_value = (2 << 8) | 6
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Side Playback Volume",
+ .info = wm_vol_info,
+ .get = wm_vol_get,
+ .put = wm_vol_put,
+ .private_value = (2 << 8) | 6
+ }
+};
+
+static snd_kcontrol_new_t wm_controls[] __devinitdata = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "PCM Playback Switch",
+ .info = wm_pcm_mute_info,
+ .get = wm_pcm_mute_get,
+ .put = wm_pcm_mute_put
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "PCM Playback Volume",
+ .info = wm_pcm_vol_info,
+ .get = wm_pcm_vol_get,
+ .put = wm_pcm_vol_put
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "DAC Deemphasis Switch",
+ .info = phase28_deemp_info,
+ .get = phase28_deemp_get,
+ .put = phase28_deemp_put
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "ADC Oversampling",
+ .info = phase28_oversampling_info,
+ .get = phase28_oversampling_get,
+ .put = phase28_oversampling_put
+ }
+};
+
+static int __devinit phase28_add_controls(ice1712_t *ice)
+{
+ unsigned int i, counts;
+ int err;
+
+ counts = ARRAY_SIZE(phase28_dac_controls);
+ for (i = 0; i < counts; i++) {
+ err = snd_ctl_add(ice->card, snd_ctl_new1(&phase28_dac_controls[i], ice));
+ if (err < 0)
+ return err;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(wm_controls); i++) {
+ err = snd_ctl_add(ice->card, snd_ctl_new1(&wm_controls[i], ice));
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
struct snd_ice1712_card_info snd_vt1724_phase_cards[] __devinitdata = {
{
.subvendor = VT1724_SUBDEVICE_PHASE22,
.eeprom_size = sizeof(phase22_eeprom),
.eeprom_data = phase22_eeprom,
},
+ {
+ .subvendor = VT1724_SUBDEVICE_PHASE28,
+ .name = "Terratec PHASE 28",
+ .model = "phase28",
+ .chip_init = phase28_init,
+ .build_controls = phase28_add_controls,
+ .eeprom_size = sizeof(phase28_eeprom),
+ .eeprom_data = phase28_eeprom,
+ },
{ } /* terminator */
};
*
*/
-#define PHASE_DEVICE_DESC "{Terratec,Phase 22},"
+#define PHASE_DEVICE_DESC "{Terratec,Phase 22},"\
+ "{Terratec,Phase 28},"
#define VT1724_SUBDEVICE_PHASE22 0x3b155011
+#define VT1724_SUBDEVICE_PHASE28 0x3b154911
/* entry point */
extern struct snd_ice1712_card_info snd_vt1724_phase_cards[];
+/* PHASE28 GPIO bits */
+#define PHASE28_SPI_MISO (1 << 21)
+#define PHASE28_WM_RESET (1 << 20)
+#define PHASE28_SPI_CLK (1 << 19)
+#define PHASE28_SPI_MOSI (1 << 18)
+#define PHASE28_WM_RW (1 << 17)
+#define PHASE28_AC97_RESET (1 << 16)
+#define PHASE28_DIGITAL_SEL1 (1 << 15)
+#define PHASE28_HP_SEL (1 << 14)
+#define PHASE28_WM_CS (1 << 12)
+#define PHASE28_AC97_COMMIT (1 << 11)
+#define PHASE28_AC97_ADDR (1 << 10)
+#define PHASE28_AC97_DATA_LOW (1 << 9)
+#define PHASE28_AC97_DATA_HIGH (1 << 8)
+#define PHASE28_AC97_DATA_MASK 0xFF
#endif /* __SOUND_PHASE */
.eeprom_size = sizeof(k8x800_eeprom),
.eeprom_data = k8x800_eeprom,
},
+ {
+ .subvendor = VT1720_SUBDEVICE_SN25P,
+ .name = "Shuttle SN25P",
+ /* identical with k8x800 */
+ .chip_init = k8x800_init,
+ .build_controls = k8x800_add_controls,
+ .eeprom_size = sizeof(k8x800_eeprom),
+ .eeprom_data = k8x800_eeprom,
+ },
{ } /* terminator */
};
#define VT1720_MOBO_DEVICE_DESC "{Albatron,K8X800 Pro II},"\
"{Chaintech,ZNF3-150},"\
"{Chaintech,ZNF3-250},"\
- "{Chaintech,9CJS},"
+ "{Chaintech,9CJS},"\
+ "{Shuttle,SN25P},"
#define VT1720_SUBDEVICE_K8X800 0xf217052c
#define VT1720_SUBDEVICE_ZNF3_150 0x0f2741f6
#define VT1720_SUBDEVICE_ZNF3_250 0x0f2745f6
#define VT1720_SUBDEVICE_9CJS 0x0f272327
+#define VT1720_SUBDEVICE_SN25P 0x97123650
extern struct snd_ice1712_card_info snd_vt1720_mobo_cards[];
static struct ac97_quirk ac97_quirks[] __devinitdata = {
{
- .vendor = 0x0e11,
- .device = 0x008a,
+ .subvendor = 0x0e11,
+ .subdevice = 0x008a,
.name = "Compaq Evo W4000", /* AD1885 */
.type = AC97_TUNE_HP_ONLY
},
{
- .vendor = 0x0e11,
- .device = 0x00b8,
+ .subvendor = 0x0e11,
+ .subdevice = 0x00b8,
.name = "Compaq Evo D510C",
.type = AC97_TUNE_HP_ONLY
},
{
- .vendor = 0x0e11,
- .device = 0x0860,
+ .subvendor = 0x0e11,
+ .subdevice = 0x0860,
.name = "HP/Compaq nx7010",
.type = AC97_TUNE_MUTE_LED
},
{
- .vendor = 0x1014,
- .device = 0x1f00,
+ .subvendor = 0x1014,
+ .subdevice = 0x1f00,
.name = "MS-9128",
.type = AC97_TUNE_ALC_JACK
},
{
- .vendor = 0x1028,
- .device = 0x00d8,
+ .subvendor = 0x1028,
+ .subdevice = 0x00d8,
.name = "Dell Precision 530", /* AD1885 */
.type = AC97_TUNE_HP_ONLY
},
{
- .vendor = 0x1028,
- .device = 0x010d,
+ .subvendor = 0x1028,
+ .subdevice = 0x010d,
.name = "Dell", /* which model? AD1885 */
.type = AC97_TUNE_HP_ONLY
},
{
- .vendor = 0x1028,
- .device = 0x0126,
+ .subvendor = 0x1028,
+ .subdevice = 0x0126,
.name = "Dell Optiplex GX260", /* AD1981A */
.type = AC97_TUNE_HP_ONLY
},
{
- .vendor = 0x1028,
- .device = 0x012c,
+ .subvendor = 0x1028,
+ .subdevice = 0x012c,
.name = "Dell Precision 650", /* AD1981A */
.type = AC97_TUNE_HP_ONLY
},
{
- .vendor = 0x1028,
- .device = 0x012d,
+ .subvendor = 0x1028,
+ .subdevice = 0x012d,
.name = "Dell Precision 450", /* AD1981B*/
.type = AC97_TUNE_HP_ONLY
},
{
- .vendor = 0x1028,
- .device = 0x0147,
+ .subvendor = 0x1028,
+ .subdevice = 0x0147,
.name = "Dell", /* which model? AD1981B*/
.type = AC97_TUNE_HP_ONLY
},
{
- .vendor = 0x1028,
- .device = 0x0163,
+ .subvendor = 0x1028,
+ .subdevice = 0x0163,
.name = "Dell Unknown", /* STAC9750/51 */
.type = AC97_TUNE_HP_ONLY
},
{
- .vendor = 0x103c,
- .device = 0x006d,
+ .subvendor = 0x103c,
+ .subdevice = 0x006d,
.name = "HP zv5000",
.type = AC97_TUNE_MUTE_LED /*AD1981B*/
},
{ /* FIXME: which codec? */
- .vendor = 0x103c,
- .device = 0x00c3,
+ .subvendor = 0x103c,
+ .subdevice = 0x00c3,
.name = "HP xw6000",
.type = AC97_TUNE_HP_ONLY
},
{
- .vendor = 0x103c,
- .device = 0x088c,
+ .subvendor = 0x103c,
+ .subdevice = 0x088c,
.name = "HP nc8000",
.type = AC97_TUNE_MUTE_LED
},
{
- .vendor = 0x103c,
- .device = 0x0890,
+ .subvendor = 0x103c,
+ .subdevice = 0x0890,
.name = "HP nc6000",
.type = AC97_TUNE_MUTE_LED
},
{
- .vendor = 0x103c,
- .device = 0x129d,
+ .subvendor = 0x103c,
+ .subdevice = 0x129d,
.name = "HP xw8000",
.type = AC97_TUNE_HP_ONLY
},
{
- .vendor = 0x103c,
- .device = 0x12f1,
+ .subvendor = 0x103c,
+ .subdevice = 0x12f1,
.name = "HP xw8200", /* AD1981B*/
.type = AC97_TUNE_HP_ONLY
},
{
- .vendor = 0x103c,
- .device = 0x12f2,
+ .subvendor = 0x103c,
+ .subdevice = 0x12f2,
.name = "HP xw6200",
.type = AC97_TUNE_HP_ONLY
},
{
- .vendor = 0x103c,
- .device = 0x3008,
+ .subvendor = 0x103c,
+ .subdevice = 0x3008,
.name = "HP xw4200", /* AD1981B*/
.type = AC97_TUNE_HP_ONLY
},
{
- .vendor = 0x104d,
- .device = 0x8197,
+ .subvendor = 0x104d,
+ .subdevice = 0x8197,
.name = "Sony S1XP",
.type = AC97_TUNE_INV_EAPD
},
{
- .vendor = 0x1043,
- .device = 0x80f3,
+ .subvendor = 0x1043,
+ .subdevice = 0x80f3,
.name = "ASUS ICH5/AD1985",
.type = AC97_TUNE_AD_SHARING
},
{
- .vendor = 0x10cf,
- .device = 0x11c3,
+ .subvendor = 0x10cf,
+ .subdevice = 0x11c3,
.name = "Fujitsu-Siemens E4010",
.type = AC97_TUNE_HP_ONLY
},
{
- .vendor = 0x10cf,
- .device = 0x1253,
+ .subvendor = 0x10cf,
+ .subdevice = 0x1225,
+ .name = "Fujitsu-Siemens T3010",
+ .type = AC97_TUNE_HP_ONLY
+ },
+ {
+ .subvendor = 0x10cf,
+ .subdevice = 0x1253,
.name = "Fujitsu S6210", /* STAC9750/51 */
.type = AC97_TUNE_HP_ONLY
},
{
- .vendor = 0x10f1,
- .device = 0x2665,
+ .subvendor = 0x10f1,
+ .subdevice = 0x2665,
.name = "Fujitsu-Siemens Celsius", /* AD1981? */
.type = AC97_TUNE_HP_ONLY
},
{
- .vendor = 0x10f1,
- .device = 0x2885,
+ .subvendor = 0x10f1,
+ .subdevice = 0x2885,
.name = "AMD64 Mobo", /* ALC650 */
.type = AC97_TUNE_HP_ONLY
},
{
- .vendor = 0x110a,
- .device = 0x0056,
+ .subvendor = 0x110a,
+ .subdevice = 0x0056,
.name = "Fujitsu-Siemens Scenic", /* AD1981? */
.type = AC97_TUNE_HP_ONLY
},
{
- .vendor = 0x11d4,
- .device = 0x5375,
+ .subvendor = 0x11d4,
+ .subdevice = 0x5375,
.name = "ADI AD1985 (discrete)",
.type = AC97_TUNE_HP_ONLY
},
{
- .vendor = 0x1462,
- .device = 0x5470,
+ .subvendor = 0x1462,
+ .subdevice = 0x5470,
.name = "MSI P4 ATX 645 Ultra",
.type = AC97_TUNE_HP_ONLY
},
{
- .vendor = 0x1734,
- .device = 0x0088,
+ .subvendor = 0x1734,
+ .subdevice = 0x0088,
.name = "Fujitsu-Siemens D1522", /* AD1981 */
.type = AC97_TUNE_HP_ONLY
},
{
- .vendor = 0x8086,
- .device = 0x2000,
+ .subvendor = 0x8086,
+ .subdevice = 0x2000,
.mask = 0xfff0,
.name = "Intel ICH5/AD1985",
.type = AC97_TUNE_AD_SHARING
},
{
- .vendor = 0x8086,
- .device = 0x4000,
+ .subvendor = 0x8086,
+ .subdevice = 0x4000,
.mask = 0xfff0,
.name = "Intel ICH5/AD1985",
.type = AC97_TUNE_AD_SHARING
},
{
- .vendor = 0x8086,
- .device = 0x4856,
+ .subvendor = 0x8086,
+ .subdevice = 0x4856,
.name = "Intel D845WN (82801BA)",
.type = AC97_TUNE_SWAP_HP
},
{
- .vendor = 0x8086,
- .device = 0x4d44,
+ .subvendor = 0x8086,
+ .subdevice = 0x4d44,
.name = "Intel D850EMV2", /* AD1885 */
.type = AC97_TUNE_HP_ONLY
},
{
- .vendor = 0x8086,
- .device = 0x4d56,
+ .subvendor = 0x8086,
+ .subdevice = 0x4d56,
.name = "Intel ICH/AD1885",
.type = AC97_TUNE_HP_ONLY
},
{
- .vendor = 0x8086,
- .device = 0x6000,
+ .subvendor = 0x8086,
+ .subdevice = 0x6000,
.mask = 0xfff0,
.name = "Intel ICH5/AD1985",
.type = AC97_TUNE_AD_SHARING
},
{
- .vendor = 0x8086,
- .device = 0xe000,
+ .subvendor = 0x8086,
+ .subdevice = 0xe000,
.mask = 0xfff0,
.name = "Intel ICH5/AD1985",
.type = AC97_TUNE_AD_SHARING
},
#if 0 /* FIXME: this seems wrong on most boards */
{
- .vendor = 0x8086,
- .device = 0xa000,
+ .subvendor = 0x8086,
+ .subdevice = 0xa000,
.mask = 0xfff0,
.name = "Intel ICH5/AD1985",
.type = AC97_TUNE_HP_ONLY
static int __init alsa_card_intel8x0_init(void)
{
- return pci_module_init(&driver);
+ return pci_register_driver(&driver);
}
static void __exit alsa_card_intel8x0_exit(void)
#include <sound/pcm.h>
#include <sound/ac97_codec.h>
#include <sound/info.h>
-#include <sound/control.h>
#include <sound/initval.h>
MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
#endif
{ 0, }
};
-static int snd_intel8x0m_switch_default_get(snd_kcontrol_t *kcontrol,
- snd_ctl_elem_value_t *ucontrol);
-static int snd_intel8x0m_switch_default_put(snd_kcontrol_t *kcontrol,
- snd_ctl_elem_value_t *ucontrol);
-static int snd_intel8x0m_switch_default_info(snd_kcontrol_t *kcontrol,
- snd_ctl_elem_info_t *uinfo);
-
-#define PRIVATE_VALUE_INITIALIZER(r,m) (((r) & 0xffff) << 16 | ((m) & 0xffff))
-#define PRIVATE_VALUE_MASK(control) ((control)->private_value & 0xffff)
-#define PRIVATE_VALUE_REG(control) (((control)->private_value >> 16) & 0xffff)
-
-static snd_kcontrol_new_t snd_intel8x0m_mixer_switches[] __devinitdata = {
- { .name = "Off-hook Switch",
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .info = snd_intel8x0m_switch_default_info,
- .get = snd_intel8x0m_switch_default_get,
- .put = snd_intel8x0m_switch_default_put,
- .private_value = PRIVATE_VALUE_INITIALIZER(AC97_GPIO_STATUS,AC97_GPIO_LINE1_OH)
- }
-};
MODULE_DEVICE_TABLE(pci, snd_intel8x0m_ids);
-static int snd_intel8x0m_switch_default_info(snd_kcontrol_t *kcontrol,
- snd_ctl_elem_info_t *uinfo)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
- uinfo->count = 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 1;
- return 0;
-}
-
-static int snd_intel8x0m_switch_default_get(snd_kcontrol_t *kcontrol,
- snd_ctl_elem_value_t *ucontrol)
-{
- unsigned short mask = PRIVATE_VALUE_MASK(kcontrol);
- unsigned short reg = PRIVATE_VALUE_REG(kcontrol);
- intel8x0_t *chip = snd_kcontrol_chip(kcontrol);
- unsigned int status;
- status = snd_ac97_read(chip->ac97, reg) & mask ? 1 : 0;
- ucontrol->value.integer.value[0] = status;
- return 0;
-}
-static int snd_intel8x0m_switch_default_put(snd_kcontrol_t *kcontrol,
- snd_ctl_elem_value_t *ucontrol)
-{
- unsigned short mask = PRIVATE_VALUE_MASK(kcontrol);
- unsigned short reg = PRIVATE_VALUE_REG(kcontrol);
- intel8x0_t *chip = snd_kcontrol_chip(kcontrol);
- unsigned short new_status = ucontrol->value.integer.value[0] ? mask : ~mask;
- return snd_ac97_update_bits(chip->ac97, reg,
- mask, new_status);
-}
/*
* Lowlevel I/O - busmaster
*/
res = 0xffff;
}
}
+ if (reg == AC97_GPIO_STATUS)
+ iagetword(chip, 0); /* clear semaphore */
return res;
}
return bytes_to_frames(substream->runtime, ptr);
}
-static int snd_intel8x0m_pcm_trigger(snd_pcm_substream_t *substream, int cmd)
-{
- /* hook off/on on start/stop */
- /* Moved this to mixer control */
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- break;
- case SNDRV_PCM_TRIGGER_STOP:
- break;
- default:
- return -EINVAL;
- }
- return snd_intel8x0_pcm_trigger(substream,cmd);
-}
-
static int snd_intel8x0m_pcm_prepare(snd_pcm_substream_t * substream)
{
intel8x0_t *chip = snd_pcm_substream_chip(substream);
.hw_params = snd_intel8x0_hw_params,
.hw_free = snd_intel8x0_hw_free,
.prepare = snd_intel8x0m_pcm_prepare,
- .trigger = snd_intel8x0m_pcm_trigger,
+ .trigger = snd_intel8x0_pcm_trigger,
.pointer = snd_intel8x0_pcm_pointer,
};
.hw_params = snd_intel8x0_hw_params,
.hw_free = snd_intel8x0_hw_free,
.prepare = snd_intel8x0m_pcm_prepare,
- .trigger = snd_intel8x0m_pcm_trigger,
+ .trigger = snd_intel8x0_pcm_trigger,
.pointer = snd_intel8x0_pcm_pointer,
};
ac97_t *x97;
int err;
unsigned int glob_sta = 0;
- unsigned int idx;
static ac97_bus_ops_t ops = {
.write = snd_intel8x0_codec_write,
.read = snd_intel8x0_codec_read,
chip->ichd[ICHD_MDMIN].ac97 = x97;
chip->ichd[ICHD_MDMOUT].ac97 = x97;
}
- for (idx = 0; idx < ARRAY_SIZE(snd_intel8x0m_mixer_switches); idx++) {
- if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_intel8x0m_mixer_switches[idx], chip))) < 0)
- goto __err;
- }
chip->in_ac97_init = 0;
return 0;
static int __init alsa_card_intel8x0m_init(void)
{
- return pci_module_init(&driver);
+ return pci_register_driver(&driver);
}
static void __exit alsa_card_intel8x0m_exit(void)
static int __init alsa_card_korg1212_init(void)
{
- return pci_module_init(&driver);
+ return pci_register_driver(&driver);
}
static void __exit alsa_card_korg1212_exit(void)
(e.g. for IrDA on Dell Inspirons) */
};
+struct m3_hv_quirk {
+ u16 vendor, device, subsystem_vendor, subsystem_device;
+ u32 config; /* ALLEGRO_CONFIG hardware volume bits */
+ int is_omnibook; /* Do HP OmniBook GPIO magic? */
+};
+
struct m3_list {
int curlen;
int mem_addr;
struct pci_dev *pci;
struct m3_quirk *quirk;
+ struct m3_hv_quirk *hv_quirk;
int dacs_active;
int timer_users;
m3_dma_t *substreams;
spinlock_t reg_lock;
+ spinlock_t ac97_lock;
+
+ snd_kcontrol_t *master_switch;
+ snd_kcontrol_t *master_volume;
+ struct tasklet_struct hwvol_tq;
#ifdef CONFIG_PM
u16 *suspend_mem;
{ NULL }
};
+/* These values came from the Windows driver. */
+static struct m3_hv_quirk m3_hv_quirk_list[] = {
+ /* Allegro chips */
+ { 0x125D, 0x1988, 0x0E11, 0x002E, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+ { 0x125D, 0x1988, 0x0E11, 0x0094, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+ { 0x125D, 0x1988, 0x0E11, 0xB112, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+ { 0x125D, 0x1988, 0x0E11, 0xB114, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+ { 0x125D, 0x1988, 0x103C, 0x0012, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+ { 0x125D, 0x1988, 0x103C, 0x0018, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+ { 0x125D, 0x1988, 0x103C, 0x001C, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+ { 0x125D, 0x1988, 0x103C, 0x001D, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+ { 0x125D, 0x1988, 0x103C, 0x001E, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+ { 0x125D, 0x1988, 0x107B, 0x3350, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+ { 0x125D, 0x1988, 0x10F7, 0x8338, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+ { 0x125D, 0x1988, 0x10F7, 0x833C, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+ { 0x125D, 0x1988, 0x10F7, 0x833D, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+ { 0x125D, 0x1988, 0x10F7, 0x833E, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+ { 0x125D, 0x1988, 0x10F7, 0x833F, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+ { 0x125D, 0x1988, 0x13BD, 0x1018, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+ { 0x125D, 0x1988, 0x13BD, 0x1019, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+ { 0x125D, 0x1988, 0x13BD, 0x101A, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+ { 0x125D, 0x1988, 0x14FF, 0x0F03, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+ { 0x125D, 0x1988, 0x14FF, 0x0F04, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+ { 0x125D, 0x1988, 0x14FF, 0x0F05, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+ { 0x125D, 0x1988, 0x156D, 0xB400, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+ { 0x125D, 0x1988, 0x156D, 0xB795, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+ { 0x125D, 0x1988, 0x156D, 0xB797, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+ { 0x125D, 0x1988, 0x156D, 0xC700, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+ { 0x125D, 0x1988, 0x1033, 0x80F1, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
+ { 0x125D, 0x1988, 0x103C, 0x001A, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, /* HP OmniBook 6100 */
+ { 0x125D, 0x1988, 0x107B, 0x340A, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
+ { 0x125D, 0x1988, 0x107B, 0x3450, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
+ { 0x125D, 0x1988, 0x109F, 0x3134, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
+ { 0x125D, 0x1988, 0x109F, 0x3161, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
+ { 0x125D, 0x1988, 0x144D, 0x3280, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
+ { 0x125D, 0x1988, 0x144D, 0x3281, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
+ { 0x125D, 0x1988, 0x144D, 0xC002, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
+ { 0x125D, 0x1988, 0x144D, 0xC003, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
+ { 0x125D, 0x1988, 0x1509, 0x1740, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
+ { 0x125D, 0x1988, 0x1610, 0x0010, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
+ { 0x125D, 0x1988, 0x1042, 0x1042, HV_CTRL_ENABLE, 0 },
+ { 0x125D, 0x1988, 0x107B, 0x9500, HV_CTRL_ENABLE, 0 },
+ { 0x125D, 0x1988, 0x14FF, 0x0F06, HV_CTRL_ENABLE, 0 },
+ { 0x125D, 0x1988, 0x1558, 0x8586, HV_CTRL_ENABLE, 0 },
+ { 0x125D, 0x1988, 0x161F, 0x2011, HV_CTRL_ENABLE, 0 },
+ /* Maestro3 chips */
+ { 0x125D, 0x1998, 0x103C, 0x000E, HV_CTRL_ENABLE, 0 },
+ { 0x125D, 0x1998, 0x103C, 0x0010, HV_CTRL_ENABLE, 1 }, /* HP OmniBook 6000 */
+ { 0x125D, 0x1998, 0x103C, 0x0011, HV_CTRL_ENABLE, 1 }, /* HP OmniBook 500 */
+ { 0x125D, 0x1998, 0x103C, 0x001B, HV_CTRL_ENABLE, 0 },
+ { 0x125D, 0x1998, 0x104D, 0x80A6, HV_CTRL_ENABLE, 0 },
+ { 0x125D, 0x1998, 0x104D, 0x80AA, HV_CTRL_ENABLE, 0 },
+ { 0x125D, 0x1998, 0x107B, 0x5300, HV_CTRL_ENABLE, 0 },
+ { 0x125D, 0x1998, 0x110A, 0x1998, HV_CTRL_ENABLE, 0 },
+ { 0x125D, 0x1998, 0x13BD, 0x1015, HV_CTRL_ENABLE, 0 },
+ { 0x125D, 0x1998, 0x13BD, 0x101C, HV_CTRL_ENABLE, 0 },
+ { 0x125D, 0x1998, 0x13BD, 0x1802, HV_CTRL_ENABLE, 0 },
+ { 0x125D, 0x1998, 0x1599, 0x0715, HV_CTRL_ENABLE, 0 },
+ { 0x125D, 0x1998, 0x5643, 0x5643, HV_CTRL_ENABLE, 0 },
+ { 0x125D, 0x199A, 0x144D, 0x3260, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 },
+ { 0x125D, 0x199A, 0x144D, 0x3261, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 },
+ { 0x125D, 0x199A, 0x144D, 0xC000, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 },
+ { 0x125D, 0x199A, 0x144D, 0xC001, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 },
+ { 0 }
+};
/*
* lowlevel functions
}
}
+static void snd_m3_update_hw_volume(unsigned long private_data)
+{
+ m3_t *chip = (m3_t *) private_data;
+ int x, val;
+ unsigned long flags;
+
+ /* Figure out which volume control button was pushed,
+ based on differences from the default register
+ values. */
+ x = inb(chip->iobase + SHADOW_MIX_REG_VOICE) & 0xee;
+
+ /* Reset the volume control registers. */
+ outb(0x88, chip->iobase + SHADOW_MIX_REG_VOICE);
+ outb(0x88, chip->iobase + HW_VOL_COUNTER_VOICE);
+ outb(0x88, chip->iobase + SHADOW_MIX_REG_MASTER);
+ outb(0x88, chip->iobase + HW_VOL_COUNTER_MASTER);
+
+ if (!chip->master_switch || !chip->master_volume)
+ return;
+
+ /* FIXME: we can't call snd_ac97_* functions since here is in tasklet. */
+ spin_lock_irqsave(&chip->ac97_lock, flags);
+
+ val = chip->ac97->regs[AC97_MASTER_VOL];
+ switch (x) {
+ case 0x88:
+ /* mute */
+ val ^= 0x8000;
+ chip->ac97->regs[AC97_MASTER_VOL] = val;
+ outw(val, chip->iobase + CODEC_DATA);
+ outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND);
+ snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &chip->master_switch->id);
+ break;
+ case 0xaa:
+ /* volume up */
+ if ((val & 0x7f) > 0)
+ val--;
+ if ((val & 0x7f00) > 0)
+ val -= 0x0100;
+ chip->ac97->regs[AC97_MASTER_VOL] = val;
+ outw(val, chip->iobase + CODEC_DATA);
+ outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND);
+ snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &chip->master_volume->id);
+ break;
+ case 0x66:
+ /* volume down */
+ if ((val & 0x7f) < 0x1f)
+ val++;
+ if ((val & 0x7f00) < 0x1f00)
+ val += 0x0100;
+ chip->ac97->regs[AC97_MASTER_VOL] = val;
+ outw(val, chip->iobase + CODEC_DATA);
+ outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND);
+ snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &chip->master_volume->id);
+ break;
+ }
+ spin_unlock_irqrestore(&chip->ac97_lock, flags);
+}
+
static irqreturn_t
snd_m3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
if (status == 0xff)
return IRQ_NONE;
-
+
+ if (status & HV_INT_PENDING)
+ tasklet_hi_schedule(&chip->hwvol_tq);
+
/*
* ack an assp int if its running
* and has an int pending
#endif
/* ack ints */
- snd_m3_outw(chip, HOST_INT_STATUS, status);
+ outb(status, chip->iobase + HOST_INT_STATUS);
return IRQ_HANDLED;
}
snd_m3_ac97_read(ac97_t *ac97, unsigned short reg)
{
m3_t *chip = ac97->private_data;
+ unsigned long flags;
+ unsigned short data;
if (snd_m3_ac97_wait(chip))
return 0xffff;
+ spin_lock_irqsave(&chip->ac97_lock, flags);
snd_m3_outb(chip, 0x80 | (reg & 0x7f), CODEC_COMMAND);
if (snd_m3_ac97_wait(chip))
return 0xffff;
- return snd_m3_inw(chip, CODEC_DATA);
+ data = snd_m3_inw(chip, CODEC_DATA);
+ spin_unlock_irqrestore(&chip->ac97_lock, flags);
+ return data;
}
static void
snd_m3_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short val)
{
m3_t *chip = ac97->private_data;
+ unsigned long flags;
if (snd_m3_ac97_wait(chip))
return;
+ spin_lock_irqsave(&chip->ac97_lock, flags);
snd_m3_outw(chip, val, CODEC_DATA);
snd_m3_outb(chip, reg & 0x7f, CODEC_COMMAND);
+ spin_unlock_irqrestore(&chip->ac97_lock, flags);
}
{
ac97_bus_t *pbus;
ac97_template_t ac97;
+ snd_ctl_elem_id_t id;
int err;
static ac97_bus_ops_t ops = {
.write = snd_m3_ac97_write,
schedule_timeout(HZ / 10);
snd_ac97_write(chip->ac97, AC97_PCM, 0);
+ memset(&id, 0, sizeof(id));
+ id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ strcpy(id.name, "Master Playback Switch");
+ chip->master_switch = snd_ctl_find_id(chip->card, &id);
+ memset(&id, 0, sizeof(id));
+ id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ strcpy(id.name, "Master Playback Volume");
+ chip->master_volume = snd_ctl_find_id(chip->card, &id);
+
return 0;
}
snd_m3_chip_init(m3_t *chip)
{
struct pci_dev *pcidev = chip->pci;
+ unsigned long io = chip->iobase;
u32 n;
u16 w;
u8 t; /* makes as much sense as 'n', no? */
DISABLE_LEGACY);
pci_write_config_word(pcidev, PCI_LEGACY_AUDIO_CTRL, w);
+ if (chip->hv_quirk && chip->hv_quirk->is_omnibook) {
+ /*
+ * Volume buttons on some HP OmniBook laptops don't work
+ * correctly. This makes them work for the most part.
+ *
+ * Volume up and down buttons on the laptop side work.
+ * Fn+cursor_up (volme up) works.
+ * Fn+cursor_down (volume down) doesn't work.
+ * Fn+F7 (mute) works acts as volume up.
+ */
+ outw(~(GPI_VOL_DOWN|GPI_VOL_UP), io + GPIO_MASK);
+ outw(inw(io + GPIO_DIRECTION) & ~(GPI_VOL_DOWN|GPI_VOL_UP), io + GPIO_DIRECTION);
+ outw((GPI_VOL_DOWN|GPI_VOL_UP), io + GPIO_DATA);
+ outw(0xffff, io + GPIO_MASK);
+ }
pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n);
- n &= REDUCED_DEBOUNCE;
+ n &= ~(HV_CTRL_ENABLE | REDUCED_DEBOUNCE | HV_BUTTON_FROM_GD);
+ if (chip->hv_quirk)
+ n |= chip->hv_quirk->config;
+ /* For some reason we must always use reduced debounce. */
+ n |= REDUCED_DEBOUNCE;
n |= PM_CTRL_ENABLE | CLK_DIV_BY_49 | USE_PCI_TIMING;
pci_write_config_dword(pcidev, PCI_ALLEGRO_CONFIG, n);
outb(RUN_ASSP, chip->iobase + ASSP_CONTROL_B);
+ outb(0x00, io + HARDWARE_VOL_CTRL);
+ outb(0x88, io + SHADOW_MIX_REG_VOICE);
+ outb(0x88, io + HW_VOL_COUNTER_VOICE);
+ outb(0x88, io + SHADOW_MIX_REG_MASTER);
+ outb(0x88, io + HW_VOL_COUNTER_MASTER);
+
return 0;
}
unsigned long io = chip->iobase;
/* TODO: MPU401 not supported yet */
- outw(ASSP_INT_ENABLE /*| MPU401_INT_ENABLE*/, io + HOST_INT_CTRL);
+ outw(ASSP_INT_ENABLE | HV_INT_ENABLE /*| MPU401_INT_ENABLE*/, io + HOST_INT_CTRL);
outb(inb(io + ASSP_CONTROL_C) | ASSP_HOST_INT_ENABLE,
io + ASSP_CONTROL_C);
}
kfree(chip->substreams);
}
if (chip->iobase) {
- snd_m3_outw(chip, HOST_INT_CTRL, 0); /* disable ints */
+ outw(0, chip->iobase + HOST_INT_CTRL); /* disable ints */
}
#ifdef CONFIG_PM
m3_t *chip;
int i, err;
struct m3_quirk *quirk;
- u16 subsystem_vendor, subsystem_device;
+ struct m3_hv_quirk *hv_quirk;
static snd_device_ops_t ops = {
.dev_free = snd_m3_dev_free,
};
chip->pci = pci;
chip->irq = -1;
- pci_read_config_word(pci, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor);
- pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &subsystem_device);
-
for (quirk = m3_quirk_list; quirk->vendor; quirk++) {
- if (subsystem_vendor == quirk->vendor &&
- subsystem_device == quirk->device) {
+ if (pci->subsystem_vendor == quirk->vendor &&
+ pci->subsystem_device == quirk->device) {
printk(KERN_INFO "maestro3: enabled hack for '%s'\n", quirk->name);
chip->quirk = quirk;
break;
}
}
+ for (hv_quirk = m3_hv_quirk_list; hv_quirk->vendor; hv_quirk++) {
+ if (pci->vendor == hv_quirk->vendor &&
+ pci->device == hv_quirk->device &&
+ pci->subsystem_vendor == hv_quirk->subsystem_vendor &&
+ pci->subsystem_device == hv_quirk->subsystem_device) {
+ chip->hv_quirk = hv_quirk;
+ break;
+ }
+ }
+
chip->external_amp = enable_amp;
if (amp_gpio >= 0 && amp_gpio <= 0x0f)
chip->amp_gpio = amp_gpio;
return err;
}
+ spin_lock_init(&chip->ac97_lock);
+ tasklet_init(&chip->hwvol_tq, snd_m3_update_hw_volume, (unsigned long)chip);
+
if ((err = snd_m3_mixer(chip)) < 0)
return err;
static int __init alsa_card_m3_init(void)
{
- return pci_module_init(&driver);
+ return pci_register_driver(&driver);
}
static void __exit alsa_card_m3_exit(void)
static int __init alsa_card_mixart_init(void)
{
- return pci_module_init(&driver);
+ return pci_register_driver(&driver);
}
static void __exit alsa_card_mixart_exit(void)
static int __init alsa_card_nm256_init(void)
{
- return pci_module_init(&driver);
+ return pci_register_driver(&driver);
}
static void __exit alsa_card_nm256_exit(void)
static int __init alsa_card_rme32_init(void)
{
- return pci_module_init(&driver);
+ return pci_register_driver(&driver);
}
static void __exit alsa_card_rme32_exit(void)
static int __init alsa_card_rme96_init(void)
{
- return pci_module_init(&driver);
+ return pci_register_driver(&driver);
}
static void __exit alsa_card_rme96_exit(void)
snd-rme9652-objs := rme9652.o
snd-hdsp-objs := hdsp.o
+snd-hdspm-objs := hdspm.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_RME9652) += snd-rme9652.o
obj-$(CONFIG_SND_HDSP) += snd-hdsp.o
+obj-$(CONFIG_SND_HDSPM) +=snd-hdspm.o
{
dmab->dev.type = SNDRV_DMA_TYPE_DEV;
dmab->dev.dev = snd_dma_pci_data(pci);
- if (! snd_dma_get_reserved_buf(dmab, snd_dma_pci_buf_id(pci))) {
- if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
- size, dmab) < 0)
- return -ENOMEM;
+ if (snd_dma_get_reserved_buf(dmab, snd_dma_pci_buf_id(pci))) {
+ if (dmab->bytes >= size)
+ return 0;
}
+ if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
+ size, dmab) < 0)
+ return -ENOMEM;
return 0;
}
static void snd_hammerfall_free_buffer(struct snd_dma_buffer *dmab, struct pci_dev *pci)
{
- if (dmab->area)
+ if (dmab->area) {
+ dmab->dev.dev = NULL; /* make it anonymous */
snd_dma_reserve_buf(dmab, snd_dma_pci_buf_id(pci));
+ }
}
release_firmware(fw);
return -EINVAL;
}
-#ifdef SNDRV_BIG_ENDIAN
- {
- int i;
- u32 *src = (u32*)fw->data;
- for (i = 0; i < ARRAY_SIZE(hdsp->firmware_cache); i++, src++)
- hdsp->firmware_cache[i] = ((*src & 0x000000ff) << 16) |
- ((*src & 0x0000ff00) << 8) |
- ((*src & 0x00ff0000) >> 8) |
- ((*src & 0xff000000) >> 16);
- }
-#else
+
memcpy(hdsp->firmware_cache, fw->data, sizeof(hdsp->firmware_cache));
-#endif
+
release_firmware(fw);
hdsp->state |= HDSP_FirmwareCached;
static int __init alsa_card_hdsp_init(void)
{
- return pci_module_init(&driver);
+ return pci_register_driver(&driver);
}
static void __exit alsa_card_hdsp_exit(void)
--- /dev/null
+/* -*- linux-c -*-
+ *
+ * ALSA driver for RME Hammerfall DSP MADI audio interface(s)
+ *
+ * Copyright (c) 2003 Winfried Ritsch (IEM)
+ * code based on hdsp.c Paul Davis
+ * Marcus Andersson
+ * Thomas Charbonnel
+ *
+ * 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 <linux/init.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/moduleparam.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/info.h>
+#include <sound/asoundef.h>
+#include <sound/rawmidi.h>
+#include <sound/hwdep.h>
+#include <sound/initval.h>
+
+#include <sound/hdspm.h>
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;/* Enable this card */
+
+/* Disable precise pointer at start */
+static int precise_ptr[SNDRV_CARDS];
+
+/* Send all playback to line outs */
+static int line_outs_monitor[SNDRV_CARDS];
+
+/* Enable Analog Outs on Channel 63/64 by default */
+static int enable_monitor[SNDRV_CARDS];
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for RME HDSPM interface.");
+
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for RME HDSPM interface.");
+
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable/disable specific HDSPM soundcards.");
+
+module_param_array(precise_ptr, bool, NULL, 0444);
+MODULE_PARM_DESC(precise_ptr, "Enable precise pointer, or disable.");
+
+module_param_array(line_outs_monitor, bool, NULL, 0444);
+MODULE_PARM_DESC(line_outs_monitor,
+ "Send playback streams to analog outs by default.");
+
+module_param_array(enable_monitor, bool, NULL, 0444);
+MODULE_PARM_DESC(enable_monitor,
+ "Enable Analog Out on Channel 63/64 by default.");
+
+MODULE_AUTHOR
+ ("Winfried Ritsch <ritsch_AT_iem.at>, Paul Davis <paul@linuxaudiosystems.com>, "
+ "Marcus Andersson, Thomas Charbonnel <thomas@undata.org>");
+MODULE_DESCRIPTION("RME HDSPM");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
+
+/* --- Write registers. ---
+ These are defined as byte-offsets from the iobase value. */
+
+#define HDSPM_controlRegister 64
+#define HDSPM_interruptConfirmation 96
+#define HDSPM_control2Reg 256 /* not in specs ???????? */
+#define HDSPM_midiDataOut0 352 /* just believe in old code */
+#define HDSPM_midiDataOut1 356
+
+/* DMA enable for 64 channels, only Bit 0 is relevant */
+#define HDSPM_outputEnableBase 512 /* 512-767 input DMA */
+#define HDSPM_inputEnableBase 768 /* 768-1023 output DMA */
+
+/* 16 page addresses for each of the 64 channels DMA buffer in and out
+ (each 64k=16*4k) Buffer must be 4k aligned (which is default i386 ????) */
+#define HDSPM_pageAddressBufferOut 8192
+#define HDSPM_pageAddressBufferIn (HDSPM_pageAddressBufferOut+64*16*4)
+
+#define HDSPM_MADI_mixerBase 32768 /* 32768-65535 for 2x64x64 Fader */
+
+#define HDSPM_MATRIX_MIXER_SIZE 8192 /* = 2*64*64 * 4 Byte => 32kB */
+
+/* --- Read registers. ---
+ These are defined as byte-offsets from the iobase value */
+#define HDSPM_statusRegister 0
+#define HDSPM_statusRegister2 96
+
+#define HDSPM_midiDataIn0 360
+#define HDSPM_midiDataIn1 364
+
+/* status is data bytes in MIDI-FIFO (0-128) */
+#define HDSPM_midiStatusOut0 384
+#define HDSPM_midiStatusOut1 388
+#define HDSPM_midiStatusIn0 392
+#define HDSPM_midiStatusIn1 396
+
+
+/* the meters are regular i/o-mapped registers, but offset
+ considerably from the rest. the peak registers are reset
+ when read; the least-significant 4 bits are full-scale counters;
+ the actual peak value is in the most-significant 24 bits.
+*/
+#define HDSPM_MADI_peakrmsbase 4096 /* 4096-8191 2x64x32Bit Meters */
+
+/* --- Control Register bits --------- */
+#define HDSPM_Start (1<<0) /* start engine */
+
+#define HDSPM_Latency0 (1<<1) /* buffer size = 2^n */
+#define HDSPM_Latency1 (1<<2) /* where n is defined */
+#define HDSPM_Latency2 (1<<3) /* by Latency{2,1,0} */
+
+#define HDSPM_ClockModeMaster (1<<4) /* 1=Master, 0=Slave/Autosync */
+
+#define HDSPM_AudioInterruptEnable (1<<5) /* what do you think ? */
+
+#define HDSPM_Frequency0 (1<<6) /* 0=44.1kHz/88.2kHz 1=48kHz/96kHz */
+#define HDSPM_Frequency1 (1<<7) /* 0=32kHz/64kHz */
+#define HDSPM_DoubleSpeed (1<<8) /* 0=normal speed, 1=double speed */
+#define HDSPM_QuadSpeed (1<<31) /* quad speed bit, not implemented now */
+
+#define HDSPM_TX_64ch (1<<10) /* Output 64channel MODE=1,
+ 56channelMODE=0 */
+
+#define HDSPM_AutoInp (1<<11) /* Auto Input (takeover) == Safe Mode,
+ 0=off, 1=on */
+
+#define HDSPM_InputSelect0 (1<<14) /* Input select 0= optical, 1=coax */
+#define HDSPM_InputSelect1 (1<<15) /* should be 0 */
+
+#define HDSPM_SyncRef0 (1<<16) /* 0=WOrd, 1=MADI */
+#define HDSPM_SyncRef1 (1<<17) /* should be 0 */
+
+#define HDSPM_clr_tms (1<<19) /* clear track marker, do not use
+ AES additional bits in
+ lower 5 Audiodatabits ??? */
+
+#define HDSPM_Midi0InterruptEnable (1<<22)
+#define HDSPM_Midi1InterruptEnable (1<<23)
+
+#define HDSPM_LineOut (1<<24) /* Analog Out on channel 63/64 on=1, mute=0 */
+
+
+/* --- bit helper defines */
+#define HDSPM_LatencyMask (HDSPM_Latency0|HDSPM_Latency1|HDSPM_Latency2)
+#define HDSPM_FrequencyMask (HDSPM_Frequency0|HDSPM_Frequency1)
+#define HDSPM_InputMask (HDSPM_InputSelect0|HDSPM_InputSelect1)
+#define HDSPM_InputOptical 0
+#define HDSPM_InputCoaxial (HDSPM_InputSelect0)
+#define HDSPM_SyncRefMask (HDSPM_SyncRef0|HDSPM_SyncRef1)
+#define HDSPM_SyncRef_Word 0
+#define HDSPM_SyncRef_MADI (HDSPM_SyncRef0)
+
+#define HDSPM_SYNC_FROM_WORD 0 /* Preferred sync reference */
+#define HDSPM_SYNC_FROM_MADI 1 /* choices - used by "pref_sync_ref" */
+
+#define HDSPM_Frequency32KHz HDSPM_Frequency0
+#define HDSPM_Frequency44_1KHz HDSPM_Frequency1
+#define HDSPM_Frequency48KHz (HDSPM_Frequency1|HDSPM_Frequency0)
+#define HDSPM_Frequency64KHz (HDSPM_DoubleSpeed|HDSPM_Frequency0)
+#define HDSPM_Frequency88_2KHz (HDSPM_DoubleSpeed|HDSPM_Frequency1)
+#define HDSPM_Frequency96KHz (HDSPM_DoubleSpeed|HDSPM_Frequency1|HDSPM_Frequency0)
+
+/* --- for internal discrimination */
+#define HDSPM_CLOCK_SOURCE_AUTOSYNC 0 /* Sample Clock Sources */
+#define HDSPM_CLOCK_SOURCE_INTERNAL_32KHZ 1
+#define HDSPM_CLOCK_SOURCE_INTERNAL_44_1KHZ 2
+#define HDSPM_CLOCK_SOURCE_INTERNAL_48KHZ 3
+#define HDSPM_CLOCK_SOURCE_INTERNAL_64KHZ 4
+#define HDSPM_CLOCK_SOURCE_INTERNAL_88_2KHZ 5
+#define HDSPM_CLOCK_SOURCE_INTERNAL_96KHZ 6
+#define HDSPM_CLOCK_SOURCE_INTERNAL_128KHZ 7
+#define HDSPM_CLOCK_SOURCE_INTERNAL_176_4KHZ 8
+#define HDSPM_CLOCK_SOURCE_INTERNAL_192KHZ 9
+
+/* Synccheck Status */
+#define HDSPM_SYNC_CHECK_NO_LOCK 0
+#define HDSPM_SYNC_CHECK_LOCK 1
+#define HDSPM_SYNC_CHECK_SYNC 2
+
+/* AutoSync References - used by "autosync_ref" control switch */
+#define HDSPM_AUTOSYNC_FROM_WORD 0
+#define HDSPM_AUTOSYNC_FROM_MADI 1
+#define HDSPM_AUTOSYNC_FROM_NONE 2
+
+/* Possible sources of MADI input */
+#define HDSPM_OPTICAL 0 /* optical */
+#define HDSPM_COAXIAL 1 /* BNC */
+
+#define hdspm_encode_latency(x) (((x)<<1) & HDSPM_LatencyMask)
+#define hdspm_decode_latency(x) (((x) & HDSPM_LatencyMask)>>1)
+
+#define hdspm_encode_in(x) (((x)&0x3)<<14)
+#define hdspm_decode_in(x) (((x)>>14)&0x3)
+
+/* --- control2 register bits --- */
+#define HDSPM_TMS (1<<0)
+#define HDSPM_TCK (1<<1)
+#define HDSPM_TDI (1<<2)
+#define HDSPM_JTAG (1<<3)
+#define HDSPM_PWDN (1<<4)
+#define HDSPM_PROGRAM (1<<5)
+#define HDSPM_CONFIG_MODE_0 (1<<6)
+#define HDSPM_CONFIG_MODE_1 (1<<7)
+/*#define HDSPM_VERSION_BIT (1<<8) not defined any more*/
+#define HDSPM_BIGENDIAN_MODE (1<<9)
+#define HDSPM_RD_MULTIPLE (1<<10)
+
+/* --- Status Register bits --- */
+#define HDSPM_audioIRQPending (1<<0) /* IRQ is high and pending */
+#define HDSPM_RX_64ch (1<<1) /* Input 64chan. MODE=1, 56chn. MODE=0 */
+#define HDSPM_AB_int (1<<2) /* InputChannel Opt=0, Coax=1 (like inp0) */
+#define HDSPM_madiLock (1<<3) /* MADI Locked =1, no=0 */
+
+#define HDSPM_BufferPositionMask 0x000FFC0 /* Bit 6..15 : h/w buffer pointer */
+ /* since 64byte accurate last 6 bits
+ are not used */
+
+#define HDSPM_madiSync (1<<18) /* MADI is in sync */
+#define HDSPM_DoubleSpeedStatus (1<<19) /* (input) card in double speed */
+
+#define HDSPM_madiFreq0 (1<<22) /* system freq 0=error */
+#define HDSPM_madiFreq1 (1<<23) /* 1=32, 2=44.1 3=48 */
+#define HDSPM_madiFreq2 (1<<24) /* 4=64, 5=88.2 6=96 */
+#define HDSPM_madiFreq3 (1<<25) /* 7=128, 8=176.4 9=192 */
+
+#define HDSPM_BufferID (1<<26) /* (Double)Buffer ID toggles with Interrupt */
+#define HDSPM_midi0IRQPending (1<<30) /* MIDI IRQ is pending */
+#define HDSPM_midi1IRQPending (1<<31) /* and aktiv */
+
+/* --- status bit helpers */
+#define HDSPM_madiFreqMask (HDSPM_madiFreq0|HDSPM_madiFreq1|HDSPM_madiFreq2|HDSPM_madiFreq3)
+#define HDSPM_madiFreq32 (HDSPM_madiFreq0)
+#define HDSPM_madiFreq44_1 (HDSPM_madiFreq1)
+#define HDSPM_madiFreq48 (HDSPM_madiFreq0|HDSPM_madiFreq1)
+#define HDSPM_madiFreq64 (HDSPM_madiFreq2)
+#define HDSPM_madiFreq88_2 (HDSPM_madiFreq0|HDSPM_madiFreq2)
+#define HDSPM_madiFreq96 (HDSPM_madiFreq1|HDSPM_madiFreq2)
+#define HDSPM_madiFreq128 (HDSPM_madiFreq0|HDSPM_madiFreq1|HDSPM_madiFreq2)
+#define HDSPM_madiFreq176_4 (HDSPM_madiFreq3)
+#define HDSPM_madiFreq192 (HDSPM_madiFreq3|HDSPM_madiFreq0)
+
+/* Status2 Register bits */
+
+#define HDSPM_version0 (1<<0) /* not realy defined but I guess */
+#define HDSPM_version1 (1<<1) /* in former cards it was ??? */
+#define HDSPM_version2 (1<<2)
+
+#define HDSPM_wcLock (1<<3) /* Wordclock is detected and locked */
+#define HDSPM_wcSync (1<<4) /* Wordclock is in sync with systemclock */
+
+#define HDSPM_wc_freq0 (1<<5) /* input freq detected via autosync */
+#define HDSPM_wc_freq1 (1<<6) /* 001=32, 010==44.1, 011=48, */
+#define HDSPM_wc_freq2 (1<<7) /* 100=64, 101=88.2, 110=96, */
+/* missing Bit for 111=128, 1000=176.4, 1001=192 */
+
+#define HDSPM_SelSyncRef0 (1<<8) /* Sync Source in slave mode */
+#define HDSPM_SelSyncRef1 (1<<9) /* 000=word, 001=MADI, */
+#define HDSPM_SelSyncRef2 (1<<10) /* 111=no valid signal */
+
+#define HDSPM_wc_valid (HDSPM_wcLock|HDSPM_wcSync)
+
+#define HDSPM_wcFreqMask (HDSPM_wc_freq0|HDSPM_wc_freq1|HDSPM_wc_freq2)
+#define HDSPM_wcFreq32 (HDSPM_wc_freq0)
+#define HDSPM_wcFreq44_1 (HDSPM_wc_freq1)
+#define HDSPM_wcFreq48 (HDSPM_wc_freq0|HDSPM_wc_freq1)
+#define HDSPM_wcFreq64 (HDSPM_wc_freq2)
+#define HDSPM_wcFreq88_2 (HDSPM_wc_freq0|HDSPM_wc_freq2)
+#define HDSPM_wcFreq96 (HDSPM_wc_freq1|HDSPM_wc_freq2)
+
+
+#define HDSPM_SelSyncRefMask (HDSPM_SelSyncRef0|HDSPM_SelSyncRef1|HDSPM_SelSyncRef2)
+#define HDSPM_SelSyncRef_WORD 0
+#define HDSPM_SelSyncRef_MADI (HDSPM_SelSyncRef0)
+#define HDSPM_SelSyncRef_NVALID (HDSPM_SelSyncRef0|HDSPM_SelSyncRef1|HDSPM_SelSyncRef2)
+
+/* Mixer Values */
+#define UNITY_GAIN 32768 /* = 65536/2 */
+#define MINUS_INFINITY_GAIN 0
+
+/* PCI info */
+#ifndef PCI_VENDOR_ID_XILINX
+#define PCI_VENDOR_ID_XILINX 0x10ee
+#endif
+#ifndef PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP
+#define PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP 0x3fc5
+#endif
+#ifndef PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP_MADI
+#define PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP_MADI 0x3fc6
+#endif
+
+
+/* Number of channels for different Speed Modes */
+#define MADI_SS_CHANNELS 64
+#define MADI_DS_CHANNELS 32
+#define MADI_QS_CHANNELS 16
+
+/* the size of a substream (1 mono data stream) */
+#define HDSPM_CHANNEL_BUFFER_SAMPLES (16*1024)
+#define HDSPM_CHANNEL_BUFFER_BYTES (4*HDSPM_CHANNEL_BUFFER_SAMPLES)
+
+/* the size of the area we need to allocate for DMA transfers. the
+ size is the same regardless of the number of channels, and
+ also the latency to use.
+ for one direction !!!
+*/
+#define HDSPM_DMA_AREA_BYTES (HDSPM_MAX_CHANNELS * HDSPM_CHANNEL_BUFFER_BYTES)
+#define HDSPM_DMA_AREA_KILOBYTES (HDSPM_DMA_AREA_BYTES/1024)
+
+typedef struct _hdspm hdspm_t;
+typedef struct _hdspm_midi hdspm_midi_t;
+
+struct _hdspm_midi {
+ hdspm_t *hdspm;
+ int id;
+ snd_rawmidi_t *rmidi;
+ snd_rawmidi_substream_t *input;
+ snd_rawmidi_substream_t *output;
+ char istimer; /* timer in use */
+ struct timer_list timer;
+ spinlock_t lock;
+ int pending;
+};
+
+struct _hdspm {
+ spinlock_t lock;
+ snd_pcm_substream_t *capture_substream; /* only one playback */
+ snd_pcm_substream_t *playback_substream; /* and/or capture stream */
+
+ char *card_name; /* for procinfo */
+ unsigned short firmware_rev; /* dont know if relevant */
+
+ int precise_ptr; /* use precise pointers, to be tested */
+ int monitor_outs; /* set up monitoring outs init flag */
+
+ u32 control_register; /* cached value */
+ u32 control2_register; /* cached value */
+
+ hdspm_midi_t midi[2];
+ struct tasklet_struct midi_tasklet;
+
+ size_t period_bytes;
+ unsigned char ss_channels; /* channels of card in single speed */
+ unsigned char ds_channels; /* Double Speed */
+ unsigned char qs_channels; /* Quad Speed */
+
+ unsigned char *playback_buffer; /* suitably aligned address */
+ unsigned char *capture_buffer; /* suitably aligned address */
+
+ pid_t capture_pid; /* process id which uses capture */
+ pid_t playback_pid; /* process id which uses capture */
+ int running; /* running status */
+
+ int last_external_sample_rate; /* samplerate mystic ... */
+ int last_internal_sample_rate;
+ int system_sample_rate;
+
+ char *channel_map; /* channel map for DS and Quadspeed */
+
+ int dev; /* Hardware vars... */
+ int irq;
+ unsigned long port;
+ void __iomem *iobase;
+
+ int irq_count; /* for debug */
+
+ snd_card_t *card; /* one card */
+ snd_pcm_t *pcm; /* has one pcm */
+ snd_hwdep_t *hwdep; /* and a hwdep for additional ioctl */
+ struct pci_dev *pci; /* and an pci info */
+
+ /* Mixer vars */
+ snd_kcontrol_t *playback_mixer_ctls[HDSPM_MAX_CHANNELS]; /* fast alsa mixer */
+ snd_kcontrol_t *input_mixer_ctls[HDSPM_MAX_CHANNELS]; /* but input to much, so not used */
+ hdspm_mixer_t *mixer; /* full mixer accessable over mixer ioctl or hwdep-device */
+
+};
+
+/* These tables map the ALSA channels 1..N to the channels that we
+ need to use in order to find the relevant channel buffer. RME
+ refer to this kind of mapping as between "the ADAT channel and
+ the DMA channel." We index it using the logical audio channel,
+ and the value is the DMA channel (i.e. channel buffer number)
+ where the data for that channel can be read/written from/to.
+*/
+
+static char channel_map_madi_ss[HDSPM_MAX_CHANNELS] = {
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63
+};
+
+static char channel_map_madi_ds[HDSPM_MAX_CHANNELS] = {
+ 0, 2, 4, 6, 8, 10, 12, 14,
+ 16, 18, 20, 22, 24, 26, 28, 30,
+ 32, 34, 36, 38, 40, 42, 44, 46,
+ 48, 50, 52, 54, 56, 58, 60, 62,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1
+};
+
+static char channel_map_madi_qs[HDSPM_MAX_CHANNELS] = {
+ 0, 4, 8, 12, 16, 20, 24, 28,
+ 32, 36, 40, 44, 48, 52, 56, 60
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1
+};
+
+
+static struct pci_device_id snd_hdspm_ids[] = {
+ {
+ .vendor = PCI_VENDOR_ID_XILINX,
+ .device = PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP_MADI,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .class = 0,
+ .class_mask = 0,
+ .driver_data = 0},
+ {0,}
+};
+
+MODULE_DEVICE_TABLE(pci, snd_hdspm_ids);
+
+/* prototypes */
+static int __devinit snd_hdspm_create_alsa_devices(snd_card_t * card,
+ hdspm_t * hdspm);
+static int __devinit snd_hdspm_create_pcm(snd_card_t * card,
+ hdspm_t * hdspm);
+
+static inline void snd_hdspm_initialize_midi_flush(hdspm_t * hdspm);
+static int hdspm_update_simple_mixer_controls(hdspm_t * hdspm);
+static int hdspm_autosync_ref(hdspm_t * hdspm);
+static int snd_hdspm_set_defaults(hdspm_t * hdspm);
+static void hdspm_set_sgbuf(hdspm_t * hdspm, struct snd_sg_buf *sgbuf,
+ unsigned int reg, int channels);
+
+/* Write/read to/from HDSPM with Adresses in Bytes
+ not words but only 32Bit writes are allowed */
+
+static inline void hdspm_write(hdspm_t * hdspm, unsigned int reg,
+ unsigned int val)
+{
+ writel(val, hdspm->iobase + reg);
+}
+
+static inline unsigned int hdspm_read(hdspm_t * hdspm, unsigned int reg)
+{
+ return readl(hdspm->iobase + reg);
+}
+
+/* for each output channel (chan) I have an Input (in) and Playback (pb) Fader
+ mixer is write only on hardware so we have to cache him for read
+ each fader is a u32, but uses only the first 16 bit */
+
+static inline int hdspm_read_in_gain(hdspm_t * hdspm, unsigned int chan,
+ unsigned int in)
+{
+ if (chan > HDSPM_MIXER_CHANNELS || in > HDSPM_MIXER_CHANNELS)
+ return 0;
+
+ return hdspm->mixer->ch[chan].in[in];
+}
+
+static inline int hdspm_read_pb_gain(hdspm_t * hdspm, unsigned int chan,
+ unsigned int pb)
+{
+ if (chan > HDSPM_MIXER_CHANNELS || pb > HDSPM_MIXER_CHANNELS)
+ return 0;
+ return hdspm->mixer->ch[chan].pb[pb];
+}
+
+static inline int hdspm_write_in_gain(hdspm_t * hdspm, unsigned int chan,
+ unsigned int in, unsigned short data)
+{
+ if (chan >= HDSPM_MIXER_CHANNELS || in >= HDSPM_MIXER_CHANNELS)
+ return -1;
+
+ hdspm_write(hdspm,
+ HDSPM_MADI_mixerBase +
+ ((in + 128 * chan) * sizeof(u32)),
+ (hdspm->mixer->ch[chan].in[in] = data & 0xFFFF));
+ return 0;
+}
+
+static inline int hdspm_write_pb_gain(hdspm_t * hdspm, unsigned int chan,
+ unsigned int pb, unsigned short data)
+{
+ if (chan >= HDSPM_MIXER_CHANNELS || pb >= HDSPM_MIXER_CHANNELS)
+ return -1;
+
+ hdspm_write(hdspm,
+ HDSPM_MADI_mixerBase +
+ ((64 + pb + 128 * chan) * sizeof(u32)),
+ (hdspm->mixer->ch[chan].pb[pb] = data & 0xFFFF));
+ return 0;
+}
+
+
+/* enable DMA for specific channels, now available for DSP-MADI */
+static inline void snd_hdspm_enable_in(hdspm_t * hdspm, int i, int v)
+{
+ hdspm_write(hdspm, HDSPM_inputEnableBase + (4 * i), v);
+}
+
+static inline void snd_hdspm_enable_out(hdspm_t * hdspm, int i, int v)
+{
+ hdspm_write(hdspm, HDSPM_outputEnableBase + (4 * i), v);
+}
+
+/* check if same process is writing and reading */
+static inline int snd_hdspm_use_is_exclusive(hdspm_t * hdspm)
+{
+ unsigned long flags;
+ int ret = 1;
+
+ spin_lock_irqsave(&hdspm->lock, flags);
+ if ((hdspm->playback_pid != hdspm->capture_pid) &&
+ (hdspm->playback_pid >= 0) && (hdspm->capture_pid >= 0)) {
+ ret = 0;
+ }
+ spin_unlock_irqrestore(&hdspm->lock, flags);
+ return ret;
+}
+
+/* check for external sample rate */
+static inline int hdspm_external_sample_rate(hdspm_t * hdspm)
+{
+ unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
+ unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister);
+ unsigned int rate_bits;
+ int rate = 0;
+
+ /* if wordclock has synced freq and wordclock is valid */
+ if ((status2 & HDSPM_wcLock) != 0 &&
+ (status & HDSPM_SelSyncRef0) == 0) {
+
+ rate_bits = status2 & HDSPM_wcFreqMask;
+
+ switch (rate_bits) {
+ case HDSPM_wcFreq32:
+ rate = 32000;
+ break;
+ case HDSPM_wcFreq44_1:
+ rate = 44100;
+ break;
+ case HDSPM_wcFreq48:
+ rate = 48000;
+ break;
+ case HDSPM_wcFreq64:
+ rate = 64000;
+ break;
+ case HDSPM_wcFreq88_2:
+ rate = 88200;
+ break;
+ case HDSPM_wcFreq96:
+ rate = 96000;
+ break;
+ /* Quadspeed Bit missing ???? */
+ default:
+ rate = 0;
+ break;
+ }
+ }
+
+ /* if rate detected and Syncref is Word than have it, word has priority to MADI */
+ if (rate != 0
+ && (status2 & HDSPM_SelSyncRefMask) == HDSPM_SelSyncRef_WORD)
+ return rate;
+
+ /* maby a madi input (which is taken if sel sync is madi) */
+ if (status & HDSPM_madiLock) {
+ rate_bits = status & HDSPM_madiFreqMask;
+
+ switch (rate_bits) {
+ case HDSPM_madiFreq32:
+ rate = 32000;
+ break;
+ case HDSPM_madiFreq44_1:
+ rate = 44100;
+ break;
+ case HDSPM_madiFreq48:
+ rate = 48000;
+ break;
+ case HDSPM_madiFreq64:
+ rate = 64000;
+ break;
+ case HDSPM_madiFreq88_2:
+ rate = 88200;
+ break;
+ case HDSPM_madiFreq96:
+ rate = 96000;
+ break;
+ case HDSPM_madiFreq128:
+ rate = 128000;
+ break;
+ case HDSPM_madiFreq176_4:
+ rate = 176400;
+ break;
+ case HDSPM_madiFreq192:
+ rate = 192000;
+ break;
+ default:
+ rate = 0;
+ break;
+ }
+ }
+ return rate;
+}
+
+/* Latency function */
+static inline void hdspm_compute_period_size(hdspm_t * hdspm)
+{
+ hdspm->period_bytes =
+ 1 << ((hdspm_decode_latency(hdspm->control_register) + 8));
+}
+
+static snd_pcm_uframes_t hdspm_hw_pointer(hdspm_t * hdspm)
+{
+ int position;
+
+ position = hdspm_read(hdspm, HDSPM_statusRegister);
+
+ if (!hdspm->precise_ptr) {
+ return (position & HDSPM_BufferID) ? (hdspm->period_bytes /
+ 4) : 0;
+ }
+
+ /* hwpointer comes in bytes and is 64Bytes accurate (by docu since PCI Burst)
+ i have experimented that it is at most 64 Byte to much for playing
+ so substraction of 64 byte should be ok for ALSA, but use it only
+ for application where you know what you do since if you come to
+ near with record pointer it can be a disaster */
+
+ position &= HDSPM_BufferPositionMask;
+ position = ((position - 64) % (2 * hdspm->period_bytes)) / 4;
+
+ return position;
+}
+
+
+static inline void hdspm_start_audio(hdspm_t * s)
+{
+ s->control_register |= (HDSPM_AudioInterruptEnable | HDSPM_Start);
+ hdspm_write(s, HDSPM_controlRegister, s->control_register);
+}
+
+static inline void hdspm_stop_audio(hdspm_t * s)
+{
+ s->control_register &= ~(HDSPM_Start | HDSPM_AudioInterruptEnable);
+ hdspm_write(s, HDSPM_controlRegister, s->control_register);
+}
+
+/* should I silence all or only opened ones ? doit all for first even is 4MB*/
+static inline void hdspm_silence_playback(hdspm_t * hdspm)
+{
+ int i;
+ int n = hdspm->period_bytes;
+ void *buf = hdspm->playback_buffer;
+
+ snd_assert(buf != NULL, return);
+
+ for (i = 0; i < HDSPM_MAX_CHANNELS; i++) {
+ memset(buf, 0, n);
+ buf += HDSPM_CHANNEL_BUFFER_BYTES;
+ }
+}
+
+static int hdspm_set_interrupt_interval(hdspm_t * s, unsigned int frames)
+{
+ int n;
+
+ spin_lock_irq(&s->lock);
+
+ frames >>= 7;
+ n = 0;
+ while (frames) {
+ n++;
+ frames >>= 1;
+ }
+ s->control_register &= ~HDSPM_LatencyMask;
+ s->control_register |= hdspm_encode_latency(n);
+
+ hdspm_write(s, HDSPM_controlRegister, s->control_register);
+
+ hdspm_compute_period_size(s);
+
+ spin_unlock_irq(&s->lock);
+
+ return 0;
+}
+
+
+/* dummy set rate lets see what happens */
+static int hdspm_set_rate(hdspm_t * hdspm, int rate, int called_internally)
+{
+ int reject_if_open = 0;
+ int current_rate;
+ int rate_bits;
+ int not_set = 0;
+
+ /* ASSUMPTION: hdspm->lock is either set, or there is no need for
+ it (e.g. during module initialization).
+ */
+
+ if (!(hdspm->control_register & HDSPM_ClockModeMaster)) {
+
+ /* SLAVE --- */
+ if (called_internally) {
+
+ /* request from ctl or card initialization
+ just make a warning an remember setting
+ for future master mode switching */
+
+ snd_printk
+ (KERN_WARNING "HDSPM: Warning: device is not running as a clock master.\n");
+ not_set = 1;
+ } else {
+
+ /* hw_param request while in AutoSync mode */
+ int external_freq =
+ hdspm_external_sample_rate(hdspm);
+
+ if ((hdspm_autosync_ref(hdspm) ==
+ HDSPM_AUTOSYNC_FROM_NONE)) {
+
+ snd_printk(KERN_WARNING "HDSPM: Detected no Externel Sync \n");
+ not_set = 1;
+
+ } else if (rate != external_freq) {
+
+ snd_printk
+ (KERN_WARNING "HDSPM: Warning: No AutoSync source for requested rate\n");
+ not_set = 1;
+ }
+ }
+ }
+
+ current_rate = hdspm->system_sample_rate;
+
+ /* Changing between Singe, Double and Quad speed is not
+ allowed if any substreams are open. This is because such a change
+ causes a shift in the location of the DMA buffers and a reduction
+ in the number of available buffers.
+
+ Note that a similar but essentially insoluble problem exists for
+ externally-driven rate changes. All we can do is to flag rate
+ changes in the read/write routines.
+ */
+
+ switch (rate) {
+ case 32000:
+ if (current_rate > 48000) {
+ reject_if_open = 1;
+ }
+ rate_bits = HDSPM_Frequency32KHz;
+ break;
+ case 44100:
+ if (current_rate > 48000) {
+ reject_if_open = 1;
+ }
+ rate_bits = HDSPM_Frequency44_1KHz;
+ break;
+ case 48000:
+ if (current_rate > 48000) {
+ reject_if_open = 1;
+ }
+ rate_bits = HDSPM_Frequency48KHz;
+ break;
+ case 64000:
+ if (current_rate <= 48000) {
+ reject_if_open = 1;
+ }
+ rate_bits = HDSPM_Frequency64KHz;
+ break;
+ case 88200:
+ if (current_rate <= 48000) {
+ reject_if_open = 1;
+ }
+ rate_bits = HDSPM_Frequency88_2KHz;
+ break;
+ case 96000:
+ if (current_rate <= 48000) {
+ reject_if_open = 1;
+ }
+ rate_bits = HDSPM_Frequency96KHz;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (reject_if_open
+ && (hdspm->capture_pid >= 0 || hdspm->playback_pid >= 0)) {
+ snd_printk
+ (KERN_ERR "HDSPM: cannot change between single- and double-speed mode (capture PID = %d, playback PID = %d)\n",
+ hdspm->capture_pid, hdspm->playback_pid);
+ return -EBUSY;
+ }
+
+ hdspm->control_register &= ~HDSPM_FrequencyMask;
+ hdspm->control_register |= rate_bits;
+ hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
+
+ if (rate > 64000)
+ hdspm->channel_map = channel_map_madi_qs;
+ else if (rate > 48000)
+ hdspm->channel_map = channel_map_madi_ds;
+ else
+ hdspm->channel_map = channel_map_madi_ss;
+
+ hdspm->system_sample_rate = rate;
+
+ if (not_set != 0)
+ return -1;
+
+ return 0;
+}
+
+/* mainly for init to 0 on load */
+static void all_in_all_mixer(hdspm_t * hdspm, int sgain)
+{
+ int i, j;
+ unsigned int gain =
+ (sgain > UNITY_GAIN) ? UNITY_GAIN : (sgain < 0) ? 0 : sgain;
+
+ for (i = 0; i < HDSPM_MIXER_CHANNELS; i++)
+ for (j = 0; j < HDSPM_MIXER_CHANNELS; j++) {
+ hdspm_write_in_gain(hdspm, i, j, gain);
+ hdspm_write_pb_gain(hdspm, i, j, gain);
+ }
+}
+
+/*----------------------------------------------------------------------------
+ MIDI
+ ----------------------------------------------------------------------------*/
+
+static inline unsigned char snd_hdspm_midi_read_byte (hdspm_t *hdspm, int id)
+{
+ /* the hardware already does the relevant bit-mask with 0xff */
+ if (id)
+ return hdspm_read(hdspm, HDSPM_midiDataIn1);
+ else
+ return hdspm_read(hdspm, HDSPM_midiDataIn0);
+}
+
+static inline void snd_hdspm_midi_write_byte (hdspm_t *hdspm, int id, int val)
+{
+ /* the hardware already does the relevant bit-mask with 0xff */
+ if (id)
+ return hdspm_write(hdspm, HDSPM_midiDataOut1, val);
+ else
+ return hdspm_write(hdspm, HDSPM_midiDataOut0, val);
+}
+
+static inline int snd_hdspm_midi_input_available (hdspm_t *hdspm, int id)
+{
+ if (id)
+ return (hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xff);
+ else
+ return (hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xff);
+}
+
+static inline int snd_hdspm_midi_output_possible (hdspm_t *hdspm, int id)
+{
+ int fifo_bytes_used;
+
+ if (id)
+ fifo_bytes_used = hdspm_read(hdspm, HDSPM_midiStatusOut1) & 0xff;
+ else
+ fifo_bytes_used = hdspm_read(hdspm, HDSPM_midiStatusOut0) & 0xff;
+
+ if (fifo_bytes_used < 128)
+ return 128 - fifo_bytes_used;
+ else
+ return 0;
+}
+
+static inline void snd_hdspm_flush_midi_input (hdspm_t *hdspm, int id)
+{
+ while (snd_hdspm_midi_input_available (hdspm, id))
+ snd_hdspm_midi_read_byte (hdspm, id);
+}
+
+static int snd_hdspm_midi_output_write (hdspm_midi_t *hmidi)
+{
+ unsigned long flags;
+ int n_pending;
+ int to_write;
+ int i;
+ unsigned char buf[128];
+
+ /* Output is not interrupt driven */
+
+ spin_lock_irqsave (&hmidi->lock, flags);
+ if (hmidi->output) {
+ if (!snd_rawmidi_transmit_empty (hmidi->output)) {
+ if ((n_pending = snd_hdspm_midi_output_possible (hmidi->hdspm, hmidi->id)) > 0) {
+ if (n_pending > (int)sizeof (buf))
+ n_pending = sizeof (buf);
+
+ if ((to_write = snd_rawmidi_transmit (hmidi->output, buf, n_pending)) > 0) {
+ for (i = 0; i < to_write; ++i)
+ snd_hdspm_midi_write_byte (hmidi->hdspm, hmidi->id, buf[i]);
+ }
+ }
+ }
+ }
+ spin_unlock_irqrestore (&hmidi->lock, flags);
+ return 0;
+}
+
+static int snd_hdspm_midi_input_read (hdspm_midi_t *hmidi)
+{
+ unsigned char buf[128]; /* this buffer is designed to match the MIDI input FIFO size */
+ unsigned long flags;
+ int n_pending;
+ int i;
+
+ spin_lock_irqsave (&hmidi->lock, flags);
+ if ((n_pending = snd_hdspm_midi_input_available (hmidi->hdspm, hmidi->id)) > 0) {
+ if (hmidi->input) {
+ if (n_pending > (int)sizeof (buf)) {
+ n_pending = sizeof (buf);
+ }
+ for (i = 0; i < n_pending; ++i) {
+ buf[i] = snd_hdspm_midi_read_byte (hmidi->hdspm, hmidi->id);
+ }
+ if (n_pending) {
+ snd_rawmidi_receive (hmidi->input, buf, n_pending);
+ }
+ } else {
+ /* flush the MIDI input FIFO */
+ while (n_pending--) {
+ snd_hdspm_midi_read_byte (hmidi->hdspm, hmidi->id);
+ }
+ }
+ }
+ hmidi->pending = 0;
+ if (hmidi->id) {
+ hmidi->hdspm->control_register |= HDSPM_Midi1InterruptEnable;
+ } else {
+ hmidi->hdspm->control_register |= HDSPM_Midi0InterruptEnable;
+ }
+ hdspm_write(hmidi->hdspm, HDSPM_controlRegister, hmidi->hdspm->control_register);
+ spin_unlock_irqrestore (&hmidi->lock, flags);
+ return snd_hdspm_midi_output_write (hmidi);
+}
+
+static void snd_hdspm_midi_input_trigger(snd_rawmidi_substream_t * substream, int up)
+{
+ hdspm_t *hdspm;
+ hdspm_midi_t *hmidi;
+ unsigned long flags;
+ u32 ie;
+
+ hmidi = (hdspm_midi_t *) substream->rmidi->private_data;
+ hdspm = hmidi->hdspm;
+ ie = hmidi->id ? HDSPM_Midi1InterruptEnable : HDSPM_Midi0InterruptEnable;
+ spin_lock_irqsave (&hdspm->lock, flags);
+ if (up) {
+ if (!(hdspm->control_register & ie)) {
+ snd_hdspm_flush_midi_input (hdspm, hmidi->id);
+ hdspm->control_register |= ie;
+ }
+ } else {
+ hdspm->control_register &= ~ie;
+ }
+
+ hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
+ spin_unlock_irqrestore (&hdspm->lock, flags);
+}
+
+static void snd_hdspm_midi_output_timer(unsigned long data)
+{
+ hdspm_midi_t *hmidi = (hdspm_midi_t *) data;
+ unsigned long flags;
+
+ snd_hdspm_midi_output_write(hmidi);
+ spin_lock_irqsave (&hmidi->lock, flags);
+
+ /* this does not bump hmidi->istimer, because the
+ kernel automatically removed the timer when it
+ expired, and we are now adding it back, thus
+ leaving istimer wherever it was set before.
+ */
+
+ if (hmidi->istimer) {
+ hmidi->timer.expires = 1 + jiffies;
+ add_timer(&hmidi->timer);
+ }
+
+ spin_unlock_irqrestore (&hmidi->lock, flags);
+}
+
+static void snd_hdspm_midi_output_trigger(snd_rawmidi_substream_t * substream, int up)
+{
+ hdspm_midi_t *hmidi;
+ unsigned long flags;
+
+ hmidi = (hdspm_midi_t *) substream->rmidi->private_data;
+ spin_lock_irqsave (&hmidi->lock, flags);
+ if (up) {
+ if (!hmidi->istimer) {
+ init_timer(&hmidi->timer);
+ hmidi->timer.function = snd_hdspm_midi_output_timer;
+ hmidi->timer.data = (unsigned long) hmidi;
+ hmidi->timer.expires = 1 + jiffies;
+ add_timer(&hmidi->timer);
+ hmidi->istimer++;
+ }
+ } else {
+ if (hmidi->istimer && --hmidi->istimer <= 0) {
+ del_timer (&hmidi->timer);
+ }
+ }
+ spin_unlock_irqrestore (&hmidi->lock, flags);
+ if (up)
+ snd_hdspm_midi_output_write(hmidi);
+}
+
+static int snd_hdspm_midi_input_open(snd_rawmidi_substream_t * substream)
+{
+ hdspm_midi_t *hmidi;
+
+ hmidi = (hdspm_midi_t *) substream->rmidi->private_data;
+ spin_lock_irq (&hmidi->lock);
+ snd_hdspm_flush_midi_input (hmidi->hdspm, hmidi->id);
+ hmidi->input = substream;
+ spin_unlock_irq (&hmidi->lock);
+
+ return 0;
+}
+
+static int snd_hdspm_midi_output_open(snd_rawmidi_substream_t * substream)
+{
+ hdspm_midi_t *hmidi;
+
+ hmidi = (hdspm_midi_t *) substream->rmidi->private_data;
+ spin_lock_irq (&hmidi->lock);
+ hmidi->output = substream;
+ spin_unlock_irq (&hmidi->lock);
+
+ return 0;
+}
+
+static int snd_hdspm_midi_input_close(snd_rawmidi_substream_t * substream)
+{
+ hdspm_midi_t *hmidi;
+
+ snd_hdspm_midi_input_trigger (substream, 0);
+
+ hmidi = (hdspm_midi_t *) substream->rmidi->private_data;
+ spin_lock_irq (&hmidi->lock);
+ hmidi->input = NULL;
+ spin_unlock_irq (&hmidi->lock);
+
+ return 0;
+}
+
+static int snd_hdspm_midi_output_close(snd_rawmidi_substream_t * substream)
+{
+ hdspm_midi_t *hmidi;
+
+ snd_hdspm_midi_output_trigger (substream, 0);
+
+ hmidi = (hdspm_midi_t *) substream->rmidi->private_data;
+ spin_lock_irq (&hmidi->lock);
+ hmidi->output = NULL;
+ spin_unlock_irq (&hmidi->lock);
+
+ return 0;
+}
+
+snd_rawmidi_ops_t snd_hdspm_midi_output =
+{
+ .open = snd_hdspm_midi_output_open,
+ .close = snd_hdspm_midi_output_close,
+ .trigger = snd_hdspm_midi_output_trigger,
+};
+
+snd_rawmidi_ops_t snd_hdspm_midi_input =
+{
+ .open = snd_hdspm_midi_input_open,
+ .close = snd_hdspm_midi_input_close,
+ .trigger = snd_hdspm_midi_input_trigger,
+};
+
+static int __devinit snd_hdspm_create_midi (snd_card_t *card, hdspm_t *hdspm, int id)
+{
+ int err;
+ char buf[32];
+
+ hdspm->midi[id].id = id;
+ hdspm->midi[id].rmidi = NULL;
+ hdspm->midi[id].input = NULL;
+ hdspm->midi[id].output = NULL;
+ hdspm->midi[id].hdspm = hdspm;
+ hdspm->midi[id].istimer = 0;
+ hdspm->midi[id].pending = 0;
+ spin_lock_init (&hdspm->midi[id].lock);
+
+ sprintf (buf, "%s MIDI %d", card->shortname, id+1);
+ if ((err = snd_rawmidi_new (card, buf, id, 1, 1, &hdspm->midi[id].rmidi)) < 0)
+ return err;
+
+ sprintf (hdspm->midi[id].rmidi->name, "%s MIDI %d", card->id, id+1);
+ hdspm->midi[id].rmidi->private_data = &hdspm->midi[id];
+
+ snd_rawmidi_set_ops (hdspm->midi[id].rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_hdspm_midi_output);
+ snd_rawmidi_set_ops (hdspm->midi[id].rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_hdspm_midi_input);
+
+ hdspm->midi[id].rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT |
+ SNDRV_RAWMIDI_INFO_INPUT |
+ SNDRV_RAWMIDI_INFO_DUPLEX;
+
+ return 0;
+}
+
+
+static void hdspm_midi_tasklet(unsigned long arg)
+{
+ hdspm_t *hdspm = (hdspm_t *)arg;
+
+ if (hdspm->midi[0].pending)
+ snd_hdspm_midi_input_read (&hdspm->midi[0]);
+ if (hdspm->midi[1].pending)
+ snd_hdspm_midi_input_read (&hdspm->midi[1]);
+}
+
+
+/*-----------------------------------------------------------------------------
+ Status Interface
+ ----------------------------------------------------------------------------*/
+
+/* get the system sample rate which is set */
+
+#define HDSPM_SYSTEM_SAMPLE_RATE(xname, xindex) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+ .name = xname, \
+ .index = xindex, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READ, \
+ .info = snd_hdspm_info_system_sample_rate, \
+ .get = snd_hdspm_get_system_sample_rate \
+}
+
+static int snd_hdspm_info_system_sample_rate(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_info_t * uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ return 0;
+}
+
+static int snd_hdspm_get_system_sample_rate(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_value_t *
+ ucontrol)
+{
+ hdspm_t *hdspm = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.enumerated.item[0] = hdspm->system_sample_rate;
+ return 0;
+}
+
+#define HDSPM_AUTOSYNC_SAMPLE_RATE(xname, xindex) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, \
+ .name = xname, \
+ .index = xindex, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READ, \
+ .info = snd_hdspm_info_autosync_sample_rate, \
+ .get = snd_hdspm_get_autosync_sample_rate \
+}
+
+static int snd_hdspm_info_autosync_sample_rate(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_info_t * uinfo)
+{
+ static char *texts[] = { "32000", "44100", "48000",
+ "64000", "88200", "96000",
+ "128000", "176400", "192000",
+ "None"
+ };
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 10;
+ if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+ uinfo->value.enumerated.item =
+ uinfo->value.enumerated.items - 1;
+ strcpy(uinfo->value.enumerated.name,
+ texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+static int snd_hdspm_get_autosync_sample_rate(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_value_t *
+ ucontrol)
+{
+ hdspm_t *hdspm = snd_kcontrol_chip(kcontrol);
+
+ switch (hdspm_external_sample_rate(hdspm)) {
+ case 32000:
+ ucontrol->value.enumerated.item[0] = 0;
+ break;
+ case 44100:
+ ucontrol->value.enumerated.item[0] = 1;
+ break;
+ case 48000:
+ ucontrol->value.enumerated.item[0] = 2;
+ break;
+ case 64000:
+ ucontrol->value.enumerated.item[0] = 3;
+ break;
+ case 88200:
+ ucontrol->value.enumerated.item[0] = 4;
+ break;
+ case 96000:
+ ucontrol->value.enumerated.item[0] = 5;
+ break;
+ case 128000:
+ ucontrol->value.enumerated.item[0] = 6;
+ break;
+ case 176400:
+ ucontrol->value.enumerated.item[0] = 7;
+ break;
+ case 192000:
+ ucontrol->value.enumerated.item[0] = 8;
+ break;
+
+ default:
+ ucontrol->value.enumerated.item[0] = 9;
+ }
+ return 0;
+}
+
+#define HDSPM_SYSTEM_CLOCK_MODE(xname, xindex) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+ .name = xname, \
+ .index = xindex, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READ, \
+ .info = snd_hdspm_info_system_clock_mode, \
+ .get = snd_hdspm_get_system_clock_mode, \
+}
+
+
+
+static int hdspm_system_clock_mode(hdspm_t * hdspm)
+{
+ /* Always reflect the hardware info, rme is never wrong !!!! */
+
+ if (hdspm->control_register & HDSPM_ClockModeMaster)
+ return 0;
+ return 1;
+}
+
+static int snd_hdspm_info_system_clock_mode(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_info_t * uinfo)
+{
+ static char *texts[] = { "Master", "Slave" };
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 2;
+ if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+ uinfo->value.enumerated.item =
+ uinfo->value.enumerated.items - 1;
+ strcpy(uinfo->value.enumerated.name,
+ texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+static int snd_hdspm_get_system_clock_mode(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_value_t * ucontrol)
+{
+ hdspm_t *hdspm = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.enumerated.item[0] =
+ hdspm_system_clock_mode(hdspm);
+ return 0;
+}
+
+#define HDSPM_CLOCK_SOURCE(xname, xindex) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, \
+ .name = xname, \
+ .index = xindex, \
+ .info = snd_hdspm_info_clock_source, \
+ .get = snd_hdspm_get_clock_source, \
+ .put = snd_hdspm_put_clock_source \
+}
+
+static int hdspm_clock_source(hdspm_t * hdspm)
+{
+ if (hdspm->control_register & HDSPM_ClockModeMaster) {
+ switch (hdspm->system_sample_rate) {
+ case 32000:
+ return 1;
+ case 44100:
+ return 2;
+ case 48000:
+ return 3;
+ case 64000:
+ return 4;
+ case 88200:
+ return 5;
+ case 96000:
+ return 6;
+ case 128000:
+ return 7;
+ case 176400:
+ return 8;
+ case 192000:
+ return 9;
+ default:
+ return 3;
+ }
+ } else {
+ return 0;
+ }
+}
+
+static int hdspm_set_clock_source(hdspm_t * hdspm, int mode)
+{
+ int rate;
+ switch (mode) {
+
+ case HDSPM_CLOCK_SOURCE_AUTOSYNC:
+ if (hdspm_external_sample_rate(hdspm) != 0) {
+ hdspm->control_register &= ~HDSPM_ClockModeMaster;
+ hdspm_write(hdspm, HDSPM_controlRegister,
+ hdspm->control_register);
+ return 0;
+ }
+ return -1;
+ case HDSPM_CLOCK_SOURCE_INTERNAL_32KHZ:
+ rate = 32000;
+ break;
+ case HDSPM_CLOCK_SOURCE_INTERNAL_44_1KHZ:
+ rate = 44100;
+ break;
+ case HDSPM_CLOCK_SOURCE_INTERNAL_48KHZ:
+ rate = 48000;
+ break;
+ case HDSPM_CLOCK_SOURCE_INTERNAL_64KHZ:
+ rate = 64000;
+ break;
+ case HDSPM_CLOCK_SOURCE_INTERNAL_88_2KHZ:
+ rate = 88200;
+ break;
+ case HDSPM_CLOCK_SOURCE_INTERNAL_96KHZ:
+ rate = 96000;
+ break;
+ case HDSPM_CLOCK_SOURCE_INTERNAL_128KHZ:
+ rate = 128000;
+ break;
+ case HDSPM_CLOCK_SOURCE_INTERNAL_176_4KHZ:
+ rate = 176400;
+ break;
+ case HDSPM_CLOCK_SOURCE_INTERNAL_192KHZ:
+ rate = 192000;
+ break;
+
+ default:
+ rate = 44100;
+ }
+ hdspm->control_register |= HDSPM_ClockModeMaster;
+ hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
+ hdspm_set_rate(hdspm, rate, 1);
+ return 0;
+}
+
+static int snd_hdspm_info_clock_source(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_info_t * uinfo)
+{
+ static char *texts[] = { "AutoSync",
+ "Internal 32.0 kHz", "Internal 44.1 kHz",
+ "Internal 48.0 kHz",
+ "Internal 64.0 kHz", "Internal 88.2 kHz",
+ "Internal 96.0 kHz",
+ "Internal 128.0 kHz", "Internal 176.4 kHz",
+ "Internal 192.0 kHz"
+ };
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 10;
+
+ if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+ uinfo->value.enumerated.item =
+ uinfo->value.enumerated.items - 1;
+
+ strcpy(uinfo->value.enumerated.name,
+ texts[uinfo->value.enumerated.item]);
+
+ return 0;
+}
+
+static int snd_hdspm_get_clock_source(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_value_t * ucontrol)
+{
+ hdspm_t *hdspm = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.enumerated.item[0] = hdspm_clock_source(hdspm);
+ return 0;
+}
+
+static int snd_hdspm_put_clock_source(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_value_t * ucontrol)
+{
+ hdspm_t *hdspm = snd_kcontrol_chip(kcontrol);
+ int change;
+ int val;
+
+ if (!snd_hdspm_use_is_exclusive(hdspm))
+ return -EBUSY;
+ val = ucontrol->value.enumerated.item[0];
+ if (val < 0)
+ val = 0;
+ if (val > 6)
+ val = 6;
+ spin_lock_irq(&hdspm->lock);
+ if (val != hdspm_clock_source(hdspm))
+ change = (hdspm_set_clock_source(hdspm, val) == 0) ? 1 : 0;
+ else
+ change = 0;
+ spin_unlock_irq(&hdspm->lock);
+ return change;
+}
+
+#define HDSPM_PREF_SYNC_REF(xname, xindex) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+ .name = xname, \
+ .index = xindex, \
+ .info = snd_hdspm_info_pref_sync_ref, \
+ .get = snd_hdspm_get_pref_sync_ref, \
+ .put = snd_hdspm_put_pref_sync_ref \
+}
+
+static int hdspm_pref_sync_ref(hdspm_t * hdspm)
+{
+ /* Notice that this looks at the requested sync source,
+ not the one actually in use.
+ */
+ switch (hdspm->control_register & HDSPM_SyncRefMask) {
+ case HDSPM_SyncRef_Word:
+ return HDSPM_SYNC_FROM_WORD;
+ case HDSPM_SyncRef_MADI:
+ return HDSPM_SYNC_FROM_MADI;
+ }
+
+ return HDSPM_SYNC_FROM_WORD;
+}
+
+static int hdspm_set_pref_sync_ref(hdspm_t * hdspm, int pref)
+{
+ hdspm->control_register &= ~HDSPM_SyncRefMask;
+
+ switch (pref) {
+ case HDSPM_SYNC_FROM_MADI:
+ hdspm->control_register |= HDSPM_SyncRef_MADI;
+ break;
+ case HDSPM_SYNC_FROM_WORD:
+ hdspm->control_register |= HDSPM_SyncRef_Word;
+ break;
+ default:
+ return -1;
+ }
+ hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
+ return 0;
+}
+
+static int snd_hdspm_info_pref_sync_ref(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_info_t * uinfo)
+{
+ static char *texts[] = { "Word", "MADI" };
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+
+ uinfo->value.enumerated.items = 2;
+
+ if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+ uinfo->value.enumerated.item =
+ uinfo->value.enumerated.items - 1;
+ strcpy(uinfo->value.enumerated.name,
+ texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+static int snd_hdspm_get_pref_sync_ref(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_value_t * ucontrol)
+{
+ hdspm_t *hdspm = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.enumerated.item[0] = hdspm_pref_sync_ref(hdspm);
+ return 0;
+}
+
+static int snd_hdspm_put_pref_sync_ref(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_value_t * ucontrol)
+{
+ hdspm_t *hdspm = snd_kcontrol_chip(kcontrol);
+ int change, max;
+ unsigned int val;
+
+ max = 2;
+
+ if (!snd_hdspm_use_is_exclusive(hdspm))
+ return -EBUSY;
+
+ val = ucontrol->value.enumerated.item[0] % max;
+
+ spin_lock_irq(&hdspm->lock);
+ change = (int) val != hdspm_pref_sync_ref(hdspm);
+ hdspm_set_pref_sync_ref(hdspm, val);
+ spin_unlock_irq(&hdspm->lock);
+ return change;
+}
+
+#define HDSPM_AUTOSYNC_REF(xname, xindex) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+ .name = xname, \
+ .index = xindex, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READ, \
+ .info = snd_hdspm_info_autosync_ref, \
+ .get = snd_hdspm_get_autosync_ref, \
+}
+
+static int hdspm_autosync_ref(hdspm_t * hdspm)
+{
+ /* This looks at the autosync selected sync reference */
+ unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
+
+ switch (status2 & HDSPM_SelSyncRefMask) {
+
+ case HDSPM_SelSyncRef_WORD:
+ return HDSPM_AUTOSYNC_FROM_WORD;
+
+ case HDSPM_SelSyncRef_MADI:
+ return HDSPM_AUTOSYNC_FROM_MADI;
+
+ case HDSPM_SelSyncRef_NVALID:
+ return HDSPM_AUTOSYNC_FROM_NONE;
+
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static int snd_hdspm_info_autosync_ref(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_info_t * uinfo)
+{
+ static char *texts[] = { "WordClock", "MADI", "None" };
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 3;
+ if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+ uinfo->value.enumerated.item =
+ uinfo->value.enumerated.items - 1;
+ strcpy(uinfo->value.enumerated.name,
+ texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+static int snd_hdspm_get_autosync_ref(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_value_t * ucontrol)
+{
+ hdspm_t *hdspm = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.enumerated.item[0] = hdspm_pref_sync_ref(hdspm);
+ return 0;
+}
+
+#define HDSPM_LINE_OUT(xname, xindex) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+ .name = xname, \
+ .index = xindex, \
+ .info = snd_hdspm_info_line_out, \
+ .get = snd_hdspm_get_line_out, \
+ .put = snd_hdspm_put_line_out \
+}
+
+static int hdspm_line_out(hdspm_t * hdspm)
+{
+ return (hdspm->control_register & HDSPM_LineOut) ? 1 : 0;
+}
+
+
+static int hdspm_set_line_output(hdspm_t * hdspm, int out)
+{
+ if (out)
+ hdspm->control_register |= HDSPM_LineOut;
+ else
+ hdspm->control_register &= ~HDSPM_LineOut;
+ hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
+
+ return 0;
+}
+
+static int snd_hdspm_info_line_out(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_info_t * uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+static int snd_hdspm_get_line_out(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_value_t * ucontrol)
+{
+ hdspm_t *hdspm = snd_kcontrol_chip(kcontrol);
+
+ spin_lock_irq(&hdspm->lock);
+ ucontrol->value.integer.value[0] = hdspm_line_out(hdspm);
+ spin_unlock_irq(&hdspm->lock);
+ return 0;
+}
+
+static int snd_hdspm_put_line_out(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_value_t * ucontrol)
+{
+ hdspm_t *hdspm = snd_kcontrol_chip(kcontrol);
+ int change;
+ unsigned int val;
+
+ if (!snd_hdspm_use_is_exclusive(hdspm))
+ return -EBUSY;
+ val = ucontrol->value.integer.value[0] & 1;
+ spin_lock_irq(&hdspm->lock);
+ change = (int) val != hdspm_line_out(hdspm);
+ hdspm_set_line_output(hdspm, val);
+ spin_unlock_irq(&hdspm->lock);
+ return change;
+}
+
+#define HDSPM_TX_64(xname, xindex) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+ .name = xname, \
+ .index = xindex, \
+ .info = snd_hdspm_info_tx_64, \
+ .get = snd_hdspm_get_tx_64, \
+ .put = snd_hdspm_put_tx_64 \
+}
+
+static int hdspm_tx_64(hdspm_t * hdspm)
+{
+ return (hdspm->control_register & HDSPM_TX_64ch) ? 1 : 0;
+}
+
+static int hdspm_set_tx_64(hdspm_t * hdspm, int out)
+{
+ if (out)
+ hdspm->control_register |= HDSPM_TX_64ch;
+ else
+ hdspm->control_register &= ~HDSPM_TX_64ch;
+ hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
+
+ return 0;
+}
+
+static int snd_hdspm_info_tx_64(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_info_t * uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+static int snd_hdspm_get_tx_64(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_value_t * ucontrol)
+{
+ hdspm_t *hdspm = snd_kcontrol_chip(kcontrol);
+
+ spin_lock_irq(&hdspm->lock);
+ ucontrol->value.integer.value[0] = hdspm_tx_64(hdspm);
+ spin_unlock_irq(&hdspm->lock);
+ return 0;
+}
+
+static int snd_hdspm_put_tx_64(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_value_t * ucontrol)
+{
+ hdspm_t *hdspm = snd_kcontrol_chip(kcontrol);
+ int change;
+ unsigned int val;
+
+ if (!snd_hdspm_use_is_exclusive(hdspm))
+ return -EBUSY;
+ val = ucontrol->value.integer.value[0] & 1;
+ spin_lock_irq(&hdspm->lock);
+ change = (int) val != hdspm_tx_64(hdspm);
+ hdspm_set_tx_64(hdspm, val);
+ spin_unlock_irq(&hdspm->lock);
+ return change;
+}
+
+#define HDSPM_C_TMS(xname, xindex) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+ .name = xname, \
+ .index = xindex, \
+ .info = snd_hdspm_info_c_tms, \
+ .get = snd_hdspm_get_c_tms, \
+ .put = snd_hdspm_put_c_tms \
+}
+
+static int hdspm_c_tms(hdspm_t * hdspm)
+{
+ return (hdspm->control_register & HDSPM_clr_tms) ? 1 : 0;
+}
+
+static int hdspm_set_c_tms(hdspm_t * hdspm, int out)
+{
+ if (out)
+ hdspm->control_register |= HDSPM_clr_tms;
+ else
+ hdspm->control_register &= ~HDSPM_clr_tms;
+ hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
+
+ return 0;
+}
+
+static int snd_hdspm_info_c_tms(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_info_t * uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+static int snd_hdspm_get_c_tms(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_value_t * ucontrol)
+{
+ hdspm_t *hdspm = snd_kcontrol_chip(kcontrol);
+
+ spin_lock_irq(&hdspm->lock);
+ ucontrol->value.integer.value[0] = hdspm_c_tms(hdspm);
+ spin_unlock_irq(&hdspm->lock);
+ return 0;
+}
+
+static int snd_hdspm_put_c_tms(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_value_t * ucontrol)
+{
+ hdspm_t *hdspm = snd_kcontrol_chip(kcontrol);
+ int change;
+ unsigned int val;
+
+ if (!snd_hdspm_use_is_exclusive(hdspm))
+ return -EBUSY;
+ val = ucontrol->value.integer.value[0] & 1;
+ spin_lock_irq(&hdspm->lock);
+ change = (int) val != hdspm_c_tms(hdspm);
+ hdspm_set_c_tms(hdspm, val);
+ spin_unlock_irq(&hdspm->lock);
+ return change;
+}
+
+#define HDSPM_SAFE_MODE(xname, xindex) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+ .name = xname, \
+ .index = xindex, \
+ .info = snd_hdspm_info_safe_mode, \
+ .get = snd_hdspm_get_safe_mode, \
+ .put = snd_hdspm_put_safe_mode \
+}
+
+static int hdspm_safe_mode(hdspm_t * hdspm)
+{
+ return (hdspm->control_register & HDSPM_AutoInp) ? 1 : 0;
+}
+
+static int hdspm_set_safe_mode(hdspm_t * hdspm, int out)
+{
+ if (out)
+ hdspm->control_register |= HDSPM_AutoInp;
+ else
+ hdspm->control_register &= ~HDSPM_AutoInp;
+ hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
+
+ return 0;
+}
+
+static int snd_hdspm_info_safe_mode(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_info_t * uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+static int snd_hdspm_get_safe_mode(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_value_t * ucontrol)
+{
+ hdspm_t *hdspm = snd_kcontrol_chip(kcontrol);
+
+ spin_lock_irq(&hdspm->lock);
+ ucontrol->value.integer.value[0] = hdspm_safe_mode(hdspm);
+ spin_unlock_irq(&hdspm->lock);
+ return 0;
+}
+
+static int snd_hdspm_put_safe_mode(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_value_t * ucontrol)
+{
+ hdspm_t *hdspm = snd_kcontrol_chip(kcontrol);
+ int change;
+ unsigned int val;
+
+ if (!snd_hdspm_use_is_exclusive(hdspm))
+ return -EBUSY;
+ val = ucontrol->value.integer.value[0] & 1;
+ spin_lock_irq(&hdspm->lock);
+ change = (int) val != hdspm_safe_mode(hdspm);
+ hdspm_set_safe_mode(hdspm, val);
+ spin_unlock_irq(&hdspm->lock);
+ return change;
+}
+
+#define HDSPM_INPUT_SELECT(xname, xindex) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+ .name = xname, \
+ .index = xindex, \
+ .info = snd_hdspm_info_input_select, \
+ .get = snd_hdspm_get_input_select, \
+ .put = snd_hdspm_put_input_select \
+}
+
+static int hdspm_input_select(hdspm_t * hdspm)
+{
+ return (hdspm->control_register & HDSPM_InputSelect0) ? 1 : 0;
+}
+
+static int hdspm_set_input_select(hdspm_t * hdspm, int out)
+{
+ if (out)
+ hdspm->control_register |= HDSPM_InputSelect0;
+ else
+ hdspm->control_register &= ~HDSPM_InputSelect0;
+ hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
+
+ return 0;
+}
+
+static int snd_hdspm_info_input_select(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_info_t * uinfo)
+{
+ static char *texts[] = { "optical", "coaxial" };
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 2;
+
+ if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+ uinfo->value.enumerated.item =
+ uinfo->value.enumerated.items - 1;
+ strcpy(uinfo->value.enumerated.name,
+ texts[uinfo->value.enumerated.item]);
+
+ return 0;
+}
+
+static int snd_hdspm_get_input_select(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_value_t * ucontrol)
+{
+ hdspm_t *hdspm = snd_kcontrol_chip(kcontrol);
+
+ spin_lock_irq(&hdspm->lock);
+ ucontrol->value.enumerated.item[0] = hdspm_input_select(hdspm);
+ spin_unlock_irq(&hdspm->lock);
+ return 0;
+}
+
+static int snd_hdspm_put_input_select(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_value_t * ucontrol)
+{
+ hdspm_t *hdspm = snd_kcontrol_chip(kcontrol);
+ int change;
+ unsigned int val;
+
+ if (!snd_hdspm_use_is_exclusive(hdspm))
+ return -EBUSY;
+ val = ucontrol->value.integer.value[0] & 1;
+ spin_lock_irq(&hdspm->lock);
+ change = (int) val != hdspm_input_select(hdspm);
+ hdspm_set_input_select(hdspm, val);
+ spin_unlock_irq(&hdspm->lock);
+ return change;
+}
+
+/* Simple Mixer
+ deprecated since to much faders ???
+ MIXER interface says output (source, destination, value)
+ where source > MAX_channels are playback channels
+ on MADICARD
+ - playback mixer matrix: [channelout+64] [output] [value]
+ - input(thru) mixer matrix: [channelin] [output] [value]
+ (better do 2 kontrols for seperation ?)
+*/
+
+#define HDSPM_MIXER(xname, xindex) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+ .name = xname, \
+ .index = xindex, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
+ .info = snd_hdspm_info_mixer, \
+ .get = snd_hdspm_get_mixer, \
+ .put = snd_hdspm_put_mixer \
+}
+
+static int snd_hdspm_info_mixer(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_info_t * uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 3;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 65535;
+ uinfo->value.integer.step = 1;
+ return 0;
+}
+
+static int snd_hdspm_get_mixer(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_value_t * ucontrol)
+{
+ hdspm_t *hdspm = snd_kcontrol_chip(kcontrol);
+ int source;
+ int destination;
+
+ source = ucontrol->value.integer.value[0];
+ if (source < 0)
+ source = 0;
+ else if (source >= 2 * HDSPM_MAX_CHANNELS)
+ source = 2 * HDSPM_MAX_CHANNELS - 1;
+
+ destination = ucontrol->value.integer.value[1];
+ if (destination < 0)
+ destination = 0;
+ else if (destination >= HDSPM_MAX_CHANNELS)
+ destination = HDSPM_MAX_CHANNELS - 1;
+
+ spin_lock_irq(&hdspm->lock);
+ if (source >= HDSPM_MAX_CHANNELS)
+ ucontrol->value.integer.value[2] =
+ hdspm_read_pb_gain(hdspm, destination,
+ source - HDSPM_MAX_CHANNELS);
+ else
+ ucontrol->value.integer.value[2] =
+ hdspm_read_in_gain(hdspm, destination, source);
+
+ spin_unlock_irq(&hdspm->lock);
+
+ return 0;
+}
+
+static int snd_hdspm_put_mixer(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_value_t * ucontrol)
+{
+ hdspm_t *hdspm = snd_kcontrol_chip(kcontrol);
+ int change;
+ int source;
+ int destination;
+ int gain;
+
+ if (!snd_hdspm_use_is_exclusive(hdspm))
+ return -EBUSY;
+
+ source = ucontrol->value.integer.value[0];
+ destination = ucontrol->value.integer.value[1];
+
+ if (source < 0 || source >= 2 * HDSPM_MAX_CHANNELS)
+ return -1;
+ if (destination < 0 || destination >= HDSPM_MAX_CHANNELS)
+ return -1;
+
+ gain = ucontrol->value.integer.value[2];
+
+ spin_lock_irq(&hdspm->lock);
+
+ if (source >= HDSPM_MAX_CHANNELS)
+ change = gain != hdspm_read_pb_gain(hdspm, destination,
+ source -
+ HDSPM_MAX_CHANNELS);
+ else
+ change =
+ gain != hdspm_read_in_gain(hdspm, destination, source);
+
+ if (change) {
+ if (source >= HDSPM_MAX_CHANNELS)
+ hdspm_write_pb_gain(hdspm, destination,
+ source - HDSPM_MAX_CHANNELS,
+ gain);
+ else
+ hdspm_write_in_gain(hdspm, destination, source,
+ gain);
+ }
+ spin_unlock_irq(&hdspm->lock);
+
+ return change;
+}
+
+/* The simple mixer control(s) provide gain control for the
+ basic 1:1 mappings of playback streams to output
+ streams.
+*/
+
+#define HDSPM_PLAYBACK_MIXER \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_WRITE | \
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
+ .info = snd_hdspm_info_playback_mixer, \
+ .get = snd_hdspm_get_playback_mixer, \
+ .put = snd_hdspm_put_playback_mixer \
+}
+
+static int snd_hdspm_info_playback_mixer(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_info_t * uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 65536;
+ uinfo->value.integer.step = 1;
+ return 0;
+}
+
+static int snd_hdspm_get_playback_mixer(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_value_t * ucontrol)
+{
+ hdspm_t *hdspm = snd_kcontrol_chip(kcontrol);
+ int channel;
+ int mapped_channel;
+
+ channel = ucontrol->id.index - 1;
+
+ snd_assert(channel >= 0
+ || channel < HDSPM_MAX_CHANNELS, return -EINVAL);
+
+ if ((mapped_channel = hdspm->channel_map[channel]) < 0)
+ return -EINVAL;
+
+ spin_lock_irq(&hdspm->lock);
+ ucontrol->value.integer.value[0] =
+ hdspm_read_pb_gain(hdspm, mapped_channel, mapped_channel);
+ spin_unlock_irq(&hdspm->lock);
+
+ /* snd_printdd("get pb mixer index %d, channel %d, mapped_channel %d, value %d\n",
+ ucontrol->id.index, channel, mapped_channel, ucontrol->value.integer.value[0]);
+ */
+
+ return 0;
+}
+
+static int snd_hdspm_put_playback_mixer(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_value_t * ucontrol)
+{
+ hdspm_t *hdspm = snd_kcontrol_chip(kcontrol);
+ int change;
+ int channel;
+ int mapped_channel;
+ int gain;
+
+ if (!snd_hdspm_use_is_exclusive(hdspm))
+ return -EBUSY;
+
+ channel = ucontrol->id.index - 1;
+
+ snd_assert(channel >= 0
+ || channel < HDSPM_MAX_CHANNELS, return -EINVAL);
+
+ if ((mapped_channel = hdspm->channel_map[channel]) < 0)
+ return -EINVAL;
+
+ gain = ucontrol->value.integer.value[0];
+
+ spin_lock_irq(&hdspm->lock);
+ change =
+ gain != hdspm_read_pb_gain(hdspm, mapped_channel,
+ mapped_channel);
+ if (change)
+ hdspm_write_pb_gain(hdspm, mapped_channel, mapped_channel,
+ gain);
+ spin_unlock_irq(&hdspm->lock);
+ return change;
+}
+
+#define HDSPM_WC_SYNC_CHECK(xname, xindex) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+ .name = xname, \
+ .index = xindex, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
+ .info = snd_hdspm_info_sync_check, \
+ .get = snd_hdspm_get_wc_sync_check \
+}
+
+static int snd_hdspm_info_sync_check(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_info_t * uinfo)
+{
+ static char *texts[] = { "No Lock", "Lock", "Sync" };
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 3;
+ if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+ uinfo->value.enumerated.item =
+ uinfo->value.enumerated.items - 1;
+ strcpy(uinfo->value.enumerated.name,
+ texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+static int hdspm_wc_sync_check(hdspm_t * hdspm)
+{
+ int status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
+ if (status2 & HDSPM_wcLock) {
+ if (status2 & HDSPM_wcSync)
+ return 2;
+ else
+ return 1;
+ }
+ return 0;
+}
+
+static int snd_hdspm_get_wc_sync_check(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_value_t * ucontrol)
+{
+ hdspm_t *hdspm = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.enumerated.item[0] = hdspm_wc_sync_check(hdspm);
+ return 0;
+}
+
+
+#define HDSPM_MADI_SYNC_CHECK(xname, xindex) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+ .name = xname, \
+ .index = xindex, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
+ .info = snd_hdspm_info_sync_check, \
+ .get = snd_hdspm_get_madisync_sync_check \
+}
+
+static int hdspm_madisync_sync_check(hdspm_t * hdspm)
+{
+ int status = hdspm_read(hdspm, HDSPM_statusRegister);
+ if (status & HDSPM_madiLock) {
+ if (status & HDSPM_madiSync)
+ return 2;
+ else
+ return 1;
+ }
+ return 0;
+}
+
+static int snd_hdspm_get_madisync_sync_check(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_value_t *
+ ucontrol)
+{
+ hdspm_t *hdspm = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.enumerated.item[0] =
+ hdspm_madisync_sync_check(hdspm);
+ return 0;
+}
+
+
+
+
+static snd_kcontrol_new_t snd_hdspm_controls[] = {
+
+ HDSPM_MIXER("Mixer", 0),
+/* 'Sample Clock Source' complies with the alsa control naming scheme */
+ HDSPM_CLOCK_SOURCE("Sample Clock Source", 0),
+
+ HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0),
+ HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0),
+ HDSPM_AUTOSYNC_REF("AutoSync Reference", 0),
+ HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0),
+/* 'External Rate' complies with the alsa control naming scheme */
+ HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0),
+ HDSPM_WC_SYNC_CHECK("Word Clock Lock Status", 0),
+ HDSPM_MADI_SYNC_CHECK("MADI Sync Lock Status", 0),
+ HDSPM_LINE_OUT("Line Out", 0),
+ HDSPM_TX_64("TX 64 channels mode", 0),
+ HDSPM_C_TMS("Clear Track Marker", 0),
+ HDSPM_SAFE_MODE("Safe Mode", 0),
+ HDSPM_INPUT_SELECT("Input Select", 0),
+};
+
+static snd_kcontrol_new_t snd_hdspm_playback_mixer = HDSPM_PLAYBACK_MIXER;
+
+
+static int hdspm_update_simple_mixer_controls(hdspm_t * hdspm)
+{
+ int i;
+
+ for (i = hdspm->ds_channels; i < hdspm->ss_channels; ++i) {
+ if (hdspm->system_sample_rate > 48000) {
+ hdspm->playback_mixer_ctls[i]->vd[0].access =
+ SNDRV_CTL_ELEM_ACCESS_INACTIVE |
+ SNDRV_CTL_ELEM_ACCESS_READ |
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE;
+ } else {
+ hdspm->playback_mixer_ctls[i]->vd[0].access =
+ SNDRV_CTL_ELEM_ACCESS_READWRITE |
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE;
+ }
+ snd_ctl_notify(hdspm->card, SNDRV_CTL_EVENT_MASK_VALUE |
+ SNDRV_CTL_EVENT_MASK_INFO,
+ &hdspm->playback_mixer_ctls[i]->id);
+ }
+
+ return 0;
+}
+
+
+static int snd_hdspm_create_controls(snd_card_t * card, hdspm_t * hdspm)
+{
+ unsigned int idx, limit;
+ int err;
+ snd_kcontrol_t *kctl;
+
+ /* add control list first */
+
+ for (idx = 0; idx < ARRAY_SIZE(snd_hdspm_controls); idx++) {
+ if ((err =
+ snd_ctl_add(card, kctl =
+ snd_ctl_new1(&snd_hdspm_controls[idx],
+ hdspm))) < 0) {
+ return err;
+ }
+ }
+
+ /* Channel playback mixer as default control
+ Note: the whole matrix would be 128*HDSPM_MIXER_CHANNELS Faders, thats to big for any alsamixer
+ they are accesible via special IOCTL on hwdep
+ and the mixer 2dimensional mixer control */
+
+ snd_hdspm_playback_mixer.name = "Chn";
+ limit = HDSPM_MAX_CHANNELS;
+
+ /* The index values are one greater than the channel ID so that alsamixer
+ will display them correctly. We want to use the index for fast lookup
+ of the relevant channel, but if we use it at all, most ALSA software
+ does the wrong thing with it ...
+ */
+
+ for (idx = 0; idx < limit; ++idx) {
+ snd_hdspm_playback_mixer.index = idx + 1;
+ if ((err = snd_ctl_add(card,
+ kctl =
+ snd_ctl_new1
+ (&snd_hdspm_playback_mixer,
+ hdspm)))) {
+ return err;
+ }
+ hdspm->playback_mixer_ctls[idx] = kctl;
+ }
+
+ return 0;
+}
+
+/*------------------------------------------------------------
+ /proc interface
+ ------------------------------------------------------------*/
+
+static void
+snd_hdspm_proc_read(snd_info_entry_t * entry, snd_info_buffer_t * buffer)
+{
+ hdspm_t *hdspm = (hdspm_t *) entry->private_data;
+ unsigned int status;
+ unsigned int status2;
+ char *pref_sync_ref;
+ char *autosync_ref;
+ char *system_clock_mode;
+ char *clock_source;
+ char *insel;
+ char *syncref;
+ int x, x2;
+
+ status = hdspm_read(hdspm, HDSPM_statusRegister);
+ status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
+
+ snd_iprintf(buffer, "%s (Card #%d) Rev.%x Status2first3bits: %x\n",
+ hdspm->card_name, hdspm->card->number + 1,
+ hdspm->firmware_rev,
+ (status2 & HDSPM_version0) |
+ (status2 & HDSPM_version1) | (status2 &
+ HDSPM_version2));
+
+ snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n",
+ hdspm->irq, hdspm->port, (unsigned long)hdspm->iobase);
+
+ snd_iprintf(buffer, "--- System ---\n");
+
+ snd_iprintf(buffer,
+ "IRQ Pending: Audio=%d, MIDI0=%d, MIDI1=%d, IRQcount=%d\n",
+ status & HDSPM_audioIRQPending,
+ (status & HDSPM_midi0IRQPending) ? 1 : 0,
+ (status & HDSPM_midi1IRQPending) ? 1 : 0,
+ hdspm->irq_count);
+ snd_iprintf(buffer,
+ "HW pointer: id = %d, rawptr = %d (%d->%d) estimated= %ld (bytes)\n",
+ ((status & HDSPM_BufferID) ? 1 : 0),
+ (status & HDSPM_BufferPositionMask),
+ (status & HDSPM_BufferPositionMask) % (2 *
+ (int)hdspm->
+ period_bytes),
+ ((status & HDSPM_BufferPositionMask) -
+ 64) % (2 * (int)hdspm->period_bytes),
+ (long) hdspm_hw_pointer(hdspm) * 4);
+
+ snd_iprintf(buffer,
+ "MIDI FIFO: Out1=0x%x, Out2=0x%x, In1=0x%x, In2=0x%x \n",
+ hdspm_read(hdspm, HDSPM_midiStatusOut0) & 0xFF,
+ hdspm_read(hdspm, HDSPM_midiStatusOut1) & 0xFF,
+ hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xFF,
+ hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xFF);
+ snd_iprintf(buffer,
+ "Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, status2=0x%x\n",
+ hdspm->control_register, hdspm->control2_register,
+ status, status2);
+
+ snd_iprintf(buffer, "--- Settings ---\n");
+
+ x = 1 << (6 +
+ hdspm_decode_latency(hdspm->
+ control_register &
+ HDSPM_LatencyMask));
+
+ snd_iprintf(buffer,
+ "Size (Latency): %d samples (2 periods of %lu bytes)\n",
+ x, (unsigned long) hdspm->period_bytes);
+
+ snd_iprintf(buffer, "Line out: %s, Precise Pointer: %s\n",
+ (hdspm->
+ control_register & HDSPM_LineOut) ? "on " : "off",
+ (hdspm->precise_ptr) ? "on" : "off");
+
+ switch (hdspm->control_register & HDSPM_InputMask) {
+ case HDSPM_InputOptical:
+ insel = "Optical";
+ break;
+ case HDSPM_InputCoaxial:
+ insel = "Coaxial";
+ break;
+ default:
+ insel = "Unkown";
+ }
+
+ switch (hdspm->control_register & HDSPM_SyncRefMask) {
+ case HDSPM_SyncRef_Word:
+ syncref = "WordClock";
+ break;
+ case HDSPM_SyncRef_MADI:
+ syncref = "MADI";
+ break;
+ default:
+ syncref = "Unkown";
+ }
+ snd_iprintf(buffer, "Inputsel = %s, SyncRef = %s\n", insel,
+ syncref);
+
+ snd_iprintf(buffer,
+ "ClearTrackMarker = %s, Transmit in %s Channel Mode, Auto Input %s\n",
+ (hdspm->
+ control_register & HDSPM_clr_tms) ? "on" : "off",
+ (hdspm->
+ control_register & HDSPM_TX_64ch) ? "64" : "56",
+ (hdspm->
+ control_register & HDSPM_AutoInp) ? "on" : "off");
+
+ switch (hdspm_clock_source(hdspm)) {
+ case HDSPM_CLOCK_SOURCE_AUTOSYNC:
+ clock_source = "AutoSync";
+ break;
+ case HDSPM_CLOCK_SOURCE_INTERNAL_32KHZ:
+ clock_source = "Internal 32 kHz";
+ break;
+ case HDSPM_CLOCK_SOURCE_INTERNAL_44_1KHZ:
+ clock_source = "Internal 44.1 kHz";
+ break;
+ case HDSPM_CLOCK_SOURCE_INTERNAL_48KHZ:
+ clock_source = "Internal 48 kHz";
+ break;
+ case HDSPM_CLOCK_SOURCE_INTERNAL_64KHZ:
+ clock_source = "Internal 64 kHz";
+ break;
+ case HDSPM_CLOCK_SOURCE_INTERNAL_88_2KHZ:
+ clock_source = "Internal 88.2 kHz";
+ break;
+ case HDSPM_CLOCK_SOURCE_INTERNAL_96KHZ:
+ clock_source = "Internal 96 kHz";
+ break;
+ default:
+ clock_source = "Error";
+ }
+ snd_iprintf(buffer, "Sample Clock Source: %s\n", clock_source);
+ if (!(hdspm->control_register & HDSPM_ClockModeMaster)) {
+ system_clock_mode = "Slave";
+ } else {
+ system_clock_mode = "Master";
+ }
+ snd_iprintf(buffer, "System Clock Mode: %s\n", system_clock_mode);
+
+ switch (hdspm_pref_sync_ref(hdspm)) {
+ case HDSPM_SYNC_FROM_WORD:
+ pref_sync_ref = "Word Clock";
+ break;
+ case HDSPM_SYNC_FROM_MADI:
+ pref_sync_ref = "MADI Sync";
+ break;
+ default:
+ pref_sync_ref = "XXXX Clock";
+ break;
+ }
+ snd_iprintf(buffer, "Preferred Sync Reference: %s\n",
+ pref_sync_ref);
+
+ snd_iprintf(buffer, "System Clock Frequency: %d\n",
+ hdspm->system_sample_rate);
+
+
+ snd_iprintf(buffer, "--- Status:\n");
+
+ x = status & HDSPM_madiSync;
+ x2 = status2 & HDSPM_wcSync;
+
+ snd_iprintf(buffer, "Inputs MADI=%s, WordClock=%s\n",
+ (status & HDSPM_madiLock) ? (x ? "Sync" : "Lock") :
+ "NoLock",
+ (status2 & HDSPM_wcLock) ? (x2 ? "Sync" : "Lock") :
+ "NoLock");
+
+ switch (hdspm_autosync_ref(hdspm)) {
+ case HDSPM_AUTOSYNC_FROM_WORD:
+ autosync_ref = "Word Clock";
+ break;
+ case HDSPM_AUTOSYNC_FROM_MADI:
+ autosync_ref = "MADI Sync";
+ break;
+ case HDSPM_AUTOSYNC_FROM_NONE:
+ autosync_ref = "Input not valid";
+ break;
+ default:
+ autosync_ref = "---";
+ break;
+ }
+ snd_iprintf(buffer,
+ "AutoSync: Reference= %s, Freq=%d (MADI = %d, Word = %d)\n",
+ autosync_ref, hdspm_external_sample_rate(hdspm),
+ (status & HDSPM_madiFreqMask) >> 22,
+ (status2 & HDSPM_wcFreqMask) >> 5);
+
+ snd_iprintf(buffer, "Input: %s, Mode=%s\n",
+ (status & HDSPM_AB_int) ? "Coax" : "Optical",
+ (status & HDSPM_RX_64ch) ? "64 channels" :
+ "56 channels");
+
+ snd_iprintf(buffer, "\n");
+}
+
+static void __devinit snd_hdspm_proc_init(hdspm_t * hdspm)
+{
+ snd_info_entry_t *entry;
+
+ if (!snd_card_proc_new(hdspm->card, "hdspm", &entry))
+ snd_info_set_text_ops(entry, hdspm, 1024,
+ snd_hdspm_proc_read);
+}
+
+/*------------------------------------------------------------
+ hdspm intitialize
+ ------------------------------------------------------------*/
+
+static int snd_hdspm_set_defaults(hdspm_t * hdspm)
+{
+ unsigned int i;
+
+ /* ASSUMPTION: hdspm->lock is either held, or there is no need to
+ hold it (e.g. during module initalization).
+ */
+
+ /* set defaults: */
+
+ hdspm->control_register = HDSPM_ClockModeMaster | /* Master Cloack Mode on */
+ hdspm_encode_latency(7) | /* latency maximum = 8192 samples */
+ HDSPM_InputCoaxial | /* Input Coax not Optical */
+ HDSPM_SyncRef_MADI | /* Madi is syncclock */
+ HDSPM_LineOut | /* Analog output in */
+ HDSPM_TX_64ch | /* transmit in 64ch mode */
+ HDSPM_AutoInp; /* AutoInput chossing (takeover) */
+
+ /* ! HDSPM_Frequency0|HDSPM_Frequency1 = 44.1khz */
+ /* ! HDSPM_DoubleSpeed HDSPM_QuadSpeed = normal speed */
+ /* ! HDSPM_clr_tms = do not clear bits in track marks */
+
+ hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
+
+#ifdef SNDRV_BIG_ENDIAN
+ hdspm->control2_register = HDSPM_BIGENDIAN_MODE;
+#else
+ hdspm->control2_register = 0;
+#endif
+
+ hdspm_write(hdspm, HDSPM_control2Reg, hdspm->control2_register);
+ hdspm_compute_period_size(hdspm);
+
+ /* silence everything */
+
+ all_in_all_mixer(hdspm, 0 * UNITY_GAIN);
+
+ if (line_outs_monitor[hdspm->dev]) {
+
+ snd_printk(KERN_INFO "HDSPM: sending all playback streams to line outs.\n");
+
+ for (i = 0; i < HDSPM_MIXER_CHANNELS; i++) {
+ if (hdspm_write_pb_gain(hdspm, i, i, UNITY_GAIN))
+ return -EIO;
+ }
+ }
+
+ /* set a default rate so that the channel map is set up. */
+ hdspm->channel_map = channel_map_madi_ss;
+ hdspm_set_rate(hdspm, 44100, 1);
+
+ return 0;
+}
+
+
+/*------------------------------------------------------------
+ interupt
+ ------------------------------------------------------------*/
+
+static irqreturn_t snd_hdspm_interrupt(int irq, void *dev_id,
+ struct pt_regs *regs)
+{
+ hdspm_t *hdspm = (hdspm_t *) dev_id;
+ unsigned int status;
+ int audio;
+ int midi0;
+ int midi1;
+ unsigned int midi0status;
+ unsigned int midi1status;
+ int schedule = 0;
+
+ status = hdspm_read(hdspm, HDSPM_statusRegister);
+
+ audio = status & HDSPM_audioIRQPending;
+ midi0 = status & HDSPM_midi0IRQPending;
+ midi1 = status & HDSPM_midi1IRQPending;
+
+ if (!audio && !midi0 && !midi1)
+ return IRQ_NONE;
+
+ hdspm_write(hdspm, HDSPM_interruptConfirmation, 0);
+ hdspm->irq_count++;
+
+ midi0status = hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xff;
+ midi1status = hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xff;
+
+ if (audio) {
+
+ if (hdspm->capture_substream)
+ snd_pcm_period_elapsed(hdspm->pcm->
+ streams
+ [SNDRV_PCM_STREAM_CAPTURE].
+ substream);
+
+ if (hdspm->playback_substream)
+ snd_pcm_period_elapsed(hdspm->pcm->
+ streams
+ [SNDRV_PCM_STREAM_PLAYBACK].
+ substream);
+ }
+
+ if (midi0 && midi0status) {
+ /* we disable interrupts for this input until processing is done */
+ hdspm->control_register &= ~HDSPM_Midi0InterruptEnable;
+ hdspm_write(hdspm, HDSPM_controlRegister,
+ hdspm->control_register);
+ hdspm->midi[0].pending = 1;
+ schedule = 1;
+ }
+ if (midi1 && midi1status) {
+ /* we disable interrupts for this input until processing is done */
+ hdspm->control_register &= ~HDSPM_Midi1InterruptEnable;
+ hdspm_write(hdspm, HDSPM_controlRegister,
+ hdspm->control_register);
+ hdspm->midi[1].pending = 1;
+ schedule = 1;
+ }
+ if (schedule)
+ tasklet_hi_schedule(&hdspm->midi_tasklet);
+ return IRQ_HANDLED;
+}
+
+/*------------------------------------------------------------
+ pcm interface
+ ------------------------------------------------------------*/
+
+
+static snd_pcm_uframes_t snd_hdspm_hw_pointer(snd_pcm_substream_t *
+ substream)
+{
+ hdspm_t *hdspm = snd_pcm_substream_chip(substream);
+ return hdspm_hw_pointer(hdspm);
+}
+
+static char *hdspm_channel_buffer_location(hdspm_t * hdspm,
+ int stream, int channel)
+{
+ int mapped_channel;
+
+ snd_assert(channel >= 0
+ || channel < HDSPM_MAX_CHANNELS, return NULL);
+
+ if ((mapped_channel = hdspm->channel_map[channel]) < 0)
+ return NULL;
+
+ if (stream == SNDRV_PCM_STREAM_CAPTURE) {
+ return hdspm->capture_buffer +
+ mapped_channel * HDSPM_CHANNEL_BUFFER_BYTES;
+ } else {
+ return hdspm->playback_buffer +
+ mapped_channel * HDSPM_CHANNEL_BUFFER_BYTES;
+ }
+}
+
+
+/* dont know why need it ??? */
+static int snd_hdspm_playback_copy(snd_pcm_substream_t * substream,
+ int channel, snd_pcm_uframes_t pos,
+ void __user *src, snd_pcm_uframes_t count)
+{
+ hdspm_t *hdspm = snd_pcm_substream_chip(substream);
+ char *channel_buf;
+
+ snd_assert(pos + count <= HDSPM_CHANNEL_BUFFER_BYTES / 4,
+ return -EINVAL);
+
+ channel_buf = hdspm_channel_buffer_location(hdspm,
+ substream->pstr->
+ stream, channel);
+
+ snd_assert(channel_buf != NULL, return -EIO);
+
+ return copy_from_user(channel_buf + pos * 4, src, count * 4);
+}
+
+static int snd_hdspm_capture_copy(snd_pcm_substream_t * substream,
+ int channel, snd_pcm_uframes_t pos,
+ void __user *dst, snd_pcm_uframes_t count)
+{
+ hdspm_t *hdspm = snd_pcm_substream_chip(substream);
+ char *channel_buf;
+
+ snd_assert(pos + count <= HDSPM_CHANNEL_BUFFER_BYTES / 4,
+ return -EINVAL);
+
+ channel_buf = hdspm_channel_buffer_location(hdspm,
+ substream->pstr->
+ stream, channel);
+ snd_assert(channel_buf != NULL, return -EIO);
+ return copy_to_user(dst, channel_buf + pos * 4, count * 4);
+}
+
+static int snd_hdspm_hw_silence(snd_pcm_substream_t * substream,
+ int channel, snd_pcm_uframes_t pos,
+ snd_pcm_uframes_t count)
+{
+ hdspm_t *hdspm = snd_pcm_substream_chip(substream);
+ char *channel_buf;
+
+ channel_buf =
+ hdspm_channel_buffer_location(hdspm, substream->pstr->stream,
+ channel);
+ snd_assert(channel_buf != NULL, return -EIO);
+ memset(channel_buf + pos * 4, 0, count * 4);
+ return 0;
+}
+
+static int snd_hdspm_reset(snd_pcm_substream_t * substream)
+{
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ hdspm_t *hdspm = snd_pcm_substream_chip(substream);
+ snd_pcm_substream_t *other;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ other = hdspm->capture_substream;
+ else
+ other = hdspm->playback_substream;
+
+ if (hdspm->running)
+ runtime->status->hw_ptr = hdspm_hw_pointer(hdspm);
+ else
+ runtime->status->hw_ptr = 0;
+ if (other) {
+ struct list_head *pos;
+ snd_pcm_substream_t *s;
+ snd_pcm_runtime_t *oruntime = other->runtime;
+ snd_pcm_group_for_each(pos, substream) {
+ s = snd_pcm_group_substream_entry(pos);
+ if (s == other) {
+ oruntime->status->hw_ptr =
+ runtime->status->hw_ptr;
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+static int snd_hdspm_hw_params(snd_pcm_substream_t * substream,
+ snd_pcm_hw_params_t * params)
+{
+ hdspm_t *hdspm = snd_pcm_substream_chip(substream);
+ int err;
+ int i;
+ pid_t this_pid;
+ pid_t other_pid;
+ struct snd_sg_buf *sgbuf;
+
+
+ spin_lock_irq(&hdspm->lock);
+
+ if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ this_pid = hdspm->playback_pid;
+ other_pid = hdspm->capture_pid;
+ } else {
+ this_pid = hdspm->capture_pid;
+ other_pid = hdspm->playback_pid;
+ }
+
+ if ((other_pid > 0) && (this_pid != other_pid)) {
+
+ /* The other stream is open, and not by the same
+ task as this one. Make sure that the parameters
+ that matter are the same.
+ */
+
+ if (params_rate(params) != hdspm->system_sample_rate) {
+ spin_unlock_irq(&hdspm->lock);
+ _snd_pcm_hw_param_setempty(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+ return -EBUSY;
+ }
+
+ if (params_period_size(params) != hdspm->period_bytes / 4) {
+ spin_unlock_irq(&hdspm->lock);
+ _snd_pcm_hw_param_setempty(params,
+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
+ return -EBUSY;
+ }
+
+ }
+ /* We're fine. */
+ spin_unlock_irq(&hdspm->lock);
+
+ /* how to make sure that the rate matches an externally-set one ? */
+
+ spin_lock_irq(&hdspm->lock);
+ if ((err = hdspm_set_rate(hdspm, params_rate(params), 0)) < 0) {
+ spin_unlock_irq(&hdspm->lock);
+ _snd_pcm_hw_param_setempty(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+ return err;
+ }
+ spin_unlock_irq(&hdspm->lock);
+
+ if ((err =
+ hdspm_set_interrupt_interval(hdspm,
+ params_period_size(params))) <
+ 0) {
+ _snd_pcm_hw_param_setempty(params,
+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
+ return err;
+ }
+
+ /* Memory allocation, takashi's method, dont know if we should spinlock */
+ /* malloc all buffer even if not enabled to get sure */
+ /* malloc only needed bytes */
+ err =
+ snd_pcm_lib_malloc_pages(substream,
+ HDSPM_CHANNEL_BUFFER_BYTES *
+ params_channels(params));
+ if (err < 0)
+ return err;
+
+ sgbuf = snd_pcm_substream_sgbuf(substream);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+
+ hdspm_set_sgbuf(hdspm, sgbuf, HDSPM_pageAddressBufferOut,
+ params_channels(params));
+
+ for (i = 0; i < params_channels(params); ++i)
+ snd_hdspm_enable_out(hdspm, i, 1);
+
+ hdspm->playback_buffer =
+ (unsigned char *) substream->runtime->dma_area;
+ } else {
+ hdspm_set_sgbuf(hdspm, sgbuf, HDSPM_pageAddressBufferIn,
+ params_channels(params));
+
+ for (i = 0; i < params_channels(params); ++i)
+ snd_hdspm_enable_in(hdspm, i, 1);
+
+ hdspm->capture_buffer =
+ (unsigned char *) substream->runtime->dma_area;
+ }
+ return 0;
+}
+
+static int snd_hdspm_hw_free(snd_pcm_substream_t * substream)
+{
+ int i;
+ hdspm_t *hdspm = snd_pcm_substream_chip(substream);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+
+ /* params_channels(params) should be enough,
+ but to get sure in case of error */
+ for (i = 0; i < HDSPM_MAX_CHANNELS; ++i)
+ snd_hdspm_enable_out(hdspm, i, 0);
+
+ hdspm->playback_buffer = NULL;
+ } else {
+ for (i = 0; i < HDSPM_MAX_CHANNELS; ++i)
+ snd_hdspm_enable_in(hdspm, i, 0);
+
+ hdspm->capture_buffer = NULL;
+
+ }
+
+ snd_pcm_lib_free_pages(substream);
+
+ return 0;
+}
+
+static int snd_hdspm_channel_info(snd_pcm_substream_t * substream,
+ snd_pcm_channel_info_t * info)
+{
+ hdspm_t *hdspm = snd_pcm_substream_chip(substream);
+ int mapped_channel;
+
+ snd_assert(info->channel < HDSPM_MAX_CHANNELS, return -EINVAL);
+
+ if ((mapped_channel = hdspm->channel_map[info->channel]) < 0)
+ return -EINVAL;
+
+ info->offset = mapped_channel * HDSPM_CHANNEL_BUFFER_BYTES;
+ info->first = 0;
+ info->step = 32;
+ return 0;
+}
+
+static int snd_hdspm_ioctl(snd_pcm_substream_t * substream,
+ unsigned int cmd, void *arg)
+{
+ switch (cmd) {
+ case SNDRV_PCM_IOCTL1_RESET:
+ {
+ return snd_hdspm_reset(substream);
+ }
+
+ case SNDRV_PCM_IOCTL1_CHANNEL_INFO:
+ {
+ snd_pcm_channel_info_t *info = arg;
+ return snd_hdspm_channel_info(substream, info);
+ }
+ default:
+ break;
+ }
+
+ return snd_pcm_lib_ioctl(substream, cmd, arg);
+}
+
+static int snd_hdspm_trigger(snd_pcm_substream_t * substream, int cmd)
+{
+ hdspm_t *hdspm = snd_pcm_substream_chip(substream);
+ snd_pcm_substream_t *other;
+ int running;
+
+ spin_lock(&hdspm->lock);
+ running = hdspm->running;
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ running |= 1 << substream->stream;
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ running &= ~(1 << substream->stream);
+ break;
+ default:
+ snd_BUG();
+ spin_unlock(&hdspm->lock);
+ return -EINVAL;
+ }
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ other = hdspm->capture_substream;
+ else
+ other = hdspm->playback_substream;
+
+ if (other) {
+ struct list_head *pos;
+ snd_pcm_substream_t *s;
+ snd_pcm_group_for_each(pos, substream) {
+ s = snd_pcm_group_substream_entry(pos);
+ if (s == other) {
+ snd_pcm_trigger_done(s, substream);
+ if (cmd == SNDRV_PCM_TRIGGER_START)
+ running |= 1 << s->stream;
+ else
+ running &= ~(1 << s->stream);
+ goto _ok;
+ }
+ }
+ if (cmd == SNDRV_PCM_TRIGGER_START) {
+ if (!(running & (1 << SNDRV_PCM_STREAM_PLAYBACK))
+ && substream->stream ==
+ SNDRV_PCM_STREAM_CAPTURE)
+ hdspm_silence_playback(hdspm);
+ } else {
+ if (running &&
+ substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ hdspm_silence_playback(hdspm);
+ }
+ } else {
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ hdspm_silence_playback(hdspm);
+ }
+ _ok:
+ snd_pcm_trigger_done(substream, substream);
+ if (!hdspm->running && running)
+ hdspm_start_audio(hdspm);
+ else if (hdspm->running && !running)
+ hdspm_stop_audio(hdspm);
+ hdspm->running = running;
+ spin_unlock(&hdspm->lock);
+
+ return 0;
+}
+
+static int snd_hdspm_prepare(snd_pcm_substream_t * substream)
+{
+ return 0;
+}
+
+static unsigned int period_sizes[] =
+ { 64, 128, 256, 512, 1024, 2048, 4096, 8192 };
+
+static snd_pcm_hardware_t snd_hdspm_playback_subinfo = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_NONINTERLEAVED |
+ SNDRV_PCM_INFO_SYNC_START | SNDRV_PCM_INFO_DOUBLE),
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,
+ .rates = (SNDRV_PCM_RATE_32000 |
+ SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_64000 |
+ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000),
+ .rate_min = 32000,
+ .rate_max = 96000,
+ .channels_min = 1,
+ .channels_max = HDSPM_MAX_CHANNELS,
+ .buffer_bytes_max =
+ HDSPM_CHANNEL_BUFFER_BYTES * HDSPM_MAX_CHANNELS,
+ .period_bytes_min = (64 * 4),
+ .period_bytes_max = (8192 * 4) * HDSPM_MAX_CHANNELS,
+ .periods_min = 2,
+ .periods_max = 2,
+ .fifo_size = 0
+};
+
+static snd_pcm_hardware_t snd_hdspm_capture_subinfo = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_NONINTERLEAVED |
+ SNDRV_PCM_INFO_SYNC_START),
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,
+ .rates = (SNDRV_PCM_RATE_32000 |
+ SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_64000 |
+ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000),
+ .rate_min = 32000,
+ .rate_max = 96000,
+ .channels_min = 1,
+ .channels_max = HDSPM_MAX_CHANNELS,
+ .buffer_bytes_max =
+ HDSPM_CHANNEL_BUFFER_BYTES * HDSPM_MAX_CHANNELS,
+ .period_bytes_min = (64 * 4),
+ .period_bytes_max = (8192 * 4) * HDSPM_MAX_CHANNELS,
+ .periods_min = 2,
+ .periods_max = 2,
+ .fifo_size = 0
+};
+
+static snd_pcm_hw_constraint_list_t hw_constraints_period_sizes = {
+ .count = ARRAY_SIZE(period_sizes),
+ .list = period_sizes,
+ .mask = 0
+};
+
+
+static int snd_hdspm_hw_rule_channels_rate(snd_pcm_hw_params_t * params,
+ snd_pcm_hw_rule_t * rule)
+{
+ hdspm_t *hdspm = rule->private;
+ snd_interval_t *c =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ snd_interval_t *r =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+
+ if (r->min > 48000) {
+ snd_interval_t t = {
+ .min = 1,
+ .max = hdspm->ds_channels,
+ .integer = 1,
+ };
+ return snd_interval_refine(c, &t);
+ } else if (r->max < 64000) {
+ snd_interval_t t = {
+ .min = 1,
+ .max = hdspm->ss_channels,
+ .integer = 1,
+ };
+ return snd_interval_refine(c, &t);
+ }
+ return 0;
+}
+
+static int snd_hdspm_hw_rule_rate_channels(snd_pcm_hw_params_t * params,
+ snd_pcm_hw_rule_t * rule)
+{
+ hdspm_t *hdspm = rule->private;
+ snd_interval_t *c =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ snd_interval_t *r =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+
+ if (c->min <= hdspm->ss_channels) {
+ snd_interval_t t = {
+ .min = 32000,
+ .max = 48000,
+ .integer = 1,
+ };
+ return snd_interval_refine(r, &t);
+ } else if (c->max > hdspm->ss_channels) {
+ snd_interval_t t = {
+ .min = 64000,
+ .max = 96000,
+ .integer = 1,
+ };
+
+ return snd_interval_refine(r, &t);
+ }
+ return 0;
+}
+
+static int snd_hdspm_playback_open(snd_pcm_substream_t * substream)
+{
+ hdspm_t *hdspm = snd_pcm_substream_chip(substream);
+ snd_pcm_runtime_t *runtime = substream->runtime;
+
+ snd_printdd("Open device substream %d\n", substream->stream);
+
+ spin_lock_irq(&hdspm->lock);
+
+ snd_pcm_set_sync(substream);
+
+ runtime->hw = snd_hdspm_playback_subinfo;
+
+ if (hdspm->capture_substream == NULL)
+ hdspm_stop_audio(hdspm);
+
+ hdspm->playback_pid = current->pid;
+ hdspm->playback_substream = substream;
+
+ spin_unlock_irq(&hdspm->lock);
+
+ snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
+
+ snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+ &hw_constraints_period_sizes);
+
+ snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+ snd_hdspm_hw_rule_channels_rate, hdspm,
+ SNDRV_PCM_HW_PARAM_RATE, -1);
+
+ snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+ snd_hdspm_hw_rule_rate_channels, hdspm,
+ SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+
+ return 0;
+}
+
+static int snd_hdspm_playback_release(snd_pcm_substream_t * substream)
+{
+ hdspm_t *hdspm = snd_pcm_substream_chip(substream);
+
+ spin_lock_irq(&hdspm->lock);
+
+ hdspm->playback_pid = -1;
+ hdspm->playback_substream = NULL;
+
+ spin_unlock_irq(&hdspm->lock);
+
+ return 0;
+}
+
+
+static int snd_hdspm_capture_open(snd_pcm_substream_t * substream)
+{
+ hdspm_t *hdspm = snd_pcm_substream_chip(substream);
+ snd_pcm_runtime_t *runtime = substream->runtime;
+
+ spin_lock_irq(&hdspm->lock);
+ snd_pcm_set_sync(substream);
+ runtime->hw = snd_hdspm_capture_subinfo;
+
+ if (hdspm->playback_substream == NULL)
+ hdspm_stop_audio(hdspm);
+
+ hdspm->capture_pid = current->pid;
+ hdspm->capture_substream = substream;
+
+ spin_unlock_irq(&hdspm->lock);
+
+ snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
+ snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+ &hw_constraints_period_sizes);
+
+ snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+ snd_hdspm_hw_rule_channels_rate, hdspm,
+ SNDRV_PCM_HW_PARAM_RATE, -1);
+
+ snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+ snd_hdspm_hw_rule_rate_channels, hdspm,
+ SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+ return 0;
+}
+
+static int snd_hdspm_capture_release(snd_pcm_substream_t * substream)
+{
+ hdspm_t *hdspm = snd_pcm_substream_chip(substream);
+
+ spin_lock_irq(&hdspm->lock);
+
+ hdspm->capture_pid = -1;
+ hdspm->capture_substream = NULL;
+
+ spin_unlock_irq(&hdspm->lock);
+ return 0;
+}
+
+static int snd_hdspm_hwdep_dummy_op(snd_hwdep_t * hw, struct file *file)
+{
+ /* we have nothing to initialize but the call is required */
+ return 0;
+}
+
+
+static int snd_hdspm_hwdep_ioctl(snd_hwdep_t * hw, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ hdspm_t *hdspm = (hdspm_t *) hw->private_data;
+ struct sndrv_hdspm_mixer_ioctl mixer;
+ hdspm_config_info_t info;
+ hdspm_version_t hdspm_version;
+ struct sndrv_hdspm_peak_rms_ioctl rms;
+
+ switch (cmd) {
+
+
+ case SNDRV_HDSPM_IOCTL_GET_PEAK_RMS:
+ if (copy_from_user(&rms, (void __user *)arg, sizeof(rms)))
+ return -EFAULT;
+ /* maybe there is a chance to memorymap in future so dont touch just copy */
+ if(copy_to_user_fromio((void __user *)rms.peak,
+ hdspm->iobase+HDSPM_MADI_peakrmsbase,
+ sizeof(hdspm_peak_rms_t)) != 0 )
+ return -EFAULT;
+
+ break;
+
+
+ case SNDRV_HDSPM_IOCTL_GET_CONFIG_INFO:
+
+ spin_lock_irq(&hdspm->lock);
+ info.pref_sync_ref =
+ (unsigned char) hdspm_pref_sync_ref(hdspm);
+ info.wordclock_sync_check =
+ (unsigned char) hdspm_wc_sync_check(hdspm);
+
+ info.system_sample_rate = hdspm->system_sample_rate;
+ info.autosync_sample_rate =
+ hdspm_external_sample_rate(hdspm);
+ info.system_clock_mode =
+ (unsigned char) hdspm_system_clock_mode(hdspm);
+ info.clock_source =
+ (unsigned char) hdspm_clock_source(hdspm);
+ info.autosync_ref =
+ (unsigned char) hdspm_autosync_ref(hdspm);
+ info.line_out = (unsigned char) hdspm_line_out(hdspm);
+ info.passthru = 0;
+ spin_unlock_irq(&hdspm->lock);
+ if (copy_to_user((void __user *) arg, &info, sizeof(info)))
+ return -EFAULT;
+ break;
+
+ case SNDRV_HDSPM_IOCTL_GET_VERSION:
+ hdspm_version.firmware_rev = hdspm->firmware_rev;
+ if (copy_to_user((void __user *) arg, &hdspm_version,
+ sizeof(hdspm_version)))
+ return -EFAULT;
+ break;
+
+ case SNDRV_HDSPM_IOCTL_GET_MIXER:
+ if (copy_from_user(&mixer, (void __user *)arg, sizeof(mixer)))
+ return -EFAULT;
+ if (copy_to_user
+ ((void __user *)mixer.mixer, hdspm->mixer, sizeof(hdspm_mixer_t)))
+ return -EFAULT;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static snd_pcm_ops_t snd_hdspm_playback_ops = {
+ .open = snd_hdspm_playback_open,
+ .close = snd_hdspm_playback_release,
+ .ioctl = snd_hdspm_ioctl,
+ .hw_params = snd_hdspm_hw_params,
+ .hw_free = snd_hdspm_hw_free,
+ .prepare = snd_hdspm_prepare,
+ .trigger = snd_hdspm_trigger,
+ .pointer = snd_hdspm_hw_pointer,
+ .copy = snd_hdspm_playback_copy,
+ .silence = snd_hdspm_hw_silence,
+ .page = snd_pcm_sgbuf_ops_page,
+};
+
+static snd_pcm_ops_t snd_hdspm_capture_ops = {
+ .open = snd_hdspm_capture_open,
+ .close = snd_hdspm_capture_release,
+ .ioctl = snd_hdspm_ioctl,
+ .hw_params = snd_hdspm_hw_params,
+ .hw_free = snd_hdspm_hw_free,
+ .prepare = snd_hdspm_prepare,
+ .trigger = snd_hdspm_trigger,
+ .pointer = snd_hdspm_hw_pointer,
+ .copy = snd_hdspm_capture_copy,
+ .page = snd_pcm_sgbuf_ops_page,
+};
+
+static int __devinit snd_hdspm_create_hwdep(snd_card_t * card,
+ hdspm_t * hdspm)
+{
+ snd_hwdep_t *hw;
+ int err;
+
+ if ((err = snd_hwdep_new(card, "HDSPM hwdep", 0, &hw)) < 0)
+ return err;
+
+ hdspm->hwdep = hw;
+ hw->private_data = hdspm;
+ strcpy(hw->name, "HDSPM hwdep interface");
+
+ hw->ops.open = snd_hdspm_hwdep_dummy_op;
+ hw->ops.ioctl = snd_hdspm_hwdep_ioctl;
+ hw->ops.release = snd_hdspm_hwdep_dummy_op;
+
+ return 0;
+}
+
+
+/*------------------------------------------------------------
+ memory interface
+ ------------------------------------------------------------*/
+static int __devinit snd_hdspm_preallocate_memory(hdspm_t * hdspm)
+{
+ int err;
+ snd_pcm_t *pcm;
+ size_t wanted;
+
+ pcm = hdspm->pcm;
+
+ wanted = HDSPM_DMA_AREA_BYTES + 4096; /* dont know why, but it works */
+
+ if ((err =
+ snd_pcm_lib_preallocate_pages_for_all(pcm,
+ SNDRV_DMA_TYPE_DEV_SG,
+ snd_dma_pci_data(hdspm->pci),
+ wanted,
+ wanted)) < 0) {
+ snd_printdd("Could not preallocate %d Bytes\n", wanted);
+
+ return err;
+ } else
+ snd_printdd(" Preallocated %d Bytes\n", wanted);
+
+ return 0;
+}
+
+static int snd_hdspm_memory_free(hdspm_t * hdspm)
+{
+ snd_printdd("memory_free_for_all %p\n", hdspm->pcm);
+
+ snd_pcm_lib_preallocate_free_for_all(hdspm->pcm);
+ return 0;
+}
+
+
+static void hdspm_set_sgbuf(hdspm_t * hdspm, struct snd_sg_buf *sgbuf,
+ unsigned int reg, int channels)
+{
+ int i;
+ for (i = 0; i < (channels * 16); i++)
+ hdspm_write(hdspm, reg + 4 * i,
+ snd_pcm_sgbuf_get_addr(sgbuf,
+ (size_t) 4096 * i));
+}
+
+/* ------------- ALSA Devices ---------------------------- */
+static int __devinit snd_hdspm_create_pcm(snd_card_t * card,
+ hdspm_t * hdspm)
+{
+ snd_pcm_t *pcm;
+ int err;
+
+ if ((err = snd_pcm_new(card, hdspm->card_name, 0, 1, 1, &pcm)) < 0)
+ return err;
+
+ hdspm->pcm = pcm;
+ pcm->private_data = hdspm;
+ strcpy(pcm->name, hdspm->card_name);
+
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ &snd_hdspm_playback_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+ &snd_hdspm_capture_ops);
+
+ pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX;
+
+ if ((err = snd_hdspm_preallocate_memory(hdspm)) < 0)
+ return err;
+
+ return 0;
+}
+
+static inline void snd_hdspm_initialize_midi_flush(hdspm_t * hdspm)
+{
+ snd_hdspm_flush_midi_input(hdspm, 0);
+ snd_hdspm_flush_midi_input(hdspm, 1);
+}
+
+static int __devinit snd_hdspm_create_alsa_devices(snd_card_t * card,
+ hdspm_t * hdspm)
+{
+ int err;
+
+ snd_printdd("Create card...\n");
+ if ((err = snd_hdspm_create_pcm(card, hdspm)) < 0)
+ return err;
+
+ if ((err = snd_hdspm_create_midi(card, hdspm, 0)) < 0)
+ return err;
+
+ if ((err = snd_hdspm_create_midi(card, hdspm, 1)) < 0)
+ return err;
+
+ if ((err = snd_hdspm_create_controls(card, hdspm)) < 0)
+ return err;
+
+ if ((err = snd_hdspm_create_hwdep(card, hdspm)) < 0)
+ return err;
+
+ snd_printdd("proc init...\n");
+ snd_hdspm_proc_init(hdspm);
+
+ hdspm->system_sample_rate = -1;
+ hdspm->last_external_sample_rate = -1;
+ hdspm->last_internal_sample_rate = -1;
+ hdspm->playback_pid = -1;
+ hdspm->capture_pid = -1;
+ hdspm->capture_substream = NULL;
+ hdspm->playback_substream = NULL;
+
+ snd_printdd("Set defaults...\n");
+ if ((err = snd_hdspm_set_defaults(hdspm)) < 0)
+ return err;
+
+ snd_printdd("Update mixer controls...\n");
+ hdspm_update_simple_mixer_controls(hdspm);
+
+ snd_printdd("Initializeing complete ???\n");
+
+ if ((err = snd_card_register(card)) < 0) {
+ snd_printk(KERN_ERR "HDSPM: error registering card\n");
+ return err;
+ }
+
+ snd_printdd("... yes now\n");
+
+ return 0;
+}
+
+static int __devinit snd_hdspm_create(snd_card_t * card, hdspm_t * hdspm,
+ int precise_ptr, int enable_monitor)
+{
+ struct pci_dev *pci = hdspm->pci;
+ int err;
+ int i;
+
+ unsigned long io_extent;
+
+ hdspm->irq = -1;
+ hdspm->irq_count = 0;
+
+ hdspm->midi[0].rmidi = NULL;
+ hdspm->midi[1].rmidi = NULL;
+ hdspm->midi[0].input = NULL;
+ hdspm->midi[1].input = NULL;
+ hdspm->midi[0].output = NULL;
+ hdspm->midi[1].output = NULL;
+ spin_lock_init(&hdspm->midi[0].lock);
+ spin_lock_init(&hdspm->midi[1].lock);
+ hdspm->iobase = NULL;
+ hdspm->control_register = 0;
+ hdspm->control2_register = 0;
+
+ hdspm->playback_buffer = NULL;
+ hdspm->capture_buffer = NULL;
+
+ for (i = 0; i < HDSPM_MAX_CHANNELS; ++i)
+ hdspm->playback_mixer_ctls[i] = NULL;
+ hdspm->mixer = NULL;
+
+ hdspm->card = card;
+
+ spin_lock_init(&hdspm->lock);
+
+ tasklet_init(&hdspm->midi_tasklet,
+ hdspm_midi_tasklet, (unsigned long) hdspm);
+
+ pci_read_config_word(hdspm->pci,
+ PCI_CLASS_REVISION, &hdspm->firmware_rev);
+
+ strcpy(card->driver, "HDSPM");
+ strcpy(card->mixername, "Xilinx FPGA");
+ hdspm->card_name = "RME HDSPM MADI";
+
+ if ((err = pci_enable_device(pci)) < 0)
+ return err;
+
+ pci_set_master(hdspm->pci);
+
+ if ((err = pci_request_regions(pci, "hdspm")) < 0)
+ return err;
+
+ hdspm->port = pci_resource_start(pci, 0);
+ io_extent = pci_resource_len(pci, 0);
+
+ snd_printdd("grabbed memory region 0x%lx-0x%lx\n",
+ hdspm->port, hdspm->port + io_extent - 1);
+
+
+ if ((hdspm->iobase = ioremap_nocache(hdspm->port, io_extent)) == NULL) {
+ snd_printk(KERN_ERR "HDSPM: unable to remap region 0x%lx-0x%lx\n",
+ hdspm->port, hdspm->port + io_extent - 1);
+ return -EBUSY;
+ }
+ snd_printdd("remapped region (0x%lx) 0x%lx-0x%lx\n",
+ (unsigned long)hdspm->iobase, hdspm->port,
+ hdspm->port + io_extent - 1);
+
+ if (request_irq(pci->irq, snd_hdspm_interrupt,
+ SA_INTERRUPT | SA_SHIRQ, "hdspm",
+ (void *) hdspm)) {
+ snd_printk(KERN_ERR "HDSPM: unable to use IRQ %d\n", pci->irq);
+ return -EBUSY;
+ }
+
+ snd_printdd("use IRQ %d\n", pci->irq);
+
+ hdspm->irq = pci->irq;
+ hdspm->precise_ptr = precise_ptr;
+
+ hdspm->monitor_outs = enable_monitor;
+
+ snd_printdd("kmalloc Mixer memory of %d Bytes\n",
+ sizeof(hdspm_mixer_t));
+ if ((hdspm->mixer =
+ (hdspm_mixer_t *) kmalloc(sizeof(hdspm_mixer_t), GFP_KERNEL))
+ == NULL) {
+ snd_printk(KERN_ERR "HDSPM: unable to kmalloc Mixer memory of %d Bytes\n",
+ (int)sizeof(hdspm_mixer_t));
+ return err;
+ }
+
+ hdspm->ss_channels = MADI_SS_CHANNELS;
+ hdspm->ds_channels = MADI_DS_CHANNELS;
+ hdspm->qs_channels = MADI_QS_CHANNELS;
+
+ snd_printdd("create alsa devices.\n");
+ if ((err = snd_hdspm_create_alsa_devices(card, hdspm)) < 0)
+ return err;
+
+ snd_hdspm_initialize_midi_flush(hdspm);
+
+ return 0;
+}
+
+static int snd_hdspm_free(hdspm_t * hdspm)
+{
+
+ if (hdspm->port) {
+
+ /* stop th audio, and cancel all interrupts */
+ hdspm->control_register &=
+ ~(HDSPM_Start | HDSPM_AudioInterruptEnable
+ | HDSPM_Midi0InterruptEnable |
+ HDSPM_Midi1InterruptEnable);
+ hdspm_write(hdspm, HDSPM_controlRegister,
+ hdspm->control_register);
+ }
+
+ if (hdspm->irq >= 0)
+ free_irq(hdspm->irq, (void *) hdspm);
+
+
+ if (hdspm->mixer)
+ kfree(hdspm->mixer);
+
+ if (hdspm->iobase)
+ iounmap(hdspm->iobase);
+
+ snd_hdspm_memory_free(hdspm);
+
+ if (hdspm->port)
+ pci_release_regions(hdspm->pci);
+
+ pci_disable_device(hdspm->pci);
+ return 0;
+}
+
+static void snd_hdspm_card_free(snd_card_t * card)
+{
+ hdspm_t *hdspm = (hdspm_t *) card->private_data;
+
+ if (hdspm)
+ snd_hdspm_free(hdspm);
+}
+
+static int __devinit snd_hdspm_probe(struct pci_dev *pci,
+ const struct pci_device_id *pci_id)
+{
+ static int dev;
+ hdspm_t *hdspm;
+ snd_card_t *card;
+ int err;
+
+ if (dev >= SNDRV_CARDS)
+ return -ENODEV;
+ if (!enable[dev]) {
+ dev++;
+ return -ENOENT;
+ }
+
+ if (!(card = snd_card_new(index[dev], id[dev],
+ THIS_MODULE, sizeof(hdspm_t))))
+ return -ENOMEM;
+
+ hdspm = (hdspm_t *) card->private_data;
+ card->private_free = snd_hdspm_card_free;
+ hdspm->dev = dev;
+ hdspm->pci = pci;
+
+ if ((err =
+ snd_hdspm_create(card, hdspm, precise_ptr[dev],
+ enable_monitor[dev])) < 0) {
+ snd_card_free(card);
+ return err;
+ }
+
+ strcpy(card->shortname, "HDSPM MADI");
+ sprintf(card->longname, "%s at 0x%lx, irq %d", hdspm->card_name,
+ hdspm->port, hdspm->irq);
+
+ if ((err = snd_card_register(card)) < 0) {
+ snd_card_free(card);
+ return err;
+ }
+
+ pci_set_drvdata(pci, card);
+
+ dev++;
+ return 0;
+}
+
+static void __devexit snd_hdspm_remove(struct pci_dev *pci)
+{
+ snd_card_free(pci_get_drvdata(pci));
+ pci_set_drvdata(pci, NULL);
+}
+
+static struct pci_driver driver = {
+ .name = "RME Hammerfall DSP MADI",
+ .id_table = snd_hdspm_ids,
+ .probe = snd_hdspm_probe,
+ .remove = __devexit_p(snd_hdspm_remove),
+};
+
+
+static int __init alsa_card_hdspm_init(void)
+{
+ return pci_register_driver(&driver);
+}
+
+static void __exit alsa_card_hdspm_exit(void)
+{
+ pci_unregister_driver(&driver);
+}
+
+module_init(alsa_card_hdspm_init)
+module_exit(alsa_card_hdspm_exit)
{
dmab->dev.type = SNDRV_DMA_TYPE_DEV;
dmab->dev.dev = snd_dma_pci_data(pci);
- if (! snd_dma_get_reserved_buf(dmab, snd_dma_pci_buf_id(pci))) {
- if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
- size, dmab) < 0)
- return -ENOMEM;
+ if (snd_dma_get_reserved_buf(dmab, snd_dma_pci_buf_id(pci))) {
+ if (dmab->bytes >= size)
+ return 0;
}
+ if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
+ size, dmab) < 0)
+ return -ENOMEM;
return 0;
}
static void snd_hammerfall_free_buffer(struct snd_dma_buffer *dmab, struct pci_dev *pci)
{
- if (dmab->area)
+ if (dmab->area) {
+ dmab->dev.dev = NULL; /* make it anonymous */
snd_dma_reserve_buf(dmab, snd_dma_pci_buf_id(pci));
+ }
}
static int __init alsa_card_hammerfall_init(void)
{
- return pci_module_init(&driver);
+ return pci_register_driver(&driver);
}
static void __exit alsa_card_hammerfall_exit(void)
static int __init alsa_card_sonicvibes_init(void)
{
- return pci_module_init(&driver);
+ return pci_register_driver(&driver);
}
static void __exit alsa_card_sonicvibes_exit(void)
return err;
}
}
- if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_TRID4DWAVE,
+ if (trident->device != TRIDENT_DEVICE_ID_SI7018 &&
+ (err = snd_mpu401_uart_new(card, 0, MPU401_HW_TRID4DWAVE,
trident->midi_port, 1,
trident->irq, 0, &trident->rmidi)) < 0) {
snd_card_free(card);
static int __init alsa_card_trident_init(void)
{
- return pci_module_init(&driver);
+ return pci_register_driver(&driver);
}
static void __exit alsa_card_trident_exit(void)
module_param_array(ac97_quirk, charp, NULL, 0444);
MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware.");
module_param_array(dxs_support, int, NULL, 0444);
-MODULE_PARM_DESC(dxs_support, "Support for DXS channels (0 = auto, 1 = enable, 2 = disable, 3 = 48k only, 4 = no VRA)");
+MODULE_PARM_DESC(dxs_support, "Support for DXS channels (0 = auto, 1 = enable, 2 = disable, 3 = 48k only, 4 = no VRA, 5 = enable any sample rate)");
/* pci ids */
#define VIA_DXS_DISABLE 2
#define VIA_DXS_48K 3
#define VIA_DXS_NO_VRA 4
+#define VIA_DXS_SRC 5
/*
struct via_rate_lock rates[2]; /* playback and capture */
unsigned int dxs_fixed: 1; /* DXS channel accepts only 48kHz */
unsigned int no_vra: 1; /* no need to set VRA on DXS channels */
+ unsigned int dxs_src: 1; /* use full SRC capabilities of DXS */
unsigned int spdif_on: 1; /* only spdif rates work to external DACs */
snd_pcm_t *pcms[2];
snd_dma_free_pages(&dev->table);
dev->table.area = NULL;
}
- if (dev->idx_table) {
- kfree(dev->idx_table);
- dev->idx_table = NULL;
- }
+ kfree(dev->idx_table);
+ dev->idx_table = NULL;
return 0;
}
via82xx_t *chip = snd_pcm_substream_chip(substream);
viadev_t *viadev = (viadev_t *)substream->runtime->private_data;
snd_pcm_runtime_t *runtime = substream->runtime;
+ int ac97_rate = chip->dxs_src ? 48000 : runtime->rate;
int rate_changed;
u32 rbits;
- if ((rate_changed = via_lock_rate(&chip->rates[0], runtime->rate)) < 0)
+ if ((rate_changed = via_lock_rate(&chip->rates[0], ac97_rate)) < 0)
return rate_changed;
if (rate_changed) {
snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE,
chip->no_vra ? 48000 : runtime->rate);
- snd_ac97_set_rate(chip->ac97, AC97_SPDIF, runtime->rate);
+ snd_ac97_set_rate(chip->ac97, AC97_SPDIF,
+ chip->no_vra ? 48000 : runtime->rate);
}
if (runtime->rate == 48000)
rbits = 0xfffff;
/* fixed DXS playback rate */
runtime->hw.rates = SNDRV_PCM_RATE_48000;
runtime->hw.rate_min = runtime->hw.rate_max = 48000;
+ } else if (chip->dxs_src && viadev->reg_offset < 0x40) {
+ /* use full SRC capabilities of DXS */
+ runtime->hw.rates = (SNDRV_PCM_RATE_CONTINUOUS |
+ SNDRV_PCM_RATE_8000_48000);
+ runtime->hw.rate_min = 8000;
+ runtime->hw.rate_max = 48000;
} else if (! ratep->rate) {
int idx = viadev->direction ? AC97_RATES_ADC : AC97_RATES_FRONT_DAC;
runtime->hw.rates = chip->ac97->rates[idx];
static struct ac97_quirk ac97_quirks[] = {
{
- .vendor = 0x1106,
- .device = 0x4161,
+ .subvendor = 0x1106,
+ .subdevice = 0x4161,
.codec_id = 0x56494161, /* VT1612A */
.name = "Soltek SL-75DRV5",
.type = AC97_TUNE_NONE
},
{ /* FIXME: which codec? */
- .vendor = 0x1106,
- .device = 0x4161,
+ .subvendor = 0x1106,
+ .subdevice = 0x4161,
.name = "ASRock K7VT2",
.type = AC97_TUNE_HP_ONLY
},
{
- .vendor = 0x1019,
- .device = 0x0a81,
+ .subvendor = 0x1019,
+ .subdevice = 0x0a81,
.name = "ECS K7VTA3",
.type = AC97_TUNE_HP_ONLY
},
{
- .vendor = 0x1019,
- .device = 0x0a85,
+ .subvendor = 0x1019,
+ .subdevice = 0x0a85,
.name = "ECS L7VMM2",
.type = AC97_TUNE_HP_ONLY
},
{
- .vendor = 0x1849,
- .device = 0x3059,
+ .subvendor = 0x1849,
+ .subdevice = 0x3059,
.name = "ASRock K7VM2",
.type = AC97_TUNE_HP_ONLY /* VT1616 */
},
{
- .vendor = 0x14cd,
- .device = 0x7002,
+ .subvendor = 0x14cd,
+ .subdevice = 0x7002,
.name = "Unknown",
.type = AC97_TUNE_ALC_JACK
},
{
- .vendor = 0x1071,
- .device = 0x8590,
+ .subvendor = 0x1071,
+ .subdevice = 0x8590,
.name = "Mitac Mobo",
.type = AC97_TUNE_ALC_JACK
},
{
- .vendor = 0x161f,
- .device = 0x202b,
+ .subvendor = 0x161f,
+ .subdevice = 0x202b,
.name = "Arima Notebook",
.type = AC97_TUNE_HP_ONLY,
},
* auto detection of DXS channel supports.
*/
struct dxs_whitelist {
- unsigned short vendor;
- unsigned short device;
+ unsigned short subvendor;
+ unsigned short subdevice;
unsigned short mask;
short action; /* new dxs_support value */
};
static int __devinit check_dxs_list(struct pci_dev *pci)
{
static struct dxs_whitelist whitelist[] = {
- { .vendor = 0x1005, .device = 0x4710, .action = VIA_DXS_ENABLE }, /* Avance Logic Mobo */
- { .vendor = 0x1019, .device = 0x0996, .action = VIA_DXS_48K },
- { .vendor = 0x1019, .device = 0x0a81, .action = VIA_DXS_NO_VRA }, /* ECS K7VTA3 v8.0 */
- { .vendor = 0x1019, .device = 0x0a85, .action = VIA_DXS_NO_VRA }, /* ECS L7VMM2 */
- { .vendor = 0x1025, .device = 0x0033, .action = VIA_DXS_NO_VRA }, /* Acer Inspire 1353LM */
- { .vendor = 0x1043, .device = 0x8095, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8X (FIXME: possibly VIA_DXS_ENABLE?)*/
- { .vendor = 0x1043, .device = 0x80a1, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8-X */
- { .vendor = 0x1043, .device = 0x80b0, .action = VIA_DXS_NO_VRA }, /* ASUS A7V600 & K8V*/
- { .vendor = 0x1071, .device = 0x8375, .action = VIA_DXS_NO_VRA }, /* Vobis/Yakumo/Mitac notebook */
- { .vendor = 0x10cf, .device = 0x118e, .action = VIA_DXS_ENABLE }, /* FSC laptop */
- { .vendor = 0x1106, .device = 0x4161, .action = VIA_DXS_NO_VRA }, /* ASRock K7VT2 */
- { .vendor = 0x1106, .device = 0x4552, .action = VIA_DXS_NO_VRA }, /* QDI Kudoz 7X/600-6AL */
- { .vendor = 0x1106, .device = 0xaa01, .action = VIA_DXS_NO_VRA }, /* EPIA MII */
- { .vendor = 0x1297, .device = 0xa232, .action = VIA_DXS_ENABLE }, /* Shuttle ?? */
- { .vendor = 0x1297, .device = 0xc160, .action = VIA_DXS_ENABLE }, /* Shuttle SK41G */
- { .vendor = 0x1458, .device = 0xa002, .action = VIA_DXS_ENABLE }, /* Gigabyte GA-7VAXP */
- { .vendor = 0x1462, .device = 0x3800, .action = VIA_DXS_ENABLE }, /* MSI KT266 */
- { .vendor = 0x1462, .device = 0x5901, .action = VIA_DXS_NO_VRA }, /* MSI KT6 Delta-SR */
- { .vendor = 0x1462, .device = 0x7023, .action = VIA_DXS_NO_VRA }, /* MSI K8T Neo2-FI */
- { .vendor = 0x1462, .device = 0x7120, .action = VIA_DXS_ENABLE }, /* MSI KT4V */
- { .vendor = 0x147b, .device = 0x1401, .action = VIA_DXS_ENABLE }, /* ABIT KD7(-RAID) */
- { .vendor = 0x147b, .device = 0x1411, .action = VIA_DXS_ENABLE }, /* ABIT VA-20 */
- { .vendor = 0x147b, .device = 0x1413, .action = VIA_DXS_ENABLE }, /* ABIT KV8 Pro */
- { .vendor = 0x147b, .device = 0x1415, .action = VIA_DXS_NO_VRA }, /* Abit AV8 */
- { .vendor = 0x14ff, .device = 0x0403, .action = VIA_DXS_ENABLE }, /* Twinhead mobo */
- { .vendor = 0x1584, .device = 0x8120, .action = VIA_DXS_ENABLE }, /* Gericom/Targa/Vobis/Uniwill laptop */
- { .vendor = 0x1584, .device = 0x8123, .action = VIA_DXS_NO_VRA }, /* Uniwill (Targa Visionary XP-210) */
- { .vendor = 0x161f, .device = 0x202b, .action = VIA_DXS_NO_VRA }, /* Amira Note book */
- { .vendor = 0x161f, .device = 0x2032, .action = VIA_DXS_48K }, /* m680x machines */
- { .vendor = 0x1631, .device = 0xe004, .action = VIA_DXS_ENABLE }, /* Easy Note 3174, Packard Bell */
- { .vendor = 0x1695, .device = 0x3005, .action = VIA_DXS_ENABLE }, /* EPoX EP-8K9A */
- { .vendor = 0x1849, .device = 0x3059, .action = VIA_DXS_NO_VRA }, /* ASRock K7VM2 */
+ { .subvendor = 0x1005, .subdevice = 0x4710, .action = VIA_DXS_ENABLE }, /* Avance Logic Mobo */
+ { .subvendor = 0x1019, .subdevice = 0x0996, .action = VIA_DXS_48K },
+ { .subvendor = 0x1019, .subdevice = 0x0a81, .action = VIA_DXS_NO_VRA }, /* ECS K7VTA3 v8.0 */
+ { .subvendor = 0x1019, .subdevice = 0x0a85, .action = VIA_DXS_NO_VRA }, /* ECS L7VMM2 */
+ { .subvendor = 0x1025, .subdevice = 0x0033, .action = VIA_DXS_NO_VRA }, /* Acer Inspire 1353LM */
+ { .subvendor = 0x1043, .subdevice = 0x8095, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8X (FIXME: possibly VIA_DXS_ENABLE?)*/
+ { .subvendor = 0x1043, .subdevice = 0x80a1, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8-X */
+ { .subvendor = 0x1043, .subdevice = 0x80b0, .action = VIA_DXS_NO_VRA }, /* ASUS A7V600 & K8V*/
+ { .subvendor = 0x1043, .subdevice = 0x812a, .action = VIA_DXS_SRC }, /* ASUS A8V Deluxe */
+ { .subvendor = 0x1071, .subdevice = 0x8375, .action = VIA_DXS_NO_VRA }, /* Vobis/Yakumo/Mitac notebook */
+ { .subvendor = 0x1071, .subdevice = 0x8399, .action = VIA_DXS_NO_VRA }, /* Umax AB 595T (VIA K8N800A - VT8237) */
+ { .subvendor = 0x10cf, .subdevice = 0x118e, .action = VIA_DXS_ENABLE }, /* FSC laptop */
+ { .subvendor = 0x1106, .subdevice = 0x4161, .action = VIA_DXS_NO_VRA }, /* ASRock K7VT2 */
+ { .subvendor = 0x1106, .subdevice = 0x4552, .action = VIA_DXS_NO_VRA }, /* QDI Kudoz 7X/600-6AL */
+ { .subvendor = 0x1106, .subdevice = 0xaa01, .action = VIA_DXS_NO_VRA }, /* EPIA MII */
+ { .subvendor = 0x1106, .subdevice = 0xc001, .action = VIA_DXS_SRC }, /* Insight P4-ITX */
+ { .subvendor = 0x1297, .subdevice = 0xa232, .action = VIA_DXS_ENABLE }, /* Shuttle ?? */
+ { .subvendor = 0x1297, .subdevice = 0xc160, .action = VIA_DXS_ENABLE }, /* Shuttle SK41G */
+ { .subvendor = 0x1458, .subdevice = 0xa002, .action = VIA_DXS_ENABLE }, /* Gigabyte GA-7VAXP */
+ { .subvendor = 0x1462, .subdevice = 0x0080, .action = VIA_DXS_SRC }, /* MSI K8T Neo-FIS2R */
+ { .subvendor = 0x1462, .subdevice = 0x3800, .action = VIA_DXS_ENABLE }, /* MSI KT266 */
+ { .subvendor = 0x1462, .subdevice = 0x5901, .action = VIA_DXS_NO_VRA }, /* MSI KT6 Delta-SR */
+ { .subvendor = 0x1462, .subdevice = 0x7023, .action = VIA_DXS_NO_VRA }, /* MSI K8T Neo2-FI */
+ { .subvendor = 0x1462, .subdevice = 0x7120, .action = VIA_DXS_ENABLE }, /* MSI KT4V */
+ { .subvendor = 0x147b, .subdevice = 0x1401, .action = VIA_DXS_ENABLE }, /* ABIT KD7(-RAID) */
+ { .subvendor = 0x147b, .subdevice = 0x1411, .action = VIA_DXS_ENABLE }, /* ABIT VA-20 */
+ { .subvendor = 0x147b, .subdevice = 0x1413, .action = VIA_DXS_ENABLE }, /* ABIT KV8 Pro */
+ { .subvendor = 0x147b, .subdevice = 0x1415, .action = VIA_DXS_NO_VRA }, /* Abit AV8 */
+ { .subvendor = 0x14ff, .subdevice = 0x0403, .action = VIA_DXS_ENABLE }, /* Twinhead mobo */
+ { .subvendor = 0x14ff, .subdevice = 0x0408, .action = VIA_DXS_NO_VRA }, /* Twinhead mobo */
+ { .subvendor = 0x1584, .subdevice = 0x8120, .action = VIA_DXS_ENABLE }, /* Gericom/Targa/Vobis/Uniwill laptop */
+ { .subvendor = 0x1584, .subdevice = 0x8123, .action = VIA_DXS_NO_VRA }, /* Uniwill (Targa Visionary XP-210) */
+ { .subvendor = 0x161f, .subdevice = 0x202b, .action = VIA_DXS_NO_VRA }, /* Amira Note book */
+ { .subvendor = 0x161f, .subdevice = 0x2032, .action = VIA_DXS_48K }, /* m680x machines */
+ { .subvendor = 0x1631, .subdevice = 0xe004, .action = VIA_DXS_ENABLE }, /* Easy Note 3174, Packard Bell */
+ { .subvendor = 0x1695, .subdevice = 0x3005, .action = VIA_DXS_ENABLE }, /* EPoX EP-8K9A */
+ { .subvendor = 0x1849, .subdevice = 0x3059, .action = VIA_DXS_NO_VRA }, /* ASRock K7VM2 */
+ { .subvendor = 0x1919, .subdevice = 0x200a, .action = VIA_DXS_NO_VRA }, /* Soltek SL-K8Tpro-939 */
{ } /* terminator */
};
struct dxs_whitelist *w;
pci_read_config_word(pci, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor);
pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &subsystem_device);
- for (w = whitelist; w->vendor; w++) {
- if (w->vendor != subsystem_vendor)
+ for (w = whitelist; w->subvendor; w++) {
+ if (w->subvendor != subsystem_vendor)
continue;
if (w->mask) {
- if ((w->mask & subsystem_device) == w->device)
+ if ((w->mask & subsystem_device) == w->subdevice)
return w->action;
} else {
- if (subsystem_device == w->device)
+ if (subsystem_device == w->subdevice)
return w->action;
}
}
* not detected, try 48k rate only to be sure.
*/
printk(KERN_INFO "via82xx: Assuming DXS channels with 48k fixed sample rate.\n");
- printk(KERN_INFO " Please try dxs_support=1 or dxs_support=4 option\n");
+ printk(KERN_INFO " Please try dxs_support=5 option\n");
printk(KERN_INFO " and report if it works on your machine.\n");
+ printk(KERN_INFO " For more details, read ALSA-Configuration.txt.\n");
return VIA_DXS_48K;
};
chip->dxs_fixed = 1;
else if (dxs_support[dev] == VIA_DXS_NO_VRA)
chip->no_vra = 1;
+ else if (dxs_support[dev] == VIA_DXS_SRC) {
+ chip->no_vra = 1;
+ chip->dxs_src = 1;
+ }
}
if ((err = snd_via8233_init_misc(chip, dev)) < 0)
goto __error;
static int __init alsa_card_via82xx_init(void)
{
- return pci_module_init(&driver);
+ return pci_register_driver(&driver);
}
static void __exit alsa_card_via82xx_exit(void)
snd_dma_free_pages(&dev->table);
dev->table.area = NULL;
}
- if (dev->idx_table) {
- kfree(dev->idx_table);
- dev->idx_table = NULL;
- }
+ kfree(dev->idx_table);
+ dev->idx_table = NULL;
return 0;
}
{
via82xx_t *chip = ac97->private_data;
unsigned int xval;
-
+ if(reg == AC97_GPIO_STATUS) {
+ outl(val, VIAREG(chip, GPI_STATUS));
+ return;
+ }
xval = !ac97->num ? VIA_REG_AC97_CODEC_ID_PRIMARY : VIA_REG_AC97_CODEC_ID_SECONDARY;
xval <<= VIA_REG_AC97_CODEC_ID_SHIFT;
xval |= reg << VIA_REG_AC97_CMD_SHIFT;
return 0;
}
-static int snd_via82xx_modem_pcm_trigger(snd_pcm_substream_t * substream, int cmd)
-{
- via82xx_t *chip = snd_pcm_substream_chip(substream);
- unsigned int val = 0;
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- val = snd_ac97_read(chip->ac97, AC97_GPIO_STATUS);
- outl(val|AC97_GPIO_LINE1_OH, VIAREG(chip, GPI_STATUS));
- break;
- case SNDRV_PCM_TRIGGER_STOP:
- val = snd_ac97_read(chip->ac97, AC97_GPIO_STATUS);
- outl(val&~AC97_GPIO_LINE1_OH, VIAREG(chip, GPI_STATUS));
- break;
- default:
- break;
- }
- return snd_via82xx_pcm_trigger(substream, cmd);
-}
-
/*
* pointer callbacks
*/
.hw_params = snd_via82xx_hw_params,
.hw_free = snd_via82xx_hw_free,
.prepare = snd_via82xx_pcm_prepare,
- .trigger = snd_via82xx_modem_pcm_trigger,
+ .trigger = snd_via82xx_pcm_trigger,
.pointer = snd_via686_pcm_pointer,
.page = snd_pcm_sgbuf_ops_page,
};
.hw_params = snd_via82xx_hw_params,
.hw_free = snd_via82xx_hw_free,
.prepare = snd_via82xx_pcm_prepare,
- .trigger = snd_via82xx_modem_pcm_trigger,
+ .trigger = snd_via82xx_pcm_trigger,
.pointer = snd_via686_pcm_pointer,
.page = snd_pcm_sgbuf_ops_page,
};
*
*/
-static int __devinit snd_via82xx_chip_init(via82xx_t *chip)
+static int snd_via82xx_chip_init(via82xx_t *chip)
{
unsigned int val;
int max_count;
static int __init alsa_card_via82xx_init(void)
{
- return pci_module_init(&driver);
+ return pci_register_driver(&driver);
}
static void __exit alsa_card_via82xx_exit(void)
static int __init alsa_card_vx222_init(void)
{
- return pci_module_init(&driver);
+ return pci_register_driver(&driver);
}
static void __exit alsa_card_vx222_exit(void)
static int __init alsa_card_ymfpci_init(void)
{
- return pci_module_init(&driver);
+ return pci_register_driver(&driver);
}
static void __exit alsa_card_ymfpci_exit(void)
static void snd_ymfpci_pcm_free_substream(snd_pcm_runtime_t *runtime)
{
- ymfpci_pcm_t *ypcm = runtime->private_data;
-
- kfree(ypcm);
+ kfree(runtime->private_data);
}
static int snd_ymfpci_playback_open_1(snd_pcm_substream_t * substream)
static int snd_ymfpci_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
{
- unsigned int mask = 1;
-
switch (kcontrol->private_value) {
case YDSXGR_SPDIFOUTCTRL: break;
case YDSXGR_SPDIFINCTRL: break;
default: return -EINVAL;
}
- uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
uinfo->count = 1;
uinfo->value.integer.min = 0;
- uinfo->value.integer.max = mask;
+ uinfo->value.integer.max = 1;
return 0;
}
{
ymfpci_t *chip = snd_kcontrol_chip(kcontrol);
int reg = kcontrol->private_value;
- unsigned int shift = 0, mask = 1, invert = 0;
+ unsigned int shift = 0, mask = 1;
switch (kcontrol->private_value) {
case YDSXGR_SPDIFOUTCTRL: break;
default: return -EINVAL;
}
ucontrol->value.integer.value[0] = (snd_ymfpci_readl(chip, reg) >> shift) & mask;
- if (invert)
- ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
return 0;
}
{
ymfpci_t *chip = snd_kcontrol_chip(kcontrol);
int reg = kcontrol->private_value;
- unsigned int shift = 0, mask = 1, invert = 0;
+ unsigned int shift = 0, mask = 1;
int change;
unsigned int val, oval;
default: return -EINVAL;
}
val = (ucontrol->value.integer.value[0] & mask);
- if (invert)
- val = mask - val;
val <<= shift;
spin_lock_irq(&chip->reg_lock);
oval = snd_ymfpci_readl(chip, reg);
static int snd_ymfpci_info_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
{
unsigned int reg = kcontrol->private_value;
- unsigned int mask = 16383;
if (reg < 0x80 || reg >= 0xc0)
return -EINVAL;
- uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 2;
uinfo->value.integer.min = 0;
- uinfo->value.integer.max = mask;
+ uinfo->value.integer.max = 16383;
return 0;
}
{
ymfpci_t *chip = snd_kcontrol_chip(kcontrol);
unsigned int reg = kcontrol->private_value;
- unsigned int shift_left = 0, shift_right = 16, mask = 16383, invert = 0;
+ unsigned int shift_left = 0, shift_right = 16, mask = 16383;
unsigned int val;
if (reg < 0x80 || reg >= 0xc0)
spin_unlock_irq(&chip->reg_lock);
ucontrol->value.integer.value[0] = (val >> shift_left) & mask;
ucontrol->value.integer.value[1] = (val >> shift_right) & mask;
- if (invert) {
- ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
- ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1];
- }
return 0;
}
{
ymfpci_t *chip = snd_kcontrol_chip(kcontrol);
unsigned int reg = kcontrol->private_value;
- unsigned int shift_left = 0, shift_right = 16, mask = 16383, invert = 0;
+ unsigned int shift_left = 0, shift_right = 16, mask = 16383;
int change;
unsigned int val1, val2, oval;
return -EINVAL;
val1 = ucontrol->value.integer.value[0] & mask;
val2 = ucontrol->value.integer.value[1] & mask;
- if (invert) {
- val1 = mask - val1;
- val2 = mask - val2;
- }
val1 <<= shift_left;
val2 <<= shift_right;
spin_lock_irq(&chip->reg_lock);
if (hw)
hw->card_list[vxp->index] = NULL;
chip->card = NULL;
- if (chip->dev)
- kfree(chip->dev);
+ kfree(chip->dev);
snd_vx_free_firmware(chip);
kfree(chip);
void
snd_emux_delete_effect(snd_emux_port_t *p)
{
- if (p->effect) {
- kfree(p->effect);
- p->effect = NULL;
- }
+ kfree(p->effect);
+ p->effect = NULL;
}
void
config SND_USB_AUDIO
tristate "USB Audio/MIDI driver"
depends on SND && USB
+ select SND_HWDEP
select SND_RAWMIDI
select SND_PCM
help
#define MAX_PACKS 10
#define MAX_PACKS_HS (MAX_PACKS * 8) /* in high speed mode */
#define MAX_URBS 5 /* max. 20ms long packets */
-#define SYNC_URBS 2 /* always two urbs for sync */
+#define SYNC_URBS 4 /* always four urbs for sync */
#define MIN_PACKS_URB 1 /* minimum 1 packet per urb */
typedef struct snd_usb_substream snd_usb_substream_t;
unsigned int nurbs; /* # urbs */
snd_urb_ctx_t dataurb[MAX_URBS]; /* data urb table */
snd_urb_ctx_t syncurb[SYNC_URBS]; /* sync urb table */
- char syncbuf[SYNC_URBS * MAX_PACKS * 4]; /* sync buffer; it's so small - let's get static */
+ char syncbuf[SYNC_URBS * 4]; /* sync buffer; it's so small - let's get static */
char *tmpbuf; /* temporary buffer for playback */
u64 formats; /* format bitmasks (all or'ed) */
{
unsigned char *cp = urb->transfer_buffer;
snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context;
- int i, offs;
- urb->number_of_packets = ctx->packets;
urb->dev = ctx->subs->dev; /* we need to set this at each time */
- for (i = offs = 0; i < urb->number_of_packets; i++, offs += 4, cp += 4) {
- urb->iso_frame_desc[i].length = 3;
- urb->iso_frame_desc[i].offset = offs;
- cp[0] = subs->freqn >> 2;
- cp[1] = subs->freqn >> 10;
- cp[2] = subs->freqn >> 18;
- }
+ urb->iso_frame_desc[0].length = 3;
+ urb->iso_frame_desc[0].offset = 0;
+ cp[0] = subs->freqn >> 2;
+ cp[1] = subs->freqn >> 10;
+ cp[2] = subs->freqn >> 18;
return 0;
}
{
unsigned char *cp = urb->transfer_buffer;
snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context;
- int i, offs;
- urb->number_of_packets = ctx->packets;
urb->dev = ctx->subs->dev; /* we need to set this at each time */
- for (i = offs = 0; i < urb->number_of_packets; i++, offs += 4, cp += 4) {
- urb->iso_frame_desc[i].length = 4;
- urb->iso_frame_desc[i].offset = offs;
- cp[0] = subs->freqn;
- cp[1] = subs->freqn >> 8;
- cp[2] = subs->freqn >> 16;
- cp[3] = subs->freqn >> 24;
- }
+ urb->iso_frame_desc[0].length = 4;
+ urb->iso_frame_desc[0].offset = 0;
+ cp[0] = subs->freqn;
+ cp[1] = subs->freqn >> 8;
+ cp[2] = subs->freqn >> 16;
+ cp[3] = subs->freqn >> 24;
return 0;
}
snd_pcm_runtime_t *runtime,
struct urb *urb)
{
- int i, offs;
snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context;
- urb->number_of_packets = ctx->packets;
urb->dev = ctx->subs->dev; /* we need to set this at each time */
- for (i = offs = 0; i < urb->number_of_packets; i++, offs += 4) {
- urb->iso_frame_desc[i].length = 3;
- urb->iso_frame_desc[i].offset = offs;
- }
+ urb->iso_frame_desc[0].length = 3;
+ urb->iso_frame_desc[0].offset = 0;
return 0;
}
snd_pcm_runtime_t *runtime,
struct urb *urb)
{
- int i, offs;
snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context;
- urb->number_of_packets = ctx->packets;
urb->dev = ctx->subs->dev; /* we need to set this at each time */
- for (i = offs = 0; i < urb->number_of_packets; i++, offs += 4) {
- urb->iso_frame_desc[i].length = 4;
- urb->iso_frame_desc[i].offset = offs;
- }
+ urb->iso_frame_desc[0].length = 4;
+ urb->iso_frame_desc[0].offset = 0;
return 0;
}
snd_pcm_runtime_t *runtime,
struct urb *urb)
{
- int i;
- unsigned int f, found;
- unsigned char *cp = urb->transfer_buffer;
+ unsigned int f;
unsigned long flags;
- found = 0;
- for (i = 0; i < urb->number_of_packets; i++, cp += 4) {
- if (urb->iso_frame_desc[i].status ||
- urb->iso_frame_desc[i].actual_length < 3)
- continue;
- f = combine_triple(cp) << 2;
-#if 0
- if (f < subs->freqn - (subs->freqn>>3) || f > subs->freqmax) {
- snd_printd(KERN_WARNING "requested frequency %d (%u,%03uHz) out of range (current nominal %d (%u,%03uHz))\n",
- f, f >> 14, (f & ((1 << 14) - 1) * 1000) / ((1 << 14) - 1),
- subs->freqn, subs->freqn >> 14, (subs->freqn & ((1 << 14) - 1) * 1000) / ((1 << 14) - 1));
- continue;
+ if (urb->iso_frame_desc[0].status == 0 &&
+ urb->iso_frame_desc[0].actual_length == 3) {
+ f = combine_triple((u8*)urb->transfer_buffer) << 2;
+ if (f >= subs->freqn - subs->freqn / 8 && f <= subs->freqmax) {
+ spin_lock_irqsave(&subs->lock, flags);
+ subs->freqm = f;
+ spin_unlock_irqrestore(&subs->lock, flags);
}
-#endif
- found = f;
- }
- if (found) {
- spin_lock_irqsave(&subs->lock, flags);
- subs->freqm = found;
- spin_unlock_irqrestore(&subs->lock, flags);
}
return 0;
snd_pcm_runtime_t *runtime,
struct urb *urb)
{
- int i;
- unsigned int found;
- unsigned char *cp = urb->transfer_buffer;
+ unsigned int f;
unsigned long flags;
- found = 0;
- for (i = 0; i < urb->number_of_packets; i++, cp += 4) {
- if (urb->iso_frame_desc[i].status ||
- urb->iso_frame_desc[i].actual_length < 4)
- continue;
- found = combine_quad(cp) & 0x0fffffff;
- }
- if (found) {
- spin_lock_irqsave(&subs->lock, flags);
- subs->freqm = found;
- spin_unlock_irqrestore(&subs->lock, flags);
+ if (urb->iso_frame_desc[0].status == 0 &&
+ urb->iso_frame_desc[0].actual_length == 4) {
+ f = combine_quad((u8*)urb->transfer_buffer) & 0x0fffffff;
+ if (f >= subs->freqn - subs->freqn / 8 && f <= subs->freqmax) {
+ spin_lock_irqsave(&subs->lock, flags);
+ subs->freqm = f;
+ spin_unlock_irqrestore(&subs->lock, flags);
+ }
}
return 0;
/* set the buffer pointer */
urb->transfer_buffer = runtime->dma_area + subs->hwptr * stride;
subs->hwptr += offs;
+ if (subs->hwptr == runtime->buffer_size)
+ subs->hwptr = 0;
}
spin_unlock_irqrestore(&subs->lock, flags);
urb->transfer_buffer_length = offs * stride;
usb_free_urb(u->urb);
u->urb = NULL;
}
- if (u->buf) {
- kfree(u->buf);
- u->buf = NULL;
- }
+ kfree(u->buf);
+ u->buf = NULL;
}
/*
release_urb_ctx(&subs->dataurb[i]);
for (i = 0; i < SYNC_URBS; i++)
release_urb_ctx(&subs->syncurb[i]);
- if (subs->tmpbuf) {
- kfree(subs->tmpbuf);
- subs->tmpbuf = NULL;
- }
+ kfree(subs->tmpbuf);
+ subs->tmpbuf = NULL;
subs->nurbs = 0;
}
snd_urb_ctx_t *u = &subs->syncurb[i];
u->index = i;
u->subs = subs;
- u->packets = nrpacks;
- u->urb = usb_alloc_urb(u->packets, GFP_KERNEL);
+ u->packets = 1;
+ u->urb = usb_alloc_urb(1, GFP_KERNEL);
if (! u->urb) {
release_substream_urbs(subs, 0);
return -ENOMEM;
}
- u->urb->transfer_buffer = subs->syncbuf + i * nrpacks * 4;
- u->urb->transfer_buffer_length = nrpacks * 4;
+ u->urb->transfer_buffer = subs->syncbuf + i * 4;
+ u->urb->transfer_buffer_length = 4;
u->urb->dev = subs->dev;
u->urb->pipe = subs->syncpipe;
u->urb->transfer_flags = URB_ISO_ASAP;
- u->urb->number_of_packets = u->packets;
- if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH)
- u->urb->interval = 8;
- else
- u->urb->interval = 1;
+ u->urb->number_of_packets = 1;
+ u->urb->interval = 1 << subs->syncinterval;
u->urb->context = u;
u->urb->complete = snd_usb_complete_callback(snd_complete_sync_urb);
}
subs->syncpipe = usb_rcvisocpipe(dev, ep);
else
subs->syncpipe = usb_sndisocpipe(dev, ep);
- subs->syncinterval = get_endpoint(alts, 1)->bRefresh;
+ if (get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE &&
+ get_endpoint(alts, 1)->bRefresh >= 1 &&
+ get_endpoint(alts, 1)->bRefresh <= 9)
+ subs->syncinterval = get_endpoint(alts, 1)->bRefresh;
+ else if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL)
+ subs->syncinterval = 1;
+ else if (get_endpoint(alts, 1)->bInterval >= 1 &&
+ get_endpoint(alts, 1)->bInterval <= 16)
+ subs->syncinterval = get_endpoint(alts, 1)->bInterval - 1;
+ else
+ subs->syncinterval = 3;
}
/* always fill max packet size */
snd_iprintf(buffer, "%d ", subs->dataurb[i].packets);
snd_iprintf(buffer, "]\n");
snd_iprintf(buffer, " Packet Size = %d\n", subs->curpacksize);
- snd_iprintf(buffer, " Momentary freq = %u Hz\n",
+ snd_iprintf(buffer, " Momentary freq = %u Hz (%#x.%04x)\n",
snd_usb_get_speed(subs->dev) == USB_SPEED_FULL
? get_full_speed_hz(subs->freqm)
- : get_high_speed_hz(subs->freqm));
+ : get_high_speed_hz(subs->freqm),
+ subs->freqm >> 16, subs->freqm & 0xffff);
} else {
snd_iprintf(buffer, " Status: Stop\n");
}
/*
* check if the device uses big-endian samples
*/
-static int is_big_endian_format(struct usb_device *dev, struct audioformat *fp)
+static int is_big_endian_format(snd_usb_audio_t *chip, struct audioformat *fp)
{
- /* M-Audio */
- if (le16_to_cpu(dev->descriptor.idVendor) == 0x0763) {
- /* Quattro: captured data only */
- if (le16_to_cpu(dev->descriptor.idProduct) == 0x2001 &&
- fp->endpoint & USB_DIR_IN)
- return 1;
- /* Audiophile USB */
- if (le16_to_cpu(dev->descriptor.idProduct) == 0x2003)
+ switch (chip->usb_id) {
+ case USB_ID(0x0763, 0x2001): /* M-Audio Quattro: captured data only */
+ if (fp->endpoint & USB_DIR_IN)
return 1;
+ break;
+ case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */
+ return 1;
}
return 0;
}
* @format: the format tag (wFormatTag)
* @fmt: the format type descriptor
*/
-static int parse_audio_format_i_type(struct usb_device *dev, struct audioformat *fp,
+static int parse_audio_format_i_type(snd_usb_audio_t *chip, struct audioformat *fp,
int format, unsigned char *fmt)
{
int pcm_format;
switch (format) {
case 0: /* some devices don't define this correctly... */
snd_printdd(KERN_INFO "%d:%u:%d : format type 0 is detected, processed as PCM\n",
- dev->devnum, fp->iface, fp->altsetting);
+ chip->dev->devnum, fp->iface, fp->altsetting);
/* fall-through */
case USB_AUDIO_FORMAT_PCM:
if (sample_width > sample_bytes * 8) {
snd_printk(KERN_INFO "%d:%u:%d : sample bitwidth %d in over sample bytes %d\n",
- dev->devnum, fp->iface, fp->altsetting,
+ chip->dev->devnum, fp->iface, fp->altsetting,
sample_width, sample_bytes);
}
/* check the format byte size */
pcm_format = SNDRV_PCM_FORMAT_S8;
break;
case 2:
- if (is_big_endian_format(dev, fp))
+ if (is_big_endian_format(chip, fp))
pcm_format = SNDRV_PCM_FORMAT_S16_BE; /* grrr, big endian!! */
else
pcm_format = SNDRV_PCM_FORMAT_S16_LE;
break;
case 3:
- if (is_big_endian_format(dev, fp))
+ if (is_big_endian_format(chip, fp))
pcm_format = SNDRV_PCM_FORMAT_S24_3BE; /* grrr, big endian!! */
else
pcm_format = SNDRV_PCM_FORMAT_S24_3LE;
break;
default:
snd_printk(KERN_INFO "%d:%u:%d : unsupported sample bitwidth %d in %d bytes\n",
- dev->devnum, fp->iface, fp->altsetting, sample_width, sample_bytes);
+ chip->dev->devnum, fp->iface,
+ fp->altsetting, sample_width, sample_bytes);
break;
}
break;
case USB_AUDIO_FORMAT_PCM8:
/* Dallas DS4201 workaround */
- if (le16_to_cpu(dev->descriptor.idVendor) == 0x04fa &&
- le16_to_cpu(dev->descriptor.idProduct) == 0x4201)
+ if (chip->usb_id == USB_ID(0x04fa, 0x4201))
pcm_format = SNDRV_PCM_FORMAT_S8;
else
pcm_format = SNDRV_PCM_FORMAT_U8;
break;
default:
snd_printk(KERN_INFO "%d:%u:%d : unsupported format type %d\n",
- dev->devnum, fp->iface, fp->altsetting, format);
+ chip->dev->devnum, fp->iface, fp->altsetting, format);
break;
}
return pcm_format;
* @offset: the start offset of descriptor pointing the rate type
* (7 for type I and II, 8 for type II)
*/
-static int parse_audio_format_rates(struct usb_device *dev, struct audioformat *fp,
+static int parse_audio_format_rates(snd_usb_audio_t *chip, struct audioformat *fp,
unsigned char *fmt, int offset)
{
int nr_rates = fmt[offset];
if (fmt[0] < offset + 1 + 3 * (nr_rates ? nr_rates : 2)) {
snd_printk(KERN_ERR "%d:%u:%d : invalid FORMAT_TYPE desc\n",
- dev->devnum, fp->iface, fp->altsetting);
+ chip->dev->devnum, fp->iface, fp->altsetting);
return -1;
}
/*
* parse the format type I and III descriptors
*/
-static int parse_audio_format_i(struct usb_device *dev, struct audioformat *fp,
+static int parse_audio_format_i(snd_usb_audio_t *chip, struct audioformat *fp,
int format, unsigned char *fmt)
{
int pcm_format;
*/
pcm_format = SNDRV_PCM_FORMAT_S16_LE;
} else {
- pcm_format = parse_audio_format_i_type(dev, fp, format, fmt);
+ pcm_format = parse_audio_format_i_type(chip, fp, format, fmt);
if (pcm_format < 0)
return -1;
}
fp->channels = fmt[4];
if (fp->channels < 1) {
snd_printk(KERN_ERR "%d:%u:%d : invalid channels %d\n",
- dev->devnum, fp->iface, fp->altsetting, fp->channels);
+ chip->dev->devnum, fp->iface, fp->altsetting, fp->channels);
return -1;
}
- return parse_audio_format_rates(dev, fp, fmt, 7);
+ return parse_audio_format_rates(chip, fp, fmt, 7);
}
/*
* prase the format type II descriptor
*/
-static int parse_audio_format_ii(struct usb_device *dev, struct audioformat *fp,
+static int parse_audio_format_ii(snd_usb_audio_t *chip, struct audioformat *fp,
int format, unsigned char *fmt)
{
int brate, framesize;
break;
default:
snd_printd(KERN_INFO "%d:%u:%d : unknown format tag 0x%x is detected. processed as MPEG.\n",
- dev->devnum, fp->iface, fp->altsetting, format);
+ chip->dev->devnum, fp->iface, fp->altsetting, format);
fp->format = SNDRV_PCM_FORMAT_MPEG;
break;
}
framesize = combine_word(&fmt[6]); /* fmt[6,7]: wSamplesPerFrame */
snd_printd(KERN_INFO "found format II with max.bitrate = %d, frame size=%d\n", brate, framesize);
fp->frame_size = framesize;
- return parse_audio_format_rates(dev, fp, fmt, 8); /* fmt[8..] sample rates */
+ return parse_audio_format_rates(chip, fp, fmt, 8); /* fmt[8..] sample rates */
}
-static int parse_audio_format(struct usb_device *dev, struct audioformat *fp,
+static int parse_audio_format(snd_usb_audio_t *chip, struct audioformat *fp,
int format, unsigned char *fmt, int stream)
{
int err;
switch (fmt[3]) {
case USB_FORMAT_TYPE_I:
case USB_FORMAT_TYPE_III:
- err = parse_audio_format_i(dev, fp, format, fmt);
+ err = parse_audio_format_i(chip, fp, format, fmt);
break;
case USB_FORMAT_TYPE_II:
- err = parse_audio_format_ii(dev, fp, format, fmt);
+ err = parse_audio_format_ii(chip, fp, format, fmt);
break;
default:
snd_printd(KERN_INFO "%d:%u:%d : format type %d is not supported yet\n",
- dev->devnum, fp->iface, fp->altsetting, fmt[3]);
+ chip->dev->devnum, fp->iface, fp->altsetting, fmt[3]);
return -1;
}
fp->fmt_type = fmt[3];
if (err < 0)
return err;
#if 1
- /* FIXME: temporary hack for extigy */
+ /* FIXME: temporary hack for extigy/audigy 2 nx */
/* extigy apparently supports sample rates other than 48k
* but not in ordinary way. so we enable only 48k atm.
*/
- if (le16_to_cpu(dev->descriptor.idVendor) == 0x041e &&
- le16_to_cpu(dev->descriptor.idProduct) == 0x3000) {
+ if (chip->usb_id == USB_ID(0x041e, 0x3000) ||
+ chip->usb_id == USB_ID(0x041e, 0x3020)) {
if (fmt[3] == USB_FORMAT_TYPE_I &&
stream == SNDRV_PCM_STREAM_PLAYBACK &&
- fp->rates != SNDRV_PCM_RATE_48000)
+ fp->rates != SNDRV_PCM_RATE_48000 &&
+ fp->rates != SNDRV_PCM_RATE_96000)
return -1; /* use 48k only */
}
#endif
/* some quirks for attributes here */
- /* workaround for AudioTrak Optoplay */
- if (le16_to_cpu(dev->descriptor.idVendor) == 0x0a92 &&
- le16_to_cpu(dev->descriptor.idProduct) == 0x0053) {
+ switch (chip->usb_id) {
+ case USB_ID(0x0a92, 0x0053): /* AudioTrak Optoplay */
/* Optoplay sets the sample rate attribute although
* it seems not supporting it in fact.
*/
fp->attributes &= ~EP_CS_ATTR_SAMPLE_RATE;
- }
-
- /* workaround for M-Audio Audiophile USB */
- if (le16_to_cpu(dev->descriptor.idVendor) == 0x0763 &&
- le16_to_cpu(dev->descriptor.idProduct) == 0x2003) {
+ break;
+ case USB_ID(0x041e, 0x3020): /* Creative SB Audigy 2 NX */
+ case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */
/* doesn't set the sample rate attribute, but supports it */
fp->attributes |= EP_CS_ATTR_SAMPLE_RATE;
- }
-
+ break;
+ case USB_ID(0x047f, 0x0ca1): /* plantronics headset */
+ case USB_ID(0x077d, 0x07af): /* Griffin iMic (note that there is
+ an older model 77d:223) */
/*
* plantronics headset and Griffin iMic have set adaptive-in
* although it's really not...
*/
- if ((le16_to_cpu(dev->descriptor.idVendor) == 0x047f &&
- le16_to_cpu(dev->descriptor.idProduct) == 0x0ca1) ||
- /* Griffin iMic (note that there is an older model 77d:223) */
- (le16_to_cpu(dev->descriptor.idVendor) == 0x077d &&
- le16_to_cpu(dev->descriptor.idProduct) == 0x07af)) {
fp->ep_attr &= ~EP_ATTR_MASK;
if (stream == SNDRV_PCM_STREAM_PLAYBACK)
fp->ep_attr |= EP_ATTR_ADAPTIVE;
else
fp->ep_attr |= EP_ATTR_SYNC;
+ break;
}
/* ok, let's parse further... */
- if (parse_audio_format(dev, fp, format, fmt, stream) < 0) {
+ if (parse_audio_format(chip, fp, format, fmt, stream) < 0) {
kfree(fp->rate_table);
kfree(fp);
continue;
* disconnect streams
* called from snd_usb_audio_disconnect()
*/
-static void snd_usb_stream_disconnect(struct list_head *head, struct usb_driver *driver)
+static void snd_usb_stream_disconnect(struct list_head *head)
{
int idx;
snd_usb_stream_t *as;
.type = QUIRK_MIDI_FIXED_ENDPOINT,
.data = &ua25_ep
};
- if (le16_to_cpu(chip->dev->descriptor.idProduct) == 0x002b)
+ if (chip->usb_id == USB_ID(0x0582, 0x002b))
return snd_usb_create_midi_interface(chip, iface,
&ua700_quirk);
else
return 0;
}
+static int snd_usb_audigy2nx_boot_quirk(struct usb_device *dev)
+{
+#if 0
+ /* TODO: enable this when high speed synchronization actually works */
+ u8 buf = 1;
+
+ snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), 0x2a,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER,
+ 0, 0, &buf, 1, 1000);
+ if (buf == 0) {
+ snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), 0x29,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
+ 1, 2000, NULL, 0, 1000);
+ return -ENODEV;
+ }
+#endif
+ return 0;
+}
+
/*
* audio-interface quirks
snd_usb_audio_t *chip = entry->private_data;
if (! chip->shutdown)
snd_iprintf(buffer, "%04x:%04x\n",
- le16_to_cpu(chip->dev->descriptor.idVendor),
- le16_to_cpu(chip->dev->descriptor.idProduct));
+ USB_ID_VENDOR(chip->usb_id),
+ USB_ID_PRODUCT(chip->usb_id));
}
static void snd_usb_audio_create_proc(snd_usb_audio_t *chip)
chip->index = idx;
chip->dev = dev;
chip->card = card;
+ chip->usb_id = USB_ID(le16_to_cpu(dev->descriptor.idVendor),
+ le16_to_cpu(dev->descriptor.idProduct));
INIT_LIST_HEAD(&chip->pcm_list);
INIT_LIST_HEAD(&chip->midi_list);
+ INIT_LIST_HEAD(&chip->mixer_list);
if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
snd_usb_audio_free(chip);
strcpy(card->driver, "USB-Audio");
sprintf(component, "USB%04x:%04x",
- le16_to_cpu(dev->descriptor.idVendor),
- le16_to_cpu(dev->descriptor.idProduct));
+ USB_ID_VENDOR(chip->usb_id), USB_ID_PRODUCT(chip->usb_id));
snd_component_add(card, component);
/* retrieve the device string as shortname */
card->shortname, sizeof(card->shortname)) <= 0) {
/* no name available from anywhere, so use ID */
sprintf(card->shortname, "USB Device %#04x:%#04x",
- le16_to_cpu(dev->descriptor.idVendor),
- le16_to_cpu(dev->descriptor.idProduct));
+ USB_ID_VENDOR(chip->usb_id),
+ USB_ID_PRODUCT(chip->usb_id));
}
}
snd_usb_audio_create_proc(chip);
- snd_card_set_dev(card, &dev->dev);
-
*rchip = chip;
return 0;
}
snd_usb_audio_t *chip;
struct usb_host_interface *alts;
int ifnum;
+ u32 id;
alts = &intf->altsetting[0];
ifnum = get_iface_desc(alts)->bInterfaceNumber;
+ id = USB_ID(le16_to_cpu(dev->descriptor.idVendor),
+ le16_to_cpu(dev->descriptor.idProduct));
if (quirk && quirk->ifnum >= 0 && ifnum != quirk->ifnum)
goto __err_val;
/* SB Extigy needs special boot-up sequence */
/* if more models come, this will go to the quirk list. */
- if (le16_to_cpu(dev->descriptor.idVendor) == 0x041e &&
- le16_to_cpu(dev->descriptor.idProduct) == 0x3000) {
+ if (id == USB_ID(0x041e, 0x3000)) {
if (snd_usb_extigy_boot_quirk(dev, intf) < 0)
goto __err_val;
config = dev->actconfig;
}
+ /* SB Audigy 2 NX needs its own boot-up magic, too */
+ if (id == USB_ID(0x041e, 0x3020)) {
+ if (snd_usb_audigy2nx_boot_quirk(dev) < 0)
+ goto __err_val;
+ }
/*
* found a config. now register to ALSA
}
for (i = 0; i < SNDRV_CARDS; i++)
if (enable[i] && ! usb_chip[i] &&
- (vid[i] == -1 || vid[i] == le16_to_cpu(dev->descriptor.idVendor)) &&
- (pid[i] == -1 || pid[i] == le16_to_cpu(dev->descriptor.idProduct))) {
+ (vid[i] == -1 || vid[i] == USB_ID_VENDOR(id)) &&
+ (pid[i] == -1 || pid[i] == USB_ID_PRODUCT(id))) {
if (snd_usb_audio_create(dev, i, quirk, &chip) < 0) {
goto __error;
}
+ snd_card_set_dev(chip->card, &intf->dev);
break;
}
if (! chip) {
snd_card_disconnect(card);
/* release the pcm resources */
list_for_each(p, &chip->pcm_list) {
- snd_usb_stream_disconnect(p, &usb_audio_driver);
+ snd_usb_stream_disconnect(p);
}
/* release the midi resources */
list_for_each(p, &chip->midi_list) {
- snd_usbmidi_disconnect(p, &usb_audio_driver);
+ snd_usbmidi_disconnect(p);
+ }
+ /* release mixer resources */
+ list_for_each(p, &chip->mixer_list) {
+ snd_usb_mixer_disconnect(p);
}
usb_chip[chip->index] = NULL;
up(®ister_mutex);
/* maximum number of endpoints per interface */
#define MIDI_MAX_ENDPOINTS 2
+/* handling of USB vendor/product ID pairs as 32-bit numbers */
+#define USB_ID(vendor, product) (((vendor) << 16) | (product))
+#define USB_ID_VENDOR(id) ((id) >> 16)
+#define USB_ID_PRODUCT(id) ((u16)(id))
+
/*
*/
int index;
struct usb_device *dev;
snd_card_t *card;
+ u32 usb_id;
int shutdown;
int num_interfaces;
struct list_head midi_list; /* list of midi interfaces */
int next_midi_device;
- unsigned int ignore_ctl_error; /* for mixer */
+ struct list_head mixer_list; /* list of mixer interfaces */
};
/*
int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, __u16 size, int timeout);
int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif);
+void snd_usb_mixer_disconnect(struct list_head *p);
int snd_usb_create_midi_interface(snd_usb_audio_t *chip, struct usb_interface *iface, const snd_usb_audio_quirk_t *quirk);
void snd_usbmidi_input_stop(struct list_head* p);
void snd_usbmidi_input_start(struct list_head* p);
-void snd_usbmidi_disconnect(struct list_head *p, struct usb_driver *driver);
+void snd_usbmidi_disconnect(struct list_head *p);
/*
* retrieve usb_interface descriptor from the host interface
/*
* Unlinks all URBs (must be done before the usb_device is deleted).
*/
-void snd_usbmidi_disconnect(struct list_head* p, struct usb_driver *driver)
+void snd_usbmidi_disconnect(struct list_head* p)
{
snd_usb_midi_t* umidi;
int i;
* such as internal control or synthesizer ports.
*/
static struct {
- __u16 vendor;
- __u16 product;
+ u32 id;
int port;
const char *name_format;
} snd_usbmidi_port_names[] = {
/* Roland UA-100 */
- {0x0582, 0x0000, 2, "%s Control"},
+ { USB_ID(0x0582, 0x0000), 2, "%s Control" },
/* Roland SC-8850 */
- {0x0582, 0x0003, 0, "%s Part A"},
- {0x0582, 0x0003, 1, "%s Part B"},
- {0x0582, 0x0003, 2, "%s Part C"},
- {0x0582, 0x0003, 3, "%s Part D"},
- {0x0582, 0x0003, 4, "%s MIDI 1"},
- {0x0582, 0x0003, 5, "%s MIDI 2"},
+ { USB_ID(0x0582, 0x0003), 0, "%s Part A" },
+ { USB_ID(0x0582, 0x0003), 1, "%s Part B" },
+ { USB_ID(0x0582, 0x0003), 2, "%s Part C" },
+ { USB_ID(0x0582, 0x0003), 3, "%s Part D" },
+ { USB_ID(0x0582, 0x0003), 4, "%s MIDI 1" },
+ { USB_ID(0x0582, 0x0003), 5, "%s MIDI 2" },
/* Roland U-8 */
- {0x0582, 0x0004, 0, "%s MIDI"},
- {0x0582, 0x0004, 1, "%s Control"},
+ { USB_ID(0x0582, 0x0004), 0, "%s MIDI" },
+ { USB_ID(0x0582, 0x0004), 1, "%s Control" },
/* Roland SC-8820 */
- {0x0582, 0x0007, 0, "%s Part A"},
- {0x0582, 0x0007, 1, "%s Part B"},
- {0x0582, 0x0007, 2, "%s MIDI"},
+ { USB_ID(0x0582, 0x0007), 0, "%s Part A" },
+ { USB_ID(0x0582, 0x0007), 1, "%s Part B" },
+ { USB_ID(0x0582, 0x0007), 2, "%s MIDI" },
/* Roland SK-500 */
- {0x0582, 0x000b, 0, "%s Part A"},
- {0x0582, 0x000b, 1, "%s Part B"},
- {0x0582, 0x000b, 2, "%s MIDI"},
+ { USB_ID(0x0582, 0x000b), 0, "%s Part A" },
+ { USB_ID(0x0582, 0x000b), 1, "%s Part B" },
+ { USB_ID(0x0582, 0x000b), 2, "%s MIDI" },
/* Roland SC-D70 */
- {0x0582, 0x000c, 0, "%s Part A"},
- {0x0582, 0x000c, 1, "%s Part B"},
- {0x0582, 0x000c, 2, "%s MIDI"},
+ { USB_ID(0x0582, 0x000c), 0, "%s Part A" },
+ { USB_ID(0x0582, 0x000c), 1, "%s Part B" },
+ { USB_ID(0x0582, 0x000c), 2, "%s MIDI" },
/* Edirol UM-880 */
- {0x0582, 0x0014, 8, "%s Control"},
+ { USB_ID(0x0582, 0x0014), 8, "%s Control" },
/* Edirol SD-90 */
- {0x0582, 0x0016, 0, "%s Part A"},
- {0x0582, 0x0016, 1, "%s Part B"},
- {0x0582, 0x0016, 2, "%s MIDI 1"},
- {0x0582, 0x0016, 3, "%s MIDI 2"},
+ { USB_ID(0x0582, 0x0016), 0, "%s Part A" },
+ { USB_ID(0x0582, 0x0016), 1, "%s Part B" },
+ { USB_ID(0x0582, 0x0016), 2, "%s MIDI 1" },
+ { USB_ID(0x0582, 0x0016), 3, "%s MIDI 2" },
/* Edirol UM-550 */
- {0x0582, 0x0023, 5, "%s Control"},
+ { USB_ID(0x0582, 0x0023), 5, "%s Control" },
/* Edirol SD-20 */
- {0x0582, 0x0027, 0, "%s Part A"},
- {0x0582, 0x0027, 1, "%s Part B"},
- {0x0582, 0x0027, 2, "%s MIDI"},
+ { USB_ID(0x0582, 0x0027), 0, "%s Part A" },
+ { USB_ID(0x0582, 0x0027), 1, "%s Part B" },
+ { USB_ID(0x0582, 0x0027), 2, "%s MIDI" },
/* Edirol SD-80 */
- {0x0582, 0x0029, 0, "%s Part A"},
- {0x0582, 0x0029, 1, "%s Part B"},
- {0x0582, 0x0029, 2, "%s MIDI 1"},
- {0x0582, 0x0029, 3, "%s MIDI 2"},
+ { USB_ID(0x0582, 0x0029), 0, "%s Part A" },
+ { USB_ID(0x0582, 0x0029), 1, "%s Part B" },
+ { USB_ID(0x0582, 0x0029), 2, "%s MIDI 1" },
+ { USB_ID(0x0582, 0x0029), 3, "%s MIDI 2" },
/* Edirol UA-700 */
- {0x0582, 0x002b, 0, "%s MIDI"},
- {0x0582, 0x002b, 1, "%s Control"},
+ { USB_ID(0x0582, 0x002b), 0, "%s MIDI" },
+ { USB_ID(0x0582, 0x002b), 1, "%s Control" },
/* Roland VariOS */
- {0x0582, 0x002f, 0, "%s MIDI"},
- {0x0582, 0x002f, 1, "%s External MIDI"},
- {0x0582, 0x002f, 2, "%s Sync"},
+ { USB_ID(0x0582, 0x002f), 0, "%s MIDI" },
+ { USB_ID(0x0582, 0x002f), 1, "%s External MIDI" },
+ { USB_ID(0x0582, 0x002f), 2, "%s Sync" },
/* Edirol PCR */
- {0x0582, 0x0033, 0, "%s MIDI"},
- {0x0582, 0x0033, 1, "%s 1"},
- {0x0582, 0x0033, 2, "%s 2"},
+ { USB_ID(0x0582, 0x0033), 0, "%s MIDI" },
+ { USB_ID(0x0582, 0x0033), 1, "%s 1" },
+ { USB_ID(0x0582, 0x0033), 2, "%s 2" },
/* BOSS GS-10 */
- {0x0582, 0x003b, 0, "%s MIDI"},
- {0x0582, 0x003b, 1, "%s Control"},
+ { USB_ID(0x0582, 0x003b), 0, "%s MIDI" },
+ { USB_ID(0x0582, 0x003b), 1, "%s Control" },
/* Edirol UA-1000 */
- {0x0582, 0x0044, 0, "%s MIDI"},
- {0x0582, 0x0044, 1, "%s Control"},
+ { USB_ID(0x0582, 0x0044), 0, "%s MIDI" },
+ { USB_ID(0x0582, 0x0044), 1, "%s Control" },
/* Edirol UR-80 */
- {0x0582, 0x0048, 0, "%s MIDI"},
- {0x0582, 0x0048, 1, "%s 1"},
- {0x0582, 0x0048, 2, "%s 2"},
+ { USB_ID(0x0582, 0x0048), 0, "%s MIDI" },
+ { USB_ID(0x0582, 0x0048), 1, "%s 1" },
+ { USB_ID(0x0582, 0x0048), 2, "%s 2" },
/* Edirol PCR-A */
- {0x0582, 0x004d, 0, "%s MIDI"},
- {0x0582, 0x004d, 1, "%s 1"},
- {0x0582, 0x004d, 2, "%s 2"},
+ { USB_ID(0x0582, 0x004d), 0, "%s MIDI" },
+ { USB_ID(0x0582, 0x004d), 1, "%s 1" },
+ { USB_ID(0x0582, 0x004d), 2, "%s 2" },
/* M-Audio MidiSport 8x8 */
- {0x0763, 0x1031, 8, "%s Control"},
- {0x0763, 0x1033, 8, "%s Control"},
+ { USB_ID(0x0763, 0x1031), 8, "%s Control" },
+ { USB_ID(0x0763, 0x1033), 8, "%s Control" },
/* MOTU Fastlane */
- {0x07fd, 0x0001, 0, "%s MIDI A"},
- {0x07fd, 0x0001, 1, "%s MIDI B"},
+ { USB_ID(0x07fd, 0x0001), 0, "%s MIDI A" },
+ { USB_ID(0x07fd, 0x0001), 1, "%s MIDI B" },
/* Emagic Unitor8/AMT8/MT4 */
- {0x086a, 0x0001, 8, "%s Broadcast"},
- {0x086a, 0x0002, 8, "%s Broadcast"},
- {0x086a, 0x0003, 4, "%s Broadcast"},
+ { USB_ID(0x086a, 0x0001), 8, "%s Broadcast" },
+ { USB_ID(0x086a, 0x0002), 8, "%s Broadcast" },
+ { USB_ID(0x086a, 0x0003), 4, "%s Broadcast" },
};
static void snd_usbmidi_init_substream(snd_usb_midi_t* umidi,
snd_rawmidi_substream_t** rsubstream)
{
int i;
- __u16 vendor, product;
const char *name_format;
snd_rawmidi_substream_t* substream = snd_usbmidi_find_substream(umidi, stream, number);
/* TODO: read port name from jack descriptor */
name_format = "%s MIDI %d";
- vendor = le16_to_cpu(umidi->chip->dev->descriptor.idVendor);
- product = le16_to_cpu(umidi->chip->dev->descriptor.idProduct);
for (i = 0; i < ARRAY_SIZE(snd_usbmidi_port_names); ++i) {
- if (snd_usbmidi_port_names[i].vendor == vendor &&
- snd_usbmidi_port_names[i].product == product &&
+ if (snd_usbmidi_port_names[i].id == umidi->chip->usb_id &&
snd_usbmidi_port_names[i].port == number) {
name_format = snd_usbmidi_port_names[i].name_format;
break;
struct usb_endpoint_descriptor* epd;
int i, out_eps = 0, in_eps = 0;
- if (le16_to_cpu(umidi->chip->dev->descriptor.idVendor) == 0x0582)
+ if (USB_ID_VENDOR(umidi->chip->usb_id) == 0x0582)
snd_usbmidi_switch_roland_altsetting(umidi);
+ if (endpoint[0].out_ep || endpoint[0].in_ep)
+ return 0;
+
intf = umidi->iface;
if (!intf || intf->num_altsetting < 1)
return -ENOENT;
#include <linux/usb.h>
#include <sound/core.h>
#include <sound/control.h>
+#include <sound/hwdep.h>
+#include <sound/info.h>
#include "usbaudio.h"
-
/*
*/
typedef struct usb_mixer_elem_info usb_mixer_elem_info_t;
+struct usb_mixer_interface {
+ snd_usb_audio_t *chip;
+ unsigned int ctrlif;
+ struct list_head list;
+ unsigned int ignore_ctl_error;
+ struct urb *urb;
+ usb_mixer_elem_info_t **id_elems; /* array[256], indexed by unit id */
+
+ /* Sound Blaster remote control stuff */
+ enum {
+ RC_NONE,
+ RC_EXTIGY,
+ RC_AUDIGY2NX,
+ } rc_type;
+ unsigned long rc_hwdep_open;
+ u32 rc_code;
+ wait_queue_head_t rc_waitq;
+ struct urb *rc_urb;
+ struct usb_ctrlrequest *rc_setup_packet;
+ u8 rc_buffer[6];
+
+ u8 audigy2nx_leds[3];
+};
+
+
struct usb_audio_term {
int id;
int type;
struct usb_mixer_build {
snd_usb_audio_t *chip;
+ struct usb_mixer_interface *mixer;
unsigned char *buffer;
unsigned int buflen;
- unsigned int ctrlif;
- unsigned short vendor;
- unsigned short product;
- DECLARE_BITMAP(unitbitmap, 32*32);
+ DECLARE_BITMAP(unitbitmap, 256);
usb_audio_term_t oterm;
const struct usbmix_name_map *map;
+ const struct usbmix_selector_map *selector_map;
};
struct usb_mixer_elem_info {
- snd_usb_audio_t *chip;
- unsigned int ctrlif;
+ struct usb_mixer_interface *mixer;
+ usb_mixer_elem_info_t *next_id_elem; /* list of controls with same id */
+ snd_ctl_elem_id_t *elem_id;
unsigned int id;
unsigned int control; /* CS or ICN (high byte) */
unsigned int cmask; /* channel mask bitmap: 0 = master */
int channels;
int val_type;
int min, max, res;
- unsigned int initialized: 1;
+ u8 initialized;
};
return 0;
}
+/* get the mapped selector source name */
+static int check_mapped_selector_name(mixer_build_t *state, int unitid,
+ int index, char *buf, int buflen)
+{
+ const struct usbmix_selector_map *p;
+
+ if (! state->selector_map)
+ return 0;
+ for (p = state->selector_map; p->id; p++) {
+ if (p->id == unitid && index < p->count)
+ return strlcpy(buf, p->names[index], buflen);
+ }
+ return 0;
+}
+
/*
* find an audio control unit with the given unit id
*/
int timeout = 10;
while (timeout-- > 0) {
- if (snd_usb_ctl_msg(cval->chip->dev, usb_rcvctrlpipe(cval->chip->dev, 0),
+ if (snd_usb_ctl_msg(cval->mixer->chip->dev,
+ usb_rcvctrlpipe(cval->mixer->chip->dev, 0),
request,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
- validx, cval->ctrlif | (cval->id << 8),
+ validx, cval->mixer->ctrlif | (cval->id << 8),
buf, val_len, 100) >= 0) {
*value_ret = convert_signed_value(cval, snd_usb_combine_bytes(buf, val_len));
return 0;
}
}
- snd_printdd(KERN_ERR "cannot get ctl value: req = 0x%x, wValue = 0x%x, wIndex = 0x%x, type = %d\n", request, validx, cval->ctrlif | (cval->id << 8), cval->val_type);
+ snd_printdd(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n",
+ request, validx, cval->mixer->ctrlif | (cval->id << 8), cval->val_type);
return -EINVAL;
}
buf[0] = value_set & 0xff;
buf[1] = (value_set >> 8) & 0xff;
while (timeout -- > 0)
- if (snd_usb_ctl_msg(cval->chip->dev, usb_sndctrlpipe(cval->chip->dev, 0),
+ if (snd_usb_ctl_msg(cval->mixer->chip->dev,
+ usb_sndctrlpipe(cval->mixer->chip->dev, 0),
request,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
- validx, cval->ctrlif | (cval->id << 8),
+ validx, cval->mixer->ctrlif | (cval->id << 8),
buf, val_len, 100) >= 0)
return 0;
- snd_printdd(KERN_ERR "cannot set ctl value: req = 0x%x, wValue = 0x%x, wIndex = 0x%x, type = %d, data = 0x%x/0x%x\n", request, validx, cval->ctrlif | (cval->id << 8), cval->val_type, buf[0], buf[1]);
+ snd_printdd(KERN_ERR "cannot set ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d, data = %#x/%#x\n",
+ request, validx, cval->mixer->ctrlif | (cval->id << 8), cval->val_type, buf[0], buf[1]);
return -EINVAL;
}
* if failed, give up and free the control instance.
*/
-static int add_control_to_empty(snd_card_t *card, snd_kcontrol_t *kctl)
+static int add_control_to_empty(mixer_build_t *state, snd_kcontrol_t *kctl)
{
+ usb_mixer_elem_info_t *cval = kctl->private_data;
int err;
- while (snd_ctl_find_id(card, &kctl->id))
+
+ while (snd_ctl_find_id(state->chip->card, &kctl->id))
kctl->id.index++;
- if ((err = snd_ctl_add(card, kctl)) < 0) {
+ if ((err = snd_ctl_add(state->chip->card, kctl)) < 0) {
snd_printd(KERN_ERR "cannot add control (err = %d)\n", err);
snd_ctl_free_one(kctl);
+ return err;
}
- return err;
+ cval->elem_id = &kctl->id;
+ cval->next_id_elem = state->mixer->id_elems[cval->id];
+ state->mixer->id_elems[cval->id] = cval;
+ return 0;
}
/* private_free callback */
static void usb_mixer_elem_free(snd_kcontrol_t *kctl)
{
- if (kctl->private_data) {
- kfree(kctl->private_data);
- kctl->private_data = NULL;
- }
+ kfree(kctl->private_data);
+ kctl->private_data = NULL;
}
}
if (get_ctl_value(cval, GET_MAX, (cval->control << 8) | minchn, &cval->max) < 0 ||
get_ctl_value(cval, GET_MIN, (cval->control << 8) | minchn, &cval->min) < 0) {
- snd_printd(KERN_ERR "%d:%d: cannot get min/max values for control %d (id %d)\n", cval->id, cval->ctrlif, cval->control, cval->id);
+ snd_printd(KERN_ERR "%d:%d: cannot get min/max values for control %d (id %d)\n",
+ cval->id, cval->mixer->ctrlif, cval->control, cval->id);
return -EINVAL;
}
if (get_ctl_value(cval, GET_RES, (cval->control << 8) | minchn, &cval->res) < 0) {
if (cval->cmask & (1 << c)) {
err = get_cur_mix_value(cval, c + 1, &val);
if (err < 0) {
- if (cval->chip->ignore_ctl_error) {
+ if (cval->mixer->ignore_ctl_error) {
ucontrol->value.integer.value[0] = cval->min;
return 0;
}
/* master channel */
err = get_cur_mix_value(cval, 0, &val);
if (err < 0) {
- if (cval->chip->ignore_ctl_error) {
+ if (cval->mixer->ignore_ctl_error) {
ucontrol->value.integer.value[0] = cval->min;
return 0;
}
if (cval->cmask & (1 << c)) {
err = get_cur_mix_value(cval, c + 1, &oval);
if (err < 0) {
- if (cval->chip->ignore_ctl_error)
+ if (cval->mixer->ignore_ctl_error)
return 0;
return err;
}
} else {
/* master channel */
err = get_cur_mix_value(cval, 0, &oval);
- if (err < 0 && cval->chip->ignore_ctl_error)
+ if (err < 0 && cval->mixer->ignore_ctl_error)
return 0;
if (err < 0)
return err;
snd_printk(KERN_ERR "cannot malloc kcontrol\n");
return;
}
- cval->chip = state->chip;
- cval->ctrlif = state->ctrlif;
+ cval->mixer = state->mixer;
cval->id = unitid;
cval->control = control;
cval->cmask = ctl_mask;
/* note that detection between firmware 2.1.1.7 (N101) and later 2.1.1.21 */
/* is not very clear from datasheets */
/* I hope that the min value is -15360 for newer firmware --jk */
- if (((state->vendor == 0x471 && (state->product == 0x104 || state->product == 0x105 || state->product == 0x101)) ||
- (state->vendor == 0x672 && state->product == 0x1041)) && !strcmp(kctl->id.name, "PCM Playback Volume") &&
- cval->min == -15616) {
- snd_printk("USB Audio: using volume control quirk for the UDA1321/N101 chip\n");
- cval->max = -256;
+ switch (state->chip->usb_id) {
+ case USB_ID(0x0471, 0x0101):
+ case USB_ID(0x0471, 0x0104):
+ case USB_ID(0x0471, 0x0105):
+ case USB_ID(0x0672, 0x1041):
+ if (!strcmp(kctl->id.name, "PCM Playback Volume") &&
+ cval->min == -15616) {
+ snd_printk("using volume control quirk for the UDA1321/N101 chip\n");
+ cval->max = -256;
+ }
}
snd_printdd(KERN_INFO "[%d] FU [%s] ch = %d, val = %d/%d/%d\n",
cval->id, kctl->id.name, cval->channels, cval->min, cval->max, cval->res);
- add_control_to_empty(state->chip->card, kctl);
+ add_control_to_empty(state, kctl);
}
if (! cval)
return;
- cval->chip = state->chip;
- cval->ctrlif = state->ctrlif;
+ cval->mixer = state->mixer;
cval->id = unitid;
cval->control = in_ch + 1; /* based on 1 */
cval->val_type = USB_MIXER_S16;
snd_printdd(KERN_INFO "[%d] MU [%s] ch = %d, val = %d/%d\n",
cval->id, kctl->id.name, cval->channels, cval->min, cval->max);
- add_control_to_empty(state->chip->card, kctl);
+ add_control_to_empty(state, kctl);
}
int err, val;
err = get_cur_ctl_value(cval, cval->control << 8, &val);
- if (err < 0 && cval->chip->ignore_ctl_error) {
+ if (err < 0 && cval->mixer->ignore_ctl_error) {
ucontrol->value.integer.value[0] = cval->min;
return 0;
}
err = get_cur_ctl_value(cval, cval->control << 8, &oval);
if (err < 0) {
- if (cval->chip->ignore_ctl_error)
+ if (cval->mixer->ignore_ctl_error)
return 0;
return err;
}
}
type = combine_word(&dsc[4]);
- if (! type)
- return 0; /* undefined? */
-
for (info = list; info && info->type; info++)
if (info->type == type)
break;
snd_printk(KERN_ERR "cannot malloc kcontrol\n");
return -ENOMEM;
}
- cval->chip = state->chip;
- cval->ctrlif = state->ctrlif;
+ cval->mixer = state->mixer;
cval->id = unitid;
cval->control = valinfo->control;
cval->val_type = valinfo->val_type;
snd_printdd(KERN_INFO "[%d] PU [%s] ch = %d, val = %d/%d\n",
cval->id, kctl->id.name, cval->channels, cval->min, cval->max);
- if ((err = add_control_to_empty(state->chip->card, kctl)) < 0)
+ if ((err = add_control_to_empty(state, kctl)) < 0)
return err;
}
return 0;
err = get_cur_ctl_value(cval, 0, &val);
if (err < 0) {
- if (cval->chip->ignore_ctl_error) {
+ if (cval->mixer->ignore_ctl_error) {
ucontrol->value.enumerated.item[0] = 0;
return 0;
}
err = get_cur_ctl_value(cval, 0, &oval);
if (err < 0) {
- if (cval->chip->ignore_ctl_error)
+ if (cval->mixer->ignore_ctl_error)
return 0;
return err;
}
snd_printk(KERN_ERR "cannot malloc kcontrol\n");
return -ENOMEM;
}
- cval->chip = state->chip;
- cval->ctrlif = state->ctrlif;
+ cval->mixer = state->mixer;
cval->id = unitid;
cval->val_type = USB_MIXER_U8;
cval->channels = 1;
kfree(cval);
return -ENOMEM;
}
- if (check_input_term(state, desc[5 + i], &iterm) >= 0)
+ len = check_mapped_selector_name(state, unitid, i, namelist[i],
+ MAX_ITEM_NAME_LEN);
+ if (! len && check_input_term(state, desc[5 + i], &iterm) >= 0)
len = get_term_name(state, &iterm, namelist[i], MAX_ITEM_NAME_LEN, 0);
if (! len)
sprintf(namelist[i], "Input %d", i);
snd_printdd(KERN_INFO "[%d] SU [%s] items = %d\n",
cval->id, kctl->id.name, num_ins);
- if ((err = add_control_to_empty(state->chip->card, kctl)) < 0)
+ if ((err = add_control_to_empty(state, kctl)) < 0)
return err;
return 0;
}
}
+static void snd_usb_mixer_free(struct usb_mixer_interface *mixer)
+{
+ kfree(mixer->id_elems);
+ if (mixer->urb) {
+ kfree(mixer->urb->transfer_buffer);
+ usb_free_urb(mixer->urb);
+ }
+ if (mixer->rc_urb)
+ usb_free_urb(mixer->rc_urb);
+ kfree(mixer->rc_setup_packet);
+ kfree(mixer);
+}
+
+static int snd_usb_mixer_dev_free(snd_device_t *device)
+{
+ struct usb_mixer_interface *mixer = device->device_data;
+ snd_usb_mixer_free(mixer);
+ return 0;
+}
+
/*
* create mixer controls
*
* walk through all OUTPUT_TERMINAL descriptors to search for mixers
*/
-int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif)
+static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer)
{
unsigned char *desc;
mixer_build_t state;
int err;
const struct usbmix_ctl_map *map;
- struct usb_device_descriptor *dev = &chip->dev->descriptor;
- struct usb_host_interface *hostif = &usb_ifnum_to_if(chip->dev, ctrlif)->altsetting[0];
-
- strcpy(chip->card->mixername, "USB Mixer");
+ struct usb_host_interface *hostif;
+ hostif = &usb_ifnum_to_if(mixer->chip->dev, mixer->ctrlif)->altsetting[0];
memset(&state, 0, sizeof(state));
- state.chip = chip;
+ state.chip = mixer->chip;
+ state.mixer = mixer;
state.buffer = hostif->extra;
state.buflen = hostif->extralen;
- state.ctrlif = ctrlif;
- state.vendor = le16_to_cpu(dev->idVendor);
- state.product = le16_to_cpu(dev->idProduct);
/* check the mapping table */
- for (map = usbmix_ctl_maps; map->vendor; map++) {
- if (map->vendor == state.vendor && map->product == state.product) {
+ for (map = usbmix_ctl_maps; map->id; map++) {
+ if (map->id == state.chip->usb_id) {
state.map = map->map;
- chip->ignore_ctl_error = map->ignore_ctl_error;
+ state.selector_map = map->selector_map;
+ mixer->ignore_ctl_error = map->ignore_ctl_error;
break;
}
}
-#ifdef IGNORE_CTL_ERROR
- chip->ignore_ctl_error = 1;
-#endif
desc = NULL;
while ((desc = snd_usb_find_csint_desc(hostif->extra, hostif->extralen, desc, OUTPUT_TERMINAL)) != NULL) {
}
return 0;
}
+
+static void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer,
+ int unitid)
+{
+ usb_mixer_elem_info_t *info;
+
+ for (info = mixer->id_elems[unitid]; info; info = info->next_id_elem)
+ snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
+ info->elem_id);
+}
+
+static void snd_usb_mixer_memory_change(struct usb_mixer_interface *mixer,
+ int unitid)
+{
+ if (mixer->rc_type == RC_NONE)
+ return;
+ /* unit ids specific to Extigy/Audigy 2 NX: */
+ switch (unitid) {
+ case 0: /* remote control */
+ mixer->rc_urb->dev = mixer->chip->dev;
+ usb_submit_urb(mixer->rc_urb, GFP_ATOMIC);
+ break;
+ case 4: /* digital in jack */
+ case 7: /* line in jacks */
+ case 19: /* speaker out jacks */
+ case 20: /* headphones out jack */
+ break;
+ default:
+ snd_printd(KERN_DEBUG "memory change in unknown unit %d\n", unitid);
+ break;
+ }
+}
+
+static void snd_usb_mixer_status_complete(struct urb *urb, struct pt_regs *regs)
+{
+ struct usb_mixer_interface *mixer = urb->context;
+
+ if (urb->status == 0) {
+ u8 *buf = urb->transfer_buffer;
+ int i;
+
+ for (i = urb->actual_length; i >= 2; buf += 2, i -= 2) {
+ snd_printd(KERN_DEBUG "status interrupt: %02x %02x\n",
+ buf[0], buf[1]);
+ /* ignore any notifications not from the control interface */
+ if ((buf[0] & 0x0f) != 0)
+ continue;
+ if (!(buf[0] & 0x40))
+ snd_usb_mixer_notify_id(mixer, buf[1]);
+ else
+ snd_usb_mixer_memory_change(mixer, buf[1]);
+ }
+ }
+ if (urb->status != -ENOENT && urb->status != -ECONNRESET) {
+ urb->dev = mixer->chip->dev;
+ usb_submit_urb(urb, GFP_ATOMIC);
+ }
+}
+
+/* create the handler for the optional status interrupt endpoint */
+static int snd_usb_mixer_status_create(struct usb_mixer_interface *mixer)
+{
+ struct usb_host_interface *hostif;
+ struct usb_endpoint_descriptor *ep;
+ void *transfer_buffer;
+ int buffer_length;
+ unsigned int epnum;
+
+ hostif = &usb_ifnum_to_if(mixer->chip->dev, mixer->ctrlif)->altsetting[0];
+ /* we need one interrupt input endpoint */
+ if (get_iface_desc(hostif)->bNumEndpoints < 1)
+ return 0;
+ ep = get_endpoint(hostif, 0);
+ if ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) != USB_DIR_IN ||
+ (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT)
+ return 0;
+
+ epnum = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+ buffer_length = le16_to_cpu(ep->wMaxPacketSize);
+ transfer_buffer = kmalloc(buffer_length, GFP_KERNEL);
+ if (!transfer_buffer)
+ return -ENOMEM;
+ mixer->urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!mixer->urb) {
+ kfree(transfer_buffer);
+ return -ENOMEM;
+ }
+ usb_fill_int_urb(mixer->urb, mixer->chip->dev,
+ usb_rcvintpipe(mixer->chip->dev, epnum),
+ transfer_buffer, buffer_length,
+ snd_usb_mixer_status_complete, mixer, ep->bInterval);
+ usb_submit_urb(mixer->urb, GFP_KERNEL);
+ return 0;
+}
+
+static void snd_usb_soundblaster_remote_complete(struct urb *urb,
+ struct pt_regs *regs)
+{
+ struct usb_mixer_interface *mixer = urb->context;
+ /*
+ * format of remote control data:
+ * Extigy: xx 00
+ * Audigy 2 NX: 06 80 xx 00 00 00
+ */
+ int offset = mixer->rc_type == RC_EXTIGY ? 0 : 2;
+ u32 code;
+
+ if (urb->status < 0 || urb->actual_length <= offset)
+ return;
+ code = mixer->rc_buffer[offset];
+ /* the Mute button actually changes the mixer control */
+ if (code == 13)
+ snd_usb_mixer_notify_id(mixer, 18);
+ mixer->rc_code = code;
+ wmb();
+ wake_up(&mixer->rc_waitq);
+}
+
+static int snd_usb_sbrc_hwdep_open(snd_hwdep_t *hw, struct file *file)
+{
+ struct usb_mixer_interface *mixer = hw->private_data;
+
+ if (test_and_set_bit(0, &mixer->rc_hwdep_open))
+ return -EBUSY;
+ return 0;
+}
+
+static int snd_usb_sbrc_hwdep_release(snd_hwdep_t *hw, struct file *file)
+{
+ struct usb_mixer_interface *mixer = hw->private_data;
+
+ clear_bit(0, &mixer->rc_hwdep_open);
+ smp_mb__after_clear_bit();
+ return 0;
+}
+
+static long snd_usb_sbrc_hwdep_read(snd_hwdep_t *hw, char __user *buf,
+ long count, loff_t *offset)
+{
+ struct usb_mixer_interface *mixer = hw->private_data;
+ int err;
+ u32 rc_code;
+
+ if (count != 1 && count != 4)
+ return -EINVAL;
+ err = wait_event_interruptible(mixer->rc_waitq,
+ (rc_code = xchg(&mixer->rc_code, 0)) != 0);
+ if (err == 0) {
+ if (count == 1)
+ err = put_user(rc_code, buf);
+ else
+ err = put_user(rc_code, (u32 __user *)buf);
+ }
+ return err < 0 ? err : count;
+}
+
+static unsigned int snd_usb_sbrc_hwdep_poll(snd_hwdep_t *hw, struct file *file,
+ poll_table *wait)
+{
+ struct usb_mixer_interface *mixer = hw->private_data;
+
+ poll_wait(file, &mixer->rc_waitq, wait);
+ return mixer->rc_code ? POLLIN | POLLRDNORM : 0;
+}
+
+static int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer)
+{
+ snd_hwdep_t *hwdep;
+ int err, len;
+
+ switch (mixer->chip->usb_id) {
+ case USB_ID(0x041e, 0x3000):
+ mixer->rc_type = RC_EXTIGY;
+ len = 2;
+ break;
+ case USB_ID(0x041e, 0x3020):
+ mixer->rc_type = RC_AUDIGY2NX;
+ len = 6;
+ break;
+ default:
+ return 0;
+ }
+
+ init_waitqueue_head(&mixer->rc_waitq);
+ err = snd_hwdep_new(mixer->chip->card, "SB remote control", 0, &hwdep);
+ if (err < 0)
+ return err;
+ snprintf(hwdep->name, sizeof(hwdep->name),
+ "%s remote control", mixer->chip->card->shortname);
+ hwdep->iface = SNDRV_HWDEP_IFACE_SB_RC;
+ hwdep->private_data = mixer;
+ hwdep->ops.read = snd_usb_sbrc_hwdep_read;
+ hwdep->ops.open = snd_usb_sbrc_hwdep_open;
+ hwdep->ops.release = snd_usb_sbrc_hwdep_release;
+ hwdep->ops.poll = snd_usb_sbrc_hwdep_poll;
+
+ mixer->rc_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!mixer->rc_urb)
+ return -ENOMEM;
+ mixer->rc_setup_packet = kmalloc(sizeof(*mixer->rc_setup_packet), GFP_KERNEL);
+ if (!mixer->rc_setup_packet) {
+ usb_free_urb(mixer->rc_urb);
+ mixer->rc_urb = NULL;
+ return -ENOMEM;
+ }
+ mixer->rc_setup_packet->bRequestType =
+ USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+ mixer->rc_setup_packet->bRequest = GET_MEM;
+ mixer->rc_setup_packet->wValue = cpu_to_le16(0);
+ mixer->rc_setup_packet->wIndex = cpu_to_le16(0);
+ mixer->rc_setup_packet->wLength = cpu_to_le16(len);
+ usb_fill_control_urb(mixer->rc_urb, mixer->chip->dev,
+ usb_rcvctrlpipe(mixer->chip->dev, 0),
+ (u8*)mixer->rc_setup_packet, mixer->rc_buffer, len,
+ snd_usb_soundblaster_remote_complete, mixer);
+ return 0;
+}
+
+static int snd_audigy2nx_led_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+static int snd_audigy2nx_led_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+ struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
+ int index = kcontrol->private_value;
+
+ ucontrol->value.integer.value[0] = mixer->audigy2nx_leds[index];
+ return 0;
+}
+
+static int snd_audigy2nx_led_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+ struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
+ int index = kcontrol->private_value;
+ int value = ucontrol->value.integer.value[0];
+ int err, changed;
+
+ if (value > 1)
+ return -EINVAL;
+ changed = value != mixer->audigy2nx_leds[index];
+ err = snd_usb_ctl_msg(mixer->chip->dev,
+ usb_sndctrlpipe(mixer->chip->dev, 0), 0x24,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
+ value, index + 2, NULL, 0, 100);
+ if (err < 0)
+ return err;
+ mixer->audigy2nx_leds[index] = value;
+ return changed;
+}
+
+static snd_kcontrol_new_t snd_audigy2nx_controls[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "CMSS LED Switch",
+ .info = snd_audigy2nx_led_info,
+ .get = snd_audigy2nx_led_get,
+ .put = snd_audigy2nx_led_put,
+ .private_value = 0,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Power LED Switch",
+ .info = snd_audigy2nx_led_info,
+ .get = snd_audigy2nx_led_get,
+ .put = snd_audigy2nx_led_put,
+ .private_value = 1,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Dolby Digital LED Switch",
+ .info = snd_audigy2nx_led_info,
+ .get = snd_audigy2nx_led_get,
+ .put = snd_audigy2nx_led_put,
+ .private_value = 2,
+ },
+};
+
+static int snd_audigy2nx_controls_create(struct usb_mixer_interface *mixer)
+{
+ int i, err;
+
+ for (i = 0; i < ARRAY_SIZE(snd_audigy2nx_controls); ++i) {
+ err = snd_ctl_add(mixer->chip->card,
+ snd_ctl_new1(&snd_audigy2nx_controls[i], mixer));
+ if (err < 0)
+ return err;
+ }
+ mixer->audigy2nx_leds[1] = 1; /* Power LED is on by default */
+ return 0;
+}
+
+static void snd_audigy2nx_proc_read(snd_info_entry_t *entry,
+ snd_info_buffer_t *buffer)
+{
+ static const struct {
+ int unitid;
+ const char *name;
+ } jacks[] = {
+ {4, "dig in "},
+ {7, "line in"},
+ {19, "spk out"},
+ {20, "hph out"},
+ };
+ struct usb_mixer_interface *mixer = entry->private_data;
+ int i, err;
+ u8 buf[3];
+
+ snd_iprintf(buffer, "%s jacks\n\n", mixer->chip->card->shortname);
+ for (i = 0; i < ARRAY_SIZE(jacks); ++i) {
+ snd_iprintf(buffer, "%s: ", jacks[i].name);
+ err = snd_usb_ctl_msg(mixer->chip->dev,
+ usb_rcvctrlpipe(mixer->chip->dev, 0),
+ GET_MEM, USB_DIR_IN | USB_TYPE_CLASS |
+ USB_RECIP_INTERFACE, 0,
+ jacks[i].unitid << 8, buf, 3, 100);
+ if (err == 3 && buf[0] == 3)
+ snd_iprintf(buffer, "%02x %02x\n", buf[1], buf[2]);
+ else
+ snd_iprintf(buffer, "?\n");
+ }
+}
+
+int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif)
+{
+ static snd_device_ops_t dev_ops = {
+ .dev_free = snd_usb_mixer_dev_free
+ };
+ struct usb_mixer_interface *mixer;
+ int err;
+
+ strcpy(chip->card->mixername, "USB Mixer");
+
+ mixer = kcalloc(1, sizeof(*mixer), GFP_KERNEL);
+ if (!mixer)
+ return -ENOMEM;
+ mixer->chip = chip;
+ mixer->ctrlif = ctrlif;
+#ifdef IGNORE_CTL_ERROR
+ mixer->ignore_ctl_error = 1;
+#endif
+ mixer->id_elems = kcalloc(256, sizeof(*mixer->id_elems), GFP_KERNEL);
+ if (!mixer->id_elems) {
+ kfree(mixer);
+ return -ENOMEM;
+ }
+
+ if ((err = snd_usb_mixer_controls(mixer)) < 0 ||
+ (err = snd_usb_mixer_status_create(mixer)) < 0)
+ goto _error;
+
+ if ((err = snd_usb_soundblaster_remote_init(mixer)) < 0)
+ goto _error;
+
+ if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020)) {
+ snd_info_entry_t *entry;
+
+ if ((err = snd_audigy2nx_controls_create(mixer)) < 0)
+ goto _error;
+ if (!snd_card_proc_new(chip->card, "audigy2nx", &entry))
+ snd_info_set_text_ops(entry, mixer, 1024,
+ snd_audigy2nx_proc_read);
+ }
+
+ err = snd_device_new(chip->card, SNDRV_DEV_LOWLEVEL, mixer, &dev_ops);
+ if (err < 0)
+ goto _error;
+ list_add(&mixer->list, &chip->mixer_list);
+ return 0;
+
+_error:
+ snd_usb_mixer_free(mixer);
+ return err;
+}
+
+void snd_usb_mixer_disconnect(struct list_head *p)
+{
+ struct usb_mixer_interface *mixer;
+
+ mixer = list_entry(p, struct usb_mixer_interface, list);
+ if (mixer->urb)
+ usb_kill_urb(mixer->urb);
+ if (mixer->rc_urb)
+ usb_kill_urb(mixer->rc_urb);
+}
int control;
};
+struct usbmix_selector_map {
+ int id;
+ int count;
+ const char **names;
+};
+
struct usbmix_ctl_map {
- int vendor;
- int product;
+ u32 id;
const struct usbmix_name_map *map;
+ const struct usbmix_selector_map *selector_map;
int ignore_ctl_error;
};
{ 0 } /* terminator */
};
+/* Sound Blaster MP3+ controls mapping
+ * The default mixer channels have totally misleading names,
+ * e.g. no Master and fake PCM volume
+ * Pavel Mihaylov <bin@bash.info>
+ */
+static struct usbmix_name_map mp3plus_map[] = {
+ /* 1: IT pcm */
+ /* 2: IT mic */
+ /* 3: IT line */
+ /* 4: IT digital in */
+ /* 5: OT digital out */
+ /* 6: OT speaker */
+ /* 7: OT pcm capture */
+ { 8, "Capture Input Source" }, /* FU, default PCM Capture Source */
+ /* (Mic, Input 1 = Line input, Input 2 = Optical input) */
+ { 9, "Master Playback" }, /* FU, default Speaker 1 */
+ /* { 10, "Mic Capture", 1 }, */ /* FU, Mic Capture */
+ /* { 10, "Mic Capture", 2 }, */ /* FU, Mic Capture */
+ { 10, "Mic Boost", 7 }, /* FU, default Auto Gain Input */
+ { 11, "Line Capture" }, /* FU, default PCM Capture */
+ { 12, "Digital In Playback" }, /* FU, default PCM 1 */
+ /* { 13, "Mic Playback" }, */ /* FU, default Mic Playback */
+ { 14, "Line Playback" }, /* FU, default Speaker */
+ /* 15: MU */
+ { 0 } /* terminator */
+};
+
+/* Topology of SB Audigy 2 NX
+
+ +----------------------------->EU[27]--+
+ | v
+ | +----------------------------------->SU[29]---->FU[22]-->Dig_OUT[24]
+ | | ^
+USB_IN[1]-+------------+ +->EU[17]->+->FU[11]-+
+ | v | v |
+Dig_IN[4]---+->FU[6]-->MU[16]->FU[18]-+->EU[21]->SU[31]----->FU[30]->Hph_OUT[20]
+ | ^ | |
+Lin_IN[7]-+--->FU[8]---+ +->EU[23]->FU[28]------------->Spk_OUT[19]
+ | | v
+ +--->FU[12]------------------------------------->SU[14]--->USB_OUT[15]
+ | ^
+ +->FU[13]--------------------------------------+
+*/
+static struct usbmix_name_map audigy2nx_map[] = {
+ /* 1: IT pcm playback */
+ /* 4: IT digital in */
+ { 6, "Digital In Playback" }, /* FU */
+ /* 7: IT line in */
+ { 8, "Line Playback" }, /* FU */
+ { 11, "What-U-Hear Capture" }, /* FU */
+ { 12, "Line Capture" }, /* FU */
+ { 13, "Digital In Capture" }, /* FU */
+ { 14, "Capture Source" }, /* SU */
+ /* 15: OT pcm capture */
+ /* 16: MU w/o controls */
+ { 17, NULL }, /* DISABLED: EU (for what?) */
+ { 18, "Master Playback" }, /* FU */
+ /* 19: OT speaker */
+ /* 20: OT headphone */
+ { 21, NULL }, /* DISABLED: EU (for what?) */
+ { 22, "Digital Out Playback" }, /* FU */
+ { 23, NULL }, /* DISABLED: EU (for what?) */
+ /* 24: OT digital out */
+ { 27, NULL }, /* DISABLED: EU (for what?) */
+ { 28, "Speaker Playback" }, /* FU */
+ { 29, "Digital Out Source" }, /* SU */
+ { 30, "Headphone Playback" }, /* FU */
+ { 31, "Headphone Source" }, /* SU */
+ { 0 } /* terminator */
+};
+
+static struct usbmix_selector_map audigy2nx_selectors[] = {
+ {
+ .id = 14, /* Capture Source */
+ .count = 3,
+ .names = (const char*[]) {"Line", "Digital In", "What-U-Hear"}
+ },
+ {
+ .id = 29, /* Digital Out Source */
+ .count = 3,
+ .names = (const char*[]) {"Front", "PCM", "Digital In"}
+ },
+ {
+ .id = 31, /* Headphone Source */
+ .count = 2,
+ .names = (const char*[]) {"Front", "Side"}
+ },
+ { 0 } /* terminator */
+};
+
/* LineX FM Transmitter entry - needed to bypass controls bug */
static struct usbmix_name_map linex_map[] = {
/* 1: IT pcm */
*/
static struct usbmix_ctl_map usbmix_ctl_maps[] = {
- { 0x41e, 0x3000, extigy_map, 1 },
- { 0x8bb, 0x2702, linex_map, 1 },
- { 0xc45, 0x1158, justlink_map, 0 },
+ {
+ .id = USB_ID(0x041e, 0x3000),
+ .map = extigy_map,
+ .ignore_ctl_error = 1,
+ },
+ {
+ .id = USB_ID(0x041e, 0x3010),
+ .map = mp3plus_map,
+ },
+ {
+ .id = USB_ID(0x041e, 0x3020),
+ .map = audigy2nx_map,
+ .selector_map = audigy2nx_selectors,
+ },
+ {
+ .id = USB_ID(0x08bb, 0x2702),
+ .map = linex_map,
+ .ignore_ctl_error = 1,
+ },
+ {
+ .id = USB_ID(0x0c45, 0x1158),
+ .map = justlink_map,
+ },
{ 0 } /* terminator */
};
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "EDIROL",
.product_name = "UM-4",
- .ifnum = 2,
- .type = QUIRK_MIDI_FIXED_ENDPOINT,
- .data = & (const snd_usb_midi_endpoint_info_t) {
- .out_cables = 0x000f,
- .in_cables = 0x000f
+ .ifnum = QUIRK_ANY_INTERFACE,
+ .type = QUIRK_COMPOSITE,
+ .data = (const snd_usb_audio_quirk_t[]) {
+ {
+ .ifnum = 0,
+ .type = QUIRK_IGNORE_INTERFACE
+ },
+ {
+ .ifnum = 1,
+ .type = QUIRK_IGNORE_INTERFACE
+ },
+ {
+ .ifnum = 2,
+ .type = QUIRK_MIDI_FIXED_ENDPOINT,
+ .data = & (const snd_usb_midi_endpoint_info_t) {
+ .out_cables = 0x000f,
+ .in_cables = 0x000f
+ }
+ },
+ {
+ .ifnum = -1
+ }
}
}
},
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "Roland",
.product_name = "SC-8850",
- .ifnum = 2,
- .type = QUIRK_MIDI_FIXED_ENDPOINT,
- .data = & (const snd_usb_midi_endpoint_info_t) {
- .out_cables = 0x003f,
- .in_cables = 0x003f
+ .ifnum = QUIRK_ANY_INTERFACE,
+ .type = QUIRK_COMPOSITE,
+ .data = (const snd_usb_audio_quirk_t[]) {
+ {
+ .ifnum = 0,
+ .type = QUIRK_IGNORE_INTERFACE
+ },
+ {
+ .ifnum = 1,
+ .type = QUIRK_IGNORE_INTERFACE
+ },
+ {
+ .ifnum = 2,
+ .type = QUIRK_MIDI_FIXED_ENDPOINT,
+ .data = & (const snd_usb_midi_endpoint_info_t) {
+ .out_cables = 0x003f,
+ .in_cables = 0x003f
+ }
+ },
+ {
+ .ifnum = -1
+ }
}
}
},
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "Roland",
.product_name = "U-8",
- .ifnum = 2,
- .type = QUIRK_MIDI_FIXED_ENDPOINT,
- .data = & (const snd_usb_midi_endpoint_info_t) {
- .out_cables = 0x0005,
- .in_cables = 0x0005
+ .ifnum = QUIRK_ANY_INTERFACE,
+ .type = QUIRK_COMPOSITE,
+ .data = (const snd_usb_audio_quirk_t[]) {
+ {
+ .ifnum = 0,
+ .type = QUIRK_IGNORE_INTERFACE
+ },
+ {
+ .ifnum = 1,
+ .type = QUIRK_IGNORE_INTERFACE
+ },
+ {
+ .ifnum = 2,
+ .type = QUIRK_MIDI_FIXED_ENDPOINT,
+ .data = & (const snd_usb_midi_endpoint_info_t) {
+ .out_cables = 0x0005,
+ .in_cables = 0x0005
+ }
+ },
+ {
+ .ifnum = -1
+ }
}
}
},
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "EDIROL",
.product_name = "UM-2",
- .ifnum = 2,
- .type = QUIRK_MIDI_FIXED_ENDPOINT,
- .data = & (const snd_usb_midi_endpoint_info_t) {
- .out_cables = 0x0003,
- .in_cables = 0x0003
+ .ifnum = QUIRK_ANY_INTERFACE,
+ .type = QUIRK_COMPOSITE,
+ .data = (const snd_usb_audio_quirk_t[]) {
+ {
+ .ifnum = 0,
+ .type = QUIRK_IGNORE_INTERFACE
+ },
+ {
+ .ifnum = 1,
+ .type = QUIRK_IGNORE_INTERFACE
+ },
+ {
+ .ifnum = 2,
+ .type = QUIRK_MIDI_FIXED_ENDPOINT,
+ .data = & (const snd_usb_midi_endpoint_info_t) {
+ .out_cables = 0x0003,
+ .in_cables = 0x0003
+ }
+ },
+ {
+ .ifnum = -1
+ }
}
}
},
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "Roland",
.product_name = "SC-8820",
- .ifnum = 2,
- .type = QUIRK_MIDI_FIXED_ENDPOINT,
- .data = & (const snd_usb_midi_endpoint_info_t) {
- .out_cables = 0x0013,
- .in_cables = 0x0013
+ .ifnum = QUIRK_ANY_INTERFACE,
+ .type = QUIRK_COMPOSITE,
+ .data = (const snd_usb_audio_quirk_t[]) {
+ {
+ .ifnum = 0,
+ .type = QUIRK_IGNORE_INTERFACE
+ },
+ {
+ .ifnum = 1,
+ .type = QUIRK_IGNORE_INTERFACE
+ },
+ {
+ .ifnum = 2,
+ .type = QUIRK_MIDI_FIXED_ENDPOINT,
+ .data = & (const snd_usb_midi_endpoint_info_t) {
+ .out_cables = 0x0013,
+ .in_cables = 0x0013
+ }
+ },
+ {
+ .ifnum = -1
+ }
}
}
},
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "Roland",
.product_name = "PC-300",
- .ifnum = 2,
- .type = QUIRK_MIDI_FIXED_ENDPOINT,
- .data = & (const snd_usb_midi_endpoint_info_t) {
- .out_cables = 0x0001,
- .in_cables = 0x0001
+ .ifnum = QUIRK_ANY_INTERFACE,
+ .type = QUIRK_COMPOSITE,
+ .data = (const snd_usb_audio_quirk_t[]) {
+ {
+ .ifnum = 0,
+ .type = QUIRK_IGNORE_INTERFACE
+ },
+ {
+ .ifnum = 1,
+ .type = QUIRK_IGNORE_INTERFACE
+ },
+ {
+ .ifnum = 2,
+ .type = QUIRK_MIDI_FIXED_ENDPOINT,
+ .data = & (const snd_usb_midi_endpoint_info_t) {
+ .out_cables = 0x0001,
+ .in_cables = 0x0001
+ }
+ },
+ {
+ .ifnum = -1
+ }
}
}
},
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "EDIROL",
.product_name = "UM-1",
- .ifnum = 2,
- .type = QUIRK_MIDI_FIXED_ENDPOINT,
- .data = & (const snd_usb_midi_endpoint_info_t) {
- .out_cables = 0x0001,
- .in_cables = 0x0001
+ .ifnum = QUIRK_ANY_INTERFACE,
+ .type = QUIRK_COMPOSITE,
+ .data = (const snd_usb_audio_quirk_t[]) {
+ {
+ .ifnum = 0,
+ .type = QUIRK_IGNORE_INTERFACE
+ },
+ {
+ .ifnum = 1,
+ .type = QUIRK_IGNORE_INTERFACE
+ },
+ {
+ .ifnum = 2,
+ .type = QUIRK_MIDI_FIXED_ENDPOINT,
+ .data = & (const snd_usb_midi_endpoint_info_t) {
+ .out_cables = 0x0001,
+ .in_cables = 0x0001
+ }
+ },
+ {
+ .ifnum = -1
+ }
}
}
},
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "Roland",
.product_name = "SK-500",
- .ifnum = 2,
- .type = QUIRK_MIDI_FIXED_ENDPOINT,
- .data = & (const snd_usb_midi_endpoint_info_t) {
- .out_cables = 0x0013,
- .in_cables = 0x0013
+ .ifnum = QUIRK_ANY_INTERFACE,
+ .type = QUIRK_COMPOSITE,
+ .data = (const snd_usb_audio_quirk_t[]) {
+ {
+ .ifnum = 0,
+ .type = QUIRK_IGNORE_INTERFACE
+ },
+ {
+ .ifnum = 1,
+ .type = QUIRK_IGNORE_INTERFACE
+ },
+ {
+ .ifnum = 2,
+ .type = QUIRK_MIDI_FIXED_ENDPOINT,
+ .data = & (const snd_usb_midi_endpoint_info_t) {
+ .out_cables = 0x0013,
+ .in_cables = 0x0013
+ }
+ },
+ {
+ .ifnum = -1
+ }
}
}
},
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "EDIROL",
.product_name = "SD-90",
- .ifnum = 2,
- .type = QUIRK_MIDI_FIXED_ENDPOINT,
- .data = & (const snd_usb_midi_endpoint_info_t) {
- .out_cables = 0x000f,
- .in_cables = 0x000f
+ .ifnum = QUIRK_ANY_INTERFACE,
+ .type = QUIRK_COMPOSITE,
+ .data = (const snd_usb_audio_quirk_t[]) {
+ {
+ .ifnum = 0,
+ .type = QUIRK_IGNORE_INTERFACE
+ },
+ {
+ .ifnum = 1,
+ .type = QUIRK_IGNORE_INTERFACE
+ },
+ {
+ .ifnum = 2,
+ .type = QUIRK_MIDI_FIXED_ENDPOINT,
+ .data = & (const snd_usb_midi_endpoint_info_t) {
+ .out_cables = 0x000f,
+ .in_cables = 0x000f
+ }
+ },
+ {
+ .ifnum = -1
+ }
}
}
},
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "Roland",
.product_name = "MMP-2",
- .ifnum = 2,
- .type = QUIRK_MIDI_FIXED_ENDPOINT,
- .data = & (const snd_usb_midi_endpoint_info_t) {
- .out_cables = 0x0001,
- .in_cables = 0x0001
+ .ifnum = QUIRK_ANY_INTERFACE,
+ .type = QUIRK_COMPOSITE,
+ .data = (const snd_usb_audio_quirk_t[]) {
+ {
+ .ifnum = 0,
+ .type = QUIRK_IGNORE_INTERFACE
+ },
+ {
+ .ifnum = 1,
+ .type = QUIRK_IGNORE_INTERFACE
+ },
+ {
+ .ifnum = 2,
+ .type = QUIRK_MIDI_FIXED_ENDPOINT,
+ .data = & (const snd_usb_midi_endpoint_info_t) {
+ .out_cables = 0x0001,
+ .in_cables = 0x0001
+ }
+ },
+ {
+ .ifnum = -1
+ }
}
}
},
}
},
{
+ /*
+ * This quirk is for the "Advanced Driver" mode. If off, the GS-10
+ * has ID 0x003c and is standard compliant, but has only 16-bit PCM
+ * and no MIDI.
+ */
USB_DEVICE_VENDOR_SPEC(0x0582, 0x003b),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "BOSS",
.product_name = "GS-10",
- .ifnum = 3,
- .type = QUIRK_MIDI_FIXED_ENDPOINT,
- .data = & (const snd_usb_midi_endpoint_info_t) {
- .out_cables = 0x0003,
- .in_cables = 0x0003
+ .ifnum = QUIRK_ANY_INTERFACE,
+ .type = QUIRK_COMPOSITE,
+ .data = & (const snd_usb_audio_quirk_t[]) {
+ {
+ .ifnum = 1,
+ .type = QUIRK_AUDIO_STANDARD_INTERFACE
+ },
+ {
+ .ifnum = 2,
+ .type = QUIRK_AUDIO_STANDARD_INTERFACE
+ },
+ {
+ .ifnum = 3,
+ .type = QUIRK_MIDI_STANDARD_INTERFACE
+ },
+ {
+ .ifnum = -1
+ }
}
}
},
snd_card_disconnect((snd_card_t*)ptr);
/* release the midi resources */
list_for_each(p, &usX2Y->chip.midi_list) {
- snd_usbmidi_disconnect(p, &snd_usX2Y_usb_driver);
+ snd_usbmidi_disconnect(p);
}
if (usX2Y->us428ctls_sharedmem)
wake_up(&usX2Y->us428ctls_wait_queue_head);
for (i = 0; i < NRURBS; i++)
usX2Y_urb_release(subs->urb + i, subs != subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK]);
- if (subs->tmpbuf) {
- kfree(subs->tmpbuf);
- subs->tmpbuf = NULL;
- }
+ kfree(subs->tmpbuf);
+ subs->tmpbuf = NULL;
}
/*
* initialize a substream's urbs