diff options
392 files changed, 27106 insertions, 5427 deletions
@@ -2380,9 +2380,10 @@ E: tmolina@cablespeed.com | |||
2380 | D: bug fixes, documentation, minor hackery | 2380 | D: bug fixes, documentation, minor hackery |
2381 | 2381 | ||
2382 | N: James Morris | 2382 | N: James Morris |
2383 | E: jmorris@intercode.com.au | 2383 | E: jmorris@redhat.com |
2384 | W: http://www.intercode.com.au/jmorris/ | 2384 | W: http://www.intercode.com.au/jmorris/ |
2385 | D: Netfilter, Linux Security Modules (LSM). | 2385 | D: Netfilter, Linux Security Modules (LSM), SELinux, IPSec, |
2386 | D: Crypto API, general networking, miscellaneous. | ||
2386 | S: PO Box 707 | 2387 | S: PO Box 707 |
2387 | S: Spit Junction NSW 2088 | 2388 | S: Spit Junction NSW 2088 |
2388 | S: Australia | 2389 | S: Australia |
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index b9eb209318ab..26414bc87c65 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt | |||
@@ -83,3 +83,13 @@ Why: Deprecated in favour of the new ioctl-based rawiso interface, which is | |||
83 | more efficient. You should really be using libraw1394 for raw1394 | 83 | more efficient. You should really be using libraw1394 for raw1394 |
84 | access anyway. | 84 | access anyway. |
85 | Who: Jody McIntyre <scjody@steamballoon.com> | 85 | Who: Jody McIntyre <scjody@steamballoon.com> |
86 | |||
87 | --------------------------- | ||
88 | |||
89 | What: i2c sysfs name change: in1_ref, vid deprecated in favour of cpu0_vid | ||
90 | When: November 2005 | ||
91 | Files: drivers/i2c/chips/adm1025.c, drivers/i2c/chips/adm1026.c | ||
92 | Why: Match the other drivers' name for the same function, duplicate names | ||
93 | will be available until removal of old names. | ||
94 | Who: Grant Coady <gcoady@gmail.com> | ||
95 | |||
diff --git a/Documentation/i2c/busses/i2c-sis69x b/Documentation/i2c/busses/i2c-sis69x index 5be48769f65b..b88953dfd580 100644 --- a/Documentation/i2c/busses/i2c-sis69x +++ b/Documentation/i2c/busses/i2c-sis69x | |||
@@ -42,7 +42,7 @@ I suspect that this driver could be made to work for the following SiS | |||
42 | chipsets as well: 635, and 635T. If anyone owns a board with those chips | 42 | chipsets as well: 635, and 635T. If anyone owns a board with those chips |
43 | AND is willing to risk crashing & burning an otherwise well-behaved kernel | 43 | AND is willing to risk crashing & burning an otherwise well-behaved kernel |
44 | in the name of progress... please contact me at <mhoffman@lightlink.com> or | 44 | in the name of progress... please contact me at <mhoffman@lightlink.com> or |
45 | via the project's mailing list: <sensors@stimpy.netroedge.com>. Please | 45 | via the project's mailing list: <lm-sensors@lm-sensors.org>. Please |
46 | send bug reports and/or success stories as well. | 46 | send bug reports and/or success stories as well. |
47 | 47 | ||
48 | 48 | ||
diff --git a/Documentation/i2c/chips/adm1021 b/Documentation/i2c/chips/adm1021 new file mode 100644 index 000000000000..03d02bfb3df1 --- /dev/null +++ b/Documentation/i2c/chips/adm1021 | |||
@@ -0,0 +1,111 @@ | |||
1 | Kernel driver adm1021 | ||
2 | ===================== | ||
3 | |||
4 | Supported chips: | ||
5 | * Analog Devices ADM1021 | ||
6 | Prefix: 'adm1021' | ||
7 | Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e | ||
8 | Datasheet: Publicly available at the Analog Devices website | ||
9 | * Analog Devices ADM1021A/ADM1023 | ||
10 | Prefix: 'adm1023' | ||
11 | Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e | ||
12 | Datasheet: Publicly available at the Analog Devices website | ||
13 | * Genesys Logic GL523SM | ||
14 | Prefix: 'gl523sm' | ||
15 | Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e | ||
16 | Datasheet: | ||
17 | * Intel Xeon Processor | ||
18 | Prefix: - any other - may require 'force_adm1021' parameter | ||
19 | Addresses scanned: none | ||
20 | Datasheet: Publicly available at Intel website | ||
21 | * Maxim MAX1617 | ||
22 | Prefix: 'max1617' | ||
23 | Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e | ||
24 | Datasheet: Publicly available at the Maxim website | ||
25 | * Maxim MAX1617A | ||
26 | Prefix: 'max1617a' | ||
27 | Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e | ||
28 | Datasheet: Publicly available at the Maxim website | ||
29 | * National Semiconductor LM84 | ||
30 | Prefix: 'lm84' | ||
31 | Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e | ||
32 | Datasheet: Publicly available at the National Semiconductor website | ||
33 | * Philips NE1617 | ||
34 | Prefix: 'max1617' (probably detected as a max1617) | ||
35 | Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e | ||
36 | Datasheet: Publicly available at the Philips website | ||
37 | * Philips NE1617A | ||
38 | Prefix: 'max1617' (probably detected as a max1617) | ||
39 | Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e | ||
40 | Datasheet: Publicly available at the Philips website | ||
41 | * TI THMC10 | ||
42 | Prefix: 'thmc10' | ||
43 | Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e | ||
44 | Datasheet: Publicly available at the TI website | ||
45 | * Onsemi MC1066 | ||
46 | Prefix: 'mc1066' | ||
47 | Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e | ||
48 | Datasheet: Publicly available at the Onsemi website | ||
49 | |||
50 | |||
51 | Authors: | ||
52 | Frodo Looijaard <frodol@dds.nl>, | ||
53 | Philip Edelbrock <phil@netroedge.com> | ||
54 | |||
55 | Module Parameters | ||
56 | ----------------- | ||
57 | |||
58 | * read_only: int | ||
59 | Don't set any values, read only mode | ||
60 | |||
61 | |||
62 | Description | ||
63 | ----------- | ||
64 | |||
65 | The chips supported by this driver are very similar. The Maxim MAX1617 is | ||
66 | the oldest; it has the problem that it is not very well detectable. The | ||
67 | MAX1617A solves that. The ADM1021 is a straight clone of the MAX1617A. | ||
68 | Ditto for the THMC10. From here on, we will refer to all these chips as | ||
69 | ADM1021-clones. | ||
70 | |||
71 | The ADM1021 and MAX1617A reports a die code, which is a sort of revision | ||
72 | code. This can help us pinpoint problems; it is not very useful | ||
73 | otherwise. | ||
74 | |||
75 | ADM1021-clones implement two temperature sensors. One of them is internal, | ||
76 | and measures the temperature of the chip itself; the other is external and | ||
77 | is realised in the form of a transistor-like device. A special alarm | ||
78 | indicates whether the remote sensor is connected. | ||
79 | |||
80 | Each sensor has its own low and high limits. When they are crossed, the | ||
81 | corresponding alarm is set and remains on as long as the temperature stays | ||
82 | out of range. Temperatures are measured in degrees Celsius. Measurements | ||
83 | are possible between -65 and +127 degrees, with a resolution of one degree. | ||
84 | |||
85 | If an alarm triggers, it will remain triggered until the hardware register | ||
86 | is read at least once. This means that the cause for the alarm may already | ||
87 | have disappeared! | ||
88 | |||
89 | This driver only updates its values each 1.5 seconds; reading it more often | ||
90 | will do no harm, but will return 'old' values. It is possible to make | ||
91 | ADM1021-clones do faster measurements, but there is really no good reason | ||
92 | for that. | ||
93 | |||
94 | Xeon support | ||
95 | ------------ | ||
96 | |||
97 | Some Xeon processors have real max1617, adm1021, or compatible chips | ||
98 | within them, with two temperature sensors. | ||
99 | |||
100 | Other Xeons have chips with only one sensor. | ||
101 | |||
102 | If you have a Xeon, and the adm1021 module loads, and both temperatures | ||
103 | appear valid, then things are good. | ||
104 | |||
105 | If the adm1021 module doesn't load, you should try this: | ||
106 | modprobe adm1021 force_adm1021=BUS,ADDRESS | ||
107 | ADDRESS can only be 0x18, 0x1a, 0x29, 0x2b, 0x4c, or 0x4e. | ||
108 | |||
109 | If you have dual Xeons you may have appear to have two separate | ||
110 | adm1021-compatible chips, or two single-temperature sensors, at distinct | ||
111 | addresses. | ||
diff --git a/Documentation/i2c/chips/adm1025 b/Documentation/i2c/chips/adm1025 new file mode 100644 index 000000000000..39d2b781b5d6 --- /dev/null +++ b/Documentation/i2c/chips/adm1025 | |||
@@ -0,0 +1,51 @@ | |||
1 | Kernel driver adm1025 | ||
2 | ===================== | ||
3 | |||
4 | Supported chips: | ||
5 | * Analog Devices ADM1025, ADM1025A | ||
6 | Prefix: 'adm1025' | ||
7 | Addresses scanned: I2C 0x2c - 0x2e | ||
8 | Datasheet: Publicly available at the Analog Devices website | ||
9 | * Philips NE1619 | ||
10 | Prefix: 'ne1619' | ||
11 | Addresses scanned: I2C 0x2c - 0x2d | ||
12 | Datasheet: Publicly available at the Philips website | ||
13 | |||
14 | The NE1619 presents some differences with the original ADM1025: | ||
15 | * Only two possible addresses (0x2c - 0x2d). | ||
16 | * No temperature offset register, but we don't use it anyway. | ||
17 | * No INT mode for pin 16. We don't play with it anyway. | ||
18 | |||
19 | Authors: | ||
20 | Chen-Yuan Wu <gwu@esoft.com>, | ||
21 | Jean Delvare <khali@linux-fr.org> | ||
22 | |||
23 | Description | ||
24 | ----------- | ||
25 | |||
26 | (This is from Analog Devices.) The ADM1025 is a complete system hardware | ||
27 | monitor for microprocessor-based systems, providing measurement and limit | ||
28 | comparison of various system parameters. Five voltage measurement inputs | ||
29 | are provided, for monitoring +2.5V, +3.3V, +5V and +12V power supplies and | ||
30 | the processor core voltage. The ADM1025 can monitor a sixth power-supply | ||
31 | voltage by measuring its own VCC. One input (two pins) is dedicated to a | ||
32 | remote temperature-sensing diode and an on-chip temperature sensor allows | ||
33 | ambient temperature to be monitored. | ||
34 | |||
35 | One specificity of this chip is that the pin 11 can be hardwired in two | ||
36 | different manners. It can act as the +12V power-supply voltage analog | ||
37 | input, or as the a fifth digital entry for the VID reading (bit 4). It's | ||
38 | kind of strange since both are useful, and the reason for designing the | ||
39 | chip that way is obscure at least to me. The bit 5 of the configuration | ||
40 | register can be used to define how the chip is hardwired. Please note that | ||
41 | it is not a choice you have to make as the user. The choice was already | ||
42 | made by your motherboard's maker. If the configuration bit isn't set | ||
43 | properly, you'll have a wrong +12V reading or a wrong VID reading. The way | ||
44 | the driver handles that is to preserve this bit through the initialization | ||
45 | process, assuming that the BIOS set it up properly beforehand. If it turns | ||
46 | out not to be true in some cases, we'll provide a module parameter to force | ||
47 | modes. | ||
48 | |||
49 | This driver also supports the ADM1025A, which differs from the ADM1025 | ||
50 | only in that it has "open-drain VID inputs while the ADM1025 has on-chip | ||
51 | 100k pull-ups on the VID inputs". It doesn't make any difference for us. | ||
diff --git a/Documentation/i2c/chips/adm1026 b/Documentation/i2c/chips/adm1026 new file mode 100644 index 000000000000..473c689d7924 --- /dev/null +++ b/Documentation/i2c/chips/adm1026 | |||
@@ -0,0 +1,93 @@ | |||
1 | Kernel driver adm1026 | ||
2 | ===================== | ||
3 | |||
4 | Supported chips: | ||
5 | * Analog Devices ADM1026 | ||
6 | Prefix: 'adm1026' | ||
7 | Addresses scanned: I2C 0x2c, 0x2d, 0x2e | ||
8 | Datasheet: Publicly available at the Analog Devices website | ||
9 | http://www.analog.com/en/prod/0,,766_825_ADM1026,00.html | ||
10 | |||
11 | Authors: | ||
12 | Philip Pokorny <ppokorny@penguincomputing.com> for Penguin Computing | ||
13 | Justin Thiessen <jthiessen@penguincomputing.com> | ||
14 | |||
15 | Module Parameters | ||
16 | ----------------- | ||
17 | |||
18 | * gpio_input: int array (min = 1, max = 17) | ||
19 | List of GPIO pins (0-16) to program as inputs | ||
20 | * gpio_output: int array (min = 1, max = 17) | ||
21 | List of GPIO pins (0-16) to program as outputs | ||
22 | * gpio_inverted: int array (min = 1, max = 17) | ||
23 | List of GPIO pins (0-16) to program as inverted | ||
24 | * gpio_normal: int array (min = 1, max = 17) | ||
25 | List of GPIO pins (0-16) to program as normal/non-inverted | ||
26 | * gpio_fan: int array (min = 1, max = 8) | ||
27 | List of GPIO pins (0-7) to program as fan tachs | ||
28 | |||
29 | |||
30 | Description | ||
31 | ----------- | ||
32 | |||
33 | This driver implements support for the Analog Devices ADM1026. Analog | ||
34 | Devices calls it a "complete thermal system management controller." | ||
35 | |||
36 | The ADM1026 implements three (3) temperature sensors, 17 voltage sensors, | ||
37 | 16 general purpose digital I/O lines, eight (8) fan speed sensors (8-bit), | ||
38 | an analog output and a PWM output along with limit, alarm and mask bits for | ||
39 | all of the above. There is even 8k bytes of EEPROM memory on chip. | ||
40 | |||
41 | Temperatures are measured in degrees Celsius. There are two external | ||
42 | sensor inputs and one internal sensor. Each sensor has a high and low | ||
43 | limit. If the limit is exceeded, an interrupt (#SMBALERT) can be | ||
44 | generated. The interrupts can be masked. In addition, there are over-temp | ||
45 | limits for each sensor. If this limit is exceeded, the #THERM output will | ||
46 | be asserted. The current temperature and limits have a resolution of 1 | ||
47 | degree. | ||
48 | |||
49 | Fan rotation speeds are reported in RPM (rotations per minute) but measured | ||
50 | in counts of a 22.5kHz internal clock. Each fan has a high limit which | ||
51 | corresponds to a minimum fan speed. If the limit is exceeded, an interrupt | ||
52 | can be generated. Each fan can be programmed to divide the reference clock | ||
53 | by 1, 2, 4 or 8. Not all RPM values can accurately be represented, so some | ||
54 | rounding is done. With a divider of 8, the slowest measurable speed of a | ||
55 | two pulse per revolution fan is 661 RPM. | ||
56 | |||
57 | There are 17 voltage sensors. An alarm is triggered if the voltage has | ||
58 | crossed a programmable minimum or maximum limit. Note that minimum in this | ||
59 | case always means 'closest to zero'; this is important for negative voltage | ||
60 | measurements. Several inputs have integrated attenuators so they can measure | ||
61 | higher voltages directly. 3.3V, 5V, 12V, -12V and battery voltage all have | ||
62 | dedicated inputs. There are several inputs scaled to 0-3V full-scale range | ||
63 | for SCSI terminator power. The remaining inputs are not scaled and have | ||
64 | a 0-2.5V full-scale range. A 2.5V or 1.82V reference voltage is provided | ||
65 | for negative voltage measurements. | ||
66 | |||
67 | If an alarm triggers, it will remain triggered until the hardware register | ||
68 | is read at least once. This means that the cause for the alarm may already | ||
69 | have disappeared! Note that in the current implementation, all hardware | ||
70 | registers are read whenever any data is read (unless it is less than 2.0 | ||
71 | seconds since the last update). This means that you can easily miss | ||
72 | once-only alarms. | ||
73 | |||
74 | The ADM1026 measures continuously. Analog inputs are measured about 4 | ||
75 | times a second. Fan speed measurement time depends on fan speed and | ||
76 | divisor. It can take as long as 1.5 seconds to measure all fan speeds. | ||
77 | |||
78 | The ADM1026 has the ability to automatically control fan speed based on the | ||
79 | temperature sensor inputs. Both the PWM output and the DAC output can be | ||
80 | used to control fan speed. Usually only one of these two outputs will be | ||
81 | used. Write the minimum PWM or DAC value to the appropriate control | ||
82 | register. Then set the low temperature limit in the tmin values for each | ||
83 | temperature sensor. The range of control is fixed at 20 °C, and the | ||
84 | largest difference between current and tmin of the temperature sensors sets | ||
85 | the control output. See the datasheet for several example circuits for | ||
86 | controlling fan speed with the PWM and DAC outputs. The fan speed sensors | ||
87 | do not have PWM compensation, so it is probably best to control the fan | ||
88 | voltage from the power lead rather than on the ground lead. | ||
89 | |||
90 | The datasheet shows an example application with VID signals attached to | ||
91 | GPIO lines. Unfortunately, the chip may not be connected to the VID lines | ||
92 | in this way. The driver assumes that the chips *is* connected this way to | ||
93 | get a VID voltage. | ||
diff --git a/Documentation/i2c/chips/adm1031 b/Documentation/i2c/chips/adm1031 new file mode 100644 index 000000000000..130a38382b98 --- /dev/null +++ b/Documentation/i2c/chips/adm1031 | |||
@@ -0,0 +1,35 @@ | |||
1 | Kernel driver adm1031 | ||
2 | ===================== | ||
3 | |||
4 | Supported chips: | ||
5 | * Analog Devices ADM1030 | ||
6 | Prefix: 'adm1030' | ||
7 | Addresses scanned: I2C 0x2c to 0x2e | ||
8 | Datasheet: Publicly available at the Analog Devices website | ||
9 | http://products.analog.com/products/info.asp?product=ADM1030 | ||
10 | |||
11 | * Analog Devices ADM1031 | ||
12 | Prefix: 'adm1031' | ||
13 | Addresses scanned: I2C 0x2c to 0x2e | ||
14 | Datasheet: Publicly available at the Analog Devices website | ||
15 | http://products.analog.com/products/info.asp?product=ADM1031 | ||
16 | |||
17 | Authors: | ||
18 | Alexandre d'Alton <alex@alexdalton.org> | ||
19 | Jean Delvare <khali@linux-fr.org> | ||
20 | |||
21 | Description | ||
22 | ----------- | ||
23 | |||
24 | The ADM1030 and ADM1031 are digital temperature sensors and fan controllers. | ||
25 | They sense their own temperature as well as the temperature of up to one | ||
26 | (ADM1030) or two (ADM1031) external diodes. | ||
27 | |||
28 | All temperature values are given in degrees Celsius. Resolution is 0.5 | ||
29 | degree for the local temperature, 0.125 degree for the remote temperatures. | ||
30 | |||
31 | Each temperature channel has its own high and low limits, plus a critical | ||
32 | limit. | ||
33 | |||
34 | The ADM1030 monitors a single fan speed, while the ADM1031 monitors up to | ||
35 | two. Each fan channel has its own low speed limit. | ||
diff --git a/Documentation/i2c/chips/adm9240 b/Documentation/i2c/chips/adm9240 new file mode 100644 index 000000000000..35f618f32896 --- /dev/null +++ b/Documentation/i2c/chips/adm9240 | |||
@@ -0,0 +1,177 @@ | |||
1 | Kernel driver adm9240 | ||
2 | ===================== | ||
3 | |||
4 | Supported chips: | ||
5 | * Analog Devices ADM9240 | ||
6 | Prefix: 'adm9240' | ||
7 | Addresses scanned: I2C 0x2c - 0x2f | ||
8 | Datasheet: Publicly available at the Analog Devices website | ||
9 | http://www.analog.com/UploadedFiles/Data_Sheets/79857778ADM9240_0.pdf | ||
10 | |||
11 | * Dallas Semiconductor DS1780 | ||
12 | Prefix: 'ds1780' | ||
13 | Addresses scanned: I2C 0x2c - 0x2f | ||
14 | Datasheet: Publicly available at the Dallas Semiconductor (Maxim) website | ||
15 | http://pdfserv.maxim-ic.com/en/ds/DS1780.pdf | ||
16 | |||
17 | * National Semiconductor LM81 | ||
18 | Prefix: 'lm81' | ||
19 | Addresses scanned: I2C 0x2c - 0x2f | ||
20 | Datasheet: Publicly available at the National Semiconductor website | ||
21 | http://www.national.com/ds.cgi/LM/LM81.pdf | ||
22 | |||
23 | Authors: | ||
24 | Frodo Looijaard <frodol@dds.nl>, | ||
25 | Philip Edelbrock <phil@netroedge.com>, | ||
26 | Michiel Rook <michiel@grendelproject.nl>, | ||
27 | Grant Coady <gcoady@gmail.com> with guidance | ||
28 | from Jean Delvare <khali@linux-fr.org> | ||
29 | |||
30 | Interface | ||
31 | --------- | ||
32 | The I2C addresses listed above assume BIOS has not changed the | ||
33 | chip MSB 5-bit address. Each chip reports a unique manufacturer | ||
34 | identification code as well as the chip revision/stepping level. | ||
35 | |||
36 | Description | ||
37 | ----------- | ||
38 | [From ADM9240] The ADM9240 is a complete system hardware monitor for | ||
39 | microprocessor-based systems, providing measurement and limit comparison | ||
40 | of up to four power supplies and two processor core voltages, plus | ||
41 | temperature, two fan speeds and chassis intrusion. Measured values can | ||
42 | be read out via an I2C-compatible serial System Management Bus, and values | ||
43 | for limit comparisons can be programmed in over the same serial bus. The | ||
44 | high speed successive approximation ADC allows frequent sampling of all | ||
45 | analog channels to ensure a fast interrupt response to any out-of-limit | ||
46 | measurement. | ||
47 | |||
48 | The ADM9240, DS1780 and LM81 are register compatible, the following | ||
49 | details are common to the three chips. Chip differences are described | ||
50 | after this section. | ||
51 | |||
52 | |||
53 | Measurements | ||
54 | ------------ | ||
55 | The measurement cycle | ||
56 | |||
57 | The adm9240 driver will take a measurement reading no faster than once | ||
58 | each two seconds. User-space may read sysfs interface faster than the | ||
59 | measurement update rate and will receive cached data from the most | ||
60 | recent measurement. | ||
61 | |||
62 | ADM9240 has a very fast 320us temperature and voltage measurement cycle | ||
63 | with independent fan speed measurement cycles counting alternating rising | ||
64 | edges of the fan tacho inputs. | ||
65 | |||
66 | DS1780 measurement cycle is about once per second including fan speed. | ||
67 | |||
68 | LM81 measurement cycle is about once per 400ms including fan speed. | ||
69 | The LM81 12-bit extended temperature measurement mode is not supported. | ||
70 | |||
71 | Temperature | ||
72 | ----------- | ||
73 | On chip temperature is reported as degrees Celsius as 9-bit signed data | ||
74 | with resolution of 0.5 degrees Celsius. High and low temperature limits | ||
75 | are 8-bit signed data with resolution of one degree Celsius. | ||
76 | |||
77 | Temperature alarm is asserted once the temperature exceeds the high limit, | ||
78 | and is cleared when the temperature falls below the temp1_max_hyst value. | ||
79 | |||
80 | Fan Speed | ||
81 | --------- | ||
82 | Two fan tacho inputs are provided, the ADM9240 gates an internal 22.5kHz | ||
83 | clock via a divider to an 8-bit counter. Fan speed (rpm) is calculated by: | ||
84 | |||
85 | rpm = (22500 * 60) / (count * divider) | ||
86 | |||
87 | Automatic fan clock divider | ||
88 | |||
89 | * User sets 0 to fan_min limit | ||
90 | - low speed alarm is disabled | ||
91 | - fan clock divider not changed | ||
92 | - auto fan clock adjuster enabled for valid fan speed reading | ||
93 | |||
94 | * User sets fan_min limit too low | ||
95 | - low speed alarm is enabled | ||
96 | - fan clock divider set to max | ||
97 | - fan_min set to register value 254 which corresponds | ||
98 | to 664 rpm on adm9240 | ||
99 | - low speed alarm will be asserted if fan speed is | ||
100 | less than minimum measurable speed | ||
101 | - auto fan clock adjuster disabled | ||
102 | |||
103 | * User sets reasonable fan speed | ||
104 | - low speed alarm is enabled | ||
105 | - fan clock divider set to suit fan_min | ||
106 | - auto fan clock adjuster enabled: adjusts fan_min | ||
107 | |||
108 | * User sets unreasonably high low fan speed limit | ||
109 | - resolution of the low speed limit may be reduced | ||
110 | - alarm will be asserted | ||
111 | - auto fan clock adjuster enabled: adjusts fan_min | ||
112 | |||
113 | * fan speed may be displayed as zero until the auto fan clock divider | ||
114 | adjuster brings fan speed clock divider back into chip measurement | ||
115 | range, this will occur within a few measurement cycles. | ||
116 | |||
117 | Analog Output | ||
118 | ------------- | ||
119 | An analog output provides a 0 to 1.25 volt signal intended for an external | ||
120 | fan speed amplifier circuit. The analog output is set to maximum value on | ||
121 | power up or reset. This doesn't do much on the test Intel SE440BX-2. | ||
122 | |||
123 | Voltage Monitor | ||
124 | |||
125 | Voltage (IN) measurement is internally scaled: | ||
126 | |||
127 | nr label nominal maximum resolution | ||
128 | mV mV mV | ||
129 | 0 +2.5V 2500 3320 13.0 | ||
130 | 1 Vccp1 2700 3600 14.1 | ||
131 | 2 +3.3V 3300 4380 17.2 | ||
132 | 3 +5V 5000 6640 26.0 | ||
133 | 4 +12V 12000 15940 62.5 | ||
134 | 5 Vccp2 2700 3600 14.1 | ||
135 | |||
136 | The reading is an unsigned 8-bit value, nominal voltage measurement is | ||
137 | represented by a reading of 192, being 3/4 of the measurement range. | ||
138 | |||
139 | An alarm is asserted for any voltage going below or above the set limits. | ||
140 | |||
141 | The driver reports and accepts voltage limits scaled to the above table. | ||
142 | |||
143 | VID Monitor | ||
144 | ----------- | ||
145 | The chip has five inputs to read the 5-bit VID and reports the mV value | ||
146 | based on detected CPU type. | ||
147 | |||
148 | Chassis Intrusion | ||
149 | ----------------- | ||
150 | An alarm is asserted when the CI pin goes active high. The ADM9240 | ||
151 | Datasheet has an example of an external temperature sensor driving | ||
152 | this pin. On an Intel SE440BX-2 the Chassis Intrusion header is | ||
153 | connected to a normally open switch. | ||
154 | |||
155 | The ADM9240 provides an internal open drain on this line, and may output | ||
156 | a 20 ms active low pulse to reset an external Chassis Intrusion latch. | ||
157 | |||
158 | Clear the CI latch by writing value 1 to the sysfs chassis_clear file. | ||
159 | |||
160 | Alarm flags reported as 16-bit word | ||
161 | |||
162 | bit label comment | ||
163 | --- ------------- -------------------------- | ||
164 | 0 +2.5 V_Error high or low limit exceeded | ||
165 | 1 VCCP_Error high or low limit exceeded | ||
166 | 2 +3.3 V_Error high or low limit exceeded | ||
167 | 3 +5 V_Error high or low limit exceeded | ||
168 | 4 Temp_Error temperature error | ||
169 | 6 FAN1_Error fan low limit exceeded | ||
170 | 7 FAN2_Error fan low limit exceeded | ||
171 | 8 +12 V_Error high or low limit exceeded | ||
172 | 9 VCCP2_Error high or low limit exceeded | ||
173 | 12 Chassis_Error CI pin went high | ||
174 | |||
175 | Remaining bits are reserved and thus undefined. It is important to note | ||
176 | that alarm bits may be cleared on read, user-space may latch alarms and | ||
177 | provide the end-user with a method to clear alarm memory. | ||
diff --git a/Documentation/i2c/chips/asb100 b/Documentation/i2c/chips/asb100 new file mode 100644 index 000000000000..ab7365e139be --- /dev/null +++ b/Documentation/i2c/chips/asb100 | |||
@@ -0,0 +1,72 @@ | |||
1 | Kernel driver asb100 | ||
2 | ==================== | ||
3 | |||
4 | Supported Chips: | ||
5 | * Asus ASB100 and ASB100-A "Bach" | ||
6 | Prefix: 'asb100' | ||
7 | Addresses scanned: I2C 0x2d | ||
8 | Datasheet: none released | ||
9 | |||
10 | Author: Mark M. Hoffman <mhoffman@lightlink.com> | ||
11 | |||
12 | Description | ||
13 | ----------- | ||
14 | |||
15 | This driver implements support for the Asus ASB100 and ASB100-A "Bach". | ||
16 | These are custom ASICs available only on Asus mainboards. Asus refuses to | ||
17 | supply a datasheet for these chips. Thanks go to many people who helped | ||
18 | investigate their hardware, including: | ||
19 | |||
20 | Vitaly V. Bursov | ||
21 | Alexander van Kaam (author of MBM for Windows) | ||
22 | Bertrik Sikken | ||
23 | |||
24 | The ASB100 implements seven voltage sensors, three fan rotation speed | ||
25 | sensors, four temperature sensors, VID lines and alarms. In addition to | ||
26 | these, the ASB100-A also implements a single PWM controller for fans 2 and | ||
27 | 3 (i.e. one setting controls both.) If you have a plain ASB100, the PWM | ||
28 | controller will simply not work (or maybe it will for you... it doesn't for | ||
29 | me). | ||
30 | |||
31 | Temperatures are measured and reported in degrees Celsius. | ||
32 | |||
33 | Fan speeds are reported in RPM (rotations per minute). An alarm is | ||
34 | triggered if the rotation speed has dropped below a programmable limit. | ||
35 | |||
36 | Voltage sensors (also known as IN sensors) report values in volts. | ||
37 | |||
38 | The VID lines encode the core voltage value: the voltage level your | ||
39 | processor should work with. This is hardcoded by the mainboard and/or | ||
40 | processor itself. It is a value in volts. | ||
41 | |||
42 | Alarms: (TODO question marks indicate may or may not work) | ||
43 | |||
44 | 0x0001 => in0 (?) | ||
45 | 0x0002 => in1 (?) | ||
46 | 0x0004 => in2 | ||
47 | 0x0008 => in3 | ||
48 | 0x0010 => temp1 (1) | ||
49 | 0x0020 => temp2 | ||
50 | 0x0040 => fan1 | ||
51 | 0x0080 => fan2 | ||
52 | 0x0100 => in4 | ||
53 | 0x0200 => in5 (?) (2) | ||
54 | 0x0400 => in6 (?) (2) | ||
55 | 0x0800 => fan3 | ||
56 | 0x1000 => chassis switch | ||
57 | 0x2000 => temp3 | ||
58 | |||
59 | Alarm Notes: | ||
60 | |||
61 | (1) This alarm will only trigger if the hysteresis value is 127C. | ||
62 | I.e. it behaves the same as w83781d. | ||
63 | |||
64 | (2) The min and max registers for these values appear to | ||
65 | be read-only or otherwise stuck at 0x00. | ||
66 | |||
67 | TODO: | ||
68 | * Experiment with fan divisors > 8. | ||
69 | * Experiment with temp. sensor types. | ||
70 | * Are there really 13 voltage inputs? Probably not... | ||
71 | * Cleanups, no doubt... | ||
72 | |||
diff --git a/Documentation/i2c/chips/ds1621 b/Documentation/i2c/chips/ds1621 new file mode 100644 index 000000000000..1fee6f1e6bc5 --- /dev/null +++ b/Documentation/i2c/chips/ds1621 | |||
@@ -0,0 +1,108 @@ | |||
1 | Kernel driver ds1621 | ||
2 | ==================== | ||
3 | |||
4 | Supported chips: | ||
5 | * Dallas Semiconductor DS1621 | ||
6 | Prefix: 'ds1621' | ||
7 | Addresses scanned: I2C 0x48 - 0x4f | ||
8 | Datasheet: Publicly available at the Dallas Semiconductor website | ||
9 | http://www.dalsemi.com/ | ||
10 | * Dallas Semiconductor DS1625 | ||
11 | Prefix: 'ds1621' | ||
12 | Addresses scanned: I2C 0x48 - 0x4f | ||
13 | Datasheet: Publicly available at the Dallas Semiconductor website | ||
14 | http://www.dalsemi.com/ | ||
15 | |||
16 | Authors: | ||
17 | Christian W. Zuckschwerdt <zany@triq.net> | ||
18 | valuable contributions by Jan M. Sendler <sendler@sendler.de> | ||
19 | ported to 2.6 by Aurelien Jarno <aurelien@aurel32.net> | ||
20 | with the help of Jean Delvare <khali@linux-fr.org> | ||
21 | |||
22 | Module Parameters | ||
23 | ------------------ | ||
24 | |||
25 | * polarity int | ||
26 | Output's polarity: 0 = active high, 1 = active low | ||
27 | |||
28 | Description | ||
29 | ----------- | ||
30 | |||
31 | The DS1621 is a (one instance) digital thermometer and thermostat. It has | ||
32 | both high and low temperature limits which can be user defined (i.e. | ||
33 | programmed into non-volatile on-chip registers). Temperature range is -55 | ||
34 | degree Celsius to +125 in 0.5 increments. You may convert this into a | ||
35 | Fahrenheit range of -67 to +257 degrees with 0.9 steps. If polarity | ||
36 | parameter is not provided, original value is used. | ||
37 | |||
38 | As for the thermostat, behavior can also be programmed using the polarity | ||
39 | toggle. On the one hand ("heater"), the thermostat output of the chip, | ||
40 | Tout, will trigger when the low limit temperature is met or underrun and | ||
41 | stays high until the high limit is met or exceeded. On the other hand | ||
42 | ("cooler"), vice versa. That way "heater" equals "active low", whereas | ||
43 | "conditioner" equals "active high". Please note that the DS1621 data sheet | ||
44 | is somewhat misleading in this point since setting the polarity bit does | ||
45 | not simply invert Tout. | ||
46 | |||
47 | A second thing is that, during extensive testing, Tout showed a tolerance | ||
48 | of up to +/- 0.5 degrees even when compared against precise temperature | ||
49 | readings. Be sure to have a high vs. low temperature limit gap of al least | ||
50 | 1.0 degree Celsius to avoid Tout "bouncing", though! | ||
51 | |||
52 | As for alarms, you can read the alarm status of the DS1621 via the 'alarms' | ||
53 | /sys file interface. The result consists mainly of bit 6 and 5 of the | ||
54 | configuration register of the chip; bit 6 (0x40 or 64) is the high alarm | ||
55 | bit and bit 5 (0x20 or 32) the low one. These bits are set when the high or | ||
56 | low limits are met or exceeded and are reset by the module as soon as the | ||
57 | respective temperature ranges are left. | ||
58 | |||
59 | The alarm registers are in no way suitable to find out about the actual | ||
60 | status of Tout. They will only tell you about its history, whether or not | ||
61 | any of the limits have ever been met or exceeded since last power-up or | ||
62 | reset. Be aware: When testing, it showed that the status of Tout can change | ||
63 | with neither of the alarms set. | ||
64 | |||
65 | Temperature conversion of the DS1621 takes up to 1000ms; internal access to | ||
66 | non-volatile registers may last for 10ms or below. | ||
67 | |||
68 | High Accuracy Temperature Reading | ||
69 | --------------------------------- | ||
70 | |||
71 | As said before, the temperature issued via the 9-bit i2c-bus data is | ||
72 | somewhat arbitrary. Internally, the temperature conversion is of a | ||
73 | different kind that is explained (not so...) well in the DS1621 data sheet. | ||
74 | To cut the long story short: Inside the DS1621 there are two oscillators, | ||
75 | both of them biassed by a temperature coefficient. | ||
76 | |||
77 | Higher resolution of the temperature reading can be achieved using the | ||
78 | internal projection, which means taking account of REG_COUNT and REG_SLOPE | ||
79 | (the driver manages them): | ||
80 | |||
81 | Taken from Dallas Semiconductors App Note 068: 'Increasing Temperature | ||
82 | Resolution on the DS1620' and App Note 105: 'High Resolution Temperature | ||
83 | Measurement with Dallas Direct-to-Digital Temperature Sensors' | ||
84 | |||
85 | - Read the 9-bit temperature and strip the LSB (Truncate the .5 degs) | ||
86 | - The resulting value is TEMP_READ. | ||
87 | - Then, read REG_COUNT. | ||
88 | - And then, REG_SLOPE. | ||
89 | |||
90 | TEMP = TEMP_READ - 0.25 + ((REG_SLOPE - REG_COUNT) / REG_SLOPE) | ||
91 | |||
92 | Note that this is what the DONE bit in the DS1621 configuration register is | ||
93 | good for: Internally, one temperature conversion takes up to 1000ms. Before | ||
94 | that conversion is complete you will not be able to read valid things out | ||
95 | of REG_COUNT and REG_SLOPE. The DONE bit, as you may have guessed by now, | ||
96 | tells you whether the conversion is complete ("done", in plain English) and | ||
97 | thus, whether the values you read are good or not. | ||
98 | |||
99 | The DS1621 has two modes of operation: "Continuous" conversion, which can | ||
100 | be understood as the default stand-alone mode where the chip gets the | ||
101 | temperature and controls external devices via its Tout pin or tells other | ||
102 | i2c's about it if they care. The other mode is called "1SHOT", that means | ||
103 | that it only figures out about the temperature when it is explicitly told | ||
104 | to do so; this can be seen as power saving mode. | ||
105 | |||
106 | Now if you want to read REG_COUNT and REG_SLOPE, you have to either stop | ||
107 | the continuous conversions until the contents of these registers are valid, | ||
108 | or, in 1SHOT mode, you have to have one conversion made. | ||
diff --git a/Documentation/i2c/chips/eeprom b/Documentation/i2c/chips/eeprom new file mode 100644 index 000000000000..f7e8104b5764 --- /dev/null +++ b/Documentation/i2c/chips/eeprom | |||
@@ -0,0 +1,96 @@ | |||
1 | Kernel driver eeprom | ||
2 | ==================== | ||
3 | |||
4 | Supported chips: | ||
5 | * Any EEPROM chip in the designated address range | ||
6 | Prefix: 'eeprom' | ||
7 | Addresses scanned: I2C 0x50 - 0x57 | ||
8 | Datasheets: Publicly available from: | ||
9 | Atmel (www.atmel.com), | ||
10 | Catalyst (www.catsemi.com), | ||
11 | Fairchild (www.fairchildsemi.com), | ||
12 | Microchip (www.microchip.com), | ||
13 | Philips (www.semiconductor.philips.com), | ||
14 | Rohm (www.rohm.com), | ||
15 | ST (www.st.com), | ||
16 | Xicor (www.xicor.com), | ||
17 | and others. | ||
18 | |||
19 | Chip Size (bits) Address | ||
20 | 24C01 1K 0x50 (shadows at 0x51 - 0x57) | ||
21 | 24C01A 1K 0x50 - 0x57 (Typical device on DIMMs) | ||
22 | 24C02 2K 0x50 - 0x57 | ||
23 | 24C04 4K 0x50, 0x52, 0x54, 0x56 | ||
24 | (additional data at 0x51, 0x53, 0x55, 0x57) | ||
25 | 24C08 8K 0x50, 0x54 (additional data at 0x51, 0x52, | ||
26 | 0x53, 0x55, 0x56, 0x57) | ||
27 | 24C16 16K 0x50 (additional data at 0x51 - 0x57) | ||
28 | Sony 2K 0x57 | ||
29 | |||
30 | Atmel 34C02B 2K 0x50 - 0x57, SW write protect at 0x30-37 | ||
31 | Catalyst 34FC02 2K 0x50 - 0x57, SW write protect at 0x30-37 | ||
32 | Catalyst 34RC02 2K 0x50 - 0x57, SW write protect at 0x30-37 | ||
33 | Fairchild 34W02 2K 0x50 - 0x57, SW write protect at 0x30-37 | ||
34 | Microchip 24AA52 2K 0x50 - 0x57, SW write protect at 0x30-37 | ||
35 | ST M34C02 2K 0x50 - 0x57, SW write protect at 0x30-37 | ||
36 | |||
37 | |||
38 | Authors: | ||
39 | Frodo Looijaard <frodol@dds.nl>, | ||
40 | Philip Edelbrock <phil@netroedge.com>, | ||
41 | Jean Delvare <khali@linux-fr.org>, | ||
42 | Greg Kroah-Hartman <greg@kroah.com>, | ||
43 | IBM Corp. | ||
44 | |||
45 | Description | ||
46 | ----------- | ||
47 | |||
48 | This is a simple EEPROM module meant to enable reading the first 256 bytes | ||
49 | of an EEPROM (on a SDRAM DIMM for example). However, it will access serial | ||
50 | EEPROMs on any I2C adapter. The supported devices are generically called | ||
51 | 24Cxx, and are listed above; however the numbering for these | ||
52 | industry-standard devices may vary by manufacturer. | ||
53 | |||
54 | This module was a programming exercise to get used to the new project | ||
55 | organization laid out by Frodo, but it should be at least completely | ||
56 | effective for decoding the contents of EEPROMs on DIMMs. | ||
57 | |||
58 | DIMMS will typically contain a 24C01A or 24C02, or the 34C02 variants. | ||
59 | The other devices will not be found on a DIMM because they respond to more | ||
60 | than one address. | ||
61 | |||
62 | DDC Monitors may contain any device. Often a 24C01, which responds to all 8 | ||
63 | addresses, is found. | ||
64 | |||
65 | Recent Sony Vaio laptops have an EEPROM at 0x57. We couldn't get the | ||
66 | specification, so it is guess work and far from being complete. | ||
67 | |||
68 | The Microchip 24AA52/24LCS52, ST M34C02, and others support an additional | ||
69 | software write protect register at 0x30 - 0x37 (0x20 less than the memory | ||
70 | location). The chip responds to "write quick" detection at this address but | ||
71 | does not respond to byte reads. If this register is present, the lower 128 | ||
72 | bytes of the memory array are not write protected. Any byte data write to | ||
73 | this address will write protect the memory array permanently, and the | ||
74 | device will no longer respond at the 0x30-37 address. The eeprom driver | ||
75 | does not support this register. | ||
76 | |||
77 | Lacking functionality: | ||
78 | |||
79 | * Full support for larger devices (24C04, 24C08, 24C16). These are not | ||
80 | typically found on a PC. These devices will appear as separate devices at | ||
81 | multiple addresses. | ||
82 | |||
83 | * Support for really large devices (24C32, 24C64, 24C128, 24C256, 24C512). | ||
84 | These devices require two-byte address fields and are not supported. | ||
85 | |||
86 | * Enable Writing. Again, no technical reason why not, but making it easy | ||
87 | to change the contents of the EEPROMs (on DIMMs anyway) also makes it easy | ||
88 | to disable the DIMMs (potentially preventing the computer from booting) | ||
89 | until the values are restored somehow. | ||
90 | |||
91 | Use: | ||
92 | |||
93 | After inserting the module (and any other required SMBus/i2c modules), you | ||
94 | should have some EEPROM directories in /sys/bus/i2c/devices/* of names such | ||
95 | as "0-0050". Inside each of these is a series of files, the eeprom file | ||
96 | contains the binary data from EEPROM. | ||
diff --git a/Documentation/i2c/chips/fscher b/Documentation/i2c/chips/fscher new file mode 100644 index 000000000000..64031659aff3 --- /dev/null +++ b/Documentation/i2c/chips/fscher | |||
@@ -0,0 +1,169 @@ | |||
1 | Kernel driver fscher | ||
2 | ==================== | ||
3 | |||
4 | Supported chips: | ||
5 | * Fujitsu-Siemens Hermes chip | ||
6 | Prefix: 'fscher' | ||
7 | Addresses scanned: I2C 0x73 | ||
8 | |||
9 | Authors: | ||
10 | Reinhard Nissl <rnissl@gmx.de> based on work | ||
11 | from Hermann Jung <hej@odn.de>, | ||
12 | Frodo Looijaard <frodol@dds.nl>, | ||
13 | Philip Edelbrock <phil@netroedge.com> | ||
14 | |||
15 | Description | ||
16 | ----------- | ||
17 | |||
18 | This driver implements support for the Fujitsu-Siemens Hermes chip. It is | ||
19 | described in the 'Register Set Specification BMC Hermes based Systemboard' | ||
20 | from Fujitsu-Siemens. | ||
21 | |||
22 | The Hermes chip implements a hardware-based system management, e.g. for | ||
23 | controlling fan speed and core voltage. There is also a watchdog counter on | ||
24 | the chip which can trigger an alarm and even shut the system down. | ||
25 | |||
26 | The chip provides three temperature values (CPU, motherboard and | ||
27 | auxiliary), three voltage values (+12V, +5V and battery) and three fans | ||
28 | (power supply, CPU and auxiliary). | ||
29 | |||
30 | Temperatures are measured in degrees Celsius. The resolution is 1 degree. | ||
31 | |||
32 | Fan rotation speeds are reported in RPM (rotations per minute). The value | ||
33 | can be divided by a programmable divider (1, 2 or 4) which is stored on | ||
34 | the chip. | ||
35 | |||
36 | Voltage sensors (also known as "in" sensors) report their values in volts. | ||
37 | |||
38 | All values are reported as final values from the driver. There is no need | ||
39 | for further calculations. | ||
40 | |||
41 | |||
42 | Detailed description | ||
43 | -------------------- | ||
44 | |||
45 | Below you'll find a single line description of all the bit values. With | ||
46 | this information, you're able to decode e. g. alarms, wdog, etc. To make | ||
47 | use of the watchdog, you'll need to set the watchdog time and enable the | ||
48 | watchdog. After that it is necessary to restart the watchdog time within | ||
49 | the specified period of time, or a system reset will occur. | ||
50 | |||
51 | * revision | ||
52 | READING & 0xff = 0x??: HERMES revision identification | ||
53 | |||
54 | * alarms | ||
55 | READING & 0x80 = 0x80: CPU throttling active | ||
56 | READING & 0x80 = 0x00: CPU running at full speed | ||
57 | |||
58 | READING & 0x10 = 0x10: software event (see control:1) | ||
59 | READING & 0x10 = 0x00: no software event | ||
60 | |||
61 | READING & 0x08 = 0x08: watchdog event (see wdog:2) | ||
62 | READING & 0x08 = 0x00: no watchdog event | ||
63 | |||
64 | READING & 0x02 = 0x02: thermal event (see temp*:1) | ||
65 | READING & 0x02 = 0x00: no thermal event | ||
66 | |||
67 | READING & 0x01 = 0x01: fan event (see fan*:1) | ||
68 | READING & 0x01 = 0x00: no fan event | ||
69 | |||
70 | READING & 0x13 ! 0x00: ALERT LED is flashing | ||
71 | |||
72 | * control | ||
73 | READING & 0x01 = 0x01: software event | ||
74 | READING & 0x01 = 0x00: no software event | ||
75 | |||
76 | WRITING & 0x01 = 0x01: set software event | ||
77 | WRITING & 0x01 = 0x00: clear software event | ||
78 | |||
79 | * watchdog_control | ||
80 | READING & 0x80 = 0x80: power off on watchdog event while thermal event | ||
81 | READING & 0x80 = 0x00: watchdog power off disabled (just system reset enabled) | ||
82 | |||
83 | READING & 0x40 = 0x40: watchdog timebase 60 seconds (see also wdog:1) | ||
84 | READING & 0x40 = 0x00: watchdog timebase 2 seconds | ||
85 | |||
86 | READING & 0x10 = 0x10: watchdog enabled | ||
87 | READING & 0x10 = 0x00: watchdog disabled | ||
88 | |||
89 | WRITING & 0x80 = 0x80: enable "power off on watchdog event while thermal event" | ||
90 | WRITING & 0x80 = 0x00: disable "power off on watchdog event while thermal event" | ||
91 | |||
92 | WRITING & 0x40 = 0x40: set watchdog timebase to 60 seconds | ||
93 | WRITING & 0x40 = 0x00: set watchdog timebase to 2 seconds | ||
94 | |||
95 | WRITING & 0x20 = 0x20: disable watchdog | ||
96 | |||
97 | WRITING & 0x10 = 0x10: enable watchdog / restart watchdog time | ||
98 | |||
99 | * watchdog_state | ||
100 | READING & 0x02 = 0x02: watchdog system reset occurred | ||
101 | READING & 0x02 = 0x00: no watchdog system reset occurred | ||
102 | |||
103 | WRITING & 0x02 = 0x02: clear watchdog event | ||
104 | |||
105 | * watchdog_preset | ||
106 | READING & 0xff = 0x??: configured watch dog time in units (see wdog:3 0x40) | ||
107 | |||
108 | WRITING & 0xff = 0x??: configure watch dog time in units | ||
109 | |||
110 | * in* (0: +5V, 1: +12V, 2: onboard 3V battery) | ||
111 | READING: actual voltage value | ||
112 | |||
113 | * temp*_status (1: CPU sensor, 2: onboard sensor, 3: auxiliary sensor) | ||
114 | READING & 0x02 = 0x02: thermal event (overtemperature) | ||
115 | READING & 0x02 = 0x00: no thermal event | ||
116 | |||
117 | READING & 0x01 = 0x01: sensor is working | ||
118 | READING & 0x01 = 0x00: sensor is faulty | ||
119 | |||
120 | WRITING & 0x02 = 0x02: clear thermal event | ||
121 | |||
122 | * temp*_input (1: CPU sensor, 2: onboard sensor, 3: auxiliary sensor) | ||
123 | READING: actual temperature value | ||
124 | |||
125 | * fan*_status (1: power supply fan, 2: CPU fan, 3: auxiliary fan) | ||
126 | READING & 0x04 = 0x04: fan event (fan fault) | ||
127 | READING & 0x04 = 0x00: no fan event | ||
128 | |||
129 | WRITING & 0x04 = 0x04: clear fan event | ||
130 | |||
131 | * fan*_div (1: power supply fan, 2: CPU fan, 3: auxiliary fan) | ||
132 | Divisors 2,4 and 8 are supported, both for reading and writing | ||
133 | |||
134 | * fan*_pwm (1: power supply fan, 2: CPU fan, 3: auxiliary fan) | ||
135 | READING & 0xff = 0x00: fan may be switched off | ||
136 | READING & 0xff = 0x01: fan must run at least at minimum speed (supply: 6V) | ||
137 | READING & 0xff = 0xff: fan must run at maximum speed (supply: 12V) | ||
138 | READING & 0xff = 0x??: fan must run at least at given speed (supply: 6V..12V) | ||
139 | |||
140 | WRITING & 0xff = 0x00: fan may be switched off | ||
141 | WRITING & 0xff = 0x01: fan must run at least at minimum speed (supply: 6V) | ||
142 | WRITING & 0xff = 0xff: fan must run at maximum speed (supply: 12V) | ||
143 | WRITING & 0xff = 0x??: fan must run at least at given speed (supply: 6V..12V) | ||
144 | |||
145 | * fan*_input (1: power supply fan, 2: CPU fan, 3: auxiliary fan) | ||
146 | READING: actual RPM value | ||
147 | |||
148 | |||
149 | Limitations | ||
150 | ----------- | ||
151 | |||
152 | * Measuring fan speed | ||
153 | It seems that the chip counts "ripples" (typical fans produce 2 ripples per | ||
154 | rotation while VERAX fans produce 18) in a 9-bit register. This register is | ||
155 | read out every second, then the ripple prescaler (2, 4 or 8) is applied and | ||
156 | the result is stored in the 8 bit output register. Due to the limitation of | ||
157 | the counting register to 9 bits, it is impossible to measure a VERAX fan | ||
158 | properly (even with a prescaler of 8). At its maximum speed of 3500 RPM the | ||
159 | fan produces 1080 ripples per second which causes the counting register to | ||
160 | overflow twice, leading to only 186 RPM. | ||
161 | |||
162 | * Measuring input voltages | ||
163 | in2 ("battery") reports the voltage of the onboard lithium battery and not | ||
164 | +3.3V from the power supply. | ||
165 | |||
166 | * Undocumented features | ||
167 | Fujitsu-Siemens Computers has not documented all features of the chip so | ||
168 | far. Their software, System Guard, shows that there are a still some | ||
169 | features which cannot be controlled by this implementation. | ||
diff --git a/Documentation/i2c/chips/gl518sm b/Documentation/i2c/chips/gl518sm new file mode 100644 index 000000000000..ce0881883bca --- /dev/null +++ b/Documentation/i2c/chips/gl518sm | |||
@@ -0,0 +1,74 @@ | |||
1 | Kernel driver gl518sm | ||
2 | ===================== | ||
3 | |||
4 | Supported chips: | ||
5 | * Genesys Logic GL518SM release 0x00 | ||
6 | Prefix: 'gl518sm' | ||
7 | Addresses scanned: I2C 0x2c and 0x2d | ||
8 | Datasheet: http://www.genesyslogic.com/pdf | ||
9 | * Genesys Logic GL518SM release 0x80 | ||
10 | Prefix: 'gl518sm' | ||
11 | Addresses scanned: I2C 0x2c and 0x2d | ||
12 | Datasheet: http://www.genesyslogic.com/pdf | ||
13 | |||
14 | Authors: | ||
15 | Frodo Looijaard <frodol@dds.nl>, | ||
16 | Kyösti Mälkki <kmalkki@cc.hut.fi> | ||
17 | Hong-Gunn Chew <hglinux@gunnet.org> | ||
18 | Jean Delvare <khali@linux-fr.org> | ||
19 | |||
20 | Description | ||
21 | ----------- | ||
22 | |||
23 | IMPORTANT: | ||
24 | |||
25 | For the revision 0x00 chip, the in0, in1, and in2 values (+5V, +3V, | ||
26 | and +12V) CANNOT be read. This is a limitation of the chip, not the driver. | ||
27 | |||
28 | This driver supports the Genesys Logic GL518SM chip. There are at least | ||
29 | two revision of this chip, which we call revision 0x00 and 0x80. Revision | ||
30 | 0x80 chips support the reading of all voltages and revision 0x00 only | ||
31 | for VIN3. | ||
32 | |||
33 | The GL518SM implements one temperature sensor, two fan rotation speed | ||
34 | sensors, and four voltage sensors. It can report alarms through the | ||
35 | computer speakers. | ||
36 | |||
37 | Temperatures are measured in degrees Celsius. An alarm goes off while the | ||
38 | temperature is above the over temperature limit, and has not yet dropped | ||
39 | below the hysteresis limit. The alarm always reflects the current | ||
40 | situation. Measurements are guaranteed between -10 degrees and +110 | ||
41 | degrees, with a accuracy of +/-3 degrees. | ||
42 | |||
43 | Rotation speeds are reported in RPM (rotations per minute). An alarm is | ||
44 | triggered if the rotation speed has dropped below a programmable limit. In | ||
45 | case when you have selected to turn fan1 off, no fan1 alarm is triggered. | ||
46 | |||
47 | Fan readings can be divided by a programmable divider (1, 2, 4 or 8) to | ||
48 | give the readings more range or accuracy. Not all RPM values can | ||
49 | accurately be represented, so some rounding is done. With a divider | ||
50 | of 2, the lowest representable value is around 1900 RPM. | ||
51 | |||
52 | Voltage sensors (also known as VIN sensors) report their values in volts. | ||
53 | An alarm is triggered if the voltage has crossed a programmable minimum or | ||
54 | maximum limit. Note that minimum in this case always means 'closest to | ||
55 | zero'; this is important for negative voltage measurements. The VDD input | ||
56 | measures voltages between 0.000 and 5.865 volt, with a resolution of 0.023 | ||
57 | volt. The other inputs measure voltages between 0.000 and 4.845 volt, with | ||
58 | a resolution of 0.019 volt. Note that revision 0x00 chips do not support | ||
59 | reading the current voltage of any input except for VIN3; limit setting and | ||
60 | alarms work fine, though. | ||
61 | |||
62 | When an alarm is triggered, you can be warned by a beeping signal through your | ||
63 | computer speaker. It is possible to enable all beeping globally, or only the | ||
64 | beeping for some alarms. | ||
65 | |||
66 | If an alarm triggers, it will remain triggered until the hardware register | ||
67 | is read at least once (except for temperature alarms). This means that the | ||
68 | cause for the alarm may already have disappeared! Note that in the current | ||
69 | implementation, all hardware registers are read whenever any data is read | ||
70 | (unless it is less than 1.5 seconds since the last update). This means that | ||
71 | you can easily miss once-only alarms. | ||
72 | |||
73 | The GL518SM only updates its values each 1.5 seconds; reading it more often | ||
74 | will do no harm, but will return 'old' values. | ||
diff --git a/Documentation/i2c/chips/it87 b/Documentation/i2c/chips/it87 new file mode 100644 index 000000000000..0d0195040d88 --- /dev/null +++ b/Documentation/i2c/chips/it87 | |||
@@ -0,0 +1,96 @@ | |||
1 | Kernel driver it87 | ||
2 | ================== | ||
3 | |||
4 | Supported chips: | ||
5 | * IT8705F | ||
6 | Prefix: 'it87' | ||
7 | Addresses scanned: from Super I/O config space, or default ISA 0x290 (8 I/O ports) | ||
8 | Datasheet: Publicly available at the ITE website | ||
9 | http://www.ite.com.tw/ | ||
10 | * IT8712F | ||
11 | Prefix: 'it8712' | ||
12 | Addresses scanned: I2C 0x28 - 0x2f | ||
13 | from Super I/O config space, or default ISA 0x290 (8 I/O ports) | ||
14 | Datasheet: Publicly available at the ITE website | ||
15 | http://www.ite.com.tw/ | ||
16 | * SiS950 [clone of IT8705F] | ||
17 | Prefix: 'sis950' | ||
18 | Addresses scanned: from Super I/O config space, or default ISA 0x290 (8 I/O ports) | ||
19 | Datasheet: No longer be available | ||
20 | |||
21 | Author: Christophe Gauthron <chrisg@0-in.com> | ||
22 | |||
23 | |||
24 | Module Parameters | ||
25 | ----------------- | ||
26 | |||
27 | * update_vbat: int | ||
28 | |||
29 | 0 if vbat should report power on value, 1 if vbat should be updated after | ||
30 | each read. Default is 0. On some boards the battery voltage is provided | ||
31 | by either the battery or the onboard power supply. Only the first reading | ||
32 | at power on will be the actual battery voltage (which the chip does | ||
33 | automatically). On other boards the battery voltage is always fed to | ||
34 | the chip so can be read at any time. Excessive reading may decrease | ||
35 | battery life but no information is given in the datasheet. | ||
36 | |||
37 | * fix_pwm_polarity int | ||
38 | |||
39 | Force PWM polarity to active high (DANGEROUS). Some chips are | ||
40 | misconfigured by BIOS - PWM values would be inverted. This option tries | ||
41 | to fix this. Please contact your BIOS manufacturer and ask him for fix. | ||
42 | |||
43 | Description | ||
44 | ----------- | ||
45 | |||
46 | This driver implements support for the IT8705F, IT8712F and SiS950 chips. | ||
47 | |||
48 | This driver also supports IT8712F, which adds SMBus access, and a VID | ||
49 | input, used to report the Vcore voltage of the Pentium processor. | ||
50 | The IT8712F additionally features VID inputs. | ||
51 | |||
52 | These chips are 'Super I/O chips', supporting floppy disks, infrared ports, | ||
53 | joysticks and other miscellaneous stuff. For hardware monitoring, they | ||
54 | include an 'environment controller' with 3 temperature sensors, 3 fan | ||
55 | rotation speed sensors, 8 voltage sensors, and associated alarms. | ||
56 | |||
57 | Temperatures are measured in degrees Celsius. An alarm is triggered once | ||
58 | when the Overtemperature Shutdown limit is crossed. | ||
59 | |||
60 | Fan rotation speeds are reported in RPM (rotations per minute). An alarm is | ||
61 | triggered if the rotation speed has dropped below a programmable limit. Fan | ||
62 | readings can be divided by a programmable divider (1, 2, 4 or 8) to give the | ||
63 | readings more range or accuracy. Not all RPM values can accurately be | ||
64 | represented, so some rounding is done. With a divider of 2, the lowest | ||
65 | representable value is around 2600 RPM. | ||
66 | |||
67 | Voltage sensors (also known as IN sensors) report their values in volts. An | ||
68 | alarm is triggered if the voltage has crossed a programmable minimum or | ||
69 | maximum limit. Note that minimum in this case always means 'closest to | ||
70 | zero'; this is important for negative voltage measurements. All voltage | ||
71 | inputs can measure voltages between 0 and 4.08 volts, with a resolution of | ||
72 | 0.016 volt. The battery voltage in8 does not have limit registers. | ||
73 | |||
74 | The VID lines (IT8712F only) encode the core voltage value: the voltage | ||
75 | level your processor should work with. This is hardcoded by the mainboard | ||
76 | and/or processor itself. It is a value in volts. | ||
77 | |||
78 | If an alarm triggers, it will remain triggered until the hardware register | ||
79 | is read at least once. This means that the cause for the alarm may already | ||
80 | have disappeared! Note that in the current implementation, all hardware | ||
81 | registers are read whenever any data is read (unless it is less than 1.5 | ||
82 | seconds since the last update). This means that you can easily miss | ||
83 | once-only alarms. | ||
84 | |||
85 | The IT87xx only updates its values each 1.5 seconds; reading it more often | ||
86 | will do no harm, but will return 'old' values. | ||
87 | |||
88 | To change sensor N to a thermistor, 'echo 2 > tempN_type' where N is 1, 2, | ||
89 | or 3. To change sensor N to a thermal diode, 'echo 3 > tempN_type'. | ||
90 | Give 0 for unused sensor. Any other value is invalid. To configure this at | ||
91 | startup, consult lm_sensors's /etc/sensors.conf. (2 = thermistor; | ||
92 | 3 = thermal diode) | ||
93 | |||
94 | The fan speed control features are limited to manual PWM mode. Automatic | ||
95 | "Smart Guardian" mode control handling is not implemented. However | ||
96 | if you want to go for "manual mode" just write 1 to pwmN_enable. | ||
diff --git a/Documentation/i2c/chips/lm63 b/Documentation/i2c/chips/lm63 new file mode 100644 index 000000000000..31660bf97979 --- /dev/null +++ b/Documentation/i2c/chips/lm63 | |||
@@ -0,0 +1,57 @@ | |||
1 | Kernel driver lm63 | ||
2 | ================== | ||
3 | |||
4 | Supported chips: | ||
5 | * National Semiconductor LM63 | ||
6 | Prefix: 'lm63' | ||
7 | Addresses scanned: I2C 0x4c | ||
8 | Datasheet: Publicly available at the National Semiconductor website | ||
9 | http://www.national.com/pf/LM/LM63.html | ||
10 | |||
11 | Author: Jean Delvare <khali@linux-fr.org> | ||
12 | |||
13 | Thanks go to Tyan and especially Alex Buckingham for setting up a remote | ||
14 | access to their S4882 test platform for this driver. | ||
15 | http://www.tyan.com/ | ||
16 | |||
17 | Description | ||
18 | ----------- | ||
19 | |||
20 | The LM63 is a digital temperature sensor with integrated fan monitoring | ||
21 | and control. | ||
22 | |||
23 | The LM63 is basically an LM86 with fan speed monitoring and control | ||
24 | capabilities added. It misses some of the LM86 features though: | ||
25 | - No low limit for local temperature. | ||
26 | - No critical limit for local temperature. | ||
27 | - Critical limit for remote temperature can be changed only once. We | ||
28 | will consider that the critical limit is read-only. | ||
29 | |||
30 | The datasheet isn't very clear about what the tachometer reading is. | ||
31 | |||
32 | An explanation from National Semiconductor: The two lower bits of the read | ||
33 | value have to be masked out. The value is still 16 bit in width. | ||
34 | |||
35 | All temperature values are given in degrees Celsius. Resolution is 1.0 | ||
36 | degree for the local temperature, 0.125 degree for the remote temperature. | ||
37 | |||
38 | The fan speed is measured using a tachometer. Contrary to most chips which | ||
39 | store the value in an 8-bit register and have a selectable clock divider | ||
40 | to make sure that the result will fit in the register, the LM63 uses 16-bit | ||
41 | value for measuring the speed of the fan. It can measure fan speeds down to | ||
42 | 83 RPM, at least in theory. | ||
43 | |||
44 | Note that the pin used for fan monitoring is shared with an alert out | ||
45 | function. Depending on how the board designer wanted to use the chip, fan | ||
46 | speed monitoring will or will not be possible. The proper chip configuration | ||
47 | is left to the BIOS, and the driver will blindly trust it. | ||
48 | |||
49 | A PWM output can be used to control the speed of the fan. The LM63 has two | ||
50 | PWM modes: manual and automatic. Automatic mode is not fully implemented yet | ||
51 | (you cannot define your custom PWM/temperature curve), and mode change isn't | ||
52 | supported either. | ||
53 | |||
54 | The lm63 driver will not update its values more frequently than every | ||
55 | second; reading them more often will do no harm, but will return 'old' | ||
56 | values. | ||
57 | |||
diff --git a/Documentation/i2c/chips/lm75 b/Documentation/i2c/chips/lm75 new file mode 100644 index 000000000000..8e6356fe05d7 --- /dev/null +++ b/Documentation/i2c/chips/lm75 | |||
@@ -0,0 +1,65 @@ | |||
1 | Kernel driver lm75 | ||
2 | ================== | ||
3 | |||
4 | Supported chips: | ||
5 | * National Semiconductor LM75 | ||
6 | Prefix: 'lm75' | ||
7 | Addresses scanned: I2C 0x48 - 0x4f | ||
8 | Datasheet: Publicly available at the National Semiconductor website | ||
9 | http://www.national.com/ | ||
10 | * Dallas Semiconductor DS75 | ||
11 | Prefix: 'lm75' | ||
12 | Addresses scanned: I2C 0x48 - 0x4f | ||
13 | Datasheet: Publicly available at the Dallas Semiconductor website | ||
14 | http://www.maxim-ic.com/ | ||
15 | * Dallas Semiconductor DS1775 | ||
16 | Prefix: 'lm75' | ||
17 | Addresses scanned: I2C 0x48 - 0x4f | ||
18 | Datasheet: Publicly available at the Dallas Semiconductor website | ||
19 | http://www.maxim-ic.com/ | ||
20 | * Maxim MAX6625, MAX6626 | ||
21 | Prefix: 'lm75' | ||
22 | Addresses scanned: I2C 0x48 - 0x4b | ||
23 | Datasheet: Publicly available at the Maxim website | ||
24 | http://www.maxim-ic.com/ | ||
25 | * Microchip (TelCom) TCN75 | ||
26 | Prefix: 'lm75' | ||
27 | Addresses scanned: I2C 0x48 - 0x4f | ||
28 | Datasheet: Publicly available at the Microchip website | ||
29 | http://www.microchip.com/ | ||
30 | |||
31 | Author: Frodo Looijaard <frodol@dds.nl> | ||
32 | |||
33 | Description | ||
34 | ----------- | ||
35 | |||
36 | The LM75 implements one temperature sensor. Limits can be set through the | ||
37 | Overtemperature Shutdown register and Hysteresis register. Each value can be | ||
38 | set and read to half-degree accuracy. | ||
39 | An alarm is issued (usually to a connected LM78) when the temperature | ||
40 | gets higher then the Overtemperature Shutdown value; it stays on until | ||
41 | the temperature falls below the Hysteresis value. | ||
42 | All temperatures are in degrees Celsius, and are guaranteed within a | ||
43 | range of -55 to +125 degrees. | ||
44 | |||
45 | The LM75 only updates its values each 1.5 seconds; reading it more often | ||
46 | will do no harm, but will return 'old' values. | ||
47 | |||
48 | The LM75 is usually used in combination with LM78-like chips, to measure | ||
49 | the temperature of the processor(s). | ||
50 | |||
51 | The DS75, DS1775, MAX6625, and MAX6626 are supported as well. | ||
52 | They are not distinguished from an LM75. While most of these chips | ||
53 | have three additional bits of accuracy (12 vs. 9 for the LM75), | ||
54 | the additional bits are not supported. Not only that, but these chips will | ||
55 | not be detected if not in 9-bit precision mode (use the force parameter if | ||
56 | needed). | ||
57 | |||
58 | The TCN75 is supported as well, and is not distinguished from an LM75. | ||
59 | |||
60 | The LM75 is essentially an industry standard; there may be other | ||
61 | LM75 clones not listed here, with or without various enhancements, | ||
62 | that are supported. | ||
63 | |||
64 | The LM77 is not supported, contrary to what we pretended for a long time. | ||
65 | Both chips are simply not compatible, value encoding differs. | ||
diff --git a/Documentation/i2c/chips/lm77 b/Documentation/i2c/chips/lm77 new file mode 100644 index 000000000000..57c3a46d6370 --- /dev/null +++ b/Documentation/i2c/chips/lm77 | |||
@@ -0,0 +1,22 @@ | |||
1 | Kernel driver lm77 | ||
2 | ================== | ||
3 | |||
4 | Supported chips: | ||
5 | * National Semiconductor LM77 | ||
6 | Prefix: 'lm77' | ||
7 | Addresses scanned: I2C 0x48 - 0x4b | ||
8 | Datasheet: Publicly available at the National Semiconductor website | ||
9 | http://www.national.com/ | ||
10 | |||
11 | Author: Andras BALI <drewie@freemail.hu> | ||
12 | |||
13 | Description | ||
14 | ----------- | ||
15 | |||
16 | The LM77 implements one temperature sensor. The temperature | ||
17 | sensor incorporates a band-gap type temperature sensor, | ||
18 | 10-bit ADC, and a digital comparator with user-programmable upper | ||
19 | and lower limit values. | ||
20 | |||
21 | Limits can be set through the Overtemperature Shutdown register and | ||
22 | Hysteresis register. | ||
diff --git a/Documentation/i2c/chips/lm78 b/Documentation/i2c/chips/lm78 new file mode 100644 index 000000000000..357086ed7f64 --- /dev/null +++ b/Documentation/i2c/chips/lm78 | |||
@@ -0,0 +1,82 @@ | |||
1 | Kernel driver lm78 | ||
2 | ================== | ||
3 | |||
4 | Supported chips: | ||
5 | * National Semiconductor LM78 | ||
6 | Prefix: 'lm78' | ||
7 | Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports) | ||
8 | Datasheet: Publicly available at the National Semiconductor website | ||
9 | http://www.national.com/ | ||
10 | * National Semiconductor LM78-J | ||
11 | Prefix: 'lm78-j' | ||
12 | Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports) | ||
13 | Datasheet: Publicly available at the National Semiconductor website | ||
14 | http://www.national.com/ | ||
15 | * National Semiconductor LM79 | ||
16 | Prefix: 'lm79' | ||
17 | Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports) | ||
18 | Datasheet: Publicly available at the National Semiconductor website | ||
19 | http://www.national.com/ | ||
20 | |||
21 | Author: Frodo Looijaard <frodol@dds.nl> | ||
22 | |||
23 | Description | ||
24 | ----------- | ||
25 | |||
26 | This driver implements support for the National Semiconductor LM78, LM78-J | ||
27 | and LM79. They are described as 'Microprocessor System Hardware Monitors'. | ||
28 | |||
29 | There is almost no difference between the three supported chips. Functionally, | ||
30 | the LM78 and LM78-J are exactly identical. The LM79 has one more VID line, | ||
31 | which is used to report the lower voltages newer Pentium processors use. | ||
32 | From here on, LM7* means either of these three types. | ||
33 | |||
34 | The LM7* implements one temperature sensor, three fan rotation speed sensors, | ||
35 | seven voltage sensors, VID lines, alarms, and some miscellaneous stuff. | ||
36 | |||
37 | Temperatures are measured in degrees Celsius. An alarm is triggered once | ||
38 | when the Overtemperature Shutdown limit is crossed; it is triggered again | ||
39 | as soon as it drops below the Hysteresis value. A more useful behavior | ||
40 | can be found by setting the Hysteresis value to +127 degrees Celsius; in | ||
41 | this case, alarms are issued during all the time when the actual temperature | ||
42 | is above the Overtemperature Shutdown value. Measurements are guaranteed | ||
43 | between -55 and +125 degrees, with a resolution of 1 degree. | ||
44 | |||
45 | Fan rotation speeds are reported in RPM (rotations per minute). An alarm is | ||
46 | triggered if the rotation speed has dropped below a programmable limit. Fan | ||
47 | readings can be divided by a programmable divider (1, 2, 4 or 8) to give | ||
48 | the readings more range or accuracy. Not all RPM values can accurately be | ||
49 | represented, so some rounding is done. With a divider of 2, the lowest | ||
50 | representable value is around 2600 RPM. | ||
51 | |||
52 | Voltage sensors (also known as IN sensors) report their values in volts. | ||
53 | An alarm is triggered if the voltage has crossed a programmable minimum | ||
54 | or maximum limit. Note that minimum in this case always means 'closest to | ||
55 | zero'; this is important for negative voltage measurements. All voltage | ||
56 | inputs can measure voltages between 0 and 4.08 volts, with a resolution | ||
57 | of 0.016 volt. | ||
58 | |||
59 | The VID lines encode the core voltage value: the voltage level your processor | ||
60 | should work with. This is hardcoded by the mainboard and/or processor itself. | ||
61 | It is a value in volts. When it is unconnected, you will often find the | ||
62 | value 3.50 V here. | ||
63 | |||
64 | In addition to the alarms described above, there are a couple of additional | ||
65 | ones. There is a BTI alarm, which gets triggered when an external chip has | ||
66 | crossed its limits. Usually, this is connected to all LM75 chips; if at | ||
67 | least one crosses its limits, this bit gets set. The CHAS alarm triggers | ||
68 | if your computer case is open. The FIFO alarms should never trigger; it | ||
69 | indicates an internal error. The SMI_IN alarm indicates some other chip | ||
70 | has triggered an SMI interrupt. As we do not use SMI interrupts at all, | ||
71 | this condition usually indicates there is a problem with some other | ||
72 | device. | ||
73 | |||
74 | If an alarm triggers, it will remain triggered until the hardware register | ||
75 | is read at least once. This means that the cause for the alarm may | ||
76 | already have disappeared! Note that in the current implementation, all | ||
77 | hardware registers are read whenever any data is read (unless it is less | ||
78 | than 1.5 seconds since the last update). This means that you can easily | ||
79 | miss once-only alarms. | ||
80 | |||
81 | The LM7* only updates its values each 1.5 seconds; reading it more often | ||
82 | will do no harm, but will return 'old' values. | ||
diff --git a/Documentation/i2c/chips/lm80 b/Documentation/i2c/chips/lm80 new file mode 100644 index 000000000000..cb5b407ba3e6 --- /dev/null +++ b/Documentation/i2c/chips/lm80 | |||
@@ -0,0 +1,56 @@ | |||
1 | Kernel driver lm80 | ||
2 | ================== | ||
3 | |||
4 | Supported chips: | ||
5 | * National Semiconductor LM80 | ||
6 | Prefix: 'lm80' | ||
7 | Addresses scanned: I2C 0x28 - 0x2f | ||
8 | Datasheet: Publicly available at the National Semiconductor website | ||
9 | http://www.national.com/ | ||
10 | |||
11 | Authors: | ||
12 | Frodo Looijaard <frodol@dds.nl>, | ||
13 | Philip Edelbrock <phil@netroedge.com> | ||
14 | |||
15 | Description | ||
16 | ----------- | ||
17 | |||
18 | This driver implements support for the National Semiconductor LM80. | ||
19 | It is described as a 'Serial Interface ACPI-Compatible Microprocessor | ||
20 | System Hardware Monitor'. | ||
21 | |||
22 | The LM80 implements one temperature sensor, two fan rotation speed sensors, | ||
23 | seven voltage sensors, alarms, and some miscellaneous stuff. | ||
24 | |||
25 | Temperatures are measured in degrees Celsius. There are two sets of limits | ||
26 | which operate independently. When the HOT Temperature Limit is crossed, | ||
27 | this will cause an alarm that will be reasserted until the temperature | ||
28 | drops below the HOT Hysteresis. The Overtemperature Shutdown (OS) limits | ||
29 | should work in the same way (but this must be checked; the datasheet | ||
30 | is unclear about this). Measurements are guaranteed between -55 and | ||
31 | +125 degrees. The current temperature measurement has a resolution of | ||
32 | 0.0625 degrees; the limits have a resolution of 1 degree. | ||
33 | |||
34 | Fan rotation speeds are reported in RPM (rotations per minute). An alarm is | ||
35 | triggered if the rotation speed has dropped below a programmable limit. Fan | ||
36 | readings can be divided by a programmable divider (1, 2, 4 or 8) to give | ||
37 | the readings more range or accuracy. Not all RPM values can accurately be | ||
38 | represented, so some rounding is done. With a divider of 2, the lowest | ||
39 | representable value is around 2600 RPM. | ||
40 | |||
41 | Voltage sensors (also known as IN sensors) report their values in volts. | ||
42 | An alarm is triggered if the voltage has crossed a programmable minimum | ||
43 | or maximum limit. Note that minimum in this case always means 'closest to | ||
44 | zero'; this is important for negative voltage measurements. All voltage | ||
45 | inputs can measure voltages between 0 and 2.55 volts, with a resolution | ||
46 | of 0.01 volt. | ||
47 | |||
48 | If an alarm triggers, it will remain triggered until the hardware register | ||
49 | is read at least once. This means that the cause for the alarm may | ||
50 | already have disappeared! Note that in the current implementation, all | ||
51 | hardware registers are read whenever any data is read (unless it is less | ||
52 | than 2.0 seconds since the last update). This means that you can easily | ||
53 | miss once-only alarms. | ||
54 | |||
55 | The LM80 only updates its values each 1.5 seconds; reading it more often | ||
56 | will do no harm, but will return 'old' values. | ||
diff --git a/Documentation/i2c/chips/lm83 b/Documentation/i2c/chips/lm83 new file mode 100644 index 000000000000..061d9ed8ff43 --- /dev/null +++ b/Documentation/i2c/chips/lm83 | |||
@@ -0,0 +1,76 @@ | |||
1 | Kernel driver lm83 | ||
2 | ================== | ||
3 | |||
4 | Supported chips: | ||
5 | * National Semiconductor LM83 | ||
6 | Prefix: 'lm83' | ||
7 | Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e | ||
8 | Datasheet: Publicly available at the National Semiconductor website | ||
9 | http://www.national.com/pf/LM/LM83.html | ||
10 | |||
11 | |||
12 | Author: Jean Delvare <khali@linux-fr.org> | ||
13 | |||
14 | Description | ||
15 | ----------- | ||
16 | |||
17 | The LM83 is a digital temperature sensor. It senses its own temperature as | ||
18 | well as the temperature of up to three external diodes. It is compatible | ||
19 | with many other devices such as the LM84 and all other ADM1021 clones. | ||
20 | The main difference between the LM83 and the LM84 in that the later can | ||
21 | only sense the temperature of one external diode. | ||
22 | |||
23 | Using the adm1021 driver for a LM83 should work, but only two temperatures | ||
24 | will be reported instead of four. | ||
25 | |||
26 | The LM83 is only found on a handful of motherboards. Both a confirmed | ||
27 | list and an unconfirmed list follow. If you can confirm or infirm the | ||
28 | fact that any of these motherboards do actually have an LM83, please | ||
29 | contact us. Note that the LM90 can easily be misdetected as a LM83. | ||
30 | |||
31 | Confirmed motherboards: | ||
32 | SBS P014 | ||
33 | |||
34 | Unconfirmed motherboards: | ||
35 | Gigabyte GA-8IK1100 | ||
36 | Iwill MPX2 | ||
37 | Soltek SL-75DRV5 | ||
38 | |||
39 | The driver has been successfully tested by Magnus Forsström, who I'd | ||
40 | like to thank here. More testers will be of course welcome. | ||
41 | |||
42 | The fact that the LM83 is only scarcely used can be easily explained. | ||
43 | Most motherboards come with more than just temperature sensors for | ||
44 | health monitoring. They also have voltage and fan rotation speed | ||
45 | sensors. This means that temperature-only chips are usually used as | ||
46 | secondary chips coupled with another chip such as an IT8705F or similar | ||
47 | chip, which provides more features. Since systems usually need three | ||
48 | temperature sensors (motherboard, processor, power supply) and primary | ||
49 | chips provide some temperature sensors, the secondary chip, if needed, | ||
50 | won't have to handle more than two temperatures. Thus, ADM1021 clones | ||
51 | are sufficient, and there is no need for a four temperatures sensor | ||
52 | chip such as the LM83. The only case where using an LM83 would make | ||
53 | sense is on SMP systems, such as the above-mentioned Iwill MPX2, | ||
54 | because you want an additional temperature sensor for each additional | ||
55 | CPU. | ||
56 | |||
57 | On the SBS P014, this is different, since the LM83 is the only hardware | ||
58 | monitoring chipset. One temperature sensor is used for the motherboard | ||
59 | (actually measuring the LM83's own temperature), one is used for the | ||
60 | CPU. The two other sensors must be used to measure the temperature of | ||
61 | two other points of the motherboard. We suspect these points to be the | ||
62 | north and south bridges, but this couldn't be confirmed. | ||
63 | |||
64 | All temperature values are given in degrees Celsius. Local temperature | ||
65 | is given within a range of 0 to +85 degrees. Remote temperatures are | ||
66 | given within a range of 0 to +125 degrees. Resolution is 1.0 degree, | ||
67 | accuracy is guaranteed to 3.0 degrees (see the datasheet for more | ||
68 | details). | ||
69 | |||
70 | Each sensor has its own high limit, but the critical limit is common to | ||
71 | all four sensors. There is no hysteresis mechanism as found on most | ||
72 | recent temperature sensors. | ||
73 | |||
74 | The lm83 driver will not update its values more frequently than every | ||
75 | other second; reading them more often will do no harm, but will return | ||
76 | 'old' values. | ||
diff --git a/Documentation/i2c/chips/lm85 b/Documentation/i2c/chips/lm85 new file mode 100644 index 000000000000..9549237530cf --- /dev/null +++ b/Documentation/i2c/chips/lm85 | |||
@@ -0,0 +1,221 @@ | |||
1 | Kernel driver lm85 | ||
2 | ================== | ||
3 | |||
4 | Supported chips: | ||
5 | * National Semiconductor LM85 (B and C versions) | ||
6 | Prefix: 'lm85' | ||
7 | Addresses scanned: I2C 0x2c, 0x2d, 0x2e | ||
8 | Datasheet: http://www.national.com/pf/LM/LM85.html | ||
9 | * Analog Devices ADM1027 | ||
10 | Prefix: 'adm1027' | ||
11 | Addresses scanned: I2C 0x2c, 0x2d, 0x2e | ||
12 | Datasheet: http://www.analog.com/en/prod/0,,766_825_ADM1027,00.html | ||
13 | * Analog Devices ADT7463 | ||
14 | Prefix: 'adt7463' | ||
15 | Addresses scanned: I2C 0x2c, 0x2d, 0x2e | ||
16 | Datasheet: http://www.analog.com/en/prod/0,,766_825_ADT7463,00.html | ||
17 | * SMSC EMC6D100, SMSC EMC6D101 | ||
18 | Prefix: 'emc6d100' | ||
19 | Addresses scanned: I2C 0x2c, 0x2d, 0x2e | ||
20 | Datasheet: http://www.smsc.com/main/tools/discontinued/6d100.pdf | ||
21 | * SMSC EMC6D102 | ||
22 | Prefix: 'emc6d102' | ||
23 | Addresses scanned: I2C 0x2c, 0x2d, 0x2e | ||
24 | Datasheet: http://www.smsc.com/main/catalog/emc6d102.html | ||
25 | |||
26 | Authors: | ||
27 | Philip Pokorny <ppokorny@penguincomputing.com>, | ||
28 | Frodo Looijaard <frodol@dds.nl>, | ||
29 | Richard Barrington <rich_b_nz@clear.net.nz>, | ||
30 | Margit Schubert-While <margitsw@t-online.de>, | ||
31 | Justin Thiessen <jthiessen@penguincomputing.com> | ||
32 | |||
33 | Description | ||
34 | ----------- | ||
35 | |||
36 | This driver implements support for the National Semiconductor LM85 and | ||
37 | compatible chips including the Analog Devices ADM1027, ADT7463 and | ||
38 | SMSC EMC6D10x chips family. | ||
39 | |||
40 | The LM85 uses the 2-wire interface compatible with the SMBUS 2.0 | ||
41 | specification. Using an analog to digital converter it measures three (3) | ||
42 | temperatures and five (5) voltages. It has four (4) 16-bit counters for | ||
43 | measuring fan speed. Five (5) digital inputs are provided for sampling the | ||
44 | VID signals from the processor to the VRM. Lastly, there are three (3) PWM | ||
45 | outputs that can be used to control fan speed. | ||
46 | |||
47 | The voltage inputs have internal scaling resistors so that the following | ||
48 | voltage can be measured without external resistors: | ||
49 | |||
50 | 2.5V, 3.3V, 5V, 12V, and CPU core voltage (2.25V) | ||
51 | |||
52 | The temperatures measured are one internal diode, and two remote diodes. | ||
53 | Remote 1 is generally the CPU temperature. These inputs are designed to | ||
54 | measure a thermal diode like the one in a Pentium 4 processor in a socket | ||
55 | 423 or socket 478 package. They can also measure temperature using a | ||
56 | transistor like the 2N3904. | ||
57 | |||
58 | A sophisticated control system for the PWM outputs is designed into the | ||
59 | LM85 that allows fan speed to be adjusted automatically based on any of the | ||
60 | three temperature sensors. Each PWM output is individually adjustable and | ||
61 | programmable. Once configured, the LM85 will adjust the PWM outputs in | ||
62 | response to the measured temperatures without further host intervention. | ||
63 | This feature can also be disabled for manual control of the PWM's. | ||
64 | |||
65 | Each of the measured inputs (voltage, temperature, fan speed) has | ||
66 | corresponding high/low limit values. The LM85 will signal an ALARM if any | ||
67 | measured value exceeds either limit. | ||
68 | |||
69 | The LM85 samples all inputs continuously. The lm85 driver will not read | ||
70 | the registers more often than once a second. Further, configuration data is | ||
71 | only read once each 5 minutes. There is twice as much config data as | ||
72 | measurements, so this would seem to be a worthwhile optimization. | ||
73 | |||
74 | Special Features | ||
75 | ---------------- | ||
76 | |||
77 | The LM85 has four fan speed monitoring modes. The ADM1027 has only two. | ||
78 | Both have special circuitry to compensate for PWM interactions with the | ||
79 | TACH signal from the fans. The ADM1027 can be configured to measure the | ||
80 | speed of a two wire fan, but the input conditioning circuitry is different | ||
81 | for 3-wire and 2-wire mode. For this reason, the 2-wire fan modes are not | ||
82 | exposed to user control. The BIOS should initialize them to the correct | ||
83 | mode. If you've designed your own ADM1027, you'll have to modify the | ||
84 | init_client function and add an insmod parameter to set this up. | ||
85 | |||
86 | To smooth the response of fans to changes in temperature, the LM85 has an | ||
87 | optional filter for smoothing temperatures. The ADM1027 has the same | ||
88 | config option but uses it to rate limit the changes to fan speed instead. | ||
89 | |||
90 | The ADM1027 and ADT7463 have a 10-bit ADC and can therefore measure | ||
91 | temperatures with 0.25 degC resolution. They also provide an offset to the | ||
92 | temperature readings that is automatically applied during measurement. | ||
93 | This offset can be used to zero out any errors due to traces and placement. | ||
94 | The documentation says that the offset is in 0.25 degC steps, but in | ||
95 | initial testing of the ADM1027 it was 1.00 degC steps. Analog Devices has | ||
96 | confirmed this "bug". The ADT7463 is reported to work as described in the | ||
97 | documentation. The current lm85 driver does not show the offset register. | ||
98 | |||
99 | The ADT7463 has a THERM asserted counter. This counter has a 22.76ms | ||
100 | resolution and a range of 5.8 seconds. The driver implements a 32-bit | ||
101 | accumulator of the counter value to extend the range to over a year. The | ||
102 | counter will stay at it's max value until read. | ||
103 | |||
104 | See the vendor datasheets for more information. There is application note | ||
105 | from National (AN-1260) with some additional information about the LM85. | ||
106 | The Analog Devices datasheet is very detailed and describes a procedure for | ||
107 | determining an optimal configuration for the automatic PWM control. | ||
108 | |||
109 | The SMSC EMC6D100 & EMC6D101 monitor external voltages, temperatures, and | ||
110 | fan speeds. They use this monitoring capability to alert the system to out | ||
111 | of limit conditions and can automatically control the speeds of multiple | ||
112 | fans in a PC or embedded system. The EMC6D101, available in a 24-pin SSOP | ||
113 | package, and the EMC6D100, available in a 28-pin SSOP package, are designed | ||
114 | to be register compatible. The EMC6D100 offers all the features of the | ||
115 | EMC6D101 plus additional voltage monitoring and system control features. | ||
116 | Unfortunately it is not possible to distinguish between the package | ||
117 | versions on register level so these additional voltage inputs may read | ||
118 | zero. The EMC6D102 features addtional ADC bits thus extending precision | ||
119 | of voltage and temperature channels. | ||
120 | |||
121 | |||
122 | Hardware Configurations | ||
123 | ----------------------- | ||
124 | |||
125 | The LM85 can be jumpered for 3 different SMBus addresses. There are | ||
126 | no other hardware configuration options for the LM85. | ||
127 | |||
128 | The lm85 driver detects both LM85B and LM85C revisions of the chip. See the | ||
129 | datasheet for a complete description of the differences. Other than | ||
130 | identifying the chip, the driver behaves no differently with regard to | ||
131 | these two chips. The LM85B is recommended for new designs. | ||
132 | |||
133 | The ADM1027 and ADT7463 chips have an optional SMBALERT output that can be | ||
134 | used to signal the chipset in case a limit is exceeded or the temperature | ||
135 | sensors fail. Individual sensor interrupts can be masked so they won't | ||
136 | trigger SMBALERT. The SMBALERT output if configured replaces one of the other | ||
137 | functions (PWM2 or IN0). This functionality is not implemented in current | ||
138 | driver. | ||
139 | |||
140 | The ADT7463 also has an optional THERM output/input which can be connected | ||
141 | to the processor PROC_HOT output. If available, the autofan control | ||
142 | dynamic Tmin feature can be enabled to keep the system temperature within | ||
143 | spec (just?!) with the least possible fan noise. | ||
144 | |||
145 | Configuration Notes | ||
146 | ------------------- | ||
147 | |||
148 | Besides standard interfaces driver adds following: | ||
149 | |||
150 | * Temperatures and Zones | ||
151 | |||
152 | Each temperature sensor is associated with a Zone. There are three | ||
153 | sensors and therefore three zones (# 1, 2 and 3). Each zone has the following | ||
154 | temperature configuration points: | ||
155 | |||
156 | * temp#_auto_temp_off - temperature below which fans should be off or spinning very low. | ||
157 | * temp#_auto_temp_min - temperature over which fans start to spin. | ||
158 | * temp#_auto_temp_max - temperature when fans spin at full speed. | ||
159 | * temp#_auto_temp_crit - temperature when all fans will run full speed. | ||
160 | |||
161 | * PWM Control | ||
162 | |||
163 | There are three PWM outputs. The LM85 datasheet suggests that the | ||
164 | pwm3 output control both fan3 and fan4. Each PWM can be individually | ||
165 | configured and assigned to a zone for it's control value. Each PWM can be | ||
166 | configured individually according to the following options. | ||
167 | |||
168 | * pwm#_auto_pwm_min - this specifies the PWM value for temp#_auto_temp_off | ||
169 | temperature. (PWM value from 0 to 255) | ||
170 | |||
171 | * pwm#_auto_pwm_freq - select base frequency of PWM output. You can select | ||
172 | in range of 10.0 to 94.0 Hz in .1 Hz units. | ||
173 | (Values 100 to 940). | ||
174 | |||
175 | The pwm#_auto_pwm_freq can be set to one of the following 8 values. Setting the | ||
176 | frequency to a value not on this list, will result in the next higher frequency | ||
177 | being selected. The actual device frequency may vary slightly from this | ||
178 | specification as designed by the manufacturer. Consult the datasheet for more | ||
179 | details. (PWM Frequency values: 100, 150, 230, 300, 380, 470, 620, 940) | ||
180 | |||
181 | * pwm#_auto_pwm_minctl - this flags selects for temp#_auto_temp_off temperature | ||
182 | the bahaviour of fans. Write 1 to let fans spinning at | ||
183 | pwm#_auto_pwm_min or write 0 to let them off. | ||
184 | |||
185 | NOTE: It has been reported that there is a bug in the LM85 that causes the flag | ||
186 | to be associated with the zones not the PWMs. This contradicts all the | ||
187 | published documentation. Setting pwm#_min_ctl in this case actually affects all | ||
188 | PWMs controlled by zone '#'. | ||
189 | |||
190 | * PWM Controlling Zone selection | ||
191 | |||
192 | * pwm#_auto_channels - controls zone that is associated with PWM | ||
193 | |||
194 | Configuration choices: | ||
195 | |||
196 | Value Meaning | ||
197 | ------ ------------------------------------------------ | ||
198 | 1 Controlled by Zone 1 | ||
199 | 2 Controlled by Zone 2 | ||
200 | 3 Controlled by Zone 3 | ||
201 | 23 Controlled by higher temp of Zone 2 or 3 | ||
202 | 123 Controlled by highest temp of Zone 1, 2 or 3 | ||
203 | 0 PWM always 0% (off) | ||
204 | -1 PWM always 100% (full on) | ||
205 | -2 Manual control (write to 'pwm#' to set) | ||
206 | |||
207 | The National LM85's have two vendor specific configuration | ||
208 | features. Tach. mode and Spinup Control. For more details on these, | ||
209 | see the LM85 datasheet or Application Note AN-1260. | ||
210 | |||
211 | The Analog Devices ADM1027 has several vendor specific enhancements. | ||
212 | The number of pulses-per-rev of the fans can be set, Tach monitoring | ||
213 | can be optimized for PWM operation, and an offset can be applied to | ||
214 | the temperatures to compensate for systemic errors in the | ||
215 | measurements. | ||
216 | |||
217 | In addition to the ADM1027 features, the ADT7463 also has Tmin control | ||
218 | and THERM asserted counts. Automatic Tmin control acts to adjust the | ||
219 | Tmin value to maintain the measured temperature sensor at a specified | ||
220 | temperature. There isn't much documentation on this feature in the | ||
221 | ADT7463 data sheet. This is not supported by current driver. | ||
diff --git a/Documentation/i2c/chips/lm87 b/Documentation/i2c/chips/lm87 new file mode 100644 index 000000000000..c952c57f0e11 --- /dev/null +++ b/Documentation/i2c/chips/lm87 | |||
@@ -0,0 +1,73 @@ | |||
1 | Kernel driver lm87 | ||
2 | ================== | ||
3 | |||
4 | Supported chips: | ||
5 | * National Semiconductor LM87 | ||
6 | Prefix: 'lm87' | ||
7 | Addresses scanned: I2C 0x2c - 0x2f | ||
8 | Datasheet: http://www.national.com/pf/LM/LM87.html | ||
9 | |||
10 | Authors: | ||
11 | Frodo Looijaard <frodol@dds.nl>, | ||
12 | Philip Edelbrock <phil@netroedge.com>, | ||
13 | Mark Studebaker <mdsxyz123@yahoo.com>, | ||
14 | Stephen Rousset <stephen.rousset@rocketlogix.com>, | ||
15 | Dan Eaton <dan.eaton@rocketlogix.com>, | ||
16 | Jean Delvare <khali@linux-fr.org>, | ||
17 | Original 2.6 port Jeff Oliver | ||
18 | |||
19 | Description | ||
20 | ----------- | ||
21 | |||
22 | This driver implements support for the National Semiconductor LM87. | ||
23 | |||
24 | The LM87 implements up to three temperature sensors, up to two fan | ||
25 | rotation speed sensors, up to seven voltage sensors, alarms, and some | ||
26 | miscellaneous stuff. | ||
27 | |||
28 | Temperatures are measured in degrees Celsius. Each input has a high | ||
29 | and low alarm settings. A high limit produces an alarm when the value | ||
30 | goes above it, and an alarm is also produced when the value goes below | ||
31 | the low limit. | ||
32 | |||
33 | Fan rotation speeds are reported in RPM (rotations per minute). An alarm is | ||
34 | triggered if the rotation speed has dropped below a programmable limit. Fan | ||
35 | readings can be divided by a programmable divider (1, 2, 4 or 8) to give | ||
36 | the readings more range or accuracy. Not all RPM values can accurately be | ||
37 | represented, so some rounding is done. With a divider of 2, the lowest | ||
38 | representable value is around 2600 RPM. | ||
39 | |||
40 | Voltage sensors (also known as IN sensors) report their values in | ||
41 | volts. An alarm is triggered if the voltage has crossed a programmable | ||
42 | minimum or maximum limit. Note that minimum in this case always means | ||
43 | 'closest to zero'; this is important for negative voltage measurements. | ||
44 | |||
45 | If an alarm triggers, it will remain triggered until the hardware register | ||
46 | is read at least once. This means that the cause for the alarm may | ||
47 | already have disappeared! Note that in the current implementation, all | ||
48 | hardware registers are read whenever any data is read (unless it is less | ||
49 | than 1.0 seconds since the last update). This means that you can easily | ||
50 | miss once-only alarms. | ||
51 | |||
52 | The lm87 driver only updates its values each 1.0 seconds; reading it more | ||
53 | often will do no harm, but will return 'old' values. | ||
54 | |||
55 | |||
56 | Hardware Configurations | ||
57 | ----------------------- | ||
58 | |||
59 | The LM87 has four pins which can serve one of two possible functions, | ||
60 | depending on the hardware configuration. | ||
61 | |||
62 | Some functions share pins, so not all functions are available at the same | ||
63 | time. Which are depends on the hardware setup. This driver assumes that | ||
64 | the BIOS configured the chip correctly. In that respect, it differs from | ||
65 | the original driver (from lm_sensors for Linux 2.4), which would force the | ||
66 | LM87 to an arbitrary, compile-time chosen mode, regardless of the actual | ||
67 | chipset wiring. | ||
68 | |||
69 | For reference, here is the list of exclusive functions: | ||
70 | - in0+in5 (default) or temp3 | ||
71 | - fan1 (default) or in6 | ||
72 | - fan2 (default) or in7 | ||
73 | - VID lines (default) or IRQ lines (not handled by this driver) | ||
diff --git a/Documentation/i2c/chips/lm90 b/Documentation/i2c/chips/lm90 new file mode 100644 index 000000000000..2c4cf39471f4 --- /dev/null +++ b/Documentation/i2c/chips/lm90 | |||
@@ -0,0 +1,121 @@ | |||
1 | Kernel driver lm90 | ||
2 | ================== | ||
3 | |||
4 | Supported chips: | ||
5 | * National Semiconductor LM90 | ||
6 | Prefix: 'lm90' | ||
7 | Addresses scanned: I2C 0x4c | ||
8 | Datasheet: Publicly available at the National Semiconductor website | ||
9 | http://www.national.com/pf/LM/LM90.html | ||
10 | * National Semiconductor LM89 | ||
11 | Prefix: 'lm99' | ||
12 | Addresses scanned: I2C 0x4c and 0x4d | ||
13 | Datasheet: Publicly available at the National Semiconductor website | ||
14 | http://www.national.com/pf/LM/LM89.html | ||
15 | * National Semiconductor LM99 | ||
16 | Prefix: 'lm99' | ||
17 | Addresses scanned: I2C 0x4c and 0x4d | ||
18 | Datasheet: Publicly available at the National Semiconductor website | ||
19 | http://www.national.com/pf/LM/LM99.html | ||
20 | * National Semiconductor LM86 | ||
21 | Prefix: 'lm86' | ||
22 | Addresses scanned: I2C 0x4c | ||
23 | Datasheet: Publicly available at the National Semiconductor website | ||
24 | http://www.national.com/pf/LM/LM86.html | ||
25 | * Analog Devices ADM1032 | ||
26 | Prefix: 'adm1032' | ||
27 | Addresses scanned: I2C 0x4c | ||
28 | Datasheet: Publicly available at the Analog Devices website | ||
29 | http://products.analog.com/products/info.asp?product=ADM1032 | ||
30 | * Analog Devices ADT7461 | ||
31 | Prefix: 'adt7461' | ||
32 | Addresses scanned: I2C 0x4c | ||
33 | Datasheet: Publicly available at the Analog Devices website | ||
34 | http://products.analog.com/products/info.asp?product=ADT7461 | ||
35 | Note: Only if in ADM1032 compatibility mode | ||
36 | * Maxim MAX6657 | ||
37 | Prefix: 'max6657' | ||
38 | Addresses scanned: I2C 0x4c | ||
39 | Datasheet: Publicly available at the Maxim website | ||
40 | http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2578 | ||
41 | * Maxim MAX6658 | ||
42 | Prefix: 'max6657' | ||
43 | Addresses scanned: I2C 0x4c | ||
44 | Datasheet: Publicly available at the Maxim website | ||
45 | http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2578 | ||
46 | * Maxim MAX6659 | ||
47 | Prefix: 'max6657' | ||
48 | Addresses scanned: I2C 0x4c, 0x4d (unsupported 0x4e) | ||
49 | Datasheet: Publicly available at the Maxim website | ||
50 | http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2578 | ||
51 | |||
52 | |||
53 | Author: Jean Delvare <khali@linux-fr.org> | ||
54 | |||
55 | |||
56 | Description | ||
57 | ----------- | ||
58 | |||
59 | The LM90 is a digital temperature sensor. It senses its own temperature as | ||
60 | well as the temperature of up to one external diode. It is compatible | ||
61 | with many other devices such as the LM86, the LM89, the LM99, the ADM1032, | ||
62 | the MAX6657, MAX6658 and the MAX6659 all of which are supported by this driver. | ||
63 | Note that there is no easy way to differentiate between the last three | ||
64 | variants. The extra address and features of the MAX6659 are not supported by | ||
65 | this driver. Additionally, the ADT7461 is supported if found in ADM1032 | ||
66 | compatibility mode. | ||
67 | |||
68 | The specificity of this family of chipsets over the ADM1021/LM84 | ||
69 | family is that it features critical limits with hysteresis, and an | ||
70 | increased resolution of the remote temperature measurement. | ||
71 | |||
72 | The different chipsets of the family are not strictly identical, although | ||
73 | very similar. This driver doesn't handle any specific feature for now, | ||
74 | but could if there ever was a need for it. For reference, here comes a | ||
75 | non-exhaustive list of specific features: | ||
76 | |||
77 | LM90: | ||
78 | * Filter and alert configuration register at 0xBF. | ||
79 | * ALERT is triggered by temperatures over critical limits. | ||
80 | |||
81 | LM86 and LM89: | ||
82 | * Same as LM90 | ||
83 | * Better external channel accuracy | ||
84 | |||
85 | LM99: | ||
86 | * Same as LM89 | ||
87 | * External temperature shifted by 16 degrees down | ||
88 | |||
89 | ADM1032: | ||
90 | * Consecutive alert register at 0x22. | ||
91 | * Conversion averaging. | ||
92 | * Up to 64 conversions/s. | ||
93 | * ALERT is triggered by open remote sensor. | ||
94 | |||
95 | ADT7461 | ||
96 | * Extended temperature range (breaks compatibility) | ||
97 | * Lower resolution for remote temperature | ||
98 | |||
99 | MAX6657 and MAX6658: | ||
100 | * Remote sensor type selection | ||
101 | |||
102 | MAX6659 | ||
103 | * Selectable address | ||
104 | * Second critical temperature limit | ||
105 | * Remote sensor type selection | ||
106 | |||
107 | All temperature values are given in degrees Celsius. Resolution | ||
108 | is 1.0 degree for the local temperature, 0.125 degree for the remote | ||
109 | temperature. | ||
110 | |||
111 | Each sensor has its own high and low limits, plus a critical limit. | ||
112 | Additionally, there is a relative hysteresis value common to both critical | ||
113 | values. To make life easier to user-space applications, two absolute values | ||
114 | are exported, one for each channel, but these values are of course linked. | ||
115 | Only the local hysteresis can be set from user-space, and the same delta | ||
116 | applies to the remote hysteresis. | ||
117 | |||
118 | The lm90 driver will not update its values more frequently than every | ||
119 | other second; reading them more often will do no harm, but will return | ||
120 | 'old' values. | ||
121 | |||
diff --git a/Documentation/i2c/chips/lm92 b/Documentation/i2c/chips/lm92 new file mode 100644 index 000000000000..7705bfaa0708 --- /dev/null +++ b/Documentation/i2c/chips/lm92 | |||
@@ -0,0 +1,37 @@ | |||
1 | Kernel driver lm92 | ||
2 | ================== | ||
3 | |||
4 | Supported chips: | ||
5 | * National Semiconductor LM92 | ||
6 | Prefix: 'lm92' | ||
7 | Addresses scanned: I2C 0x48 - 0x4b | ||
8 | Datasheet: http://www.national.com/pf/LM/LM92.html | ||
9 | * National Semiconductor LM76 | ||
10 | Prefix: 'lm92' | ||
11 | Addresses scanned: none, force parameter needed | ||
12 | Datasheet: http://www.national.com/pf/LM/LM76.html | ||
13 | * Maxim MAX6633/MAX6634/MAX6635 | ||
14 | Prefix: 'lm92' | ||
15 | Addresses scanned: I2C 0x48 - 0x4b | ||
16 | MAX6633 with address in 0x40 - 0x47, 0x4c - 0x4f needs force parameter | ||
17 | and MAX6634 with address in 0x4c - 0x4f needs force parameter | ||
18 | Datasheet: http://www.maxim-ic.com/quick_view2.cfm/qv_pk/3074 | ||
19 | |||
20 | Authors: | ||
21 | Abraham van der Merwe <abraham@2d3d.co.za> | ||
22 | Jean Delvare <khali@linux-fr.org> | ||
23 | |||
24 | |||
25 | Description | ||
26 | ----------- | ||
27 | |||
28 | This driver implements support for the National Semiconductor LM92 | ||
29 | temperature sensor. | ||
30 | |||
31 | Each LM92 temperature sensor supports a single temperature sensor. There are | ||
32 | alarms for high, low, and critical thresholds. There's also an hysteresis to | ||
33 | control the thresholds for resetting alarms. | ||
34 | |||
35 | Support was added later for the LM76 and Maxim MAX6633/MAX6634/MAX6635, | ||
36 | which are mostly compatible. They have not all been tested, so you | ||
37 | may need to use the force parameter. | ||
diff --git a/Documentation/i2c/chips/max1619 b/Documentation/i2c/chips/max1619 new file mode 100644 index 000000000000..d6f8d9cd7d7f --- /dev/null +++ b/Documentation/i2c/chips/max1619 | |||
@@ -0,0 +1,29 @@ | |||
1 | Kernel driver max1619 | ||
2 | ===================== | ||
3 | |||
4 | Supported chips: | ||
5 | * Maxim MAX1619 | ||
6 | Prefix: 'max1619' | ||
7 | Addresses scanned: I2C 0x18-0x1a, 0x29-0x2b, 0x4c-0x4e | ||
8 | Datasheet: Publicly available at the Maxim website | ||
9 | http://pdfserv.maxim-ic.com/en/ds/MAX1619.pdf | ||
10 | |||
11 | Authors: | ||
12 | Alexey Fisher <fishor@mail.ru>, | ||
13 | Jean Delvare <khali@linux-fr.org> | ||
14 | |||
15 | Description | ||
16 | ----------- | ||
17 | |||
18 | The MAX1619 is a digital temperature sensor. It senses its own temperature as | ||
19 | well as the temperature of up to one external diode. | ||
20 | |||
21 | All temperature values are given in degrees Celsius. Resolution | ||
22 | is 1.0 degree for the local temperature and for the remote temperature. | ||
23 | |||
24 | Only the external sensor has high and low limits. | ||
25 | |||
26 | The max1619 driver will not update its values more frequently than every | ||
27 | other second; reading them more often will do no harm, but will return | ||
28 | 'old' values. | ||
29 | |||
diff --git a/Documentation/i2c/chips/max6875 b/Documentation/i2c/chips/max6875 new file mode 100644 index 000000000000..b4fb49b41813 --- /dev/null +++ b/Documentation/i2c/chips/max6875 | |||
@@ -0,0 +1,54 @@ | |||
1 | Kernel driver max6875 | ||
2 | ===================== | ||
3 | |||
4 | Supported chips: | ||
5 | * Maxim max6874, max6875 | ||
6 | Prefixes: 'max6875' | ||
7 | Addresses scanned: 0x50, 0x52 | ||
8 | Datasheets: | ||
9 | http://pdfserv.maxim-ic.com/en/ds/MAX6874-MAX6875.pdf | ||
10 | |||
11 | Author: Ben Gardner <bgardner@wabtec.com> | ||
12 | |||
13 | |||
14 | Module Parameters | ||
15 | ----------------- | ||
16 | |||
17 | * allow_write int | ||
18 | Set to non-zero to enable write permission: | ||
19 | *0: Read only | ||
20 | 1: Read and write | ||
21 | |||
22 | |||
23 | Description | ||
24 | ----------- | ||
25 | |||
26 | The MAXIM max6875 is a EEPROM-programmable power-supply sequencer/supervisor. | ||
27 | It provides timed outputs that can be used as a watchdog, if properly wired. | ||
28 | It also provides 512 bytes of user EEPROM. | ||
29 | |||
30 | At reset, the max6875 reads the configuration eeprom into its configuration | ||
31 | registers. The chip then begins to operate according to the values in the | ||
32 | registers. | ||
33 | |||
34 | See the datasheet for details on how to program the EEPROM. | ||
35 | |||
36 | |||
37 | Sysfs entries | ||
38 | ------------- | ||
39 | |||
40 | eeprom_user - 512 bytes of user-defined EEPROM space. Only writable if | ||
41 | allow_write was set and register 0x43 is 0. | ||
42 | |||
43 | eeprom_config - 70 bytes of config EEPROM. Note that changes will not get | ||
44 | loaded into register space until a power cycle or device reset. | ||
45 | |||
46 | reg_config - 70 bytes of register space. Any changes take affect immediately. | ||
47 | |||
48 | |||
49 | General Remarks | ||
50 | --------------- | ||
51 | |||
52 | A typical application will require that the EEPROMs be programmed once and | ||
53 | never altered afterwards. | ||
54 | |||
diff --git a/Documentation/i2c/chips/pc87360 b/Documentation/i2c/chips/pc87360 new file mode 100644 index 000000000000..89a8fcfa78df --- /dev/null +++ b/Documentation/i2c/chips/pc87360 | |||
@@ -0,0 +1,189 @@ | |||
1 | Kernel driver pc87360 | ||
2 | ===================== | ||
3 | |||
4 | Supported chips: | ||
5 | * National Semiconductor PC87360, PC87363, PC87364, PC87365 and PC87366 | ||
6 | Prefixes: 'pc87360', 'pc87363', 'pc87364', 'pc87365', 'pc87366' | ||
7 | Addresses scanned: none, address read from Super I/O config space | ||
8 | Datasheets: | ||
9 | http://www.national.com/pf/PC/PC87360.html | ||
10 | http://www.national.com/pf/PC/PC87363.html | ||
11 | http://www.national.com/pf/PC/PC87364.html | ||
12 | http://www.national.com/pf/PC/PC87365.html | ||
13 | http://www.national.com/pf/PC/PC87366.html | ||
14 | |||
15 | Authors: Jean Delvare <khali@linux-fr.org> | ||
16 | |||
17 | Thanks to Sandeep Mehta, Tonko de Rooy and Daniel Ceregatti for testing. | ||
18 | Thanks to Rudolf Marek for helping me investigate conversion issues. | ||
19 | |||
20 | |||
21 | Module Parameters | ||
22 | ----------------- | ||
23 | |||
24 | * init int | ||
25 | Chip initialization level: | ||
26 | 0: None | ||
27 | *1: Forcibly enable internal voltage and temperature channels, except in9 | ||
28 | 2: Forcibly enable all voltage and temperature channels, except in9 | ||
29 | 3: Forcibly enable all voltage and temperature channels, including in9 | ||
30 | |||
31 | Note that this parameter has no effect for the PC87360, PC87363 and PC87364 | ||
32 | chips. | ||
33 | |||
34 | Also note that for the PC87366, initialization levels 2 and 3 don't enable | ||
35 | all temperature channels, because some of them share pins with each other, | ||
36 | so they can't be used at the same time. | ||
37 | |||
38 | |||
39 | Description | ||
40 | ----------- | ||
41 | |||
42 | The National Semiconductor PC87360 Super I/O chip contains monitoring and | ||
43 | PWM control circuitry for two fans. The PC87363 chip is similar, and the | ||
44 | PC87364 chip has monitoring and PWM control for a third fan. | ||
45 | |||
46 | The National Semiconductor PC87365 and PC87366 Super I/O chips are complete | ||
47 | hardware monitoring chipsets, not only controlling and monitoring three fans, | ||
48 | but also monitoring eleven voltage inputs and two (PC87365) or up to four | ||
49 | (PC87366) temperatures. | ||
50 | |||
51 | Chip #vin #fan #pwm #temp devid | ||
52 | |||
53 | PC87360 - 2 2 - 0xE1 | ||
54 | PC87363 - 2 2 - 0xE8 | ||
55 | PC87364 - 3 3 - 0xE4 | ||
56 | PC87365 11 3 3 2 0xE5 | ||
57 | PC87366 11 3 3 3-4 0xE9 | ||
58 | |||
59 | The driver assumes that no more than one chip is present, and one of the | ||
60 | standard Super I/O addresses is used (0x2E/0x2F or 0x4E/0x4F) | ||
61 | |||
62 | Fan Monitoring | ||
63 | -------------- | ||
64 | |||
65 | Fan rotation speeds are reported in RPM (revolutions per minute). An alarm | ||
66 | is triggered if the rotation speed has dropped below a programmable limit. | ||
67 | A different alarm is triggered if the fan speed is too low to be measured. | ||
68 | |||
69 | Fan readings are affected by a programmable clock divider, giving the | ||
70 | readings more range or accuracy. Usually, users have to learn how it works, | ||
71 | but this driver implements dynamic clock divider selection, so you don't | ||
72 | have to care no more. | ||
73 | |||
74 | For reference, here are a few values about clock dividers: | ||
75 | |||
76 | slowest accuracy highest | ||
77 | measurable around 3000 accurate | ||
78 | divider speed (RPM) RPM (RPM) speed (RPM) | ||
79 | 1 1882 18 6928 | ||
80 | 2 941 37 4898 | ||
81 | 4 470 74 3464 | ||
82 | 8 235 150 2449 | ||
83 | |||
84 | For the curious, here is how the values above were computed: | ||
85 | * slowest measurable speed: clock/(255*divider) | ||
86 | * accuracy around 3000 RPM: 3000^2/clock | ||
87 | * highest accurate speed: sqrt(clock*100) | ||
88 | The clock speed for the PC87360 family is 480 kHz. I arbitrarily chose 100 | ||
89 | RPM as the lowest acceptable accuracy. | ||
90 | |||
91 | As mentioned above, you don't have to care about this no more. | ||
92 | |||
93 | Note that not all RPM values can be represented, even when the best clock | ||
94 | divider is selected. This is not only true for the measured speeds, but | ||
95 | also for the programmable low limits, so don't be surprised if you try to | ||
96 | set, say, fan1_min to 2900 and it finally reads 2909. | ||
97 | |||
98 | |||
99 | Fan Control | ||
100 | ----------- | ||
101 | |||
102 | PWM (pulse width modulation) values range from 0 to 255, with 0 meaning | ||
103 | that the fan is stopped, and 255 meaning that the fan goes at full speed. | ||
104 | |||
105 | Be extremely careful when changing PWM values. Low PWM values, even | ||
106 | non-zero, can stop the fan, which may cause irreversible damage to your | ||
107 | hardware if temperature increases too much. When changing PWM values, go | ||
108 | step by step and keep an eye on temperatures. | ||
109 | |||
110 | One user reported problems with PWM. Changing PWM values would break fan | ||
111 | speed readings. No explanation nor fix could be found. | ||
112 | |||
113 | |||
114 | Temperature Monitoring | ||
115 | ---------------------- | ||
116 | |||
117 | Temperatures are reported in degrees Celsius. Each temperature measured has | ||
118 | associated low, high and overtemperature limits, each of which triggers an | ||
119 | alarm when crossed. | ||
120 | |||
121 | The first two temperature channels are external. The third one (PC87366 | ||
122 | only) is internal. | ||
123 | |||
124 | The PC87366 has three additional temperature channels, based on | ||
125 | thermistors (as opposed to thermal diodes for the first three temperature | ||
126 | channels). For technical reasons, these channels are held by the VLM | ||
127 | (voltage level monitor) logical device, not the TMS (temperature | ||
128 | measurement) one. As a consequence, these temperatures are exported as | ||
129 | voltages, and converted into temperatures in user-space. | ||
130 | |||
131 | Note that these three additional channels share their pins with the | ||
132 | external thermal diode channels, so you (physically) can't use them all at | ||
133 | the same time. Although it should be possible to mix the two sensor types, | ||
134 | the documents from National Semiconductor suggest that motherboard | ||
135 | manufacturers should choose one type and stick to it. So you will more | ||
136 | likely have either channels 1 to 3 (thermal diodes) or 3 to 6 (internal | ||
137 | thermal diode, and thermistors). | ||
138 | |||
139 | |||
140 | Voltage Monitoring | ||
141 | ------------------ | ||
142 | |||
143 | Voltages are reported relatively to a reference voltage, either internal or | ||
144 | external. Some of them (in7:Vsb, in8:Vdd and in10:AVdd) are divided by two | ||
145 | internally, you will have to compensate in sensors.conf. Others (in0 to in6) | ||
146 | are likely to be divided externally. The meaning of each of these inputs as | ||
147 | well as the values of the resistors used for division is left to the | ||
148 | motherboard manufacturers, so you will have to document yourself and edit | ||
149 | sensors.conf accordingly. National Semiconductor has a document with | ||
150 | recommended resistor values for some voltages, but this still leaves much | ||
151 | room for per motherboard specificities, unfortunately. Even worse, | ||
152 | motherboard manufacturers don't seem to care about National Semiconductor's | ||
153 | recommendations. | ||
154 | |||
155 | Each voltage measured has associated low and high limits, each of which | ||
156 | triggers an alarm when crossed. | ||
157 | |||
158 | When available, VID inputs are used to provide the nominal CPU Core voltage. | ||
159 | The driver will default to VRM 9.0, but this can be changed from user-space. | ||
160 | The chipsets can handle two sets of VID inputs (on dual-CPU systems), but | ||
161 | the driver will only export one for now. This may change later if there is | ||
162 | a need. | ||
163 | |||
164 | |||
165 | General Remarks | ||
166 | --------------- | ||
167 | |||
168 | If an alarm triggers, it will remain triggered until the hardware register | ||
169 | is read at least once. This means that the cause for the alarm may already | ||
170 | have disappeared! Note that all hardware registers are read whenever any | ||
171 | data is read (unless it is less than 2 seconds since the last update, in | ||
172 | which case cached values are returned instead). As a consequence, when | ||
173 | a once-only alarm triggers, it may take 2 seconds for it to show, and 2 | ||
174 | more seconds for it to disappear. | ||
175 | |||
176 | Monitoring of in9 isn't enabled at lower init levels (<3) because that | ||
177 | channel measures the battery voltage (Vbat). It is a known fact that | ||
178 | repeatedly sampling the battery voltage reduces its lifetime. National | ||
179 | Semiconductor smartly designed their chipset so that in9 is sampled only | ||
180 | once every 1024 sampling cycles (that is every 34 minutes at the default | ||
181 | sampling rate), so the effect is attenuated, but still present. | ||
182 | |||
183 | |||
184 | Limitations | ||
185 | ----------- | ||
186 | |||
187 | The datasheets suggests that some values (fan mins, fan dividers) | ||
188 | shouldn't be changed once the monitoring has started, but we ignore that | ||
189 | recommendation. We'll reconsider if it actually causes trouble. | ||
diff --git a/Documentation/i2c/chips/pca9539 b/Documentation/i2c/chips/pca9539 new file mode 100644 index 000000000000..c4fce6a13537 --- /dev/null +++ b/Documentation/i2c/chips/pca9539 | |||
@@ -0,0 +1,47 @@ | |||
1 | Kernel driver pca9539 | ||
2 | ===================== | ||
3 | |||
4 | Supported chips: | ||
5 | * Philips PCA9539 | ||
6 | Prefix: 'pca9539' | ||
7 | Addresses scanned: 0x74 - 0x77 | ||
8 | Datasheet: | ||
9 | http://www.semiconductors.philips.com/acrobat/datasheets/PCA9539_2.pdf | ||
10 | |||
11 | Author: Ben Gardner <bgardner@wabtec.com> | ||
12 | |||
13 | |||
14 | Description | ||
15 | ----------- | ||
16 | |||
17 | The Philips PCA9539 is a 16 bit low power I/O device. | ||
18 | All 16 lines can be individually configured as an input or output. | ||
19 | The input sense can also be inverted. | ||
20 | The 16 lines are split between two bytes. | ||
21 | |||
22 | |||
23 | Sysfs entries | ||
24 | ------------- | ||
25 | |||
26 | Each is a byte that maps to the 8 I/O bits. | ||
27 | A '0' suffix is for bits 0-7, while '1' is for bits 8-15. | ||
28 | |||
29 | input[01] - read the current value | ||
30 | output[01] - sets the output value | ||
31 | direction[01] - direction of each bit: 1=input, 0=output | ||
32 | invert[01] - toggle the input bit sense | ||
33 | |||
34 | input reads the actual state of the line and is always available. | ||
35 | The direction defaults to input for all channels. | ||
36 | |||
37 | |||
38 | General Remarks | ||
39 | --------------- | ||
40 | |||
41 | Note that each output, direction, and invert entry controls 8 lines. | ||
42 | You should use the read, modify, write sequence. | ||
43 | For example. to set output bit 0 of 1. | ||
44 | val=$(cat output0) | ||
45 | val=$(( $val | 1 )) | ||
46 | echo $val > output0 | ||
47 | |||
diff --git a/Documentation/i2c/chips/pcf8574 b/Documentation/i2c/chips/pcf8574 new file mode 100644 index 000000000000..2752c8ce3167 --- /dev/null +++ b/Documentation/i2c/chips/pcf8574 | |||
@@ -0,0 +1,69 @@ | |||
1 | Kernel driver pcf8574 | ||
2 | ===================== | ||
3 | |||
4 | Supported chips: | ||
5 | * Philips PCF8574 | ||
6 | Prefix: 'pcf8574' | ||
7 | Addresses scanned: I2C 0x20 - 0x27 | ||
8 | Datasheet: Publicly available at the Philips Semiconductors website | ||
9 | http://www.semiconductors.philips.com/pip/PCF8574P.html | ||
10 | |||
11 | * Philips PCF8574A | ||
12 | Prefix: 'pcf8574a' | ||
13 | Addresses scanned: I2C 0x38 - 0x3f | ||
14 | Datasheet: Publicly available at the Philips Semiconductors website | ||
15 | http://www.semiconductors.philips.com/pip/PCF8574P.html | ||
16 | |||
17 | Authors: | ||
18 | Frodo Looijaard <frodol@dds.nl>, | ||
19 | Philip Edelbrock <phil@netroedge.com>, | ||
20 | Dan Eaton <dan.eaton@rocketlogix.com>, | ||
21 | Aurelien Jarno <aurelien@aurel32.net>, | ||
22 | Jean Delvare <khali@linux-fr.org>, | ||
23 | |||
24 | |||
25 | Description | ||
26 | ----------- | ||
27 | The PCF8574(A) is an 8-bit I/O expander for the I2C bus produced by Philips | ||
28 | Semiconductors. It is designed to provide a byte I2C interface to up to 16 | ||
29 | separate devices (8 x PCF8574 and 8 x PCF8574A). | ||
30 | |||
31 | This device consists of a quasi-bidirectional port. Each of the eight I/Os | ||
32 | can be independently used as an input or output. To setup an I/O as an | ||
33 | input, you have to write a 1 to the corresponding output. | ||
34 | |||
35 | For more informations see the datasheet. | ||
36 | |||
37 | |||
38 | Accessing PCF8574(A) via /sys interface | ||
39 | ------------------------------------- | ||
40 | |||
41 | ! Be careful ! | ||
42 | The PCF8574(A) is plainly impossible to detect ! Stupid chip. | ||
43 | So every chip with address in the interval [20..27] and [38..3f] are | ||
44 | detected as PCF8574(A). If you have other chips in this address | ||
45 | range, the workaround is to load this module after the one | ||
46 | for your others chips. | ||
47 | |||
48 | On detection (i.e. insmod, modprobe et al.), directories are being | ||
49 | created for each detected PCF8574(A): | ||
50 | |||
51 | /sys/bus/i2c/devices/<0>-<1>/ | ||
52 | where <0> is the bus the chip was detected on (e. g. i2c-0) | ||
53 | and <1> the chip address ([20..27] or [38..3f]): | ||
54 | |||
55 | (example: /sys/bus/i2c/devices/1-0020/) | ||
56 | |||
57 | Inside these directories, there are two files each: | ||
58 | read and write (and one file with chip name). | ||
59 | |||
60 | The read file is read-only. Reading gives you the current I/O input | ||
61 | if the corresponding output is set as 1, otherwise the current output | ||
62 | value, that is to say 0. | ||
63 | |||
64 | The write file is read/write. Writing a value outputs it on the I/O | ||
65 | port. Reading returns the last written value. | ||
66 | |||
67 | On module initialization the chip is configured as eight inputs (all | ||
68 | outputs to 1), so you can connect any circuit to the PCF8574(A) without | ||
69 | being afraid of short-circuit. | ||
diff --git a/Documentation/i2c/chips/pcf8591 b/Documentation/i2c/chips/pcf8591 new file mode 100644 index 000000000000..5628fcf4207f --- /dev/null +++ b/Documentation/i2c/chips/pcf8591 | |||
@@ -0,0 +1,90 @@ | |||
1 | Kernel driver pcf8591 | ||
2 | ===================== | ||
3 | |||
4 | Supported chips: | ||
5 | * Philips PCF8591 | ||
6 | Prefix: 'pcf8591' | ||
7 | Addresses scanned: I2C 0x48 - 0x4f | ||
8 | Datasheet: Publicly available at the Philips Semiconductor website | ||
9 | http://www.semiconductors.philips.com/pip/PCF8591P.html | ||
10 | |||
11 | Authors: | ||
12 | Aurelien Jarno <aurelien@aurel32.net> | ||
13 | valuable contributions by Jan M. Sendler <sendler@sendler.de>, | ||
14 | Jean Delvare <khali@linux-fr.org> | ||
15 | |||
16 | |||
17 | Description | ||
18 | ----------- | ||
19 | The PCF8591 is an 8-bit A/D and D/A converter (4 analog inputs and one | ||
20 | analog output) for the I2C bus produced by Philips Semiconductors. It | ||
21 | is designed to provide a byte I2C interface to up to 4 separate devices. | ||
22 | |||
23 | The PCF8591 has 4 analog inputs programmable as single-ended or | ||
24 | differential inputs : | ||
25 | - mode 0 : four single ended inputs | ||
26 | Pins AIN0 to AIN3 are single ended inputs for channels 0 to 3 | ||
27 | |||
28 | - mode 1 : three differential inputs | ||
29 | Pins AIN3 is the common negative differential input | ||
30 | Pins AIN0 to AIN2 are positive differential inputs for channels 0 to 2 | ||
31 | |||
32 | - mode 2 : single ended and differential mixed | ||
33 | Pins AIN0 and AIN1 are single ended inputs for channels 0 and 1 | ||
34 | Pins AIN2 is the positive differential input for channel 3 | ||
35 | Pins AIN3 is the negative differential input for channel 3 | ||
36 | |||
37 | - mode 3 : two differential inputs | ||
38 | Pins AIN0 is the positive differential input for channel 0 | ||
39 | Pins AIN1 is the negative differential input for channel 0 | ||
40 | Pins AIN2 is the positive differential input for channel 1 | ||
41 | Pins AIN3 is the negative differential input for channel 1 | ||
42 | |||
43 | See the datasheet for details. | ||
44 | |||
45 | Module parameters | ||
46 | ----------------- | ||
47 | |||
48 | * input_mode int | ||
49 | |||
50 | Analog input mode: | ||
51 | 0 = four single ended inputs | ||
52 | 1 = three differential inputs | ||
53 | 2 = single ended and differential mixed | ||
54 | 3 = two differential inputs | ||
55 | |||
56 | |||
57 | Accessing PCF8591 via /sys interface | ||
58 | ------------------------------------- | ||
59 | |||
60 | ! Be careful ! | ||
61 | The PCF8591 is plainly impossible to detect ! Stupid chip. | ||
62 | So every chip with address in the interval [48..4f] is | ||
63 | detected as PCF8591. If you have other chips in this address | ||
64 | range, the workaround is to load this module after the one | ||
65 | for your others chips. | ||
66 | |||
67 | On detection (i.e. insmod, modprobe et al.), directories are being | ||
68 | created for each detected PCF8591: | ||
69 | |||
70 | /sys/bus/devices/<0>-<1>/ | ||
71 | where <0> is the bus the chip was detected on (e. g. i2c-0) | ||
72 | and <1> the chip address ([48..4f]) | ||
73 | |||
74 | Inside these directories, there are such files: | ||
75 | in0, in1, in2, in3, out0_enable, out0_output, name | ||
76 | |||
77 | Name contains chip name. | ||
78 | |||
79 | The in0, in1, in2 and in3 files are RO. Reading gives the value of the | ||
80 | corresponding channel. Depending on the current analog inputs configuration, | ||
81 | files in2 and/or in3 do not exist. Values range are from 0 to 255 for single | ||
82 | ended inputs and -128 to +127 for differential inputs (8-bit ADC). | ||
83 | |||
84 | The out0_enable file is RW. Reading gives "1" for analog output enabled and | ||
85 | "0" for analog output disabled. Writing accepts "0" and "1" accordingly. | ||
86 | |||
87 | The out0_output file is RW. Writing a number between 0 and 255 (8-bit DAC), send | ||
88 | the value to the digital-to-analog converter. Note that a voltage will | ||
89 | only appears on AOUT pin if aout0_enable equals 1. Reading returns the last | ||
90 | value written. | ||
diff --git a/Documentation/i2c/chips/sis5595 b/Documentation/i2c/chips/sis5595 new file mode 100644 index 000000000000..b7ae36b8cdf5 --- /dev/null +++ b/Documentation/i2c/chips/sis5595 | |||
@@ -0,0 +1,106 @@ | |||
1 | Kernel driver sis5595 | ||
2 | ===================== | ||
3 | |||
4 | Supported chips: | ||
5 | * Silicon Integrated Systems Corp. SiS5595 Southbridge Hardware Monitor | ||
6 | Prefix: 'sis5595' | ||
7 | Addresses scanned: ISA in PCI-space encoded address | ||
8 | Datasheet: Publicly available at the Silicon Integrated Systems Corp. site. | ||
9 | |||
10 | Authors: | ||
11 | Kyösti Mälkki <kmalkki@cc.hut.fi>, | ||
12 | Mark D. Studebaker <mdsxyz123@yahoo.com>, | ||
13 | Aurelien Jarno <aurelien@aurel32.net> 2.6 port | ||
14 | |||
15 | SiS southbridge has a LM78-like chip integrated on the same IC. | ||
16 | This driver is a customized copy of lm78.c | ||
17 | |||
18 | Supports following revisions: | ||
19 | Version PCI ID PCI Revision | ||
20 | 1 1039/0008 AF or less | ||
21 | 2 1039/0008 B0 or greater | ||
22 | |||
23 | Note: these chips contain a 0008 device which is incompatible with the | ||
24 | 5595. We recognize these by the presence of the listed | ||
25 | "blacklist" PCI ID and refuse to load. | ||
26 | |||
27 | NOT SUPPORTED PCI ID BLACKLIST PCI ID | ||
28 | 540 0008 0540 | ||
29 | 550 0008 0550 | ||
30 | 5513 0008 5511 | ||
31 | 5581 0008 5597 | ||
32 | 5582 0008 5597 | ||
33 | 5597 0008 5597 | ||
34 | 630 0008 0630 | ||
35 | 645 0008 0645 | ||
36 | 730 0008 0730 | ||
37 | 735 0008 0735 | ||
38 | |||
39 | |||
40 | Module Parameters | ||
41 | ----------------- | ||
42 | force_addr=0xaddr Set the I/O base address. Useful for boards | ||
43 | that don't set the address in the BIOS. Does not do a | ||
44 | PCI force; the device must still be present in lspci. | ||
45 | Don't use this unless the driver complains that the | ||
46 | base address is not set. | ||
47 | Example: 'modprobe sis5595 force_addr=0x290' | ||
48 | |||
49 | |||
50 | Description | ||
51 | ----------- | ||
52 | |||
53 | The SiS5595 southbridge has integrated hardware monitor functions. It also | ||
54 | has an I2C bus, but this driver only supports the hardware monitor. For the | ||
55 | I2C bus driver see i2c-sis5595. | ||
56 | |||
57 | The SiS5595 implements zero or one temperature sensor, two fan speed | ||
58 | sensors, four or five voltage sensors, and alarms. | ||
59 | |||
60 | On the first version of the chip, there are four voltage sensors and one | ||
61 | temperature sensor. | ||
62 | |||
63 | On the second version of the chip, the temperature sensor (temp) and the | ||
64 | fifth voltage sensor (in4) share a pin which is configurable, but not | ||
65 | through the driver. Sorry. The driver senses the configuration of the pin, | ||
66 | which was hopefully set by the BIOS. | ||
67 | |||
68 | Temperatures are measured in degrees Celsius. An alarm is triggered once | ||
69 | when the max is crossed; it is also triggered when it drops below the min | ||
70 | value. Measurements are guaranteed between -55 and +125 degrees, with a | ||
71 | resolution of 1 degree. | ||
72 | |||
73 | Fan rotation speeds are reported in RPM (rotations per minute). An alarm is | ||
74 | triggered if the rotation speed has dropped below a programmable limit. Fan | ||
75 | readings can be divided by a programmable divider (1, 2, 4 or 8) to give | ||
76 | the readings more range or accuracy. Not all RPM values can accurately be | ||
77 | represented, so some rounding is done. With a divider of 2, the lowest | ||
78 | representable value is around 2600 RPM. | ||
79 | |||
80 | Voltage sensors (also known as IN sensors) report their values in volts. An | ||
81 | alarm is triggered if the voltage has crossed a programmable minimum or | ||
82 | maximum limit. Note that minimum in this case always means 'closest to | ||
83 | zero'; this is important for negative voltage measurements. All voltage | ||
84 | inputs can measure voltages between 0 and 4.08 volts, with a resolution of | ||
85 | 0.016 volt. | ||
86 | |||
87 | In addition to the alarms described above, there is a BTI alarm, which gets | ||
88 | triggered when an external chip has crossed its limits. Usually, this is | ||
89 | connected to some LM75-like chip; if at least one crosses its limits, this | ||
90 | bit gets set. | ||
91 | |||
92 | If an alarm triggers, it will remain triggered until the hardware register | ||
93 | is read at least once. This means that the cause for the alarm may already | ||
94 | have disappeared! Note that in the current implementation, all hardware | ||
95 | registers are read whenever any data is read (unless it is less than 1.5 | ||
96 | seconds since the last update). This means that you can easily miss | ||
97 | once-only alarms. | ||
98 | |||
99 | The SiS5595 only updates its values each 1.5 seconds; reading it more often | ||
100 | will do no harm, but will return 'old' values. | ||
101 | |||
102 | Problems | ||
103 | -------- | ||
104 | Some chips refuse to be enabled. We don't know why. | ||
105 | The driver will recognize this and print a message in dmesg. | ||
106 | |||
diff --git a/Documentation/i2c/chips/smsc47b397.txt b/Documentation/i2c/chips/smsc47b397 index 389edae7f8df..da9d80c96432 100644 --- a/Documentation/i2c/chips/smsc47b397.txt +++ b/Documentation/i2c/chips/smsc47b397 | |||
@@ -1,7 +1,19 @@ | |||
1 | Kernel driver smsc47b397 | ||
2 | ======================== | ||
3 | |||
4 | Supported chips: | ||
5 | * SMSC LPC47B397-NC | ||
6 | Prefix: 'smsc47b397' | ||
7 | Addresses scanned: none, address read from Super I/O config space | ||
8 | Datasheet: In this file | ||
9 | |||
10 | Authors: Mark M. Hoffman <mhoffman@lightlink.com> | ||
11 | Utilitek Systems, Inc. | ||
12 | |||
1 | November 23, 2004 | 13 | November 23, 2004 |
2 | 14 | ||
3 | The following specification describes the SMSC LPC47B397-NC sensor chip | 15 | The following specification describes the SMSC LPC47B397-NC sensor chip |
4 | (for which there is no public datasheet available). This document was | 16 | (for which there is no public datasheet available). This document was |
5 | provided by Craig Kelly (In-Store Broadcast Network) and edited/corrected | 17 | provided by Craig Kelly (In-Store Broadcast Network) and edited/corrected |
6 | by Mark M. Hoffman <mhoffman@lightlink.com>. | 18 | by Mark M. Hoffman <mhoffman@lightlink.com>. |
7 | 19 | ||
@@ -10,10 +22,10 @@ by Mark M. Hoffman <mhoffman@lightlink.com>. | |||
10 | Methods for detecting the HP SIO and reading the thermal data on a dc7100. | 22 | Methods for detecting the HP SIO and reading the thermal data on a dc7100. |
11 | 23 | ||
12 | The thermal information on the dc7100 is contained in the SIO Hardware Monitor | 24 | The thermal information on the dc7100 is contained in the SIO Hardware Monitor |
13 | (HWM). The information is accessed through an index/data pair. The index/data | 25 | (HWM). The information is accessed through an index/data pair. The index/data |
14 | pair is located at the HWM Base Address + 0 and the HWM Base Address + 1. The | 26 | pair is located at the HWM Base Address + 0 and the HWM Base Address + 1. The |
15 | HWM Base address can be obtained from Logical Device 8, registers 0x60 (MSB) | 27 | HWM Base address can be obtained from Logical Device 8, registers 0x60 (MSB) |
16 | and 0x61 (LSB). Currently we are using 0x480 for the HWM Base Address and | 28 | and 0x61 (LSB). Currently we are using 0x480 for the HWM Base Address and |
17 | 0x480 and 0x481 for the index/data pair. | 29 | 0x480 and 0x481 for the index/data pair. |
18 | 30 | ||
19 | Reading temperature information. | 31 | Reading temperature information. |
@@ -50,7 +62,7 @@ Reading the tach LSB locks the tach MSB. | |||
50 | The LSB Must be read first. | 62 | The LSB Must be read first. |
51 | 63 | ||
52 | How to convert the tach reading to RPM. | 64 | How to convert the tach reading to RPM. |
53 | The tach reading (TCount) is given by: (Tach MSB * 256) + (Tach LSB) | 65 | The tach reading (TCount) is given by: (Tach MSB * 256) + (Tach LSB) |
54 | The SIO counts the number of 90kHz (11.111us) pulses per revolution. | 66 | The SIO counts the number of 90kHz (11.111us) pulses per revolution. |
55 | RPM = 60/(TCount * 11.111us) | 67 | RPM = 60/(TCount * 11.111us) |
56 | 68 | ||
@@ -72,20 +84,20 @@ To program the configuration registers, the following sequence must be followed: | |||
72 | 84 | ||
73 | Enter Configuration Mode | 85 | Enter Configuration Mode |
74 | To place the chip into the Configuration State The config key (0x55) is written | 86 | To place the chip into the Configuration State The config key (0x55) is written |
75 | to the CONFIG PORT (0x2E). | 87 | to the CONFIG PORT (0x2E). |
76 | 88 | ||
77 | Configuration Mode | 89 | Configuration Mode |
78 | In configuration mode, the INDEX PORT is located at the CONFIG PORT address and | 90 | In configuration mode, the INDEX PORT is located at the CONFIG PORT address and |
79 | the DATA PORT is at INDEX PORT address + 1. | 91 | the DATA PORT is at INDEX PORT address + 1. |
80 | 92 | ||
81 | The desired configuration registers are accessed in two steps: | 93 | The desired configuration registers are accessed in two steps: |
82 | a. Write the index of the Logical Device Number Configuration Register | 94 | a. Write the index of the Logical Device Number Configuration Register |
83 | (i.e., 0x07) to the INDEX PORT and then write the number of the | 95 | (i.e., 0x07) to the INDEX PORT and then write the number of the |
84 | desired logical device to the DATA PORT. | 96 | desired logical device to the DATA PORT. |
85 | 97 | ||
86 | b. Write the address of the desired configuration register within the | 98 | b. Write the address of the desired configuration register within the |
87 | logical device to the INDEX PORT and then write or read the config- | 99 | logical device to the INDEX PORT and then write or read the config- |
88 | uration register through the DATA PORT. | 100 | uration register through the DATA PORT. |
89 | 101 | ||
90 | Note: If accessing the Global Configuration Registers, step (a) is not required. | 102 | Note: If accessing the Global Configuration Registers, step (a) is not required. |
91 | 103 | ||
@@ -96,18 +108,18 @@ The chip returns to the RUN State. (This is important). | |||
96 | Programming Example | 108 | Programming Example |
97 | The following is an example of how to read the SIO Device ID located at 0x20 | 109 | The following is an example of how to read the SIO Device ID located at 0x20 |
98 | 110 | ||
99 | ; ENTER CONFIGURATION MODE | 111 | ; ENTER CONFIGURATION MODE |
100 | MOV DX,02EH | 112 | MOV DX,02EH |
101 | MOV AX,055H | 113 | MOV AX,055H |
102 | OUT DX,AL | 114 | OUT DX,AL |
103 | ; GLOBAL CONFIGURATION REGISTER | 115 | ; GLOBAL CONFIGURATION REGISTER |
104 | MOV DX,02EH | 116 | MOV DX,02EH |
105 | MOV AL,20H | 117 | MOV AL,20H |
106 | OUT DX,AL | 118 | OUT DX,AL |
107 | ; READ THE DATA | 119 | ; READ THE DATA |
108 | MOV DX,02FH | 120 | MOV DX,02FH |
109 | IN AL,DX | 121 | IN AL,DX |
110 | ; EXIT CONFIGURATION MODE | 122 | ; EXIT CONFIGURATION MODE |
111 | MOV DX,02EH | 123 | MOV DX,02EH |
112 | MOV AX,0AAH | 124 | MOV AX,0AAH |
113 | OUT DX,AL | 125 | OUT DX,AL |
@@ -122,12 +134,12 @@ Obtaining the HWM Base Address. | |||
122 | The following is an example of how to read the HWM Base Address located in | 134 | The following is an example of how to read the HWM Base Address located in |
123 | Logical Device 8. | 135 | Logical Device 8. |
124 | 136 | ||
125 | ; ENTER CONFIGURATION MODE | 137 | ; ENTER CONFIGURATION MODE |
126 | MOV DX,02EH | 138 | MOV DX,02EH |
127 | MOV AX,055H | 139 | MOV AX,055H |
128 | OUT DX,AL | 140 | OUT DX,AL |
129 | ; CONFIGURE REGISTER CRE0, | 141 | ; CONFIGURE REGISTER CRE0, |
130 | ; LOGICAL DEVICE 8 | 142 | ; LOGICAL DEVICE 8 |
131 | MOV DX,02EH | 143 | MOV DX,02EH |
132 | MOV AL,07H | 144 | MOV AL,07H |
133 | OUT DX,AL ;Point to LD# Config Reg | 145 | OUT DX,AL ;Point to LD# Config Reg |
@@ -135,12 +147,12 @@ MOV DX,02FH | |||
135 | MOV AL, 08H | 147 | MOV AL, 08H |
136 | OUT DX,AL;Point to Logical Device 8 | 148 | OUT DX,AL;Point to Logical Device 8 |
137 | ; | 149 | ; |
138 | MOV DX,02EH | 150 | MOV DX,02EH |
139 | MOV AL,60H | 151 | MOV AL,60H |
140 | OUT DX,AL ; Point to HWM Base Addr MSB | 152 | OUT DX,AL ; Point to HWM Base Addr MSB |
141 | MOV DX,02FH | 153 | MOV DX,02FH |
142 | IN AL,DX ; Get MSB of HWM Base Addr | 154 | IN AL,DX ; Get MSB of HWM Base Addr |
143 | ; EXIT CONFIGURATION MODE | 155 | ; EXIT CONFIGURATION MODE |
144 | MOV DX,02EH | 156 | MOV DX,02EH |
145 | MOV AX,0AAH | 157 | MOV AX,0AAH |
146 | OUT DX,AL | 158 | OUT DX,AL |
diff --git a/Documentation/i2c/chips/smsc47m1 b/Documentation/i2c/chips/smsc47m1 new file mode 100644 index 000000000000..34e6478c1425 --- /dev/null +++ b/Documentation/i2c/chips/smsc47m1 | |||
@@ -0,0 +1,52 @@ | |||
1 | Kernel driver smsc47m1 | ||
2 | ====================== | ||
3 | |||
4 | Supported chips: | ||
5 | * SMSC LPC47B27x, LPC47M10x, LPC47M13x, LPC47M14x, LPC47M15x and LPC47M192 | ||
6 | Addresses scanned: none, address read from Super I/O config space | ||
7 | Prefix: 'smsc47m1' | ||
8 | Datasheets: | ||
9 | http://www.smsc.com/main/datasheets/47b27x.pdf | ||
10 | http://www.smsc.com/main/datasheets/47m10x.pdf | ||
11 | http://www.smsc.com/main/tools/discontinued/47m13x.pdf | ||
12 | http://www.smsc.com/main/datasheets/47m14x.pdf | ||
13 | http://www.smsc.com/main/tools/discontinued/47m15x.pdf | ||
14 | http://www.smsc.com/main/datasheets/47m192.pdf | ||
15 | |||
16 | Authors: | ||
17 | Mark D. Studebaker <mdsxyz123@yahoo.com>, | ||
18 | With assistance from Bruce Allen <ballen@uwm.edu>, and his | ||
19 | fan.c program: http://www.lsc-group.phys.uwm.edu/%7Eballen/driver/ | ||
20 | Gabriele Gorla <gorlik@yahoo.com>, | ||
21 | Jean Delvare <khali@linux-fr.org> | ||
22 | |||
23 | Description | ||
24 | ----------- | ||
25 | |||
26 | The Standard Microsystems Corporation (SMSC) 47M1xx Super I/O chips | ||
27 | contain monitoring and PWM control circuitry for two fans. | ||
28 | |||
29 | The 47M15x and 47M192 chips contain a full 'hardware monitoring block' | ||
30 | in addition to the fan monitoring and control. The hardware monitoring | ||
31 | block is not supported by the driver. | ||
32 | |||
33 | Fan rotation speeds are reported in RPM (rotations per minute). An alarm is | ||
34 | triggered if the rotation speed has dropped below a programmable limit. Fan | ||
35 | readings can be divided by a programmable divider (1, 2, 4 or 8) to give | ||
36 | the readings more range or accuracy. Not all RPM values can accurately be | ||
37 | represented, so some rounding is done. With a divider of 2, the lowest | ||
38 | representable value is around 2600 RPM. | ||
39 | |||
40 | PWM values are from 0 to 255. | ||
41 | |||
42 | If an alarm triggers, it will remain triggered until the hardware register | ||
43 | is read at least once. This means that the cause for the alarm may | ||
44 | already have disappeared! Note that in the current implementation, all | ||
45 | hardware registers are read whenever any data is read (unless it is less | ||
46 | than 1.5 seconds since the last update). This means that you can easily | ||
47 | miss once-only alarms. | ||
48 | |||
49 | |||
50 | ********************** | ||
51 | The lm_sensors project gratefully acknowledges the support of | ||
52 | Intel in the development of this driver. | ||
diff --git a/Documentation/i2c/chips/via686a b/Documentation/i2c/chips/via686a new file mode 100644 index 000000000000..b82014cb7c53 --- /dev/null +++ b/Documentation/i2c/chips/via686a | |||
@@ -0,0 +1,65 @@ | |||
1 | Kernel driver via686a | ||
2 | ===================== | ||
3 | |||
4 | Supported chips: | ||
5 | * Via VT82C686A, VT82C686B Southbridge Integrated Hardware Monitor | ||
6 | Prefix: 'via686a' | ||
7 | Addresses scanned: ISA in PCI-space encoded address | ||
8 | Datasheet: On request through web form (http://www.via.com.tw/en/support/datasheets/) | ||
9 | |||
10 | Authors: | ||
11 | Kyösti Mälkki <kmalkki@cc.hut.fi>, | ||
12 | Mark D. Studebaker <mdsxyz123@yahoo.com> | ||
13 | Bob Dougherty <bobd@stanford.edu> | ||
14 | (Some conversion-factor data were contributed by | ||
15 | Jonathan Teh Soon Yew <j.teh@iname.com> | ||
16 | and Alex van Kaam <darkside@chello.nl>.) | ||
17 | |||
18 | Module Parameters | ||
19 | ----------------- | ||
20 | |||
21 | force_addr=0xaddr Set the I/O base address. Useful for Asus A7V boards | ||
22 | that don't set the address in the BIOS. Does not do a | ||
23 | PCI force; the via686a must still be present in lspci. | ||
24 | Don't use this unless the driver complains that the | ||
25 | base address is not set. | ||
26 | Example: 'modprobe via686a force_addr=0x6000' | ||
27 | |||
28 | Description | ||
29 | ----------- | ||
30 | |||
31 | The driver does not distinguish between the chips and reports | ||
32 | all as a 686A. | ||
33 | |||
34 | The Via 686a southbridge has integrated hardware monitor functionality. | ||
35 | It also has an I2C bus, but this driver only supports the hardware monitor. | ||
36 | For the I2C bus driver, see <file:Documentation/i2c/busses/i2c-viapro> | ||
37 | |||
38 | The Via 686a implements three temperature sensors, two fan rotation speed | ||
39 | sensors, five voltage sensors and alarms. | ||
40 | |||
41 | Temperatures are measured in degrees Celsius. An alarm is triggered once | ||
42 | when the Overtemperature Shutdown limit is crossed; it is triggered again | ||
43 | as soon as it drops below the hysteresis value. | ||
44 | |||
45 | Fan rotation speeds are reported in RPM (rotations per minute). An alarm is | ||
46 | triggered if the rotation speed has dropped below a programmable limit. Fan | ||
47 | readings can be divided by a programmable divider (1, 2, 4 or 8) to give | ||
48 | the readings more range or accuracy. Not all RPM values can accurately be | ||
49 | represented, so some rounding is done. With a divider of 2, the lowest | ||
50 | representable value is around 2600 RPM. | ||
51 | |||
52 | Voltage sensors (also known as IN sensors) report their values in volts. | ||
53 | An alarm is triggered if the voltage has crossed a programmable minimum | ||
54 | or maximum limit. Voltages are internally scalled, so each voltage channel | ||
55 | has a different resolution and range. | ||
56 | |||
57 | If an alarm triggers, it will remain triggered until the hardware register | ||
58 | is read at least once. This means that the cause for the alarm may | ||
59 | already have disappeared! Note that in the current implementation, all | ||
60 | hardware registers are read whenever any data is read (unless it is less | ||
61 | than 1.5 seconds since the last update). This means that you can easily | ||
62 | miss once-only alarms. | ||
63 | |||
64 | The driver only updates its values each 1.5 seconds; reading it more often | ||
65 | will do no harm, but will return 'old' values. | ||
diff --git a/Documentation/i2c/chips/w83627hf b/Documentation/i2c/chips/w83627hf new file mode 100644 index 000000000000..78f37c2d602e --- /dev/null +++ b/Documentation/i2c/chips/w83627hf | |||
@@ -0,0 +1,66 @@ | |||
1 | Kernel driver w83627hf | ||
2 | ====================== | ||
3 | |||
4 | Supported chips: | ||
5 | * Winbond W83627HF (ISA accesses ONLY) | ||
6 | Prefix: 'w83627hf' | ||
7 | Addresses scanned: ISA address retrieved from Super I/O registers | ||
8 | Datasheet: http://www.winbond.com/PDF/sheet/w83627hf.pdf | ||
9 | * Winbond W83627THF | ||
10 | Prefix: 'w83627thf' | ||
11 | Addresses scanned: ISA address retrieved from Super I/O registers | ||
12 | Datasheet: http://www.winbond.com/PDF/sheet/w83627thf.pdf | ||
13 | * Winbond W83697HF | ||
14 | Prefix: 'w83697hf' | ||
15 | Addresses scanned: ISA address retrieved from Super I/O registers | ||
16 | Datasheet: http://www.winbond.com/PDF/sheet/697hf.pdf | ||
17 | * Winbond W83637HF | ||
18 | Prefix: 'w83637hf' | ||
19 | Addresses scanned: ISA address retrieved from Super I/O registers | ||
20 | Datasheet: http://www.winbond.com/PDF/sheet/w83637hf.pdf | ||
21 | |||
22 | Authors: | ||
23 | Frodo Looijaard <frodol@dds.nl>, | ||
24 | Philip Edelbrock <phil@netroedge.com>, | ||
25 | Mark Studebaker <mdsxyz123@yahoo.com>, | ||
26 | Bernhard C. Schrenk <clemy@clemy.org> | ||
27 | |||
28 | Module Parameters | ||
29 | ----------------- | ||
30 | |||
31 | * force_addr: int | ||
32 | Initialize the ISA address of the sensors | ||
33 | * force_i2c: int | ||
34 | Initialize the I2C address of the sensors | ||
35 | * init: int | ||
36 | (default is 1) | ||
37 | Use 'init=0' to bypass initializing the chip. | ||
38 | Try this if your computer crashes when you load the module. | ||
39 | |||
40 | Description | ||
41 | ----------- | ||
42 | |||
43 | This driver implements support for ISA accesses *only* for | ||
44 | the Winbond W83627HF, W83627THF, W83697HF and W83637HF Super I/O chips. | ||
45 | We will refer to them collectively as Winbond chips. | ||
46 | |||
47 | This driver supports ISA accesses, which should be more reliable | ||
48 | than i2c accesses. Also, for Tyan boards which contain both a | ||
49 | Super I/O chip and a second i2c-only Winbond chip (often a W83782D), | ||
50 | using this driver will avoid i2c address conflicts and complex | ||
51 | initialization that were required in the w83781d driver. | ||
52 | |||
53 | If you really want i2c accesses for these Super I/O chips, | ||
54 | use the w83781d driver. However this is not the preferred method | ||
55 | now that this ISA driver has been developed. | ||
56 | |||
57 | Technically, the w83627thf does not support a VID reading. However, it's | ||
58 | possible or even likely that your mainboard maker has routed these signals | ||
59 | to a specific set of general purpose IO pins (the Asus P4C800-E is one such | ||
60 | board). The w83627thf driver now interprets these as VID. If the VID on | ||
61 | your board doesn't work, first see doc/vid in the lm_sensors package. If | ||
62 | that still doesn't help, email us at lm-sensors@lm-sensors.org. | ||
63 | |||
64 | For further information on this driver see the w83781d driver | ||
65 | documentation. | ||
66 | |||
diff --git a/Documentation/i2c/chips/w83781d b/Documentation/i2c/chips/w83781d new file mode 100644 index 000000000000..e5459333ba68 --- /dev/null +++ b/Documentation/i2c/chips/w83781d | |||
@@ -0,0 +1,402 @@ | |||
1 | Kernel driver w83781d | ||
2 | ===================== | ||
3 | |||
4 | Supported chips: | ||
5 | * Winbond W83781D | ||
6 | Prefix: 'w83781d' | ||
7 | Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports) | ||
8 | Datasheet: http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/w83781d.pdf | ||
9 | * Winbond W83782D | ||
10 | Prefix: 'w83782d' | ||
11 | Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports) | ||
12 | Datasheet: http://www.winbond.com/PDF/sheet/w83782d.pdf | ||
13 | * Winbond W83783S | ||
14 | Prefix: 'w83783s' | ||
15 | Addresses scanned: I2C 0x2d | ||
16 | Datasheet: http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/w83783s.pdf | ||
17 | * Winbond W83627HF | ||
18 | Prefix: 'w83627hf' | ||
19 | Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports) | ||
20 | Datasheet: http://www.winbond.com/PDF/sheet/w83627hf.pdf | ||
21 | * Asus AS99127F | ||
22 | Prefix: 'as99127f' | ||
23 | Addresses scanned: I2C 0x28 - 0x2f | ||
24 | Datasheet: Unavailable from Asus | ||
25 | |||
26 | Authors: | ||
27 | Frodo Looijaard <frodol@dds.nl>, | ||
28 | Philip Edelbrock <phil@netroedge.com>, | ||
29 | Mark Studebaker <mdsxyz123@yahoo.com> | ||
30 | |||
31 | Module parameters | ||
32 | ----------------- | ||
33 | |||
34 | * init int | ||
35 | (default 1) | ||
36 | Use 'init=0' to bypass initializing the chip. | ||
37 | Try this if your computer crashes when you load the module. | ||
38 | |||
39 | force_subclients=bus,caddr,saddr,saddr | ||
40 | This is used to force the i2c addresses for subclients of | ||
41 | a certain chip. Typical usage is `force_subclients=0,0x2d,0x4a,0x4b' | ||
42 | to force the subclients of chip 0x2d on bus 0 to i2c addresses | ||
43 | 0x4a and 0x4b. This parameter is useful for certain Tyan boards. | ||
44 | |||
45 | Description | ||
46 | ----------- | ||
47 | |||
48 | This driver implements support for the Winbond W83781D, W83782D, W83783S, | ||
49 | W83627HF chips, and the Asus AS99127F chips. We will refer to them | ||
50 | collectively as W8378* chips. | ||
51 | |||
52 | There is quite some difference between these chips, but they are similar | ||
53 | enough that it was sensible to put them together in one driver. | ||
54 | The W83627HF chip is assumed to be identical to the ISA W83782D. | ||
55 | The Asus chips are similar to an I2C-only W83782D. | ||
56 | |||
57 | Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA | ||
58 | as99127f 7 3 0 3 0x31 0x12c3 yes no | ||
59 | as99127f rev.2 (type_name = as99127f) 0x31 0x5ca3 yes no | ||
60 | w83781d 7 3 0 3 0x10-1 0x5ca3 yes yes | ||
61 | w83627hf 9 3 2 3 0x21 0x5ca3 yes yes(LPC) | ||
62 | w83782d 9 3 2-4 3 0x30 0x5ca3 yes yes | ||
63 | w83783s 5-6 3 2 1-2 0x40 0x5ca3 yes no | ||
64 | |||
65 | Detection of these chips can sometimes be foiled because they can be in | ||
66 | an internal state that allows no clean access. If you know the address | ||
67 | of the chip, use a 'force' parameter; this will put them into a more | ||
68 | well-behaved state first. | ||
69 | |||
70 | The W8378* implements temperature sensors (three on the W83781D and W83782D, | ||
71 | two on the W83783S), three fan rotation speed sensors, voltage sensors | ||
72 | (seven on the W83781D, nine on the W83782D and six on the W83783S), VID | ||
73 | lines, alarms with beep warnings, and some miscellaneous stuff. | ||
74 | |||
75 | Temperatures are measured in degrees Celsius. There is always one main | ||
76 | temperature sensor, and one (W83783S) or two (W83781D and W83782D) other | ||
77 | sensors. An alarm is triggered for the main sensor once when the | ||
78 | Overtemperature Shutdown limit is crossed; it is triggered again as soon as | ||
79 | it drops below the Hysteresis value. A more useful behavior | ||
80 | can be found by setting the Hysteresis value to +127 degrees Celsius; in | ||
81 | this case, alarms are issued during all the time when the actual temperature | ||
82 | is above the Overtemperature Shutdown value. The driver sets the | ||
83 | hysteresis value for temp1 to 127 at initialization. | ||
84 | |||
85 | For the other temperature sensor(s), an alarm is triggered when the | ||
86 | temperature gets higher then the Overtemperature Shutdown value; it stays | ||
87 | on until the temperature falls below the Hysteresis value. But on the | ||
88 | W83781D, there is only one alarm that functions for both other sensors! | ||
89 | Temperatures are guaranteed within a range of -55 to +125 degrees. The | ||
90 | main temperature sensors has a resolution of 1 degree; the other sensor(s) | ||
91 | of 0.5 degree. | ||
92 | |||
93 | Fan rotation speeds are reported in RPM (rotations per minute). An alarm is | ||
94 | triggered if the rotation speed has dropped below a programmable limit. Fan | ||
95 | readings can be divided by a programmable divider (1, 2, 4 or 8 for the | ||
96 | W83781D; 1, 2, 4, 8, 16, 32, 64 or 128 for the others) to give | ||
97 | the readings more range or accuracy. Not all RPM values can accurately | ||
98 | be represented, so some rounding is done. With a divider of 2, the lowest | ||
99 | representable value is around 2600 RPM. | ||
100 | |||
101 | Voltage sensors (also known as IN sensors) report their values in volts. | ||
102 | An alarm is triggered if the voltage has crossed a programmable minimum | ||
103 | or maximum limit. Note that minimum in this case always means 'closest to | ||
104 | zero'; this is important for negative voltage measurements. All voltage | ||
105 | inputs can measure voltages between 0 and 4.08 volts, with a resolution | ||
106 | of 0.016 volt. | ||
107 | |||
108 | The VID lines encode the core voltage value: the voltage level your processor | ||
109 | should work with. This is hardcoded by the mainboard and/or processor itself. | ||
110 | It is a value in volts. When it is unconnected, you will often find the | ||
111 | value 3.50 V here. | ||
112 | |||
113 | The W83782D and W83783S temperature conversion machine understands about | ||
114 | several kinds of temperature probes. You can program the so-called | ||
115 | beta value in the sensor files. '1' is the PII/Celeron diode, '2' is the | ||
116 | TN3904 transistor, and 3435 the default thermistor value. Other values | ||
117 | are (not yet) supported. | ||
118 | |||
119 | In addition to the alarms described above, there is a CHAS alarm on the | ||
120 | chips which triggers if your computer case is open. | ||
121 | |||
122 | When an alarm goes off, you can be warned by a beeping signal through | ||
123 | your computer speaker. It is possible to enable all beeping globally, | ||
124 | or only the beeping for some alarms. | ||
125 | |||
126 | If an alarm triggers, it will remain triggered until the hardware register | ||
127 | is read at least once. This means that the cause for the alarm may | ||
128 | already have disappeared! Note that in the current implementation, all | ||
129 | hardware registers are read whenever any data is read (unless it is less | ||
130 | than 1.5 seconds since the last update). This means that you can easily | ||
131 | miss once-only alarms. | ||
132 | |||
133 | The chips only update values each 1.5 seconds; reading them more often | ||
134 | will do no harm, but will return 'old' values. | ||
135 | |||
136 | AS99127F PROBLEMS | ||
137 | ----------------- | ||
138 | The as99127f support was developed without the benefit of a datasheet. | ||
139 | In most cases it is treated as a w83781d (although revision 2 of the | ||
140 | AS99127F looks more like a w83782d). | ||
141 | This support will be BETA until a datasheet is released. | ||
142 | One user has reported problems with fans stopping | ||
143 | occasionally. | ||
144 | |||
145 | Note that the individual beep bits are inverted from the other chips. | ||
146 | The driver now takes care of this so that user-space applications | ||
147 | don't have to know about it. | ||
148 | |||
149 | Known problems: | ||
150 | - Problems with diode/thermistor settings (supported?) | ||
151 | - One user reports fans stopping under high server load. | ||
152 | - Revision 2 seems to have 2 PWM registers but we don't know | ||
153 | how to handle them. More details below. | ||
154 | |||
155 | These will not be fixed unless we get a datasheet. | ||
156 | If you have problems, please lobby Asus to release a datasheet. | ||
157 | Unfortunately several others have without success. | ||
158 | Please do not send mail to us asking for better as99127f support. | ||
159 | We have done the best we can without a datasheet. | ||
160 | Please do not send mail to the author or the sensors group asking for | ||
161 | a datasheet or ideas on how to convince Asus. We can't help. | ||
162 | |||
163 | |||
164 | NOTES: | ||
165 | ----- | ||
166 | 783s has no in1 so that in[2-6] are compatible with the 781d/782d. | ||
167 | |||
168 | 783s pin is programmable for -5V or temp1; defaults to -5V, | ||
169 | no control in driver so temp1 doesn't work. | ||
170 | |||
171 | 782d and 783s datasheets differ on which is pwm1 and which is pwm2. | ||
172 | We chose to follow 782d. | ||
173 | |||
174 | 782d and 783s pin is programmable for fan3 input or pwm2 output; | ||
175 | defaults to fan3 input. | ||
176 | If pwm2 is enabled (with echo 255 1 > pwm2), then | ||
177 | fan3 will report 0. | ||
178 | |||
179 | 782d has pwm1-2 for ISA, pwm1-4 for i2c. (pwm3-4 share pins with | ||
180 | the ISA pins) | ||
181 | |||
182 | Data sheet updates: | ||
183 | ------------------ | ||
184 | - PWM clock registers: | ||
185 | |||
186 | 000: master / 512 | ||
187 | 001: master / 1024 | ||
188 | 010: master / 2048 | ||
189 | 011: master / 4096 | ||
190 | 100: master / 8192 | ||
191 | |||
192 | |||
193 | Answers from Winbond tech support | ||
194 | --------------------------------- | ||
195 | > | ||
196 | > 1) In the W83781D data sheet section 7.2 last paragraph, it talks about | ||
197 | > reprogramming the R-T table if the Beta of the thermistor is not | ||
198 | > 3435K. The R-T table is described briefly in section 8.20. | ||
199 | > What formulas do I use to program a new R-T table for a given Beta? | ||
200 | > | ||
201 | We are sorry that the calculation for R-T table value is | ||
202 | confidential. If you have another Beta value of thermistor, we can help | ||
203 | to calculate the R-T table for you. But you should give us real R-T | ||
204 | Table which can be gotten by thermistor vendor. Therefore we will calculate | ||
205 | them and obtain 32-byte data, and you can fill the 32-byte data to the | ||
206 | register in Bank0.CR51 of W83781D. | ||
207 | |||
208 | |||
209 | > 2) In the W83782D data sheet, it mentions that pins 38, 39, and 40 are | ||
210 | > programmable to be either thermistor or Pentium II diode inputs. | ||
211 | > How do I program them for diode inputs? I can't find any register | ||
212 | > to program these to be diode inputs. | ||
213 | --> You may program Bank0 CR[5Dh] and CR[59h] registers. | ||
214 | |||
215 | CR[5Dh] bit 1(VTIN1) bit 2(VTIN2) bit 3(VTIN3) | ||
216 | |||
217 | thermistor 0 0 0 | ||
218 | diode 1 1 1 | ||
219 | |||
220 | |||
221 | (error) CR[59h] bit 4(VTIN1) bit 2(VTIN2) bit 3(VTIN3) | ||
222 | (right) CR[59h] bit 4(VTIN1) bit 5(VTIN2) bit 6(VTIN3) | ||
223 | |||
224 | PII thermal diode 1 1 1 | ||
225 | 2N3904 diode 0 0 0 | ||
226 | |||
227 | |||
228 | Asus Clones | ||
229 | ----------- | ||
230 | |||
231 | We have no datasheets for the Asus clones (AS99127F and ASB100 Bach). | ||
232 | Here are some very useful information that were given to us by Alex Van | ||
233 | Kaam about how to detect these chips, and how to read their values. He | ||
234 | also gives advice for another Asus chipset, the Mozart-2 (which we | ||
235 | don't support yet). Thanks Alex! | ||
236 | I reworded some parts and added personal comments. | ||
237 | |||
238 | # Detection: | ||
239 | |||
240 | AS99127F rev.1, AS99127F rev.2 and ASB100: | ||
241 | - I2C address range: 0x29 - 0x2F | ||
242 | - If register 0x58 holds 0x31 then we have an Asus (either ASB100 or | ||
243 | AS99127F) | ||
244 | - Which one depends on register 0x4F (manufacturer ID): | ||
245 | 0x06 or 0x94: ASB100 | ||
246 | 0x12 or 0xC3: AS99127F rev.1 | ||
247 | 0x5C or 0xA3: AS99127F rev.2 | ||
248 | Note that 0x5CA3 is Winbond's ID (WEC), which let us think Asus get their | ||
249 | AS99127F rev.2 direct from Winbond. The other codes mean ATT and DVC, | ||
250 | respectively. ATT could stand for Asustek something (although it would be | ||
251 | very badly chosen IMHO), I don't know what DVC could stand for. Maybe | ||
252 | these codes simply aren't meant to be decoded that way. | ||
253 | |||
254 | Mozart-2: | ||
255 | - I2C address: 0x77 | ||
256 | - If register 0x58 holds 0x56 or 0x10 then we have a Mozart-2 | ||
257 | - Of the Mozart there are 3 types: | ||
258 | 0x58=0x56, 0x4E=0x94, 0x4F=0x36: Asus ASM58 Mozart-2 | ||
259 | 0x58=0x56, 0x4E=0x94, 0x4F=0x06: Asus AS2K129R Mozart-2 | ||
260 | 0x58=0x10, 0x4E=0x5C, 0x4F=0xA3: Asus ??? Mozart-2 | ||
261 | You can handle all 3 the exact same way :) | ||
262 | |||
263 | # Temperature sensors: | ||
264 | |||
265 | ASB100: | ||
266 | - sensor 1: register 0x27 | ||
267 | - sensor 2 & 3 are the 2 LM75's on the SMBus | ||
268 | - sensor 4: register 0x17 | ||
269 | Remark: I noticed that on Intel boards sensor 2 is used for the CPU | ||
270 | and 4 is ignored/stuck, on AMD boards sensor 4 is the CPU and sensor 2 is | ||
271 | either ignored or a socket temperature. | ||
272 | |||
273 | AS99127F (rev.1 and 2 alike): | ||
274 | - sensor 1: register 0x27 | ||
275 | - sensor 2 & 3 are the 2 LM75's on the SMBus | ||
276 | Remark: Register 0x5b is suspected to be temperature type selector. Bit 1 | ||
277 | would control temp1, bit 3 temp2 and bit 5 temp3. | ||
278 | |||
279 | Mozart-2: | ||
280 | - sensor 1: register 0x27 | ||
281 | - sensor 2: register 0x13 | ||
282 | |||
283 | # Fan sensors: | ||
284 | |||
285 | ASB100, AS99127F (rev.1 and 2 alike): | ||
286 | - 3 fans, identical to the W83781D | ||
287 | |||
288 | Mozart-2: | ||
289 | - 2 fans only, 1350000/RPM/div | ||
290 | - fan 1: register 0x28, divisor on register 0xA1 (bits 4-5) | ||
291 | - fan 2: register 0x29, divisor on register 0xA1 (bits 6-7) | ||
292 | |||
293 | # Voltages: | ||
294 | |||
295 | This is where there is a difference between AS99127F rev.1 and 2. | ||
296 | Remark: The difference is similar to the difference between | ||
297 | W83781D and W83782D. | ||
298 | |||
299 | ASB100: | ||
300 | in0=r(0x20)*0.016 | ||
301 | in1=r(0x21)*0.016 | ||
302 | in2=r(0x22)*0.016 | ||
303 | in3=r(0x23)*0.016*1.68 | ||
304 | in4=r(0x24)*0.016*3.8 | ||
305 | in5=r(0x25)*(-0.016)*3.97 | ||
306 | in6=r(0x26)*(-0.016)*1.666 | ||
307 | |||
308 | AS99127F rev.1: | ||
309 | in0=r(0x20)*0.016 | ||
310 | in1=r(0x21)*0.016 | ||
311 | in2=r(0x22)*0.016 | ||
312 | in3=r(0x23)*0.016*1.68 | ||
313 | in4=r(0x24)*0.016*3.8 | ||
314 | in5=r(0x25)*(-0.016)*3.97 | ||
315 | in6=r(0x26)*(-0.016)*1.503 | ||
316 | |||
317 | AS99127F rev.2: | ||
318 | in0=r(0x20)*0.016 | ||
319 | in1=r(0x21)*0.016 | ||
320 | in2=r(0x22)*0.016 | ||
321 | in3=r(0x23)*0.016*1.68 | ||
322 | in4=r(0x24)*0.016*3.8 | ||
323 | in5=(r(0x25)*0.016-3.6)*5.14+3.6 | ||
324 | in6=(r(0x26)*0.016-3.6)*3.14+3.6 | ||
325 | |||
326 | Mozart-2: | ||
327 | in0=r(0x20)*0.016 | ||
328 | in1=255 | ||
329 | in2=r(0x22)*0.016 | ||
330 | in3=r(0x23)*0.016*1.68 | ||
331 | in4=r(0x24)*0.016*4 | ||
332 | in5=255 | ||
333 | in6=255 | ||
334 | |||
335 | |||
336 | # PWM | ||
337 | |||
338 | Additional info about PWM on the AS99127F (may apply to other Asus | ||
339 | chips as well) by Jean Delvare as of 2004-04-09: | ||
340 | |||
341 | AS99127F revision 2 seems to have two PWM registers at 0x59 and 0x5A, | ||
342 | and a temperature sensor type selector at 0x5B (which basically means | ||
343 | that they swapped registers 0x59 and 0x5B when you compare with Winbond | ||
344 | chips). | ||
345 | Revision 1 of the chip also has the temperature sensor type selector at | ||
346 | 0x5B, but PWM registers have no effect. | ||
347 | |||
348 | We don't know exactly how the temperature sensor type selection works. | ||
349 | Looks like bits 1-0 are for temp1, bits 3-2 for temp2 and bits 5-4 for | ||
350 | temp3, although it is possible that only the most significant bit matters | ||
351 | each time. So far, values other than 0 always broke the readings. | ||
352 | |||
353 | PWM registers seem to be split in two parts: bit 7 is a mode selector, | ||
354 | while the other bits seem to define a value or threshold. | ||
355 | |||
356 | When bit 7 is clear, bits 6-0 seem to hold a threshold value. If the value | ||
357 | is below a given limit, the fan runs at low speed. If the value is above | ||
358 | the limit, the fan runs at full speed. We have no clue as to what the limit | ||
359 | represents. Note that there seem to be some inertia in this mode, speed | ||
360 | changes may need some time to trigger. Also, an hysteresis mechanism is | ||
361 | suspected since walking through all the values increasingly and then | ||
362 | decreasingly led to slightly different limits. | ||
363 | |||
364 | When bit 7 is set, bits 3-0 seem to hold a threshold value, while bits 6-4 | ||
365 | would not be significant. If the value is below a given limit, the fan runs | ||
366 | at full speed, while if it is above the limit it runs at low speed (so this | ||
367 | is the contrary of the other mode, in a way). Here again, we don't know | ||
368 | what the limit is supposed to represent. | ||
369 | |||
370 | One remarkable thing is that the fans would only have two or three | ||
371 | different speeds (transitional states left apart), not a whole range as | ||
372 | you usually get with PWM. | ||
373 | |||
374 | As a conclusion, you can write 0x00 or 0x8F to the PWM registers to make | ||
375 | fans run at low speed, and 0x7F or 0x80 to make them run at full speed. | ||
376 | |||
377 | Please contact us if you can figure out how it is supposed to work. As | ||
378 | long as we don't know more, the w83781d driver doesn't handle PWM on | ||
379 | AS99127F chips at all. | ||
380 | |||
381 | Additional info about PWM on the AS99127F rev.1 by Hector Martin: | ||
382 | |||
383 | I've been fiddling around with the (in)famous 0x59 register and | ||
384 | found out the following values do work as a form of coarse pwm: | ||
385 | |||
386 | 0x80 - seems to turn fans off after some time(1-2 minutes)... might be | ||
387 | some form of auto-fan-control based on temp? hmm (Qfan? this mobo is an | ||
388 | old ASUS, it isn't marketed as Qfan. Maybe some beta pre-attemp at Qfan | ||
389 | that was dropped at the BIOS) | ||
390 | 0x81 - off | ||
391 | 0x82 - slightly "on-ner" than off, but my fans do not get to move. I can | ||
392 | hear the high-pitched PWM sound that motors give off at too-low-pwm. | ||
393 | 0x83 - now they do move. Estimate about 70% speed or so. | ||
394 | 0x84-0x8f - full on | ||
395 | |||
396 | Changing the high nibble doesn't seem to do much except the high bit | ||
397 | (0x80) must be set for PWM to work, else the current pwm doesn't seem to | ||
398 | change. | ||
399 | |||
400 | My mobo is an ASUS A7V266-E. This behavior is similar to what I got | ||
401 | with speedfan under Windows, where 0-15% would be off, 15-2x% (can't | ||
402 | remember the exact value) would be 70% and higher would be full on. | ||
diff --git a/Documentation/i2c/chips/w83l785ts b/Documentation/i2c/chips/w83l785ts new file mode 100644 index 000000000000..1841cedc25b2 --- /dev/null +++ b/Documentation/i2c/chips/w83l785ts | |||
@@ -0,0 +1,39 @@ | |||
1 | Kernel driver w83l785ts | ||
2 | ======================= | ||
3 | |||
4 | Supported chips: | ||
5 | * Winbond W83L785TS-S | ||
6 | Prefix: 'w83l785ts' | ||
7 | Addresses scanned: I2C 0x2e | ||
8 | Datasheet: Publicly available at the Winbond USA website | ||
9 | http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83L785TS-S.pdf | ||
10 | |||
11 | Authors: | ||
12 | Jean Delvare <khali@linux-fr.org> | ||
13 | |||
14 | Description | ||
15 | ----------- | ||
16 | |||
17 | The W83L785TS-S is a digital temperature sensor. It senses the | ||
18 | temperature of a single external diode. The high limit is | ||
19 | theoretically defined as 85 or 100 degrees C through a combination | ||
20 | of external resistors, so the user cannot change it. Values seen so | ||
21 | far suggest that the two possible limits are actually 95 and 110 | ||
22 | degrees C. The datasheet is rather poor and obviously inaccurate | ||
23 | on several points including this one. | ||
24 | |||
25 | All temperature values are given in degrees Celsius. Resolution | ||
26 | is 1.0 degree. See the datasheet for details. | ||
27 | |||
28 | The w83l785ts driver will not update its values more frequently than | ||
29 | every other second; reading them more often will do no harm, but will | ||
30 | return 'old' values. | ||
31 | |||
32 | Known Issues | ||
33 | ------------ | ||
34 | |||
35 | On some systems (Asus), the BIOS is known to interfere with the driver | ||
36 | and cause read errors. The driver will retry a given number of times | ||
37 | (5 by default) and then give up, returning the old value (or 0 if | ||
38 | there is no old value). It seems to work well enough so that you should | ||
39 | not notice anything. Thanks to James Bolt for helping test this feature. | ||
diff --git a/Documentation/i2c/porting-clients b/Documentation/i2c/porting-clients index 56404918eabc..a7adbdd9ea8a 100644 --- a/Documentation/i2c/porting-clients +++ b/Documentation/i2c/porting-clients | |||
@@ -57,7 +57,7 @@ Technical changes: | |||
57 | Documentation/i2c/sysfs-interface for the individual files. Also | 57 | Documentation/i2c/sysfs-interface for the individual files. Also |
58 | convert the units these files read and write to the specified ones. | 58 | convert the units these files read and write to the specified ones. |
59 | If you need to add a new type of file, please discuss it on the | 59 | If you need to add a new type of file, please discuss it on the |
60 | sensors mailing list <sensors@stimpy.netroedge.com> by providing a | 60 | sensors mailing list <lm-sensors@lm-sensors.org> by providing a |
61 | patch to the Documentation/i2c/sysfs-interface file. | 61 | patch to the Documentation/i2c/sysfs-interface file. |
62 | 62 | ||
63 | * [Attach] For I2C drivers, the attach function should make sure | 63 | * [Attach] For I2C drivers, the attach function should make sure |
diff --git a/Documentation/i2c/userspace-tools b/Documentation/i2c/userspace-tools new file mode 100644 index 000000000000..2622aac65422 --- /dev/null +++ b/Documentation/i2c/userspace-tools | |||
@@ -0,0 +1,39 @@ | |||
1 | Introduction | ||
2 | ------------ | ||
3 | |||
4 | Most mainboards have sensor chips to monitor system health (like temperatures, | ||
5 | voltages, fans speed). They are often connected through an I2C bus, but some | ||
6 | are also connected directly through the ISA bus. | ||
7 | |||
8 | The kernel drivers make the data from the sensor chips available in the /sys | ||
9 | virtual filesystem. Userspace tools are then used to display or set or the | ||
10 | data in a more friendly manner. | ||
11 | |||
12 | Lm-sensors | ||
13 | ---------- | ||
14 | |||
15 | Core set of utilites that will allow you to obtain health information, | ||
16 | setup monitoring limits etc. You can get them on their homepage | ||
17 | http://www.lm-sensors.nu/ or as a package from your Linux distribution. | ||
18 | |||
19 | If from website: | ||
20 | Get lmsensors from project web site. Please note, you need only userspace | ||
21 | part, so compile with "make user_install" target. | ||
22 | |||
23 | General hints to get things working: | ||
24 | |||
25 | 0) get lm-sensors userspace utils | ||
26 | 1) compile all drivers in I2C section as modules in your kernel | ||
27 | 2) run sensors-detect script, it will tell you what modules you need to load. | ||
28 | 3) load them and run "sensors" command, you should see some results. | ||
29 | 4) fix sensors.conf, labels, limits, fan divisors | ||
30 | 5) if any more problems consult FAQ, or documentation | ||
31 | |||
32 | Other utilites | ||
33 | -------------- | ||
34 | |||
35 | If you want some graphical indicators of system health look for applications | ||
36 | like: gkrellm, ksensors, xsensors, wmtemp, wmsensors, wmgtemp, ksysguardd, | ||
37 | hardware-monitor | ||
38 | |||
39 | If you are server administrator you can try snmpd or mrtgutils. | ||
diff --git a/Documentation/i2c/writing-clients b/Documentation/i2c/writing-clients index ad27511e3c7d..f482dae81de3 100644 --- a/Documentation/i2c/writing-clients +++ b/Documentation/i2c/writing-clients | |||
@@ -171,45 +171,31 @@ The following lists are used internally: | |||
171 | 171 | ||
172 | normal_i2c: filled in by the module writer. | 172 | normal_i2c: filled in by the module writer. |
173 | A list of I2C addresses which should normally be examined. | 173 | A list of I2C addresses which should normally be examined. |
174 | normal_i2c_range: filled in by the module writer. | ||
175 | A list of pairs of I2C addresses, each pair being an inclusive range of | ||
176 | addresses which should normally be examined. | ||
177 | probe: insmod parameter. | 174 | probe: insmod parameter. |
178 | A list of pairs. The first value is a bus number (-1 for any I2C bus), | 175 | A list of pairs. The first value is a bus number (-1 for any I2C bus), |
179 | the second is the address. These addresses are also probed, as if they | 176 | the second is the address. These addresses are also probed, as if they |
180 | were in the 'normal' list. | 177 | were in the 'normal' list. |
181 | probe_range: insmod parameter. | ||
182 | A list of triples. The first value is a bus number (-1 for any I2C bus), | ||
183 | the second and third are addresses. These form an inclusive range of | ||
184 | addresses that are also probed, as if they were in the 'normal' list. | ||
185 | ignore: insmod parameter. | 178 | ignore: insmod parameter. |
186 | A list of pairs. The first value is a bus number (-1 for any I2C bus), | 179 | A list of pairs. The first value is a bus number (-1 for any I2C bus), |
187 | the second is the I2C address. These addresses are never probed. | 180 | the second is the I2C address. These addresses are never probed. |
188 | This parameter overrules 'normal' and 'probe', but not the 'force' lists. | 181 | This parameter overrules 'normal' and 'probe', but not the 'force' lists. |
189 | ignore_range: insmod parameter. | ||
190 | A list of triples. The first value is a bus number (-1 for any I2C bus), | ||
191 | the second and third are addresses. These form an inclusive range of | ||
192 | I2C addresses that are never probed. | ||
193 | This parameter overrules 'normal' and 'probe', but not the 'force' lists. | ||
194 | force: insmod parameter. | 182 | force: insmod parameter. |
195 | A list of pairs. The first value is a bus number (-1 for any I2C bus), | 183 | A list of pairs. The first value is a bus number (-1 for any I2C bus), |
196 | the second is the I2C address. A device is blindly assumed to be on | 184 | the second is the I2C address. A device is blindly assumed to be on |
197 | the given address, no probing is done. | 185 | the given address, no probing is done. |
198 | 186 | ||
199 | Fortunately, as a module writer, you just have to define the `normal' | 187 | Fortunately, as a module writer, you just have to define the `normal_i2c' |
200 | and/or `normal_range' parameters. The complete declaration could look | 188 | parameter. The complete declaration could look like this: |
201 | like this: | ||
202 | 189 | ||
203 | /* Scan 0x20 to 0x2f, 0x37, and 0x40 to 0x4f */ | 190 | /* Scan 0x37, and 0x48 to 0x4f */ |
204 | static unsigned short normal_i2c[] = { 0x37,I2C_CLIENT_END }; | 191 | static unsigned short normal_i2c[] = { 0x37, 0x48, 0x49, 0x4a, 0x4b, 0x4c, |
205 | static unsigned short normal_i2c_range[] = { 0x20, 0x2f, 0x40, 0x4f, | 192 | 0x4d, 0x4e, 0x4f, I2C_CLIENT_END }; |
206 | I2C_CLIENT_END }; | ||
207 | 193 | ||
208 | /* Magic definition of all other variables and things */ | 194 | /* Magic definition of all other variables and things */ |
209 | I2C_CLIENT_INSMOD; | 195 | I2C_CLIENT_INSMOD; |
210 | 196 | ||
211 | Note that you *have* to call the two defined variables `normal_i2c' and | 197 | Note that you *have* to call the defined variable `normal_i2c', |
212 | `normal_i2c_range', without any prefix! | 198 | without any prefix! |
213 | 199 | ||
214 | 200 | ||
215 | Probing classes (sensors) | 201 | Probing classes (sensors) |
@@ -223,39 +209,17 @@ The following lists are used internally. They are all lists of integers. | |||
223 | 209 | ||
224 | normal_i2c: filled in by the module writer. Terminated by SENSORS_I2C_END. | 210 | normal_i2c: filled in by the module writer. Terminated by SENSORS_I2C_END. |
225 | A list of I2C addresses which should normally be examined. | 211 | A list of I2C addresses which should normally be examined. |
226 | normal_i2c_range: filled in by the module writer. Terminated by | ||
227 | SENSORS_I2C_END | ||
228 | A list of pairs of I2C addresses, each pair being an inclusive range of | ||
229 | addresses which should normally be examined. | ||
230 | normal_isa: filled in by the module writer. Terminated by SENSORS_ISA_END. | 212 | normal_isa: filled in by the module writer. Terminated by SENSORS_ISA_END. |
231 | A list of ISA addresses which should normally be examined. | 213 | A list of ISA addresses which should normally be examined. |
232 | normal_isa_range: filled in by the module writer. Terminated by | ||
233 | SENSORS_ISA_END | ||
234 | A list of triples. The first two elements are ISA addresses, being an | ||
235 | range of addresses which should normally be examined. The third is the | ||
236 | modulo parameter: only addresses which are 0 module this value relative | ||
237 | to the first address of the range are actually considered. | ||
238 | probe: insmod parameter. Initialize this list with SENSORS_I2C_END values. | 214 | probe: insmod parameter. Initialize this list with SENSORS_I2C_END values. |
239 | A list of pairs. The first value is a bus number (SENSORS_ISA_BUS for | 215 | A list of pairs. The first value is a bus number (SENSORS_ISA_BUS for |
240 | the ISA bus, -1 for any I2C bus), the second is the address. These | 216 | the ISA bus, -1 for any I2C bus), the second is the address. These |
241 | addresses are also probed, as if they were in the 'normal' list. | 217 | addresses are also probed, as if they were in the 'normal' list. |
242 | probe_range: insmod parameter. Initialize this list with SENSORS_I2C_END | ||
243 | values. | ||
244 | A list of triples. The first value is a bus number (SENSORS_ISA_BUS for | ||
245 | the ISA bus, -1 for any I2C bus), the second and third are addresses. | ||
246 | These form an inclusive range of addresses that are also probed, as | ||
247 | if they were in the 'normal' list. | ||
248 | ignore: insmod parameter. Initialize this list with SENSORS_I2C_END values. | 218 | ignore: insmod parameter. Initialize this list with SENSORS_I2C_END values. |
249 | A list of pairs. The first value is a bus number (SENSORS_ISA_BUS for | 219 | A list of pairs. The first value is a bus number (SENSORS_ISA_BUS for |
250 | the ISA bus, -1 for any I2C bus), the second is the I2C address. These | 220 | the ISA bus, -1 for any I2C bus), the second is the I2C address. These |
251 | addresses are never probed. This parameter overrules 'normal' and | 221 | addresses are never probed. This parameter overrules 'normal' and |
252 | 'probe', but not the 'force' lists. | 222 | 'probe', but not the 'force' lists. |
253 | ignore_range: insmod parameter. Initialize this list with SENSORS_I2C_END | ||
254 | values. | ||
255 | A list of triples. The first value is a bus number (SENSORS_ISA_BUS for | ||
256 | the ISA bus, -1 for any I2C bus), the second and third are addresses. | ||
257 | These form an inclusive range of I2C addresses that are never probed. | ||
258 | This parameter overrules 'normal' and 'probe', but not the 'force' lists. | ||
259 | 223 | ||
260 | Also used is a list of pointers to sensors_force_data structures: | 224 | Also used is a list of pointers to sensors_force_data structures: |
261 | force_data: insmod parameters. A list, ending with an element of which | 225 | force_data: insmod parameters. A list, ending with an element of which |
@@ -269,16 +233,14 @@ Also used is a list of pointers to sensors_force_data structures: | |||
269 | So we have a generic insmod variabled `force', and chip-specific variables | 233 | So we have a generic insmod variabled `force', and chip-specific variables |
270 | `force_CHIPNAME'. | 234 | `force_CHIPNAME'. |
271 | 235 | ||
272 | Fortunately, as a module writer, you just have to define the `normal' | 236 | Fortunately, as a module writer, you just have to define the `normal_i2c' |
273 | and/or `normal_range' parameters, and define what chip names are used. | 237 | and `normal_isa' parameters, and define what chip names are used. |
274 | The complete declaration could look like this: | 238 | The complete declaration could look like this: |
275 | /* Scan i2c addresses 0x20 to 0x2f, 0x37, and 0x40 to 0x4f | 239 | /* Scan i2c addresses 0x37, and 0x48 to 0x4f */ |
276 | static unsigned short normal_i2c[] = {0x37,SENSORS_I2C_END}; | 240 | static unsigned short normal_i2c[] = { 0x37, 0x48, 0x49, 0x4a, 0x4b, 0x4c, |
277 | static unsigned short normal_i2c_range[] = {0x20,0x2f,0x40,0x4f, | 241 | 0x4d, 0x4e, 0x4f, I2C_CLIENT_END }; |
278 | SENSORS_I2C_END}; | ||
279 | /* Scan ISA address 0x290 */ | 242 | /* Scan ISA address 0x290 */ |
280 | static unsigned int normal_isa[] = {0x0290,SENSORS_ISA_END}; | 243 | static unsigned int normal_isa[] = {0x0290,SENSORS_ISA_END}; |
281 | static unsigned int normal_isa_range[] = {SENSORS_ISA_END}; | ||
282 | 244 | ||
283 | /* Define chips foo and bar, as well as all module parameters and things */ | 245 | /* Define chips foo and bar, as well as all module parameters and things */ |
284 | SENSORS_INSMOD_2(foo,bar); | 246 | SENSORS_INSMOD_2(foo,bar); |
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 71ef0498d5e0..104a994b8289 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt | |||
@@ -615,9 +615,11 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
615 | Module snd-hda-intel | 615 | Module snd-hda-intel |
616 | -------------------- | 616 | -------------------- |
617 | 617 | ||
618 | Module for Intel HD Audio (ICH6, ICH6M, ICH7) | 618 | Module for Intel HD Audio (ICH6, ICH6M, ICH7), ATI SB450, |
619 | VIA VT8251/VT8237A | ||
619 | 620 | ||
620 | model - force the model name | 621 | model - force the model name |
622 | position_fix - Fix DMA pointer (0 = FIFO size, 1 = none, 2 = POSBUF) | ||
621 | 623 | ||
622 | Module supports up to 8 cards. | 624 | Module supports up to 8 cards. |
623 | 625 | ||
@@ -635,6 +637,10 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
635 | 5stack 5-jack in back, 2-jack in front | 637 | 5stack 5-jack in back, 2-jack in front |
636 | 5stack-digout 5-jack in back, 2-jack in front, a SPDIF out | 638 | 5stack-digout 5-jack in back, 2-jack in front, a SPDIF out |
637 | w810 3-jack | 639 | w810 3-jack |
640 | z71v 3-jack (HP shared SPDIF) | ||
641 | asus 3-jack | ||
642 | uniwill 3-jack | ||
643 | F1734 2-jack | ||
638 | 644 | ||
639 | CMI9880 | 645 | CMI9880 |
640 | minimal 3-jack in back | 646 | minimal 3-jack in back |
@@ -642,6 +648,15 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
642 | full 6-jack in back, 2-jack in front | 648 | full 6-jack in back, 2-jack in front |
643 | full_dig 6-jack in back, 2-jack in front, SPDIF I/O | 649 | full_dig 6-jack in back, 2-jack in front, SPDIF I/O |
644 | allout 5-jack in back, 2-jack in front, SPDIF out | 650 | allout 5-jack in back, 2-jack in front, SPDIF out |
651 | auto auto-config reading BIOS (default) | ||
652 | |||
653 | Note 2: If you get click noises on output, try the module option | ||
654 | position_fix=1 or 2. position_fix=1 will use the SD_LPIB | ||
655 | register value without FIFO size correction as the current | ||
656 | DMA pointer. position_fix=2 will make the driver to use | ||
657 | the position buffer instead of reading SD_LPIB register. | ||
658 | (Usually SD_LPLIB register is more accurate than the | ||
659 | position buffer.) | ||
645 | 660 | ||
646 | Module snd-hdsp | 661 | Module snd-hdsp |
647 | --------------- | 662 | --------------- |
@@ -660,7 +675,19 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
660 | module did formerly. It will allocate the buffers in advance | 675 | module did formerly. It will allocate the buffers in advance |
661 | when any HDSP cards are found. To make the buffer | 676 | when any HDSP cards are found. To make the buffer |
662 | allocation sure, load snd-page-alloc module in the early | 677 | allocation sure, load snd-page-alloc module in the early |
663 | stage of boot sequence. | 678 | stage of boot sequence. See "Early Buffer Allocation" |
679 | section. | ||
680 | |||
681 | Module snd-hdspm | ||
682 | ---------------- | ||
683 | |||
684 | Module for RME HDSP MADI board. | ||
685 | |||
686 | precise_ptr - Enable precise pointer, or disable. | ||
687 | line_outs_monitor - Send playback streams to analog outs by default. | ||
688 | enable_monitor - Enable Analog Out on Channel 63/64 by default. | ||
689 | |||
690 | See hdspm.txt for details. | ||
664 | 691 | ||
665 | Module snd-ice1712 | 692 | Module snd-ice1712 |
666 | ------------------ | 693 | ------------------ |
@@ -677,15 +704,19 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
677 | * TerraTec EWS 88D | 704 | * TerraTec EWS 88D |
678 | * TerraTec EWX 24/96 | 705 | * TerraTec EWX 24/96 |
679 | * TerraTec DMX 6Fire | 706 | * TerraTec DMX 6Fire |
707 | * TerraTec Phase 88 | ||
680 | * Hoontech SoundTrack DSP 24 | 708 | * Hoontech SoundTrack DSP 24 |
681 | * Hoontech SoundTrack DSP 24 Value | 709 | * Hoontech SoundTrack DSP 24 Value |
682 | * Hoontech SoundTrack DSP 24 Media 7.1 | 710 | * Hoontech SoundTrack DSP 24 Media 7.1 |
711 | * Event Electronics, EZ8 | ||
683 | * Digigram VX442 | 712 | * Digigram VX442 |
713 | * Lionstracs, Mediastaton | ||
684 | 714 | ||
685 | model - Use the given board model, one of the following: | 715 | model - Use the given board model, one of the following: |
686 | delta1010, dio2496, delta66, delta44, audiophile, delta410, | 716 | delta1010, dio2496, delta66, delta44, audiophile, delta410, |
687 | delta1010lt, vx442, ewx2496, ews88mt, ews88mt_new, ews88d, | 717 | delta1010lt, vx442, ewx2496, ews88mt, ews88mt_new, ews88d, |
688 | dmx6fire, dsp24, dsp24_value, dsp24_71, ez8 | 718 | dmx6fire, dsp24, dsp24_value, dsp24_71, ez8, |
719 | phase88, mediastation | ||
689 | omni - Omni I/O support for MidiMan M-Audio Delta44/66 | 720 | omni - Omni I/O support for MidiMan M-Audio Delta44/66 |
690 | cs8427_timeout - reset timeout for the CS8427 chip (S/PDIF transciever) | 721 | cs8427_timeout - reset timeout for the CS8427 chip (S/PDIF transciever) |
691 | in msec resolution, default value is 500 (0.5 sec) | 722 | in msec resolution, default value is 500 (0.5 sec) |
@@ -694,20 +725,46 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
694 | is not used with all Envy24 based cards (for example in the MidiMan Delta | 725 | is not used with all Envy24 based cards (for example in the MidiMan Delta |
695 | serie). | 726 | serie). |
696 | 727 | ||
728 | Note: The supported board is detected by reading EEPROM or PCI | ||
729 | SSID (if EEPROM isn't available). You can override the | ||
730 | model by passing "model" module option in case that the | ||
731 | driver isn't configured properly or you want to try another | ||
732 | type for testing. | ||
733 | |||
697 | Module snd-ice1724 | 734 | Module snd-ice1724 |
698 | ------------------ | 735 | ------------------ |
699 | 736 | ||
700 | Module for Envy24HT (VT/ICE1724) based PCI sound cards. | 737 | Module for Envy24HT (VT/ICE1724), Envy24PT (VT1720) based PCI sound cards. |
701 | * MidiMan M Audio Revolution 7.1 | 738 | * MidiMan M Audio Revolution 7.1 |
702 | * AMP Ltd AUDIO2000 | 739 | * AMP Ltd AUDIO2000 |
703 | * TerraTec Aureon Sky-5.1, Space-7.1 | 740 | * TerraTec Aureon 5.1 Sky |
741 | * TerraTec Aureon 7.1 Space | ||
742 | * TerraTec Aureon 7.1 Universe | ||
743 | * TerraTec Phase 22 | ||
744 | * TerraTec Phase 28 | ||
745 | * AudioTrak Prodigy 7.1 | ||
746 | * AudioTrak Prodigy 192 | ||
747 | * Pontis MS300 | ||
748 | * Albatron K8X800 Pro II | ||
749 | * Chaintech ZNF3-150 | ||
750 | * Chaintech ZNF3-250 | ||
751 | * Chaintech 9CJS | ||
752 | * Chaintech AV-710 | ||
753 | * Shuttle SN25P | ||
704 | 754 | ||
705 | model - Use the given board model, one of the following: | 755 | model - Use the given board model, one of the following: |
706 | revo71, amp2000, prodigy71, aureon51, aureon71, | 756 | revo71, amp2000, prodigy71, prodigy192, aureon51, |
707 | k8x800 | 757 | aureon71, universe, k8x800, phase22, phase28, ms300, |
758 | av710 | ||
708 | 759 | ||
709 | Module supports up to 8 cards and autoprobe. | 760 | Module supports up to 8 cards and autoprobe. |
710 | 761 | ||
762 | Note: The supported board is detected by reading EEPROM or PCI | ||
763 | SSID (if EEPROM isn't available). You can override the | ||
764 | model by passing "model" module option in case that the | ||
765 | driver isn't configured properly or you want to try another | ||
766 | type for testing. | ||
767 | |||
711 | Module snd-intel8x0 | 768 | Module snd-intel8x0 |
712 | ------------------- | 769 | ------------------- |
713 | 770 | ||
@@ -1026,7 +1083,8 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
1026 | module did formerly. It will allocate the buffers in advance | 1083 | module did formerly. It will allocate the buffers in advance |
1027 | when any RME9652 cards are found. To make the buffer | 1084 | when any RME9652 cards are found. To make the buffer |
1028 | allocation sure, load snd-page-alloc module in the early | 1085 | allocation sure, load snd-page-alloc module in the early |
1029 | stage of boot sequence. | 1086 | stage of boot sequence. See "Early Buffer Allocation" |
1087 | section. | ||
1030 | 1088 | ||
1031 | Module snd-sa11xx-uda1341 (on arm only) | 1089 | Module snd-sa11xx-uda1341 (on arm only) |
1032 | --------------------------------------- | 1090 | --------------------------------------- |
@@ -1211,16 +1269,18 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
1211 | ------------------ | 1269 | ------------------ |
1212 | 1270 | ||
1213 | Module for AC'97 motherboards based on VIA 82C686A/686B, 8233, | 1271 | Module for AC'97 motherboards based on VIA 82C686A/686B, 8233, |
1214 | 8233A, 8233C, 8235 (south) bridge. | 1272 | 8233A, 8233C, 8235, 8237 (south) bridge. |
1215 | 1273 | ||
1216 | mpu_port - 0x300,0x310,0x320,0x330, otherwise obtain BIOS setup | 1274 | mpu_port - 0x300,0x310,0x320,0x330, otherwise obtain BIOS setup |
1217 | [VIA686A/686B only] | 1275 | [VIA686A/686B only] |
1218 | joystick - Enable joystick (default off) [VIA686A/686B only] | 1276 | joystick - Enable joystick (default off) [VIA686A/686B only] |
1219 | ac97_clock - AC'97 codec clock base (default 48000Hz) | 1277 | ac97_clock - AC'97 codec clock base (default 48000Hz) |
1220 | dxs_support - support DXS channels, | 1278 | dxs_support - support DXS channels, |
1221 | 0 = auto (defalut), 1 = enable, 2 = disable, | 1279 | 0 = auto (default), 1 = enable, 2 = disable, |
1222 | 3 = 48k only, 4 = no VRA | 1280 | 3 = 48k only, 4 = no VRA, 5 = enable any sample |
1223 | [VIA8233/C,8235 only] | 1281 | rate and different sample rates on different |
1282 | channels | ||
1283 | [VIA8233/C, 8235, 8237 only] | ||
1224 | ac97_quirk - AC'97 workaround for strange hardware | 1284 | ac97_quirk - AC'97 workaround for strange hardware |
1225 | See the description of intel8x0 module for details. | 1285 | See the description of intel8x0 module for details. |
1226 | 1286 | ||
@@ -1232,18 +1292,23 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
1232 | default value 1.4. Then the interrupt number will be | 1292 | default value 1.4. Then the interrupt number will be |
1233 | assigned under 15. You might also upgrade your BIOS. | 1293 | assigned under 15. You might also upgrade your BIOS. |
1234 | 1294 | ||
1235 | Note: VIA8233/5 (not VIA8233A) can support DXS (direct sound) | 1295 | Note: VIA8233/5/7 (not VIA8233A) can support DXS (direct sound) |
1236 | channels as the first PCM. On these channels, up to 4 | 1296 | channels as the first PCM. On these channels, up to 4 |
1237 | streams can be played at the same time. | 1297 | streams can be played at the same time, and the controller |
1298 | can perform sample rate conversion with separate rates for | ||
1299 | each channel. | ||
1238 | As default (dxs_support = 0), 48k fixed rate is chosen | 1300 | As default (dxs_support = 0), 48k fixed rate is chosen |
1239 | except for the known devices since the output is often | 1301 | except for the known devices since the output is often |
1240 | noisy except for 48k on some mother boards due to the | 1302 | noisy except for 48k on some mother boards due to the |
1241 | bug of BIOS. | 1303 | bug of BIOS. |
1242 | Please try once dxs_support=1 and if it works on other | 1304 | Please try once dxs_support=5 and if it works on other |
1243 | sample rates (e.g. 44.1kHz of mp3 playback), please let us | 1305 | sample rates (e.g. 44.1kHz of mp3 playback), please let us |
1244 | know the PCI subsystem vendor/device id's (output of | 1306 | know the PCI subsystem vendor/device id's (output of |
1245 | "lspci -nv"). | 1307 | "lspci -nv"). |
1246 | If it doesn't work, try dxs_support=4. If it still doesn't | 1308 | If dxs_support=5 does not work, try dxs_support=4; if it |
1309 | doesn't work too, try dxs_support=1. (dxs_support=1 is | ||
1310 | usually for old motherboards. The correct implementated | ||
1311 | board should work with 4 or 5.) If it still doesn't | ||
1247 | work and the default setting is ok, dxs_support=3 is the | 1312 | work and the default setting is ok, dxs_support=3 is the |
1248 | right choice. If the default setting doesn't work at all, | 1313 | right choice. If the default setting doesn't work at all, |
1249 | try dxs_support=2 to disable the DXS channels. | 1314 | try dxs_support=2 to disable the DXS channels. |
@@ -1497,6 +1562,36 @@ Proc interfaces (/proc/asound) | |||
1497 | echo "rvplayer 0 0 block" > /proc/asound/card0/pcm0p/oss | 1562 | echo "rvplayer 0 0 block" > /proc/asound/card0/pcm0p/oss |
1498 | 1563 | ||
1499 | 1564 | ||
1565 | Early Buffer Allocation | ||
1566 | ======================= | ||
1567 | |||
1568 | Some drivers (e.g. hdsp) require the large contiguous buffers, and | ||
1569 | sometimes it's too late to find such spaces when the driver module is | ||
1570 | actually loaded due to memory fragmentation. You can pre-allocate the | ||
1571 | PCM buffers by loading snd-page-alloc module and write commands to its | ||
1572 | proc file in prior, for example, in the early boot stage like | ||
1573 | /etc/init.d/*.local scripts. | ||
1574 | |||
1575 | Reading the proc file /proc/drivers/snd-page-alloc shows the current | ||
1576 | usage of page allocation. In writing, you can send the following | ||
1577 | commands to the snd-page-alloc driver: | ||
1578 | |||
1579 | - add VENDOR DEVICE MASK SIZE BUFFERS | ||
1580 | |||
1581 | VENDOR and DEVICE are PCI vendor and device IDs. They take | ||
1582 | integer numbers (0x prefix is needed for the hex). | ||
1583 | MASK is the PCI DMA mask. Pass 0 if not restricted. | ||
1584 | SIZE is the size of each buffer to allocate. You can pass | ||
1585 | k and m suffix for KB and MB. The max number is 16MB. | ||
1586 | BUFFERS is the number of buffers to allocate. It must be greater | ||
1587 | than 0. The max number is 4. | ||
1588 | |||
1589 | - erase | ||
1590 | |||
1591 | This will erase the all pre-allocated buffers which are not in | ||
1592 | use. | ||
1593 | |||
1594 | |||
1500 | Links | 1595 | Links |
1501 | ===== | 1596 | ===== |
1502 | 1597 | ||
diff --git a/Documentation/sound/alsa/CMIPCI.txt b/Documentation/sound/alsa/CMIPCI.txt index 4a7df771b806..1872e24442a4 100644 --- a/Documentation/sound/alsa/CMIPCI.txt +++ b/Documentation/sound/alsa/CMIPCI.txt | |||
@@ -89,19 +89,22 @@ and use the interleaved 4 channel data. | |||
89 | 89 | ||
90 | There are some control switchs affecting to the speaker connections: | 90 | There are some control switchs affecting to the speaker connections: |
91 | 91 | ||
92 | "Line-In As Rear" - As mentioned above, the line-in jack is used | 92 | "Line-In Mode" - an enum control to change the behavior of line-in |
93 | for the rear (3th and 4th channels) output. | 93 | jack. Either "Line-In", "Rear Output" or "Bass Output" can |
94 | "Line-In As Bass" - The line-in jack is used for the bass (5th | 94 | be selected. The last item is available only with model 039 |
95 | and 6th channels) output. | 95 | or newer. |
96 | "Mic As Center/LFE" - The mic jack is used for the bass output. | 96 | When "Rear Output" is chosen, the surround channels 3 and 4 |
97 | If this switch is on, you cannot use a microphone as a capture | 97 | are output to line-in jack. |
98 | source, of course. | 98 | "Mic-In Mode" - an enum control to change the behavior of mic-in |
99 | 99 | jack. Either "Mic-In" or "Center/LFE Output" can be | |
100 | selected. | ||
101 | When "Center/LFE Output" is chosen, the center and bass | ||
102 | channels (channels 5 and 6) are output to mic-in jack. | ||
100 | 103 | ||
101 | Digital I/O | 104 | Digital I/O |
102 | ----------- | 105 | ----------- |
103 | 106 | ||
104 | The CM8x38 provides the excellent SPDIF capability with very chip | 107 | The CM8x38 provides the excellent SPDIF capability with very cheap |
105 | price (yes, that's the reason I bought the card :) | 108 | price (yes, that's the reason I bought the card :) |
106 | 109 | ||
107 | The SPDIF playback and capture are done via the third PCM device | 110 | The SPDIF playback and capture are done via the third PCM device |
@@ -122,8 +125,9 @@ respectively, so you cannot playback both analog and digital streams | |||
122 | simultaneously. | 125 | simultaneously. |
123 | 126 | ||
124 | To enable SPDIF output, you need to turn on "IEC958 Output Switch" | 127 | To enable SPDIF output, you need to turn on "IEC958 Output Switch" |
125 | control via mixer or alsactl. Then you'll see the red light on from | 128 | control via mixer or alsactl ("IEC958" is the official name of |
126 | the card so you know that's working obviously :) | 129 | so-called S/PDIF). Then you'll see the red light on from the card so |
130 | you know that's working obviously :) | ||
127 | The SPDIF input is always enabled, so you can hear SPDIF input data | 131 | The SPDIF input is always enabled, so you can hear SPDIF input data |
128 | from line-out with "IEC958 In Monitor" switch at any time (see | 132 | from line-out with "IEC958 In Monitor" switch at any time (see |
129 | below). | 133 | below). |
@@ -205,9 +209,10 @@ In addition to the standard SB mixer, CM8x38 provides more functions. | |||
205 | MIDI CONTROLLER | 209 | MIDI CONTROLLER |
206 | --------------- | 210 | --------------- |
207 | 211 | ||
208 | The MPU401-UART interface is enabled as default only for the first | 212 | The MPU401-UART interface is disabled as default. You need to set |
209 | (CMIPCI) card. You need to set module option "midi_port" properly | 213 | module option "mpu_port" with a valid I/O port address to enable the |
210 | for the 2nd (CMIPCI) card. | 214 | MIDI support. The valid I/O ports are 0x300, 0x310, 0x320 and 0x330. |
215 | Choose the value which doesn't conflict with other cards. | ||
211 | 216 | ||
212 | There is _no_ hardware wavetable function on this chip (except for | 217 | There is _no_ hardware wavetable function on this chip (except for |
213 | OPL3 synth below). | 218 | OPL3 synth below). |
@@ -229,9 +234,11 @@ I don't know why.. | |||
229 | Joystick and Modem | 234 | Joystick and Modem |
230 | ------------------ | 235 | ------------------ |
231 | 236 | ||
232 | The joystick and modem should be available by enabling the control | 237 | The legacy joystick is supported. To enable the joystick support, pass |
233 | switch "Joystick" and "Modem" respectively. But I myself have never | 238 | joystick_port=1 module option. The value 1 means the auto-detection. |
234 | tested them yet. | 239 | If the auto-detection fails, try to pass the exact I/O address. |
240 | |||
241 | The modem is enabled dynamically via a card control switch "Modem". | ||
235 | 242 | ||
236 | 243 | ||
237 | Debugging Information | 244 | Debugging Information |
diff --git a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl index e789475304b6..db0b7d2dc477 100644 --- a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl +++ b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl | |||
@@ -371,7 +371,7 @@ | |||
371 | <listitem><para>create <function>probe()</function> callback.</para></listitem> | 371 | <listitem><para>create <function>probe()</function> callback.</para></listitem> |
372 | <listitem><para>create <function>remove()</function> callback.</para></listitem> | 372 | <listitem><para>create <function>remove()</function> callback.</para></listitem> |
373 | <listitem><para>create pci_driver table which contains the three pointers above.</para></listitem> | 373 | <listitem><para>create pci_driver table which contains the three pointers above.</para></listitem> |
374 | <listitem><para>create <function>init()</function> function just calling <function>pci_module_init()</function> to register the pci_driver table defined above.</para></listitem> | 374 | <listitem><para>create <function>init()</function> function just calling <function>pci_register_driver()</function> to register the pci_driver table defined above.</para></listitem> |
375 | <listitem><para>create <function>exit()</function> function to call <function>pci_unregister_driver()</function> function.</para></listitem> | 375 | <listitem><para>create <function>exit()</function> function to call <function>pci_unregister_driver()</function> function.</para></listitem> |
376 | </itemizedlist> | 376 | </itemizedlist> |
377 | </para> | 377 | </para> |
@@ -1198,7 +1198,7 @@ | |||
1198 | /* initialization of the module */ | 1198 | /* initialization of the module */ |
1199 | static int __init alsa_card_mychip_init(void) | 1199 | static int __init alsa_card_mychip_init(void) |
1200 | { | 1200 | { |
1201 | return pci_module_init(&driver); | 1201 | return pci_register_driver(&driver); |
1202 | } | 1202 | } |
1203 | 1203 | ||
1204 | /* clean up the module */ | 1204 | /* clean up the module */ |
@@ -1654,7 +1654,7 @@ | |||
1654 | <![CDATA[ | 1654 | <![CDATA[ |
1655 | static int __init alsa_card_mychip_init(void) | 1655 | static int __init alsa_card_mychip_init(void) |
1656 | { | 1656 | { |
1657 | return pci_module_init(&driver); | 1657 | return pci_register_driver(&driver); |
1658 | } | 1658 | } |
1659 | 1659 | ||
1660 | static void __exit alsa_card_mychip_exit(void) | 1660 | static void __exit alsa_card_mychip_exit(void) |
diff --git a/Documentation/sound/alsa/emu10k1-jack.txt b/Documentation/sound/alsa/emu10k1-jack.txt new file mode 100644 index 000000000000..751d45036a05 --- /dev/null +++ b/Documentation/sound/alsa/emu10k1-jack.txt | |||
@@ -0,0 +1,74 @@ | |||
1 | This document is a guide to using the emu10k1 based devices with JACK for low | ||
2 | latency, multichannel recording functionality. All of my recent work to allow | ||
3 | Linux users to use the full capabilities of their hardware has been inspired | ||
4 | by the kX Project. Without their work I never would have discovered the true | ||
5 | power of this hardware. | ||
6 | |||
7 | http://www.kxproject.com | ||
8 | - Lee Revell, 2005.03.30 | ||
9 | |||
10 | Low latency, multichannel audio with JACK and the emu10k1/emu10k2 | ||
11 | ----------------------------------------------------------------- | ||
12 | |||
13 | Until recently, emu10k1 users on Linux did not have access to the same low | ||
14 | latency, multichannel features offered by the "kX ASIO" feature of their | ||
15 | Windows driver. As of ALSA 1.0.9 this is no more! | ||
16 | |||
17 | For those unfamiliar with kX ASIO, this consists of 16 capture and 16 playback | ||
18 | channels. With a post 2.6.9 Linux kernel, latencies down to 64 (1.33 ms) or | ||
19 | even 32 (0.66ms) frames should work well. | ||
20 | |||
21 | The configuration is slightly more involved than on Windows, as you have to | ||
22 | select the correct device for JACK to use. Actually, for qjackctl users it's | ||
23 | fairly self explanatory - select Duplex, then for capture and playback select | ||
24 | the multichannel devices, set the in and out channels to 16, and the sample | ||
25 | rate to 48000Hz. The command line looks like this: | ||
26 | |||
27 | /usr/local/bin/jackd -R -dalsa -r48000 -p64 -n2 -D -Chw:0,2 -Phw:0,3 -S | ||
28 | |||
29 | This will give you 16 input ports and 16 output ports. | ||
30 | |||
31 | The 16 output ports map onto the 16 FX buses (or the first 16 of 64, for the | ||
32 | Audigy). The mapping from FX bus to physical output is described in | ||
33 | SB-Live-mixer.txt (or Audigy-mixer.txt). | ||
34 | |||
35 | The 16 input ports are connected to the 16 physical inputs. Contrary to | ||
36 | popular belief, all emu10k1 cards are multichannel cards. Which of these | ||
37 | input channels have physical inputs connected to them depends on the card | ||
38 | model. Trial and error is highly recommended; the pinout diagrams | ||
39 | for the card have been reverse engineered by some enterprising kX users and are | ||
40 | available on the internet. Meterbridge is helpful here, and the kX forums are | ||
41 | packed with useful information. | ||
42 | |||
43 | Each input port will either correspond to a digital (SPDIF) input, an analog | ||
44 | input, or nothing. The one exception is the SBLive! 5.1. On these devices, | ||
45 | the second and third input ports are wired to the center/LFE output. You will | ||
46 | still see 16 capture channels, but only 14 are available for recording inputs. | ||
47 | |||
48 | This chart, borrowed from kxfxlib/da_asio51.cpp, describes the mapping of JACK | ||
49 | ports to FXBUS2 (multitrack recording input) and EXTOUT (physical output) | ||
50 | channels. | ||
51 | |||
52 | /*JACK (& ASIO) mappings on 10k1 5.1 SBLive cards: | ||
53 | -------------------------------------------- | ||
54 | JACK Epilog FXBUS2(nr) | ||
55 | -------------------------------------------- | ||
56 | capture_1 asio14 FXBUS2(0xe) | ||
57 | capture_2 asio15 FXBUS2(0xf) | ||
58 | capture_3 asio0 FXBUS2(0x0) | ||
59 | ~capture_4 Center EXTOUT(0x11) // mapped to by Center | ||
60 | ~capture_5 LFE EXTOUT(0x12) // mapped to by LFE | ||
61 | capture_6 asio3 FXBUS2(0x3) | ||
62 | capture_7 asio4 FXBUS2(0x4) | ||
63 | capture_8 asio5 FXBUS2(0x5) | ||
64 | capture_9 asio6 FXBUS2(0x6) | ||
65 | capture_10 asio7 FXBUS2(0x7) | ||
66 | capture_11 asio8 FXBUS2(0x8) | ||
67 | capture_12 asio9 FXBUS2(0x9) | ||
68 | capture_13 asio10 FXBUS2(0xa) | ||
69 | capture_14 asio11 FXBUS2(0xb) | ||
70 | capture_15 asio12 FXBUS2(0xc) | ||
71 | capture_16 asio13 FXBUS2(0xd) | ||
72 | */ | ||
73 | |||
74 | TODO: describe use of ld10k1/qlo10k1 in conjunction with JACK | ||
diff --git a/Documentation/sound/alsa/hdspm.txt b/Documentation/sound/alsa/hdspm.txt new file mode 100644 index 000000000000..7a67ff71a9f8 --- /dev/null +++ b/Documentation/sound/alsa/hdspm.txt | |||
@@ -0,0 +1,362 @@ | |||
1 | Software Interface ALSA-DSP MADI Driver | ||
2 | |||
3 | (translated from German, so no good English ;-), | ||
4 | 2004 - winfried ritsch | ||
5 | |||
6 | |||
7 | |||
8 | Full functionality has been added to the driver. Since some of | ||
9 | the Controls and startup-options are ALSA-Standard and only the | ||
10 | special Controls are described and discussed below. | ||
11 | |||
12 | |||
13 | hardware functionality: | ||
14 | |||
15 | |||
16 | Audio transmission: | ||
17 | |||
18 | number of channels -- depends on transmission mode | ||
19 | |||
20 | The number of channels chosen is from 1..Nmax. The reason to | ||
21 | use for a lower number of channels is only resource allocation, | ||
22 | since unused DMA channels are disabled and less memory is | ||
23 | allocated. So also the throughput of the PCI system can be | ||
24 | scaled. (Only important for low performance boards). | ||
25 | |||
26 | Single Speed -- 1..64 channels | ||
27 | |||
28 | (Note: Choosing the 56channel mode for transmission or as | ||
29 | receiver, only 56 are transmitted/received over the MADI, but | ||
30 | all 64 channels are available for the mixer, so channel count | ||
31 | for the driver) | ||
32 | |||
33 | Double Speed -- 1..32 channels | ||
34 | |||
35 | Note: Choosing the 56-channel mode for | ||
36 | transmission/receive-mode , only 28 are transmitted/received | ||
37 | over the MADI, but all 32 channels are available for the mixer, | ||
38 | so channel count for the driver | ||
39 | |||
40 | |||
41 | Quad Speed -- 1..16 channels | ||
42 | |||
43 | Note: Choosing the 56-channel mode for | ||
44 | transmission/receive-mode , only 14 are transmitted/received | ||
45 | over the MADI, but all 16 channels are available for the mixer, | ||
46 | so channel count for the driver | ||
47 | |||
48 | Format -- signed 32 Bit Little Endian (SNDRV_PCM_FMTBIT_S32_LE) | ||
49 | |||
50 | Sample Rates -- | ||
51 | |||
52 | Single Speed -- 32000, 44100, 48000 | ||
53 | |||
54 | Double Speed -- 64000, 88200, 96000 (untested) | ||
55 | |||
56 | Quad Speed -- 128000, 176400, 192000 (untested) | ||
57 | |||
58 | access-mode -- MMAP (memory mapped), Not interleaved | ||
59 | (PCM_NON-INTERLEAVED) | ||
60 | |||
61 | buffer-sizes -- 64,128,256,512,1024,2048,8192 Samples | ||
62 | |||
63 | fragments -- 2 | ||
64 | |||
65 | Hardware-pointer -- 2 Modi | ||
66 | |||
67 | |||
68 | The Card supports the readout of the actual Buffer-pointer, | ||
69 | where DMA reads/writes. Since of the bulk mode of PCI it is only | ||
70 | 64 Byte accurate. SO it is not really usable for the | ||
71 | ALSA-mid-level functions (here the buffer-ID gives a better | ||
72 | result), but if MMAP is used by the application. Therefore it | ||
73 | can be configured at load-time with the parameter | ||
74 | precise-pointer. | ||
75 | |||
76 | |||
77 | (Hint: Experimenting I found that the pointer is maximum 64 to | ||
78 | large never to small. So if you subtract 64 you always have a | ||
79 | safe pointer for writing, which is used on this mode inside | ||
80 | ALSA. In theory now you can get now a latency as low as 16 | ||
81 | Samples, which is a quarter of the interrupt possibilities.) | ||
82 | |||
83 | Precise Pointer -- off | ||
84 | interrupt used for pointer-calculation | ||
85 | |||
86 | Precise Pointer -- on | ||
87 | hardware pointer used. | ||
88 | |||
89 | Controller: | ||
90 | |||
91 | |||
92 | Since DSP-MADI-Mixer has 8152 Fader, it does not make sense to | ||
93 | use the standard mixer-controls, since this would break most of | ||
94 | (especially graphic) ALSA-Mixer GUIs. So Mixer control has be | ||
95 | provided by a 2-dimensional controller using the | ||
96 | hwdep-interface. | ||
97 | |||
98 | Also all 128+256 Peak and RMS-Meter can be accessed via the | ||
99 | hwdep-interface. Since it could be a performance problem always | ||
100 | copying and converting Peak and RMS-Levels even if you just need | ||
101 | one, I decided to export the hardware structure, so that of | ||
102 | needed some driver-guru can implement a memory-mapping of mixer | ||
103 | or peak-meters over ioctl, or also to do only copying and no | ||
104 | conversion. A test-application shows the usage of the controller. | ||
105 | |||
106 | Latency Controls --- not implemented !!! | ||
107 | |||
108 | |||
109 | Note: Within the windows-driver the latency is accessible of a | ||
110 | control-panel, but buffer-sizes are controlled with ALSA from | ||
111 | hwparams-calls and should not be changed in run-state, I did not | ||
112 | implement it here. | ||
113 | |||
114 | |||
115 | System Clock -- suspended !!!! | ||
116 | |||
117 | Name -- "System Clock Mode" | ||
118 | |||
119 | Access -- Read Write | ||
120 | |||
121 | Values -- "Master" "Slave" | ||
122 | |||
123 | |||
124 | !!!! This is a hardware-function but is in conflict with the | ||
125 | Clock-source controller, which is a kind of ALSA-standard. I | ||
126 | makes sense to set the card to a special mode (master at some | ||
127 | frequency or slave), since even not using an Audio-application | ||
128 | a studio should have working synchronisations setup. So use | ||
129 | Clock-source-controller instead !!!! | ||
130 | |||
131 | Clock Source | ||
132 | |||
133 | Name -- "Sample Clock Source" | ||
134 | |||
135 | Access -- Read Write | ||
136 | |||
137 | Values -- "AutoSync", "Internal 32.0 kHz", "Internal 44.1 kHz", | ||
138 | "Internal 48.0 kHz", "Internal 64.0 kHz", "Internal 88.2 kHz", | ||
139 | "Internal 96.0 kHz" | ||
140 | |||
141 | Choose between Master at a specific Frequency and so also the | ||
142 | Speed-mode or Slave (Autosync). Also see "Preferred Sync Ref" | ||
143 | |||
144 | |||
145 | !!!! This is no pure hardware function but was implemented by | ||
146 | ALSA by some ALSA-drivers before, so I use it also. !!! | ||
147 | |||
148 | |||
149 | Preferred Sync Ref | ||
150 | |||
151 | Name -- "Preferred Sync Reference" | ||
152 | |||
153 | Access -- Read Write | ||
154 | |||
155 | Values -- "Word" "MADI" | ||
156 | |||
157 | |||
158 | Within the Auto-sync-Mode the preferred Sync Source can be | ||
159 | chosen. If it is not available another is used if possible. | ||
160 | |||
161 | Note: Since MADI has a much higher bit-rate than word-clock, the | ||
162 | card should synchronise better in MADI Mode. But since the | ||
163 | RME-PLL is very good, there are almost no problems with | ||
164 | word-clock too. I never found a difference. | ||
165 | |||
166 | |||
167 | TX 64 channel --- | ||
168 | |||
169 | Name -- "TX 64 channels mode" | ||
170 | |||
171 | Access -- Read Write | ||
172 | |||
173 | Values -- 0 1 | ||
174 | |||
175 | Using 64-channel-modus (1) or 56-channel-modus for | ||
176 | MADI-transmission (0). | ||
177 | |||
178 | |||
179 | Note: This control is for output only. Input-mode is detected | ||
180 | automatically from hardware sending MADI. | ||
181 | |||
182 | |||
183 | Clear TMS --- | ||
184 | |||
185 | Name -- "Clear Track Marker" | ||
186 | |||
187 | Access -- Read Write | ||
188 | |||
189 | Values -- 0 1 | ||
190 | |||
191 | |||
192 | Don't use to lower 5 Audio-bits on AES as additional Bits. | ||
193 | |||
194 | |||
195 | Safe Mode oder Auto Input --- | ||
196 | |||
197 | Name -- "Safe Mode" | ||
198 | |||
199 | Access -- Read Write | ||
200 | |||
201 | Values -- 0 1 | ||
202 | |||
203 | (default on) | ||
204 | |||
205 | If on (1), then if either the optical or coaxial connection | ||
206 | has a failure, there is a takeover to the working one, with no | ||
207 | sample failure. Its only useful if you use the second as a | ||
208 | backup connection. | ||
209 | |||
210 | Input --- | ||
211 | |||
212 | Name -- "Input Select" | ||
213 | |||
214 | Access -- Read Write | ||
215 | |||
216 | Values -- optical coaxial | ||
217 | |||
218 | |||
219 | Choosing the Input, optical or coaxial. If Safe-mode is active, | ||
220 | this is the preferred Input. | ||
221 | |||
222 | -------------- Mixer ---------------------- | ||
223 | |||
224 | Mixer | ||
225 | |||
226 | Name -- "Mixer" | ||
227 | |||
228 | Access -- Read Write | ||
229 | |||
230 | Values - <channel-number 0-127> <Value 0-65535> | ||
231 | |||
232 | |||
233 | Here as a first value the channel-index is taken to get/set the | ||
234 | corresponding mixer channel, where 0-63 are the input to output | ||
235 | fader and 64-127 the playback to outputs fader. Value 0 | ||
236 | is channel muted 0 and 32768 an amplification of 1. | ||
237 | |||
238 | Chn 1-64 | ||
239 | |||
240 | fast mixer for the ALSA-mixer utils. The diagonal of the | ||
241 | mixer-matrix is implemented from playback to output. | ||
242 | |||
243 | |||
244 | Line Out | ||
245 | |||
246 | Name -- "Line Out" | ||
247 | |||
248 | Access -- Read Write | ||
249 | |||
250 | Values -- 0 1 | ||
251 | |||
252 | Switching on and off the analog out, which has nothing to do | ||
253 | with mixing or routing. the analog outs reflects channel 63,64. | ||
254 | |||
255 | |||
256 | --- information (only read access): | ||
257 | |||
258 | Sample Rate | ||
259 | |||
260 | Name -- "System Sample Rate" | ||
261 | |||
262 | Access -- Read-only | ||
263 | |||
264 | getting the sample rate. | ||
265 | |||
266 | |||
267 | External Rate measured | ||
268 | |||
269 | Name -- "External Rate" | ||
270 | |||
271 | Access -- Read only | ||
272 | |||
273 | |||
274 | Should be "Autosync Rate", but Name used is | ||
275 | ALSA-Scheme. External Sample frequency liked used on Autosync is | ||
276 | reported. | ||
277 | |||
278 | |||
279 | MADI Sync Status | ||
280 | |||
281 | Name -- "MADI Sync Lock Status" | ||
282 | |||
283 | Access -- Read | ||
284 | |||
285 | Values -- 0,1,2 | ||
286 | |||
287 | MADI-Input is 0=Unlocked, 1=Locked, or 2=Synced. | ||
288 | |||
289 | |||
290 | Word Clock Sync Status | ||
291 | |||
292 | Name -- "Word Clock Lock Status" | ||
293 | |||
294 | Access -- Read | ||
295 | |||
296 | Values -- 0,1,2 | ||
297 | |||
298 | Word Clock Input is 0=Unlocked, 1=Locked, or 2=Synced. | ||
299 | |||
300 | AutoSync | ||
301 | |||
302 | Name -- "AutoSync Reference" | ||
303 | |||
304 | Access -- Read | ||
305 | |||
306 | Values -- "WordClock", "MADI", "None" | ||
307 | |||
308 | Sync-Reference is either "WordClock", "MADI" or none. | ||
309 | |||
310 | RX 64ch --- noch nicht implementiert | ||
311 | |||
312 | MADI-Receiver is in 64 channel mode oder 56 channel mode. | ||
313 | |||
314 | |||
315 | AB_inp --- not tested | ||
316 | |||
317 | Used input for Auto-Input. | ||
318 | |||
319 | |||
320 | actual Buffer Position --- not implemented | ||
321 | |||
322 | !!! this is a ALSA internal function, so no control is used !!! | ||
323 | |||
324 | |||
325 | |||
326 | Calling Parameter: | ||
327 | |||
328 | index int array (min = 1, max = 8), | ||
329 | "Index value for RME HDSPM interface." card-index within ALSA | ||
330 | |||
331 | note: ALSA-standard | ||
332 | |||
333 | id string array (min = 1, max = 8), | ||
334 | "ID string for RME HDSPM interface." | ||
335 | |||
336 | note: ALSA-standard | ||
337 | |||
338 | enable int array (min = 1, max = 8), | ||
339 | "Enable/disable specific HDSPM sound-cards." | ||
340 | |||
341 | note: ALSA-standard | ||
342 | |||
343 | precise_ptr int array (min = 1, max = 8), | ||
344 | "Enable precise pointer, or disable." | ||
345 | |||
346 | note: Use only when the application supports this (which is a special case). | ||
347 | |||
348 | line_outs_monitor int array (min = 1, max = 8), | ||
349 | "Send playback streams to analog outs by default." | ||
350 | |||
351 | |||
352 | note: each playback channel is mixed to the same numbered output | ||
353 | channel (routed). This is against the ALSA-convention, where all | ||
354 | channels have to be muted on after loading the driver, but was | ||
355 | used before on other cards, so i historically use it again) | ||
356 | |||
357 | |||
358 | |||
359 | enable_monitor int array (min = 1, max = 8), | ||
360 | "Enable Analog Out on Channel 63/64 by default." | ||
361 | |||
362 | note: here the analog output is enabled (but not routed). \ No newline at end of file | ||
diff --git a/Documentation/w1/w1.generic b/Documentation/w1/w1.generic index eace3046a858..f937fbe1cacb 100644 --- a/Documentation/w1/w1.generic +++ b/Documentation/w1/w1.generic | |||
@@ -1,19 +1,92 @@ | |||
1 | Any w1 device must be connected to w1 bus master device - for example | 1 | The 1-wire (w1) subsystem |
2 | ds9490 usb device or w1-over-GPIO or RS232 converter. | 2 | ------------------------------------------------------------------ |
3 | Driver for w1 bus master must provide several functions(you can find | 3 | The 1-wire bus is a simple master-slave bus that communicates via a single |
4 | them in struct w1_bus_master definition in w1.h) which then will be | 4 | signal wire (plus ground, so two wires). |
5 | called by w1 core to send various commands over w1 bus(by default it is | 5 | |
6 | reset and search commands). When some device is found on the bus, w1 core | 6 | Devices communicate on the bus by pulling the signal to ground via an open |
7 | checks if driver for it's family is loaded. | 7 | drain output and by sampling the logic level of the signal line. |
8 | If driver is loaded w1 core creates new w1_slave object and registers it | 8 | |
9 | in the system(creates some generic sysfs files(struct w1_family_ops in | 9 | The w1 subsystem provides the framework for managing w1 masters and |
10 | w1_family.h), notifies any registered listener and so on...). | 10 | communication with slaves. |
11 | It is device driver's business to provide any communication method | 11 | |
12 | upstream. | 12 | All w1 slave devices must be connected to a w1 bus master device. |
13 | For example w1_therm driver(ds18?20 thermal sensor family driver) | 13 | |
14 | provides temperature reading function which is bound to ->rbin() method | 14 | Example w1 master devices: |
15 | of the above w1_family_ops structure. | 15 | DS9490 usb device |
16 | w1_smem - driver for simple 64bit memory cell provides ID reading | 16 | W1-over-GPIO |
17 | method. | 17 | DS2482 (i2c to w1 bridge) |
18 | Emulated devices, such as a RS232 converter, parallel port adapter, etc | ||
19 | |||
20 | |||
21 | What does the w1 subsystem do? | ||
22 | ------------------------------------------------------------------ | ||
23 | When a w1 master driver registers with the w1 subsystem, the following occurs: | ||
24 | |||
25 | - sysfs entries for that w1 master are created | ||
26 | - the w1 bus is periodically searched for new slave devices | ||
27 | |||
28 | When a device is found on the bus, w1 core checks if driver for it's family is | ||
29 | loaded. If so, the family driver is attached to the slave. | ||
30 | If there is no driver for the family, a simple sysfs entry is created | ||
31 | for the slave device. | ||
32 | |||
33 | |||
34 | W1 device families | ||
35 | ------------------------------------------------------------------ | ||
36 | Slave devices are handled by a driver written for a family of w1 devices. | ||
37 | |||
38 | A family driver populates a struct w1_family_ops (see w1_family.h) and | ||
39 | registers with the w1 subsystem. | ||
40 | |||
41 | Current family drivers: | ||
42 | w1_therm - (ds18?20 thermal sensor family driver) | ||
43 | provides temperature reading function which is bound to ->rbin() method | ||
44 | of the above w1_family_ops structure. | ||
45 | |||
46 | w1_smem - driver for simple 64bit memory cell provides ID reading method. | ||
18 | 47 | ||
19 | You can call above methods by reading appropriate sysfs files. | 48 | You can call above methods by reading appropriate sysfs files. |
49 | |||
50 | |||
51 | What does a w1 master driver need to implement? | ||
52 | ------------------------------------------------------------------ | ||
53 | |||
54 | The driver for w1 bus master must provide at minimum two functions. | ||
55 | |||
56 | Emulated devices must provide the ability to set the output signal level | ||
57 | (write_bit) and sample the signal level (read_bit). | ||
58 | |||
59 | Devices that support the 1-wire natively must provide the ability to write and | ||
60 | sample a bit (touch_bit) and reset the bus (reset_bus). | ||
61 | |||
62 | Most hardware provides higher-level functions that offload w1 handling. | ||
63 | See struct w1_bus_master definition in w1.h for details. | ||
64 | |||
65 | |||
66 | w1 master sysfs interface | ||
67 | ------------------------------------------------------------------ | ||
68 | <xx-xxxxxxxxxxxxx> - a directory for a found device. The format is family-serial | ||
69 | bus - (standard) symlink to the w1 bus | ||
70 | driver - (standard) symlink to the w1 driver | ||
71 | w1_master_attempts - the number of times a search was attempted | ||
72 | w1_master_max_slave_count | ||
73 | - the maximum slaves that may be attached to a master | ||
74 | w1_master_name - the name of the device (w1_bus_masterX) | ||
75 | w1_master_search - the number of searches left to do, -1=continual (default) | ||
76 | w1_master_slave_count | ||
77 | - the number of slaves found | ||
78 | w1_master_slaves - the names of the slaves, one per line | ||
79 | w1_master_timeout - the delay in seconds between searches | ||
80 | |||
81 | If you have a w1 bus that never changes (you don't add or remove devices), | ||
82 | you can set w1_master_search to a positive value to disable searches. | ||
83 | |||
84 | |||
85 | w1 slave sysfs interface | ||
86 | ------------------------------------------------------------------ | ||
87 | bus - (standard) symlink to the w1 bus | ||
88 | driver - (standard) symlink to the w1 driver | ||
89 | name - the device name, usually the same as the directory name | ||
90 | w1_slave - (optional) a binary file whose meaning depends on the | ||
91 | family driver | ||
92 | |||
diff --git a/MAINTAINERS b/MAINTAINERS index 0f88a70a15d8..4d44824884ef 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -194,7 +194,7 @@ S: Maintained | |||
194 | ADM1025 HARDWARE MONITOR DRIVER | 194 | ADM1025 HARDWARE MONITOR DRIVER |
195 | P: Jean Delvare | 195 | P: Jean Delvare |
196 | M: khali@linux-fr.org | 196 | M: khali@linux-fr.org |
197 | L: sensors@stimpy.netroedge.com | 197 | L: lm-sensors@lm-sensors.org |
198 | S: Maintained | 198 | S: Maintained |
199 | 199 | ||
200 | ADT746X FAN DRIVER | 200 | ADT746X FAN DRIVER |
@@ -242,7 +242,7 @@ S: Maintained | |||
242 | ALI1563 I2C DRIVER | 242 | ALI1563 I2C DRIVER |
243 | P: Rudolf Marek | 243 | P: Rudolf Marek |
244 | M: r.marek@sh.cvut.cz | 244 | M: r.marek@sh.cvut.cz |
245 | L: sensors@stimpy.netroedge.com | 245 | L: lm-sensors@lm-sensors.org |
246 | S: Maintained | 246 | S: Maintained |
247 | 247 | ||
248 | ALPHA PORT | 248 | ALPHA PORT |
@@ -1002,7 +1002,7 @@ P: Greg Kroah-Hartman | |||
1002 | M: greg@kroah.com | 1002 | M: greg@kroah.com |
1003 | P: Jean Delvare | 1003 | P: Jean Delvare |
1004 | M: khali@linux-fr.org | 1004 | M: khali@linux-fr.org |
1005 | L: sensors@stimpy.netroedge.com | 1005 | L: lm-sensors@lm-sensors.org |
1006 | W: http://www.lm-sensors.nu/ | 1006 | W: http://www.lm-sensors.nu/ |
1007 | S: Maintained | 1007 | S: Maintained |
1008 | 1008 | ||
@@ -1430,13 +1430,13 @@ S: Supported | |||
1430 | LM83 HARDWARE MONITOR DRIVER | 1430 | LM83 HARDWARE MONITOR DRIVER |
1431 | P: Jean Delvare | 1431 | P: Jean Delvare |
1432 | M: khali@linux-fr.org | 1432 | M: khali@linux-fr.org |
1433 | L: sensors@stimpy.netroedge.com | 1433 | L: lm-sensors@lm-sensors.org |
1434 | S: Maintained | 1434 | S: Maintained |
1435 | 1435 | ||
1436 | LM90 HARDWARE MONITOR DRIVER | 1436 | LM90 HARDWARE MONITOR DRIVER |
1437 | P: Jean Delvare | 1437 | P: Jean Delvare |
1438 | M: khali@linux-fr.org | 1438 | M: khali@linux-fr.org |
1439 | L: sensors@stimpy.netroedge.com | 1439 | L: lm-sensors@lm-sensors.org |
1440 | S: Maintained | 1440 | S: Maintained |
1441 | 1441 | ||
1442 | LOGICAL DISK MANAGER SUPPORT (LDM, Windows 2000/XP Dynamic Disks) | 1442 | LOGICAL DISK MANAGER SUPPORT (LDM, Windows 2000/XP Dynamic Disks) |
@@ -2075,7 +2075,7 @@ S: Maintained | |||
2075 | SMSC47M1 HARDWARE MONITOR DRIVER | 2075 | SMSC47M1 HARDWARE MONITOR DRIVER |
2076 | P: Jean Delvare | 2076 | P: Jean Delvare |
2077 | M: khali@linux-fr.org | 2077 | M: khali@linux-fr.org |
2078 | L: sensors@stimpy.netroedge.com | 2078 | L: lm-sensors@lm-sensors.org |
2079 | S: Odd Fixes | 2079 | S: Odd Fixes |
2080 | 2080 | ||
2081 | SMB FILESYSTEM | 2081 | SMB FILESYSTEM |
@@ -2614,7 +2614,7 @@ S: Orphan | |||
2614 | W1 DALLAS'S 1-WIRE BUS | 2614 | W1 DALLAS'S 1-WIRE BUS |
2615 | P: Evgeniy Polyakov | 2615 | P: Evgeniy Polyakov |
2616 | M: johnpol@2ka.mipt.ru | 2616 | M: johnpol@2ka.mipt.ru |
2617 | L: sensors@stimpy.netroedge.com | 2617 | L: lm-sensors@lm-sensors.org |
2618 | S: Maintained | 2618 | S: Maintained |
2619 | 2619 | ||
2620 | W83L51xD SD/MMC CARD INTERFACE DRIVER | 2620 | W83L51xD SD/MMC CARD INTERFACE DRIVER |
@@ -2627,7 +2627,7 @@ S: Maintained | |||
2627 | W83L785TS HARDWARE MONITOR DRIVER | 2627 | W83L785TS HARDWARE MONITOR DRIVER |
2628 | P: Jean Delvare | 2628 | P: Jean Delvare |
2629 | M: khali@linux-fr.org | 2629 | M: khali@linux-fr.org |
2630 | L: sensors@stimpy.netroedge.com | 2630 | L: lm-sensors@lm-sensors.org |
2631 | S: Odd Fixes | 2631 | S: Odd Fixes |
2632 | 2632 | ||
2633 | WAN ROUTER & SANGOMA WANPIPE DRIVERS & API (X.25, FRAME RELAY, PPP, CISCO HDLC) | 2633 | WAN ROUTER & SANGOMA WANPIPE DRIVERS & API (X.25, FRAME RELAY, PPP, CISCO HDLC) |
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig index 34e603cc1716..ce4dfa8b834d 100644 --- a/arch/ia64/Kconfig +++ b/arch/ia64/Kconfig | |||
@@ -220,7 +220,7 @@ config IOSAPIC | |||
220 | 220 | ||
221 | config IA64_SGI_SN_SIM | 221 | config IA64_SGI_SN_SIM |
222 | bool "SGI Medusa Simulator Support" | 222 | bool "SGI Medusa Simulator Support" |
223 | depends on IA64_SGI_SN2 | 223 | depends on IA64_SGI_SN2 || IA64_GENERIC |
224 | help | 224 | help |
225 | If you are compiling a kernel that will run under SGI's IA-64 | 225 | If you are compiling a kernel that will run under SGI's IA-64 |
226 | simulator (Medusa) then say Y, otherwise say N. | 226 | simulator (Medusa) then say Y, otherwise say N. |
diff --git a/arch/ia64/configs/tiger_defconfig b/arch/ia64/configs/tiger_defconfig index 9086b789f6ac..47f45341ac62 100644 --- a/arch/ia64/configs/tiger_defconfig +++ b/arch/ia64/configs/tiger_defconfig | |||
@@ -1,7 +1,7 @@ | |||
1 | # | 1 | # |
2 | # Automatically generated make config: don't edit | 2 | # Automatically generated make config: don't edit |
3 | # Linux kernel version: 2.6.12-rc3 | 3 | # Linux kernel version: 2.6.12-20050621 |
4 | # Tue May 3 15:55:04 2005 | 4 | # Tue Jun 21 14:03:24 2005 |
5 | # | 5 | # |
6 | 6 | ||
7 | # | 7 | # |
@@ -67,6 +67,7 @@ CONFIG_GENERIC_CALIBRATE_DELAY=y | |||
67 | CONFIG_TIME_INTERPOLATION=y | 67 | CONFIG_TIME_INTERPOLATION=y |
68 | CONFIG_EFI=y | 68 | CONFIG_EFI=y |
69 | CONFIG_GENERIC_IOMAP=y | 69 | CONFIG_GENERIC_IOMAP=y |
70 | CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y | ||
70 | # CONFIG_IA64_GENERIC is not set | 71 | # CONFIG_IA64_GENERIC is not set |
71 | CONFIG_IA64_DIG=y | 72 | CONFIG_IA64_DIG=y |
72 | # CONFIG_IA64_HP_ZX1 is not set | 73 | # CONFIG_IA64_HP_ZX1 is not set |
@@ -285,6 +286,7 @@ CONFIG_CHR_DEV_ST=m | |||
285 | CONFIG_BLK_DEV_SR=m | 286 | CONFIG_BLK_DEV_SR=m |
286 | # CONFIG_BLK_DEV_SR_VENDOR is not set | 287 | # CONFIG_BLK_DEV_SR_VENDOR is not set |
287 | CONFIG_CHR_DEV_SG=m | 288 | CONFIG_CHR_DEV_SG=m |
289 | # CONFIG_CHR_DEV_SCH is not set | ||
288 | 290 | ||
289 | # | 291 | # |
290 | # Some SCSI devices (e.g. CD jukebox) support multiple LUNs | 292 | # Some SCSI devices (e.g. CD jukebox) support multiple LUNs |
@@ -313,11 +315,8 @@ CONFIG_SCSI_FC_ATTRS=y | |||
313 | # CONFIG_MEGARAID_NEWGEN is not set | 315 | # CONFIG_MEGARAID_NEWGEN is not set |
314 | # CONFIG_MEGARAID_LEGACY is not set | 316 | # CONFIG_MEGARAID_LEGACY is not set |
315 | # CONFIG_SCSI_SATA is not set | 317 | # CONFIG_SCSI_SATA is not set |
316 | # CONFIG_SCSI_BUSLOGIC is not set | ||
317 | # CONFIG_SCSI_DMX3191D is not set | 318 | # CONFIG_SCSI_DMX3191D is not set |
318 | # CONFIG_SCSI_EATA is not set | ||
319 | # CONFIG_SCSI_FUTURE_DOMAIN is not set | 319 | # CONFIG_SCSI_FUTURE_DOMAIN is not set |
320 | # CONFIG_SCSI_GDTH is not set | ||
321 | # CONFIG_SCSI_IPS is not set | 320 | # CONFIG_SCSI_IPS is not set |
322 | # CONFIG_SCSI_INITIO is not set | 321 | # CONFIG_SCSI_INITIO is not set |
323 | # CONFIG_SCSI_INIA100 is not set | 322 | # CONFIG_SCSI_INIA100 is not set |
@@ -366,8 +365,10 @@ CONFIG_DM_ZERO=m | |||
366 | # Fusion MPT device support | 365 | # Fusion MPT device support |
367 | # | 366 | # |
368 | CONFIG_FUSION=y | 367 | CONFIG_FUSION=y |
369 | CONFIG_FUSION_MAX_SGE=40 | 368 | CONFIG_FUSION_SPI=y |
370 | # CONFIG_FUSION_CTL is not set | 369 | CONFIG_FUSION_FC=y |
370 | CONFIG_FUSION_MAX_SGE=128 | ||
371 | CONFIG_FUSION_CTL=y | ||
371 | 372 | ||
372 | # | 373 | # |
373 | # IEEE 1394 (FireWire) support | 374 | # IEEE 1394 (FireWire) support |
@@ -506,9 +507,11 @@ CONFIG_E1000=y | |||
506 | # CONFIG_HAMACHI is not set | 507 | # CONFIG_HAMACHI is not set |
507 | # CONFIG_YELLOWFIN is not set | 508 | # CONFIG_YELLOWFIN is not set |
508 | # CONFIG_R8169 is not set | 509 | # CONFIG_R8169 is not set |
510 | # CONFIG_SKGE is not set | ||
509 | # CONFIG_SK98LIN is not set | 511 | # CONFIG_SK98LIN is not set |
510 | # CONFIG_VIA_VELOCITY is not set | 512 | # CONFIG_VIA_VELOCITY is not set |
511 | CONFIG_TIGON3=y | 513 | CONFIG_TIGON3=y |
514 | # CONFIG_BNX2 is not set | ||
512 | 515 | ||
513 | # | 516 | # |
514 | # Ethernet (10000 Mbit) | 517 | # Ethernet (10000 Mbit) |
@@ -598,7 +601,6 @@ CONFIG_GAMEPORT=m | |||
598 | # CONFIG_GAMEPORT_VORTEX is not set | 601 | # CONFIG_GAMEPORT_VORTEX is not set |
599 | # CONFIG_GAMEPORT_FM801 is not set | 602 | # CONFIG_GAMEPORT_FM801 is not set |
600 | # CONFIG_GAMEPORT_CS461X is not set | 603 | # CONFIG_GAMEPORT_CS461X is not set |
601 | CONFIG_SOUND_GAMEPORT=m | ||
602 | 604 | ||
603 | # | 605 | # |
604 | # Character devices | 606 | # Character devices |
@@ -611,7 +613,6 @@ CONFIG_SERIAL_NONSTANDARD=y | |||
611 | # CONFIG_CYCLADES is not set | 613 | # CONFIG_CYCLADES is not set |
612 | # CONFIG_MOXA_SMARTIO is not set | 614 | # CONFIG_MOXA_SMARTIO is not set |
613 | # CONFIG_ISI is not set | 615 | # CONFIG_ISI is not set |
614 | # CONFIG_SYNCLINK is not set | ||
615 | # CONFIG_SYNCLINKMP is not set | 616 | # CONFIG_SYNCLINKMP is not set |
616 | # CONFIG_N_HDLC is not set | 617 | # CONFIG_N_HDLC is not set |
617 | # CONFIG_SPECIALIX is not set | 618 | # CONFIG_SPECIALIX is not set |
diff --git a/arch/ia64/defconfig b/arch/ia64/defconfig index 9997ef45ab23..7be8096e0561 100644 --- a/arch/ia64/defconfig +++ b/arch/ia64/defconfig | |||
@@ -1,7 +1,7 @@ | |||
1 | # | 1 | # |
2 | # Automatically generated make config: don't edit | 2 | # Automatically generated make config: don't edit |
3 | # Linux kernel version: 2.6.10 | 3 | # Linux kernel version: 2.6.12 |
4 | # Thu Jan 6 11:13:13 2005 | 4 | # Tue Jun 21 11:30:42 2005 |
5 | # | 5 | # |
6 | 6 | ||
7 | # | 7 | # |
@@ -10,6 +10,7 @@ | |||
10 | CONFIG_EXPERIMENTAL=y | 10 | CONFIG_EXPERIMENTAL=y |
11 | CONFIG_CLEAN_COMPILE=y | 11 | CONFIG_CLEAN_COMPILE=y |
12 | CONFIG_LOCK_KERNEL=y | 12 | CONFIG_LOCK_KERNEL=y |
13 | CONFIG_INIT_ENV_ARG_LIMIT=32 | ||
13 | 14 | ||
14 | # | 15 | # |
15 | # General setup | 16 | # General setup |
@@ -21,24 +22,27 @@ CONFIG_POSIX_MQUEUE=y | |||
21 | # CONFIG_BSD_PROCESS_ACCT is not set | 22 | # CONFIG_BSD_PROCESS_ACCT is not set |
22 | CONFIG_SYSCTL=y | 23 | CONFIG_SYSCTL=y |
23 | # CONFIG_AUDIT is not set | 24 | # CONFIG_AUDIT is not set |
24 | CONFIG_LOG_BUF_SHIFT=20 | ||
25 | CONFIG_HOTPLUG=y | 25 | CONFIG_HOTPLUG=y |
26 | CONFIG_KOBJECT_UEVENT=y | 26 | CONFIG_KOBJECT_UEVENT=y |
27 | CONFIG_IKCONFIG=y | 27 | CONFIG_IKCONFIG=y |
28 | CONFIG_IKCONFIG_PROC=y | 28 | CONFIG_IKCONFIG_PROC=y |
29 | # CONFIG_CPUSETS is not set | ||
29 | # CONFIG_EMBEDDED is not set | 30 | # CONFIG_EMBEDDED is not set |
30 | CONFIG_KALLSYMS=y | 31 | CONFIG_KALLSYMS=y |
31 | CONFIG_KALLSYMS_ALL=y | 32 | CONFIG_KALLSYMS_ALL=y |
32 | # CONFIG_KALLSYMS_EXTRA_PASS is not set | 33 | # CONFIG_KALLSYMS_EXTRA_PASS is not set |
34 | CONFIG_PRINTK=y | ||
35 | CONFIG_BUG=y | ||
36 | CONFIG_BASE_FULL=y | ||
33 | CONFIG_FUTEX=y | 37 | CONFIG_FUTEX=y |
34 | CONFIG_EPOLL=y | 38 | CONFIG_EPOLL=y |
35 | # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set | ||
36 | CONFIG_SHMEM=y | 39 | CONFIG_SHMEM=y |
37 | CONFIG_CC_ALIGN_FUNCTIONS=0 | 40 | CONFIG_CC_ALIGN_FUNCTIONS=0 |
38 | CONFIG_CC_ALIGN_LABELS=0 | 41 | CONFIG_CC_ALIGN_LABELS=0 |
39 | CONFIG_CC_ALIGN_LOOPS=0 | 42 | CONFIG_CC_ALIGN_LOOPS=0 |
40 | CONFIG_CC_ALIGN_JUMPS=0 | 43 | CONFIG_CC_ALIGN_JUMPS=0 |
41 | # CONFIG_TINY_SHMEM is not set | 44 | # CONFIG_TINY_SHMEM is not set |
45 | CONFIG_BASE_SMALL=0 | ||
42 | 46 | ||
43 | # | 47 | # |
44 | # Loadable module support | 48 | # Loadable module support |
@@ -63,9 +67,11 @@ CONFIG_GENERIC_CALIBRATE_DELAY=y | |||
63 | CONFIG_TIME_INTERPOLATION=y | 67 | CONFIG_TIME_INTERPOLATION=y |
64 | CONFIG_EFI=y | 68 | CONFIG_EFI=y |
65 | CONFIG_GENERIC_IOMAP=y | 69 | CONFIG_GENERIC_IOMAP=y |
70 | CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y | ||
66 | CONFIG_IA64_GENERIC=y | 71 | CONFIG_IA64_GENERIC=y |
67 | # CONFIG_IA64_DIG is not set | 72 | # CONFIG_IA64_DIG is not set |
68 | # CONFIG_IA64_HP_ZX1 is not set | 73 | # CONFIG_IA64_HP_ZX1 is not set |
74 | # CONFIG_IA64_HP_ZX1_SWIOTLB is not set | ||
69 | # CONFIG_IA64_SGI_SN2 is not set | 75 | # CONFIG_IA64_SGI_SN2 is not set |
70 | # CONFIG_IA64_HP_SIM is not set | 76 | # CONFIG_IA64_HP_SIM is not set |
71 | # CONFIG_ITANIUM is not set | 77 | # CONFIG_ITANIUM is not set |
@@ -77,6 +83,7 @@ CONFIG_IA64_PAGE_SIZE_16KB=y | |||
77 | CONFIG_IA64_L1_CACHE_SHIFT=7 | 83 | CONFIG_IA64_L1_CACHE_SHIFT=7 |
78 | CONFIG_NUMA=y | 84 | CONFIG_NUMA=y |
79 | CONFIG_VIRTUAL_MEM_MAP=y | 85 | CONFIG_VIRTUAL_MEM_MAP=y |
86 | CONFIG_HOLES_IN_ZONE=y | ||
80 | CONFIG_DISCONTIGMEM=y | 87 | CONFIG_DISCONTIGMEM=y |
81 | CONFIG_IA64_CYCLONE=y | 88 | CONFIG_IA64_CYCLONE=y |
82 | CONFIG_IOSAPIC=y | 89 | CONFIG_IOSAPIC=y |
@@ -84,6 +91,7 @@ CONFIG_FORCE_MAX_ZONEORDER=18 | |||
84 | CONFIG_SMP=y | 91 | CONFIG_SMP=y |
85 | CONFIG_NR_CPUS=512 | 92 | CONFIG_NR_CPUS=512 |
86 | CONFIG_HOTPLUG_CPU=y | 93 | CONFIG_HOTPLUG_CPU=y |
94 | # CONFIG_SCHED_SMT is not set | ||
87 | # CONFIG_PREEMPT is not set | 95 | # CONFIG_PREEMPT is not set |
88 | CONFIG_HAVE_DEC_LOCK=y | 96 | CONFIG_HAVE_DEC_LOCK=y |
89 | CONFIG_IA32_SUPPORT=y | 97 | CONFIG_IA32_SUPPORT=y |
@@ -135,6 +143,7 @@ CONFIG_PCI_DOMAINS=y | |||
135 | # CONFIG_PCI_MSI is not set | 143 | # CONFIG_PCI_MSI is not set |
136 | CONFIG_PCI_LEGACY_PROC=y | 144 | CONFIG_PCI_LEGACY_PROC=y |
137 | CONFIG_PCI_NAMES=y | 145 | CONFIG_PCI_NAMES=y |
146 | # CONFIG_PCI_DEBUG is not set | ||
138 | 147 | ||
139 | # | 148 | # |
140 | # PCI Hotplug Support | 149 | # PCI Hotplug Support |
@@ -144,7 +153,6 @@ CONFIG_HOTPLUG_PCI=m | |||
144 | CONFIG_HOTPLUG_PCI_ACPI=m | 153 | CONFIG_HOTPLUG_PCI_ACPI=m |
145 | # CONFIG_HOTPLUG_PCI_ACPI_IBM is not set | 154 | # CONFIG_HOTPLUG_PCI_ACPI_IBM is not set |
146 | # CONFIG_HOTPLUG_PCI_CPCI is not set | 155 | # CONFIG_HOTPLUG_PCI_CPCI is not set |
147 | # CONFIG_HOTPLUG_PCI_PCIE is not set | ||
148 | # CONFIG_HOTPLUG_PCI_SHPC is not set | 156 | # CONFIG_HOTPLUG_PCI_SHPC is not set |
149 | 157 | ||
150 | # | 158 | # |
@@ -153,10 +161,6 @@ CONFIG_HOTPLUG_PCI_ACPI=m | |||
153 | # CONFIG_PCCARD is not set | 161 | # CONFIG_PCCARD is not set |
154 | 162 | ||
155 | # | 163 | # |
156 | # PC-card bridges | ||
157 | # | ||
158 | |||
159 | # | ||
160 | # Device Drivers | 164 | # Device Drivers |
161 | # | 165 | # |
162 | 166 | ||
@@ -190,6 +194,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y | |||
190 | # CONFIG_BLK_CPQ_CISS_DA is not set | 194 | # CONFIG_BLK_CPQ_CISS_DA is not set |
191 | # CONFIG_BLK_DEV_DAC960 is not set | 195 | # CONFIG_BLK_DEV_DAC960 is not set |
192 | # CONFIG_BLK_DEV_UMEM is not set | 196 | # CONFIG_BLK_DEV_UMEM is not set |
197 | # CONFIG_BLK_DEV_COW_COMMON is not set | ||
193 | CONFIG_BLK_DEV_LOOP=m | 198 | CONFIG_BLK_DEV_LOOP=m |
194 | CONFIG_BLK_DEV_CRYPTOLOOP=m | 199 | CONFIG_BLK_DEV_CRYPTOLOOP=m |
195 | CONFIG_BLK_DEV_NBD=m | 200 | CONFIG_BLK_DEV_NBD=m |
@@ -209,6 +214,7 @@ CONFIG_IOSCHED_NOOP=y | |||
209 | CONFIG_IOSCHED_AS=y | 214 | CONFIG_IOSCHED_AS=y |
210 | CONFIG_IOSCHED_DEADLINE=y | 215 | CONFIG_IOSCHED_DEADLINE=y |
211 | CONFIG_IOSCHED_CFQ=y | 216 | CONFIG_IOSCHED_CFQ=y |
217 | # CONFIG_ATA_OVER_ETH is not set | ||
212 | 218 | ||
213 | # | 219 | # |
214 | # ATA/ATAPI/MFM/RLL support | 220 | # ATA/ATAPI/MFM/RLL support |
@@ -283,6 +289,7 @@ CONFIG_CHR_DEV_ST=m | |||
283 | CONFIG_BLK_DEV_SR=m | 289 | CONFIG_BLK_DEV_SR=m |
284 | # CONFIG_BLK_DEV_SR_VENDOR is not set | 290 | # CONFIG_BLK_DEV_SR_VENDOR is not set |
285 | CONFIG_CHR_DEV_SG=m | 291 | CONFIG_CHR_DEV_SG=m |
292 | # CONFIG_CHR_DEV_SCH is not set | ||
286 | 293 | ||
287 | # | 294 | # |
288 | # Some SCSI devices (e.g. CD jukebox) support multiple LUNs | 295 | # Some SCSI devices (e.g. CD jukebox) support multiple LUNs |
@@ -310,13 +317,21 @@ CONFIG_SCSI_FC_ATTRS=y | |||
310 | # CONFIG_SCSI_AIC79XX is not set | 317 | # CONFIG_SCSI_AIC79XX is not set |
311 | # CONFIG_MEGARAID_NEWGEN is not set | 318 | # CONFIG_MEGARAID_NEWGEN is not set |
312 | # CONFIG_MEGARAID_LEGACY is not set | 319 | # CONFIG_MEGARAID_LEGACY is not set |
313 | # CONFIG_SCSI_SATA is not set | 320 | CONFIG_SCSI_SATA=y |
314 | # CONFIG_SCSI_BUSLOGIC is not set | 321 | # CONFIG_SCSI_SATA_AHCI is not set |
322 | # CONFIG_SCSI_SATA_SVW is not set | ||
323 | # CONFIG_SCSI_ATA_PIIX is not set | ||
324 | # CONFIG_SCSI_SATA_NV is not set | ||
325 | # CONFIG_SCSI_SATA_PROMISE is not set | ||
326 | # CONFIG_SCSI_SATA_QSTOR is not set | ||
327 | # CONFIG_SCSI_SATA_SX4 is not set | ||
328 | # CONFIG_SCSI_SATA_SIL is not set | ||
329 | # CONFIG_SCSI_SATA_SIS is not set | ||
330 | # CONFIG_SCSI_SATA_ULI is not set | ||
331 | # CONFIG_SCSI_SATA_VIA is not set | ||
332 | CONFIG_SCSI_SATA_VITESSE=y | ||
315 | # CONFIG_SCSI_DMX3191D is not set | 333 | # CONFIG_SCSI_DMX3191D is not set |
316 | # CONFIG_SCSI_EATA is not set | ||
317 | # CONFIG_SCSI_EATA_PIO is not set | ||
318 | # CONFIG_SCSI_FUTURE_DOMAIN is not set | 334 | # CONFIG_SCSI_FUTURE_DOMAIN is not set |
319 | # CONFIG_SCSI_GDTH is not set | ||
320 | # CONFIG_SCSI_IPS is not set | 335 | # CONFIG_SCSI_IPS is not set |
321 | # CONFIG_SCSI_INITIO is not set | 336 | # CONFIG_SCSI_INITIO is not set |
322 | # CONFIG_SCSI_INIA100 is not set | 337 | # CONFIG_SCSI_INIA100 is not set |
@@ -326,7 +341,6 @@ CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 | |||
326 | CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 | 341 | CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 |
327 | # CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set | 342 | # CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set |
328 | # CONFIG_SCSI_IPR is not set | 343 | # CONFIG_SCSI_IPR is not set |
329 | # CONFIG_SCSI_QLOGIC_ISP is not set | ||
330 | CONFIG_SCSI_QLOGIC_FC=y | 344 | CONFIG_SCSI_QLOGIC_FC=y |
331 | # CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set | 345 | # CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set |
332 | CONFIG_SCSI_QLOGIC_1280=y | 346 | CONFIG_SCSI_QLOGIC_1280=y |
@@ -337,6 +351,7 @@ CONFIG_SCSI_QLA22XX=m | |||
337 | CONFIG_SCSI_QLA2300=m | 351 | CONFIG_SCSI_QLA2300=m |
338 | CONFIG_SCSI_QLA2322=m | 352 | CONFIG_SCSI_QLA2322=m |
339 | # CONFIG_SCSI_QLA6312 is not set | 353 | # CONFIG_SCSI_QLA6312 is not set |
354 | # CONFIG_SCSI_LPFC is not set | ||
340 | # CONFIG_SCSI_DC395x is not set | 355 | # CONFIG_SCSI_DC395x is not set |
341 | # CONFIG_SCSI_DC390T is not set | 356 | # CONFIG_SCSI_DC390T is not set |
342 | # CONFIG_SCSI_DEBUG is not set | 357 | # CONFIG_SCSI_DEBUG is not set |
@@ -359,12 +374,16 @@ CONFIG_DM_CRYPT=m | |||
359 | CONFIG_DM_SNAPSHOT=m | 374 | CONFIG_DM_SNAPSHOT=m |
360 | CONFIG_DM_MIRROR=m | 375 | CONFIG_DM_MIRROR=m |
361 | CONFIG_DM_ZERO=m | 376 | CONFIG_DM_ZERO=m |
377 | CONFIG_DM_MULTIPATH=m | ||
378 | # CONFIG_DM_MULTIPATH_EMC is not set | ||
362 | 379 | ||
363 | # | 380 | # |
364 | # Fusion MPT device support | 381 | # Fusion MPT device support |
365 | # | 382 | # |
366 | CONFIG_FUSION=y | 383 | CONFIG_FUSION=y |
367 | CONFIG_FUSION_MAX_SGE=40 | 384 | CONFIG_FUSION_SPI=y |
385 | CONFIG_FUSION_FC=m | ||
386 | CONFIG_FUSION_MAX_SGE=128 | ||
368 | # CONFIG_FUSION_CTL is not set | 387 | # CONFIG_FUSION_CTL is not set |
369 | 388 | ||
370 | # | 389 | # |
@@ -387,7 +406,6 @@ CONFIG_NET=y | |||
387 | # | 406 | # |
388 | CONFIG_PACKET=y | 407 | CONFIG_PACKET=y |
389 | # CONFIG_PACKET_MMAP is not set | 408 | # CONFIG_PACKET_MMAP is not set |
390 | CONFIG_NETLINK_DEV=y | ||
391 | CONFIG_UNIX=y | 409 | CONFIG_UNIX=y |
392 | # CONFIG_NET_KEY is not set | 410 | # CONFIG_NET_KEY is not set |
393 | CONFIG_INET=y | 411 | CONFIG_INET=y |
@@ -447,7 +465,6 @@ CONFIG_DUMMY=m | |||
447 | # CONFIG_BONDING is not set | 465 | # CONFIG_BONDING is not set |
448 | # CONFIG_EQUALIZER is not set | 466 | # CONFIG_EQUALIZER is not set |
449 | # CONFIG_TUN is not set | 467 | # CONFIG_TUN is not set |
450 | # CONFIG_ETHERTAP is not set | ||
451 | 468 | ||
452 | # | 469 | # |
453 | # ARCnet devices | 470 | # ARCnet devices |
@@ -484,9 +501,7 @@ CONFIG_NET_PCI=y | |||
484 | # CONFIG_FORCEDETH is not set | 501 | # CONFIG_FORCEDETH is not set |
485 | # CONFIG_DGRS is not set | 502 | # CONFIG_DGRS is not set |
486 | CONFIG_EEPRO100=m | 503 | CONFIG_EEPRO100=m |
487 | # CONFIG_EEPRO100_PIO is not set | ||
488 | CONFIG_E100=m | 504 | CONFIG_E100=m |
489 | # CONFIG_E100_NAPI is not set | ||
490 | # CONFIG_FEALNX is not set | 505 | # CONFIG_FEALNX is not set |
491 | # CONFIG_NATSEMI is not set | 506 | # CONFIG_NATSEMI is not set |
492 | # CONFIG_NE2K_PCI is not set | 507 | # CONFIG_NE2K_PCI is not set |
@@ -508,9 +523,11 @@ CONFIG_E1000=y | |||
508 | # CONFIG_HAMACHI is not set | 523 | # CONFIG_HAMACHI is not set |
509 | # CONFIG_YELLOWFIN is not set | 524 | # CONFIG_YELLOWFIN is not set |
510 | # CONFIG_R8169 is not set | 525 | # CONFIG_R8169 is not set |
526 | # CONFIG_SKGE is not set | ||
511 | # CONFIG_SK98LIN is not set | 527 | # CONFIG_SK98LIN is not set |
512 | # CONFIG_VIA_VELOCITY is not set | 528 | # CONFIG_VIA_VELOCITY is not set |
513 | CONFIG_TIGON3=y | 529 | CONFIG_TIGON3=y |
530 | # CONFIG_BNX2 is not set | ||
514 | 531 | ||
515 | # | 532 | # |
516 | # Ethernet (10000 Mbit) | 533 | # Ethernet (10000 Mbit) |
@@ -568,25 +585,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 | |||
568 | # CONFIG_INPUT_EVBUG is not set | 585 | # CONFIG_INPUT_EVBUG is not set |
569 | 586 | ||
570 | # | 587 | # |
571 | # Input I/O drivers | ||
572 | # | ||
573 | CONFIG_GAMEPORT=m | ||
574 | CONFIG_SOUND_GAMEPORT=m | ||
575 | # CONFIG_GAMEPORT_NS558 is not set | ||
576 | # CONFIG_GAMEPORT_L4 is not set | ||
577 | # CONFIG_GAMEPORT_EMU10K1 is not set | ||
578 | # CONFIG_GAMEPORT_VORTEX is not set | ||
579 | # CONFIG_GAMEPORT_FM801 is not set | ||
580 | # CONFIG_GAMEPORT_CS461x is not set | ||
581 | CONFIG_SERIO=y | ||
582 | CONFIG_SERIO_I8042=y | ||
583 | # CONFIG_SERIO_SERPORT is not set | ||
584 | # CONFIG_SERIO_CT82C710 is not set | ||
585 | # CONFIG_SERIO_PCIPS2 is not set | ||
586 | CONFIG_SERIO_LIBPS2=y | ||
587 | # CONFIG_SERIO_RAW is not set | ||
588 | |||
589 | # | ||
590 | # Input Device Drivers | 588 | # Input Device Drivers |
591 | # | 589 | # |
592 | CONFIG_INPUT_KEYBOARD=y | 590 | CONFIG_INPUT_KEYBOARD=y |
@@ -604,6 +602,23 @@ CONFIG_MOUSE_PS2=y | |||
604 | # CONFIG_INPUT_MISC is not set | 602 | # CONFIG_INPUT_MISC is not set |
605 | 603 | ||
606 | # | 604 | # |
605 | # Hardware I/O ports | ||
606 | # | ||
607 | CONFIG_SERIO=y | ||
608 | CONFIG_SERIO_I8042=y | ||
609 | # CONFIG_SERIO_SERPORT is not set | ||
610 | # CONFIG_SERIO_PCIPS2 is not set | ||
611 | CONFIG_SERIO_LIBPS2=y | ||
612 | # CONFIG_SERIO_RAW is not set | ||
613 | CONFIG_GAMEPORT=m | ||
614 | # CONFIG_GAMEPORT_NS558 is not set | ||
615 | # CONFIG_GAMEPORT_L4 is not set | ||
616 | # CONFIG_GAMEPORT_EMU10K1 is not set | ||
617 | # CONFIG_GAMEPORT_VORTEX is not set | ||
618 | # CONFIG_GAMEPORT_FM801 is not set | ||
619 | # CONFIG_GAMEPORT_CS461X is not set | ||
620 | |||
621 | # | ||
607 | # Character devices | 622 | # Character devices |
608 | # | 623 | # |
609 | CONFIG_VT=y | 624 | CONFIG_VT=y |
@@ -613,11 +628,15 @@ CONFIG_SERIAL_NONSTANDARD=y | |||
613 | # CONFIG_ROCKETPORT is not set | 628 | # CONFIG_ROCKETPORT is not set |
614 | # CONFIG_CYCLADES is not set | 629 | # CONFIG_CYCLADES is not set |
615 | # CONFIG_MOXA_SMARTIO is not set | 630 | # CONFIG_MOXA_SMARTIO is not set |
616 | # CONFIG_SYNCLINK is not set | 631 | # CONFIG_ISI is not set |
617 | # CONFIG_SYNCLINKMP is not set | 632 | # CONFIG_SYNCLINKMP is not set |
618 | # CONFIG_N_HDLC is not set | 633 | # CONFIG_N_HDLC is not set |
634 | # CONFIG_SPECIALIX is not set | ||
635 | # CONFIG_SX is not set | ||
619 | # CONFIG_STALDRV is not set | 636 | # CONFIG_STALDRV is not set |
620 | CONFIG_SGI_SNSC=y | 637 | CONFIG_SGI_SNSC=y |
638 | CONFIG_SGI_TIOCX=y | ||
639 | CONFIG_SGI_MBCS=m | ||
621 | 640 | ||
622 | # | 641 | # |
623 | # Serial drivers | 642 | # Serial drivers |
@@ -639,6 +658,7 @@ CONFIG_SERIAL_CORE=y | |||
639 | CONFIG_SERIAL_CORE_CONSOLE=y | 658 | CONFIG_SERIAL_CORE_CONSOLE=y |
640 | CONFIG_SERIAL_SGI_L1_CONSOLE=y | 659 | CONFIG_SERIAL_SGI_L1_CONSOLE=y |
641 | CONFIG_SERIAL_SGI_IOC4=y | 660 | CONFIG_SERIAL_SGI_IOC4=y |
661 | # CONFIG_SERIAL_JSM is not set | ||
642 | CONFIG_UNIX98_PTYS=y | 662 | CONFIG_UNIX98_PTYS=y |
643 | CONFIG_LEGACY_PTYS=y | 663 | CONFIG_LEGACY_PTYS=y |
644 | CONFIG_LEGACY_PTY_COUNT=256 | 664 | CONFIG_LEGACY_PTY_COUNT=256 |
@@ -664,6 +684,7 @@ CONFIG_EFI_RTC=y | |||
664 | CONFIG_AGP=m | 684 | CONFIG_AGP=m |
665 | CONFIG_AGP_I460=m | 685 | CONFIG_AGP_I460=m |
666 | CONFIG_AGP_HP_ZX1=m | 686 | CONFIG_AGP_HP_ZX1=m |
687 | CONFIG_AGP_SGI_TIOCA=m | ||
667 | CONFIG_DRM=m | 688 | CONFIG_DRM=m |
668 | CONFIG_DRM_TDFX=m | 689 | CONFIG_DRM_TDFX=m |
669 | CONFIG_DRM_R128=m | 690 | CONFIG_DRM_R128=m |
@@ -675,9 +696,15 @@ CONFIG_HPET=y | |||
675 | # CONFIG_HPET_RTC_IRQ is not set | 696 | # CONFIG_HPET_RTC_IRQ is not set |
676 | CONFIG_HPET_MMAP=y | 697 | CONFIG_HPET_MMAP=y |
677 | CONFIG_MAX_RAW_DEVS=256 | 698 | CONFIG_MAX_RAW_DEVS=256 |
699 | # CONFIG_HANGCHECK_TIMER is not set | ||
678 | CONFIG_MMTIMER=y | 700 | CONFIG_MMTIMER=y |
679 | 701 | ||
680 | # | 702 | # |
703 | # TPM devices | ||
704 | # | ||
705 | # CONFIG_TCG_TPM is not set | ||
706 | |||
707 | # | ||
681 | # I2C support | 708 | # I2C support |
682 | # | 709 | # |
683 | # CONFIG_I2C is not set | 710 | # CONFIG_I2C is not set |
@@ -761,6 +788,8 @@ CONFIG_SND_CS46XX=m | |||
761 | CONFIG_SND_CS46XX_NEW_DSP=y | 788 | CONFIG_SND_CS46XX_NEW_DSP=y |
762 | CONFIG_SND_CS4281=m | 789 | CONFIG_SND_CS4281=m |
763 | CONFIG_SND_EMU10K1=m | 790 | CONFIG_SND_EMU10K1=m |
791 | # CONFIG_SND_EMU10K1X is not set | ||
792 | # CONFIG_SND_CA0106 is not set | ||
764 | # CONFIG_SND_KORG1212 is not set | 793 | # CONFIG_SND_KORG1212 is not set |
765 | # CONFIG_SND_MIXART is not set | 794 | # CONFIG_SND_MIXART is not set |
766 | # CONFIG_SND_NM256 is not set | 795 | # CONFIG_SND_NM256 is not set |
@@ -785,13 +814,14 @@ CONFIG_SND_FM801=m | |||
785 | # CONFIG_SND_INTEL8X0M is not set | 814 | # CONFIG_SND_INTEL8X0M is not set |
786 | # CONFIG_SND_SONICVIBES is not set | 815 | # CONFIG_SND_SONICVIBES is not set |
787 | # CONFIG_SND_VIA82XX is not set | 816 | # CONFIG_SND_VIA82XX is not set |
817 | # CONFIG_SND_VIA82XX_MODEM is not set | ||
788 | # CONFIG_SND_VX222 is not set | 818 | # CONFIG_SND_VX222 is not set |
819 | # CONFIG_SND_HDA_INTEL is not set | ||
789 | 820 | ||
790 | # | 821 | # |
791 | # USB devices | 822 | # USB devices |
792 | # | 823 | # |
793 | # CONFIG_SND_USB_AUDIO is not set | 824 | # CONFIG_SND_USB_AUDIO is not set |
794 | # CONFIG_SND_USB_USX2Y is not set | ||
795 | 825 | ||
796 | # | 826 | # |
797 | # Open Sound System | 827 | # Open Sound System |
@@ -801,6 +831,8 @@ CONFIG_SND_FM801=m | |||
801 | # | 831 | # |
802 | # USB support | 832 | # USB support |
803 | # | 833 | # |
834 | CONFIG_USB_ARCH_HAS_HCD=y | ||
835 | CONFIG_USB_ARCH_HAS_OHCI=y | ||
804 | CONFIG_USB=m | 836 | CONFIG_USB=m |
805 | # CONFIG_USB_DEBUG is not set | 837 | # CONFIG_USB_DEBUG is not set |
806 | 838 | ||
@@ -812,8 +844,6 @@ CONFIG_USB_DEVICEFS=y | |||
812 | # CONFIG_USB_DYNAMIC_MINORS is not set | 844 | # CONFIG_USB_DYNAMIC_MINORS is not set |
813 | # CONFIG_USB_SUSPEND is not set | 845 | # CONFIG_USB_SUSPEND is not set |
814 | # CONFIG_USB_OTG is not set | 846 | # CONFIG_USB_OTG is not set |
815 | CONFIG_USB_ARCH_HAS_HCD=y | ||
816 | CONFIG_USB_ARCH_HAS_OHCI=y | ||
817 | 847 | ||
818 | # | 848 | # |
819 | # USB Host Controller Drivers | 849 | # USB Host Controller Drivers |
@@ -822,6 +852,8 @@ CONFIG_USB_EHCI_HCD=m | |||
822 | # CONFIG_USB_EHCI_SPLIT_ISO is not set | 852 | # CONFIG_USB_EHCI_SPLIT_ISO is not set |
823 | # CONFIG_USB_EHCI_ROOT_HUB_TT is not set | 853 | # CONFIG_USB_EHCI_ROOT_HUB_TT is not set |
824 | CONFIG_USB_OHCI_HCD=m | 854 | CONFIG_USB_OHCI_HCD=m |
855 | # CONFIG_USB_OHCI_BIG_ENDIAN is not set | ||
856 | CONFIG_USB_OHCI_LITTLE_ENDIAN=y | ||
825 | CONFIG_USB_UHCI_HCD=m | 857 | CONFIG_USB_UHCI_HCD=m |
826 | # CONFIG_USB_SL811_HCD is not set | 858 | # CONFIG_USB_SL811_HCD is not set |
827 | 859 | ||
@@ -839,12 +871,11 @@ CONFIG_USB_UHCI_HCD=m | |||
839 | # | 871 | # |
840 | CONFIG_USB_STORAGE=m | 872 | CONFIG_USB_STORAGE=m |
841 | # CONFIG_USB_STORAGE_DEBUG is not set | 873 | # CONFIG_USB_STORAGE_DEBUG is not set |
842 | # CONFIG_USB_STORAGE_RW_DETECT is not set | ||
843 | # CONFIG_USB_STORAGE_DATAFAB is not set | 874 | # CONFIG_USB_STORAGE_DATAFAB is not set |
844 | # CONFIG_USB_STORAGE_FREECOM is not set | 875 | # CONFIG_USB_STORAGE_FREECOM is not set |
845 | # CONFIG_USB_STORAGE_ISD200 is not set | 876 | # CONFIG_USB_STORAGE_ISD200 is not set |
846 | # CONFIG_USB_STORAGE_DPCM is not set | 877 | # CONFIG_USB_STORAGE_DPCM is not set |
847 | # CONFIG_USB_STORAGE_HP8200e is not set | 878 | # CONFIG_USB_STORAGE_USBAT is not set |
848 | # CONFIG_USB_STORAGE_SDDR09 is not set | 879 | # CONFIG_USB_STORAGE_SDDR09 is not set |
849 | # CONFIG_USB_STORAGE_SDDR55 is not set | 880 | # CONFIG_USB_STORAGE_SDDR55 is not set |
850 | # CONFIG_USB_STORAGE_JUMPSHOT is not set | 881 | # CONFIG_USB_STORAGE_JUMPSHOT is not set |
@@ -894,6 +925,7 @@ CONFIG_USB_HIDINPUT=y | |||
894 | # CONFIG_USB_PEGASUS is not set | 925 | # CONFIG_USB_PEGASUS is not set |
895 | # CONFIG_USB_RTL8150 is not set | 926 | # CONFIG_USB_RTL8150 is not set |
896 | # CONFIG_USB_USBNET is not set | 927 | # CONFIG_USB_USBNET is not set |
928 | CONFIG_USB_MON=m | ||
897 | 929 | ||
898 | # | 930 | # |
899 | # USB port drivers | 931 | # USB port drivers |
@@ -909,7 +941,6 @@ CONFIG_USB_HIDINPUT=y | |||
909 | # | 941 | # |
910 | # CONFIG_USB_EMI62 is not set | 942 | # CONFIG_USB_EMI62 is not set |
911 | # CONFIG_USB_EMI26 is not set | 943 | # CONFIG_USB_EMI26 is not set |
912 | # CONFIG_USB_TIGL is not set | ||
913 | # CONFIG_USB_AUERSWALD is not set | 944 | # CONFIG_USB_AUERSWALD is not set |
914 | # CONFIG_USB_RIO500 is not set | 945 | # CONFIG_USB_RIO500 is not set |
915 | # CONFIG_USB_LEGOTOWER is not set | 946 | # CONFIG_USB_LEGOTOWER is not set |
@@ -918,6 +949,8 @@ CONFIG_USB_HIDINPUT=y | |||
918 | # CONFIG_USB_CYTHERM is not set | 949 | # CONFIG_USB_CYTHERM is not set |
919 | # CONFIG_USB_PHIDGETKIT is not set | 950 | # CONFIG_USB_PHIDGETKIT is not set |
920 | # CONFIG_USB_PHIDGETSERVO is not set | 951 | # CONFIG_USB_PHIDGETSERVO is not set |
952 | # CONFIG_USB_IDMOUSE is not set | ||
953 | # CONFIG_USB_SISUSBVGA is not set | ||
921 | # CONFIG_USB_TEST is not set | 954 | # CONFIG_USB_TEST is not set |
922 | 955 | ||
923 | # | 956 | # |
@@ -970,7 +1003,12 @@ CONFIG_REISERFS_FS_POSIX_ACL=y | |||
970 | CONFIG_REISERFS_FS_SECURITY=y | 1003 | CONFIG_REISERFS_FS_SECURITY=y |
971 | # CONFIG_JFS_FS is not set | 1004 | # CONFIG_JFS_FS is not set |
972 | CONFIG_FS_POSIX_ACL=y | 1005 | CONFIG_FS_POSIX_ACL=y |
1006 | |||
1007 | # | ||
1008 | # XFS support | ||
1009 | # | ||
973 | CONFIG_XFS_FS=y | 1010 | CONFIG_XFS_FS=y |
1011 | CONFIG_XFS_EXPORT=y | ||
974 | # CONFIG_XFS_RT is not set | 1012 | # CONFIG_XFS_RT is not set |
975 | # CONFIG_XFS_QUOTA is not set | 1013 | # CONFIG_XFS_QUOTA is not set |
976 | # CONFIG_XFS_SECURITY is not set | 1014 | # CONFIG_XFS_SECURITY is not set |
@@ -1048,7 +1086,7 @@ CONFIG_NFSD_V4=y | |||
1048 | CONFIG_NFSD_TCP=y | 1086 | CONFIG_NFSD_TCP=y |
1049 | CONFIG_LOCKD=m | 1087 | CONFIG_LOCKD=m |
1050 | CONFIG_LOCKD_V4=y | 1088 | CONFIG_LOCKD_V4=y |
1051 | CONFIG_EXPORTFS=m | 1089 | CONFIG_EXPORTFS=y |
1052 | CONFIG_SUNRPC=m | 1090 | CONFIG_SUNRPC=m |
1053 | CONFIG_SUNRPC_GSS=m | 1091 | CONFIG_SUNRPC_GSS=m |
1054 | CONFIG_RPCSEC_GSS_KRB5=m | 1092 | CONFIG_RPCSEC_GSS_KRB5=m |
@@ -1134,6 +1172,8 @@ CONFIG_NLS_UTF8=m | |||
1134 | # CONFIG_CRC_CCITT is not set | 1172 | # CONFIG_CRC_CCITT is not set |
1135 | CONFIG_CRC32=y | 1173 | CONFIG_CRC32=y |
1136 | # CONFIG_LIBCRC32C is not set | 1174 | # CONFIG_LIBCRC32C is not set |
1175 | CONFIG_GENERIC_HARDIRQS=y | ||
1176 | CONFIG_GENERIC_IRQ_PROBE=y | ||
1137 | 1177 | ||
1138 | # | 1178 | # |
1139 | # HP Simulator drivers | 1179 | # HP Simulator drivers |
@@ -1150,14 +1190,17 @@ CONFIG_CRC32=y | |||
1150 | # | 1190 | # |
1151 | # Kernel hacking | 1191 | # Kernel hacking |
1152 | # | 1192 | # |
1193 | # CONFIG_PRINTK_TIME is not set | ||
1153 | CONFIG_DEBUG_KERNEL=y | 1194 | CONFIG_DEBUG_KERNEL=y |
1154 | CONFIG_MAGIC_SYSRQ=y | 1195 | CONFIG_MAGIC_SYSRQ=y |
1196 | CONFIG_LOG_BUF_SHIFT=20 | ||
1155 | # CONFIG_SCHEDSTATS is not set | 1197 | # CONFIG_SCHEDSTATS is not set |
1156 | # CONFIG_DEBUG_SLAB is not set | 1198 | # CONFIG_DEBUG_SLAB is not set |
1157 | # CONFIG_DEBUG_SPINLOCK is not set | 1199 | # CONFIG_DEBUG_SPINLOCK is not set |
1158 | # CONFIG_DEBUG_SPINLOCK_SLEEP is not set | 1200 | # CONFIG_DEBUG_SPINLOCK_SLEEP is not set |
1159 | # CONFIG_DEBUG_KOBJECT is not set | 1201 | # CONFIG_DEBUG_KOBJECT is not set |
1160 | # CONFIG_DEBUG_INFO is not set | 1202 | # CONFIG_DEBUG_INFO is not set |
1203 | # CONFIG_DEBUG_FS is not set | ||
1161 | CONFIG_IA64_GRANULE_16MB=y | 1204 | CONFIG_IA64_GRANULE_16MB=y |
1162 | # CONFIG_IA64_GRANULE_64MB is not set | 1205 | # CONFIG_IA64_GRANULE_64MB is not set |
1163 | # CONFIG_IA64_PRINT_HAZARDS is not set | 1206 | # CONFIG_IA64_PRINT_HAZARDS is not set |
@@ -1184,6 +1227,7 @@ CONFIG_CRYPTO_MD5=m | |||
1184 | # CONFIG_CRYPTO_SHA256 is not set | 1227 | # CONFIG_CRYPTO_SHA256 is not set |
1185 | # CONFIG_CRYPTO_SHA512 is not set | 1228 | # CONFIG_CRYPTO_SHA512 is not set |
1186 | # CONFIG_CRYPTO_WP512 is not set | 1229 | # CONFIG_CRYPTO_WP512 is not set |
1230 | # CONFIG_CRYPTO_TGR192 is not set | ||
1187 | CONFIG_CRYPTO_DES=m | 1231 | CONFIG_CRYPTO_DES=m |
1188 | # CONFIG_CRYPTO_BLOWFISH is not set | 1232 | # CONFIG_CRYPTO_BLOWFISH is not set |
1189 | # CONFIG_CRYPTO_TWOFISH is not set | 1233 | # CONFIG_CRYPTO_TWOFISH is not set |
diff --git a/arch/ia64/kernel/entry.h b/arch/ia64/kernel/entry.h index 6d4ecec989b5..78eeb0793419 100644 --- a/arch/ia64/kernel/entry.h +++ b/arch/ia64/kernel/entry.h | |||
@@ -60,7 +60,7 @@ | |||
60 | .spillsp @priunat,SW(AR_UNAT)+16+(off); \ | 60 | .spillsp @priunat,SW(AR_UNAT)+16+(off); \ |
61 | .spillsp ar.rnat,SW(AR_RNAT)+16+(off); \ | 61 | .spillsp ar.rnat,SW(AR_RNAT)+16+(off); \ |
62 | .spillsp ar.bspstore,SW(AR_BSPSTORE)+16+(off); \ | 62 | .spillsp ar.bspstore,SW(AR_BSPSTORE)+16+(off); \ |
63 | .spillsp pr,SW(PR)+16+(off)) | 63 | .spillsp pr,SW(PR)+16+(off) |
64 | 64 | ||
65 | #define DO_SAVE_SWITCH_STACK \ | 65 | #define DO_SAVE_SWITCH_STACK \ |
66 | movl r28=1f; \ | 66 | movl r28=1f; \ |
diff --git a/arch/ia64/kernel/ivt.S b/arch/ia64/kernel/ivt.S index d9c05d53435b..2bc085a73e30 100644 --- a/arch/ia64/kernel/ivt.S +++ b/arch/ia64/kernel/ivt.S | |||
@@ -405,17 +405,22 @@ ENTRY(nested_dtlb_miss) | |||
405 | * r30: continuation address | 405 | * r30: continuation address |
406 | * r31: saved pr | 406 | * r31: saved pr |
407 | * | 407 | * |
408 | * Clobbered: b0, r18, r19, r21, psr.dt (cleared) | 408 | * Clobbered: b0, r18, r19, r21, r22, psr.dt (cleared) |
409 | */ | 409 | */ |
410 | rsm psr.dt // switch to using physical data addressing | 410 | rsm psr.dt // switch to using physical data addressing |
411 | mov r19=IA64_KR(PT_BASE) // get the page table base address | 411 | mov r19=IA64_KR(PT_BASE) // get the page table base address |
412 | shl r21=r16,3 // shift bit 60 into sign bit | 412 | shl r21=r16,3 // shift bit 60 into sign bit |
413 | mov r18=cr.itir | ||
413 | ;; | 414 | ;; |
414 | shr.u r17=r16,61 // get the region number into r17 | 415 | shr.u r17=r16,61 // get the region number into r17 |
416 | extr.u r18=r18,2,6 // get the faulting page size | ||
415 | ;; | 417 | ;; |
416 | cmp.eq p6,p7=5,r17 // is faulting address in region 5? | 418 | cmp.eq p6,p7=5,r17 // is faulting address in region 5? |
417 | shr.u r18=r16,PGDIR_SHIFT // get bits 33-63 of faulting address | 419 | add r22=-PAGE_SHIFT,r18 // adjustment for hugetlb address |
420 | add r18=PGDIR_SHIFT-PAGE_SHIFT,r18 | ||
418 | ;; | 421 | ;; |
422 | shr.u r22=r16,r22 | ||
423 | shr.u r18=r16,r18 | ||
419 | (p7) dep r17=r17,r19,(PAGE_SHIFT-3),3 // put region number bits in place | 424 | (p7) dep r17=r17,r19,(PAGE_SHIFT-3),3 // put region number bits in place |
420 | 425 | ||
421 | srlz.d | 426 | srlz.d |
@@ -428,7 +433,7 @@ ENTRY(nested_dtlb_miss) | |||
428 | (p6) dep r17=r18,r19,3,(PAGE_SHIFT-3) // r17=PTA + IFA(33,42)*8 | 433 | (p6) dep r17=r18,r19,3,(PAGE_SHIFT-3) // r17=PTA + IFA(33,42)*8 |
429 | (p7) dep r17=r18,r17,3,(PAGE_SHIFT-6) // r17=PTA + (((IFA(61,63) << 7) | IFA(33,39))*8) | 434 | (p7) dep r17=r18,r17,3,(PAGE_SHIFT-6) // r17=PTA + (((IFA(61,63) << 7) | IFA(33,39))*8) |
430 | cmp.eq p7,p6=0,r21 // unused address bits all zeroes? | 435 | cmp.eq p7,p6=0,r21 // unused address bits all zeroes? |
431 | shr.u r18=r16,PMD_SHIFT // shift L2 index into position | 436 | shr.u r18=r22,PMD_SHIFT // shift L2 index into position |
432 | ;; | 437 | ;; |
433 | ld8 r17=[r17] // fetch the L1 entry (may be 0) | 438 | ld8 r17=[r17] // fetch the L1 entry (may be 0) |
434 | ;; | 439 | ;; |
@@ -436,7 +441,7 @@ ENTRY(nested_dtlb_miss) | |||
436 | dep r17=r18,r17,3,(PAGE_SHIFT-3) // compute address of L2 page table entry | 441 | dep r17=r18,r17,3,(PAGE_SHIFT-3) // compute address of L2 page table entry |
437 | ;; | 442 | ;; |
438 | (p7) ld8 r17=[r17] // fetch the L2 entry (may be 0) | 443 | (p7) ld8 r17=[r17] // fetch the L2 entry (may be 0) |
439 | shr.u r19=r16,PAGE_SHIFT // shift L3 index into position | 444 | shr.u r19=r22,PAGE_SHIFT // shift L3 index into position |
440 | ;; | 445 | ;; |
441 | (p7) cmp.eq.or.andcm p6,p7=r17,r0 // was L2 entry NULL? | 446 | (p7) cmp.eq.or.andcm p6,p7=r17,r0 // was L2 entry NULL? |
442 | dep r17=r19,r17,3,(PAGE_SHIFT-3) // compute address of L3 page table entry | 447 | dep r17=r19,r17,3,(PAGE_SHIFT-3) // compute address of L3 page table entry |
diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c index 575a8f657b31..6d57aebad485 100644 --- a/arch/ia64/kernel/ptrace.c +++ b/arch/ia64/kernel/ptrace.c | |||
@@ -945,6 +945,13 @@ access_uarea (struct task_struct *child, unsigned long addr, | |||
945 | *data = (pt->cr_ipsr & IPSR_MASK); | 945 | *data = (pt->cr_ipsr & IPSR_MASK); |
946 | return 0; | 946 | return 0; |
947 | 947 | ||
948 | case PT_AR_RSC: | ||
949 | if (write_access) | ||
950 | pt->ar_rsc = *data | (3 << 2); /* force PL3 */ | ||
951 | else | ||
952 | *data = pt->ar_rsc; | ||
953 | return 0; | ||
954 | |||
948 | case PT_AR_RNAT: | 955 | case PT_AR_RNAT: |
949 | urbs_end = ia64_get_user_rbs_end(child, pt, NULL); | 956 | urbs_end = ia64_get_user_rbs_end(child, pt, NULL); |
950 | rnat_addr = (long) ia64_rse_rnat_addr((long *) | 957 | rnat_addr = (long) ia64_rse_rnat_addr((long *) |
@@ -996,9 +1003,6 @@ access_uarea (struct task_struct *child, unsigned long addr, | |||
996 | case PT_AR_BSPSTORE: | 1003 | case PT_AR_BSPSTORE: |
997 | ptr = pt_reg_addr(pt, ar_bspstore); | 1004 | ptr = pt_reg_addr(pt, ar_bspstore); |
998 | break; | 1005 | break; |
999 | case PT_AR_RSC: | ||
1000 | ptr = pt_reg_addr(pt, ar_rsc); | ||
1001 | break; | ||
1002 | case PT_AR_UNAT: | 1006 | case PT_AR_UNAT: |
1003 | ptr = pt_reg_addr(pt, ar_unat); | 1007 | ptr = pt_reg_addr(pt, ar_unat); |
1004 | break; | 1008 | break; |
@@ -1234,7 +1238,7 @@ ptrace_getregs (struct task_struct *child, struct pt_all_user_regs __user *ppr) | |||
1234 | static long | 1238 | static long |
1235 | ptrace_setregs (struct task_struct *child, struct pt_all_user_regs __user *ppr) | 1239 | ptrace_setregs (struct task_struct *child, struct pt_all_user_regs __user *ppr) |
1236 | { | 1240 | { |
1237 | unsigned long psr, ec, lc, rnat, bsp, cfm, nat_bits, val = 0; | 1241 | unsigned long psr, rsc, ec, lc, rnat, bsp, cfm, nat_bits, val = 0; |
1238 | struct unw_frame_info info; | 1242 | struct unw_frame_info info; |
1239 | struct switch_stack *sw; | 1243 | struct switch_stack *sw; |
1240 | struct ia64_fpreg fpval; | 1244 | struct ia64_fpreg fpval; |
@@ -1267,7 +1271,7 @@ ptrace_setregs (struct task_struct *child, struct pt_all_user_regs __user *ppr) | |||
1267 | /* app regs */ | 1271 | /* app regs */ |
1268 | 1272 | ||
1269 | retval |= __get_user(pt->ar_pfs, &ppr->ar[PT_AUR_PFS]); | 1273 | retval |= __get_user(pt->ar_pfs, &ppr->ar[PT_AUR_PFS]); |
1270 | retval |= __get_user(pt->ar_rsc, &ppr->ar[PT_AUR_RSC]); | 1274 | retval |= __get_user(rsc, &ppr->ar[PT_AUR_RSC]); |
1271 | retval |= __get_user(pt->ar_bspstore, &ppr->ar[PT_AUR_BSPSTORE]); | 1275 | retval |= __get_user(pt->ar_bspstore, &ppr->ar[PT_AUR_BSPSTORE]); |
1272 | retval |= __get_user(pt->ar_unat, &ppr->ar[PT_AUR_UNAT]); | 1276 | retval |= __get_user(pt->ar_unat, &ppr->ar[PT_AUR_UNAT]); |
1273 | retval |= __get_user(pt->ar_ccv, &ppr->ar[PT_AUR_CCV]); | 1277 | retval |= __get_user(pt->ar_ccv, &ppr->ar[PT_AUR_CCV]); |
@@ -1365,6 +1369,7 @@ ptrace_setregs (struct task_struct *child, struct pt_all_user_regs __user *ppr) | |||
1365 | retval |= __get_user(nat_bits, &ppr->nat); | 1369 | retval |= __get_user(nat_bits, &ppr->nat); |
1366 | 1370 | ||
1367 | retval |= access_uarea(child, PT_CR_IPSR, &psr, 1); | 1371 | retval |= access_uarea(child, PT_CR_IPSR, &psr, 1); |
1372 | retval |= access_uarea(child, PT_AR_RSC, &rsc, 1); | ||
1368 | retval |= access_uarea(child, PT_AR_EC, &ec, 1); | 1373 | retval |= access_uarea(child, PT_AR_EC, &ec, 1); |
1369 | retval |= access_uarea(child, PT_AR_LC, &lc, 1); | 1374 | retval |= access_uarea(child, PT_AR_LC, &lc, 1); |
1370 | retval |= access_uarea(child, PT_AR_RNAT, &rnat, 1); | 1375 | retval |= access_uarea(child, PT_AR_RNAT, &rnat, 1); |
diff --git a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c index 499b7e5317cf..edd9f07860b2 100644 --- a/arch/ia64/kernel/signal.c +++ b/arch/ia64/kernel/signal.c | |||
@@ -94,7 +94,7 @@ sys_sigaltstack (const stack_t __user *uss, stack_t __user *uoss, long arg2, | |||
94 | static long | 94 | static long |
95 | restore_sigcontext (struct sigcontext __user *sc, struct sigscratch *scr) | 95 | restore_sigcontext (struct sigcontext __user *sc, struct sigscratch *scr) |
96 | { | 96 | { |
97 | unsigned long ip, flags, nat, um, cfm; | 97 | unsigned long ip, flags, nat, um, cfm, rsc; |
98 | long err; | 98 | long err; |
99 | 99 | ||
100 | /* Always make any pending restarted system calls return -EINTR */ | 100 | /* Always make any pending restarted system calls return -EINTR */ |
@@ -106,7 +106,7 @@ restore_sigcontext (struct sigcontext __user *sc, struct sigscratch *scr) | |||
106 | err |= __get_user(ip, &sc->sc_ip); /* instruction pointer */ | 106 | err |= __get_user(ip, &sc->sc_ip); /* instruction pointer */ |
107 | err |= __get_user(cfm, &sc->sc_cfm); | 107 | err |= __get_user(cfm, &sc->sc_cfm); |
108 | err |= __get_user(um, &sc->sc_um); /* user mask */ | 108 | err |= __get_user(um, &sc->sc_um); /* user mask */ |
109 | err |= __get_user(scr->pt.ar_rsc, &sc->sc_ar_rsc); | 109 | err |= __get_user(rsc, &sc->sc_ar_rsc); |
110 | err |= __get_user(scr->pt.ar_unat, &sc->sc_ar_unat); | 110 | err |= __get_user(scr->pt.ar_unat, &sc->sc_ar_unat); |
111 | err |= __get_user(scr->pt.ar_fpsr, &sc->sc_ar_fpsr); | 111 | err |= __get_user(scr->pt.ar_fpsr, &sc->sc_ar_fpsr); |
112 | err |= __get_user(scr->pt.ar_pfs, &sc->sc_ar_pfs); | 112 | err |= __get_user(scr->pt.ar_pfs, &sc->sc_ar_pfs); |
@@ -119,6 +119,7 @@ restore_sigcontext (struct sigcontext __user *sc, struct sigscratch *scr) | |||
119 | err |= __copy_from_user(&scr->pt.r15, &sc->sc_gr[15], 8); /* r15 */ | 119 | err |= __copy_from_user(&scr->pt.r15, &sc->sc_gr[15], 8); /* r15 */ |
120 | 120 | ||
121 | scr->pt.cr_ifs = cfm | (1UL << 63); | 121 | scr->pt.cr_ifs = cfm | (1UL << 63); |
122 | scr->pt.ar_rsc = rsc | (3 << 2); /* force PL3 */ | ||
122 | 123 | ||
123 | /* establish new instruction pointer: */ | 124 | /* establish new instruction pointer: */ |
124 | scr->pt.cr_iip = ip & ~0x3UL; | 125 | scr->pt.cr_iip = ip & ~0x3UL; |
diff --git a/arch/ia64/kernel/smp.c b/arch/ia64/kernel/smp.c index 953095e2ce15..b49d4ddaab93 100644 --- a/arch/ia64/kernel/smp.c +++ b/arch/ia64/kernel/smp.c | |||
@@ -269,7 +269,7 @@ smp_call_function_single (int cpuid, void (*func) (void *info), void *info, int | |||
269 | int me = get_cpu(); /* prevent preemption and reschedule on another processor */ | 269 | int me = get_cpu(); /* prevent preemption and reschedule on another processor */ |
270 | 270 | ||
271 | if (cpuid == me) { | 271 | if (cpuid == me) { |
272 | printk("%s: trying to call self\n", __FUNCTION__); | 272 | printk(KERN_INFO "%s: trying to call self\n", __FUNCTION__); |
273 | put_cpu(); | 273 | put_cpu(); |
274 | return -EBUSY; | 274 | return -EBUSY; |
275 | } | 275 | } |
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c index 88641e5095b5..e3fc4edea113 100644 --- a/arch/ia64/pci/pci.c +++ b/arch/ia64/pci/pci.c | |||
@@ -33,8 +33,6 @@ | |||
33 | #include <asm/hw_irq.h> | 33 | #include <asm/hw_irq.h> |
34 | 34 | ||
35 | 35 | ||
36 | static int pci_routeirq; | ||
37 | |||
38 | /* | 36 | /* |
39 | * Low-level SAL-based PCI configuration access functions. Note that SAL | 37 | * Low-level SAL-based PCI configuration access functions. Note that SAL |
40 | * calls are already serialized (via sal_lock), so we don't need another | 38 | * calls are already serialized (via sal_lock), so we don't need another |
@@ -139,24 +137,8 @@ static void acpi_map_iosapics(void) | |||
139 | static int __init | 137 | static int __init |
140 | pci_acpi_init (void) | 138 | pci_acpi_init (void) |
141 | { | 139 | { |
142 | struct pci_dev *dev = NULL; | ||
143 | |||
144 | printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n"); | ||
145 | |||
146 | acpi_map_iosapics(); | 140 | acpi_map_iosapics(); |
147 | 141 | ||
148 | if (pci_routeirq) { | ||
149 | /* | ||
150 | * PCI IRQ routing is set up by pci_enable_device(), but we | ||
151 | * also do it here in case there are still broken drivers that | ||
152 | * don't use pci_enable_device(). | ||
153 | */ | ||
154 | printk(KERN_INFO "PCI: Routing interrupts for all devices because \"pci=routeirq\" specified\n"); | ||
155 | for_each_pci_dev(dev) | ||
156 | acpi_pci_irq_enable(dev); | ||
157 | } else | ||
158 | printk(KERN_INFO "PCI: If a device doesn't work, try \"pci=routeirq\". If it helps, post a report\n"); | ||
159 | |||
160 | return 0; | 142 | return 0; |
161 | } | 143 | } |
162 | 144 | ||
@@ -500,8 +482,6 @@ pcibios_align_resource (void *data, struct resource *res, | |||
500 | char * __init | 482 | char * __init |
501 | pcibios_setup (char *str) | 483 | pcibios_setup (char *str) |
502 | { | 484 | { |
503 | if (!strcmp(str, "routeirq")) | ||
504 | pci_routeirq = 1; | ||
505 | return NULL; | 485 | return NULL; |
506 | } | 486 | } |
507 | 487 | ||
diff --git a/arch/ppc/platforms/83xx/mpc834x_sys.c b/arch/ppc/platforms/83xx/mpc834x_sys.c index 86ca5cf81263..37ece1542799 100644 --- a/arch/ppc/platforms/83xx/mpc834x_sys.c +++ b/arch/ppc/platforms/83xx/mpc834x_sys.c | |||
@@ -185,6 +185,26 @@ mpc834x_sys_init_IRQ(void) | |||
185 | ipic_set_default_priority(); | 185 | ipic_set_default_priority(); |
186 | } | 186 | } |
187 | 187 | ||
188 | #if defined(CONFIG_I2C_MPC) && defined(CONFIG_SENSORS_DS1374) | ||
189 | extern ulong ds1374_get_rtc_time(void); | ||
190 | extern int ds1374_set_rtc_time(ulong); | ||
191 | |||
192 | static int __init | ||
193 | mpc834x_rtc_hookup(void) | ||
194 | { | ||
195 | struct timespec tv; | ||
196 | |||
197 | ppc_md.get_rtc_time = ds1374_get_rtc_time; | ||
198 | ppc_md.set_rtc_time = ds1374_set_rtc_time; | ||
199 | |||
200 | tv.tv_nsec = 0; | ||
201 | tv.tv_sec = (ppc_md.get_rtc_time)(); | ||
202 | do_settimeofday(&tv); | ||
203 | |||
204 | return 0; | ||
205 | } | ||
206 | late_initcall(mpc834x_rtc_hookup); | ||
207 | #endif | ||
188 | static __inline__ void | 208 | static __inline__ void |
189 | mpc834x_sys_set_bat(void) | 209 | mpc834x_sys_set_bat(void) |
190 | { | 210 | { |
diff --git a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c index 203b2ca61df8..b52c4317fefd 100644 --- a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c +++ b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c | |||
@@ -149,6 +149,7 @@ void __init | |||
149 | mpc85xx_cds_init_IRQ(void) | 149 | mpc85xx_cds_init_IRQ(void) |
150 | { | 150 | { |
151 | bd_t *binfo = (bd_t *) __res; | 151 | bd_t *binfo = (bd_t *) __res; |
152 | int i; | ||
152 | 153 | ||
153 | /* Determine the Physical Address of the OpenPIC regs */ | 154 | /* Determine the Physical Address of the OpenPIC regs */ |
154 | phys_addr_t OpenPIC_PAddr = binfo->bi_immr_base + MPC85xx_OPENPIC_OFFSET; | 155 | phys_addr_t OpenPIC_PAddr = binfo->bi_immr_base + MPC85xx_OPENPIC_OFFSET; |
diff --git a/drivers/acorn/char/pcf8583.c b/drivers/acorn/char/pcf8583.c index ad7ae7ab8920..141b4c237a50 100644 --- a/drivers/acorn/char/pcf8583.c +++ b/drivers/acorn/char/pcf8583.c | |||
@@ -26,11 +26,8 @@ static unsigned short normal_addr[] = { 0x50, I2C_CLIENT_END }; | |||
26 | 26 | ||
27 | static struct i2c_client_address_data addr_data = { | 27 | static struct i2c_client_address_data addr_data = { |
28 | .normal_i2c = normal_addr, | 28 | .normal_i2c = normal_addr, |
29 | .normal_i2c_range = ignore, | ||
30 | .probe = ignore, | 29 | .probe = ignore, |
31 | .probe_range = ignore, | ||
32 | .ignore = ignore, | 30 | .ignore = ignore, |
33 | .ignore_range = ignore, | ||
34 | .force = ignore, | 31 | .force = ignore, |
35 | }; | 32 | }; |
36 | 33 | ||
diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c index c3d912cbbbc3..cc3a952401f2 100644 --- a/drivers/i2c/algos/i2c-algo-pca.c +++ b/drivers/i2c/algos/i2c-algo-pca.c | |||
@@ -49,7 +49,7 @@ static int i2c_debug=0; | |||
49 | /* | 49 | /* |
50 | * Generate a start condition on the i2c bus. | 50 | * Generate a start condition on the i2c bus. |
51 | * | 51 | * |
52 | * returns after the start condition has occured | 52 | * returns after the start condition has occurred |
53 | */ | 53 | */ |
54 | static void pca_start(struct i2c_algo_pca_data *adap) | 54 | static void pca_start(struct i2c_algo_pca_data *adap) |
55 | { | 55 | { |
@@ -62,9 +62,9 @@ static void pca_start(struct i2c_algo_pca_data *adap) | |||
62 | } | 62 | } |
63 | 63 | ||
64 | /* | 64 | /* |
65 | * Generate a repeated start condition on the i2c bus | 65 | * Generate a repeated start condition on the i2c bus |
66 | * | 66 | * |
67 | * return after the repeated start condition has occured | 67 | * return after the repeated start condition has occurred |
68 | */ | 68 | */ |
69 | static void pca_repeated_start(struct i2c_algo_pca_data *adap) | 69 | static void pca_repeated_start(struct i2c_algo_pca_data *adap) |
70 | { | 70 | { |
@@ -82,7 +82,7 @@ static void pca_repeated_start(struct i2c_algo_pca_data *adap) | |||
82 | * returns after the stop condition has been generated | 82 | * returns after the stop condition has been generated |
83 | * | 83 | * |
84 | * STOPs do not generate an interrupt or set the SI flag, since the | 84 | * STOPs do not generate an interrupt or set the SI flag, since the |
85 | * part returns the the idle state (0xf8). Hence we don't need to | 85 | * part returns the idle state (0xf8). Hence we don't need to |
86 | * pca_wait here. | 86 | * pca_wait here. |
87 | */ | 87 | */ |
88 | static void pca_stop(struct i2c_algo_pca_data *adap) | 88 | static void pca_stop(struct i2c_algo_pca_data *adap) |
diff --git a/drivers/i2c/algos/i2c-algo-sibyte.c b/drivers/i2c/algos/i2c-algo-sibyte.c index 35789bb7126a..f2785499237b 100644 --- a/drivers/i2c/algos/i2c-algo-sibyte.c +++ b/drivers/i2c/algos/i2c-algo-sibyte.c | |||
@@ -24,7 +24,6 @@ | |||
24 | 24 | ||
25 | /* Ported for SiByte SOCs by Broadcom Corporation. */ | 25 | /* Ported for SiByte SOCs by Broadcom Corporation. */ |
26 | 26 | ||
27 | #include <linux/config.h> | ||
28 | #include <linux/kernel.h> | 27 | #include <linux/kernel.h> |
29 | #include <linux/module.h> | 28 | #include <linux/module.h> |
30 | #include <linux/init.h> | 29 | #include <linux/init.h> |
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index a0018de3bef4..916ba5e40a96 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig | |||
@@ -7,7 +7,7 @@ menu "I2C Hardware Bus support" | |||
7 | 7 | ||
8 | config I2C_ALI1535 | 8 | config I2C_ALI1535 |
9 | tristate "ALI 1535" | 9 | tristate "ALI 1535" |
10 | depends on I2C && PCI && EXPERIMENTAL | 10 | depends on I2C && PCI |
11 | help | 11 | help |
12 | If you say yes to this option, support will be included for the SMB | 12 | If you say yes to this option, support will be included for the SMB |
13 | Host controller on Acer Labs Inc. (ALI) M1535 South Bridges. The SMB | 13 | Host controller on Acer Labs Inc. (ALI) M1535 South Bridges. The SMB |
@@ -31,7 +31,7 @@ config I2C_ALI1563 | |||
31 | 31 | ||
32 | config I2C_ALI15X3 | 32 | config I2C_ALI15X3 |
33 | tristate "ALI 15x3" | 33 | tristate "ALI 15x3" |
34 | depends on I2C && PCI && EXPERIMENTAL | 34 | depends on I2C && PCI |
35 | help | 35 | help |
36 | If you say yes to this option, support will be included for the | 36 | If you say yes to this option, support will be included for the |
37 | Acer Labs Inc. (ALI) M1514 and M1543 motherboard I2C interfaces. | 37 | Acer Labs Inc. (ALI) M1514 and M1543 motherboard I2C interfaces. |
@@ -41,7 +41,7 @@ config I2C_ALI15X3 | |||
41 | 41 | ||
42 | config I2C_AMD756 | 42 | config I2C_AMD756 |
43 | tristate "AMD 756/766/768/8111 and nVidia nForce" | 43 | tristate "AMD 756/766/768/8111 and nVidia nForce" |
44 | depends on I2C && PCI && EXPERIMENTAL | 44 | depends on I2C && PCI |
45 | help | 45 | help |
46 | If you say yes to this option, support will be included for the AMD | 46 | If you say yes to this option, support will be included for the AMD |
47 | 756/766/768 mainboard I2C interfaces. The driver also includes | 47 | 756/766/768 mainboard I2C interfaces. The driver also includes |
@@ -66,7 +66,7 @@ config I2C_AMD756_S4882 | |||
66 | 66 | ||
67 | config I2C_AMD8111 | 67 | config I2C_AMD8111 |
68 | tristate "AMD 8111" | 68 | tristate "AMD 8111" |
69 | depends on I2C && PCI && EXPERIMENTAL | 69 | depends on I2C && PCI |
70 | help | 70 | help |
71 | If you say yes to this option, support will be included for the | 71 | If you say yes to this option, support will be included for the |
72 | second (SMBus 2.0) AMD 8111 mainboard I2C interface. | 72 | second (SMBus 2.0) AMD 8111 mainboard I2C interface. |
@@ -109,7 +109,7 @@ config I2C_HYDRA | |||
109 | 109 | ||
110 | config I2C_I801 | 110 | config I2C_I801 |
111 | tristate "Intel 82801 (ICH)" | 111 | tristate "Intel 82801 (ICH)" |
112 | depends on I2C && PCI && EXPERIMENTAL | 112 | depends on I2C && PCI |
113 | help | 113 | help |
114 | If you say yes to this option, support will be included for the Intel | 114 | If you say yes to this option, support will be included for the Intel |
115 | 801 family of mainboard I2C interfaces. Specifically, the following | 115 | 801 family of mainboard I2C interfaces. Specifically, the following |
@@ -130,7 +130,7 @@ config I2C_I801 | |||
130 | 130 | ||
131 | config I2C_I810 | 131 | config I2C_I810 |
132 | tristate "Intel 810/815" | 132 | tristate "Intel 810/815" |
133 | depends on I2C && PCI && EXPERIMENTAL | 133 | depends on I2C && PCI |
134 | select I2C_ALGOBIT | 134 | select I2C_ALGOBIT |
135 | help | 135 | help |
136 | If you say yes to this option, support will be included for the Intel | 136 | If you say yes to this option, support will be included for the Intel |
@@ -183,7 +183,7 @@ config I2C_IOP3XX | |||
183 | 183 | ||
184 | config I2C_ISA | 184 | config I2C_ISA |
185 | tristate "ISA Bus support" | 185 | tristate "ISA Bus support" |
186 | depends on I2C && EXPERIMENTAL | 186 | depends on I2C |
187 | help | 187 | help |
188 | If you say yes to this option, support will be included for i2c | 188 | If you say yes to this option, support will be included for i2c |
189 | interfaces that are on the ISA bus. | 189 | interfaces that are on the ISA bus. |
@@ -248,12 +248,11 @@ config I2C_MPC | |||
248 | will be called i2c-mpc. | 248 | will be called i2c-mpc. |
249 | 249 | ||
250 | config I2C_NFORCE2 | 250 | config I2C_NFORCE2 |
251 | tristate "Nvidia Nforce2" | 251 | tristate "Nvidia nForce2, nForce3 and nForce4" |
252 | depends on I2C && PCI && EXPERIMENTAL | 252 | depends on I2C && PCI |
253 | help | 253 | help |
254 | If you say yes to this option, support will be included for the Nvidia | 254 | If you say yes to this option, support will be included for the Nvidia |
255 | Nforce2 family of mainboard I2C interfaces. | 255 | nForce2, nForce3 and nForce4 families of mainboard I2C interfaces. |
256 | This driver also supports the nForce3 Pro 150 MCP. | ||
257 | 256 | ||
258 | This driver can also be built as a module. If so, the module | 257 | This driver can also be built as a module. If so, the module |
259 | will be called i2c-nforce2. | 258 | will be called i2c-nforce2. |
@@ -305,7 +304,7 @@ config I2C_PARPORT_LIGHT | |||
305 | 304 | ||
306 | config I2C_PROSAVAGE | 305 | config I2C_PROSAVAGE |
307 | tristate "S3/VIA (Pro)Savage" | 306 | tristate "S3/VIA (Pro)Savage" |
308 | depends on I2C && PCI && EXPERIMENTAL | 307 | depends on I2C && PCI |
309 | select I2C_ALGOBIT | 308 | select I2C_ALGOBIT |
310 | help | 309 | help |
311 | If you say yes to this option, support will be included for the | 310 | If you say yes to this option, support will be included for the |
@@ -388,7 +387,7 @@ config SCx200_ACB | |||
388 | 387 | ||
389 | config I2C_SIS5595 | 388 | config I2C_SIS5595 |
390 | tristate "SiS 5595" | 389 | tristate "SiS 5595" |
391 | depends on I2C && PCI && EXPERIMENTAL | 390 | depends on I2C && PCI |
392 | help | 391 | help |
393 | If you say yes to this option, support will be included for the | 392 | If you say yes to this option, support will be included for the |
394 | SiS5595 SMBus (a subset of I2C) interface. | 393 | SiS5595 SMBus (a subset of I2C) interface. |
@@ -398,7 +397,7 @@ config I2C_SIS5595 | |||
398 | 397 | ||
399 | config I2C_SIS630 | 398 | config I2C_SIS630 |
400 | tristate "SiS 630/730" | 399 | tristate "SiS 630/730" |
401 | depends on I2C && PCI && EXPERIMENTAL | 400 | depends on I2C && PCI |
402 | help | 401 | help |
403 | If you say yes to this option, support will be included for the | 402 | If you say yes to this option, support will be included for the |
404 | SiS630 and SiS730 SMBus (a subset of I2C) interface. | 403 | SiS630 and SiS730 SMBus (a subset of I2C) interface. |
@@ -408,7 +407,7 @@ config I2C_SIS630 | |||
408 | 407 | ||
409 | config I2C_SIS96X | 408 | config I2C_SIS96X |
410 | tristate "SiS 96x" | 409 | tristate "SiS 96x" |
411 | depends on I2C && PCI && EXPERIMENTAL | 410 | depends on I2C && PCI |
412 | help | 411 | help |
413 | If you say yes to this option, support will be included for the SiS | 412 | If you say yes to this option, support will be included for the SiS |
414 | 96x SMBus (a subset of I2C) interfaces. Specifically, the following | 413 | 96x SMBus (a subset of I2C) interfaces. Specifically, the following |
@@ -419,6 +418,7 @@ config I2C_SIS96X | |||
419 | 648/961 | 418 | 648/961 |
420 | 650/961 | 419 | 650/961 |
421 | 735 | 420 | 735 |
421 | 745 | ||
422 | 422 | ||
423 | This driver can also be built as a module. If so, the module | 423 | This driver can also be built as a module. If so, the module |
424 | will be called i2c-sis96x. | 424 | will be called i2c-sis96x. |
@@ -449,7 +449,7 @@ config I2C_VIA | |||
449 | 449 | ||
450 | config I2C_VIAPRO | 450 | config I2C_VIAPRO |
451 | tristate "VIA 82C596/82C686/823x" | 451 | tristate "VIA 82C596/82C686/823x" |
452 | depends on I2C && PCI && EXPERIMENTAL | 452 | depends on I2C && PCI |
453 | help | 453 | help |
454 | If you say yes to this option, support will be included for the VIA | 454 | If you say yes to this option, support will be included for the VIA |
455 | 82C596/82C686/823x I2C interfaces. Specifically, the following | 455 | 82C596/82C686/823x I2C interfaces. Specifically, the following |
@@ -467,7 +467,7 @@ config I2C_VIAPRO | |||
467 | 467 | ||
468 | config I2C_VOODOO3 | 468 | config I2C_VOODOO3 |
469 | tristate "Voodoo 3" | 469 | tristate "Voodoo 3" |
470 | depends on I2C && PCI && EXPERIMENTAL | 470 | depends on I2C && PCI |
471 | select I2C_ALGOBIT | 471 | select I2C_ALGOBIT |
472 | help | 472 | help |
473 | If you say yes to this option, support will be included for the | 473 | If you say yes to this option, support will be included for the |
diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c index b00cd4098221..f634a0780cf0 100644 --- a/drivers/i2c/busses/i2c-ali1535.c +++ b/drivers/i2c/busses/i2c-ali1535.c | |||
@@ -53,7 +53,6 @@ | |||
53 | 53 | ||
54 | /* Note: we assume there can only be one ALI1535, with one SMBus interface */ | 54 | /* Note: we assume there can only be one ALI1535, with one SMBus interface */ |
55 | 55 | ||
56 | #include <linux/config.h> | ||
57 | #include <linux/module.h> | 56 | #include <linux/module.h> |
58 | #include <linux/pci.h> | 57 | #include <linux/pci.h> |
59 | #include <linux/kernel.h> | 58 | #include <linux/kernel.h> |
diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c index 5bd6a4a77c1e..0f781a1a3323 100644 --- a/drivers/i2c/busses/i2c-ali15x3.c +++ b/drivers/i2c/busses/i2c-ali15x3.c | |||
@@ -60,7 +60,6 @@ | |||
60 | 60 | ||
61 | /* Note: we assume there can only be one ALI15X3, with one SMBus interface */ | 61 | /* Note: we assume there can only be one ALI15X3, with one SMBus interface */ |
62 | 62 | ||
63 | #include <linux/config.h> | ||
64 | #include <linux/module.h> | 63 | #include <linux/module.h> |
65 | #include <linux/pci.h> | 64 | #include <linux/pci.h> |
66 | #include <linux/kernel.h> | 65 | #include <linux/kernel.h> |
diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c index eca5ed3738b8..6347ebc6fb53 100644 --- a/drivers/i2c/busses/i2c-amd756.c +++ b/drivers/i2c/busses/i2c-amd756.c | |||
@@ -37,7 +37,6 @@ | |||
37 | Note: we assume there can only be one device, with one SMBus interface. | 37 | Note: we assume there can only be one device, with one SMBus interface. |
38 | */ | 38 | */ |
39 | 39 | ||
40 | #include <linux/config.h> | ||
41 | #include <linux/module.h> | 40 | #include <linux/module.h> |
42 | #include <linux/pci.h> | 41 | #include <linux/pci.h> |
43 | #include <linux/kernel.h> | 42 | #include <linux/kernel.h> |
diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c index af22b401a38b..d6644481d2a0 100644 --- a/drivers/i2c/busses/i2c-amd8111.c +++ b/drivers/i2c/busses/i2c-amd8111.c | |||
@@ -8,7 +8,6 @@ | |||
8 | * the Free Software Foundation version 2. | 8 | * the Free Software Foundation version 2. |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/config.h> | ||
12 | #include <linux/module.h> | 11 | #include <linux/module.h> |
13 | #include <linux/pci.h> | 12 | #include <linux/pci.h> |
14 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
diff --git a/drivers/i2c/busses/i2c-au1550.c b/drivers/i2c/busses/i2c-au1550.c index 75831a20b0bd..a7ff112e49bf 100644 --- a/drivers/i2c/busses/i2c-au1550.c +++ b/drivers/i2c/busses/i2c-au1550.c | |||
@@ -27,7 +27,6 @@ | |||
27 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | 27 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
28 | */ | 28 | */ |
29 | 29 | ||
30 | #include <linux/config.h> | ||
31 | #include <linux/delay.h> | 30 | #include <linux/delay.h> |
32 | #include <linux/kernel.h> | 31 | #include <linux/kernel.h> |
33 | #include <linux/module.h> | 32 | #include <linux/module.h> |
diff --git a/drivers/i2c/busses/i2c-elektor.c b/drivers/i2c/busses/i2c-elektor.c index 0a7720000a0c..6930b660e508 100644 --- a/drivers/i2c/busses/i2c-elektor.c +++ b/drivers/i2c/busses/i2c-elektor.c | |||
@@ -25,7 +25,6 @@ | |||
25 | /* Partialy rewriten by Oleg I. Vdovikin for mmapped support of | 25 | /* Partialy rewriten by Oleg I. Vdovikin for mmapped support of |
26 | for Alpha Processor Inc. UP-2000(+) boards */ | 26 | for Alpha Processor Inc. UP-2000(+) boards */ |
27 | 27 | ||
28 | #include <linux/config.h> | ||
29 | #include <linux/kernel.h> | 28 | #include <linux/kernel.h> |
30 | #include <linux/ioport.h> | 29 | #include <linux/ioport.h> |
31 | #include <linux/module.h> | 30 | #include <linux/module.h> |
diff --git a/drivers/i2c/busses/i2c-frodo.c b/drivers/i2c/busses/i2c-frodo.c index e093829a0bf7..b6f52f5a4138 100644 --- a/drivers/i2c/busses/i2c-frodo.c +++ b/drivers/i2c/busses/i2c-frodo.c | |||
@@ -12,7 +12,6 @@ | |||
12 | * version 2 as published by the Free Software Foundation. | 12 | * version 2 as published by the Free Software Foundation. |
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <linux/config.h> | ||
16 | #include <linux/module.h> | 15 | #include <linux/module.h> |
17 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
18 | #include <linux/init.h> | 17 | #include <linux/init.h> |
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 59c238c42e8c..45e6efb1dcd1 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c | |||
@@ -41,7 +41,6 @@ | |||
41 | 41 | ||
42 | /* Note: we assume there can only be one I801, with one SMBus interface */ | 42 | /* Note: we assume there can only be one I801, with one SMBus interface */ |
43 | 43 | ||
44 | #include <linux/config.h> | ||
45 | #include <linux/module.h> | 44 | #include <linux/module.h> |
46 | #include <linux/pci.h> | 45 | #include <linux/pci.h> |
47 | #include <linux/kernel.h> | 46 | #include <linux/kernel.h> |
diff --git a/drivers/i2c/busses/i2c-i810.c b/drivers/i2c/busses/i2c-i810.c index ef358bd9c3da..0ff7016e0629 100644 --- a/drivers/i2c/busses/i2c-i810.c +++ b/drivers/i2c/busses/i2c-i810.c | |||
@@ -34,7 +34,6 @@ | |||
34 | i815 1132 | 34 | i815 1132 |
35 | */ | 35 | */ |
36 | 36 | ||
37 | #include <linux/config.h> | ||
38 | #include <linux/kernel.h> | 37 | #include <linux/kernel.h> |
39 | #include <linux/module.h> | 38 | #include <linux/module.h> |
40 | #include <linux/init.h> | 39 | #include <linux/init.h> |
diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c index bb885215c08d..93ca36dc777e 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.c +++ b/drivers/i2c/busses/i2c-ibm_iic.c | |||
@@ -695,7 +695,7 @@ static int __devinit iic_probe(struct ocp_device *ocp){ | |||
695 | 695 | ||
696 | dev->irq = iic_force_poll ? -1 : ocp->def->irq; | 696 | dev->irq = iic_force_poll ? -1 : ocp->def->irq; |
697 | if (dev->irq >= 0){ | 697 | if (dev->irq >= 0){ |
698 | /* Disable interrupts until we finish intialization, | 698 | /* Disable interrupts until we finish initialization, |
699 | assumes level-sensitive IRQ setup... | 699 | assumes level-sensitive IRQ setup... |
700 | */ | 700 | */ |
701 | iic_interrupt_mode(dev, 0); | 701 | iic_interrupt_mode(dev, 0); |
diff --git a/drivers/i2c/busses/i2c-ibm_iic.h b/drivers/i2c/busses/i2c-ibm_iic.h index d819a955d890..2b3219d00e92 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.h +++ b/drivers/i2c/busses/i2c-ibm_iic.h | |||
@@ -22,7 +22,6 @@ | |||
22 | #ifndef __I2C_IBM_IIC_H_ | 22 | #ifndef __I2C_IBM_IIC_H_ |
23 | #define __I2C_IBM_IIC_H_ | 23 | #define __I2C_IBM_IIC_H_ |
24 | 24 | ||
25 | #include <linux/config.h> | ||
26 | #include <linux/i2c.h> | 25 | #include <linux/i2c.h> |
27 | 26 | ||
28 | struct iic_regs { | 27 | struct iic_regs { |
diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c index c961ba4cfb32..6b682e903f09 100644 --- a/drivers/i2c/busses/i2c-iop3xx.c +++ b/drivers/i2c/busses/i2c-iop3xx.c | |||
@@ -85,7 +85,7 @@ iop3xx_i2c_enable(struct i2c_algo_iop3xx_data *iop3xx_adap) | |||
85 | u32 cr = IOP3XX_ICR_GCD | IOP3XX_ICR_SCLEN | IOP3XX_ICR_UE; | 85 | u32 cr = IOP3XX_ICR_GCD | IOP3XX_ICR_SCLEN | IOP3XX_ICR_UE; |
86 | 86 | ||
87 | /* | 87 | /* |
88 | * Everytime unit enable is asserted, GPOD needs to be cleared | 88 | * Every time unit enable is asserted, GPOD needs to be cleared |
89 | * on IOP321 to avoid data corruption on the bus. | 89 | * on IOP321 to avoid data corruption on the bus. |
90 | */ | 90 | */ |
91 | #ifdef CONFIG_ARCH_IOP321 | 91 | #ifdef CONFIG_ARCH_IOP321 |
diff --git a/drivers/i2c/busses/i2c-isa.c b/drivers/i2c/busses/i2c-isa.c index 0f54a2a0afa5..00e7f7157b75 100644 --- a/drivers/i2c/busses/i2c-isa.c +++ b/drivers/i2c/busses/i2c-isa.c | |||
@@ -24,7 +24,6 @@ | |||
24 | the SMBus and the ISA bus very much easier. See lm78.c for an example | 24 | the SMBus and the ISA bus very much easier. See lm78.c for an example |
25 | of this. */ | 25 | of this. */ |
26 | 26 | ||
27 | #include <linux/config.h> | ||
28 | #include <linux/init.h> | 27 | #include <linux/init.h> |
29 | #include <linux/module.h> | 28 | #include <linux/module.h> |
30 | #include <linux/kernel.h> | 29 | #include <linux/kernel.h> |
diff --git a/drivers/i2c/busses/i2c-ite.c b/drivers/i2c/busses/i2c-ite.c index 702e3def1b81..5f5d2944808b 100644 --- a/drivers/i2c/busses/i2c-ite.c +++ b/drivers/i2c/busses/i2c-ite.c | |||
@@ -33,7 +33,6 @@ | |||
33 | /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even | 33 | /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even |
34 | Frodo Looijaard <frodol@dds.nl> */ | 34 | Frodo Looijaard <frodol@dds.nl> */ |
35 | 35 | ||
36 | #include <linux/config.h> | ||
37 | #include <linux/kernel.h> | 36 | #include <linux/kernel.h> |
38 | #include <linux/ioport.h> | 37 | #include <linux/ioport.h> |
39 | #include <linux/module.h> | 38 | #include <linux/module.h> |
diff --git a/drivers/i2c/busses/i2c-ixp2000.c b/drivers/i2c/busses/i2c-ixp2000.c index 21cd54d02302..ec943cad2314 100644 --- a/drivers/i2c/busses/i2c-ixp2000.c +++ b/drivers/i2c/busses/i2c-ixp2000.c | |||
@@ -26,11 +26,6 @@ | |||
26 | * 'enabled' to drive the GPIOs. | 26 | * 'enabled' to drive the GPIOs. |
27 | */ | 27 | */ |
28 | 28 | ||
29 | #include <linux/config.h> | ||
30 | #ifdef CONFIG_I2C_DEBUG_BUS | ||
31 | #define DEBUG 1 | ||
32 | #endif | ||
33 | |||
34 | #include <linux/kernel.h> | 29 | #include <linux/kernel.h> |
35 | #include <linux/init.h> | 30 | #include <linux/init.h> |
36 | #include <linux/device.h> | 31 | #include <linux/device.h> |
diff --git a/drivers/i2c/busses/i2c-ixp4xx.c b/drivers/i2c/busses/i2c-ixp4xx.c index 8c55eafc3a09..f6f5ca31fdba 100644 --- a/drivers/i2c/busses/i2c-ixp4xx.c +++ b/drivers/i2c/busses/i2c-ixp4xx.c | |||
@@ -26,11 +26,6 @@ | |||
26 | * that is passed as the platform_data to this driver. | 26 | * that is passed as the platform_data to this driver. |
27 | */ | 27 | */ |
28 | 28 | ||
29 | #include <linux/config.h> | ||
30 | #ifdef CONFIG_I2C_DEBUG_BUS | ||
31 | #define DEBUG 1 | ||
32 | #endif | ||
33 | |||
34 | #include <linux/kernel.h> | 29 | #include <linux/kernel.h> |
35 | #include <linux/init.h> | 30 | #include <linux/init.h> |
36 | #include <linux/device.h> | 31 | #include <linux/device.h> |
diff --git a/drivers/i2c/busses/i2c-keywest.c b/drivers/i2c/busses/i2c-keywest.c index 867d443e7133..363e545fc01f 100644 --- a/drivers/i2c/busses/i2c-keywest.c +++ b/drivers/i2c/busses/i2c-keywest.c | |||
@@ -46,7 +46,6 @@ | |||
46 | sound driver to be happy | 46 | sound driver to be happy |
47 | */ | 47 | */ |
48 | 48 | ||
49 | #include <linux/config.h> | ||
50 | #include <linux/module.h> | 49 | #include <linux/module.h> |
51 | #include <linux/kernel.h> | 50 | #include <linux/kernel.h> |
52 | #include <linux/ioport.h> | 51 | #include <linux/ioport.h> |
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index 6f33496d31c3..d41ca31dbcb2 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c | |||
@@ -325,7 +325,7 @@ static int __devinit mpc_i2c_probe(struct ocp_device *ocp) | |||
325 | if (i2c->irq != OCP_IRQ_NA) | 325 | if (i2c->irq != OCP_IRQ_NA) |
326 | { | 326 | { |
327 | if ((result = request_irq(ocp->def->irq, mpc_i2c_isr, | 327 | if ((result = request_irq(ocp->def->irq, mpc_i2c_isr, |
328 | 0, "i2c-mpc", i2c)) < 0) { | 328 | SA_SHIRQ, "i2c-mpc", i2c)) < 0) { |
329 | printk(KERN_ERR | 329 | printk(KERN_ERR |
330 | "i2c-mpc - failed to attach interrupt\n"); | 330 | "i2c-mpc - failed to attach interrupt\n"); |
331 | goto fail_irq; | 331 | goto fail_irq; |
@@ -333,6 +333,9 @@ static int __devinit mpc_i2c_probe(struct ocp_device *ocp) | |||
333 | } else | 333 | } else |
334 | i2c->irq = 0; | 334 | i2c->irq = 0; |
335 | 335 | ||
336 | mpc_i2c_setclock(i2c); | ||
337 | ocp_set_drvdata(ocp, i2c); | ||
338 | |||
336 | i2c->adap = mpc_ops; | 339 | i2c->adap = mpc_ops; |
337 | i2c_set_adapdata(&i2c->adap, i2c); | 340 | i2c_set_adapdata(&i2c->adap, i2c); |
338 | 341 | ||
@@ -341,8 +344,6 @@ static int __devinit mpc_i2c_probe(struct ocp_device *ocp) | |||
341 | goto fail_add; | 344 | goto fail_add; |
342 | } | 345 | } |
343 | 346 | ||
344 | mpc_i2c_setclock(i2c); | ||
345 | ocp_set_drvdata(ocp, i2c); | ||
346 | return result; | 347 | return result; |
347 | 348 | ||
348 | fail_add: | 349 | fail_add: |
@@ -358,8 +359,8 @@ static int __devinit mpc_i2c_probe(struct ocp_device *ocp) | |||
358 | static void __devexit mpc_i2c_remove(struct ocp_device *ocp) | 359 | static void __devexit mpc_i2c_remove(struct ocp_device *ocp) |
359 | { | 360 | { |
360 | struct mpc_i2c *i2c = ocp_get_drvdata(ocp); | 361 | struct mpc_i2c *i2c = ocp_get_drvdata(ocp); |
361 | ocp_set_drvdata(ocp, NULL); | ||
362 | i2c_del_adapter(&i2c->adap); | 362 | i2c_del_adapter(&i2c->adap); |
363 | ocp_set_drvdata(ocp, NULL); | ||
363 | 364 | ||
364 | if (ocp->def->irq != OCP_IRQ_NA) | 365 | if (ocp->def->irq != OCP_IRQ_NA) |
365 | free_irq(i2c->irq, i2c); | 366 | free_irq(i2c->irq, i2c); |
@@ -424,12 +425,15 @@ static int fsl_i2c_probe(struct device *device) | |||
424 | 425 | ||
425 | if (i2c->irq != 0) | 426 | if (i2c->irq != 0) |
426 | if ((result = request_irq(i2c->irq, mpc_i2c_isr, | 427 | if ((result = request_irq(i2c->irq, mpc_i2c_isr, |
427 | 0, "fsl-i2c", i2c)) < 0) { | 428 | SA_SHIRQ, "i2c-mpc", i2c)) < 0) { |
428 | printk(KERN_ERR | 429 | printk(KERN_ERR |
429 | "i2c-mpc - failed to attach interrupt\n"); | 430 | "i2c-mpc - failed to attach interrupt\n"); |
430 | goto fail_irq; | 431 | goto fail_irq; |
431 | } | 432 | } |
432 | 433 | ||
434 | mpc_i2c_setclock(i2c); | ||
435 | dev_set_drvdata(device, i2c); | ||
436 | |||
433 | i2c->adap = mpc_ops; | 437 | i2c->adap = mpc_ops; |
434 | i2c_set_adapdata(&i2c->adap, i2c); | 438 | i2c_set_adapdata(&i2c->adap, i2c); |
435 | i2c->adap.dev.parent = &pdev->dev; | 439 | i2c->adap.dev.parent = &pdev->dev; |
@@ -438,8 +442,6 @@ static int fsl_i2c_probe(struct device *device) | |||
438 | goto fail_add; | 442 | goto fail_add; |
439 | } | 443 | } |
440 | 444 | ||
441 | mpc_i2c_setclock(i2c); | ||
442 | dev_set_drvdata(device, i2c); | ||
443 | return result; | 445 | return result; |
444 | 446 | ||
445 | fail_add: | 447 | fail_add: |
@@ -456,8 +458,8 @@ static int fsl_i2c_remove(struct device *device) | |||
456 | { | 458 | { |
457 | struct mpc_i2c *i2c = dev_get_drvdata(device); | 459 | struct mpc_i2c *i2c = dev_get_drvdata(device); |
458 | 460 | ||
459 | dev_set_drvdata(device, NULL); | ||
460 | i2c_del_adapter(&i2c->adap); | 461 | i2c_del_adapter(&i2c->adap); |
462 | dev_set_drvdata(device, NULL); | ||
461 | 463 | ||
462 | if (i2c->irq != 0) | 464 | if (i2c->irq != 0) |
463 | free_irq(i2c->irq, i2c); | 465 | free_irq(i2c->irq, i2c); |
diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index 6d13127c8c4e..74eb89aa9350 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c | |||
@@ -37,7 +37,6 @@ | |||
37 | 37 | ||
38 | /* Note: we assume there can only be one nForce2, with two SMBus interfaces */ | 38 | /* Note: we assume there can only be one nForce2, with two SMBus interfaces */ |
39 | 39 | ||
40 | #include <linux/config.h> | ||
41 | #include <linux/module.h> | 40 | #include <linux/module.h> |
42 | #include <linux/pci.h> | 41 | #include <linux/pci.h> |
43 | #include <linux/kernel.h> | 42 | #include <linux/kernel.h> |
diff --git a/drivers/i2c/busses/i2c-parport-light.c b/drivers/i2c/busses/i2c-parport-light.c index cb5e722301d8..3e5eba9fcacb 100644 --- a/drivers/i2c/busses/i2c-parport-light.c +++ b/drivers/i2c/busses/i2c-parport-light.c | |||
@@ -24,7 +24,6 @@ | |||
24 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 24 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
25 | * ------------------------------------------------------------------------ */ | 25 | * ------------------------------------------------------------------------ */ |
26 | 26 | ||
27 | #include <linux/config.h> | ||
28 | #include <linux/kernel.h> | 27 | #include <linux/kernel.h> |
29 | #include <linux/module.h> | 28 | #include <linux/module.h> |
30 | #include <linux/init.h> | 29 | #include <linux/init.h> |
diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c index e9560bab51c4..71a2502fe069 100644 --- a/drivers/i2c/busses/i2c-parport.c +++ b/drivers/i2c/busses/i2c-parport.c | |||
@@ -24,7 +24,6 @@ | |||
24 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 24 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
25 | * ------------------------------------------------------------------------ */ | 25 | * ------------------------------------------------------------------------ */ |
26 | 26 | ||
27 | #include <linux/config.h> | ||
28 | #include <linux/kernel.h> | 27 | #include <linux/kernel.h> |
29 | #include <linux/module.h> | 28 | #include <linux/module.h> |
30 | #include <linux/init.h> | 29 | #include <linux/init.h> |
@@ -131,7 +130,7 @@ static int parport_getsda(void *data) | |||
131 | /* Encapsulate the functions above in the correct structure. | 130 | /* Encapsulate the functions above in the correct structure. |
132 | Note that this is only a template, from which the real structures are | 131 | Note that this is only a template, from which the real structures are |
133 | copied. The attaching code will set getscl to NULL for adapters that | 132 | copied. The attaching code will set getscl to NULL for adapters that |
134 | cannot read SCL back, and will also make the the data field point to | 133 | cannot read SCL back, and will also make the data field point to |
135 | the parallel port structure. */ | 134 | the parallel port structure. */ |
136 | static struct i2c_algo_bit_data parport_algo_data = { | 135 | static struct i2c_algo_bit_data parport_algo_data = { |
137 | .setsda = parport_setsda, | 136 | .setsda = parport_setsda, |
diff --git a/drivers/i2c/busses/i2c-pca-isa.c b/drivers/i2c/busses/i2c-pca-isa.c index 9c611134db9c..d9b4ddbad7e0 100644 --- a/drivers/i2c/busses/i2c-pca-isa.c +++ b/drivers/i2c/busses/i2c-pca-isa.c | |||
@@ -17,7 +17,6 @@ | |||
17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
18 | */ | 18 | */ |
19 | 19 | ||
20 | #include <linux/config.h> | ||
21 | #include <linux/kernel.h> | 20 | #include <linux/kernel.h> |
22 | #include <linux/ioport.h> | 21 | #include <linux/ioport.h> |
23 | #include <linux/module.h> | 22 | #include <linux/module.h> |
diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index 646381b6b3bf..1f80ba9da6f1 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c | |||
@@ -28,7 +28,6 @@ | |||
28 | Note: we assume there can only be one device, with one SMBus interface. | 28 | Note: we assume there can only be one device, with one SMBus interface. |
29 | */ | 29 | */ |
30 | 30 | ||
31 | #include <linux/config.h> | ||
32 | #include <linux/module.h> | 31 | #include <linux/module.h> |
33 | #include <linux/moduleparam.h> | 32 | #include <linux/moduleparam.h> |
34 | #include <linux/pci.h> | 33 | #include <linux/pci.h> |
diff --git a/drivers/i2c/busses/i2c-prosavage.c b/drivers/i2c/busses/i2c-prosavage.c index 13d66289933b..83fd16d61ce5 100644 --- a/drivers/i2c/busses/i2c-prosavage.c +++ b/drivers/i2c/busses/i2c-prosavage.c | |||
@@ -54,7 +54,6 @@ | |||
54 | * (Additional documentation needed :( | 54 | * (Additional documentation needed :( |
55 | */ | 55 | */ |
56 | 56 | ||
57 | #include <linux/config.h> | ||
58 | #include <linux/module.h> | 57 | #include <linux/module.h> |
59 | #include <linux/init.h> | 58 | #include <linux/init.h> |
60 | #include <linux/pci.h> | 59 | #include <linux/pci.h> |
diff --git a/drivers/i2c/busses/i2c-rpx.c b/drivers/i2c/busses/i2c-rpx.c index 9497b1b6852f..0ebec3c1a54e 100644 --- a/drivers/i2c/busses/i2c-rpx.c +++ b/drivers/i2c/busses/i2c-rpx.c | |||
@@ -11,7 +11,6 @@ | |||
11 | * changed to eliminate RPXLite references. | 11 | * changed to eliminate RPXLite references. |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/config.h> | ||
15 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
16 | #include <linux/module.h> | 15 | #include <linux/module.h> |
17 | #include <linux/init.h> | 16 | #include <linux/init.h> |
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index fcfa51c1436b..a3b38257cc3d 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c | |||
@@ -20,6 +20,7 @@ | |||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <linux/config.h> | ||
23 | #include <linux/kernel.h> | 24 | #include <linux/kernel.h> |
24 | #include <linux/module.h> | 25 | #include <linux/module.h> |
25 | 26 | ||
@@ -533,7 +534,7 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, struct i2c_msg *msgs, int | |||
533 | /* s3c24xx_i2c_xfer | 534 | /* s3c24xx_i2c_xfer |
534 | * | 535 | * |
535 | * first port of call from the i2c bus code when an message needs | 536 | * first port of call from the i2c bus code when an message needs |
536 | * transfering across the i2c bus. | 537 | * transferring across the i2c bus. |
537 | */ | 538 | */ |
538 | 539 | ||
539 | static int s3c24xx_i2c_xfer(struct i2c_adapter *adap, | 540 | static int s3c24xx_i2c_xfer(struct i2c_adapter *adap, |
diff --git a/drivers/i2c/busses/i2c-savage4.c b/drivers/i2c/busses/i2c-savage4.c index 092d0323c6c6..0c8518298e4d 100644 --- a/drivers/i2c/busses/i2c-savage4.c +++ b/drivers/i2c/busses/i2c-savage4.c | |||
@@ -29,7 +29,6 @@ | |||
29 | it easier to add later. | 29 | it easier to add later. |
30 | */ | 30 | */ |
31 | 31 | ||
32 | #include <linux/config.h> | ||
33 | #include <linux/kernel.h> | 32 | #include <linux/kernel.h> |
34 | #include <linux/module.h> | 33 | #include <linux/module.h> |
35 | #include <linux/init.h> | 34 | #include <linux/init.h> |
diff --git a/drivers/i2c/busses/i2c-sibyte.c b/drivers/i2c/busses/i2c-sibyte.c index e5dd90bdb04a..1c99536b673b 100644 --- a/drivers/i2c/busses/i2c-sibyte.c +++ b/drivers/i2c/busses/i2c-sibyte.c | |||
@@ -17,7 +17,6 @@ | |||
17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
18 | */ | 18 | */ |
19 | 19 | ||
20 | #include <linux/config.h> | ||
21 | #include <linux/module.h> | 20 | #include <linux/module.h> |
22 | #include <linux/i2c-algo-sibyte.h> | 21 | #include <linux/i2c-algo-sibyte.h> |
23 | #include <asm/sibyte/sb1250_regs.h> | 22 | #include <asm/sibyte/sb1250_regs.h> |
diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c index 425733b019b6..2b5911cfb7b5 100644 --- a/drivers/i2c/busses/i2c-sis5595.c +++ b/drivers/i2c/busses/i2c-sis5595.c | |||
@@ -55,7 +55,6 @@ | |||
55 | * Add adapter resets | 55 | * Add adapter resets |
56 | */ | 56 | */ |
57 | 57 | ||
58 | #include <linux/config.h> | ||
59 | #include <linux/kernel.h> | 58 | #include <linux/kernel.h> |
60 | #include <linux/module.h> | 59 | #include <linux/module.h> |
61 | #include <linux/delay.h> | 60 | #include <linux/delay.h> |
diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c index 58df63df1540..f58455e7689e 100644 --- a/drivers/i2c/busses/i2c-sis630.c +++ b/drivers/i2c/busses/i2c-sis630.c | |||
@@ -48,7 +48,6 @@ | |||
48 | Note: we assume there can only be one device, with one SMBus interface. | 48 | Note: we assume there can only be one device, with one SMBus interface. |
49 | */ | 49 | */ |
50 | 50 | ||
51 | #include <linux/config.h> | ||
52 | #include <linux/kernel.h> | 51 | #include <linux/kernel.h> |
53 | #include <linux/module.h> | 52 | #include <linux/module.h> |
54 | #include <linux/delay.h> | 53 | #include <linux/delay.h> |
diff --git a/drivers/i2c/busses/i2c-sis96x.c b/drivers/i2c/busses/i2c-sis96x.c index 3cac6d43bce5..6484792e23a1 100644 --- a/drivers/i2c/busses/i2c-sis96x.c +++ b/drivers/i2c/busses/i2c-sis96x.c | |||
@@ -32,7 +32,6 @@ | |||
32 | We assume there can only be one SiS96x with one SMBus interface. | 32 | We assume there can only be one SiS96x with one SMBus interface. |
33 | */ | 33 | */ |
34 | 34 | ||
35 | #include <linux/config.h> | ||
36 | #include <linux/module.h> | 35 | #include <linux/module.h> |
37 | #include <linux/pci.h> | 36 | #include <linux/pci.h> |
38 | #include <linux/kernel.h> | 37 | #include <linux/kernel.h> |
diff --git a/drivers/i2c/busses/i2c-stub.c b/drivers/i2c/busses/i2c-stub.c index 19c805ead4d8..00d94e886955 100644 --- a/drivers/i2c/busses/i2c-stub.c +++ b/drivers/i2c/busses/i2c-stub.c | |||
@@ -21,7 +21,6 @@ | |||
21 | 21 | ||
22 | #define DEBUG 1 | 22 | #define DEBUG 1 |
23 | 23 | ||
24 | #include <linux/config.h> | ||
25 | #include <linux/init.h> | 24 | #include <linux/init.h> |
26 | #include <linux/module.h> | 25 | #include <linux/module.h> |
27 | #include <linux/kernel.h> | 26 | #include <linux/kernel.h> |
diff --git a/drivers/i2c/busses/i2c-via.c b/drivers/i2c/busses/i2c-via.c index 2cbc4cd22366..040b8abeabba 100644 --- a/drivers/i2c/busses/i2c-via.c +++ b/drivers/i2c/busses/i2c-via.c | |||
@@ -21,7 +21,6 @@ | |||
21 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 21 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <linux/config.h> | ||
25 | #include <linux/kernel.h> | 24 | #include <linux/kernel.h> |
26 | #include <linux/module.h> | 25 | #include <linux/module.h> |
27 | #include <linux/pci.h> | 26 | #include <linux/pci.h> |
diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c index 0bb60a636e16..6b5008005c6f 100644 --- a/drivers/i2c/busses/i2c-viapro.c +++ b/drivers/i2c/busses/i2c-viapro.c | |||
@@ -33,7 +33,6 @@ | |||
33 | Note: we assume there can only be one device, with one SMBus interface. | 33 | Note: we assume there can only be one device, with one SMBus interface. |
34 | */ | 34 | */ |
35 | 35 | ||
36 | #include <linux/config.h> | ||
37 | #include <linux/module.h> | 36 | #include <linux/module.h> |
38 | #include <linux/delay.h> | 37 | #include <linux/delay.h> |
39 | #include <linux/pci.h> | 38 | #include <linux/pci.h> |
diff --git a/drivers/i2c/busses/i2c-voodoo3.c b/drivers/i2c/busses/i2c-voodoo3.c index 3edf0e34155e..b675773b0cc1 100644 --- a/drivers/i2c/busses/i2c-voodoo3.c +++ b/drivers/i2c/busses/i2c-voodoo3.c | |||
@@ -27,7 +27,6 @@ | |||
27 | /* This interfaces to the I2C bus of the Voodoo3 to gain access to | 27 | /* This interfaces to the I2C bus of the Voodoo3 to gain access to |
28 | the BT869 and possibly other I2C devices. */ | 28 | the BT869 and possibly other I2C devices. */ |
29 | 29 | ||
30 | #include <linux/config.h> | ||
31 | #include <linux/kernel.h> | 30 | #include <linux/kernel.h> |
32 | #include <linux/module.h> | 31 | #include <linux/module.h> |
33 | #include <linux/init.h> | 32 | #include <linux/init.h> |
diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c index 1c4159a93623..a18bdd9aa7ba 100644 --- a/drivers/i2c/busses/scx200_acb.c +++ b/drivers/i2c/busses/scx200_acb.c | |||
@@ -24,7 +24,6 @@ | |||
24 | 24 | ||
25 | */ | 25 | */ |
26 | 26 | ||
27 | #include <linux/config.h> | ||
28 | #include <linux/module.h> | 27 | #include <linux/module.h> |
29 | #include <linux/errno.h> | 28 | #include <linux/errno.h> |
30 | #include <linux/kernel.h> | 29 | #include <linux/kernel.h> |
diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index 74d23cfce2a3..a0982da09803 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig | |||
@@ -1,5 +1,5 @@ | |||
1 | # | 1 | # |
2 | # I2C Sensor device configuration | 2 | # I2C Sensor and "other" chip configuration |
3 | # | 3 | # |
4 | 4 | ||
5 | menu "Hardware Sensors Chip support" | 5 | menu "Hardware Sensors Chip support" |
@@ -11,7 +11,7 @@ config I2C_SENSOR | |||
11 | 11 | ||
12 | config SENSORS_ADM1021 | 12 | config SENSORS_ADM1021 |
13 | tristate "Analog Devices ADM1021 and compatibles" | 13 | tristate "Analog Devices ADM1021 and compatibles" |
14 | depends on I2C && EXPERIMENTAL | 14 | depends on I2C |
15 | select I2C_SENSOR | 15 | select I2C_SENSOR |
16 | help | 16 | help |
17 | If you say yes here you get support for Analog Devices ADM1021 | 17 | If you say yes here you get support for Analog Devices ADM1021 |
@@ -29,6 +29,7 @@ config SENSORS_ADM1025 | |||
29 | help | 29 | help |
30 | If you say yes here you get support for Analog Devices ADM1025 | 30 | If you say yes here you get support for Analog Devices ADM1025 |
31 | and Philips NE1619 sensor chips. | 31 | and Philips NE1619 sensor chips. |
32 | |||
32 | This driver can also be built as a module. If so, the module | 33 | This driver can also be built as a module. If so, the module |
33 | will be called adm1025. | 34 | will be called adm1025. |
34 | 35 | ||
@@ -38,6 +39,8 @@ config SENSORS_ADM1026 | |||
38 | select I2C_SENSOR | 39 | select I2C_SENSOR |
39 | help | 40 | help |
40 | If you say yes here you get support for Analog Devices ADM1026 | 41 | If you say yes here you get support for Analog Devices ADM1026 |
42 | sensor chip. | ||
43 | |||
41 | This driver can also be built as a module. If so, the module | 44 | This driver can also be built as a module. If so, the module |
42 | will be called adm1026. | 45 | will be called adm1026. |
43 | 46 | ||
@@ -48,9 +51,21 @@ config SENSORS_ADM1031 | |||
48 | help | 51 | help |
49 | If you say yes here you get support for Analog Devices ADM1031 | 52 | If you say yes here you get support for Analog Devices ADM1031 |
50 | and ADM1030 sensor chips. | 53 | and ADM1030 sensor chips. |
54 | |||
51 | This driver can also be built as a module. If so, the module | 55 | This driver can also be built as a module. If so, the module |
52 | will be called adm1031. | 56 | will be called adm1031. |
53 | 57 | ||
58 | config SENSORS_ADM9240 | ||
59 | tristate "Analog Devices ADM9240 and compatibles" | ||
60 | depends on I2C && EXPERIMENTAL | ||
61 | select I2C_SENSOR | ||
62 | help | ||
63 | If you say yes here you get support for Analog Devices ADM9240, | ||
64 | Dallas DS1780, National Semiconductor LM81 sensor chips. | ||
65 | |||
66 | This driver can also be built as a module. If so, the module | ||
67 | will be called adm9240. | ||
68 | |||
54 | config SENSORS_ASB100 | 69 | config SENSORS_ASB100 |
55 | tristate "Asus ASB100 Bach" | 70 | tristate "Asus ASB100 Bach" |
56 | depends on I2C && EXPERIMENTAL | 71 | depends on I2C && EXPERIMENTAL |
@@ -62,6 +77,19 @@ config SENSORS_ASB100 | |||
62 | This driver can also be built as a module. If so, the module | 77 | This driver can also be built as a module. If so, the module |
63 | will be called asb100. | 78 | will be called asb100. |
64 | 79 | ||
80 | config SENSORS_ATXP1 | ||
81 | tristate "Attansic ATXP1 VID controller" | ||
82 | depends on I2C && EXPERIMENTAL | ||
83 | help | ||
84 | If you say yes here you get support for the Attansic ATXP1 VID | ||
85 | controller. | ||
86 | |||
87 | If your board have such a chip, you are able to control your CPU | ||
88 | core and other voltages. | ||
89 | |||
90 | This driver can also be built as a module. If so, the module | ||
91 | will be called atxp1. | ||
92 | |||
65 | config SENSORS_DS1621 | 93 | config SENSORS_DS1621 |
66 | tristate "Dallas Semiconductor DS1621 and DS1625" | 94 | tristate "Dallas Semiconductor DS1621 and DS1625" |
67 | depends on I2C && EXPERIMENTAL | 95 | depends on I2C && EXPERIMENTAL |
@@ -97,7 +125,7 @@ config SENSORS_FSCPOS | |||
97 | 125 | ||
98 | config SENSORS_GL518SM | 126 | config SENSORS_GL518SM |
99 | tristate "Genesys Logic GL518SM" | 127 | tristate "Genesys Logic GL518SM" |
100 | depends on I2C && EXPERIMENTAL | 128 | depends on I2C |
101 | select I2C_SENSOR | 129 | select I2C_SENSOR |
102 | help | 130 | help |
103 | If you say yes here you get support for Genesys Logic GL518SM | 131 | If you say yes here you get support for Genesys Logic GL518SM |
@@ -119,7 +147,7 @@ config SENSORS_GL520SM | |||
119 | 147 | ||
120 | config SENSORS_IT87 | 148 | config SENSORS_IT87 |
121 | tristate "ITE IT87xx and compatibles" | 149 | tristate "ITE IT87xx and compatibles" |
122 | depends on I2C && EXPERIMENTAL | 150 | depends on I2C |
123 | select I2C_SENSOR | 151 | select I2C_SENSOR |
124 | help | 152 | help |
125 | If you say yes here you get support for ITE IT87xx sensor chips | 153 | If you say yes here you get support for ITE IT87xx sensor chips |
@@ -143,7 +171,7 @@ config SENSORS_LM63 | |||
143 | 171 | ||
144 | config SENSORS_LM75 | 172 | config SENSORS_LM75 |
145 | tristate "National Semiconductor LM75 and compatibles" | 173 | tristate "National Semiconductor LM75 and compatibles" |
146 | depends on I2C && EXPERIMENTAL | 174 | depends on I2C |
147 | select I2C_SENSOR | 175 | select I2C_SENSOR |
148 | help | 176 | help |
149 | If you say yes here you get support for National Semiconductor LM75 | 177 | If you say yes here you get support for National Semiconductor LM75 |
@@ -174,8 +202,7 @@ config SENSORS_LM78 | |||
174 | select I2C_SENSOR | 202 | select I2C_SENSOR |
175 | help | 203 | help |
176 | If you say yes here you get support for National Semiconductor LM78, | 204 | If you say yes here you get support for National Semiconductor LM78, |
177 | LM78-J and LM79. This can also be built as a module which can be | 205 | LM78-J and LM79. |
178 | inserted and removed while the kernel is running. | ||
179 | 206 | ||
180 | This driver can also be built as a module. If so, the module | 207 | This driver can also be built as a module. If so, the module |
181 | will be called lm78. | 208 | will be called lm78. |
@@ -208,7 +235,7 @@ config SENSORS_LM85 | |||
208 | select I2C_SENSOR | 235 | select I2C_SENSOR |
209 | help | 236 | help |
210 | If you say yes here you get support for National Semiconductor LM85 | 237 | If you say yes here you get support for National Semiconductor LM85 |
211 | sensor chips and clones: ADT7463 and ADM1027. | 238 | sensor chips and clones: ADT7463, EMC6D100, EMC6D102 and ADM1027. |
212 | 239 | ||
213 | This driver can also be built as a module. If so, the module | 240 | This driver can also be built as a module. If so, the module |
214 | will be called lm85. | 241 | will be called lm85. |
@@ -307,14 +334,14 @@ config SENSORS_SMSC47M1 | |||
307 | help | 334 | help |
308 | If you say yes here you get support for the integrated fan | 335 | If you say yes here you get support for the integrated fan |
309 | monitoring and control capabilities of the SMSC LPC47B27x, | 336 | monitoring and control capabilities of the SMSC LPC47B27x, |
310 | LPC47M10x, LPC47M13x and LPC47M14x chips. | 337 | LPC47M10x, LPC47M13x, LPC47M14x, LPC47M15x and LPC47M192 chips. |
311 | 338 | ||
312 | This driver can also be built as a module. If so, the module | 339 | This driver can also be built as a module. If so, the module |
313 | will be called smsc47m1. | 340 | will be called smsc47m1. |
314 | 341 | ||
315 | config SENSORS_VIA686A | 342 | config SENSORS_VIA686A |
316 | tristate "VIA686A" | 343 | tristate "VIA686A" |
317 | depends on I2C && PCI && EXPERIMENTAL | 344 | depends on I2C && PCI |
318 | select I2C_SENSOR | 345 | select I2C_SENSOR |
319 | select I2C_ISA | 346 | select I2C_ISA |
320 | help | 347 | help |
@@ -326,7 +353,7 @@ config SENSORS_VIA686A | |||
326 | 353 | ||
327 | config SENSORS_W83781D | 354 | config SENSORS_W83781D |
328 | tristate "Winbond W83781D, W83782D, W83783S, W83627HF, Asus AS99127F" | 355 | tristate "Winbond W83781D, W83782D, W83783S, W83627HF, Asus AS99127F" |
329 | depends on I2C && EXPERIMENTAL | 356 | depends on I2C |
330 | select I2C_SENSOR | 357 | select I2C_SENSOR |
331 | help | 358 | help |
332 | If you say yes here you get support for the Winbond W8378x series | 359 | If you say yes here you get support for the Winbond W8378x series |
@@ -360,22 +387,47 @@ config SENSORS_W83627HF | |||
360 | This driver can also be built as a module. If so, the module | 387 | This driver can also be built as a module. If so, the module |
361 | will be called w83627hf. | 388 | will be called w83627hf. |
362 | 389 | ||
390 | config SENSORS_W83627EHF | ||
391 | tristate "Winbond W83627EHF" | ||
392 | depends on I2C && EXPERIMENTAL | ||
393 | select I2C_SENSOR | ||
394 | select I2C_ISA | ||
395 | help | ||
396 | If you say yes here you get preliminary support for the hardware | ||
397 | monitoring functionality of the Winbond W83627EHF Super-I/O chip. | ||
398 | Only fan and temperature inputs are supported at the moment, while | ||
399 | the chip does much more than that. | ||
400 | |||
401 | This driver can also be built as a module. If so, the module | ||
402 | will be called w83627ehf. | ||
403 | |||
363 | endmenu | 404 | endmenu |
364 | 405 | ||
365 | menu "Other I2C Chip support" | 406 | menu "Other I2C Chip support" |
366 | depends on I2C | 407 | depends on I2C |
367 | 408 | ||
368 | config SENSORS_DS1337 | 409 | config SENSORS_DS1337 |
369 | tristate "Dallas Semiconductor DS1337 Real Time Clock" | 410 | tristate "Dallas Semiconductor DS1337 and DS1339 Real Time Clock" |
370 | depends on I2C && EXPERIMENTAL | 411 | depends on I2C && EXPERIMENTAL |
371 | select I2C_SENSOR | 412 | select I2C_SENSOR |
372 | help | 413 | help |
373 | If you say yes here you get support for Dallas Semiconductor | 414 | If you say yes here you get support for Dallas Semiconductor |
374 | DS1337 real-time clock chips. | 415 | DS1337 and DS1339 real-time clock chips. |
375 | 416 | ||
376 | This driver can also be built as a module. If so, the module | 417 | This driver can also be built as a module. If so, the module |
377 | will be called ds1337. | 418 | will be called ds1337. |
378 | 419 | ||
420 | config SENSORS_DS1374 | ||
421 | tristate "Maxim/Dallas Semiconductor DS1374 Real Time Clock" | ||
422 | depends on I2C && EXPERIMENTAL | ||
423 | select I2C_SENSOR | ||
424 | help | ||
425 | If you say yes here you get support for Dallas Semiconductor | ||
426 | DS1374 real-time clock chips. | ||
427 | |||
428 | This driver can also be built as a module. If so, the module | ||
429 | will be called ds1374. | ||
430 | |||
379 | config SENSORS_EEPROM | 431 | config SENSORS_EEPROM |
380 | tristate "EEPROM reader" | 432 | tristate "EEPROM reader" |
381 | depends on I2C && EXPERIMENTAL | 433 | depends on I2C && EXPERIMENTAL |
@@ -399,6 +451,16 @@ config SENSORS_PCF8574 | |||
399 | This driver can also be built as a module. If so, the module | 451 | This driver can also be built as a module. If so, the module |
400 | will be called pcf8574. | 452 | will be called pcf8574. |
401 | 453 | ||
454 | config SENSORS_PCA9539 | ||
455 | tristate "Philips PCA9539 16-bit I/O port" | ||
456 | depends on I2C && EXPERIMENTAL | ||
457 | help | ||
458 | If you say yes here you get support for the Philips PCA9539 | ||
459 | 16-bit I/O port. | ||
460 | |||
461 | This driver can also be built as a module. If so, the module | ||
462 | will be called pca9539. | ||
463 | |||
402 | config SENSORS_PCF8591 | 464 | config SENSORS_PCF8591 |
403 | tristate "Philips PCF8591" | 465 | tristate "Philips PCF8591" |
404 | depends on I2C && EXPERIMENTAL | 466 | depends on I2C && EXPERIMENTAL |
@@ -431,6 +493,23 @@ config ISP1301_OMAP | |||
431 | This driver can also be built as a module. If so, the module | 493 | This driver can also be built as a module. If so, the module |
432 | will be called isp1301_omap. | 494 | will be called isp1301_omap. |
433 | 495 | ||
496 | # NOTE: This isn't really OMAP-specific, except for the current | ||
497 | # interface location in <include/asm-arm/arch-omap/tps65010.h> | ||
498 | # and having mostly OMAP-specific board support | ||
499 | config TPS65010 | ||
500 | tristate "TPS6501x Power Management chips" | ||
501 | depends on I2C && ARCH_OMAP | ||
502 | default y if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_OSK | ||
503 | help | ||
504 | If you say yes here you get support for the TPS6501x series of | ||
505 | Power Management chips. These include voltage regulators, | ||
506 | lithium ion/polymer battery charging, and other features that | ||
507 | are often used in portable devices like cell phones and cameras. | ||
508 | |||
509 | This driver can also be built as a module. If so, the module | ||
510 | will be called tps65010. | ||
511 | |||
512 | |||
434 | config SENSORS_M41T00 | 513 | config SENSORS_M41T00 |
435 | tristate "ST M41T00 RTC chip" | 514 | tristate "ST M41T00 RTC chip" |
436 | depends on I2C && PPC32 | 515 | depends on I2C && PPC32 |
@@ -440,4 +519,16 @@ config SENSORS_M41T00 | |||
440 | This driver can also be built as a module. If so, the module | 519 | This driver can also be built as a module. If so, the module |
441 | will be called m41t00. | 520 | will be called m41t00. |
442 | 521 | ||
522 | config SENSORS_MAX6875 | ||
523 | tristate "MAXIM MAX6875 Power supply supervisor" | ||
524 | depends on I2C && EXPERIMENTAL | ||
525 | help | ||
526 | If you say yes here you get support for the MAX6875 | ||
527 | EEPROM-Programmable, Hex/Quad, Power-Suppy Sequencers/Supervisors. | ||
528 | |||
529 | This provides a interface to program the EEPROM and reset the chip. | ||
530 | |||
531 | This driver can also be built as a module. If so, the module | ||
532 | will be called max6875. | ||
533 | |||
443 | endmenu | 534 | endmenu |
diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile index 65599161a172..b5e6d2f84f97 100644 --- a/drivers/i2c/chips/Makefile +++ b/drivers/i2c/chips/Makefile | |||
@@ -1,5 +1,5 @@ | |||
1 | # | 1 | # |
2 | # Makefile for the kernel hardware sensors chip drivers. | 2 | # Makefile for sensor and "other" I2C chip drivers. |
3 | # | 3 | # |
4 | 4 | ||
5 | # asb100, then w83781d go first, as they can override other drivers' addresses. | 5 | # asb100, then w83781d go first, as they can override other drivers' addresses. |
@@ -11,7 +11,10 @@ obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o | |||
11 | obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o | 11 | obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o |
12 | obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o | 12 | obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o |
13 | obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o | 13 | obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o |
14 | obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o | ||
15 | obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o | ||
14 | obj-$(CONFIG_SENSORS_DS1337) += ds1337.o | 16 | obj-$(CONFIG_SENSORS_DS1337) += ds1337.o |
17 | obj-$(CONFIG_SENSORS_DS1374) += ds1374.o | ||
15 | obj-$(CONFIG_SENSORS_DS1621) += ds1621.o | 18 | obj-$(CONFIG_SENSORS_DS1621) += ds1621.o |
16 | obj-$(CONFIG_SENSORS_EEPROM) += eeprom.o | 19 | obj-$(CONFIG_SENSORS_EEPROM) += eeprom.o |
17 | obj-$(CONFIG_SENSORS_FSCHER) += fscher.o | 20 | obj-$(CONFIG_SENSORS_FSCHER) += fscher.o |
@@ -30,8 +33,10 @@ obj-$(CONFIG_SENSORS_LM87) += lm87.o | |||
30 | obj-$(CONFIG_SENSORS_LM90) += lm90.o | 33 | obj-$(CONFIG_SENSORS_LM90) += lm90.o |
31 | obj-$(CONFIG_SENSORS_LM92) += lm92.o | 34 | obj-$(CONFIG_SENSORS_LM92) += lm92.o |
32 | obj-$(CONFIG_SENSORS_MAX1619) += max1619.o | 35 | obj-$(CONFIG_SENSORS_MAX1619) += max1619.o |
36 | obj-$(CONFIG_SENSORS_MAX6875) += max6875.o | ||
33 | obj-$(CONFIG_SENSORS_M41T00) += m41t00.o | 37 | obj-$(CONFIG_SENSORS_M41T00) += m41t00.o |
34 | obj-$(CONFIG_SENSORS_PC87360) += pc87360.o | 38 | obj-$(CONFIG_SENSORS_PC87360) += pc87360.o |
39 | obj-$(CONFIG_SENSORS_PCA9539) += pca9539.o | ||
35 | obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o | 40 | obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o |
36 | obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o | 41 | obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o |
37 | obj-$(CONFIG_SENSORS_RTC8564) += rtc8564.o | 42 | obj-$(CONFIG_SENSORS_RTC8564) += rtc8564.o |
@@ -39,8 +44,11 @@ obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o | |||
39 | obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o | 44 | obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o |
40 | obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o | 45 | obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o |
41 | obj-$(CONFIG_SENSORS_VIA686A) += via686a.o | 46 | obj-$(CONFIG_SENSORS_VIA686A) += via686a.o |
47 | obj-$(CONFIG_SENSORS_W83627EHF) += w83627ehf.o | ||
42 | obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o | 48 | obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o |
49 | |||
43 | obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o | 50 | obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o |
51 | obj-$(CONFIG_TPS65010) += tps65010.o | ||
44 | 52 | ||
45 | ifeq ($(CONFIG_I2C_DEBUG_CHIP),y) | 53 | ifeq ($(CONFIG_I2C_DEBUG_CHIP),y) |
46 | EXTRA_CFLAGS += -DDEBUG | 54 | EXTRA_CFLAGS += -DDEBUG |
diff --git a/drivers/i2c/chips/adm1021.c b/drivers/i2c/chips/adm1021.c index 9058c3956710..d2c774c32f45 100644 --- a/drivers/i2c/chips/adm1021.c +++ b/drivers/i2c/chips/adm1021.c | |||
@@ -19,7 +19,6 @@ | |||
19 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 19 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <linux/config.h> | ||
23 | #include <linux/module.h> | 22 | #include <linux/module.h> |
24 | #include <linux/init.h> | 23 | #include <linux/init.h> |
25 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
@@ -103,8 +102,6 @@ struct adm1021_data { | |||
103 | u8 remote_temp_hyst; | 102 | u8 remote_temp_hyst; |
104 | u8 remote_temp_input; | 103 | u8 remote_temp_input; |
105 | u8 alarms; | 104 | u8 alarms; |
106 | /* special values for ADM1021 only */ | ||
107 | u8 die_code; | ||
108 | /* Special values for ADM1023 only */ | 105 | /* Special values for ADM1023 only */ |
109 | u8 remote_temp_prec; | 106 | u8 remote_temp_prec; |
110 | u8 remote_temp_os_prec; | 107 | u8 remote_temp_os_prec; |
@@ -156,7 +153,6 @@ static ssize_t show_##value(struct device *dev, struct device_attribute *attr, c | |||
156 | return sprintf(buf, "%d\n", data->value); \ | 153 | return sprintf(buf, "%d\n", data->value); \ |
157 | } | 154 | } |
158 | show2(alarms); | 155 | show2(alarms); |
159 | show2(die_code); | ||
160 | 156 | ||
161 | #define set(value, reg) \ | 157 | #define set(value, reg) \ |
162 | static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ | 158 | static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ |
@@ -183,7 +179,6 @@ static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_remote_temp_max, set_remot | |||
183 | static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_remote_temp_hyst, set_remote_temp_hyst); | 179 | static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_remote_temp_hyst, set_remote_temp_hyst); |
184 | static DEVICE_ATTR(temp2_input, S_IRUGO, show_remote_temp_input, NULL); | 180 | static DEVICE_ATTR(temp2_input, S_IRUGO, show_remote_temp_input, NULL); |
185 | static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); | 181 | static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); |
186 | static DEVICE_ATTR(die_code, S_IRUGO, show_die_code, NULL); | ||
187 | 182 | ||
188 | 183 | ||
189 | static int adm1021_attach_adapter(struct i2c_adapter *adapter) | 184 | static int adm1021_attach_adapter(struct i2c_adapter *adapter) |
@@ -307,8 +302,6 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind) | |||
307 | device_create_file(&new_client->dev, &dev_attr_temp2_min); | 302 | device_create_file(&new_client->dev, &dev_attr_temp2_min); |
308 | device_create_file(&new_client->dev, &dev_attr_temp2_input); | 303 | device_create_file(&new_client->dev, &dev_attr_temp2_input); |
309 | device_create_file(&new_client->dev, &dev_attr_alarms); | 304 | device_create_file(&new_client->dev, &dev_attr_alarms); |
310 | if (data->type == adm1021) | ||
311 | device_create_file(&new_client->dev, &dev_attr_die_code); | ||
312 | 305 | ||
313 | return 0; | 306 | return 0; |
314 | 307 | ||
@@ -371,8 +364,6 @@ static struct adm1021_data *adm1021_update_device(struct device *dev) | |||
371 | data->remote_temp_max = adm1021_read_value(client, ADM1021_REG_REMOTE_TOS_R); | 364 | data->remote_temp_max = adm1021_read_value(client, ADM1021_REG_REMOTE_TOS_R); |
372 | data->remote_temp_hyst = adm1021_read_value(client, ADM1021_REG_REMOTE_THYST_R); | 365 | data->remote_temp_hyst = adm1021_read_value(client, ADM1021_REG_REMOTE_THYST_R); |
373 | data->alarms = adm1021_read_value(client, ADM1021_REG_STATUS) & 0x7c; | 366 | data->alarms = adm1021_read_value(client, ADM1021_REG_STATUS) & 0x7c; |
374 | if (data->type == adm1021) | ||
375 | data->die_code = adm1021_read_value(client, ADM1021_REG_DIE_CODE); | ||
376 | if (data->type == adm1023) { | 367 | if (data->type == adm1023) { |
377 | data->remote_temp_prec = adm1021_read_value(client, ADM1021_REG_REM_TEMP_PREC); | 368 | data->remote_temp_prec = adm1021_read_value(client, ADM1021_REG_REM_TEMP_PREC); |
378 | data->remote_temp_os_prec = adm1021_read_value(client, ADM1021_REG_REM_TOS_PREC); | 369 | data->remote_temp_os_prec = adm1021_read_value(client, ADM1021_REG_REM_TOS_PREC); |
diff --git a/drivers/i2c/chips/adm1025.c b/drivers/i2c/chips/adm1025.c index 111f0c86c933..e452d0daf906 100644 --- a/drivers/i2c/chips/adm1025.c +++ b/drivers/i2c/chips/adm1025.c | |||
@@ -45,7 +45,6 @@ | |||
45 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 45 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
46 | */ | 46 | */ |
47 | 47 | ||
48 | #include <linux/config.h> | ||
49 | #include <linux/module.h> | 48 | #include <linux/module.h> |
50 | #include <linux/init.h> | 49 | #include <linux/init.h> |
51 | #include <linux/slab.h> | 50 | #include <linux/slab.h> |
@@ -287,7 +286,9 @@ static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char | |||
287 | struct adm1025_data *data = adm1025_update_device(dev); | 286 | struct adm1025_data *data = adm1025_update_device(dev); |
288 | return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm)); | 287 | return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm)); |
289 | } | 288 | } |
289 | /* in1_ref is deprecated in favour of cpu0_vid, remove after 2005-11-11 */ | ||
290 | static DEVICE_ATTR(in1_ref, S_IRUGO, show_vid, NULL); | 290 | static DEVICE_ATTR(in1_ref, S_IRUGO, show_vid, NULL); |
291 | static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); | ||
291 | 292 | ||
292 | static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) | 293 | static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) |
293 | { | 294 | { |
@@ -437,7 +438,9 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind) | |||
437 | device_create_file(&new_client->dev, &dev_attr_temp1_max); | 438 | device_create_file(&new_client->dev, &dev_attr_temp1_max); |
438 | device_create_file(&new_client->dev, &dev_attr_temp2_max); | 439 | device_create_file(&new_client->dev, &dev_attr_temp2_max); |
439 | device_create_file(&new_client->dev, &dev_attr_alarms); | 440 | device_create_file(&new_client->dev, &dev_attr_alarms); |
441 | /* in1_ref is deprecated, remove after 2005-11-11 */ | ||
440 | device_create_file(&new_client->dev, &dev_attr_in1_ref); | 442 | device_create_file(&new_client->dev, &dev_attr_in1_ref); |
443 | device_create_file(&new_client->dev, &dev_attr_cpu0_vid); | ||
441 | device_create_file(&new_client->dev, &dev_attr_vrm); | 444 | device_create_file(&new_client->dev, &dev_attr_vrm); |
442 | 445 | ||
443 | /* Pin 11 is either in4 (+12V) or VID4 */ | 446 | /* Pin 11 is either in4 (+12V) or VID4 */ |
diff --git a/drivers/i2c/chips/adm1026.c b/drivers/i2c/chips/adm1026.c index b15fafe8f111..3c85fe150cd7 100644 --- a/drivers/i2c/chips/adm1026.c +++ b/drivers/i2c/chips/adm1026.c | |||
@@ -23,15 +23,14 @@ | |||
23 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 23 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
24 | */ | 24 | */ |
25 | 25 | ||
26 | #include <linux/config.h> | ||
27 | #include <linux/module.h> | 26 | #include <linux/module.h> |
28 | #include <linux/init.h> | 27 | #include <linux/init.h> |
29 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
30 | #include <linux/jiffies.h> | 29 | #include <linux/jiffies.h> |
31 | #include <linux/i2c.h> | 30 | #include <linux/i2c.h> |
32 | #include <linux/i2c-sensor.h> | 31 | #include <linux/i2c-sensor.h> |
33 | #include <linux/i2c-sysfs.h> | ||
34 | #include <linux/i2c-vid.h> | 32 | #include <linux/i2c-vid.h> |
33 | #include <linux/hwmon-sysfs.h> | ||
35 | 34 | ||
36 | /* Addresses to scan */ | 35 | /* Addresses to scan */ |
37 | static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; | 36 | static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; |
@@ -1225,8 +1224,9 @@ static ssize_t show_vid_reg(struct device *dev, struct device_attribute *attr, c | |||
1225 | struct adm1026_data *data = adm1026_update_device(dev); | 1224 | struct adm1026_data *data = adm1026_update_device(dev); |
1226 | return sprintf(buf,"%d\n", vid_from_reg(data->vid & 0x3f, data->vrm)); | 1225 | return sprintf(buf,"%d\n", vid_from_reg(data->vid & 0x3f, data->vrm)); |
1227 | } | 1226 | } |
1228 | 1227 | /* vid deprecated in favour of cpu0_vid, remove after 2005-11-11 */ | |
1229 | static DEVICE_ATTR(vid, S_IRUGO, show_vid_reg, NULL); | 1228 | static DEVICE_ATTR(vid, S_IRUGO, show_vid_reg, NULL); |
1229 | static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); | ||
1230 | 1230 | ||
1231 | static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) | 1231 | static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) |
1232 | { | 1232 | { |
@@ -1666,7 +1666,9 @@ int adm1026_detect(struct i2c_adapter *adapter, int address, | |||
1666 | device_create_file(&new_client->dev, &dev_attr_temp1_crit_enable); | 1666 | device_create_file(&new_client->dev, &dev_attr_temp1_crit_enable); |
1667 | device_create_file(&new_client->dev, &dev_attr_temp2_crit_enable); | 1667 | device_create_file(&new_client->dev, &dev_attr_temp2_crit_enable); |
1668 | device_create_file(&new_client->dev, &dev_attr_temp3_crit_enable); | 1668 | device_create_file(&new_client->dev, &dev_attr_temp3_crit_enable); |
1669 | /* vid deprecated in favour of cpu0_vid, remove after 2005-11-11 */ | ||
1669 | device_create_file(&new_client->dev, &dev_attr_vid); | 1670 | device_create_file(&new_client->dev, &dev_attr_vid); |
1671 | device_create_file(&new_client->dev, &dev_attr_cpu0_vid); | ||
1670 | device_create_file(&new_client->dev, &dev_attr_vrm); | 1672 | device_create_file(&new_client->dev, &dev_attr_vrm); |
1671 | device_create_file(&new_client->dev, &dev_attr_alarms); | 1673 | device_create_file(&new_client->dev, &dev_attr_alarms); |
1672 | device_create_file(&new_client->dev, &dev_attr_alarm_mask); | 1674 | device_create_file(&new_client->dev, &dev_attr_alarm_mask); |
diff --git a/drivers/i2c/chips/adm1031.c b/drivers/i2c/chips/adm1031.c index 2163dba467c4..9168e983ca1d 100644 --- a/drivers/i2c/chips/adm1031.c +++ b/drivers/i2c/chips/adm1031.c | |||
@@ -440,7 +440,7 @@ pwm_reg(2); | |||
440 | 440 | ||
441 | /* | 441 | /* |
442 | * That function checks the cases where the fan reading is not | 442 | * That function checks the cases where the fan reading is not |
443 | * relevent. It is used to provide 0 as fan reading when the fan is | 443 | * relevant. It is used to provide 0 as fan reading when the fan is |
444 | * not supposed to run | 444 | * not supposed to run |
445 | */ | 445 | */ |
446 | static int trust_fan_readings(struct adm1031_data *data, int chan) | 446 | static int trust_fan_readings(struct adm1031_data *data, int chan) |
diff --git a/drivers/i2c/chips/adm9240.c b/drivers/i2c/chips/adm9240.c new file mode 100644 index 000000000000..5c68e9c311aa --- /dev/null +++ b/drivers/i2c/chips/adm9240.c | |||
@@ -0,0 +1,791 @@ | |||
1 | /* | ||
2 | * adm9240.c Part of lm_sensors, Linux kernel modules for hardware | ||
3 | * monitoring | ||
4 | * | ||
5 | * Copyright (C) 1999 Frodo Looijaard <frodol@dds.nl> | ||
6 | * Philip Edelbrock <phil@netroedge.com> | ||
7 | * Copyright (C) 2003 Michiel Rook <michiel@grendelproject.nl> | ||
8 | * Copyright (C) 2005 Grant Coady <gcoady@gmail.com> with valuable | ||
9 | * guidance from Jean Delvare | ||
10 | * | ||
11 | * Driver supports Analog Devices ADM9240 | ||
12 | * Dallas Semiconductor DS1780 | ||
13 | * National Semiconductor LM81 | ||
14 | * | ||
15 | * ADM9240 is the reference, DS1780 and LM81 are register compatibles | ||
16 | * | ||
17 | * Voltage Six inputs are scaled by chip, VID also reported | ||
18 | * Temperature Chip temperature to 0.5'C, maximum and max_hysteris | ||
19 | * Fans 2 fans, low speed alarm, automatic fan clock divider | ||
20 | * Alarms 16-bit map of active alarms | ||
21 | * Analog Out 0..1250 mV output | ||
22 | * | ||
23 | * Chassis Intrusion: clear CI latch with 'echo 1 > chassis_clear' | ||
24 | * | ||
25 | * Test hardware: Intel SE440BX-2 desktop motherboard --Grant | ||
26 | * | ||
27 | * LM81 extended temp reading not implemented | ||
28 | * | ||
29 | * This program is free software; you can redistribute it and/or modify | ||
30 | * it under the terms of the GNU General Public License as published by | ||
31 | * the Free Software Foundation; either version 2 of the License, or | ||
32 | * (at your option) any later version. | ||
33 | * | ||
34 | * This program is distributed in the hope that it will be useful, | ||
35 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
36 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
37 | * GNU General Public License for more details. | ||
38 | * | ||
39 | * You should have received a copy of the GNU General Public License | ||
40 | * along with this program; if not, write to the Free Software | ||
41 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
42 | */ | ||
43 | |||
44 | #include <linux/init.h> | ||
45 | #include <linux/module.h> | ||
46 | #include <linux/slab.h> | ||
47 | #include <linux/i2c.h> | ||
48 | #include <linux/i2c-sensor.h> | ||
49 | #include <linux/i2c-vid.h> | ||
50 | |||
51 | /* Addresses to scan */ | ||
52 | static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f, | ||
53 | I2C_CLIENT_END }; | ||
54 | |||
55 | static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; | ||
56 | |||
57 | /* Insmod parameters */ | ||
58 | SENSORS_INSMOD_3(adm9240, ds1780, lm81); | ||
59 | |||
60 | /* ADM9240 registers */ | ||
61 | #define ADM9240_REG_MAN_ID 0x3e | ||
62 | #define ADM9240_REG_DIE_REV 0x3f | ||
63 | #define ADM9240_REG_CONFIG 0x40 | ||
64 | |||
65 | #define ADM9240_REG_IN(nr) (0x20 + (nr)) /* 0..5 */ | ||
66 | #define ADM9240_REG_IN_MAX(nr) (0x2b + (nr) * 2) | ||
67 | #define ADM9240_REG_IN_MIN(nr) (0x2c + (nr) * 2) | ||
68 | #define ADM9240_REG_FAN(nr) (0x28 + (nr)) /* 0..1 */ | ||
69 | #define ADM9240_REG_FAN_MIN(nr) (0x3b + (nr)) | ||
70 | #define ADM9240_REG_INT(nr) (0x41 + (nr)) | ||
71 | #define ADM9240_REG_INT_MASK(nr) (0x43 + (nr)) | ||
72 | #define ADM9240_REG_TEMP 0x27 | ||
73 | #define ADM9240_REG_TEMP_HIGH 0x39 | ||
74 | #define ADM9240_REG_TEMP_HYST 0x3a | ||
75 | #define ADM9240_REG_ANALOG_OUT 0x19 | ||
76 | #define ADM9240_REG_CHASSIS_CLEAR 0x46 | ||
77 | #define ADM9240_REG_VID_FAN_DIV 0x47 | ||
78 | #define ADM9240_REG_I2C_ADDR 0x48 | ||
79 | #define ADM9240_REG_VID4 0x49 | ||
80 | #define ADM9240_REG_TEMP_CONF 0x4b | ||
81 | |||
82 | /* generalised scaling with integer rounding */ | ||
83 | static inline int SCALE(long val, int mul, int div) | ||
84 | { | ||
85 | if (val < 0) | ||
86 | return (val * mul - div / 2) / div; | ||
87 | else | ||
88 | return (val * mul + div / 2) / div; | ||
89 | } | ||
90 | |||
91 | /* adm9240 internally scales voltage measurements */ | ||
92 | static const u16 nom_mv[] = { 2500, 2700, 3300, 5000, 12000, 2700 }; | ||
93 | |||
94 | static inline unsigned int IN_FROM_REG(u8 reg, int n) | ||
95 | { | ||
96 | return SCALE(reg, nom_mv[n], 192); | ||
97 | } | ||
98 | |||
99 | static inline u8 IN_TO_REG(unsigned long val, int n) | ||
100 | { | ||
101 | return SENSORS_LIMIT(SCALE(val, 192, nom_mv[n]), 0, 255); | ||
102 | } | ||
103 | |||
104 | /* temperature range: -40..125, 127 disables temperature alarm */ | ||
105 | static inline s8 TEMP_TO_REG(long val) | ||
106 | { | ||
107 | return SENSORS_LIMIT(SCALE(val, 1, 1000), -40, 127); | ||
108 | } | ||
109 | |||
110 | /* two fans, each with low fan speed limit */ | ||
111 | static inline unsigned int FAN_FROM_REG(u8 reg, u8 div) | ||
112 | { | ||
113 | if (!reg) /* error */ | ||
114 | return -1; | ||
115 | |||
116 | if (reg == 255) | ||
117 | return 0; | ||
118 | |||
119 | return SCALE(1350000, 1, reg * div); | ||
120 | } | ||
121 | |||
122 | /* analog out 0..1250mV */ | ||
123 | static inline u8 AOUT_TO_REG(unsigned long val) | ||
124 | { | ||
125 | return SENSORS_LIMIT(SCALE(val, 255, 1250), 0, 255); | ||
126 | } | ||
127 | |||
128 | static inline unsigned int AOUT_FROM_REG(u8 reg) | ||
129 | { | ||
130 | return SCALE(reg, 1250, 255); | ||
131 | } | ||
132 | |||
133 | static int adm9240_attach_adapter(struct i2c_adapter *adapter); | ||
134 | static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind); | ||
135 | static void adm9240_init_client(struct i2c_client *client); | ||
136 | static int adm9240_detach_client(struct i2c_client *client); | ||
137 | static struct adm9240_data *adm9240_update_device(struct device *dev); | ||
138 | |||
139 | /* driver data */ | ||
140 | static struct i2c_driver adm9240_driver = { | ||
141 | .owner = THIS_MODULE, | ||
142 | .name = "adm9240", | ||
143 | .id = I2C_DRIVERID_ADM9240, | ||
144 | .flags = I2C_DF_NOTIFY, | ||
145 | .attach_adapter = adm9240_attach_adapter, | ||
146 | .detach_client = adm9240_detach_client, | ||
147 | }; | ||
148 | |||
149 | /* per client data */ | ||
150 | struct adm9240_data { | ||
151 | enum chips type; | ||
152 | struct i2c_client client; | ||
153 | struct semaphore update_lock; | ||
154 | char valid; | ||
155 | unsigned long last_updated_measure; | ||
156 | unsigned long last_updated_config; | ||
157 | |||
158 | u8 in[6]; /* ro in0_input */ | ||
159 | u8 in_max[6]; /* rw in0_max */ | ||
160 | u8 in_min[6]; /* rw in0_min */ | ||
161 | u8 fan[2]; /* ro fan1_input */ | ||
162 | u8 fan_min[2]; /* rw fan1_min */ | ||
163 | u8 fan_div[2]; /* rw fan1_div, read-only accessor */ | ||
164 | s16 temp; /* ro temp1_input, 9-bit sign-extended */ | ||
165 | s8 temp_high; /* rw temp1_max */ | ||
166 | s8 temp_hyst; /* rw temp1_max_hyst */ | ||
167 | u16 alarms; /* ro alarms */ | ||
168 | u8 aout; /* rw aout_output */ | ||
169 | u8 vid; /* ro vid */ | ||
170 | u8 vrm; /* -- vrm set on startup, no accessor */ | ||
171 | }; | ||
172 | |||
173 | /* i2c byte read/write interface */ | ||
174 | static int adm9240_read_value(struct i2c_client *client, u8 reg) | ||
175 | { | ||
176 | return i2c_smbus_read_byte_data(client, reg); | ||
177 | } | ||
178 | |||
179 | static int adm9240_write_value(struct i2c_client *client, u8 reg, u8 value) | ||
180 | { | ||
181 | return i2c_smbus_write_byte_data(client, reg, value); | ||
182 | } | ||
183 | |||
184 | /*** sysfs accessors ***/ | ||
185 | |||
186 | /* temperature */ | ||
187 | #define show_temp(value, scale) \ | ||
188 | static ssize_t show_##value(struct device *dev, \ | ||
189 | struct device_attribute *attr, \ | ||
190 | char *buf) \ | ||
191 | { \ | ||
192 | struct adm9240_data *data = adm9240_update_device(dev); \ | ||
193 | return sprintf(buf, "%d\n", data->value * scale); \ | ||
194 | } | ||
195 | show_temp(temp_high, 1000); | ||
196 | show_temp(temp_hyst, 1000); | ||
197 | show_temp(temp, 500); /* 0.5'C per bit */ | ||
198 | |||
199 | #define set_temp(value, reg) \ | ||
200 | static ssize_t set_##value(struct device *dev, \ | ||
201 | struct device_attribute *attr, \ | ||
202 | const char *buf, size_t count) \ | ||
203 | { \ | ||
204 | struct i2c_client *client = to_i2c_client(dev); \ | ||
205 | struct adm9240_data *data = adm9240_update_device(dev); \ | ||
206 | long temp = simple_strtoul(buf, NULL, 10); \ | ||
207 | \ | ||
208 | down(&data->update_lock); \ | ||
209 | data->value = TEMP_TO_REG(temp); \ | ||
210 | adm9240_write_value(client, reg, data->value); \ | ||
211 | up(&data->update_lock); \ | ||
212 | return count; \ | ||
213 | } | ||
214 | |||
215 | set_temp(temp_high, ADM9240_REG_TEMP_HIGH); | ||
216 | set_temp(temp_hyst, ADM9240_REG_TEMP_HYST); | ||
217 | |||
218 | static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, | ||
219 | show_temp_high, set_temp_high); | ||
220 | static DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, | ||
221 | show_temp_hyst, set_temp_hyst); | ||
222 | static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL); | ||
223 | |||
224 | /* voltage */ | ||
225 | static ssize_t show_in(struct device *dev, char *buf, int nr) | ||
226 | { | ||
227 | struct adm9240_data *data = adm9240_update_device(dev); | ||
228 | return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr], nr)); | ||
229 | } | ||
230 | |||
231 | static ssize_t show_in_min(struct device *dev, char *buf, int nr) | ||
232 | { | ||
233 | struct adm9240_data *data = adm9240_update_device(dev); | ||
234 | return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr], nr)); | ||
235 | } | ||
236 | |||
237 | static ssize_t show_in_max(struct device *dev, char *buf, int nr) | ||
238 | { | ||
239 | struct adm9240_data *data = adm9240_update_device(dev); | ||
240 | return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr], nr)); | ||
241 | } | ||
242 | |||
243 | static ssize_t set_in_min(struct device *dev, const char *buf, | ||
244 | size_t count, int nr) | ||
245 | { | ||
246 | struct i2c_client *client = to_i2c_client(dev); | ||
247 | struct adm9240_data *data = i2c_get_clientdata(client); | ||
248 | unsigned long val = simple_strtoul(buf, NULL, 10); | ||
249 | |||
250 | down(&data->update_lock); | ||
251 | data->in_min[nr] = IN_TO_REG(val, nr); | ||
252 | adm9240_write_value(client, ADM9240_REG_IN_MIN(nr), data->in_min[nr]); | ||
253 | up(&data->update_lock); | ||
254 | return count; | ||
255 | } | ||
256 | |||
257 | static ssize_t set_in_max(struct device *dev, const char *buf, | ||
258 | size_t count, int nr) | ||
259 | { | ||
260 | struct i2c_client *client = to_i2c_client(dev); | ||
261 | struct adm9240_data *data = i2c_get_clientdata(client); | ||
262 | unsigned long val = simple_strtoul(buf, NULL, 10); | ||
263 | |||
264 | down(&data->update_lock); | ||
265 | data->in_max[nr] = IN_TO_REG(val, nr); | ||
266 | adm9240_write_value(client, ADM9240_REG_IN_MAX(nr), data->in_max[nr]); | ||
267 | up(&data->update_lock); | ||
268 | return count; | ||
269 | } | ||
270 | |||
271 | #define show_in_offset(offset) \ | ||
272 | static ssize_t show_in##offset(struct device *dev, \ | ||
273 | struct device_attribute *attr, \ | ||
274 | char *buf) \ | ||
275 | { \ | ||
276 | return show_in(dev, buf, offset); \ | ||
277 | } \ | ||
278 | static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL); \ | ||
279 | static ssize_t show_in##offset##_min(struct device *dev, \ | ||
280 | struct device_attribute *attr, \ | ||
281 | char *buf) \ | ||
282 | { \ | ||
283 | return show_in_min(dev, buf, offset); \ | ||
284 | } \ | ||
285 | static ssize_t show_in##offset##_max(struct device *dev, \ | ||
286 | struct device_attribute *attr, \ | ||
287 | char *buf) \ | ||
288 | { \ | ||
289 | return show_in_max(dev, buf, offset); \ | ||
290 | } \ | ||
291 | static ssize_t \ | ||
292 | set_in##offset##_min(struct device *dev, \ | ||
293 | struct device_attribute *attr, const char *buf, \ | ||
294 | size_t count) \ | ||
295 | { \ | ||
296 | return set_in_min(dev, buf, count, offset); \ | ||
297 | } \ | ||
298 | static ssize_t \ | ||
299 | set_in##offset##_max(struct device *dev, \ | ||
300 | struct device_attribute *attr, const char *buf, \ | ||
301 | size_t count) \ | ||
302 | { \ | ||
303 | return set_in_max(dev, buf, count, offset); \ | ||
304 | } \ | ||
305 | static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ | ||
306 | show_in##offset##_min, set_in##offset##_min); \ | ||
307 | static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ | ||
308 | show_in##offset##_max, set_in##offset##_max); | ||
309 | |||
310 | show_in_offset(0); | ||
311 | show_in_offset(1); | ||
312 | show_in_offset(2); | ||
313 | show_in_offset(3); | ||
314 | show_in_offset(4); | ||
315 | show_in_offset(5); | ||
316 | |||
317 | /* fans */ | ||
318 | static ssize_t show_fan(struct device *dev, char *buf, int nr) | ||
319 | { | ||
320 | struct adm9240_data *data = adm9240_update_device(dev); | ||
321 | return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], | ||
322 | 1 << data->fan_div[nr])); | ||
323 | } | ||
324 | |||
325 | static ssize_t show_fan_min(struct device *dev, char *buf, int nr) | ||
326 | { | ||
327 | struct adm9240_data *data = adm9240_update_device(dev); | ||
328 | return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr], | ||
329 | 1 << data->fan_div[nr])); | ||
330 | } | ||
331 | |||
332 | static ssize_t show_fan_div(struct device *dev, char *buf, int nr) | ||
333 | { | ||
334 | struct adm9240_data *data = adm9240_update_device(dev); | ||
335 | return sprintf(buf, "%d\n", 1 << data->fan_div[nr]); | ||
336 | } | ||
337 | |||
338 | /* write new fan div, callers must hold data->update_lock */ | ||
339 | static void adm9240_write_fan_div(struct i2c_client *client, int nr, | ||
340 | u8 fan_div) | ||
341 | { | ||
342 | u8 reg, old, shift = (nr + 2) * 2; | ||
343 | |||
344 | reg = adm9240_read_value(client, ADM9240_REG_VID_FAN_DIV); | ||
345 | old = (reg >> shift) & 3; | ||
346 | reg &= ~(3 << shift); | ||
347 | reg |= (fan_div << shift); | ||
348 | adm9240_write_value(client, ADM9240_REG_VID_FAN_DIV, reg); | ||
349 | dev_dbg(&client->dev, "fan%d clock divider changed from %u " | ||
350 | "to %u\n", nr + 1, 1 << old, 1 << fan_div); | ||
351 | } | ||
352 | |||
353 | /* | ||
354 | * set fan speed low limit: | ||
355 | * | ||
356 | * - value is zero: disable fan speed low limit alarm | ||
357 | * | ||
358 | * - value is below fan speed measurement range: enable fan speed low | ||
359 | * limit alarm to be asserted while fan speed too slow to measure | ||
360 | * | ||
361 | * - otherwise: select fan clock divider to suit fan speed low limit, | ||
362 | * measurement code may adjust registers to ensure fan speed reading | ||
363 | */ | ||
364 | static ssize_t set_fan_min(struct device *dev, const char *buf, | ||
365 | size_t count, int nr) | ||
366 | { | ||
367 | struct i2c_client *client = to_i2c_client(dev); | ||
368 | struct adm9240_data *data = i2c_get_clientdata(client); | ||
369 | unsigned long val = simple_strtoul(buf, NULL, 10); | ||
370 | u8 new_div; | ||
371 | |||
372 | down(&data->update_lock); | ||
373 | |||
374 | if (!val) { | ||
375 | data->fan_min[nr] = 255; | ||
376 | new_div = data->fan_div[nr]; | ||
377 | |||
378 | dev_dbg(&client->dev, "fan%u low limit set disabled\n", | ||
379 | nr + 1); | ||
380 | |||
381 | } else if (val < 1350000 / (8 * 254)) { | ||
382 | new_div = 3; | ||
383 | data->fan_min[nr] = 254; | ||
384 | |||
385 | dev_dbg(&client->dev, "fan%u low limit set minimum %u\n", | ||
386 | nr + 1, FAN_FROM_REG(254, 1 << new_div)); | ||
387 | |||
388 | } else { | ||
389 | unsigned int new_min = 1350000 / val; | ||
390 | |||
391 | new_div = 0; | ||
392 | while (new_min > 192 && new_div < 3) { | ||
393 | new_div++; | ||
394 | new_min /= 2; | ||
395 | } | ||
396 | if (!new_min) /* keep > 0 */ | ||
397 | new_min++; | ||
398 | |||
399 | data->fan_min[nr] = new_min; | ||
400 | |||
401 | dev_dbg(&client->dev, "fan%u low limit set fan speed %u\n", | ||
402 | nr + 1, FAN_FROM_REG(new_min, 1 << new_div)); | ||
403 | } | ||
404 | |||
405 | if (new_div != data->fan_div[nr]) { | ||
406 | data->fan_div[nr] = new_div; | ||
407 | adm9240_write_fan_div(client, nr, new_div); | ||
408 | } | ||
409 | adm9240_write_value(client, ADM9240_REG_FAN_MIN(nr), | ||
410 | data->fan_min[nr]); | ||
411 | |||
412 | up(&data->update_lock); | ||
413 | return count; | ||
414 | } | ||
415 | |||
416 | #define show_fan_offset(offset) \ | ||
417 | static ssize_t show_fan_##offset (struct device *dev, \ | ||
418 | struct device_attribute *attr, \ | ||
419 | char *buf) \ | ||
420 | { \ | ||
421 | return show_fan(dev, buf, offset - 1); \ | ||
422 | } \ | ||
423 | static ssize_t show_fan_##offset##_div (struct device *dev, \ | ||
424 | struct device_attribute *attr, \ | ||
425 | char *buf) \ | ||
426 | { \ | ||
427 | return show_fan_div(dev, buf, offset - 1); \ | ||
428 | } \ | ||
429 | static ssize_t show_fan_##offset##_min (struct device *dev, \ | ||
430 | struct device_attribute *attr, \ | ||
431 | char *buf) \ | ||
432 | { \ | ||
433 | return show_fan_min(dev, buf, offset - 1); \ | ||
434 | } \ | ||
435 | static ssize_t set_fan_##offset##_min (struct device *dev, \ | ||
436 | struct device_attribute *attr, \ | ||
437 | const char *buf, size_t count) \ | ||
438 | { \ | ||
439 | return set_fan_min(dev, buf, count, offset - 1); \ | ||
440 | } \ | ||
441 | static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ | ||
442 | show_fan_##offset, NULL); \ | ||
443 | static DEVICE_ATTR(fan##offset##_div, S_IRUGO, \ | ||
444 | show_fan_##offset##_div, NULL); \ | ||
445 | static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ | ||
446 | show_fan_##offset##_min, set_fan_##offset##_min); | ||
447 | |||
448 | show_fan_offset(1); | ||
449 | show_fan_offset(2); | ||
450 | |||
451 | /* alarms */ | ||
452 | static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) | ||
453 | { | ||
454 | struct adm9240_data *data = adm9240_update_device(dev); | ||
455 | return sprintf(buf, "%u\n", data->alarms); | ||
456 | } | ||
457 | static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); | ||
458 | |||
459 | /* vid */ | ||
460 | static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) | ||
461 | { | ||
462 | struct adm9240_data *data = adm9240_update_device(dev); | ||
463 | return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); | ||
464 | } | ||
465 | static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); | ||
466 | |||
467 | /* analog output */ | ||
468 | static ssize_t show_aout(struct device *dev, struct device_attribute *attr, char *buf) | ||
469 | { | ||
470 | struct adm9240_data *data = adm9240_update_device(dev); | ||
471 | return sprintf(buf, "%d\n", AOUT_FROM_REG(data->aout)); | ||
472 | } | ||
473 | |||
474 | static ssize_t set_aout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | ||
475 | { | ||
476 | struct i2c_client *client = to_i2c_client(dev); | ||
477 | struct adm9240_data *data = i2c_get_clientdata(client); | ||
478 | unsigned long val = simple_strtol(buf, NULL, 10); | ||
479 | |||
480 | down(&data->update_lock); | ||
481 | data->aout = AOUT_TO_REG(val); | ||
482 | adm9240_write_value(client, ADM9240_REG_ANALOG_OUT, data->aout); | ||
483 | up(&data->update_lock); | ||
484 | return count; | ||
485 | } | ||
486 | static DEVICE_ATTR(aout_output, S_IRUGO | S_IWUSR, show_aout, set_aout); | ||
487 | |||
488 | /* chassis_clear */ | ||
489 | static ssize_t chassis_clear(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | ||
490 | { | ||
491 | struct i2c_client *client = to_i2c_client(dev); | ||
492 | unsigned long val = simple_strtol(buf, NULL, 10); | ||
493 | |||
494 | if (val == 1) { | ||
495 | adm9240_write_value(client, ADM9240_REG_CHASSIS_CLEAR, 0x80); | ||
496 | dev_dbg(&client->dev, "chassis intrusion latch cleared\n"); | ||
497 | } | ||
498 | return count; | ||
499 | } | ||
500 | static DEVICE_ATTR(chassis_clear, S_IWUSR, NULL, chassis_clear); | ||
501 | |||
502 | |||
503 | /*** sensor chip detect and driver install ***/ | ||
504 | |||
505 | static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind) | ||
506 | { | ||
507 | struct i2c_client *new_client; | ||
508 | struct adm9240_data *data; | ||
509 | int err = 0; | ||
510 | const char *name = ""; | ||
511 | u8 man_id, die_rev; | ||
512 | |||
513 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | ||
514 | goto exit; | ||
515 | |||
516 | if (!(data = kmalloc(sizeof(struct adm9240_data), GFP_KERNEL))) { | ||
517 | err = -ENOMEM; | ||
518 | goto exit; | ||
519 | } | ||
520 | memset(data, 0, sizeof(struct adm9240_data)); | ||
521 | |||
522 | new_client = &data->client; | ||
523 | i2c_set_clientdata(new_client, data); | ||
524 | new_client->addr = address; | ||
525 | new_client->adapter = adapter; | ||
526 | new_client->driver = &adm9240_driver; | ||
527 | new_client->flags = 0; | ||
528 | |||
529 | if (kind == 0) { | ||
530 | kind = adm9240; | ||
531 | } | ||
532 | |||
533 | if (kind < 0) { | ||
534 | |||
535 | /* verify chip: reg address should match i2c address */ | ||
536 | if (adm9240_read_value(new_client, ADM9240_REG_I2C_ADDR) | ||
537 | != address) { | ||
538 | dev_err(&adapter->dev, "detect fail: address match, " | ||
539 | "0x%02x\n", address); | ||
540 | goto exit_free; | ||
541 | } | ||
542 | |||
543 | /* check known chip manufacturer */ | ||
544 | man_id = adm9240_read_value(new_client, ADM9240_REG_MAN_ID); | ||
545 | |||
546 | if (man_id == 0x23) { | ||
547 | kind = adm9240; | ||
548 | } else if (man_id == 0xda) { | ||
549 | kind = ds1780; | ||
550 | } else if (man_id == 0x01) { | ||
551 | kind = lm81; | ||
552 | } else { | ||
553 | dev_err(&adapter->dev, "detect fail: unknown manuf, " | ||
554 | "0x%02x\n", man_id); | ||
555 | goto exit_free; | ||
556 | } | ||
557 | |||
558 | /* successful detect, print chip info */ | ||
559 | die_rev = adm9240_read_value(new_client, ADM9240_REG_DIE_REV); | ||
560 | dev_info(&adapter->dev, "found %s revision %u\n", | ||
561 | man_id == 0x23 ? "ADM9240" : | ||
562 | man_id == 0xda ? "DS1780" : "LM81", die_rev); | ||
563 | } | ||
564 | |||
565 | /* either forced or detected chip kind */ | ||
566 | if (kind == adm9240) { | ||
567 | name = "adm9240"; | ||
568 | } else if (kind == ds1780) { | ||
569 | name = "ds1780"; | ||
570 | } else if (kind == lm81) { | ||
571 | name = "lm81"; | ||
572 | } | ||
573 | |||
574 | /* fill in the remaining client fields and attach */ | ||
575 | strlcpy(new_client->name, name, I2C_NAME_SIZE); | ||
576 | data->type = kind; | ||
577 | init_MUTEX(&data->update_lock); | ||
578 | |||
579 | if ((err = i2c_attach_client(new_client))) | ||
580 | goto exit_free; | ||
581 | |||
582 | adm9240_init_client(new_client); | ||
583 | |||
584 | /* populate sysfs filesystem */ | ||
585 | device_create_file(&new_client->dev, &dev_attr_in0_input); | ||
586 | device_create_file(&new_client->dev, &dev_attr_in0_min); | ||
587 | device_create_file(&new_client->dev, &dev_attr_in0_max); | ||
588 | device_create_file(&new_client->dev, &dev_attr_in1_input); | ||
589 | device_create_file(&new_client->dev, &dev_attr_in1_min); | ||
590 | device_create_file(&new_client->dev, &dev_attr_in1_max); | ||
591 | device_create_file(&new_client->dev, &dev_attr_in2_input); | ||
592 | device_create_file(&new_client->dev, &dev_attr_in2_min); | ||
593 | device_create_file(&new_client->dev, &dev_attr_in2_max); | ||
594 | device_create_file(&new_client->dev, &dev_attr_in3_input); | ||
595 | device_create_file(&new_client->dev, &dev_attr_in3_min); | ||
596 | device_create_file(&new_client->dev, &dev_attr_in3_max); | ||
597 | device_create_file(&new_client->dev, &dev_attr_in4_input); | ||
598 | device_create_file(&new_client->dev, &dev_attr_in4_min); | ||
599 | device_create_file(&new_client->dev, &dev_attr_in4_max); | ||
600 | device_create_file(&new_client->dev, &dev_attr_in5_input); | ||
601 | device_create_file(&new_client->dev, &dev_attr_in5_min); | ||
602 | device_create_file(&new_client->dev, &dev_attr_in5_max); | ||
603 | device_create_file(&new_client->dev, &dev_attr_temp1_max); | ||
604 | device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); | ||
605 | device_create_file(&new_client->dev, &dev_attr_temp1_input); | ||
606 | device_create_file(&new_client->dev, &dev_attr_fan1_input); | ||
607 | device_create_file(&new_client->dev, &dev_attr_fan1_div); | ||
608 | device_create_file(&new_client->dev, &dev_attr_fan1_min); | ||
609 | device_create_file(&new_client->dev, &dev_attr_fan2_input); | ||
610 | device_create_file(&new_client->dev, &dev_attr_fan2_div); | ||
611 | device_create_file(&new_client->dev, &dev_attr_fan2_min); | ||
612 | device_create_file(&new_client->dev, &dev_attr_alarms); | ||
613 | device_create_file(&new_client->dev, &dev_attr_aout_output); | ||
614 | device_create_file(&new_client->dev, &dev_attr_chassis_clear); | ||
615 | device_create_file(&new_client->dev, &dev_attr_cpu0_vid); | ||
616 | |||
617 | return 0; | ||
618 | exit_free: | ||
619 | kfree(new_client); | ||
620 | exit: | ||
621 | return err; | ||
622 | } | ||
623 | |||
624 | static int adm9240_attach_adapter(struct i2c_adapter *adapter) | ||
625 | { | ||
626 | if (!(adapter->class & I2C_CLASS_HWMON)) | ||
627 | return 0; | ||
628 | return i2c_detect(adapter, &addr_data, adm9240_detect); | ||
629 | } | ||
630 | |||
631 | static int adm9240_detach_client(struct i2c_client *client) | ||
632 | { | ||
633 | int err; | ||
634 | |||
635 | if ((err = i2c_detach_client(client))) { | ||
636 | dev_err(&client->dev, "Client deregistration failed, " | ||
637 | "client not detached.\n"); | ||
638 | return err; | ||
639 | } | ||
640 | |||
641 | kfree(i2c_get_clientdata(client)); | ||
642 | return 0; | ||
643 | } | ||
644 | |||
645 | static void adm9240_init_client(struct i2c_client *client) | ||
646 | { | ||
647 | struct adm9240_data *data = i2c_get_clientdata(client); | ||
648 | u8 conf = adm9240_read_value(client, ADM9240_REG_CONFIG); | ||
649 | u8 mode = adm9240_read_value(client, ADM9240_REG_TEMP_CONF) & 3; | ||
650 | |||
651 | data->vrm = i2c_which_vrm(); /* need this to report vid as mV */ | ||
652 | |||
653 | dev_info(&client->dev, "Using VRM: %d.%d\n", data->vrm / 10, | ||
654 | data->vrm % 10); | ||
655 | |||
656 | if (conf & 1) { /* measurement cycle running: report state */ | ||
657 | |||
658 | dev_info(&client->dev, "status: config 0x%02x mode %u\n", | ||
659 | conf, mode); | ||
660 | |||
661 | } else { /* cold start: open limits before starting chip */ | ||
662 | int i; | ||
663 | |||
664 | for (i = 0; i < 6; i++) | ||
665 | { | ||
666 | adm9240_write_value(client, | ||
667 | ADM9240_REG_IN_MIN(i), 0); | ||
668 | adm9240_write_value(client, | ||
669 | ADM9240_REG_IN_MAX(i), 255); | ||
670 | } | ||
671 | adm9240_write_value(client, ADM9240_REG_FAN_MIN(0), 255); | ||
672 | adm9240_write_value(client, ADM9240_REG_FAN_MIN(1), 255); | ||
673 | adm9240_write_value(client, ADM9240_REG_TEMP_HIGH, 127); | ||
674 | adm9240_write_value(client, ADM9240_REG_TEMP_HYST, 127); | ||
675 | |||
676 | /* start measurement cycle */ | ||
677 | adm9240_write_value(client, ADM9240_REG_CONFIG, 1); | ||
678 | |||
679 | dev_info(&client->dev, "cold start: config was 0x%02x " | ||
680 | "mode %u\n", conf, mode); | ||
681 | } | ||
682 | } | ||
683 | |||
684 | static struct adm9240_data *adm9240_update_device(struct device *dev) | ||
685 | { | ||
686 | struct i2c_client *client = to_i2c_client(dev); | ||
687 | struct adm9240_data *data = i2c_get_clientdata(client); | ||
688 | int i; | ||
689 | |||
690 | down(&data->update_lock); | ||
691 | |||
692 | /* minimum measurement cycle: 1.75 seconds */ | ||
693 | if (time_after(jiffies, data->last_updated_measure + (HZ * 7 / 4)) | ||
694 | || !data->valid) { | ||
695 | |||
696 | for (i = 0; i < 6; i++) /* read voltages */ | ||
697 | { | ||
698 | data->in[i] = adm9240_read_value(client, | ||
699 | ADM9240_REG_IN(i)); | ||
700 | } | ||
701 | data->alarms = adm9240_read_value(client, | ||
702 | ADM9240_REG_INT(0)) | | ||
703 | adm9240_read_value(client, | ||
704 | ADM9240_REG_INT(1)) << 8; | ||
705 | |||
706 | /* read temperature: assume temperature changes less than | ||
707 | * 0.5'C per two measurement cycles thus ignore possible | ||
708 | * but unlikely aliasing error on lsb reading. --Grant */ | ||
709 | data->temp = ((adm9240_read_value(client, | ||
710 | ADM9240_REG_TEMP) << 8) | | ||
711 | adm9240_read_value(client, | ||
712 | ADM9240_REG_TEMP_CONF)) / 128; | ||
713 | |||
714 | for (i = 0; i < 2; i++) /* read fans */ | ||
715 | { | ||
716 | data->fan[i] = adm9240_read_value(client, | ||
717 | ADM9240_REG_FAN(i)); | ||
718 | |||
719 | /* adjust fan clock divider on overflow */ | ||
720 | if (data->valid && data->fan[i] == 255 && | ||
721 | data->fan_div[i] < 3) { | ||
722 | |||
723 | adm9240_write_fan_div(client, i, | ||
724 | ++data->fan_div[i]); | ||
725 | |||
726 | /* adjust fan_min if active, but not to 0 */ | ||
727 | if (data->fan_min[i] < 255 && | ||
728 | data->fan_min[i] >= 2) | ||
729 | data->fan_min[i] /= 2; | ||
730 | } | ||
731 | } | ||
732 | data->last_updated_measure = jiffies; | ||
733 | } | ||
734 | |||
735 | /* minimum config reading cycle: 300 seconds */ | ||
736 | if (time_after(jiffies, data->last_updated_config + (HZ * 300)) | ||
737 | || !data->valid) { | ||
738 | |||
739 | for (i = 0; i < 6; i++) | ||
740 | { | ||
741 | data->in_min[i] = adm9240_read_value(client, | ||
742 | ADM9240_REG_IN_MIN(i)); | ||
743 | data->in_max[i] = adm9240_read_value(client, | ||
744 | ADM9240_REG_IN_MAX(i)); | ||
745 | } | ||
746 | for (i = 0; i < 2; i++) | ||
747 | { | ||
748 | data->fan_min[i] = adm9240_read_value(client, | ||
749 | ADM9240_REG_FAN_MIN(i)); | ||
750 | } | ||
751 | data->temp_high = adm9240_read_value(client, | ||
752 | ADM9240_REG_TEMP_HIGH); | ||
753 | data->temp_hyst = adm9240_read_value(client, | ||
754 | ADM9240_REG_TEMP_HYST); | ||
755 | |||
756 | /* read fan divs and 5-bit VID */ | ||
757 | i = adm9240_read_value(client, ADM9240_REG_VID_FAN_DIV); | ||
758 | data->fan_div[0] = (i >> 4) & 3; | ||
759 | data->fan_div[1] = (i >> 6) & 3; | ||
760 | data->vid = i & 0x0f; | ||
761 | data->vid |= (adm9240_read_value(client, | ||
762 | ADM9240_REG_VID4) & 1) << 4; | ||
763 | /* read analog out */ | ||
764 | data->aout = adm9240_read_value(client, | ||
765 | ADM9240_REG_ANALOG_OUT); | ||
766 | |||
767 | data->last_updated_config = jiffies; | ||
768 | data->valid = 1; | ||
769 | } | ||
770 | up(&data->update_lock); | ||
771 | return data; | ||
772 | } | ||
773 | |||
774 | static int __init sensors_adm9240_init(void) | ||
775 | { | ||
776 | return i2c_add_driver(&adm9240_driver); | ||
777 | } | ||
778 | |||
779 | static void __exit sensors_adm9240_exit(void) | ||
780 | { | ||
781 | i2c_del_driver(&adm9240_driver); | ||
782 | } | ||
783 | |||
784 | MODULE_AUTHOR("Michiel Rook <michiel@grendelproject.nl>, " | ||
785 | "Grant Coady <gcoady@gmail.com> and others"); | ||
786 | MODULE_DESCRIPTION("ADM9240/DS1780/LM81 driver"); | ||
787 | MODULE_LICENSE("GPL"); | ||
788 | |||
789 | module_init(sensors_adm9240_init); | ||
790 | module_exit(sensors_adm9240_exit); | ||
791 | |||
diff --git a/drivers/i2c/chips/asb100.c b/drivers/i2c/chips/asb100.c index 4a47b4493e34..70d996d6fe0a 100644 --- a/drivers/i2c/chips/asb100.c +++ b/drivers/i2c/chips/asb100.c | |||
@@ -42,6 +42,7 @@ | |||
42 | #include <linux/i2c-sensor.h> | 42 | #include <linux/i2c-sensor.h> |
43 | #include <linux/i2c-vid.h> | 43 | #include <linux/i2c-vid.h> |
44 | #include <linux/init.h> | 44 | #include <linux/init.h> |
45 | #include <linux/jiffies.h> | ||
45 | #include "lm75.h" | 46 | #include "lm75.h" |
46 | 47 | ||
47 | /* | 48 | /* |
@@ -168,8 +169,6 @@ static int ASB100_PWM_FROM_REG(u8 reg) | |||
168 | return reg * 16; | 169 | return reg * 16; |
169 | } | 170 | } |
170 | 171 | ||
171 | #define ALARMS_FROM_REG(val) (val) | ||
172 | |||
173 | #define DIV_FROM_REG(val) (1 << (val)) | 172 | #define DIV_FROM_REG(val) (1 << (val)) |
174 | 173 | ||
175 | /* FAN DIV: 1, 2, 4, or 8 (defaults to 2) | 174 | /* FAN DIV: 1, 2, 4, or 8 (defaults to 2) |
@@ -556,7 +555,7 @@ device_create_file(&client->dev, &dev_attr_vrm); | |||
556 | static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) | 555 | static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) |
557 | { | 556 | { |
558 | struct asb100_data *data = asb100_update_device(dev); | 557 | struct asb100_data *data = asb100_update_device(dev); |
559 | return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->alarms)); | 558 | return sprintf(buf, "%u\n", data->alarms); |
560 | } | 559 | } |
561 | 560 | ||
562 | static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); | 561 | static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); |
diff --git a/drivers/i2c/chips/atxp1.c b/drivers/i2c/chips/atxp1.c new file mode 100644 index 000000000000..5c6597aa2c7f --- /dev/null +++ b/drivers/i2c/chips/atxp1.c | |||
@@ -0,0 +1,361 @@ | |||
1 | /* | ||
2 | atxp1.c - kernel module for setting CPU VID and general purpose | ||
3 | I/Os using the Attansic ATXP1 chip. | ||
4 | |||
5 | This program is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published by | ||
7 | the Free Software Foundation; either version 2 of the License, or | ||
8 | (at your option) any later version. | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; if not, write to the Free Software | ||
17 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
18 | |||
19 | */ | ||
20 | |||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/i2c.h> | ||
25 | #include <linux/i2c-sensor.h> | ||
26 | #include <linux/i2c-vid.h> | ||
27 | |||
28 | MODULE_LICENSE("GPL"); | ||
29 | MODULE_DESCRIPTION("System voltages control via Attansic ATXP1"); | ||
30 | MODULE_VERSION("0.6.2"); | ||
31 | MODULE_AUTHOR("Sebastian Witt <se.witt@gmx.net>"); | ||
32 | |||
33 | #define ATXP1_VID 0x00 | ||
34 | #define ATXP1_CVID 0x01 | ||
35 | #define ATXP1_GPIO1 0x06 | ||
36 | #define ATXP1_GPIO2 0x0a | ||
37 | #define ATXP1_VIDENA 0x20 | ||
38 | #define ATXP1_VIDMASK 0x1f | ||
39 | #define ATXP1_GPIO1MASK 0x0f | ||
40 | |||
41 | static unsigned short normal_i2c[] = { 0x37, 0x4e, I2C_CLIENT_END }; | ||
42 | static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; | ||
43 | |||
44 | SENSORS_INSMOD_1(atxp1); | ||
45 | |||
46 | static int atxp1_attach_adapter(struct i2c_adapter * adapter); | ||
47 | static int atxp1_detach_client(struct i2c_client * client); | ||
48 | static struct atxp1_data * atxp1_update_device(struct device *dev); | ||
49 | static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind); | ||
50 | |||
51 | static struct i2c_driver atxp1_driver = { | ||
52 | .owner = THIS_MODULE, | ||
53 | .name = "atxp1", | ||
54 | .flags = I2C_DF_NOTIFY, | ||
55 | .attach_adapter = atxp1_attach_adapter, | ||
56 | .detach_client = atxp1_detach_client, | ||
57 | }; | ||
58 | |||
59 | struct atxp1_data { | ||
60 | struct i2c_client client; | ||
61 | struct semaphore update_lock; | ||
62 | unsigned long last_updated; | ||
63 | u8 valid; | ||
64 | struct { | ||
65 | u8 vid; /* VID output register */ | ||
66 | u8 cpu_vid; /* VID input from CPU */ | ||
67 | u8 gpio1; /* General purpose I/O register 1 */ | ||
68 | u8 gpio2; /* General purpose I/O register 2 */ | ||
69 | } reg; | ||
70 | u8 vrm; /* Detected CPU VRM */ | ||
71 | }; | ||
72 | |||
73 | static struct atxp1_data * atxp1_update_device(struct device *dev) | ||
74 | { | ||
75 | struct i2c_client *client; | ||
76 | struct atxp1_data *data; | ||
77 | |||
78 | client = to_i2c_client(dev); | ||
79 | data = i2c_get_clientdata(client); | ||
80 | |||
81 | down(&data->update_lock); | ||
82 | |||
83 | if ((jiffies - data->last_updated > HZ) || | ||
84 | (jiffies < data->last_updated) || | ||
85 | !data->valid) { | ||
86 | |||
87 | /* Update local register data */ | ||
88 | data->reg.vid = i2c_smbus_read_byte_data(client, ATXP1_VID); | ||
89 | data->reg.cpu_vid = i2c_smbus_read_byte_data(client, ATXP1_CVID); | ||
90 | data->reg.gpio1 = i2c_smbus_read_byte_data(client, ATXP1_GPIO1); | ||
91 | data->reg.gpio2 = i2c_smbus_read_byte_data(client, ATXP1_GPIO2); | ||
92 | |||
93 | data->valid = 1; | ||
94 | } | ||
95 | |||
96 | up(&data->update_lock); | ||
97 | |||
98 | return(data); | ||
99 | } | ||
100 | |||
101 | /* sys file functions for cpu0_vid */ | ||
102 | static ssize_t atxp1_showvcore(struct device *dev, struct device_attribute *attr, char *buf) | ||
103 | { | ||
104 | int size; | ||
105 | struct atxp1_data *data; | ||
106 | |||
107 | data = atxp1_update_device(dev); | ||
108 | |||
109 | size = sprintf(buf, "%d\n", vid_from_reg(data->reg.vid & ATXP1_VIDMASK, data->vrm)); | ||
110 | |||
111 | return size; | ||
112 | } | ||
113 | |||
114 | static ssize_t atxp1_storevcore(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | ||
115 | { | ||
116 | struct atxp1_data *data; | ||
117 | struct i2c_client *client; | ||
118 | char vid; | ||
119 | char cvid; | ||
120 | unsigned int vcore; | ||
121 | |||
122 | client = to_i2c_client(dev); | ||
123 | data = atxp1_update_device(dev); | ||
124 | |||
125 | vcore = simple_strtoul(buf, NULL, 10); | ||
126 | vcore /= 25; | ||
127 | vcore *= 25; | ||
128 | |||
129 | /* Calculate VID */ | ||
130 | vid = vid_to_reg(vcore, data->vrm); | ||
131 | |||
132 | if (vid < 0) { | ||
133 | dev_err(dev, "VID calculation failed.\n"); | ||
134 | return -1; | ||
135 | } | ||
136 | |||
137 | /* If output enabled, use control register value. Otherwise original CPU VID */ | ||
138 | if (data->reg.vid & ATXP1_VIDENA) | ||
139 | cvid = data->reg.vid & ATXP1_VIDMASK; | ||
140 | else | ||
141 | cvid = data->reg.cpu_vid; | ||
142 | |||
143 | /* Nothing changed, aborting */ | ||
144 | if (vid == cvid) | ||
145 | return count; | ||
146 | |||
147 | dev_info(dev, "Setting VCore to %d mV (0x%02x)\n", vcore, vid); | ||
148 | |||
149 | /* Write every 25 mV step to increase stability */ | ||
150 | if (cvid > vid) { | ||
151 | for (; cvid >= vid; cvid--) { | ||
152 | i2c_smbus_write_byte_data(client, ATXP1_VID, cvid | ATXP1_VIDENA); | ||
153 | } | ||
154 | } | ||
155 | else { | ||
156 | for (; cvid <= vid; cvid++) { | ||
157 | i2c_smbus_write_byte_data(client, ATXP1_VID, cvid | ATXP1_VIDENA); | ||
158 | } | ||
159 | } | ||
160 | |||
161 | data->valid = 0; | ||
162 | |||
163 | return count; | ||
164 | } | ||
165 | |||
166 | /* CPU core reference voltage | ||
167 | unit: millivolt | ||
168 | */ | ||
169 | static DEVICE_ATTR(cpu0_vid, S_IRUGO | S_IWUSR, atxp1_showvcore, atxp1_storevcore); | ||
170 | |||
171 | /* sys file functions for GPIO1 */ | ||
172 | static ssize_t atxp1_showgpio1(struct device *dev, struct device_attribute *attr, char *buf) | ||
173 | { | ||
174 | int size; | ||
175 | struct atxp1_data *data; | ||
176 | |||
177 | data = atxp1_update_device(dev); | ||
178 | |||
179 | size = sprintf(buf, "0x%02x\n", data->reg.gpio1 & ATXP1_GPIO1MASK); | ||
180 | |||
181 | return size; | ||
182 | } | ||
183 | |||
184 | static ssize_t atxp1_storegpio1(struct device *dev, struct device_attribute *attr, const char*buf, size_t count) | ||
185 | { | ||
186 | struct atxp1_data *data; | ||
187 | struct i2c_client *client; | ||
188 | unsigned int value; | ||
189 | |||
190 | client = to_i2c_client(dev); | ||
191 | data = atxp1_update_device(dev); | ||
192 | |||
193 | value = simple_strtoul(buf, NULL, 16); | ||
194 | |||
195 | value &= ATXP1_GPIO1MASK; | ||
196 | |||
197 | if (value != (data->reg.gpio1 & ATXP1_GPIO1MASK)) { | ||
198 | dev_info(dev, "Writing 0x%x to GPIO1.\n", value); | ||
199 | |||
200 | i2c_smbus_write_byte_data(client, ATXP1_GPIO1, value); | ||
201 | |||
202 | data->valid = 0; | ||
203 | } | ||
204 | |||
205 | return count; | ||
206 | } | ||
207 | |||
208 | /* GPIO1 data register | ||
209 | unit: Four bit as hex (e.g. 0x0f) | ||
210 | */ | ||
211 | static DEVICE_ATTR(gpio1, S_IRUGO | S_IWUSR, atxp1_showgpio1, atxp1_storegpio1); | ||
212 | |||
213 | /* sys file functions for GPIO2 */ | ||
214 | static ssize_t atxp1_showgpio2(struct device *dev, struct device_attribute *attr, char *buf) | ||
215 | { | ||
216 | int size; | ||
217 | struct atxp1_data *data; | ||
218 | |||
219 | data = atxp1_update_device(dev); | ||
220 | |||
221 | size = sprintf(buf, "0x%02x\n", data->reg.gpio2); | ||
222 | |||
223 | return size; | ||
224 | } | ||
225 | |||
226 | static ssize_t atxp1_storegpio2(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | ||
227 | { | ||
228 | struct atxp1_data *data; | ||
229 | struct i2c_client *client; | ||
230 | unsigned int value; | ||
231 | |||
232 | client = to_i2c_client(dev); | ||
233 | data = atxp1_update_device(dev); | ||
234 | |||
235 | value = simple_strtoul(buf, NULL, 16) & 0xff; | ||
236 | |||
237 | if (value != data->reg.gpio2) { | ||
238 | dev_info(dev, "Writing 0x%x to GPIO1.\n", value); | ||
239 | |||
240 | i2c_smbus_write_byte_data(client, ATXP1_GPIO2, value); | ||
241 | |||
242 | data->valid = 0; | ||
243 | } | ||
244 | |||
245 | return count; | ||
246 | } | ||
247 | |||
248 | /* GPIO2 data register | ||
249 | unit: Eight bit as hex (e.g. 0xff) | ||
250 | */ | ||
251 | static DEVICE_ATTR(gpio2, S_IRUGO | S_IWUSR, atxp1_showgpio2, atxp1_storegpio2); | ||
252 | |||
253 | |||
254 | static int atxp1_attach_adapter(struct i2c_adapter *adapter) | ||
255 | { | ||
256 | return i2c_detect(adapter, &addr_data, &atxp1_detect); | ||
257 | }; | ||
258 | |||
259 | static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind) | ||
260 | { | ||
261 | struct i2c_client * new_client; | ||
262 | struct atxp1_data * data; | ||
263 | int err = 0; | ||
264 | u8 temp; | ||
265 | |||
266 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | ||
267 | goto exit; | ||
268 | |||
269 | if (!(data = kmalloc(sizeof(struct atxp1_data), GFP_KERNEL))) { | ||
270 | err = -ENOMEM; | ||
271 | goto exit; | ||
272 | } | ||
273 | |||
274 | memset(data, 0, sizeof(struct atxp1_data)); | ||
275 | new_client = &data->client; | ||
276 | i2c_set_clientdata(new_client, data); | ||
277 | |||
278 | new_client->addr = address; | ||
279 | new_client->adapter = adapter; | ||
280 | new_client->driver = &atxp1_driver; | ||
281 | new_client->flags = 0; | ||
282 | |||
283 | /* Detect ATXP1, checking if vendor ID registers are all zero */ | ||
284 | if (!((i2c_smbus_read_byte_data(new_client, 0x3e) == 0) && | ||
285 | (i2c_smbus_read_byte_data(new_client, 0x3f) == 0) && | ||
286 | (i2c_smbus_read_byte_data(new_client, 0xfe) == 0) && | ||
287 | (i2c_smbus_read_byte_data(new_client, 0xff) == 0) )) { | ||
288 | |||
289 | /* No vendor ID, now checking if registers 0x10,0x11 (non-existent) | ||
290 | * showing the same as register 0x00 */ | ||
291 | temp = i2c_smbus_read_byte_data(new_client, 0x00); | ||
292 | |||
293 | if (!((i2c_smbus_read_byte_data(new_client, 0x10) == temp) && | ||
294 | (i2c_smbus_read_byte_data(new_client, 0x11) == temp) )) | ||
295 | goto exit_free; | ||
296 | } | ||
297 | |||
298 | /* Get VRM */ | ||
299 | data->vrm = i2c_which_vrm(); | ||
300 | |||
301 | if ((data->vrm != 90) && (data->vrm != 91)) { | ||
302 | dev_err(&new_client->dev, "Not supporting VRM %d.%d\n", | ||
303 | data->vrm / 10, data->vrm % 10); | ||
304 | goto exit_free; | ||
305 | } | ||
306 | |||
307 | strncpy(new_client->name, "atxp1", I2C_NAME_SIZE); | ||
308 | |||
309 | data->valid = 0; | ||
310 | |||
311 | init_MUTEX(&data->update_lock); | ||
312 | |||
313 | err = i2c_attach_client(new_client); | ||
314 | |||
315 | if (err) | ||
316 | { | ||
317 | dev_err(&new_client->dev, "Attach client error.\n"); | ||
318 | goto exit_free; | ||
319 | } | ||
320 | |||
321 | device_create_file(&new_client->dev, &dev_attr_gpio1); | ||
322 | device_create_file(&new_client->dev, &dev_attr_gpio2); | ||
323 | device_create_file(&new_client->dev, &dev_attr_cpu0_vid); | ||
324 | |||
325 | dev_info(&new_client->dev, "Using VRM: %d.%d\n", | ||
326 | data->vrm / 10, data->vrm % 10); | ||
327 | |||
328 | return 0; | ||
329 | |||
330 | exit_free: | ||
331 | kfree(data); | ||
332 | exit: | ||
333 | return err; | ||
334 | }; | ||
335 | |||
336 | static int atxp1_detach_client(struct i2c_client * client) | ||
337 | { | ||
338 | int err; | ||
339 | |||
340 | err = i2c_detach_client(client); | ||
341 | |||
342 | if (err) | ||
343 | dev_err(&client->dev, "Failed to detach client.\n"); | ||
344 | else | ||
345 | kfree(i2c_get_clientdata(client)); | ||
346 | |||
347 | return err; | ||
348 | }; | ||
349 | |||
350 | static int __init atxp1_init(void) | ||
351 | { | ||
352 | return i2c_add_driver(&atxp1_driver); | ||
353 | }; | ||
354 | |||
355 | static void __exit atxp1_exit(void) | ||
356 | { | ||
357 | i2c_del_driver(&atxp1_driver); | ||
358 | }; | ||
359 | |||
360 | module_init(atxp1_init); | ||
361 | module_exit(atxp1_exit); | ||
diff --git a/drivers/i2c/chips/ds1337.c b/drivers/i2c/chips/ds1337.c index 07f16c3fb084..74ece8ac1c23 100644 --- a/drivers/i2c/chips/ds1337.c +++ b/drivers/i2c/chips/ds1337.c | |||
@@ -3,17 +3,16 @@ | |||
3 | * | 3 | * |
4 | * Copyright (C) 2005 James Chapman <jchapman@katalix.com> | 4 | * Copyright (C) 2005 James Chapman <jchapman@katalix.com> |
5 | * | 5 | * |
6 | * based on linux/drivers/acron/char/pcf8583.c | 6 | * based on linux/drivers/acorn/char/pcf8583.c |
7 | * Copyright (C) 2000 Russell King | 7 | * Copyright (C) 2000 Russell King |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License version 2 as | 10 | * it under the terms of the GNU General Public License version 2 as |
11 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
12 | * | 12 | * |
13 | * Driver for Dallas Semiconductor DS1337 real time clock chip | 13 | * Driver for Dallas Semiconductor DS1337 and DS1339 real time clock chip |
14 | */ | 14 | */ |
15 | 15 | ||
16 | #include <linux/config.h> | ||
17 | #include <linux/module.h> | 16 | #include <linux/module.h> |
18 | #include <linux/init.h> | 17 | #include <linux/init.h> |
19 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
@@ -69,13 +68,11 @@ static struct i2c_driver ds1337_driver = { | |||
69 | struct ds1337_data { | 68 | struct ds1337_data { |
70 | struct i2c_client client; | 69 | struct i2c_client client; |
71 | struct list_head list; | 70 | struct list_head list; |
72 | int id; | ||
73 | }; | 71 | }; |
74 | 72 | ||
75 | /* | 73 | /* |
76 | * Internal variables | 74 | * Internal variables |
77 | */ | 75 | */ |
78 | static int ds1337_id; | ||
79 | static LIST_HEAD(ds1337_clients); | 76 | static LIST_HEAD(ds1337_clients); |
80 | 77 | ||
81 | static inline int ds1337_read(struct i2c_client *client, u8 reg, u8 *value) | 78 | static inline int ds1337_read(struct i2c_client *client, u8 reg, u8 *value) |
@@ -95,7 +92,6 @@ static inline int ds1337_read(struct i2c_client *client, u8 reg, u8 *value) | |||
95 | */ | 92 | */ |
96 | static int ds1337_get_datetime(struct i2c_client *client, struct rtc_time *dt) | 93 | static int ds1337_get_datetime(struct i2c_client *client, struct rtc_time *dt) |
97 | { | 94 | { |
98 | struct ds1337_data *data = i2c_get_clientdata(client); | ||
99 | int result; | 95 | int result; |
100 | u8 buf[7]; | 96 | u8 buf[7]; |
101 | u8 val; | 97 | u8 val; |
@@ -103,9 +99,7 @@ static int ds1337_get_datetime(struct i2c_client *client, struct rtc_time *dt) | |||
103 | u8 offs = 0; | 99 | u8 offs = 0; |
104 | 100 | ||
105 | if (!dt) { | 101 | if (!dt) { |
106 | dev_dbg(&client->adapter->dev, "%s: EINVAL: dt=NULL\n", | 102 | dev_dbg(&client->dev, "%s: EINVAL: dt=NULL\n", __FUNCTION__); |
107 | __FUNCTION__); | ||
108 | |||
109 | return -EINVAL; | 103 | return -EINVAL; |
110 | } | 104 | } |
111 | 105 | ||
@@ -119,98 +113,86 @@ static int ds1337_get_datetime(struct i2c_client *client, struct rtc_time *dt) | |||
119 | msg[1].len = sizeof(buf); | 113 | msg[1].len = sizeof(buf); |
120 | msg[1].buf = &buf[0]; | 114 | msg[1].buf = &buf[0]; |
121 | 115 | ||
122 | result = client->adapter->algo->master_xfer(client->adapter, | 116 | result = i2c_transfer(client->adapter, msg, 2); |
123 | &msg[0], 2); | ||
124 | 117 | ||
125 | dev_dbg(&client->adapter->dev, | 118 | dev_dbg(&client->dev, "%s: [%d] %02x %02x %02x %02x %02x %02x %02x\n", |
126 | "%s: [%d] %02x %02x %02x %02x %02x %02x %02x\n", | ||
127 | __FUNCTION__, result, buf[0], buf[1], buf[2], buf[3], | 119 | __FUNCTION__, result, buf[0], buf[1], buf[2], buf[3], |
128 | buf[4], buf[5], buf[6]); | 120 | buf[4], buf[5], buf[6]); |
129 | 121 | ||
130 | if (result >= 0) { | 122 | if (result == 2) { |
131 | dt->tm_sec = BCD_TO_BIN(buf[0]); | 123 | dt->tm_sec = BCD2BIN(buf[0]); |
132 | dt->tm_min = BCD_TO_BIN(buf[1]); | 124 | dt->tm_min = BCD2BIN(buf[1]); |
133 | val = buf[2] & 0x3f; | 125 | val = buf[2] & 0x3f; |
134 | dt->tm_hour = BCD_TO_BIN(val); | 126 | dt->tm_hour = BCD2BIN(val); |
135 | dt->tm_wday = BCD_TO_BIN(buf[3]) - 1; | 127 | dt->tm_wday = BCD2BIN(buf[3]) - 1; |
136 | dt->tm_mday = BCD_TO_BIN(buf[4]); | 128 | dt->tm_mday = BCD2BIN(buf[4]); |
137 | val = buf[5] & 0x7f; | 129 | val = buf[5] & 0x7f; |
138 | dt->tm_mon = BCD_TO_BIN(val); | 130 | dt->tm_mon = BCD2BIN(val) - 1; |
139 | dt->tm_year = 1900 + BCD_TO_BIN(buf[6]); | 131 | dt->tm_year = BCD2BIN(buf[6]); |
140 | if (buf[5] & 0x80) | 132 | if (buf[5] & 0x80) |
141 | dt->tm_year += 100; | 133 | dt->tm_year += 100; |
142 | 134 | ||
143 | dev_dbg(&client->adapter->dev, "%s: secs=%d, mins=%d, " | 135 | dev_dbg(&client->dev, "%s: secs=%d, mins=%d, " |
144 | "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n", | 136 | "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n", |
145 | __FUNCTION__, dt->tm_sec, dt->tm_min, | 137 | __FUNCTION__, dt->tm_sec, dt->tm_min, |
146 | dt->tm_hour, dt->tm_mday, | 138 | dt->tm_hour, dt->tm_mday, |
147 | dt->tm_mon, dt->tm_year, dt->tm_wday); | 139 | dt->tm_mon, dt->tm_year, dt->tm_wday); |
148 | } else { | 140 | |
149 | dev_err(&client->adapter->dev, "ds1337[%d]: error reading " | 141 | return 0; |
150 | "data! %d\n", data->id, result); | ||
151 | result = -EIO; | ||
152 | } | 142 | } |
153 | 143 | ||
154 | return result; | 144 | dev_err(&client->dev, "error reading data! %d\n", result); |
145 | return -EIO; | ||
155 | } | 146 | } |
156 | 147 | ||
157 | static int ds1337_set_datetime(struct i2c_client *client, struct rtc_time *dt) | 148 | static int ds1337_set_datetime(struct i2c_client *client, struct rtc_time *dt) |
158 | { | 149 | { |
159 | struct ds1337_data *data = i2c_get_clientdata(client); | ||
160 | int result; | 150 | int result; |
161 | u8 buf[8]; | 151 | u8 buf[8]; |
162 | u8 val; | 152 | u8 val; |
163 | struct i2c_msg msg[1]; | 153 | struct i2c_msg msg[1]; |
164 | 154 | ||
165 | if (!dt) { | 155 | if (!dt) { |
166 | dev_dbg(&client->adapter->dev, "%s: EINVAL: dt=NULL\n", | 156 | dev_dbg(&client->dev, "%s: EINVAL: dt=NULL\n", __FUNCTION__); |
167 | __FUNCTION__); | ||
168 | |||
169 | return -EINVAL; | 157 | return -EINVAL; |
170 | } | 158 | } |
171 | 159 | ||
172 | dev_dbg(&client->adapter->dev, "%s: secs=%d, mins=%d, hours=%d, " | 160 | dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, " |
173 | "mday=%d, mon=%d, year=%d, wday=%d\n", __FUNCTION__, | 161 | "mday=%d, mon=%d, year=%d, wday=%d\n", __FUNCTION__, |
174 | dt->tm_sec, dt->tm_min, dt->tm_hour, | 162 | dt->tm_sec, dt->tm_min, dt->tm_hour, |
175 | dt->tm_mday, dt->tm_mon, dt->tm_year, dt->tm_wday); | 163 | dt->tm_mday, dt->tm_mon, dt->tm_year, dt->tm_wday); |
176 | 164 | ||
177 | buf[0] = 0; /* reg offset */ | 165 | buf[0] = 0; /* reg offset */ |
178 | buf[1] = BIN_TO_BCD(dt->tm_sec); | 166 | buf[1] = BIN2BCD(dt->tm_sec); |
179 | buf[2] = BIN_TO_BCD(dt->tm_min); | 167 | buf[2] = BIN2BCD(dt->tm_min); |
180 | buf[3] = BIN_TO_BCD(dt->tm_hour) | (1 << 6); | 168 | buf[3] = BIN2BCD(dt->tm_hour) | (1 << 6); |
181 | buf[4] = BIN_TO_BCD(dt->tm_wday) + 1; | 169 | buf[4] = BIN2BCD(dt->tm_wday) + 1; |
182 | buf[5] = BIN_TO_BCD(dt->tm_mday); | 170 | buf[5] = BIN2BCD(dt->tm_mday); |
183 | buf[6] = BIN_TO_BCD(dt->tm_mon); | 171 | buf[6] = BIN2BCD(dt->tm_mon) + 1; |
184 | if (dt->tm_year >= 2000) { | 172 | val = dt->tm_year; |
185 | val = dt->tm_year - 2000; | 173 | if (val >= 100) { |
174 | val -= 100; | ||
186 | buf[6] |= (1 << 7); | 175 | buf[6] |= (1 << 7); |
187 | } else { | ||
188 | val = dt->tm_year - 1900; | ||
189 | } | 176 | } |
190 | buf[7] = BIN_TO_BCD(val); | 177 | buf[7] = BIN2BCD(val); |
191 | 178 | ||
192 | msg[0].addr = client->addr; | 179 | msg[0].addr = client->addr; |
193 | msg[0].flags = 0; | 180 | msg[0].flags = 0; |
194 | msg[0].len = sizeof(buf); | 181 | msg[0].len = sizeof(buf); |
195 | msg[0].buf = &buf[0]; | 182 | msg[0].buf = &buf[0]; |
196 | 183 | ||
197 | result = client->adapter->algo->master_xfer(client->adapter, | 184 | result = i2c_transfer(client->adapter, msg, 1); |
198 | &msg[0], 1); | 185 | if (result == 1) |
199 | if (result < 0) { | 186 | return 0; |
200 | dev_err(&client->adapter->dev, "ds1337[%d]: error " | ||
201 | "writing data! %d\n", data->id, result); | ||
202 | result = -EIO; | ||
203 | } else { | ||
204 | result = 0; | ||
205 | } | ||
206 | 187 | ||
207 | return result; | 188 | dev_err(&client->dev, "error writing data! %d\n", result); |
189 | return -EIO; | ||
208 | } | 190 | } |
209 | 191 | ||
210 | static int ds1337_command(struct i2c_client *client, unsigned int cmd, | 192 | static int ds1337_command(struct i2c_client *client, unsigned int cmd, |
211 | void *arg) | 193 | void *arg) |
212 | { | 194 | { |
213 | dev_dbg(&client->adapter->dev, "%s: cmd=%d\n", __FUNCTION__, cmd); | 195 | dev_dbg(&client->dev, "%s: cmd=%d\n", __FUNCTION__, cmd); |
214 | 196 | ||
215 | switch (cmd) { | 197 | switch (cmd) { |
216 | case DS1337_GET_DATE: | 198 | case DS1337_GET_DATE: |
@@ -228,7 +210,7 @@ static int ds1337_command(struct i2c_client *client, unsigned int cmd, | |||
228 | * Public API for access to specific device. Useful for low-level | 210 | * Public API for access to specific device. Useful for low-level |
229 | * RTC access from kernel code. | 211 | * RTC access from kernel code. |
230 | */ | 212 | */ |
231 | int ds1337_do_command(int id, int cmd, void *arg) | 213 | int ds1337_do_command(int bus, int cmd, void *arg) |
232 | { | 214 | { |
233 | struct list_head *walk; | 215 | struct list_head *walk; |
234 | struct list_head *tmp; | 216 | struct list_head *tmp; |
@@ -236,7 +218,7 @@ int ds1337_do_command(int id, int cmd, void *arg) | |||
236 | 218 | ||
237 | list_for_each_safe(walk, tmp, &ds1337_clients) { | 219 | list_for_each_safe(walk, tmp, &ds1337_clients) { |
238 | data = list_entry(walk, struct ds1337_data, list); | 220 | data = list_entry(walk, struct ds1337_data, list); |
239 | if (data->id == id) | 221 | if (data->client.adapter->nr == bus) |
240 | return ds1337_command(&data->client, cmd, arg); | 222 | return ds1337_command(&data->client, cmd, arg); |
241 | } | 223 | } |
242 | 224 | ||
@@ -346,7 +328,6 @@ static int ds1337_detect(struct i2c_adapter *adapter, int address, int kind) | |||
346 | ds1337_init_client(new_client); | 328 | ds1337_init_client(new_client); |
347 | 329 | ||
348 | /* Add client to local list */ | 330 | /* Add client to local list */ |
349 | data->id = ds1337_id++; | ||
350 | list_add(&data->list, &ds1337_clients); | 331 | list_add(&data->list, &ds1337_clients); |
351 | 332 | ||
352 | return 0; | 333 | return 0; |
@@ -398,5 +379,7 @@ MODULE_AUTHOR("James Chapman <jchapman@katalix.com>"); | |||
398 | MODULE_DESCRIPTION("DS1337 RTC driver"); | 379 | MODULE_DESCRIPTION("DS1337 RTC driver"); |
399 | MODULE_LICENSE("GPL"); | 380 | MODULE_LICENSE("GPL"); |
400 | 381 | ||
382 | EXPORT_SYMBOL_GPL(ds1337_do_command); | ||
383 | |||
401 | module_init(ds1337_init); | 384 | module_init(ds1337_init); |
402 | module_exit(ds1337_exit); | 385 | module_exit(ds1337_exit); |
diff --git a/drivers/i2c/chips/ds1374.c b/drivers/i2c/chips/ds1374.c new file mode 100644 index 000000000000..a445736d8838 --- /dev/null +++ b/drivers/i2c/chips/ds1374.c | |||
@@ -0,0 +1,260 @@ | |||
1 | /* | ||
2 | * drivers/i2c/chips/ds1374.c | ||
3 | * | ||
4 | * I2C client/driver for the Maxim/Dallas DS1374 Real-Time Clock | ||
5 | * | ||
6 | * Author: Randy Vinson <rvinson@mvista.com> | ||
7 | * | ||
8 | * Based on the m41t00.c by Mark Greer <mgreer@mvista.com> | ||
9 | * | ||
10 | * 2005 (c) MontaVista Software, Inc. This file is licensed under | ||
11 | * the terms of the GNU General Public License version 2. This program | ||
12 | * is licensed "as is" without any warranty of any kind, whether express | ||
13 | * or implied. | ||
14 | */ | ||
15 | /* | ||
16 | * This i2c client/driver wedges between the drivers/char/genrtc.c RTC | ||
17 | * interface and the SMBus interface of the i2c subsystem. | ||
18 | * It would be more efficient to use i2c msgs/i2c_transfer directly but, as | ||
19 | * recommened in .../Documentation/i2c/writing-clients section | ||
20 | * "Sending and receiving", using SMBus level communication is preferred. | ||
21 | */ | ||
22 | |||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/interrupt.h> | ||
26 | #include <linux/i2c.h> | ||
27 | #include <linux/rtc.h> | ||
28 | #include <linux/bcd.h> | ||
29 | |||
30 | #define DS1374_REG_TOD0 0x00 | ||
31 | #define DS1374_REG_TOD1 0x01 | ||
32 | #define DS1374_REG_TOD2 0x02 | ||
33 | #define DS1374_REG_TOD3 0x03 | ||
34 | #define DS1374_REG_WDALM0 0x04 | ||
35 | #define DS1374_REG_WDALM1 0x05 | ||
36 | #define DS1374_REG_WDALM2 0x06 | ||
37 | #define DS1374_REG_CR 0x07 | ||
38 | #define DS1374_REG_SR 0x08 | ||
39 | #define DS1374_REG_SR_OSF 0x80 | ||
40 | #define DS1374_REG_TCR 0x09 | ||
41 | |||
42 | #define DS1374_DRV_NAME "ds1374" | ||
43 | |||
44 | static DECLARE_MUTEX(ds1374_mutex); | ||
45 | |||
46 | static struct i2c_driver ds1374_driver; | ||
47 | static struct i2c_client *save_client; | ||
48 | |||
49 | static unsigned short ignore[] = { I2C_CLIENT_END }; | ||
50 | static unsigned short normal_addr[] = { 0x68, I2C_CLIENT_END }; | ||
51 | |||
52 | static struct i2c_client_address_data addr_data = { | ||
53 | .normal_i2c = normal_addr, | ||
54 | .probe = ignore, | ||
55 | .ignore = ignore, | ||
56 | .force = ignore, | ||
57 | }; | ||
58 | |||
59 | static ulong ds1374_read_rtc(void) | ||
60 | { | ||
61 | ulong time = 0; | ||
62 | int reg = DS1374_REG_WDALM0; | ||
63 | |||
64 | while (reg--) { | ||
65 | s32 tmp; | ||
66 | if ((tmp = i2c_smbus_read_byte_data(save_client, reg)) < 0) { | ||
67 | dev_warn(&save_client->dev, | ||
68 | "can't read from rtc chip\n"); | ||
69 | return 0; | ||
70 | } | ||
71 | time = (time << 8) | (tmp & 0xff); | ||
72 | } | ||
73 | return time; | ||
74 | } | ||
75 | |||
76 | static void ds1374_write_rtc(ulong time) | ||
77 | { | ||
78 | int reg; | ||
79 | |||
80 | for (reg = DS1374_REG_TOD0; reg < DS1374_REG_WDALM0; reg++) { | ||
81 | if (i2c_smbus_write_byte_data(save_client, reg, time & 0xff) | ||
82 | < 0) { | ||
83 | dev_warn(&save_client->dev, | ||
84 | "can't write to rtc chip\n"); | ||
85 | break; | ||
86 | } | ||
87 | time = time >> 8; | ||
88 | } | ||
89 | } | ||
90 | |||
91 | static void ds1374_check_rtc_status(void) | ||
92 | { | ||
93 | s32 tmp; | ||
94 | |||
95 | tmp = i2c_smbus_read_byte_data(save_client, DS1374_REG_SR); | ||
96 | if (tmp < 0) { | ||
97 | dev_warn(&save_client->dev, | ||
98 | "can't read status from rtc chip\n"); | ||
99 | return; | ||
100 | } | ||
101 | if (tmp & DS1374_REG_SR_OSF) { | ||
102 | dev_warn(&save_client->dev, | ||
103 | "oscillator discontinuity flagged, time unreliable\n"); | ||
104 | tmp &= ~DS1374_REG_SR_OSF; | ||
105 | tmp = i2c_smbus_write_byte_data(save_client, DS1374_REG_SR, | ||
106 | tmp & 0xff); | ||
107 | if (tmp < 0) | ||
108 | dev_warn(&save_client->dev, | ||
109 | "can't clear discontinuity notification\n"); | ||
110 | } | ||
111 | } | ||
112 | |||
113 | ulong ds1374_get_rtc_time(void) | ||
114 | { | ||
115 | ulong t1, t2; | ||
116 | int limit = 10; /* arbitrary retry limit */ | ||
117 | |||
118 | down(&ds1374_mutex); | ||
119 | |||
120 | /* | ||
121 | * Since the reads are being performed one byte at a time using | ||
122 | * the SMBus vs a 4-byte i2c transfer, there is a chance that a | ||
123 | * carry will occur during the read. To detect this, 2 reads are | ||
124 | * performed and compared. | ||
125 | */ | ||
126 | do { | ||
127 | t1 = ds1374_read_rtc(); | ||
128 | t2 = ds1374_read_rtc(); | ||
129 | } while (t1 != t2 && limit--); | ||
130 | |||
131 | up(&ds1374_mutex); | ||
132 | |||
133 | if (t1 != t2) { | ||
134 | dev_warn(&save_client->dev, | ||
135 | "can't get consistent time from rtc chip\n"); | ||
136 | t1 = 0; | ||
137 | } | ||
138 | |||
139 | return t1; | ||
140 | } | ||
141 | |||
142 | static void ds1374_set_tlet(ulong arg) | ||
143 | { | ||
144 | ulong t1, t2; | ||
145 | int limit = 10; /* arbitrary retry limit */ | ||
146 | |||
147 | t1 = *(ulong *) arg; | ||
148 | |||
149 | down(&ds1374_mutex); | ||
150 | |||
151 | /* | ||
152 | * Since the writes are being performed one byte at a time using | ||
153 | * the SMBus vs a 4-byte i2c transfer, there is a chance that a | ||
154 | * carry will occur during the write. To detect this, the write | ||
155 | * value is read back and compared. | ||
156 | */ | ||
157 | do { | ||
158 | ds1374_write_rtc(t1); | ||
159 | t2 = ds1374_read_rtc(); | ||
160 | } while (t1 != t2 && limit--); | ||
161 | |||
162 | up(&ds1374_mutex); | ||
163 | |||
164 | if (t1 != t2) | ||
165 | dev_warn(&save_client->dev, | ||
166 | "can't confirm time set from rtc chip\n"); | ||
167 | } | ||
168 | |||
169 | ulong new_time; | ||
170 | |||
171 | DECLARE_TASKLET_DISABLED(ds1374_tasklet, ds1374_set_tlet, (ulong) & new_time); | ||
172 | |||
173 | int ds1374_set_rtc_time(ulong nowtime) | ||
174 | { | ||
175 | new_time = nowtime; | ||
176 | |||
177 | if (in_interrupt()) | ||
178 | tasklet_schedule(&ds1374_tasklet); | ||
179 | else | ||
180 | ds1374_set_tlet((ulong) & new_time); | ||
181 | |||
182 | return 0; | ||
183 | } | ||
184 | |||
185 | /* | ||
186 | ***************************************************************************** | ||
187 | * | ||
188 | * Driver Interface | ||
189 | * | ||
190 | ***************************************************************************** | ||
191 | */ | ||
192 | static int ds1374_probe(struct i2c_adapter *adap, int addr, int kind) | ||
193 | { | ||
194 | struct i2c_client *client; | ||
195 | int rc; | ||
196 | |||
197 | client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); | ||
198 | if (!client) | ||
199 | return -ENOMEM; | ||
200 | |||
201 | memset(client, 0, sizeof(struct i2c_client)); | ||
202 | strncpy(client->name, DS1374_DRV_NAME, I2C_NAME_SIZE); | ||
203 | client->flags = I2C_DF_NOTIFY; | ||
204 | client->addr = addr; | ||
205 | client->adapter = adap; | ||
206 | client->driver = &ds1374_driver; | ||
207 | |||
208 | if ((rc = i2c_attach_client(client)) != 0) { | ||
209 | kfree(client); | ||
210 | return rc; | ||
211 | } | ||
212 | |||
213 | save_client = client; | ||
214 | |||
215 | ds1374_check_rtc_status(); | ||
216 | |||
217 | return 0; | ||
218 | } | ||
219 | |||
220 | static int ds1374_attach(struct i2c_adapter *adap) | ||
221 | { | ||
222 | return i2c_probe(adap, &addr_data, ds1374_probe); | ||
223 | } | ||
224 | |||
225 | static int ds1374_detach(struct i2c_client *client) | ||
226 | { | ||
227 | int rc; | ||
228 | |||
229 | if ((rc = i2c_detach_client(client)) == 0) { | ||
230 | kfree(i2c_get_clientdata(client)); | ||
231 | tasklet_kill(&ds1374_tasklet); | ||
232 | } | ||
233 | return rc; | ||
234 | } | ||
235 | |||
236 | static struct i2c_driver ds1374_driver = { | ||
237 | .owner = THIS_MODULE, | ||
238 | .name = DS1374_DRV_NAME, | ||
239 | .id = I2C_DRIVERID_DS1374, | ||
240 | .flags = I2C_DF_NOTIFY, | ||
241 | .attach_adapter = ds1374_attach, | ||
242 | .detach_client = ds1374_detach, | ||
243 | }; | ||
244 | |||
245 | static int __init ds1374_init(void) | ||
246 | { | ||
247 | return i2c_add_driver(&ds1374_driver); | ||
248 | } | ||
249 | |||
250 | static void __exit ds1374_exit(void) | ||
251 | { | ||
252 | i2c_del_driver(&ds1374_driver); | ||
253 | } | ||
254 | |||
255 | module_init(ds1374_init); | ||
256 | module_exit(ds1374_exit); | ||
257 | |||
258 | MODULE_AUTHOR("Randy Vinson <rvinson@mvista.com>"); | ||
259 | MODULE_DESCRIPTION("Maxim/Dallas DS1374 RTC I2C Client Driver"); | ||
260 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/i2c/chips/ds1621.c b/drivers/i2c/chips/ds1621.c index 4ae15bd5dcfb..5360d58804f6 100644 --- a/drivers/i2c/chips/ds1621.c +++ b/drivers/i2c/chips/ds1621.c | |||
@@ -121,7 +121,7 @@ static int ds1621_write_value(struct i2c_client *client, u8 reg, u16 value) | |||
121 | static void ds1621_init_client(struct i2c_client *client) | 121 | static void ds1621_init_client(struct i2c_client *client) |
122 | { | 122 | { |
123 | int reg = ds1621_read_value(client, DS1621_REG_CONF); | 123 | int reg = ds1621_read_value(client, DS1621_REG_CONF); |
124 | /* switch to continous conversion mode */ | 124 | /* switch to continuous conversion mode */ |
125 | reg &= ~ DS1621_REG_CONFIG_1SHOT; | 125 | reg &= ~ DS1621_REG_CONFIG_1SHOT; |
126 | 126 | ||
127 | /* setup output polarity */ | 127 | /* setup output polarity */ |
@@ -303,7 +303,7 @@ static struct ds1621_data *ds1621_update_client(struct device *dev) | |||
303 | data->temp_max = ds1621_read_value(client, | 303 | data->temp_max = ds1621_read_value(client, |
304 | DS1621_REG_TEMP_MAX); | 304 | DS1621_REG_TEMP_MAX); |
305 | 305 | ||
306 | /* reset alarms if neccessary */ | 306 | /* reset alarms if necessary */ |
307 | new_conf = data->conf; | 307 | new_conf = data->conf; |
308 | if (data->temp < data->temp_min) | 308 | if (data->temp < data->temp_min) |
309 | new_conf &= ~DS1621_ALARM_TEMP_LOW; | 309 | new_conf &= ~DS1621_ALARM_TEMP_LOW; |
diff --git a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c index cbdfa2db6f7c..addf0adc24d4 100644 --- a/drivers/i2c/chips/eeprom.c +++ b/drivers/i2c/chips/eeprom.c | |||
@@ -26,7 +26,6 @@ | |||
26 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 26 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
27 | */ | 27 | */ |
28 | 28 | ||
29 | #include <linux/config.h> | ||
30 | #include <linux/kernel.h> | 29 | #include <linux/kernel.h> |
31 | #include <linux/init.h> | 30 | #include <linux/init.h> |
32 | #include <linux/module.h> | 31 | #include <linux/module.h> |
diff --git a/drivers/i2c/chips/fscher.c b/drivers/i2c/chips/fscher.c index c3f37dbec11a..da411741c2c5 100644 --- a/drivers/i2c/chips/fscher.c +++ b/drivers/i2c/chips/fscher.c | |||
@@ -26,7 +26,6 @@ | |||
26 | * and Philip Edelbrock <phil@netroedge.com> | 26 | * and Philip Edelbrock <phil@netroedge.com> |
27 | */ | 27 | */ |
28 | 28 | ||
29 | #include <linux/config.h> | ||
30 | #include <linux/module.h> | 29 | #include <linux/module.h> |
31 | #include <linux/init.h> | 30 | #include <linux/init.h> |
32 | #include <linux/slab.h> | 31 | #include <linux/slab.h> |
diff --git a/drivers/i2c/chips/gl518sm.c b/drivers/i2c/chips/gl518sm.c index 4316a1562251..6bedf729dcf5 100644 --- a/drivers/i2c/chips/gl518sm.c +++ b/drivers/i2c/chips/gl518sm.c | |||
@@ -36,7 +36,6 @@ | |||
36 | * 2004-01-31 Code review and approval. (Jean Delvare) | 36 | * 2004-01-31 Code review and approval. (Jean Delvare) |
37 | */ | 37 | */ |
38 | 38 | ||
39 | #include <linux/config.h> | ||
40 | #include <linux/module.h> | 39 | #include <linux/module.h> |
41 | #include <linux/init.h> | 40 | #include <linux/init.h> |
42 | #include <linux/slab.h> | 41 | #include <linux/slab.h> |
diff --git a/drivers/i2c/chips/isp1301_omap.c b/drivers/i2c/chips/isp1301_omap.c index 7f29a8aff165..354a26295672 100644 --- a/drivers/i2c/chips/isp1301_omap.c +++ b/drivers/i2c/chips/isp1301_omap.c | |||
@@ -145,7 +145,6 @@ static inline void notresponding(struct isp1301 *isp) | |||
145 | static unsigned short normal_i2c[] = { | 145 | static unsigned short normal_i2c[] = { |
146 | ISP_BASE, ISP_BASE + 1, | 146 | ISP_BASE, ISP_BASE + 1, |
147 | I2C_CLIENT_END }; | 147 | I2C_CLIENT_END }; |
148 | static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; | ||
149 | 148 | ||
150 | I2C_CLIENT_INSMOD; | 149 | I2C_CLIENT_INSMOD; |
151 | 150 | ||
diff --git a/drivers/i2c/chips/it87.c b/drivers/i2c/chips/it87.c index 007bdf9e7e2a..db20c9e47393 100644 --- a/drivers/i2c/chips/it87.c +++ b/drivers/i2c/chips/it87.c | |||
@@ -31,7 +31,6 @@ | |||
31 | type at module load time. | 31 | type at module load time. |
32 | */ | 32 | */ |
33 | 33 | ||
34 | #include <linux/config.h> | ||
35 | #include <linux/module.h> | 34 | #include <linux/module.h> |
36 | #include <linux/init.h> | 35 | #include <linux/init.h> |
37 | #include <linux/slab.h> | 36 | #include <linux/slab.h> |
@@ -39,6 +38,7 @@ | |||
39 | #include <linux/i2c.h> | 38 | #include <linux/i2c.h> |
40 | #include <linux/i2c-sensor.h> | 39 | #include <linux/i2c-sensor.h> |
41 | #include <linux/i2c-vid.h> | 40 | #include <linux/i2c-vid.h> |
41 | #include <linux/hwmon-sysfs.h> | ||
42 | #include <asm/io.h> | 42 | #include <asm/io.h> |
43 | 43 | ||
44 | 44 | ||
@@ -173,8 +173,6 @@ static inline u8 FAN_TO_REG(long rpm, int div) | |||
173 | ((val)+500)/1000),-128,127)) | 173 | ((val)+500)/1000),-128,127)) |
174 | #define TEMP_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*1000) | 174 | #define TEMP_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*1000) |
175 | 175 | ||
176 | #define ALARMS_FROM_REG(val) (val) | ||
177 | |||
178 | #define PWM_TO_REG(val) ((val) >> 1) | 176 | #define PWM_TO_REG(val) ((val) >> 1) |
179 | #define PWM_FROM_REG(val) (((val)&0x7f) << 1) | 177 | #define PWM_FROM_REG(val) (((val)&0x7f) << 1) |
180 | 178 | ||
@@ -241,27 +239,42 @@ static struct i2c_driver it87_driver = { | |||
241 | .detach_client = it87_detach_client, | 239 | .detach_client = it87_detach_client, |
242 | }; | 240 | }; |
243 | 241 | ||
244 | static ssize_t show_in(struct device *dev, char *buf, int nr) | 242 | static ssize_t show_in(struct device *dev, struct device_attribute *attr, |
243 | char *buf) | ||
245 | { | 244 | { |
245 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
246 | int nr = sensor_attr->index; | ||
247 | |||
246 | struct it87_data *data = it87_update_device(dev); | 248 | struct it87_data *data = it87_update_device(dev); |
247 | return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr])); | 249 | return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr])); |
248 | } | 250 | } |
249 | 251 | ||
250 | static ssize_t show_in_min(struct device *dev, char *buf, int nr) | 252 | static ssize_t show_in_min(struct device *dev, struct device_attribute *attr, |
253 | char *buf) | ||
251 | { | 254 | { |
255 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
256 | int nr = sensor_attr->index; | ||
257 | |||
252 | struct it87_data *data = it87_update_device(dev); | 258 | struct it87_data *data = it87_update_device(dev); |
253 | return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr])); | 259 | return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr])); |
254 | } | 260 | } |
255 | 261 | ||
256 | static ssize_t show_in_max(struct device *dev, char *buf, int nr) | 262 | static ssize_t show_in_max(struct device *dev, struct device_attribute *attr, |
263 | char *buf) | ||
257 | { | 264 | { |
265 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
266 | int nr = sensor_attr->index; | ||
267 | |||
258 | struct it87_data *data = it87_update_device(dev); | 268 | struct it87_data *data = it87_update_device(dev); |
259 | return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr])); | 269 | return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr])); |
260 | } | 270 | } |
261 | 271 | ||
262 | static ssize_t set_in_min(struct device *dev, const char *buf, | 272 | static ssize_t set_in_min(struct device *dev, struct device_attribute *attr, |
263 | size_t count, int nr) | 273 | const char *buf, size_t count) |
264 | { | 274 | { |
275 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
276 | int nr = sensor_attr->index; | ||
277 | |||
265 | struct i2c_client *client = to_i2c_client(dev); | 278 | struct i2c_client *client = to_i2c_client(dev); |
266 | struct it87_data *data = i2c_get_clientdata(client); | 279 | struct it87_data *data = i2c_get_clientdata(client); |
267 | unsigned long val = simple_strtoul(buf, NULL, 10); | 280 | unsigned long val = simple_strtoul(buf, NULL, 10); |
@@ -273,9 +286,12 @@ static ssize_t set_in_min(struct device *dev, const char *buf, | |||
273 | up(&data->update_lock); | 286 | up(&data->update_lock); |
274 | return count; | 287 | return count; |
275 | } | 288 | } |
276 | static ssize_t set_in_max(struct device *dev, const char *buf, | 289 | static ssize_t set_in_max(struct device *dev, struct device_attribute *attr, |
277 | size_t count, int nr) | 290 | const char *buf, size_t count) |
278 | { | 291 | { |
292 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
293 | int nr = sensor_attr->index; | ||
294 | |||
279 | struct i2c_client *client = to_i2c_client(dev); | 295 | struct i2c_client *client = to_i2c_client(dev); |
280 | struct it87_data *data = i2c_get_clientdata(client); | 296 | struct it87_data *data = i2c_get_clientdata(client); |
281 | unsigned long val = simple_strtoul(buf, NULL, 10); | 297 | unsigned long val = simple_strtoul(buf, NULL, 10); |
@@ -289,38 +305,14 @@ static ssize_t set_in_max(struct device *dev, const char *buf, | |||
289 | } | 305 | } |
290 | 306 | ||
291 | #define show_in_offset(offset) \ | 307 | #define show_in_offset(offset) \ |
292 | static ssize_t \ | 308 | static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \ |
293 | show_in##offset (struct device *dev, struct device_attribute *attr, char *buf) \ | 309 | show_in, NULL, offset); |
294 | { \ | ||
295 | return show_in(dev, buf, offset); \ | ||
296 | } \ | ||
297 | static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL); | ||
298 | 310 | ||
299 | #define limit_in_offset(offset) \ | 311 | #define limit_in_offset(offset) \ |
300 | static ssize_t \ | 312 | static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ |
301 | show_in##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ | 313 | show_in_min, set_in_min, offset); \ |
302 | { \ | 314 | static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ |
303 | return show_in_min(dev, buf, offset); \ | 315 | show_in_max, set_in_max, offset); |
304 | } \ | ||
305 | static ssize_t \ | ||
306 | show_in##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ | ||
307 | { \ | ||
308 | return show_in_max(dev, buf, offset); \ | ||
309 | } \ | ||
310 | static ssize_t set_in##offset##_min (struct device *dev, struct device_attribute *attr, \ | ||
311 | const char *buf, size_t count) \ | ||
312 | { \ | ||
313 | return set_in_min(dev, buf, count, offset); \ | ||
314 | } \ | ||
315 | static ssize_t set_in##offset##_max (struct device *dev, struct device_attribute *attr, \ | ||
316 | const char *buf, size_t count) \ | ||
317 | { \ | ||
318 | return set_in_max(dev, buf, count, offset); \ | ||
319 | } \ | ||
320 | static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ | ||
321 | show_in##offset##_min, set_in##offset##_min); \ | ||
322 | static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ | ||
323 | show_in##offset##_max, set_in##offset##_max); | ||
324 | 316 | ||
325 | show_in_offset(0); | 317 | show_in_offset(0); |
326 | limit_in_offset(0); | 318 | limit_in_offset(0); |
@@ -341,24 +333,39 @@ limit_in_offset(7); | |||
341 | show_in_offset(8); | 333 | show_in_offset(8); |
342 | 334 | ||
343 | /* 3 temperatures */ | 335 | /* 3 temperatures */ |
344 | static ssize_t show_temp(struct device *dev, char *buf, int nr) | 336 | static ssize_t show_temp(struct device *dev, struct device_attribute *attr, |
337 | char *buf) | ||
345 | { | 338 | { |
339 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
340 | int nr = sensor_attr->index; | ||
341 | |||
346 | struct it87_data *data = it87_update_device(dev); | 342 | struct it87_data *data = it87_update_device(dev); |
347 | return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr])); | 343 | return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr])); |
348 | } | 344 | } |
349 | static ssize_t show_temp_max(struct device *dev, char *buf, int nr) | 345 | static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr, |
346 | char *buf) | ||
350 | { | 347 | { |
348 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
349 | int nr = sensor_attr->index; | ||
350 | |||
351 | struct it87_data *data = it87_update_device(dev); | 351 | struct it87_data *data = it87_update_device(dev); |
352 | return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_high[nr])); | 352 | return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_high[nr])); |
353 | } | 353 | } |
354 | static ssize_t show_temp_min(struct device *dev, char *buf, int nr) | 354 | static ssize_t show_temp_min(struct device *dev, struct device_attribute *attr, |
355 | char *buf) | ||
355 | { | 356 | { |
357 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
358 | int nr = sensor_attr->index; | ||
359 | |||
356 | struct it87_data *data = it87_update_device(dev); | 360 | struct it87_data *data = it87_update_device(dev); |
357 | return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_low[nr])); | 361 | return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_low[nr])); |
358 | } | 362 | } |
359 | static ssize_t set_temp_max(struct device *dev, const char *buf, | 363 | static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, |
360 | size_t count, int nr) | 364 | const char *buf, size_t count) |
361 | { | 365 | { |
366 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
367 | int nr = sensor_attr->index; | ||
368 | |||
362 | struct i2c_client *client = to_i2c_client(dev); | 369 | struct i2c_client *client = to_i2c_client(dev); |
363 | struct it87_data *data = i2c_get_clientdata(client); | 370 | struct it87_data *data = i2c_get_clientdata(client); |
364 | int val = simple_strtol(buf, NULL, 10); | 371 | int val = simple_strtol(buf, NULL, 10); |
@@ -369,9 +376,12 @@ static ssize_t set_temp_max(struct device *dev, const char *buf, | |||
369 | up(&data->update_lock); | 376 | up(&data->update_lock); |
370 | return count; | 377 | return count; |
371 | } | 378 | } |
372 | static ssize_t set_temp_min(struct device *dev, const char *buf, | 379 | static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr, |
373 | size_t count, int nr) | 380 | const char *buf, size_t count) |
374 | { | 381 | { |
382 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
383 | int nr = sensor_attr->index; | ||
384 | |||
375 | struct i2c_client *client = to_i2c_client(dev); | 385 | struct i2c_client *client = to_i2c_client(dev); |
376 | struct it87_data *data = i2c_get_clientdata(client); | 386 | struct it87_data *data = i2c_get_clientdata(client); |
377 | int val = simple_strtol(buf, NULL, 10); | 387 | int val = simple_strtol(buf, NULL, 10); |
@@ -383,42 +393,23 @@ static ssize_t set_temp_min(struct device *dev, const char *buf, | |||
383 | return count; | 393 | return count; |
384 | } | 394 | } |
385 | #define show_temp_offset(offset) \ | 395 | #define show_temp_offset(offset) \ |
386 | static ssize_t show_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ | 396 | static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \ |
387 | { \ | 397 | show_temp, NULL, offset - 1); \ |
388 | return show_temp(dev, buf, offset - 1); \ | 398 | static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ |
389 | } \ | 399 | show_temp_max, set_temp_max, offset - 1); \ |
390 | static ssize_t \ | 400 | static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ |
391 | show_temp_##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ | 401 | show_temp_min, set_temp_min, offset - 1); |
392 | { \ | ||
393 | return show_temp_max(dev, buf, offset - 1); \ | ||
394 | } \ | ||
395 | static ssize_t \ | ||
396 | show_temp_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ | ||
397 | { \ | ||
398 | return show_temp_min(dev, buf, offset - 1); \ | ||
399 | } \ | ||
400 | static ssize_t set_temp_##offset##_max (struct device *dev, struct device_attribute *attr, \ | ||
401 | const char *buf, size_t count) \ | ||
402 | { \ | ||
403 | return set_temp_max(dev, buf, count, offset - 1); \ | ||
404 | } \ | ||
405 | static ssize_t set_temp_##offset##_min (struct device *dev, struct device_attribute *attr, \ | ||
406 | const char *buf, size_t count) \ | ||
407 | { \ | ||
408 | return set_temp_min(dev, buf, count, offset - 1); \ | ||
409 | } \ | ||
410 | static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, NULL); \ | ||
411 | static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ | ||
412 | show_temp_##offset##_max, set_temp_##offset##_max); \ | ||
413 | static DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ | ||
414 | show_temp_##offset##_min, set_temp_##offset##_min); | ||
415 | 402 | ||
416 | show_temp_offset(1); | 403 | show_temp_offset(1); |
417 | show_temp_offset(2); | 404 | show_temp_offset(2); |
418 | show_temp_offset(3); | 405 | show_temp_offset(3); |
419 | 406 | ||
420 | static ssize_t show_sensor(struct device *dev, char *buf, int nr) | 407 | static ssize_t show_sensor(struct device *dev, struct device_attribute *attr, |
408 | char *buf) | ||
421 | { | 409 | { |
410 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
411 | int nr = sensor_attr->index; | ||
412 | |||
422 | struct it87_data *data = it87_update_device(dev); | 413 | struct it87_data *data = it87_update_device(dev); |
423 | u8 reg = data->sensor; /* In case the value is updated while we use it */ | 414 | u8 reg = data->sensor; /* In case the value is updated while we use it */ |
424 | 415 | ||
@@ -428,9 +419,12 @@ static ssize_t show_sensor(struct device *dev, char *buf, int nr) | |||
428 | return sprintf(buf, "2\n"); /* thermistor */ | 419 | return sprintf(buf, "2\n"); /* thermistor */ |
429 | return sprintf(buf, "0\n"); /* disabled */ | 420 | return sprintf(buf, "0\n"); /* disabled */ |
430 | } | 421 | } |
431 | static ssize_t set_sensor(struct device *dev, const char *buf, | 422 | static ssize_t set_sensor(struct device *dev, struct device_attribute *attr, |
432 | size_t count, int nr) | 423 | const char *buf, size_t count) |
433 | { | 424 | { |
425 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
426 | int nr = sensor_attr->index; | ||
427 | |||
434 | struct i2c_client *client = to_i2c_client(dev); | 428 | struct i2c_client *client = to_i2c_client(dev); |
435 | struct it87_data *data = i2c_get_clientdata(client); | 429 | struct it87_data *data = i2c_get_clientdata(client); |
436 | int val = simple_strtol(buf, NULL, 10); | 430 | int val = simple_strtol(buf, NULL, 10); |
@@ -453,53 +447,67 @@ static ssize_t set_sensor(struct device *dev, const char *buf, | |||
453 | return count; | 447 | return count; |
454 | } | 448 | } |
455 | #define show_sensor_offset(offset) \ | 449 | #define show_sensor_offset(offset) \ |
456 | static ssize_t show_sensor_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ | 450 | static SENSOR_DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \ |
457 | { \ | 451 | show_sensor, set_sensor, offset - 1); |
458 | return show_sensor(dev, buf, offset - 1); \ | ||
459 | } \ | ||
460 | static ssize_t set_sensor_##offset (struct device *dev, struct device_attribute *attr, \ | ||
461 | const char *buf, size_t count) \ | ||
462 | { \ | ||
463 | return set_sensor(dev, buf, count, offset - 1); \ | ||
464 | } \ | ||
465 | static DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \ | ||
466 | show_sensor_##offset, set_sensor_##offset); | ||
467 | 452 | ||
468 | show_sensor_offset(1); | 453 | show_sensor_offset(1); |
469 | show_sensor_offset(2); | 454 | show_sensor_offset(2); |
470 | show_sensor_offset(3); | 455 | show_sensor_offset(3); |
471 | 456 | ||
472 | /* 3 Fans */ | 457 | /* 3 Fans */ |
473 | static ssize_t show_fan(struct device *dev, char *buf, int nr) | 458 | static ssize_t show_fan(struct device *dev, struct device_attribute *attr, |
459 | char *buf) | ||
474 | { | 460 | { |
461 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
462 | int nr = sensor_attr->index; | ||
463 | |||
475 | struct it87_data *data = it87_update_device(dev); | 464 | struct it87_data *data = it87_update_device(dev); |
476 | return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan[nr], | 465 | return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan[nr], |
477 | DIV_FROM_REG(data->fan_div[nr]))); | 466 | DIV_FROM_REG(data->fan_div[nr]))); |
478 | } | 467 | } |
479 | static ssize_t show_fan_min(struct device *dev, char *buf, int nr) | 468 | static ssize_t show_fan_min(struct device *dev, struct device_attribute *attr, |
469 | char *buf) | ||
480 | { | 470 | { |
471 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
472 | int nr = sensor_attr->index; | ||
473 | |||
481 | struct it87_data *data = it87_update_device(dev); | 474 | struct it87_data *data = it87_update_device(dev); |
482 | return sprintf(buf,"%d\n", | 475 | return sprintf(buf,"%d\n", |
483 | FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr]))); | 476 | FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr]))); |
484 | } | 477 | } |
485 | static ssize_t show_fan_div(struct device *dev, char *buf, int nr) | 478 | static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr, |
479 | char *buf) | ||
486 | { | 480 | { |
481 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
482 | int nr = sensor_attr->index; | ||
483 | |||
487 | struct it87_data *data = it87_update_device(dev); | 484 | struct it87_data *data = it87_update_device(dev); |
488 | return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr])); | 485 | return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr])); |
489 | } | 486 | } |
490 | static ssize_t show_pwm_enable(struct device *dev, char *buf, int nr) | 487 | static ssize_t show_pwm_enable(struct device *dev, struct device_attribute *attr, |
488 | char *buf) | ||
491 | { | 489 | { |
490 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
491 | int nr = sensor_attr->index; | ||
492 | |||
492 | struct it87_data *data = it87_update_device(dev); | 493 | struct it87_data *data = it87_update_device(dev); |
493 | return sprintf(buf,"%d\n", (data->fan_main_ctrl & (1 << nr)) ? 1 : 0); | 494 | return sprintf(buf,"%d\n", (data->fan_main_ctrl & (1 << nr)) ? 1 : 0); |
494 | } | 495 | } |
495 | static ssize_t show_pwm(struct device *dev, char *buf, int nr) | 496 | static ssize_t show_pwm(struct device *dev, struct device_attribute *attr, |
497 | char *buf) | ||
496 | { | 498 | { |
499 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
500 | int nr = sensor_attr->index; | ||
501 | |||
497 | struct it87_data *data = it87_update_device(dev); | 502 | struct it87_data *data = it87_update_device(dev); |
498 | return sprintf(buf,"%d\n", data->manual_pwm_ctl[nr]); | 503 | return sprintf(buf,"%d\n", data->manual_pwm_ctl[nr]); |
499 | } | 504 | } |
500 | static ssize_t set_fan_min(struct device *dev, const char *buf, | 505 | static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, |
501 | size_t count, int nr) | 506 | const char *buf, size_t count) |
502 | { | 507 | { |
508 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
509 | int nr = sensor_attr->index; | ||
510 | |||
503 | struct i2c_client *client = to_i2c_client(dev); | 511 | struct i2c_client *client = to_i2c_client(dev); |
504 | struct it87_data *data = i2c_get_clientdata(client); | 512 | struct it87_data *data = i2c_get_clientdata(client); |
505 | int val = simple_strtol(buf, NULL, 10); | 513 | int val = simple_strtol(buf, NULL, 10); |
@@ -510,9 +518,12 @@ static ssize_t set_fan_min(struct device *dev, const char *buf, | |||
510 | up(&data->update_lock); | 518 | up(&data->update_lock); |
511 | return count; | 519 | return count; |
512 | } | 520 | } |
513 | static ssize_t set_fan_div(struct device *dev, const char *buf, | 521 | static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, |
514 | size_t count, int nr) | 522 | const char *buf, size_t count) |
515 | { | 523 | { |
524 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
525 | int nr = sensor_attr->index; | ||
526 | |||
516 | struct i2c_client *client = to_i2c_client(dev); | 527 | struct i2c_client *client = to_i2c_client(dev); |
517 | struct it87_data *data = i2c_get_clientdata(client); | 528 | struct it87_data *data = i2c_get_clientdata(client); |
518 | int val = simple_strtol(buf, NULL, 10); | 529 | int val = simple_strtol(buf, NULL, 10); |
@@ -550,9 +561,12 @@ static ssize_t set_fan_div(struct device *dev, const char *buf, | |||
550 | up(&data->update_lock); | 561 | up(&data->update_lock); |
551 | return count; | 562 | return count; |
552 | } | 563 | } |
553 | static ssize_t set_pwm_enable(struct device *dev, const char *buf, | 564 | static ssize_t set_pwm_enable(struct device *dev, |
554 | size_t count, int nr) | 565 | struct device_attribute *attr, const char *buf, size_t count) |
555 | { | 566 | { |
567 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
568 | int nr = sensor_attr->index; | ||
569 | |||
556 | struct i2c_client *client = to_i2c_client(dev); | 570 | struct i2c_client *client = to_i2c_client(dev); |
557 | struct it87_data *data = i2c_get_clientdata(client); | 571 | struct it87_data *data = i2c_get_clientdata(client); |
558 | int val = simple_strtol(buf, NULL, 10); | 572 | int val = simple_strtol(buf, NULL, 10); |
@@ -581,9 +595,12 @@ static ssize_t set_pwm_enable(struct device *dev, const char *buf, | |||
581 | up(&data->update_lock); | 595 | up(&data->update_lock); |
582 | return count; | 596 | return count; |
583 | } | 597 | } |
584 | static ssize_t set_pwm(struct device *dev, const char *buf, | 598 | static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, |
585 | size_t count, int nr) | 599 | const char *buf, size_t count) |
586 | { | 600 | { |
601 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
602 | int nr = sensor_attr->index; | ||
603 | |||
587 | struct i2c_client *client = to_i2c_client(dev); | 604 | struct i2c_client *client = to_i2c_client(dev); |
588 | struct it87_data *data = i2c_get_clientdata(client); | 605 | struct it87_data *data = i2c_get_clientdata(client); |
589 | int val = simple_strtol(buf, NULL, 10); | 606 | int val = simple_strtol(buf, NULL, 10); |
@@ -599,64 +616,23 @@ static ssize_t set_pwm(struct device *dev, const char *buf, | |||
599 | return count; | 616 | return count; |
600 | } | 617 | } |
601 | 618 | ||
602 | #define show_fan_offset(offset) \ | 619 | #define show_fan_offset(offset) \ |
603 | static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ | 620 | static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ |
604 | { \ | 621 | show_fan, NULL, offset - 1); \ |
605 | return show_fan(dev, buf, offset - 1); \ | 622 | static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ |
606 | } \ | 623 | show_fan_min, set_fan_min, offset - 1); \ |
607 | static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ | 624 | static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ |
608 | { \ | 625 | show_fan_div, set_fan_div, offset - 1); |
609 | return show_fan_min(dev, buf, offset - 1); \ | ||
610 | } \ | ||
611 | static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \ | ||
612 | { \ | ||
613 | return show_fan_div(dev, buf, offset - 1); \ | ||
614 | } \ | ||
615 | static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \ | ||
616 | const char *buf, size_t count) \ | ||
617 | { \ | ||
618 | return set_fan_min(dev, buf, count, offset - 1); \ | ||
619 | } \ | ||
620 | static ssize_t set_fan_##offset##_div (struct device *dev, struct device_attribute *attr, \ | ||
621 | const char *buf, size_t count) \ | ||
622 | { \ | ||
623 | return set_fan_div(dev, buf, count, offset - 1); \ | ||
624 | } \ | ||
625 | static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL); \ | ||
626 | static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ | ||
627 | show_fan_##offset##_min, set_fan_##offset##_min); \ | ||
628 | static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ | ||
629 | show_fan_##offset##_div, set_fan_##offset##_div); | ||
630 | 626 | ||
631 | show_fan_offset(1); | 627 | show_fan_offset(1); |
632 | show_fan_offset(2); | 628 | show_fan_offset(2); |
633 | show_fan_offset(3); | 629 | show_fan_offset(3); |
634 | 630 | ||
635 | #define show_pwm_offset(offset) \ | 631 | #define show_pwm_offset(offset) \ |
636 | static ssize_t show_pwm##offset##_enable (struct device *dev, struct device_attribute *attr, \ | 632 | static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \ |
637 | char *buf) \ | 633 | show_pwm_enable, set_pwm_enable, offset - 1); \ |
638 | { \ | 634 | static SENSOR_DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ |
639 | return show_pwm_enable(dev, buf, offset - 1); \ | 635 | show_pwm, set_pwm, offset - 1); |
640 | } \ | ||
641 | static ssize_t show_pwm##offset (struct device *dev, struct device_attribute *attr, char *buf) \ | ||
642 | { \ | ||
643 | return show_pwm(dev, buf, offset - 1); \ | ||
644 | } \ | ||
645 | static ssize_t set_pwm##offset##_enable (struct device *dev, struct device_attribute *attr, \ | ||
646 | const char *buf, size_t count) \ | ||
647 | { \ | ||
648 | return set_pwm_enable(dev, buf, count, offset - 1); \ | ||
649 | } \ | ||
650 | static ssize_t set_pwm##offset (struct device *dev, struct device_attribute *attr, \ | ||
651 | const char *buf, size_t count) \ | ||
652 | { \ | ||
653 | return set_pwm(dev, buf, count, offset - 1); \ | ||
654 | } \ | ||
655 | static DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \ | ||
656 | show_pwm##offset##_enable, \ | ||
657 | set_pwm##offset##_enable); \ | ||
658 | static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ | ||
659 | show_pwm##offset , set_pwm##offset ); | ||
660 | 636 | ||
661 | show_pwm_offset(1); | 637 | show_pwm_offset(1); |
662 | show_pwm_offset(2); | 638 | show_pwm_offset(2); |
@@ -666,7 +642,7 @@ show_pwm_offset(3); | |||
666 | static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) | 642 | static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) |
667 | { | 643 | { |
668 | struct it87_data *data = it87_update_device(dev); | 644 | struct it87_data *data = it87_update_device(dev); |
669 | return sprintf(buf,"%d\n", ALARMS_FROM_REG(data->alarms)); | 645 | return sprintf(buf, "%u\n", data->alarms); |
670 | } | 646 | } |
671 | static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); | 647 | static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); |
672 | 648 | ||
@@ -864,60 +840,60 @@ int it87_detect(struct i2c_adapter *adapter, int address, int kind) | |||
864 | it87_init_client(new_client, data); | 840 | it87_init_client(new_client, data); |
865 | 841 | ||
866 | /* Register sysfs hooks */ | 842 | /* Register sysfs hooks */ |
867 | device_create_file(&new_client->dev, &dev_attr_in0_input); | 843 | device_create_file(&new_client->dev, &sensor_dev_attr_in0_input.dev_attr); |
868 | device_create_file(&new_client->dev, &dev_attr_in1_input); | 844 | device_create_file(&new_client->dev, &sensor_dev_attr_in1_input.dev_attr); |
869 | device_create_file(&new_client->dev, &dev_attr_in2_input); | 845 | device_create_file(&new_client->dev, &sensor_dev_attr_in2_input.dev_attr); |
870 | device_create_file(&new_client->dev, &dev_attr_in3_input); | 846 | device_create_file(&new_client->dev, &sensor_dev_attr_in3_input.dev_attr); |
871 | device_create_file(&new_client->dev, &dev_attr_in4_input); | 847 | device_create_file(&new_client->dev, &sensor_dev_attr_in4_input.dev_attr); |
872 | device_create_file(&new_client->dev, &dev_attr_in5_input); | 848 | device_create_file(&new_client->dev, &sensor_dev_attr_in5_input.dev_attr); |
873 | device_create_file(&new_client->dev, &dev_attr_in6_input); | 849 | device_create_file(&new_client->dev, &sensor_dev_attr_in6_input.dev_attr); |
874 | device_create_file(&new_client->dev, &dev_attr_in7_input); | 850 | device_create_file(&new_client->dev, &sensor_dev_attr_in7_input.dev_attr); |
875 | device_create_file(&new_client->dev, &dev_attr_in8_input); | 851 | device_create_file(&new_client->dev, &sensor_dev_attr_in8_input.dev_attr); |
876 | device_create_file(&new_client->dev, &dev_attr_in0_min); | 852 | device_create_file(&new_client->dev, &sensor_dev_attr_in0_min.dev_attr); |
877 | device_create_file(&new_client->dev, &dev_attr_in1_min); | 853 | device_create_file(&new_client->dev, &sensor_dev_attr_in1_min.dev_attr); |
878 | device_create_file(&new_client->dev, &dev_attr_in2_min); | 854 | device_create_file(&new_client->dev, &sensor_dev_attr_in2_min.dev_attr); |
879 | device_create_file(&new_client->dev, &dev_attr_in3_min); | 855 | device_create_file(&new_client->dev, &sensor_dev_attr_in3_min.dev_attr); |
880 | device_create_file(&new_client->dev, &dev_attr_in4_min); | 856 | device_create_file(&new_client->dev, &sensor_dev_attr_in4_min.dev_attr); |
881 | device_create_file(&new_client->dev, &dev_attr_in5_min); | 857 | device_create_file(&new_client->dev, &sensor_dev_attr_in5_min.dev_attr); |
882 | device_create_file(&new_client->dev, &dev_attr_in6_min); | 858 | device_create_file(&new_client->dev, &sensor_dev_attr_in6_min.dev_attr); |
883 | device_create_file(&new_client->dev, &dev_attr_in7_min); | 859 | device_create_file(&new_client->dev, &sensor_dev_attr_in7_min.dev_attr); |
884 | device_create_file(&new_client->dev, &dev_attr_in0_max); | 860 | device_create_file(&new_client->dev, &sensor_dev_attr_in0_max.dev_attr); |
885 | device_create_file(&new_client->dev, &dev_attr_in1_max); | 861 | device_create_file(&new_client->dev, &sensor_dev_attr_in1_max.dev_attr); |
886 | device_create_file(&new_client->dev, &dev_attr_in2_max); | 862 | device_create_file(&new_client->dev, &sensor_dev_attr_in2_max.dev_attr); |
887 | device_create_file(&new_client->dev, &dev_attr_in3_max); | 863 | device_create_file(&new_client->dev, &sensor_dev_attr_in3_max.dev_attr); |
888 | device_create_file(&new_client->dev, &dev_attr_in4_max); | 864 | device_create_file(&new_client->dev, &sensor_dev_attr_in4_max.dev_attr); |
889 | device_create_file(&new_client->dev, &dev_attr_in5_max); | 865 | device_create_file(&new_client->dev, &sensor_dev_attr_in5_max.dev_attr); |
890 | device_create_file(&new_client->dev, &dev_attr_in6_max); | 866 | device_create_file(&new_client->dev, &sensor_dev_attr_in6_max.dev_attr); |
891 | device_create_file(&new_client->dev, &dev_attr_in7_max); | 867 | device_create_file(&new_client->dev, &sensor_dev_attr_in7_max.dev_attr); |
892 | device_create_file(&new_client->dev, &dev_attr_temp1_input); | 868 | device_create_file(&new_client->dev, &sensor_dev_attr_temp1_input.dev_attr); |
893 | device_create_file(&new_client->dev, &dev_attr_temp2_input); | 869 | device_create_file(&new_client->dev, &sensor_dev_attr_temp2_input.dev_attr); |
894 | device_create_file(&new_client->dev, &dev_attr_temp3_input); | 870 | device_create_file(&new_client->dev, &sensor_dev_attr_temp3_input.dev_attr); |
895 | device_create_file(&new_client->dev, &dev_attr_temp1_max); | 871 | device_create_file(&new_client->dev, &sensor_dev_attr_temp1_max.dev_attr); |
896 | device_create_file(&new_client->dev, &dev_attr_temp2_max); | 872 | device_create_file(&new_client->dev, &sensor_dev_attr_temp2_max.dev_attr); |
897 | device_create_file(&new_client->dev, &dev_attr_temp3_max); | 873 | device_create_file(&new_client->dev, &sensor_dev_attr_temp3_max.dev_attr); |
898 | device_create_file(&new_client->dev, &dev_attr_temp1_min); | 874 | device_create_file(&new_client->dev, &sensor_dev_attr_temp1_min.dev_attr); |
899 | device_create_file(&new_client->dev, &dev_attr_temp2_min); | 875 | device_create_file(&new_client->dev, &sensor_dev_attr_temp2_min.dev_attr); |
900 | device_create_file(&new_client->dev, &dev_attr_temp3_min); | 876 | device_create_file(&new_client->dev, &sensor_dev_attr_temp3_min.dev_attr); |
901 | device_create_file(&new_client->dev, &dev_attr_temp1_type); | 877 | device_create_file(&new_client->dev, &sensor_dev_attr_temp1_type.dev_attr); |
902 | device_create_file(&new_client->dev, &dev_attr_temp2_type); | 878 | device_create_file(&new_client->dev, &sensor_dev_attr_temp2_type.dev_attr); |
903 | device_create_file(&new_client->dev, &dev_attr_temp3_type); | 879 | device_create_file(&new_client->dev, &sensor_dev_attr_temp3_type.dev_attr); |
904 | device_create_file(&new_client->dev, &dev_attr_fan1_input); | 880 | device_create_file(&new_client->dev, &sensor_dev_attr_fan1_input.dev_attr); |
905 | device_create_file(&new_client->dev, &dev_attr_fan2_input); | 881 | device_create_file(&new_client->dev, &sensor_dev_attr_fan2_input.dev_attr); |
906 | device_create_file(&new_client->dev, &dev_attr_fan3_input); | 882 | device_create_file(&new_client->dev, &sensor_dev_attr_fan3_input.dev_attr); |
907 | device_create_file(&new_client->dev, &dev_attr_fan1_min); | 883 | device_create_file(&new_client->dev, &sensor_dev_attr_fan1_min.dev_attr); |
908 | device_create_file(&new_client->dev, &dev_attr_fan2_min); | 884 | device_create_file(&new_client->dev, &sensor_dev_attr_fan2_min.dev_attr); |
909 | device_create_file(&new_client->dev, &dev_attr_fan3_min); | 885 | device_create_file(&new_client->dev, &sensor_dev_attr_fan3_min.dev_attr); |
910 | device_create_file(&new_client->dev, &dev_attr_fan1_div); | 886 | device_create_file(&new_client->dev, &sensor_dev_attr_fan1_div.dev_attr); |
911 | device_create_file(&new_client->dev, &dev_attr_fan2_div); | 887 | device_create_file(&new_client->dev, &sensor_dev_attr_fan2_div.dev_attr); |
912 | device_create_file(&new_client->dev, &dev_attr_fan3_div); | 888 | device_create_file(&new_client->dev, &sensor_dev_attr_fan3_div.dev_attr); |
913 | device_create_file(&new_client->dev, &dev_attr_alarms); | 889 | device_create_file(&new_client->dev, &dev_attr_alarms); |
914 | if (enable_pwm_interface) { | 890 | if (enable_pwm_interface) { |
915 | device_create_file(&new_client->dev, &dev_attr_pwm1_enable); | 891 | device_create_file(&new_client->dev, &sensor_dev_attr_pwm1_enable.dev_attr); |
916 | device_create_file(&new_client->dev, &dev_attr_pwm2_enable); | 892 | device_create_file(&new_client->dev, &sensor_dev_attr_pwm2_enable.dev_attr); |
917 | device_create_file(&new_client->dev, &dev_attr_pwm3_enable); | 893 | device_create_file(&new_client->dev, &sensor_dev_attr_pwm3_enable.dev_attr); |
918 | device_create_file(&new_client->dev, &dev_attr_pwm1); | 894 | device_create_file(&new_client->dev, &sensor_dev_attr_pwm1.dev_attr); |
919 | device_create_file(&new_client->dev, &dev_attr_pwm2); | 895 | device_create_file(&new_client->dev, &sensor_dev_attr_pwm2.dev_attr); |
920 | device_create_file(&new_client->dev, &dev_attr_pwm3); | 896 | device_create_file(&new_client->dev, &sensor_dev_attr_pwm3.dev_attr); |
921 | } | 897 | } |
922 | 898 | ||
923 | if (data->type == it8712) { | 899 | if (data->type == it8712) { |
@@ -954,7 +930,7 @@ static int it87_detach_client(struct i2c_client *client) | |||
954 | return 0; | 930 | return 0; |
955 | } | 931 | } |
956 | 932 | ||
957 | /* The SMBus locks itself, but ISA access must be locked explicitely! | 933 | /* The SMBus locks itself, but ISA access must be locked explicitly! |
958 | We don't want to lock the whole ISA bus, so we lock each client | 934 | We don't want to lock the whole ISA bus, so we lock each client |
959 | separately. | 935 | separately. |
960 | We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks, | 936 | We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks, |
@@ -974,7 +950,7 @@ static int it87_read_value(struct i2c_client *client, u8 reg) | |||
974 | return i2c_smbus_read_byte_data(client, reg); | 950 | return i2c_smbus_read_byte_data(client, reg); |
975 | } | 951 | } |
976 | 952 | ||
977 | /* The SMBus locks itself, but ISA access muse be locked explicitely! | 953 | /* The SMBus locks itself, but ISA access muse be locked explicitly! |
978 | We don't want to lock the whole ISA bus, so we lock each client | 954 | We don't want to lock the whole ISA bus, so we lock each client |
979 | separately. | 955 | separately. |
980 | We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks, | 956 | We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks, |
diff --git a/drivers/i2c/chips/lm63.c b/drivers/i2c/chips/lm63.c index bc68e031392b..7c6f9ea5a254 100644 --- a/drivers/i2c/chips/lm63.c +++ b/drivers/i2c/chips/lm63.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * lm63.c - driver for the National Semiconductor LM63 temperature sensor | 2 | * lm63.c - driver for the National Semiconductor LM63 temperature sensor |
3 | * with integrated fan control | 3 | * with integrated fan control |
4 | * Copyright (C) 2004 Jean Delvare <khali@linux-fr.org> | 4 | * Copyright (C) 2004-2005 Jean Delvare <khali@linux-fr.org> |
5 | * Based on the lm90 driver. | 5 | * Based on the lm90 driver. |
6 | * | 6 | * |
7 | * The LM63 is a sensor chip made by National Semiconductor. It measures | 7 | * The LM63 is a sensor chip made by National Semiconductor. It measures |
@@ -37,13 +37,13 @@ | |||
37 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 37 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
38 | */ | 38 | */ |
39 | 39 | ||
40 | #include <linux/config.h> | ||
41 | #include <linux/module.h> | 40 | #include <linux/module.h> |
42 | #include <linux/init.h> | 41 | #include <linux/init.h> |
43 | #include <linux/slab.h> | 42 | #include <linux/slab.h> |
44 | #include <linux/jiffies.h> | 43 | #include <linux/jiffies.h> |
45 | #include <linux/i2c.h> | 44 | #include <linux/i2c.h> |
46 | #include <linux/i2c-sensor.h> | 45 | #include <linux/i2c-sensor.h> |
46 | #include <linux/hwmon-sysfs.h> | ||
47 | 47 | ||
48 | /* | 48 | /* |
49 | * Addresses to scan | 49 | * Addresses to scan |
@@ -99,9 +99,9 @@ SENSORS_INSMOD_1(lm63); | |||
99 | * Conversions and various macros | 99 | * Conversions and various macros |
100 | * For tachometer counts, the LM63 uses 16-bit values. | 100 | * For tachometer counts, the LM63 uses 16-bit values. |
101 | * For local temperature and high limit, remote critical limit and hysteresis | 101 | * For local temperature and high limit, remote critical limit and hysteresis |
102 | * value, it uses signed 8-bit values with LSB = 1 degree Celcius. | 102 | * value, it uses signed 8-bit values with LSB = 1 degree Celsius. |
103 | * For remote temperature, low and high limits, it uses signed 11-bit values | 103 | * For remote temperature, low and high limits, it uses signed 11-bit values |
104 | * with LSB = 0.125 degree Celcius, left-justified in 16-bit registers. | 104 | * with LSB = 0.125 degree Celsius, left-justified in 16-bit registers. |
105 | */ | 105 | */ |
106 | 106 | ||
107 | #define FAN_FROM_REG(reg) ((reg) == 0xFFFC || (reg) == 0 ? 0 : \ | 107 | #define FAN_FROM_REG(reg) ((reg) == 0xFFFC || (reg) == 0 ? 0 : \ |
@@ -158,16 +158,16 @@ struct lm63_data { | |||
158 | 158 | ||
159 | /* registers values */ | 159 | /* registers values */ |
160 | u8 config, config_fan; | 160 | u8 config, config_fan; |
161 | u16 fan1_input; | 161 | u16 fan[2]; /* 0: input |
162 | u16 fan1_low; | 162 | 1: low limit */ |
163 | u8 pwm1_freq; | 163 | u8 pwm1_freq; |
164 | u8 pwm1_value; | 164 | u8 pwm1_value; |
165 | s8 temp1_input; | 165 | s8 temp8[3]; /* 0: local input |
166 | s8 temp1_high; | 166 | 1: local high limit |
167 | s16 temp2_input; | 167 | 2: remote critical limit */ |
168 | s16 temp2_high; | 168 | s16 temp11[3]; /* 0: remote input |
169 | s16 temp2_low; | 169 | 1: remote low limit |
170 | s8 temp2_crit; | 170 | 2: remote high limit */ |
171 | u8 temp2_crit_hyst; | 171 | u8 temp2_crit_hyst; |
172 | u8 alarms; | 172 | u8 alarms; |
173 | }; | 173 | }; |
@@ -176,33 +176,33 @@ struct lm63_data { | |||
176 | * Sysfs callback functions and files | 176 | * Sysfs callback functions and files |
177 | */ | 177 | */ |
178 | 178 | ||
179 | #define show_fan(value) \ | 179 | static ssize_t show_fan(struct device *dev, struct device_attribute *devattr, |
180 | static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ | 180 | char *buf) |
181 | { \ | 181 | { |
182 | struct lm63_data *data = lm63_update_device(dev); \ | 182 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
183 | return sprintf(buf, "%d\n", FAN_FROM_REG(data->value)); \ | 183 | struct lm63_data *data = lm63_update_device(dev); |
184 | return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[attr->index])); | ||
184 | } | 185 | } |
185 | show_fan(fan1_input); | ||
186 | show_fan(fan1_low); | ||
187 | 186 | ||
188 | static ssize_t set_fan1_low(struct device *dev, struct device_attribute *attr, const char *buf, | 187 | static ssize_t set_fan(struct device *dev, struct device_attribute *dummy, |
189 | size_t count) | 188 | const char *buf, size_t count) |
190 | { | 189 | { |
191 | struct i2c_client *client = to_i2c_client(dev); | 190 | struct i2c_client *client = to_i2c_client(dev); |
192 | struct lm63_data *data = i2c_get_clientdata(client); | 191 | struct lm63_data *data = i2c_get_clientdata(client); |
193 | unsigned long val = simple_strtoul(buf, NULL, 10); | 192 | unsigned long val = simple_strtoul(buf, NULL, 10); |
194 | 193 | ||
195 | down(&data->update_lock); | 194 | down(&data->update_lock); |
196 | data->fan1_low = FAN_TO_REG(val); | 195 | data->fan[1] = FAN_TO_REG(val); |
197 | i2c_smbus_write_byte_data(client, LM63_REG_TACH_LIMIT_LSB, | 196 | i2c_smbus_write_byte_data(client, LM63_REG_TACH_LIMIT_LSB, |
198 | data->fan1_low & 0xFF); | 197 | data->fan[1] & 0xFF); |
199 | i2c_smbus_write_byte_data(client, LM63_REG_TACH_LIMIT_MSB, | 198 | i2c_smbus_write_byte_data(client, LM63_REG_TACH_LIMIT_MSB, |
200 | data->fan1_low >> 8); | 199 | data->fan[1] >> 8); |
201 | up(&data->update_lock); | 200 | up(&data->update_lock); |
202 | return count; | 201 | return count; |
203 | } | 202 | } |
204 | 203 | ||
205 | static ssize_t show_pwm1(struct device *dev, struct device_attribute *attr, char *buf) | 204 | static ssize_t show_pwm1(struct device *dev, struct device_attribute *dummy, |
205 | char *buf) | ||
206 | { | 206 | { |
207 | struct lm63_data *data = lm63_update_device(dev); | 207 | struct lm63_data *data = lm63_update_device(dev); |
208 | return sprintf(buf, "%d\n", data->pwm1_value >= 2 * data->pwm1_freq ? | 208 | return sprintf(buf, "%d\n", data->pwm1_value >= 2 * data->pwm1_freq ? |
@@ -210,7 +210,8 @@ static ssize_t show_pwm1(struct device *dev, struct device_attribute *attr, char | |||
210 | (2 * data->pwm1_freq)); | 210 | (2 * data->pwm1_freq)); |
211 | } | 211 | } |
212 | 212 | ||
213 | static ssize_t set_pwm1(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | 213 | static ssize_t set_pwm1(struct device *dev, struct device_attribute *dummy, |
214 | const char *buf, size_t count) | ||
214 | { | 215 | { |
215 | struct i2c_client *client = to_i2c_client(dev); | 216 | struct i2c_client *client = to_i2c_client(dev); |
216 | struct lm63_data *data = i2c_get_clientdata(client); | 217 | struct lm63_data *data = i2c_get_clientdata(client); |
@@ -229,77 +230,83 @@ static ssize_t set_pwm1(struct device *dev, struct device_attribute *attr, const | |||
229 | return count; | 230 | return count; |
230 | } | 231 | } |
231 | 232 | ||
232 | static ssize_t show_pwm1_enable(struct device *dev, struct device_attribute *attr, char *buf) | 233 | static ssize_t show_pwm1_enable(struct device *dev, struct device_attribute *dummy, |
234 | char *buf) | ||
233 | { | 235 | { |
234 | struct lm63_data *data = lm63_update_device(dev); | 236 | struct lm63_data *data = lm63_update_device(dev); |
235 | return sprintf(buf, "%d\n", data->config_fan & 0x20 ? 1 : 2); | 237 | return sprintf(buf, "%d\n", data->config_fan & 0x20 ? 1 : 2); |
236 | } | 238 | } |
237 | 239 | ||
238 | #define show_temp8(value) \ | 240 | static ssize_t show_temp8(struct device *dev, struct device_attribute *devattr, |
239 | static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ | 241 | char *buf) |
240 | { \ | 242 | { |
241 | struct lm63_data *data = lm63_update_device(dev); \ | 243 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
242 | return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->value)); \ | 244 | struct lm63_data *data = lm63_update_device(dev); |
245 | return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp8[attr->index])); | ||
243 | } | 246 | } |
244 | #define show_temp11(value) \ | 247 | |
245 | static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ | 248 | static ssize_t set_temp8(struct device *dev, struct device_attribute *dummy, |
246 | { \ | 249 | const char *buf, size_t count) |
247 | struct lm63_data *data = lm63_update_device(dev); \ | 250 | { |
248 | return sprintf(buf, "%d\n", TEMP11_FROM_REG(data->value)); \ | 251 | struct i2c_client *client = to_i2c_client(dev); |
252 | struct lm63_data *data = i2c_get_clientdata(client); | ||
253 | long val = simple_strtol(buf, NULL, 10); | ||
254 | |||
255 | down(&data->update_lock); | ||
256 | data->temp8[1] = TEMP8_TO_REG(val); | ||
257 | i2c_smbus_write_byte_data(client, LM63_REG_LOCAL_HIGH, data->temp8[1]); | ||
258 | up(&data->update_lock); | ||
259 | return count; | ||
249 | } | 260 | } |
250 | show_temp8(temp1_input); | 261 | |
251 | show_temp8(temp1_high); | 262 | static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr, |
252 | show_temp11(temp2_input); | 263 | char *buf) |
253 | show_temp11(temp2_high); | 264 | { |
254 | show_temp11(temp2_low); | 265 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
255 | show_temp8(temp2_crit); | 266 | struct lm63_data *data = lm63_update_device(dev); |
256 | 267 | return sprintf(buf, "%d\n", TEMP11_FROM_REG(data->temp11[attr->index])); | |
257 | #define set_temp8(value, reg) \ | ||
258 | static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, \ | ||
259 | size_t count) \ | ||
260 | { \ | ||
261 | struct i2c_client *client = to_i2c_client(dev); \ | ||
262 | struct lm63_data *data = i2c_get_clientdata(client); \ | ||
263 | long val = simple_strtol(buf, NULL, 10); \ | ||
264 | \ | ||
265 | down(&data->update_lock); \ | ||
266 | data->value = TEMP8_TO_REG(val); \ | ||
267 | i2c_smbus_write_byte_data(client, reg, data->value); \ | ||
268 | up(&data->update_lock); \ | ||
269 | return count; \ | ||
270 | } | 268 | } |
271 | #define set_temp11(value, reg_msb, reg_lsb) \ | 269 | |
272 | static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, \ | 270 | static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr, |
273 | size_t count) \ | 271 | const char *buf, size_t count) |
274 | { \ | 272 | { |
275 | struct i2c_client *client = to_i2c_client(dev); \ | 273 | static const u8 reg[4] = { |
276 | struct lm63_data *data = i2c_get_clientdata(client); \ | 274 | LM63_REG_REMOTE_LOW_MSB, |
277 | long val = simple_strtol(buf, NULL, 10); \ | 275 | LM63_REG_REMOTE_LOW_LSB, |
278 | \ | 276 | LM63_REG_REMOTE_HIGH_MSB, |
279 | down(&data->update_lock); \ | 277 | LM63_REG_REMOTE_HIGH_LSB, |
280 | data->value = TEMP11_TO_REG(val); \ | 278 | }; |
281 | i2c_smbus_write_byte_data(client, reg_msb, data->value >> 8); \ | 279 | |
282 | i2c_smbus_write_byte_data(client, reg_lsb, data->value & 0xff); \ | 280 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
283 | up(&data->update_lock); \ | 281 | struct i2c_client *client = to_i2c_client(dev); |
284 | return count; \ | 282 | struct lm63_data *data = i2c_get_clientdata(client); |
283 | long val = simple_strtol(buf, NULL, 10); | ||
284 | int nr = attr->index; | ||
285 | |||
286 | down(&data->update_lock); | ||
287 | data->temp11[nr] = TEMP11_TO_REG(val); | ||
288 | i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2], | ||
289 | data->temp11[nr] >> 8); | ||
290 | i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2 + 1], | ||
291 | data->temp11[nr] & 0xff); | ||
292 | up(&data->update_lock); | ||
293 | return count; | ||
285 | } | 294 | } |
286 | set_temp8(temp1_high, LM63_REG_LOCAL_HIGH); | ||
287 | set_temp11(temp2_high, LM63_REG_REMOTE_HIGH_MSB, LM63_REG_REMOTE_HIGH_LSB); | ||
288 | set_temp11(temp2_low, LM63_REG_REMOTE_LOW_MSB, LM63_REG_REMOTE_LOW_LSB); | ||
289 | 295 | ||
290 | /* Hysteresis register holds a relative value, while we want to present | 296 | /* Hysteresis register holds a relative value, while we want to present |
291 | an absolute to user-space */ | 297 | an absolute to user-space */ |
292 | static ssize_t show_temp2_crit_hyst(struct device *dev, struct device_attribute *attr, char *buf) | 298 | static ssize_t show_temp2_crit_hyst(struct device *dev, struct device_attribute *dummy, |
299 | char *buf) | ||
293 | { | 300 | { |
294 | struct lm63_data *data = lm63_update_device(dev); | 301 | struct lm63_data *data = lm63_update_device(dev); |
295 | return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp2_crit) | 302 | return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp8[2]) |
296 | - TEMP8_FROM_REG(data->temp2_crit_hyst)); | 303 | - TEMP8_FROM_REG(data->temp2_crit_hyst)); |
297 | } | 304 | } |
298 | 305 | ||
299 | /* And now the other way around, user-space provides an absolute | 306 | /* And now the other way around, user-space provides an absolute |
300 | hysteresis value and we have to store a relative one */ | 307 | hysteresis value and we have to store a relative one */ |
301 | static ssize_t set_temp2_crit_hyst(struct device *dev, struct device_attribute *attr, const char *buf, | 308 | static ssize_t set_temp2_crit_hyst(struct device *dev, struct device_attribute *dummy, |
302 | size_t count) | 309 | const char *buf, size_t count) |
303 | { | 310 | { |
304 | struct i2c_client *client = to_i2c_client(dev); | 311 | struct i2c_client *client = to_i2c_client(dev); |
305 | struct lm63_data *data = i2c_get_clientdata(client); | 312 | struct lm63_data *data = i2c_get_clientdata(client); |
@@ -307,36 +314,37 @@ static ssize_t set_temp2_crit_hyst(struct device *dev, struct device_attribute * | |||
307 | long hyst; | 314 | long hyst; |
308 | 315 | ||
309 | down(&data->update_lock); | 316 | down(&data->update_lock); |
310 | hyst = TEMP8_FROM_REG(data->temp2_crit) - val; | 317 | hyst = TEMP8_FROM_REG(data->temp8[2]) - val; |
311 | i2c_smbus_write_byte_data(client, LM63_REG_REMOTE_TCRIT_HYST, | 318 | i2c_smbus_write_byte_data(client, LM63_REG_REMOTE_TCRIT_HYST, |
312 | HYST_TO_REG(hyst)); | 319 | HYST_TO_REG(hyst)); |
313 | up(&data->update_lock); | 320 | up(&data->update_lock); |
314 | return count; | 321 | return count; |
315 | } | 322 | } |
316 | 323 | ||
317 | static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) | 324 | static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy, |
325 | char *buf) | ||
318 | { | 326 | { |
319 | struct lm63_data *data = lm63_update_device(dev); | 327 | struct lm63_data *data = lm63_update_device(dev); |
320 | return sprintf(buf, "%u\n", data->alarms); | 328 | return sprintf(buf, "%u\n", data->alarms); |
321 | } | 329 | } |
322 | 330 | ||
323 | static DEVICE_ATTR(fan1_input, S_IRUGO, show_fan1_input, NULL); | 331 | static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0); |
324 | static DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan1_low, | 332 | static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan, |
325 | set_fan1_low); | 333 | set_fan, 1); |
326 | 334 | ||
327 | static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm1, set_pwm1); | 335 | static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm1, set_pwm1); |
328 | static DEVICE_ATTR(pwm1_enable, S_IRUGO, show_pwm1_enable, NULL); | 336 | static DEVICE_ATTR(pwm1_enable, S_IRUGO, show_pwm1_enable, NULL); |
329 | 337 | ||
330 | static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp1_input, NULL); | 338 | static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp8, NULL, 0); |
331 | static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp1_high, | 339 | static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp8, |
332 | set_temp1_high); | 340 | set_temp8, 1); |
333 | 341 | ||
334 | static DEVICE_ATTR(temp2_input, S_IRUGO, show_temp2_input, NULL); | 342 | static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 0); |
335 | static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp2_low, | 343 | static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp11, |
336 | set_temp2_low); | 344 | set_temp11, 1); |
337 | static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp2_high, | 345 | static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp11, |
338 | set_temp2_high); | 346 | set_temp11, 2); |
339 | static DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp2_crit, NULL); | 347 | static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp8, NULL, 2); |
340 | static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp2_crit_hyst, | 348 | static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp2_crit_hyst, |
341 | set_temp2_crit_hyst); | 349 | set_temp2_crit_hyst); |
342 | 350 | ||
@@ -430,17 +438,25 @@ static int lm63_detect(struct i2c_adapter *adapter, int address, int kind) | |||
430 | 438 | ||
431 | /* Register sysfs hooks */ | 439 | /* Register sysfs hooks */ |
432 | if (data->config & 0x04) { /* tachometer enabled */ | 440 | if (data->config & 0x04) { /* tachometer enabled */ |
433 | device_create_file(&new_client->dev, &dev_attr_fan1_input); | 441 | device_create_file(&new_client->dev, |
434 | device_create_file(&new_client->dev, &dev_attr_fan1_min); | 442 | &sensor_dev_attr_fan1_input.dev_attr); |
443 | device_create_file(&new_client->dev, | ||
444 | &sensor_dev_attr_fan1_min.dev_attr); | ||
435 | } | 445 | } |
436 | device_create_file(&new_client->dev, &dev_attr_pwm1); | 446 | device_create_file(&new_client->dev, &dev_attr_pwm1); |
437 | device_create_file(&new_client->dev, &dev_attr_pwm1_enable); | 447 | device_create_file(&new_client->dev, &dev_attr_pwm1_enable); |
438 | device_create_file(&new_client->dev, &dev_attr_temp1_input); | 448 | device_create_file(&new_client->dev, |
439 | device_create_file(&new_client->dev, &dev_attr_temp2_input); | 449 | &sensor_dev_attr_temp1_input.dev_attr); |
440 | device_create_file(&new_client->dev, &dev_attr_temp2_min); | 450 | device_create_file(&new_client->dev, |
441 | device_create_file(&new_client->dev, &dev_attr_temp1_max); | 451 | &sensor_dev_attr_temp2_input.dev_attr); |
442 | device_create_file(&new_client->dev, &dev_attr_temp2_max); | 452 | device_create_file(&new_client->dev, |
443 | device_create_file(&new_client->dev, &dev_attr_temp2_crit); | 453 | &sensor_dev_attr_temp2_min.dev_attr); |
454 | device_create_file(&new_client->dev, | ||
455 | &sensor_dev_attr_temp1_max.dev_attr); | ||
456 | device_create_file(&new_client->dev, | ||
457 | &sensor_dev_attr_temp2_max.dev_attr); | ||
458 | device_create_file(&new_client->dev, | ||
459 | &sensor_dev_attr_temp2_crit.dev_attr); | ||
444 | device_create_file(&new_client->dev, &dev_attr_temp2_crit_hyst); | 460 | device_create_file(&new_client->dev, &dev_attr_temp2_crit_hyst); |
445 | device_create_file(&new_client->dev, &dev_attr_alarms); | 461 | device_create_file(&new_client->dev, &dev_attr_alarms); |
446 | 462 | ||
@@ -511,14 +527,14 @@ static struct lm63_data *lm63_update_device(struct device *dev) | |||
511 | if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { | 527 | if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { |
512 | if (data->config & 0x04) { /* tachometer enabled */ | 528 | if (data->config & 0x04) { /* tachometer enabled */ |
513 | /* order matters for fan1_input */ | 529 | /* order matters for fan1_input */ |
514 | data->fan1_input = i2c_smbus_read_byte_data(client, | 530 | data->fan[0] = i2c_smbus_read_byte_data(client, |
515 | LM63_REG_TACH_COUNT_LSB) & 0xFC; | 531 | LM63_REG_TACH_COUNT_LSB) & 0xFC; |
516 | data->fan1_input |= i2c_smbus_read_byte_data(client, | 532 | data->fan[0] |= i2c_smbus_read_byte_data(client, |
517 | LM63_REG_TACH_COUNT_MSB) << 8; | 533 | LM63_REG_TACH_COUNT_MSB) << 8; |
518 | data->fan1_low = (i2c_smbus_read_byte_data(client, | 534 | data->fan[1] = (i2c_smbus_read_byte_data(client, |
519 | LM63_REG_TACH_LIMIT_LSB) & 0xFC) | 535 | LM63_REG_TACH_LIMIT_LSB) & 0xFC) |
520 | | (i2c_smbus_read_byte_data(client, | 536 | | (i2c_smbus_read_byte_data(client, |
521 | LM63_REG_TACH_LIMIT_MSB) << 8); | 537 | LM63_REG_TACH_LIMIT_MSB) << 8); |
522 | } | 538 | } |
523 | 539 | ||
524 | data->pwm1_freq = i2c_smbus_read_byte_data(client, | 540 | data->pwm1_freq = i2c_smbus_read_byte_data(client, |
@@ -528,26 +544,26 @@ static struct lm63_data *lm63_update_device(struct device *dev) | |||
528 | data->pwm1_value = i2c_smbus_read_byte_data(client, | 544 | data->pwm1_value = i2c_smbus_read_byte_data(client, |
529 | LM63_REG_PWM_VALUE); | 545 | LM63_REG_PWM_VALUE); |
530 | 546 | ||
531 | data->temp1_input = i2c_smbus_read_byte_data(client, | 547 | data->temp8[0] = i2c_smbus_read_byte_data(client, |
532 | LM63_REG_LOCAL_TEMP); | 548 | LM63_REG_LOCAL_TEMP); |
533 | data->temp1_high = i2c_smbus_read_byte_data(client, | 549 | data->temp8[1] = i2c_smbus_read_byte_data(client, |
534 | LM63_REG_LOCAL_HIGH); | 550 | LM63_REG_LOCAL_HIGH); |
535 | 551 | ||
536 | /* order matters for temp2_input */ | 552 | /* order matters for temp2_input */ |
537 | data->temp2_input = i2c_smbus_read_byte_data(client, | 553 | data->temp11[0] = i2c_smbus_read_byte_data(client, |
538 | LM63_REG_REMOTE_TEMP_MSB) << 8; | 554 | LM63_REG_REMOTE_TEMP_MSB) << 8; |
539 | data->temp2_input |= i2c_smbus_read_byte_data(client, | 555 | data->temp11[0] |= i2c_smbus_read_byte_data(client, |
540 | LM63_REG_REMOTE_TEMP_LSB); | 556 | LM63_REG_REMOTE_TEMP_LSB); |
541 | data->temp2_high = (i2c_smbus_read_byte_data(client, | 557 | data->temp11[1] = (i2c_smbus_read_byte_data(client, |
542 | LM63_REG_REMOTE_HIGH_MSB) << 8) | ||
543 | | i2c_smbus_read_byte_data(client, | ||
544 | LM63_REG_REMOTE_HIGH_LSB); | ||
545 | data->temp2_low = (i2c_smbus_read_byte_data(client, | ||
546 | LM63_REG_REMOTE_LOW_MSB) << 8) | 558 | LM63_REG_REMOTE_LOW_MSB) << 8) |
547 | | i2c_smbus_read_byte_data(client, | 559 | | i2c_smbus_read_byte_data(client, |
548 | LM63_REG_REMOTE_LOW_LSB); | 560 | LM63_REG_REMOTE_LOW_LSB); |
549 | data->temp2_crit = i2c_smbus_read_byte_data(client, | 561 | data->temp11[2] = (i2c_smbus_read_byte_data(client, |
550 | LM63_REG_REMOTE_TCRIT); | 562 | LM63_REG_REMOTE_HIGH_MSB) << 8) |
563 | | i2c_smbus_read_byte_data(client, | ||
564 | LM63_REG_REMOTE_HIGH_LSB); | ||
565 | data->temp8[2] = i2c_smbus_read_byte_data(client, | ||
566 | LM63_REG_REMOTE_TCRIT); | ||
551 | data->temp2_crit_hyst = i2c_smbus_read_byte_data(client, | 567 | data->temp2_crit_hyst = i2c_smbus_read_byte_data(client, |
552 | LM63_REG_REMOTE_TCRIT_HYST); | 568 | LM63_REG_REMOTE_TCRIT_HYST); |
553 | 569 | ||
diff --git a/drivers/i2c/chips/lm75.c b/drivers/i2c/chips/lm75.c index 57c51ac37c04..5be164ed278e 100644 --- a/drivers/i2c/chips/lm75.c +++ b/drivers/i2c/chips/lm75.c | |||
@@ -18,7 +18,6 @@ | |||
18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <linux/config.h> | ||
22 | #include <linux/module.h> | 21 | #include <linux/module.h> |
23 | #include <linux/init.h> | 22 | #include <linux/init.h> |
24 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
diff --git a/drivers/i2c/chips/lm77.c b/drivers/i2c/chips/lm77.c index 9d15cd5189f6..b98f44952997 100644 --- a/drivers/i2c/chips/lm77.c +++ b/drivers/i2c/chips/lm77.c | |||
@@ -25,7 +25,6 @@ | |||
25 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 25 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
26 | */ | 26 | */ |
27 | 27 | ||
28 | #include <linux/config.h> | ||
29 | #include <linux/module.h> | 28 | #include <linux/module.h> |
30 | #include <linux/init.h> | 29 | #include <linux/init.h> |
31 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
diff --git a/drivers/i2c/chips/lm78.c b/drivers/i2c/chips/lm78.c index 21b195ff3871..29241469dcba 100644 --- a/drivers/i2c/chips/lm78.c +++ b/drivers/i2c/chips/lm78.c | |||
@@ -18,7 +18,6 @@ | |||
18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <linux/config.h> | ||
22 | #include <linux/module.h> | 21 | #include <linux/module.h> |
23 | #include <linux/init.h> | 22 | #include <linux/init.h> |
24 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
@@ -671,7 +670,7 @@ static int lm78_detach_client(struct i2c_client *client) | |||
671 | return 0; | 670 | return 0; |
672 | } | 671 | } |
673 | 672 | ||
674 | /* The SMBus locks itself, but ISA access must be locked explicitely! | 673 | /* The SMBus locks itself, but ISA access must be locked explicitly! |
675 | We don't want to lock the whole ISA bus, so we lock each client | 674 | We don't want to lock the whole ISA bus, so we lock each client |
676 | separately. | 675 | separately. |
677 | We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks, | 676 | We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks, |
@@ -690,7 +689,7 @@ static int lm78_read_value(struct i2c_client *client, u8 reg) | |||
690 | return i2c_smbus_read_byte_data(client, reg); | 689 | return i2c_smbus_read_byte_data(client, reg); |
691 | } | 690 | } |
692 | 691 | ||
693 | /* The SMBus locks itself, but ISA access muse be locked explicitely! | 692 | /* The SMBus locks itself, but ISA access muse be locked explicitly! |
694 | We don't want to lock the whole ISA bus, so we lock each client | 693 | We don't want to lock the whole ISA bus, so we lock each client |
695 | separately. | 694 | separately. |
696 | We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks, | 695 | We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks, |
diff --git a/drivers/i2c/chips/lm80.c b/drivers/i2c/chips/lm80.c index 404057b70e90..8100595feb44 100644 --- a/drivers/i2c/chips/lm80.c +++ b/drivers/i2c/chips/lm80.c | |||
@@ -21,7 +21,6 @@ | |||
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <linux/config.h> | ||
25 | #include <linux/module.h> | 24 | #include <linux/module.h> |
26 | #include <linux/init.h> | 25 | #include <linux/init.h> |
27 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
diff --git a/drivers/i2c/chips/lm83.c b/drivers/i2c/chips/lm83.c index 4d6d7d21e14b..a49008b444c8 100644 --- a/drivers/i2c/chips/lm83.c +++ b/drivers/i2c/chips/lm83.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * lm83.c - Part of lm_sensors, Linux kernel modules for hardware | 2 | * lm83.c - Part of lm_sensors, Linux kernel modules for hardware |
3 | * monitoring | 3 | * monitoring |
4 | * Copyright (C) 2003 Jean Delvare <khali@linux-fr.org> | 4 | * Copyright (C) 2003-2005 Jean Delvare <khali@linux-fr.org> |
5 | * | 5 | * |
6 | * Heavily inspired from the lm78, lm75 and adm1021 drivers. The LM83 is | 6 | * Heavily inspired from the lm78, lm75 and adm1021 drivers. The LM83 is |
7 | * a sensor chip made by National Semiconductor. It reports up to four | 7 | * a sensor chip made by National Semiconductor. It reports up to four |
@@ -27,13 +27,13 @@ | |||
27 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 27 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
28 | */ | 28 | */ |
29 | 29 | ||
30 | #include <linux/config.h> | ||
31 | #include <linux/module.h> | 30 | #include <linux/module.h> |
32 | #include <linux/init.h> | 31 | #include <linux/init.h> |
33 | #include <linux/slab.h> | 32 | #include <linux/slab.h> |
34 | #include <linux/jiffies.h> | 33 | #include <linux/jiffies.h> |
35 | #include <linux/i2c.h> | 34 | #include <linux/i2c.h> |
36 | #include <linux/i2c-sensor.h> | 35 | #include <linux/i2c-sensor.h> |
36 | #include <linux/hwmon-sysfs.h> | ||
37 | 37 | ||
38 | /* | 38 | /* |
39 | * Addresses to scan | 39 | * Addresses to scan |
@@ -81,7 +81,7 @@ SENSORS_INSMOD_1(lm83); | |||
81 | 81 | ||
82 | /* | 82 | /* |
83 | * Conversions and various macros | 83 | * Conversions and various macros |
84 | * The LM83 uses signed 8-bit values with LSB = 1 degree Celcius. | 84 | * The LM83 uses signed 8-bit values with LSB = 1 degree Celsius. |
85 | */ | 85 | */ |
86 | 86 | ||
87 | #define TEMP_FROM_REG(val) ((val) * 1000) | 87 | #define TEMP_FROM_REG(val) ((val) * 1000) |
@@ -94,21 +94,20 @@ static const u8 LM83_REG_R_TEMP[] = { | |||
94 | LM83_REG_R_LOCAL_TEMP, | 94 | LM83_REG_R_LOCAL_TEMP, |
95 | LM83_REG_R_REMOTE1_TEMP, | 95 | LM83_REG_R_REMOTE1_TEMP, |
96 | LM83_REG_R_REMOTE2_TEMP, | 96 | LM83_REG_R_REMOTE2_TEMP, |
97 | LM83_REG_R_REMOTE3_TEMP | 97 | LM83_REG_R_REMOTE3_TEMP, |
98 | }; | ||
99 | |||
100 | static const u8 LM83_REG_R_HIGH[] = { | ||
101 | LM83_REG_R_LOCAL_HIGH, | 98 | LM83_REG_R_LOCAL_HIGH, |
102 | LM83_REG_R_REMOTE1_HIGH, | 99 | LM83_REG_R_REMOTE1_HIGH, |
103 | LM83_REG_R_REMOTE2_HIGH, | 100 | LM83_REG_R_REMOTE2_HIGH, |
104 | LM83_REG_R_REMOTE3_HIGH | 101 | LM83_REG_R_REMOTE3_HIGH, |
102 | LM83_REG_R_TCRIT, | ||
105 | }; | 103 | }; |
106 | 104 | ||
107 | static const u8 LM83_REG_W_HIGH[] = { | 105 | static const u8 LM83_REG_W_HIGH[] = { |
108 | LM83_REG_W_LOCAL_HIGH, | 106 | LM83_REG_W_LOCAL_HIGH, |
109 | LM83_REG_W_REMOTE1_HIGH, | 107 | LM83_REG_W_REMOTE1_HIGH, |
110 | LM83_REG_W_REMOTE2_HIGH, | 108 | LM83_REG_W_REMOTE2_HIGH, |
111 | LM83_REG_W_REMOTE3_HIGH | 109 | LM83_REG_W_REMOTE3_HIGH, |
110 | LM83_REG_W_TCRIT, | ||
112 | }; | 111 | }; |
113 | 112 | ||
114 | /* | 113 | /* |
@@ -144,9 +143,9 @@ struct lm83_data { | |||
144 | unsigned long last_updated; /* in jiffies */ | 143 | unsigned long last_updated; /* in jiffies */ |
145 | 144 | ||
146 | /* registers values */ | 145 | /* registers values */ |
147 | s8 temp_input[4]; | 146 | s8 temp[9]; /* 0..3: input 1-4, |
148 | s8 temp_high[4]; | 147 | 4..7: high limit 1-4, |
149 | s8 temp_crit; | 148 | 8 : critical limit */ |
150 | u16 alarms; /* bitvector, combined */ | 149 | u16 alarms; /* bitvector, combined */ |
151 | }; | 150 | }; |
152 | 151 | ||
@@ -154,65 +153,55 @@ struct lm83_data { | |||
154 | * Sysfs stuff | 153 | * Sysfs stuff |
155 | */ | 154 | */ |
156 | 155 | ||
157 | #define show_temp(suffix, value) \ | 156 | static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, |
158 | static ssize_t show_temp_##suffix(struct device *dev, struct device_attribute *attr, char *buf) \ | 157 | char *buf) |
159 | { \ | 158 | { |
160 | struct lm83_data *data = lm83_update_device(dev); \ | 159 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
161 | return sprintf(buf, "%d\n", TEMP_FROM_REG(data->value)); \ | 160 | struct lm83_data *data = lm83_update_device(dev); |
161 | return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index])); | ||
162 | } | 162 | } |
163 | show_temp(input1, temp_input[0]); | 163 | |
164 | show_temp(input2, temp_input[1]); | 164 | static ssize_t set_temp(struct device *dev, struct device_attribute *devattr, |
165 | show_temp(input3, temp_input[2]); | 165 | const char *buf, size_t count) |
166 | show_temp(input4, temp_input[3]); | 166 | { |
167 | show_temp(high1, temp_high[0]); | 167 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
168 | show_temp(high2, temp_high[1]); | 168 | struct i2c_client *client = to_i2c_client(dev); |
169 | show_temp(high3, temp_high[2]); | 169 | struct lm83_data *data = i2c_get_clientdata(client); |
170 | show_temp(high4, temp_high[3]); | 170 | long val = simple_strtol(buf, NULL, 10); |
171 | show_temp(crit, temp_crit); | 171 | int nr = attr->index; |
172 | 172 | ||
173 | #define set_temp(suffix, value, reg) \ | 173 | down(&data->update_lock); |
174 | static ssize_t set_temp_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \ | 174 | data->temp[nr] = TEMP_TO_REG(val); |
175 | size_t count) \ | 175 | i2c_smbus_write_byte_data(client, LM83_REG_W_HIGH[nr - 4], |
176 | { \ | 176 | data->temp[nr]); |
177 | struct i2c_client *client = to_i2c_client(dev); \ | 177 | up(&data->update_lock); |
178 | struct lm83_data *data = i2c_get_clientdata(client); \ | 178 | return count; |
179 | long val = simple_strtol(buf, NULL, 10); \ | ||
180 | \ | ||
181 | down(&data->update_lock); \ | ||
182 | data->value = TEMP_TO_REG(val); \ | ||
183 | i2c_smbus_write_byte_data(client, reg, data->value); \ | ||
184 | up(&data->update_lock); \ | ||
185 | return count; \ | ||
186 | } | 179 | } |
187 | set_temp(high1, temp_high[0], LM83_REG_W_LOCAL_HIGH); | ||
188 | set_temp(high2, temp_high[1], LM83_REG_W_REMOTE1_HIGH); | ||
189 | set_temp(high3, temp_high[2], LM83_REG_W_REMOTE2_HIGH); | ||
190 | set_temp(high4, temp_high[3], LM83_REG_W_REMOTE3_HIGH); | ||
191 | set_temp(crit, temp_crit, LM83_REG_W_TCRIT); | ||
192 | 180 | ||
193 | static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) | 181 | static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy, |
182 | char *buf) | ||
194 | { | 183 | { |
195 | struct lm83_data *data = lm83_update_device(dev); | 184 | struct lm83_data *data = lm83_update_device(dev); |
196 | return sprintf(buf, "%d\n", data->alarms); | 185 | return sprintf(buf, "%d\n", data->alarms); |
197 | } | 186 | } |
198 | 187 | ||
199 | static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL); | 188 | static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0); |
200 | static DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_input2, NULL); | 189 | static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1); |
201 | static DEVICE_ATTR(temp3_input, S_IRUGO, show_temp_input3, NULL); | 190 | static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2); |
202 | static DEVICE_ATTR(temp4_input, S_IRUGO, show_temp_input4, NULL); | 191 | static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3); |
203 | static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_high1, | 192 | static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp, |
204 | set_temp_high1); | 193 | set_temp, 4); |
205 | static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_high2, | 194 | static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp, |
206 | set_temp_high2); | 195 | set_temp, 5); |
207 | static DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_temp_high3, | 196 | static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_temp, |
208 | set_temp_high3); | 197 | set_temp, 6); |
209 | static DEVICE_ATTR(temp4_max, S_IWUSR | S_IRUGO, show_temp_high4, | 198 | static SENSOR_DEVICE_ATTR(temp4_max, S_IWUSR | S_IRUGO, show_temp, |
210 | set_temp_high4); | 199 | set_temp, 7); |
211 | static DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp_crit, NULL); | 200 | static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp, NULL, 8); |
212 | static DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp_crit, NULL); | 201 | static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp, NULL, 8); |
213 | static DEVICE_ATTR(temp3_crit, S_IWUSR | S_IRUGO, show_temp_crit, | 202 | static SENSOR_DEVICE_ATTR(temp3_crit, S_IWUSR | S_IRUGO, show_temp, |
214 | set_temp_crit); | 203 | set_temp, 8); |
215 | static DEVICE_ATTR(temp4_crit, S_IRUGO, show_temp_crit, NULL); | 204 | static SENSOR_DEVICE_ATTR(temp4_crit, S_IRUGO, show_temp, NULL, 8); |
216 | static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); | 205 | static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); |
217 | 206 | ||
218 | /* | 207 | /* |
@@ -323,18 +312,30 @@ static int lm83_detect(struct i2c_adapter *adapter, int address, int kind) | |||
323 | */ | 312 | */ |
324 | 313 | ||
325 | /* Register sysfs hooks */ | 314 | /* Register sysfs hooks */ |
326 | device_create_file(&new_client->dev, &dev_attr_temp1_input); | 315 | device_create_file(&new_client->dev, |
327 | device_create_file(&new_client->dev, &dev_attr_temp2_input); | 316 | &sensor_dev_attr_temp1_input.dev_attr); |
328 | device_create_file(&new_client->dev, &dev_attr_temp3_input); | 317 | device_create_file(&new_client->dev, |
329 | device_create_file(&new_client->dev, &dev_attr_temp4_input); | 318 | &sensor_dev_attr_temp2_input.dev_attr); |
330 | device_create_file(&new_client->dev, &dev_attr_temp1_max); | 319 | device_create_file(&new_client->dev, |
331 | device_create_file(&new_client->dev, &dev_attr_temp2_max); | 320 | &sensor_dev_attr_temp3_input.dev_attr); |
332 | device_create_file(&new_client->dev, &dev_attr_temp3_max); | 321 | device_create_file(&new_client->dev, |
333 | device_create_file(&new_client->dev, &dev_attr_temp4_max); | 322 | &sensor_dev_attr_temp4_input.dev_attr); |
334 | device_create_file(&new_client->dev, &dev_attr_temp1_crit); | 323 | device_create_file(&new_client->dev, |
335 | device_create_file(&new_client->dev, &dev_attr_temp2_crit); | 324 | &sensor_dev_attr_temp1_max.dev_attr); |
336 | device_create_file(&new_client->dev, &dev_attr_temp3_crit); | 325 | device_create_file(&new_client->dev, |
337 | device_create_file(&new_client->dev, &dev_attr_temp4_crit); | 326 | &sensor_dev_attr_temp2_max.dev_attr); |
327 | device_create_file(&new_client->dev, | ||
328 | &sensor_dev_attr_temp3_max.dev_attr); | ||
329 | device_create_file(&new_client->dev, | ||
330 | &sensor_dev_attr_temp4_max.dev_attr); | ||
331 | device_create_file(&new_client->dev, | ||
332 | &sensor_dev_attr_temp1_crit.dev_attr); | ||
333 | device_create_file(&new_client->dev, | ||
334 | &sensor_dev_attr_temp2_crit.dev_attr); | ||
335 | device_create_file(&new_client->dev, | ||
336 | &sensor_dev_attr_temp3_crit.dev_attr); | ||
337 | device_create_file(&new_client->dev, | ||
338 | &sensor_dev_attr_temp4_crit.dev_attr); | ||
338 | device_create_file(&new_client->dev, &dev_attr_alarms); | 339 | device_create_file(&new_client->dev, &dev_attr_alarms); |
339 | 340 | ||
340 | return 0; | 341 | return 0; |
@@ -370,16 +371,11 @@ static struct lm83_data *lm83_update_device(struct device *dev) | |||
370 | int nr; | 371 | int nr; |
371 | 372 | ||
372 | dev_dbg(&client->dev, "Updating lm83 data.\n"); | 373 | dev_dbg(&client->dev, "Updating lm83 data.\n"); |
373 | for (nr = 0; nr < 4 ; nr++) { | 374 | for (nr = 0; nr < 9; nr++) { |
374 | data->temp_input[nr] = | 375 | data->temp[nr] = |
375 | i2c_smbus_read_byte_data(client, | 376 | i2c_smbus_read_byte_data(client, |
376 | LM83_REG_R_TEMP[nr]); | 377 | LM83_REG_R_TEMP[nr]); |
377 | data->temp_high[nr] = | ||
378 | i2c_smbus_read_byte_data(client, | ||
379 | LM83_REG_R_HIGH[nr]); | ||
380 | } | 378 | } |
381 | data->temp_crit = | ||
382 | i2c_smbus_read_byte_data(client, LM83_REG_R_TCRIT); | ||
383 | data->alarms = | 379 | data->alarms = |
384 | i2c_smbus_read_byte_data(client, LM83_REG_R_STATUS1) | 380 | i2c_smbus_read_byte_data(client, LM83_REG_R_STATUS1) |
385 | + (i2c_smbus_read_byte_data(client, LM83_REG_R_STATUS2) | 381 | + (i2c_smbus_read_byte_data(client, LM83_REG_R_STATUS2) |
diff --git a/drivers/i2c/chips/lm85.c b/drivers/i2c/chips/lm85.c index b1976775b4ba..b4d7fd418264 100644 --- a/drivers/i2c/chips/lm85.c +++ b/drivers/i2c/chips/lm85.c | |||
@@ -23,7 +23,6 @@ | |||
23 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 23 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
24 | */ | 24 | */ |
25 | 25 | ||
26 | #include <linux/config.h> | ||
27 | #include <linux/module.h> | 26 | #include <linux/module.h> |
28 | #include <linux/init.h> | 27 | #include <linux/init.h> |
29 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
@@ -285,8 +284,6 @@ static int ZONE_TO_REG( int zone ) | |||
285 | /* i2c-vid.h defines vid_from_reg() */ | 284 | /* i2c-vid.h defines vid_from_reg() */ |
286 | #define VID_FROM_REG(val,vrm) (vid_from_reg((val),(vrm))) | 285 | #define VID_FROM_REG(val,vrm) (vid_from_reg((val),(vrm))) |
287 | 286 | ||
288 | #define ALARMS_FROM_REG(val) (val) | ||
289 | |||
290 | /* Unlike some other drivers we DO NOT set initial limits. Use | 287 | /* Unlike some other drivers we DO NOT set initial limits. Use |
291 | * the config file to set limits. Some users have reported | 288 | * the config file to set limits. Some users have reported |
292 | * motherboards shutting down when we set limits in a previous | 289 | * motherboards shutting down when we set limits in a previous |
@@ -481,7 +478,7 @@ static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); | |||
481 | static ssize_t show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) | 478 | static ssize_t show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) |
482 | { | 479 | { |
483 | struct lm85_data *data = lm85_update_device(dev); | 480 | struct lm85_data *data = lm85_update_device(dev); |
484 | return sprintf(buf, "%ld\n", (long) ALARMS_FROM_REG(data->alarms)); | 481 | return sprintf(buf, "%u\n", data->alarms); |
485 | } | 482 | } |
486 | 483 | ||
487 | static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); | 484 | static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); |
diff --git a/drivers/i2c/chips/lm87.c b/drivers/i2c/chips/lm87.c index 4372b61a0882..1921ed1af182 100644 --- a/drivers/i2c/chips/lm87.c +++ b/drivers/i2c/chips/lm87.c | |||
@@ -52,7 +52,6 @@ | |||
52 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 52 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
53 | */ | 53 | */ |
54 | 54 | ||
55 | #include <linux/config.h> | ||
56 | #include <linux/module.h> | 55 | #include <linux/module.h> |
57 | #include <linux/init.h> | 56 | #include <linux/init.h> |
58 | #include <linux/slab.h> | 57 | #include <linux/slab.h> |
diff --git a/drivers/i2c/chips/lm90.c b/drivers/i2c/chips/lm90.c index 9b127a07f56b..a67dcadf7cb0 100644 --- a/drivers/i2c/chips/lm90.c +++ b/drivers/i2c/chips/lm90.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * lm90.c - Part of lm_sensors, Linux kernel modules for hardware | 2 | * lm90.c - Part of lm_sensors, Linux kernel modules for hardware |
3 | * monitoring | 3 | * monitoring |
4 | * Copyright (C) 2003-2004 Jean Delvare <khali@linux-fr.org> | 4 | * Copyright (C) 2003-2005 Jean Delvare <khali@linux-fr.org> |
5 | * | 5 | * |
6 | * Based on the lm83 driver. The LM90 is a sensor chip made by National | 6 | * Based on the lm83 driver. The LM90 is a sensor chip made by National |
7 | * Semiconductor. It reports up to two temperatures (its own plus up to | 7 | * Semiconductor. It reports up to two temperatures (its own plus up to |
@@ -19,7 +19,7 @@ | |||
19 | * Complete datasheets can be obtained from National's website at: | 19 | * Complete datasheets can be obtained from National's website at: |
20 | * http://www.national.com/pf/LM/LM89.html | 20 | * http://www.national.com/pf/LM/LM89.html |
21 | * http://www.national.com/pf/LM/LM99.html | 21 | * http://www.national.com/pf/LM/LM99.html |
22 | * Note that there is no way to differenciate between both chips. | 22 | * Note that there is no way to differentiate between both chips. |
23 | * | 23 | * |
24 | * This driver also supports the LM86, another sensor chip made by | 24 | * This driver also supports the LM86, another sensor chip made by |
25 | * National Semiconductor. It is exactly similar to the LM90 except it | 25 | * National Semiconductor. It is exactly similar to the LM90 except it |
@@ -39,7 +39,7 @@ | |||
39 | * chips made by Maxim. These chips are similar to the LM86. Complete | 39 | * chips made by Maxim. These chips are similar to the LM86. Complete |
40 | * datasheet can be obtained at Maxim's website at: | 40 | * datasheet can be obtained at Maxim's website at: |
41 | * http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2578 | 41 | * http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2578 |
42 | * Note that there is no easy way to differenciate between the three | 42 | * Note that there is no easy way to differentiate between the three |
43 | * variants. The extra address and features of the MAX6659 are not | 43 | * variants. The extra address and features of the MAX6659 are not |
44 | * supported by this driver. | 44 | * supported by this driver. |
45 | * | 45 | * |
@@ -70,13 +70,13 @@ | |||
70 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 70 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
71 | */ | 71 | */ |
72 | 72 | ||
73 | #include <linux/config.h> | ||
74 | #include <linux/module.h> | 73 | #include <linux/module.h> |
75 | #include <linux/init.h> | 74 | #include <linux/init.h> |
76 | #include <linux/slab.h> | 75 | #include <linux/slab.h> |
77 | #include <linux/jiffies.h> | 76 | #include <linux/jiffies.h> |
78 | #include <linux/i2c.h> | 77 | #include <linux/i2c.h> |
79 | #include <linux/i2c-sensor.h> | 78 | #include <linux/i2c-sensor.h> |
79 | #include <linux/hwmon-sysfs.h> | ||
80 | 80 | ||
81 | /* | 81 | /* |
82 | * Addresses to scan | 82 | * Addresses to scan |
@@ -139,9 +139,9 @@ SENSORS_INSMOD_6(lm90, adm1032, lm99, lm86, max6657, adt7461); | |||
139 | /* | 139 | /* |
140 | * Conversions and various macros | 140 | * Conversions and various macros |
141 | * For local temperatures and limits, critical limits and the hysteresis | 141 | * For local temperatures and limits, critical limits and the hysteresis |
142 | * value, the LM90 uses signed 8-bit values with LSB = 1 degree Celcius. | 142 | * value, the LM90 uses signed 8-bit values with LSB = 1 degree Celsius. |
143 | * For remote temperatures and limits, it uses signed 11-bit values with | 143 | * For remote temperatures and limits, it uses signed 11-bit values with |
144 | * LSB = 0.125 degree Celcius, left-justified in 16-bit registers. | 144 | * LSB = 0.125 degree Celsius, left-justified in 16-bit registers. |
145 | */ | 145 | */ |
146 | 146 | ||
147 | #define TEMP1_FROM_REG(val) ((val) * 1000) | 147 | #define TEMP1_FROM_REG(val) ((val) * 1000) |
@@ -206,9 +206,14 @@ struct lm90_data { | |||
206 | int kind; | 206 | int kind; |
207 | 207 | ||
208 | /* registers values */ | 208 | /* registers values */ |
209 | s8 temp_input1, temp_low1, temp_high1; /* local */ | 209 | s8 temp8[5]; /* 0: local input |
210 | s16 temp_input2, temp_low2, temp_high2; /* remote, combined */ | 210 | 1: local low limit |
211 | s8 temp_crit1, temp_crit2; | 211 | 2: local high limit |
212 | 3: local critical limit | ||
213 | 4: remote critical limit */ | ||
214 | s16 temp11[3]; /* 0: remote input | ||
215 | 1: remote low limit | ||
216 | 2: remote high limit */ | ||
212 | u8 temp_hyst; | 217 | u8 temp_hyst; |
213 | u8 alarms; /* bitvector */ | 218 | u8 alarms; /* bitvector */ |
214 | }; | 219 | }; |
@@ -217,75 +222,88 @@ struct lm90_data { | |||
217 | * Sysfs stuff | 222 | * Sysfs stuff |
218 | */ | 223 | */ |
219 | 224 | ||
220 | #define show_temp(value, converter) \ | 225 | static ssize_t show_temp8(struct device *dev, struct device_attribute *devattr, |
221 | static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ | 226 | char *buf) |
222 | { \ | 227 | { |
223 | struct lm90_data *data = lm90_update_device(dev); \ | 228 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
224 | return sprintf(buf, "%d\n", converter(data->value)); \ | 229 | struct lm90_data *data = lm90_update_device(dev); |
230 | return sprintf(buf, "%d\n", TEMP1_FROM_REG(data->temp8[attr->index])); | ||
231 | } | ||
232 | |||
233 | static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr, | ||
234 | const char *buf, size_t count) | ||
235 | { | ||
236 | static const u8 reg[4] = { | ||
237 | LM90_REG_W_LOCAL_LOW, | ||
238 | LM90_REG_W_LOCAL_HIGH, | ||
239 | LM90_REG_W_LOCAL_CRIT, | ||
240 | LM90_REG_W_REMOTE_CRIT, | ||
241 | }; | ||
242 | |||
243 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
244 | struct i2c_client *client = to_i2c_client(dev); | ||
245 | struct lm90_data *data = i2c_get_clientdata(client); | ||
246 | long val = simple_strtol(buf, NULL, 10); | ||
247 | int nr = attr->index; | ||
248 | |||
249 | down(&data->update_lock); | ||
250 | if (data->kind == adt7461) | ||
251 | data->temp8[nr] = TEMP1_TO_REG_ADT7461(val); | ||
252 | else | ||
253 | data->temp8[nr] = TEMP1_TO_REG(val); | ||
254 | i2c_smbus_write_byte_data(client, reg[nr - 1], data->temp8[nr]); | ||
255 | up(&data->update_lock); | ||
256 | return count; | ||
225 | } | 257 | } |
226 | show_temp(temp_input1, TEMP1_FROM_REG); | 258 | |
227 | show_temp(temp_input2, TEMP2_FROM_REG); | 259 | static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr, |
228 | show_temp(temp_low1, TEMP1_FROM_REG); | 260 | char *buf) |
229 | show_temp(temp_low2, TEMP2_FROM_REG); | 261 | { |
230 | show_temp(temp_high1, TEMP1_FROM_REG); | 262 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
231 | show_temp(temp_high2, TEMP2_FROM_REG); | 263 | struct lm90_data *data = lm90_update_device(dev); |
232 | show_temp(temp_crit1, TEMP1_FROM_REG); | 264 | return sprintf(buf, "%d\n", TEMP2_FROM_REG(data->temp11[attr->index])); |
233 | show_temp(temp_crit2, TEMP1_FROM_REG); | ||
234 | |||
235 | #define set_temp1(value, reg) \ | ||
236 | static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, \ | ||
237 | size_t count) \ | ||
238 | { \ | ||
239 | struct i2c_client *client = to_i2c_client(dev); \ | ||
240 | struct lm90_data *data = i2c_get_clientdata(client); \ | ||
241 | long val = simple_strtol(buf, NULL, 10); \ | ||
242 | \ | ||
243 | down(&data->update_lock); \ | ||
244 | if (data->kind == adt7461) \ | ||
245 | data->value = TEMP1_TO_REG_ADT7461(val); \ | ||
246 | else \ | ||
247 | data->value = TEMP1_TO_REG(val); \ | ||
248 | i2c_smbus_write_byte_data(client, reg, data->value); \ | ||
249 | up(&data->update_lock); \ | ||
250 | return count; \ | ||
251 | } | 265 | } |
252 | #define set_temp2(value, regh, regl) \ | 266 | |
253 | static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, \ | 267 | static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr, |
254 | size_t count) \ | 268 | const char *buf, size_t count) |
255 | { \ | 269 | { |
256 | struct i2c_client *client = to_i2c_client(dev); \ | 270 | static const u8 reg[4] = { |
257 | struct lm90_data *data = i2c_get_clientdata(client); \ | 271 | LM90_REG_W_REMOTE_LOWH, |
258 | long val = simple_strtol(buf, NULL, 10); \ | 272 | LM90_REG_W_REMOTE_LOWL, |
259 | \ | 273 | LM90_REG_W_REMOTE_HIGHH, |
260 | down(&data->update_lock); \ | 274 | LM90_REG_W_REMOTE_HIGHL, |
261 | if (data->kind == adt7461) \ | 275 | }; |
262 | data->value = TEMP2_TO_REG_ADT7461(val); \ | 276 | |
263 | else \ | 277 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
264 | data->value = TEMP2_TO_REG(val); \ | 278 | struct i2c_client *client = to_i2c_client(dev); |
265 | i2c_smbus_write_byte_data(client, regh, data->value >> 8); \ | 279 | struct lm90_data *data = i2c_get_clientdata(client); |
266 | i2c_smbus_write_byte_data(client, regl, data->value & 0xff); \ | 280 | long val = simple_strtol(buf, NULL, 10); |
267 | up(&data->update_lock); \ | 281 | int nr = attr->index; |
268 | return count; \ | 282 | |
283 | down(&data->update_lock); | ||
284 | if (data->kind == adt7461) | ||
285 | data->temp11[nr] = TEMP2_TO_REG_ADT7461(val); | ||
286 | else | ||
287 | data->temp11[nr] = TEMP2_TO_REG(val); | ||
288 | i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2], | ||
289 | data->temp11[nr] >> 8); | ||
290 | i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2 + 1], | ||
291 | data->temp11[nr] & 0xff); | ||
292 | up(&data->update_lock); | ||
293 | return count; | ||
269 | } | 294 | } |
270 | set_temp1(temp_low1, LM90_REG_W_LOCAL_LOW); | 295 | |
271 | set_temp2(temp_low2, LM90_REG_W_REMOTE_LOWH, LM90_REG_W_REMOTE_LOWL); | 296 | static ssize_t show_temphyst(struct device *dev, struct device_attribute *devattr, |
272 | set_temp1(temp_high1, LM90_REG_W_LOCAL_HIGH); | 297 | char *buf) |
273 | set_temp2(temp_high2, LM90_REG_W_REMOTE_HIGHH, LM90_REG_W_REMOTE_HIGHL); | 298 | { |
274 | set_temp1(temp_crit1, LM90_REG_W_LOCAL_CRIT); | 299 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
275 | set_temp1(temp_crit2, LM90_REG_W_REMOTE_CRIT); | 300 | struct lm90_data *data = lm90_update_device(dev); |
276 | 301 | return sprintf(buf, "%d\n", TEMP1_FROM_REG(data->temp8[attr->index]) | |
277 | #define show_temp_hyst(value, basereg) \ | 302 | - TEMP1_FROM_REG(data->temp_hyst)); |
278 | static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ | ||
279 | { \ | ||
280 | struct lm90_data *data = lm90_update_device(dev); \ | ||
281 | return sprintf(buf, "%d\n", TEMP1_FROM_REG(data->basereg) \ | ||
282 | - TEMP1_FROM_REG(data->temp_hyst)); \ | ||
283 | } | 303 | } |
284 | show_temp_hyst(temp_hyst1, temp_crit1); | ||
285 | show_temp_hyst(temp_hyst2, temp_crit2); | ||
286 | 304 | ||
287 | static ssize_t set_temp_hyst1(struct device *dev, struct device_attribute *attr, const char *buf, | 305 | static ssize_t set_temphyst(struct device *dev, struct device_attribute *dummy, |
288 | size_t count) | 306 | const char *buf, size_t count) |
289 | { | 307 | { |
290 | struct i2c_client *client = to_i2c_client(dev); | 308 | struct i2c_client *client = to_i2c_client(dev); |
291 | struct lm90_data *data = i2c_get_clientdata(client); | 309 | struct lm90_data *data = i2c_get_clientdata(client); |
@@ -293,36 +311,37 @@ static ssize_t set_temp_hyst1(struct device *dev, struct device_attribute *attr, | |||
293 | long hyst; | 311 | long hyst; |
294 | 312 | ||
295 | down(&data->update_lock); | 313 | down(&data->update_lock); |
296 | hyst = TEMP1_FROM_REG(data->temp_crit1) - val; | 314 | hyst = TEMP1_FROM_REG(data->temp8[3]) - val; |
297 | i2c_smbus_write_byte_data(client, LM90_REG_W_TCRIT_HYST, | 315 | i2c_smbus_write_byte_data(client, LM90_REG_W_TCRIT_HYST, |
298 | HYST_TO_REG(hyst)); | 316 | HYST_TO_REG(hyst)); |
299 | up(&data->update_lock); | 317 | up(&data->update_lock); |
300 | return count; | 318 | return count; |
301 | } | 319 | } |
302 | 320 | ||
303 | static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) | 321 | static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy, |
322 | char *buf) | ||
304 | { | 323 | { |
305 | struct lm90_data *data = lm90_update_device(dev); | 324 | struct lm90_data *data = lm90_update_device(dev); |
306 | return sprintf(buf, "%d\n", data->alarms); | 325 | return sprintf(buf, "%d\n", data->alarms); |
307 | } | 326 | } |
308 | 327 | ||
309 | static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL); | 328 | static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp8, NULL, 0); |
310 | static DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_input2, NULL); | 329 | static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 0); |
311 | static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_low1, | 330 | static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp8, |
312 | set_temp_low1); | 331 | set_temp8, 1); |
313 | static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp_low2, | 332 | static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp11, |
314 | set_temp_low2); | 333 | set_temp11, 1); |
315 | static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_high1, | 334 | static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp8, |
316 | set_temp_high1); | 335 | set_temp8, 2); |
317 | static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_high2, | 336 | static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp11, |
318 | set_temp_high2); | 337 | set_temp11, 2); |
319 | static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp_crit1, | 338 | static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp8, |
320 | set_temp_crit1); | 339 | set_temp8, 3); |
321 | static DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp_crit2, | 340 | static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp8, |
322 | set_temp_crit2); | 341 | set_temp8, 4); |
323 | static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp_hyst1, | 342 | static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temphyst, |
324 | set_temp_hyst1); | 343 | set_temphyst, 3); |
325 | static DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temp_hyst2, NULL); | 344 | static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temphyst, NULL, 4); |
326 | static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); | 345 | static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); |
327 | 346 | ||
328 | /* | 347 | /* |
@@ -481,16 +500,26 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind) | |||
481 | lm90_init_client(new_client); | 500 | lm90_init_client(new_client); |
482 | 501 | ||
483 | /* Register sysfs hooks */ | 502 | /* Register sysfs hooks */ |
484 | device_create_file(&new_client->dev, &dev_attr_temp1_input); | 503 | device_create_file(&new_client->dev, |
485 | device_create_file(&new_client->dev, &dev_attr_temp2_input); | 504 | &sensor_dev_attr_temp1_input.dev_attr); |
486 | device_create_file(&new_client->dev, &dev_attr_temp1_min); | 505 | device_create_file(&new_client->dev, |
487 | device_create_file(&new_client->dev, &dev_attr_temp2_min); | 506 | &sensor_dev_attr_temp2_input.dev_attr); |
488 | device_create_file(&new_client->dev, &dev_attr_temp1_max); | 507 | device_create_file(&new_client->dev, |
489 | device_create_file(&new_client->dev, &dev_attr_temp2_max); | 508 | &sensor_dev_attr_temp1_min.dev_attr); |
490 | device_create_file(&new_client->dev, &dev_attr_temp1_crit); | 509 | device_create_file(&new_client->dev, |
491 | device_create_file(&new_client->dev, &dev_attr_temp2_crit); | 510 | &sensor_dev_attr_temp2_min.dev_attr); |
492 | device_create_file(&new_client->dev, &dev_attr_temp1_crit_hyst); | 511 | device_create_file(&new_client->dev, |
493 | device_create_file(&new_client->dev, &dev_attr_temp2_crit_hyst); | 512 | &sensor_dev_attr_temp1_max.dev_attr); |
513 | device_create_file(&new_client->dev, | ||
514 | &sensor_dev_attr_temp2_max.dev_attr); | ||
515 | device_create_file(&new_client->dev, | ||
516 | &sensor_dev_attr_temp1_crit.dev_attr); | ||
517 | device_create_file(&new_client->dev, | ||
518 | &sensor_dev_attr_temp2_crit.dev_attr); | ||
519 | device_create_file(&new_client->dev, | ||
520 | &sensor_dev_attr_temp1_crit_hyst.dev_attr); | ||
521 | device_create_file(&new_client->dev, | ||
522 | &sensor_dev_attr_temp2_crit_hyst.dev_attr); | ||
494 | device_create_file(&new_client->dev, &dev_attr_alarms); | 523 | device_create_file(&new_client->dev, &dev_attr_alarms); |
495 | 524 | ||
496 | return 0; | 525 | return 0; |
@@ -541,16 +570,16 @@ static struct lm90_data *lm90_update_device(struct device *dev) | |||
541 | u8 oldh, newh; | 570 | u8 oldh, newh; |
542 | 571 | ||
543 | dev_dbg(&client->dev, "Updating lm90 data.\n"); | 572 | dev_dbg(&client->dev, "Updating lm90 data.\n"); |
544 | data->temp_input1 = i2c_smbus_read_byte_data(client, | 573 | data->temp8[0] = i2c_smbus_read_byte_data(client, |
545 | LM90_REG_R_LOCAL_TEMP); | 574 | LM90_REG_R_LOCAL_TEMP); |
546 | data->temp_high1 = i2c_smbus_read_byte_data(client, | 575 | data->temp8[1] = i2c_smbus_read_byte_data(client, |
547 | LM90_REG_R_LOCAL_HIGH); | 576 | LM90_REG_R_LOCAL_LOW); |
548 | data->temp_low1 = i2c_smbus_read_byte_data(client, | 577 | data->temp8[2] = i2c_smbus_read_byte_data(client, |
549 | LM90_REG_R_LOCAL_LOW); | 578 | LM90_REG_R_LOCAL_HIGH); |
550 | data->temp_crit1 = i2c_smbus_read_byte_data(client, | 579 | data->temp8[3] = i2c_smbus_read_byte_data(client, |
551 | LM90_REG_R_LOCAL_CRIT); | 580 | LM90_REG_R_LOCAL_CRIT); |
552 | data->temp_crit2 = i2c_smbus_read_byte_data(client, | 581 | data->temp8[4] = i2c_smbus_read_byte_data(client, |
553 | LM90_REG_R_REMOTE_CRIT); | 582 | LM90_REG_R_REMOTE_CRIT); |
554 | data->temp_hyst = i2c_smbus_read_byte_data(client, | 583 | data->temp_hyst = i2c_smbus_read_byte_data(client, |
555 | LM90_REG_R_TCRIT_HYST); | 584 | LM90_REG_R_TCRIT_HYST); |
556 | 585 | ||
@@ -570,13 +599,13 @@ static struct lm90_data *lm90_update_device(struct device *dev) | |||
570 | */ | 599 | */ |
571 | oldh = i2c_smbus_read_byte_data(client, | 600 | oldh = i2c_smbus_read_byte_data(client, |
572 | LM90_REG_R_REMOTE_TEMPH); | 601 | LM90_REG_R_REMOTE_TEMPH); |
573 | data->temp_input2 = i2c_smbus_read_byte_data(client, | 602 | data->temp11[0] = i2c_smbus_read_byte_data(client, |
574 | LM90_REG_R_REMOTE_TEMPL); | 603 | LM90_REG_R_REMOTE_TEMPL); |
575 | newh = i2c_smbus_read_byte_data(client, | 604 | newh = i2c_smbus_read_byte_data(client, |
576 | LM90_REG_R_REMOTE_TEMPH); | 605 | LM90_REG_R_REMOTE_TEMPH); |
577 | if (newh != oldh) { | 606 | if (newh != oldh) { |
578 | data->temp_input2 = i2c_smbus_read_byte_data(client, | 607 | data->temp11[0] = i2c_smbus_read_byte_data(client, |
579 | LM90_REG_R_REMOTE_TEMPL); | 608 | LM90_REG_R_REMOTE_TEMPL); |
580 | #ifdef DEBUG | 609 | #ifdef DEBUG |
581 | oldh = i2c_smbus_read_byte_data(client, | 610 | oldh = i2c_smbus_read_byte_data(client, |
582 | LM90_REG_R_REMOTE_TEMPH); | 611 | LM90_REG_R_REMOTE_TEMPH); |
@@ -586,16 +615,16 @@ static struct lm90_data *lm90_update_device(struct device *dev) | |||
586 | "wrong.\n"); | 615 | "wrong.\n"); |
587 | #endif | 616 | #endif |
588 | } | 617 | } |
589 | data->temp_input2 |= (newh << 8); | 618 | data->temp11[0] |= (newh << 8); |
590 | 619 | ||
591 | data->temp_high2 = (i2c_smbus_read_byte_data(client, | 620 | data->temp11[1] = (i2c_smbus_read_byte_data(client, |
621 | LM90_REG_R_REMOTE_LOWH) << 8) + | ||
622 | i2c_smbus_read_byte_data(client, | ||
623 | LM90_REG_R_REMOTE_LOWL); | ||
624 | data->temp11[2] = (i2c_smbus_read_byte_data(client, | ||
592 | LM90_REG_R_REMOTE_HIGHH) << 8) + | 625 | LM90_REG_R_REMOTE_HIGHH) << 8) + |
593 | i2c_smbus_read_byte_data(client, | 626 | i2c_smbus_read_byte_data(client, |
594 | LM90_REG_R_REMOTE_HIGHL); | 627 | LM90_REG_R_REMOTE_HIGHL); |
595 | data->temp_low2 = (i2c_smbus_read_byte_data(client, | ||
596 | LM90_REG_R_REMOTE_LOWH) << 8) + | ||
597 | i2c_smbus_read_byte_data(client, | ||
598 | LM90_REG_R_REMOTE_LOWL); | ||
599 | data->alarms = i2c_smbus_read_byte_data(client, | 628 | data->alarms = i2c_smbus_read_byte_data(client, |
600 | LM90_REG_R_STATUS); | 629 | LM90_REG_R_STATUS); |
601 | 630 | ||
diff --git a/drivers/i2c/chips/m41t00.c b/drivers/i2c/chips/m41t00.c index e771566dffa8..5e463c47bfbc 100644 --- a/drivers/i2c/chips/m41t00.c +++ b/drivers/i2c/chips/m41t00.c | |||
@@ -40,11 +40,8 @@ static unsigned short normal_addr[] = { 0x68, I2C_CLIENT_END }; | |||
40 | 40 | ||
41 | static struct i2c_client_address_data addr_data = { | 41 | static struct i2c_client_address_data addr_data = { |
42 | .normal_i2c = normal_addr, | 42 | .normal_i2c = normal_addr, |
43 | .normal_i2c_range = ignore, | ||
44 | .probe = ignore, | 43 | .probe = ignore, |
45 | .probe_range = ignore, | ||
46 | .ignore = ignore, | 44 | .ignore = ignore, |
47 | .ignore_range = ignore, | ||
48 | .force = ignore, | 45 | .force = ignore, |
49 | }; | 46 | }; |
50 | 47 | ||
diff --git a/drivers/i2c/chips/max1619.c b/drivers/i2c/chips/max1619.c index 30a196155fd9..bf553dcd97d6 100644 --- a/drivers/i2c/chips/max1619.c +++ b/drivers/i2c/chips/max1619.c | |||
@@ -26,7 +26,6 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | 28 | ||
29 | #include <linux/config.h> | ||
30 | #include <linux/module.h> | 29 | #include <linux/module.h> |
31 | #include <linux/init.h> | 30 | #include <linux/init.h> |
32 | #include <linux/slab.h> | 31 | #include <linux/slab.h> |
diff --git a/drivers/i2c/chips/max6875.c b/drivers/i2c/chips/max6875.c new file mode 100644 index 000000000000..fe6b150ec4c2 --- /dev/null +++ b/drivers/i2c/chips/max6875.c | |||
@@ -0,0 +1,473 @@ | |||
1 | /* | ||
2 | max6875.c - driver for MAX6874/MAX6875 | ||
3 | |||
4 | Copyright (C) 2005 Ben Gardner <bgardner@wabtec.com> | ||
5 | |||
6 | Based on i2c/chips/eeprom.c | ||
7 | |||
8 | The MAX6875 has two EEPROM sections: config and user. | ||
9 | At reset, the config EEPROM is read into the registers. | ||
10 | |||
11 | This driver make 3 binary files available in sysfs: | ||
12 | reg_config - direct access to the registers | ||
13 | eeprom_config - acesses configuration eeprom space | ||
14 | eeprom_user - free for application use | ||
15 | |||
16 | In our application, we put device serial & model numbers in user eeprom. | ||
17 | |||
18 | Notes: | ||
19 | 1) The datasheet says that register 0x44 / EEPROM 0x8044 should NOT | ||
20 | be overwritten, so the driver explicitly prevents that. | ||
21 | 2) It's a good idea to keep the config (0x45) locked in config EEPROM. | ||
22 | You can temporarily enable config writes by changing register 0x45. | ||
23 | |||
24 | This program is free software; you can redistribute it and/or modify | ||
25 | it under the terms of the GNU General Public License as published by | ||
26 | the Free Software Foundation; version 2 of the License. | ||
27 | */ | ||
28 | |||
29 | #include <linux/config.h> | ||
30 | #include <linux/kernel.h> | ||
31 | #include <linux/init.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/slab.h> | ||
34 | #include <linux/sched.h> | ||
35 | #include <linux/delay.h> | ||
36 | #include <linux/i2c.h> | ||
37 | #include <linux/i2c-sensor.h> | ||
38 | |||
39 | /* Addresses to scan */ | ||
40 | static unsigned short normal_i2c[] = {0x50, 0x52, I2C_CLIENT_END}; | ||
41 | static unsigned int normal_isa[] = {I2C_CLIENT_ISA_END}; | ||
42 | |||
43 | /* Insmod parameters */ | ||
44 | SENSORS_INSMOD_1(max6875); | ||
45 | |||
46 | /* this param will prevent 'accidental' writes to the eeprom */ | ||
47 | static int allow_write = 0; | ||
48 | module_param(allow_write, int, 0); | ||
49 | MODULE_PARM_DESC(allow_write, | ||
50 | "Enable write access:\n" | ||
51 | "*0: Read only\n" | ||
52 | " 1: Read/Write access"); | ||
53 | |||
54 | /* The MAX6875 can only read/write 16 bytes at a time */ | ||
55 | #define SLICE_SIZE 16 | ||
56 | #define SLICE_BITS 4 | ||
57 | |||
58 | /* CONFIG EEPROM is at addresses 0x8000 - 0x8045, registers are at 0 - 0x45 */ | ||
59 | #define CONFIG_EEPROM_BASE 0x8000 | ||
60 | #define CONFIG_EEPROM_SIZE 0x0046 | ||
61 | #define CONFIG_EEPROM_SLICES 5 | ||
62 | |||
63 | /* USER EEPROM is at addresses 0x8100 - 0x82FF */ | ||
64 | #define USER_EEPROM_BASE 0x8100 | ||
65 | #define USER_EEPROM_SIZE 0x0200 | ||
66 | #define USER_EEPROM_SLICES 32 | ||
67 | |||
68 | /* MAX6875 commands */ | ||
69 | #define MAX6875_CMD_BLOCK_WRITE 0x83 | ||
70 | #define MAX6875_CMD_BLOCK_READ 0x84 | ||
71 | #define MAX6875_CMD_REBOOT 0x88 | ||
72 | |||
73 | enum max6875_area_type { | ||
74 | max6875_register_config=0, | ||
75 | max6875_eeprom_config, | ||
76 | max6875_eeprom_user, | ||
77 | max6857_max | ||
78 | }; | ||
79 | |||
80 | struct eeprom_block { | ||
81 | enum max6875_area_type type; | ||
82 | u8 slices; | ||
83 | u32 size; | ||
84 | u32 valid; | ||
85 | u32 base; | ||
86 | unsigned long *updated; | ||
87 | u8 *data; | ||
88 | }; | ||
89 | |||
90 | /* Each client has this additional data */ | ||
91 | struct max6875_data { | ||
92 | struct i2c_client client; | ||
93 | struct semaphore update_lock; | ||
94 | struct eeprom_block blocks[max6857_max]; | ||
95 | /* the above structs point into the arrays below */ | ||
96 | u8 data[USER_EEPROM_SIZE + (CONFIG_EEPROM_SIZE*2)]; | ||
97 | unsigned long last_updated[USER_EEPROM_SLICES + (CONFIG_EEPROM_SLICES*2)]; | ||
98 | }; | ||
99 | |||
100 | static int max6875_attach_adapter(struct i2c_adapter *adapter); | ||
101 | static int max6875_detect(struct i2c_adapter *adapter, int address, int kind); | ||
102 | static int max6875_detach_client(struct i2c_client *client); | ||
103 | |||
104 | /* This is the driver that will be inserted */ | ||
105 | static struct i2c_driver max6875_driver = { | ||
106 | .owner = THIS_MODULE, | ||
107 | .name = "max6875", | ||
108 | .flags = I2C_DF_NOTIFY, | ||
109 | .attach_adapter = max6875_attach_adapter, | ||
110 | .detach_client = max6875_detach_client, | ||
111 | }; | ||
112 | |||
113 | static int max6875_update_slice(struct i2c_client *client, | ||
114 | struct eeprom_block *blk, | ||
115 | int slice) | ||
116 | { | ||
117 | struct max6875_data *data = i2c_get_clientdata(client); | ||
118 | int i, j, addr, count; | ||
119 | u8 rdbuf[SLICE_SIZE]; | ||
120 | int retval = 0; | ||
121 | |||
122 | if (slice >= blk->slices) | ||
123 | return -1; | ||
124 | |||
125 | down(&data->update_lock); | ||
126 | |||
127 | if (!(blk->valid & (1 << slice)) || | ||
128 | (jiffies - blk->updated[slice] > 300 * HZ) || | ||
129 | (jiffies < blk->updated[slice])) { | ||
130 | dev_dbg(&client->dev, "Starting eeprom update, slice %u, base %u\n", | ||
131 | slice, blk->base); | ||
132 | |||
133 | addr = blk->base + (slice << SLICE_BITS); | ||
134 | count = blk->size - (slice << SLICE_BITS); | ||
135 | if (count > SLICE_SIZE) { | ||
136 | count = SLICE_SIZE; | ||
137 | } | ||
138 | |||
139 | /* Preset the read address */ | ||
140 | if (addr < 0x100) { | ||
141 | /* select the register */ | ||
142 | if (i2c_smbus_write_byte(client, addr & 0xFF)) { | ||
143 | dev_dbg(&client->dev, "max6875 register select has failed!\n"); | ||
144 | retval = -1; | ||
145 | goto exit; | ||
146 | } | ||
147 | } else { | ||
148 | /* select the eeprom */ | ||
149 | if (i2c_smbus_write_byte_data(client, addr >> 8, addr & 0xFF)) { | ||
150 | dev_dbg(&client->dev, "max6875 address set has failed!\n"); | ||
151 | retval = -1; | ||
152 | goto exit; | ||
153 | } | ||
154 | } | ||
155 | |||
156 | if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { | ||
157 | if (i2c_smbus_read_i2c_block_data(client, MAX6875_CMD_BLOCK_READ, | ||
158 | rdbuf) != SLICE_SIZE) | ||
159 | { | ||
160 | retval = -1; | ||
161 | goto exit; | ||
162 | } | ||
163 | |||
164 | memcpy(&blk->data[slice << SLICE_BITS], rdbuf, count); | ||
165 | } else { | ||
166 | for (i = 0; i < count; i++) { | ||
167 | j = i2c_smbus_read_byte(client); | ||
168 | if (j < 0) | ||
169 | { | ||
170 | retval = -1; | ||
171 | goto exit; | ||
172 | } | ||
173 | blk->data[(slice << SLICE_BITS) + i] = (u8) j; | ||
174 | } | ||
175 | } | ||
176 | blk->updated[slice] = jiffies; | ||
177 | blk->valid |= (1 << slice); | ||
178 | } | ||
179 | exit: | ||
180 | up(&data->update_lock); | ||
181 | return retval; | ||
182 | } | ||
183 | |||
184 | static ssize_t max6875_read(struct kobject *kobj, char *buf, loff_t off, size_t count, | ||
185 | enum max6875_area_type area_type) | ||
186 | { | ||
187 | struct i2c_client *client = to_i2c_client(container_of(kobj, struct device, kobj)); | ||
188 | struct max6875_data *data = i2c_get_clientdata(client); | ||
189 | struct eeprom_block *blk; | ||
190 | int slice; | ||
191 | |||
192 | blk = &data->blocks[area_type]; | ||
193 | |||
194 | if (off > blk->size) | ||
195 | return 0; | ||
196 | if (off + count > blk->size) | ||
197 | count = blk->size - off; | ||
198 | |||
199 | /* Only refresh slices which contain requested bytes */ | ||
200 | for (slice = (off >> SLICE_BITS); slice <= ((off + count - 1) >> SLICE_BITS); slice++) | ||
201 | max6875_update_slice(client, blk, slice); | ||
202 | |||
203 | memcpy(buf, &blk->data[off], count); | ||
204 | |||
205 | return count; | ||
206 | } | ||
207 | |||
208 | static ssize_t max6875_user_read(struct kobject *kobj, char *buf, loff_t off, size_t count) | ||
209 | { | ||
210 | return max6875_read(kobj, buf, off, count, max6875_eeprom_user); | ||
211 | } | ||
212 | |||
213 | static ssize_t max6875_config_read(struct kobject *kobj, char *buf, loff_t off, size_t count) | ||
214 | { | ||
215 | return max6875_read(kobj, buf, off, count, max6875_eeprom_config); | ||
216 | } | ||
217 | |||
218 | static ssize_t max6875_cfgreg_read(struct kobject *kobj, char *buf, loff_t off, size_t count) | ||
219 | { | ||
220 | return max6875_read(kobj, buf, off, count, max6875_register_config); | ||
221 | } | ||
222 | |||
223 | |||
224 | static ssize_t max6875_write(struct kobject *kobj, char *buf, loff_t off, size_t count, | ||
225 | enum max6875_area_type area_type) | ||
226 | { | ||
227 | struct i2c_client *client = to_i2c_client(container_of(kobj, struct device, kobj)); | ||
228 | struct max6875_data *data = i2c_get_clientdata(client); | ||
229 | struct eeprom_block *blk; | ||
230 | int slice, addr, retval; | ||
231 | ssize_t sent = 0; | ||
232 | |||
233 | blk = &data->blocks[area_type]; | ||
234 | |||
235 | if (off > blk->size) | ||
236 | return 0; | ||
237 | if ((off + count) > blk->size) | ||
238 | count = blk->size - off; | ||
239 | |||
240 | if (down_interruptible(&data->update_lock)) | ||
241 | return -EAGAIN; | ||
242 | |||
243 | /* writing to a register is done with i2c_smbus_write_byte_data() */ | ||
244 | if (blk->type == max6875_register_config) { | ||
245 | for (sent = 0; sent < count; sent++) { | ||
246 | addr = off + sent; | ||
247 | if (addr == 0x44) | ||
248 | continue; | ||
249 | |||
250 | retval = i2c_smbus_write_byte_data(client, addr, buf[sent]); | ||
251 | } | ||
252 | } else { | ||
253 | int cmd, val; | ||
254 | |||
255 | /* We are writing to EEPROM */ | ||
256 | for (sent = 0; sent < count; sent++) { | ||
257 | addr = blk->base + off + sent; | ||
258 | cmd = addr >> 8; | ||
259 | val = (addr & 0xff) | (buf[sent] << 8); // reversed | ||
260 | |||
261 | if (addr == 0x8044) | ||
262 | continue; | ||
263 | |||
264 | retval = i2c_smbus_write_word_data(client, cmd, val); | ||
265 | |||
266 | if (retval) { | ||
267 | goto error_exit; | ||
268 | } | ||
269 | |||
270 | /* A write takes up to 11 ms */ | ||
271 | msleep(11); | ||
272 | } | ||
273 | } | ||
274 | |||
275 | /* Invalidate the scratch buffer */ | ||
276 | for (slice = (off >> SLICE_BITS); slice <= ((off + count - 1) >> SLICE_BITS); slice++) | ||
277 | blk->valid &= ~(1 << slice); | ||
278 | |||
279 | error_exit: | ||
280 | up(&data->update_lock); | ||
281 | |||
282 | return sent; | ||
283 | } | ||
284 | |||
285 | static ssize_t max6875_user_write(struct kobject *kobj, char *buf, loff_t off, size_t count) | ||
286 | { | ||
287 | return max6875_write(kobj, buf, off, count, max6875_eeprom_user); | ||
288 | } | ||
289 | |||
290 | static ssize_t max6875_config_write(struct kobject *kobj, char *buf, loff_t off, size_t count) | ||
291 | { | ||
292 | return max6875_write(kobj, buf, off, count, max6875_eeprom_config); | ||
293 | } | ||
294 | |||
295 | static ssize_t max6875_cfgreg_write(struct kobject *kobj, char *buf, loff_t off, size_t count) | ||
296 | { | ||
297 | return max6875_write(kobj, buf, off, count, max6875_register_config); | ||
298 | } | ||
299 | |||
300 | static struct bin_attribute user_eeprom_attr = { | ||
301 | .attr = { | ||
302 | .name = "eeprom_user", | ||
303 | .mode = S_IRUGO | S_IWUSR | S_IWGRP, | ||
304 | .owner = THIS_MODULE, | ||
305 | }, | ||
306 | .size = USER_EEPROM_SIZE, | ||
307 | .read = max6875_user_read, | ||
308 | .write = max6875_user_write, | ||
309 | }; | ||
310 | |||
311 | static struct bin_attribute config_eeprom_attr = { | ||
312 | .attr = { | ||
313 | .name = "eeprom_config", | ||
314 | .mode = S_IRUGO | S_IWUSR, | ||
315 | .owner = THIS_MODULE, | ||
316 | }, | ||
317 | .size = CONFIG_EEPROM_SIZE, | ||
318 | .read = max6875_config_read, | ||
319 | .write = max6875_config_write, | ||
320 | }; | ||
321 | |||
322 | static struct bin_attribute config_register_attr = { | ||
323 | .attr = { | ||
324 | .name = "reg_config", | ||
325 | .mode = S_IRUGO | S_IWUSR, | ||
326 | .owner = THIS_MODULE, | ||
327 | }, | ||
328 | .size = CONFIG_EEPROM_SIZE, | ||
329 | .read = max6875_cfgreg_read, | ||
330 | .write = max6875_cfgreg_write, | ||
331 | }; | ||
332 | |||
333 | static int max6875_attach_adapter(struct i2c_adapter *adapter) | ||
334 | { | ||
335 | return i2c_detect(adapter, &addr_data, max6875_detect); | ||
336 | } | ||
337 | |||
338 | /* This function is called by i2c_detect */ | ||
339 | static int max6875_detect(struct i2c_adapter *adapter, int address, int kind) | ||
340 | { | ||
341 | struct i2c_client *new_client; | ||
342 | struct max6875_data *data; | ||
343 | int err = 0; | ||
344 | |||
345 | /* There are three ways we can read the EEPROM data: | ||
346 | (1) I2C block reads (faster, but unsupported by most adapters) | ||
347 | (2) Consecutive byte reads (100% overhead) | ||
348 | (3) Regular byte data reads (200% overhead) | ||
349 | The third method is not implemented by this driver because all | ||
350 | known adapters support at least the second. */ | ||
351 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA | | ||
352 | I2C_FUNC_SMBUS_BYTE | | ||
353 | I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) | ||
354 | goto exit; | ||
355 | |||
356 | /* OK. For now, we presume we have a valid client. We now create the | ||
357 | client structure, even though we cannot fill it completely yet. | ||
358 | But it allows us to access eeprom_{read,write}_value. */ | ||
359 | if (!(data = kmalloc(sizeof(struct max6875_data), GFP_KERNEL))) { | ||
360 | err = -ENOMEM; | ||
361 | goto exit; | ||
362 | } | ||
363 | memset(data, 0, sizeof(struct max6875_data)); | ||
364 | |||
365 | new_client = &data->client; | ||
366 | i2c_set_clientdata(new_client, data); | ||
367 | new_client->addr = address; | ||
368 | new_client->adapter = adapter; | ||
369 | new_client->driver = &max6875_driver; | ||
370 | new_client->flags = 0; | ||
371 | |||
372 | /* Setup the user section */ | ||
373 | data->blocks[max6875_eeprom_user].type = max6875_eeprom_user; | ||
374 | data->blocks[max6875_eeprom_user].slices = USER_EEPROM_SLICES; | ||
375 | data->blocks[max6875_eeprom_user].size = USER_EEPROM_SIZE; | ||
376 | data->blocks[max6875_eeprom_user].base = USER_EEPROM_BASE; | ||
377 | data->blocks[max6875_eeprom_user].data = data->data; | ||
378 | data->blocks[max6875_eeprom_user].updated = data->last_updated; | ||
379 | |||
380 | /* Setup the config section */ | ||
381 | data->blocks[max6875_eeprom_config].type = max6875_eeprom_config; | ||
382 | data->blocks[max6875_eeprom_config].slices = CONFIG_EEPROM_SLICES; | ||
383 | data->blocks[max6875_eeprom_config].size = CONFIG_EEPROM_SIZE; | ||
384 | data->blocks[max6875_eeprom_config].base = CONFIG_EEPROM_BASE; | ||
385 | data->blocks[max6875_eeprom_config].data = &data->data[USER_EEPROM_SIZE]; | ||
386 | data->blocks[max6875_eeprom_config].updated = &data->last_updated[USER_EEPROM_SLICES]; | ||
387 | |||
388 | /* Setup the register section */ | ||
389 | data->blocks[max6875_register_config].type = max6875_register_config; | ||
390 | data->blocks[max6875_register_config].slices = CONFIG_EEPROM_SLICES; | ||
391 | data->blocks[max6875_register_config].size = CONFIG_EEPROM_SIZE; | ||
392 | data->blocks[max6875_register_config].base = 0; | ||
393 | data->blocks[max6875_register_config].data = &data->data[USER_EEPROM_SIZE+CONFIG_EEPROM_SIZE]; | ||
394 | data->blocks[max6875_register_config].updated = &data->last_updated[USER_EEPROM_SLICES+CONFIG_EEPROM_SLICES]; | ||
395 | |||
396 | /* Init the data */ | ||
397 | memset(data->data, 0xff, sizeof(data->data)); | ||
398 | |||
399 | /* Fill in the remaining client fields */ | ||
400 | strlcpy(new_client->name, "max6875", I2C_NAME_SIZE); | ||
401 | init_MUTEX(&data->update_lock); | ||
402 | |||
403 | /* Verify that the chip is really what we think it is */ | ||
404 | if ((max6875_update_slice(new_client, &data->blocks[max6875_eeprom_config], 4) < 0) || | ||
405 | (max6875_update_slice(new_client, &data->blocks[max6875_register_config], 4) < 0)) | ||
406 | goto exit_kfree; | ||
407 | |||
408 | /* 0x41,0x42 must be zero and 0x40 must match in eeprom and registers */ | ||
409 | if ((data->blocks[max6875_eeprom_config].data[0x41] != 0) || | ||
410 | (data->blocks[max6875_eeprom_config].data[0x42] != 0) || | ||
411 | (data->blocks[max6875_register_config].data[0x41] != 0) || | ||
412 | (data->blocks[max6875_register_config].data[0x42] != 0) || | ||
413 | (data->blocks[max6875_eeprom_config].data[0x40] != | ||
414 | data->blocks[max6875_register_config].data[0x40])) | ||
415 | goto exit_kfree; | ||
416 | |||
417 | /* Tell the I2C layer a new client has arrived */ | ||
418 | if ((err = i2c_attach_client(new_client))) | ||
419 | goto exit_kfree; | ||
420 | |||
421 | /* create the sysfs eeprom files with the correct permissions */ | ||
422 | if (allow_write == 0) { | ||
423 | user_eeprom_attr.attr.mode &= ~S_IWUGO; | ||
424 | user_eeprom_attr.write = NULL; | ||
425 | config_eeprom_attr.attr.mode &= ~S_IWUGO; | ||
426 | config_eeprom_attr.write = NULL; | ||
427 | config_register_attr.attr.mode &= ~S_IWUGO; | ||
428 | config_register_attr.write = NULL; | ||
429 | } | ||
430 | sysfs_create_bin_file(&new_client->dev.kobj, &user_eeprom_attr); | ||
431 | sysfs_create_bin_file(&new_client->dev.kobj, &config_eeprom_attr); | ||
432 | sysfs_create_bin_file(&new_client->dev.kobj, &config_register_attr); | ||
433 | |||
434 | return 0; | ||
435 | |||
436 | exit_kfree: | ||
437 | kfree(data); | ||
438 | exit: | ||
439 | return err; | ||
440 | } | ||
441 | |||
442 | static int max6875_detach_client(struct i2c_client *client) | ||
443 | { | ||
444 | int err; | ||
445 | |||
446 | err = i2c_detach_client(client); | ||
447 | if (err) { | ||
448 | dev_err(&client->dev, "Client deregistration failed, client not detached.\n"); | ||
449 | return err; | ||
450 | } | ||
451 | |||
452 | kfree(i2c_get_clientdata(client)); | ||
453 | |||
454 | return 0; | ||
455 | } | ||
456 | |||
457 | static int __init max6875_init(void) | ||
458 | { | ||
459 | return i2c_add_driver(&max6875_driver); | ||
460 | } | ||
461 | |||
462 | static void __exit max6875_exit(void) | ||
463 | { | ||
464 | i2c_del_driver(&max6875_driver); | ||
465 | } | ||
466 | |||
467 | |||
468 | MODULE_AUTHOR("Ben Gardner <bgardner@wabtec.com>"); | ||
469 | MODULE_DESCRIPTION("MAX6875 driver"); | ||
470 | MODULE_LICENSE("GPL"); | ||
471 | |||
472 | module_init(max6875_init); | ||
473 | module_exit(max6875_exit); | ||
diff --git a/drivers/i2c/chips/pc87360.c b/drivers/i2c/chips/pc87360.c index 65637b2cd170..876c68f3af31 100644 --- a/drivers/i2c/chips/pc87360.c +++ b/drivers/i2c/chips/pc87360.c | |||
@@ -33,7 +33,6 @@ | |||
33 | * the standard Super-I/O addresses is used (0x2E/0x2F or 0x4E/0x4F). | 33 | * the standard Super-I/O addresses is used (0x2E/0x2F or 0x4E/0x4F). |
34 | */ | 34 | */ |
35 | 35 | ||
36 | #include <linux/config.h> | ||
37 | #include <linux/module.h> | 36 | #include <linux/module.h> |
38 | #include <linux/init.h> | 37 | #include <linux/init.h> |
39 | #include <linux/slab.h> | 38 | #include <linux/slab.h> |
diff --git a/drivers/i2c/chips/pca9539.c b/drivers/i2c/chips/pca9539.c new file mode 100644 index 000000000000..9f3ad45daae2 --- /dev/null +++ b/drivers/i2c/chips/pca9539.c | |||
@@ -0,0 +1,192 @@ | |||
1 | /* | ||
2 | pca9539.c - 16-bit I/O port with interrupt and reset | ||
3 | |||
4 | Copyright (C) 2005 Ben Gardner <bgardner@wabtec.com> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; version 2 of the License. | ||
9 | */ | ||
10 | |||
11 | #include <linux/module.h> | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/slab.h> | ||
14 | #include <linux/i2c.h> | ||
15 | #include <linux/hwmon-sysfs.h> | ||
16 | #include <linux/i2c-sensor.h> | ||
17 | |||
18 | /* Addresses to scan */ | ||
19 | static unsigned short normal_i2c[] = {0x74, 0x75, 0x76, 0x77, I2C_CLIENT_END}; | ||
20 | static unsigned int normal_isa[] = {I2C_CLIENT_ISA_END}; | ||
21 | |||
22 | /* Insmod parameters */ | ||
23 | SENSORS_INSMOD_1(pca9539); | ||
24 | |||
25 | enum pca9539_cmd | ||
26 | { | ||
27 | PCA9539_INPUT_0 = 0, | ||
28 | PCA9539_INPUT_1 = 1, | ||
29 | PCA9539_OUTPUT_0 = 2, | ||
30 | PCA9539_OUTPUT_1 = 3, | ||
31 | PCA9539_INVERT_0 = 4, | ||
32 | PCA9539_INVERT_1 = 5, | ||
33 | PCA9539_DIRECTION_0 = 6, | ||
34 | PCA9539_DIRECTION_1 = 7, | ||
35 | }; | ||
36 | |||
37 | static int pca9539_attach_adapter(struct i2c_adapter *adapter); | ||
38 | static int pca9539_detect(struct i2c_adapter *adapter, int address, int kind); | ||
39 | static int pca9539_detach_client(struct i2c_client *client); | ||
40 | |||
41 | /* This is the driver that will be inserted */ | ||
42 | static struct i2c_driver pca9539_driver = { | ||
43 | .owner = THIS_MODULE, | ||
44 | .name = "pca9539", | ||
45 | .flags = I2C_DF_NOTIFY, | ||
46 | .attach_adapter = pca9539_attach_adapter, | ||
47 | .detach_client = pca9539_detach_client, | ||
48 | }; | ||
49 | |||
50 | struct pca9539_data { | ||
51 | struct i2c_client client; | ||
52 | }; | ||
53 | |||
54 | /* following are the sysfs callback functions */ | ||
55 | static ssize_t pca9539_show(struct device *dev, struct device_attribute *attr, | ||
56 | char *buf) | ||
57 | { | ||
58 | struct sensor_device_attribute *psa = to_sensor_dev_attr(attr); | ||
59 | struct i2c_client *client = to_i2c_client(dev); | ||
60 | return sprintf(buf, "%d\n", i2c_smbus_read_byte_data(client, | ||
61 | psa->index)); | ||
62 | } | ||
63 | |||
64 | static ssize_t pca9539_store(struct device *dev, struct device_attribute *attr, | ||
65 | const char *buf, size_t count) | ||
66 | { | ||
67 | struct sensor_device_attribute *psa = to_sensor_dev_attr(attr); | ||
68 | struct i2c_client *client = to_i2c_client(dev); | ||
69 | unsigned long val = simple_strtoul(buf, NULL, 0); | ||
70 | if (val > 0xff) | ||
71 | return -EINVAL; | ||
72 | i2c_smbus_write_byte_data(client, psa->index, val); | ||
73 | return count; | ||
74 | } | ||
75 | |||
76 | /* Define the device attributes */ | ||
77 | |||
78 | #define PCA9539_ENTRY_RO(name, cmd_idx) \ | ||
79 | static SENSOR_DEVICE_ATTR(name, S_IRUGO, pca9539_show, NULL, cmd_idx) | ||
80 | |||
81 | #define PCA9539_ENTRY_RW(name, cmd_idx) \ | ||
82 | static SENSOR_DEVICE_ATTR(name, S_IRUGO | S_IWUSR, pca9539_show, \ | ||
83 | pca9539_store, cmd_idx) | ||
84 | |||
85 | PCA9539_ENTRY_RO(input0, PCA9539_INPUT_0); | ||
86 | PCA9539_ENTRY_RO(input1, PCA9539_INPUT_1); | ||
87 | PCA9539_ENTRY_RW(output0, PCA9539_OUTPUT_0); | ||
88 | PCA9539_ENTRY_RW(output1, PCA9539_OUTPUT_1); | ||
89 | PCA9539_ENTRY_RW(invert0, PCA9539_INVERT_0); | ||
90 | PCA9539_ENTRY_RW(invert1, PCA9539_INVERT_1); | ||
91 | PCA9539_ENTRY_RW(direction0, PCA9539_DIRECTION_0); | ||
92 | PCA9539_ENTRY_RW(direction1, PCA9539_DIRECTION_1); | ||
93 | |||
94 | static struct attribute *pca9539_attributes[] = { | ||
95 | &sensor_dev_attr_input0.dev_attr.attr, | ||
96 | &sensor_dev_attr_input1.dev_attr.attr, | ||
97 | &sensor_dev_attr_output0.dev_attr.attr, | ||
98 | &sensor_dev_attr_output1.dev_attr.attr, | ||
99 | &sensor_dev_attr_invert0.dev_attr.attr, | ||
100 | &sensor_dev_attr_invert1.dev_attr.attr, | ||
101 | &sensor_dev_attr_direction0.dev_attr.attr, | ||
102 | &sensor_dev_attr_direction1.dev_attr.attr, | ||
103 | NULL | ||
104 | }; | ||
105 | |||
106 | static struct attribute_group pca9539_defattr_group = { | ||
107 | .attrs = pca9539_attributes, | ||
108 | }; | ||
109 | |||
110 | static int pca9539_attach_adapter(struct i2c_adapter *adapter) | ||
111 | { | ||
112 | return i2c_detect(adapter, &addr_data, pca9539_detect); | ||
113 | } | ||
114 | |||
115 | /* This function is called by i2c_detect */ | ||
116 | static int pca9539_detect(struct i2c_adapter *adapter, int address, int kind) | ||
117 | { | ||
118 | struct i2c_client *new_client; | ||
119 | struct pca9539_data *data; | ||
120 | int err = 0; | ||
121 | |||
122 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | ||
123 | goto exit; | ||
124 | |||
125 | /* OK. For now, we presume we have a valid client. We now create the | ||
126 | client structure, even though we cannot fill it completely yet. */ | ||
127 | if (!(data = kmalloc(sizeof(struct pca9539_data), GFP_KERNEL))) { | ||
128 | err = -ENOMEM; | ||
129 | goto exit; | ||
130 | } | ||
131 | memset(data, 0, sizeof(struct pca9539_data)); | ||
132 | |||
133 | new_client = &data->client; | ||
134 | i2c_set_clientdata(new_client, data); | ||
135 | new_client->addr = address; | ||
136 | new_client->adapter = adapter; | ||
137 | new_client->driver = &pca9539_driver; | ||
138 | new_client->flags = 0; | ||
139 | |||
140 | /* Detection: the pca9539 only has 8 registers (0-7). | ||
141 | A read of 7 should succeed, but a read of 8 should fail. */ | ||
142 | if ((i2c_smbus_read_byte_data(new_client, 7) < 0) || | ||
143 | (i2c_smbus_read_byte_data(new_client, 8) >= 0)) | ||
144 | goto exit_kfree; | ||
145 | |||
146 | strlcpy(new_client->name, "pca9539", I2C_NAME_SIZE); | ||
147 | |||
148 | /* Tell the I2C layer a new client has arrived */ | ||
149 | if ((err = i2c_attach_client(new_client))) | ||
150 | goto exit_kfree; | ||
151 | |||
152 | /* Register sysfs hooks (don't care about failure) */ | ||
153 | sysfs_create_group(&new_client->dev.kobj, &pca9539_defattr_group); | ||
154 | |||
155 | return 0; | ||
156 | |||
157 | exit_kfree: | ||
158 | kfree(data); | ||
159 | exit: | ||
160 | return err; | ||
161 | } | ||
162 | |||
163 | static int pca9539_detach_client(struct i2c_client *client) | ||
164 | { | ||
165 | int err; | ||
166 | |||
167 | if ((err = i2c_detach_client(client))) { | ||
168 | dev_err(&client->dev, "Client deregistration failed.\n"); | ||
169 | return err; | ||
170 | } | ||
171 | |||
172 | kfree(i2c_get_clientdata(client)); | ||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | static int __init pca9539_init(void) | ||
177 | { | ||
178 | return i2c_add_driver(&pca9539_driver); | ||
179 | } | ||
180 | |||
181 | static void __exit pca9539_exit(void) | ||
182 | { | ||
183 | i2c_del_driver(&pca9539_driver); | ||
184 | } | ||
185 | |||
186 | MODULE_AUTHOR("Ben Gardner <bgardner@wabtec.com>"); | ||
187 | MODULE_DESCRIPTION("PCA9539 driver"); | ||
188 | MODULE_LICENSE("GPL"); | ||
189 | |||
190 | module_init(pca9539_init); | ||
191 | module_exit(pca9539_exit); | ||
192 | |||
diff --git a/drivers/i2c/chips/pcf8574.c b/drivers/i2c/chips/pcf8574.c index 4956e9effd75..cfcf64654080 100644 --- a/drivers/i2c/chips/pcf8574.c +++ b/drivers/i2c/chips/pcf8574.c | |||
@@ -57,7 +57,7 @@ SENSORS_INSMOD_2(pcf8574, pcf8574a); | |||
57 | struct pcf8574_data { | 57 | struct pcf8574_data { |
58 | struct i2c_client client; | 58 | struct i2c_client client; |
59 | 59 | ||
60 | u8 read, write; /* Register values */ | 60 | u8 write; /* Remember last written value */ |
61 | }; | 61 | }; |
62 | 62 | ||
63 | static int pcf8574_attach_adapter(struct i2c_adapter *adapter); | 63 | static int pcf8574_attach_adapter(struct i2c_adapter *adapter); |
@@ -79,9 +79,7 @@ static struct i2c_driver pcf8574_driver = { | |||
79 | static ssize_t show_read(struct device *dev, struct device_attribute *attr, char *buf) | 79 | static ssize_t show_read(struct device *dev, struct device_attribute *attr, char *buf) |
80 | { | 80 | { |
81 | struct i2c_client *client = to_i2c_client(dev); | 81 | struct i2c_client *client = to_i2c_client(dev); |
82 | struct pcf8574_data *data = i2c_get_clientdata(client); | 82 | return sprintf(buf, "%u\n", i2c_smbus_read_byte(client)); |
83 | data->read = i2c_smbus_read_byte(client); | ||
84 | return sprintf(buf, "%u\n", data->read); | ||
85 | } | 83 | } |
86 | 84 | ||
87 | static DEVICE_ATTR(read, S_IRUGO, show_read, NULL); | 85 | static DEVICE_ATTR(read, S_IRUGO, show_read, NULL); |
diff --git a/drivers/i2c/chips/rtc8564.c b/drivers/i2c/chips/rtc8564.c index 5a9deddb626b..588fc2261a91 100644 --- a/drivers/i2c/chips/rtc8564.c +++ b/drivers/i2c/chips/rtc8564.c | |||
@@ -19,7 +19,6 @@ | |||
19 | #include <linux/string.h> | 19 | #include <linux/string.h> |
20 | #include <linux/rtc.h> /* get the user-level API */ | 20 | #include <linux/rtc.h> /* get the user-level API */ |
21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
22 | #include <linux/init.h> | ||
23 | 22 | ||
24 | #include "rtc8564.h" | 23 | #include "rtc8564.h" |
25 | 24 | ||
@@ -66,11 +65,8 @@ static unsigned short normal_addr[] = { 0x51, I2C_CLIENT_END }; | |||
66 | 65 | ||
67 | static struct i2c_client_address_data addr_data = { | 66 | static struct i2c_client_address_data addr_data = { |
68 | .normal_i2c = normal_addr, | 67 | .normal_i2c = normal_addr, |
69 | .normal_i2c_range = ignore, | ||
70 | .probe = ignore, | 68 | .probe = ignore, |
71 | .probe_range = ignore, | ||
72 | .ignore = ignore, | 69 | .ignore = ignore, |
73 | .ignore_range = ignore, | ||
74 | .force = ignore, | 70 | .force = ignore, |
75 | }; | 71 | }; |
76 | 72 | ||
diff --git a/drivers/i2c/chips/sis5595.c b/drivers/i2c/chips/sis5595.c index c6650727a27d..6bbfc8fb4f13 100644 --- a/drivers/i2c/chips/sis5595.c +++ b/drivers/i2c/chips/sis5595.c | |||
@@ -57,6 +57,7 @@ | |||
57 | #include <linux/i2c.h> | 57 | #include <linux/i2c.h> |
58 | #include <linux/i2c-sensor.h> | 58 | #include <linux/i2c-sensor.h> |
59 | #include <linux/init.h> | 59 | #include <linux/init.h> |
60 | #include <linux/jiffies.h> | ||
60 | #include <asm/io.h> | 61 | #include <asm/io.h> |
61 | 62 | ||
62 | 63 | ||
diff --git a/drivers/i2c/chips/smsc47m1.c b/drivers/i2c/chips/smsc47m1.c index 13d6d4a8bc7d..897117a7213f 100644 --- a/drivers/i2c/chips/smsc47m1.c +++ b/drivers/i2c/chips/smsc47m1.c | |||
@@ -372,14 +372,16 @@ static int smsc47m1_find(int *address) | |||
372 | * SMSC LPC47M10x/LPC47M13x (device id 0x59), LPC47M14x (device id | 372 | * SMSC LPC47M10x/LPC47M13x (device id 0x59), LPC47M14x (device id |
373 | * 0x5F) and LPC47B27x (device id 0x51) have fan control. | 373 | * 0x5F) and LPC47B27x (device id 0x51) have fan control. |
374 | * The LPC47M15x and LPC47M192 chips "with hardware monitoring block" | 374 | * The LPC47M15x and LPC47M192 chips "with hardware monitoring block" |
375 | * can do much more besides (device id 0x60, unsupported). | 375 | * can do much more besides (device id 0x60). |
376 | */ | 376 | */ |
377 | if (val == 0x51) | 377 | if (val == 0x51) |
378 | printk(KERN_INFO "smsc47m1: Found SMSC47B27x\n"); | 378 | printk(KERN_INFO "smsc47m1: Found SMSC LPC47B27x\n"); |
379 | else if (val == 0x59) | 379 | else if (val == 0x59) |
380 | printk(KERN_INFO "smsc47m1: Found SMSC47M10x/SMSC47M13x\n"); | 380 | printk(KERN_INFO "smsc47m1: Found SMSC LPC47M10x/LPC47M13x\n"); |
381 | else if (val == 0x5F) | 381 | else if (val == 0x5F) |
382 | printk(KERN_INFO "smsc47m1: Found SMSC47M14x\n"); | 382 | printk(KERN_INFO "smsc47m1: Found SMSC LPC47M14x\n"); |
383 | else if (val == 0x60) | ||
384 | printk(KERN_INFO "smsc47m1: Found SMSC LPC47M15x/LPC47M192\n"); | ||
383 | else { | 385 | else { |
384 | superio_exit(); | 386 | superio_exit(); |
385 | return -ENODEV; | 387 | return -ENODEV; |
diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c new file mode 100644 index 000000000000..c0ac01b60039 --- /dev/null +++ b/drivers/i2c/chips/tps65010.c | |||
@@ -0,0 +1,1072 @@ | |||
1 | /* | ||
2 | * tps65010 - driver for tps6501x power management chips | ||
3 | * | ||
4 | * Copyright (C) 2004 Texas Instruments | ||
5 | * Copyright (C) 2004-2005 David Brownell | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | #undef DEBUG | ||
22 | |||
23 | #include <linux/config.h> | ||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include <linux/interrupt.h> | ||
29 | #include <linux/device.h> | ||
30 | #include <linux/i2c.h> | ||
31 | #include <linux/delay.h> | ||
32 | #include <linux/workqueue.h> | ||
33 | #include <linux/suspend.h> | ||
34 | #include <linux/debugfs.h> | ||
35 | #include <linux/seq_file.h> | ||
36 | |||
37 | #include <asm/irq.h> | ||
38 | #include <asm/mach-types.h> | ||
39 | |||
40 | #include <asm/arch/gpio.h> | ||
41 | #include <asm/arch/mux.h> | ||
42 | #include <asm/arch/tps65010.h> | ||
43 | |||
44 | /*-------------------------------------------------------------------------*/ | ||
45 | |||
46 | #define DRIVER_VERSION "2 May 2005" | ||
47 | #define DRIVER_NAME (tps65010_driver.name) | ||
48 | |||
49 | MODULE_DESCRIPTION("TPS6501x Power Management Driver"); | ||
50 | MODULE_LICENSE("GPL"); | ||
51 | |||
52 | /* only two addresses possible */ | ||
53 | #define TPS_BASE 0x48 | ||
54 | static unsigned short normal_i2c[] = { | ||
55 | TPS_BASE, | ||
56 | I2C_CLIENT_END }; | ||
57 | static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; | ||
58 | |||
59 | I2C_CLIENT_INSMOD; | ||
60 | |||
61 | static struct i2c_driver tps65010_driver; | ||
62 | |||
63 | /*-------------------------------------------------------------------------*/ | ||
64 | |||
65 | /* This driver handles a family of multipurpose chips, which incorporate | ||
66 | * voltage regulators, lithium ion/polymer battery charging, GPIOs, LEDs, | ||
67 | * and other features often needed in portable devices like cell phones | ||
68 | * or digital cameras. | ||
69 | * | ||
70 | * The tps65011 and tps65013 have different voltage settings compared | ||
71 | * to tps65010 and tps65012. The tps65013 has a NO_CHG status/irq. | ||
72 | * All except tps65010 have "wait" mode, possibly defaulted so that | ||
73 | * battery-insert != device-on. | ||
74 | * | ||
75 | * We could distinguish between some models by checking VDCDC1.UVLO or | ||
76 | * other registers, unless they've been changed already after powerup | ||
77 | * as part of board setup by a bootloader. | ||
78 | */ | ||
79 | enum tps_model { | ||
80 | TPS_UNKNOWN = 0, | ||
81 | TPS65010, | ||
82 | TPS65011, | ||
83 | TPS65012, | ||
84 | TPS65013, | ||
85 | }; | ||
86 | |||
87 | struct tps65010 { | ||
88 | struct i2c_client client; | ||
89 | struct semaphore lock; | ||
90 | int irq; | ||
91 | struct work_struct work; | ||
92 | struct dentry *file; | ||
93 | unsigned charging:1; | ||
94 | unsigned por:1; | ||
95 | unsigned model:8; | ||
96 | u16 vbus; | ||
97 | unsigned long flags; | ||
98 | #define FLAG_VBUS_CHANGED 0 | ||
99 | #define FLAG_IRQ_ENABLE 1 | ||
100 | |||
101 | /* copies of last register state */ | ||
102 | u8 chgstatus, regstatus, chgconf; | ||
103 | u8 nmask1, nmask2; | ||
104 | |||
105 | /* plus four GPIOs, probably used to switch power */ | ||
106 | }; | ||
107 | |||
108 | #define POWER_POLL_DELAY msecs_to_jiffies(800) | ||
109 | |||
110 | /*-------------------------------------------------------------------------*/ | ||
111 | |||
112 | #if defined(DEBUG) || defined(CONFIG_DEBUG_FS) | ||
113 | |||
114 | static void dbg_chgstat(char *buf, size_t len, u8 chgstatus) | ||
115 | { | ||
116 | snprintf(buf, len, "%02x%s%s%s%s%s%s%s%s\n", | ||
117 | chgstatus, | ||
118 | (chgstatus & TPS_CHG_USB) ? " USB" : "", | ||
119 | (chgstatus & TPS_CHG_AC) ? " AC" : "", | ||
120 | (chgstatus & TPS_CHG_THERM) ? " therm" : "", | ||
121 | (chgstatus & TPS_CHG_TERM) ? " done" : | ||
122 | ((chgstatus & (TPS_CHG_USB|TPS_CHG_AC)) | ||
123 | ? " (charging)" : ""), | ||
124 | (chgstatus & TPS_CHG_TAPER_TMO) ? " taper_tmo" : "", | ||
125 | (chgstatus & TPS_CHG_CHG_TMO) ? " charge_tmo" : "", | ||
126 | (chgstatus & TPS_CHG_PRECHG_TMO) ? " prechg_tmo" : "", | ||
127 | (chgstatus & TPS_CHG_TEMP_ERR) ? " temp_err" : ""); | ||
128 | } | ||
129 | |||
130 | static void dbg_regstat(char *buf, size_t len, u8 regstatus) | ||
131 | { | ||
132 | snprintf(buf, len, "%02x %s%s%s%s%s%s%s%s\n", | ||
133 | regstatus, | ||
134 | (regstatus & TPS_REG_ONOFF) ? "off" : "(on)", | ||
135 | (regstatus & TPS_REG_COVER) ? " uncover" : "", | ||
136 | (regstatus & TPS_REG_UVLO) ? " UVLO" : "", | ||
137 | (regstatus & TPS_REG_NO_CHG) ? " NO_CHG" : "", | ||
138 | (regstatus & TPS_REG_PG_LD02) ? " ld01_bad" : "", | ||
139 | (regstatus & TPS_REG_PG_LD01) ? " ld01_bad" : "", | ||
140 | (regstatus & TPS_REG_PG_MAIN) ? " main_bad" : "", | ||
141 | (regstatus & TPS_REG_PG_CORE) ? " core_bad" : ""); | ||
142 | } | ||
143 | |||
144 | static void dbg_chgconf(int por, char *buf, size_t len, u8 chgconfig) | ||
145 | { | ||
146 | char *hibit; | ||
147 | |||
148 | if (por) | ||
149 | hibit = (chgconfig & TPS_CHARGE_POR) | ||
150 | ? "POR=69ms" : "POR=1sec"; | ||
151 | else | ||
152 | hibit = (chgconfig & TPS65013_AUA) ? "AUA" : ""; | ||
153 | |||
154 | snprintf(buf, len, "%02x %s%s%s AC=%d%% USB=%dmA %sCharge\n", | ||
155 | chgconfig, hibit, | ||
156 | (chgconfig & TPS_CHARGE_RESET) ? " reset" : "", | ||
157 | (chgconfig & TPS_CHARGE_FAST) ? " fast" : "", | ||
158 | ({int p; switch ((chgconfig >> 3) & 3) { | ||
159 | case 3: p = 100; break; | ||
160 | case 2: p = 75; break; | ||
161 | case 1: p = 50; break; | ||
162 | default: p = 25; break; | ||
163 | }; p; }), | ||
164 | (chgconfig & TPS_VBUS_CHARGING) | ||
165 | ? ((chgconfig & TPS_VBUS_500MA) ? 500 : 100) | ||
166 | : 0, | ||
167 | (chgconfig & TPS_CHARGE_ENABLE) ? "" : "No"); | ||
168 | } | ||
169 | |||
170 | #endif | ||
171 | |||
172 | #ifdef DEBUG | ||
173 | |||
174 | static void show_chgstatus(const char *label, u8 chgstatus) | ||
175 | { | ||
176 | char buf [100]; | ||
177 | |||
178 | dbg_chgstat(buf, sizeof buf, chgstatus); | ||
179 | pr_debug("%s: %s %s", DRIVER_NAME, label, buf); | ||
180 | } | ||
181 | |||
182 | static void show_regstatus(const char *label, u8 regstatus) | ||
183 | { | ||
184 | char buf [100]; | ||
185 | |||
186 | dbg_regstat(buf, sizeof buf, regstatus); | ||
187 | pr_debug("%s: %s %s", DRIVER_NAME, label, buf); | ||
188 | } | ||
189 | |||
190 | static void show_chgconfig(int por, const char *label, u8 chgconfig) | ||
191 | { | ||
192 | char buf [100]; | ||
193 | |||
194 | dbg_chgconf(por, buf, sizeof buf, chgconfig); | ||
195 | pr_debug("%s: %s %s", DRIVER_NAME, label, buf); | ||
196 | } | ||
197 | |||
198 | #else | ||
199 | |||
200 | static inline void show_chgstatus(const char *label, u8 chgstatus) { } | ||
201 | static inline void show_regstatus(const char *label, u8 chgstatus) { } | ||
202 | static inline void show_chgconfig(int por, const char *label, u8 chgconfig) { } | ||
203 | |||
204 | #endif | ||
205 | |||
206 | #ifdef CONFIG_DEBUG_FS | ||
207 | |||
208 | static int dbg_show(struct seq_file *s, void *_) | ||
209 | { | ||
210 | struct tps65010 *tps = s->private; | ||
211 | u8 value, v2; | ||
212 | unsigned i; | ||
213 | char buf[100]; | ||
214 | const char *chip; | ||
215 | |||
216 | switch (tps->model) { | ||
217 | case TPS65010: chip = "tps65010"; break; | ||
218 | case TPS65011: chip = "tps65011"; break; | ||
219 | case TPS65012: chip = "tps65012"; break; | ||
220 | case TPS65013: chip = "tps65013"; break; | ||
221 | default: chip = NULL; break; | ||
222 | } | ||
223 | seq_printf(s, "driver %s\nversion %s\nchip %s\n\n", | ||
224 | DRIVER_NAME, DRIVER_VERSION, chip); | ||
225 | |||
226 | down(&tps->lock); | ||
227 | |||
228 | /* FIXME how can we tell whether a battery is present? | ||
229 | * likely involves a charge gauging chip (like BQ26501). | ||
230 | */ | ||
231 | |||
232 | seq_printf(s, "%scharging\n\n", tps->charging ? "" : "(not) "); | ||
233 | |||
234 | |||
235 | /* registers for monitoring battery charging and status; note | ||
236 | * that reading chgstat and regstat may ack IRQs... | ||
237 | */ | ||
238 | value = i2c_smbus_read_byte_data(&tps->client, TPS_CHGCONFIG); | ||
239 | dbg_chgconf(tps->por, buf, sizeof buf, value); | ||
240 | seq_printf(s, "chgconfig %s", buf); | ||
241 | |||
242 | value = i2c_smbus_read_byte_data(&tps->client, TPS_CHGSTATUS); | ||
243 | dbg_chgstat(buf, sizeof buf, value); | ||
244 | seq_printf(s, "chgstat %s", buf); | ||
245 | value = i2c_smbus_read_byte_data(&tps->client, TPS_MASK1); | ||
246 | dbg_chgstat(buf, sizeof buf, value); | ||
247 | seq_printf(s, "mask1 %s", buf); | ||
248 | /* ignore ackint1 */ | ||
249 | |||
250 | value = i2c_smbus_read_byte_data(&tps->client, TPS_REGSTATUS); | ||
251 | dbg_regstat(buf, sizeof buf, value); | ||
252 | seq_printf(s, "regstat %s", buf); | ||
253 | value = i2c_smbus_read_byte_data(&tps->client, TPS_MASK2); | ||
254 | dbg_regstat(buf, sizeof buf, value); | ||
255 | seq_printf(s, "mask2 %s\n", buf); | ||
256 | /* ignore ackint2 */ | ||
257 | |||
258 | (void) schedule_delayed_work(&tps->work, POWER_POLL_DELAY); | ||
259 | |||
260 | |||
261 | /* VMAIN voltage, enable lowpower, etc */ | ||
262 | value = i2c_smbus_read_byte_data(&tps->client, TPS_VDCDC1); | ||
263 | seq_printf(s, "vdcdc1 %02x\n", value); | ||
264 | |||
265 | /* VCORE voltage, vibrator on/off */ | ||
266 | value = i2c_smbus_read_byte_data(&tps->client, TPS_VDCDC2); | ||
267 | seq_printf(s, "vdcdc2 %02x\n", value); | ||
268 | |||
269 | /* both LD0s, and their lowpower behavior */ | ||
270 | value = i2c_smbus_read_byte_data(&tps->client, TPS_VREGS1); | ||
271 | seq_printf(s, "vregs1 %02x\n\n", value); | ||
272 | |||
273 | |||
274 | /* LEDs and GPIOs */ | ||
275 | value = i2c_smbus_read_byte_data(&tps->client, TPS_LED1_ON); | ||
276 | v2 = i2c_smbus_read_byte_data(&tps->client, TPS_LED1_PER); | ||
277 | seq_printf(s, "led1 %s, on=%02x, per=%02x, %d/%d msec\n", | ||
278 | (value & 0x80) | ||
279 | ? ((v2 & 0x80) ? "on" : "off") | ||
280 | : ((v2 & 0x80) ? "blink" : "(nPG)"), | ||
281 | value, v2, | ||
282 | (value & 0x7f) * 10, (v2 & 0x7f) * 100); | ||
283 | |||
284 | value = i2c_smbus_read_byte_data(&tps->client, TPS_LED2_ON); | ||
285 | v2 = i2c_smbus_read_byte_data(&tps->client, TPS_LED2_PER); | ||
286 | seq_printf(s, "led2 %s, on=%02x, per=%02x, %d/%d msec\n", | ||
287 | (value & 0x80) | ||
288 | ? ((v2 & 0x80) ? "on" : "off") | ||
289 | : ((v2 & 0x80) ? "blink" : "off"), | ||
290 | value, v2, | ||
291 | (value & 0x7f) * 10, (v2 & 0x7f) * 100); | ||
292 | |||
293 | value = i2c_smbus_read_byte_data(&tps->client, TPS_DEFGPIO); | ||
294 | v2 = i2c_smbus_read_byte_data(&tps->client, TPS_MASK3); | ||
295 | seq_printf(s, "defgpio %02x mask3 %02x\n", value, v2); | ||
296 | |||
297 | for (i = 0; i < 4; i++) { | ||
298 | if (value & (1 << (4 +i))) | ||
299 | seq_printf(s, " gpio%d-out %s\n", i + 1, | ||
300 | (value & (1 << i)) ? "low" : "hi "); | ||
301 | else | ||
302 | seq_printf(s, " gpio%d-in %s %s %s\n", i + 1, | ||
303 | (value & (1 << i)) ? "hi " : "low", | ||
304 | (v2 & (1 << i)) ? "no-irq" : "irq", | ||
305 | (v2 & (1 << (4 + i))) ? "rising" : "falling"); | ||
306 | } | ||
307 | |||
308 | up(&tps->lock); | ||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | static int dbg_tps_open(struct inode *inode, struct file *file) | ||
313 | { | ||
314 | return single_open(file, dbg_show, inode->u.generic_ip); | ||
315 | } | ||
316 | |||
317 | static struct file_operations debug_fops = { | ||
318 | .open = dbg_tps_open, | ||
319 | .read = seq_read, | ||
320 | .llseek = seq_lseek, | ||
321 | .release = single_release, | ||
322 | }; | ||
323 | |||
324 | #define DEBUG_FOPS &debug_fops | ||
325 | |||
326 | #else | ||
327 | #define DEBUG_FOPS NULL | ||
328 | #endif | ||
329 | |||
330 | /*-------------------------------------------------------------------------*/ | ||
331 | |||
332 | /* handle IRQS in a task context, so we can use I2C calls */ | ||
333 | static void tps65010_interrupt(struct tps65010 *tps) | ||
334 | { | ||
335 | u8 tmp = 0, mask, poll; | ||
336 | |||
337 | /* IRQs won't trigger irqs for certain events, but we can get | ||
338 | * others by polling (normally, with external power applied). | ||
339 | */ | ||
340 | poll = 0; | ||
341 | |||
342 | /* regstatus irqs */ | ||
343 | if (tps->nmask2) { | ||
344 | tmp = i2c_smbus_read_byte_data(&tps->client, TPS_REGSTATUS); | ||
345 | mask = tmp ^ tps->regstatus; | ||
346 | tps->regstatus = tmp; | ||
347 | mask &= tps->nmask2; | ||
348 | } else | ||
349 | mask = 0; | ||
350 | if (mask) { | ||
351 | tps->regstatus = tmp; | ||
352 | /* may need to shut something down ... */ | ||
353 | |||
354 | /* "off" usually means deep sleep */ | ||
355 | if (tmp & TPS_REG_ONOFF) { | ||
356 | pr_info("%s: power off button\n", DRIVER_NAME); | ||
357 | #if 0 | ||
358 | /* REVISIT: this might need its own workqueue | ||
359 | * plus tweaks including deadlock avoidance ... | ||
360 | */ | ||
361 | software_suspend(); | ||
362 | #endif | ||
363 | poll = 1; | ||
364 | } | ||
365 | } | ||
366 | |||
367 | /* chgstatus irqs */ | ||
368 | if (tps->nmask1) { | ||
369 | tmp = i2c_smbus_read_byte_data(&tps->client, TPS_CHGSTATUS); | ||
370 | mask = tmp ^ tps->chgstatus; | ||
371 | tps->chgstatus = tmp; | ||
372 | mask &= tps->nmask1; | ||
373 | } else | ||
374 | mask = 0; | ||
375 | if (mask) { | ||
376 | unsigned charging = 0; | ||
377 | |||
378 | show_chgstatus("chg/irq", tmp); | ||
379 | if (tmp & (TPS_CHG_USB|TPS_CHG_AC)) | ||
380 | show_chgconfig(tps->por, "conf", tps->chgconf); | ||
381 | |||
382 | /* Unless it was turned off or disabled, we charge any | ||
383 | * battery whenever there's power available for it | ||
384 | * and the charger hasn't been disabled. | ||
385 | */ | ||
386 | if (!(tps->chgstatus & ~(TPS_CHG_USB|TPS_CHG_AC)) | ||
387 | && (tps->chgstatus & (TPS_CHG_USB|TPS_CHG_AC)) | ||
388 | && (tps->chgconf & TPS_CHARGE_ENABLE) | ||
389 | ) { | ||
390 | if (tps->chgstatus & TPS_CHG_USB) { | ||
391 | /* VBUS options are readonly until reconnect */ | ||
392 | if (mask & TPS_CHG_USB) | ||
393 | set_bit(FLAG_VBUS_CHANGED, &tps->flags); | ||
394 | charging = 1; | ||
395 | } else if (tps->chgstatus & TPS_CHG_AC) | ||
396 | charging = 1; | ||
397 | } | ||
398 | if (charging != tps->charging) { | ||
399 | tps->charging = charging; | ||
400 | pr_info("%s: battery %scharging\n", | ||
401 | DRIVER_NAME, charging ? "" : | ||
402 | ((tps->chgstatus & (TPS_CHG_USB|TPS_CHG_AC)) | ||
403 | ? "NOT " : "dis")); | ||
404 | } | ||
405 | } | ||
406 | |||
407 | /* always poll to detect (a) power removal, without tps65013 | ||
408 | * NO_CHG IRQ; or (b) restart of charging after stop. | ||
409 | */ | ||
410 | if ((tps->model != TPS65013 || !tps->charging) | ||
411 | && (tps->chgstatus & (TPS_CHG_USB|TPS_CHG_AC))) | ||
412 | poll = 1; | ||
413 | if (poll) | ||
414 | (void) schedule_delayed_work(&tps->work, POWER_POLL_DELAY); | ||
415 | |||
416 | /* also potentially gpio-in rise or fall */ | ||
417 | } | ||
418 | |||
419 | /* handle IRQs and polling using keventd for now */ | ||
420 | static void tps65010_work(void *_tps) | ||
421 | { | ||
422 | struct tps65010 *tps = _tps; | ||
423 | |||
424 | down(&tps->lock); | ||
425 | |||
426 | tps65010_interrupt(tps); | ||
427 | |||
428 | if (test_and_clear_bit(FLAG_VBUS_CHANGED, &tps->flags)) { | ||
429 | int status; | ||
430 | u8 chgconfig, tmp; | ||
431 | |||
432 | chgconfig = i2c_smbus_read_byte_data(&tps->client, | ||
433 | TPS_CHGCONFIG); | ||
434 | chgconfig &= ~(TPS_VBUS_500MA | TPS_VBUS_CHARGING); | ||
435 | if (tps->vbus == 500) | ||
436 | chgconfig |= TPS_VBUS_500MA | TPS_VBUS_CHARGING; | ||
437 | else if (tps->vbus >= 100) | ||
438 | chgconfig |= TPS_VBUS_CHARGING; | ||
439 | |||
440 | status = i2c_smbus_write_byte_data(&tps->client, | ||
441 | TPS_CHGCONFIG, chgconfig); | ||
442 | |||
443 | /* vbus update fails unless VBUS is connected! */ | ||
444 | tmp = i2c_smbus_read_byte_data(&tps->client, TPS_CHGCONFIG); | ||
445 | tps->chgconf = tmp; | ||
446 | show_chgconfig(tps->por, "update vbus", tmp); | ||
447 | } | ||
448 | |||
449 | if (test_and_clear_bit(FLAG_IRQ_ENABLE, &tps->flags)) | ||
450 | enable_irq(tps->irq); | ||
451 | |||
452 | up(&tps->lock); | ||
453 | } | ||
454 | |||
455 | static irqreturn_t tps65010_irq(int irq, void *_tps, struct pt_regs *regs) | ||
456 | { | ||
457 | struct tps65010 *tps = _tps; | ||
458 | |||
459 | disable_irq_nosync(irq); | ||
460 | set_bit(FLAG_IRQ_ENABLE, &tps->flags); | ||
461 | (void) schedule_work(&tps->work); | ||
462 | return IRQ_HANDLED; | ||
463 | } | ||
464 | |||
465 | /*-------------------------------------------------------------------------*/ | ||
466 | |||
467 | static struct tps65010 *the_tps; | ||
468 | |||
469 | static int __exit tps65010_detach_client(struct i2c_client *client) | ||
470 | { | ||
471 | struct tps65010 *tps; | ||
472 | |||
473 | tps = container_of(client, struct tps65010, client); | ||
474 | #ifdef CONFIG_ARM | ||
475 | if (machine_is_omap_h2()) | ||
476 | omap_free_gpio(58); | ||
477 | if (machine_is_omap_osk()) | ||
478 | omap_free_gpio(OMAP_MPUIO(1)); | ||
479 | #endif | ||
480 | free_irq(tps->irq, tps); | ||
481 | debugfs_remove(tps->file); | ||
482 | if (i2c_detach_client(client) == 0) | ||
483 | kfree(tps); | ||
484 | the_tps = 0; | ||
485 | return 0; | ||
486 | } | ||
487 | |||
488 | static int tps65010_noscan(struct i2c_adapter *bus) | ||
489 | { | ||
490 | /* pure paranoia, in case someone adds another i2c bus | ||
491 | * after our init section's gone... | ||
492 | */ | ||
493 | return -ENODEV; | ||
494 | } | ||
495 | |||
496 | /* no error returns, they'd just make bus scanning stop */ | ||
497 | static int __init | ||
498 | tps65010_probe(struct i2c_adapter *bus, int address, int kind) | ||
499 | { | ||
500 | struct tps65010 *tps; | ||
501 | int status; | ||
502 | |||
503 | if (the_tps) { | ||
504 | dev_dbg(&bus->dev, "only one %s for now\n", DRIVER_NAME); | ||
505 | return 0; | ||
506 | } | ||
507 | |||
508 | tps = kmalloc(sizeof *tps, GFP_KERNEL); | ||
509 | if (!tps) | ||
510 | return 0; | ||
511 | |||
512 | memset(tps, 0, sizeof *tps); | ||
513 | init_MUTEX(&tps->lock); | ||
514 | INIT_WORK(&tps->work, tps65010_work, tps); | ||
515 | tps->irq = -1; | ||
516 | tps->client.addr = address; | ||
517 | i2c_set_clientdata(&tps->client, tps); | ||
518 | tps->client.adapter = bus; | ||
519 | tps->client.driver = &tps65010_driver; | ||
520 | strlcpy(tps->client.name, DRIVER_NAME, I2C_NAME_SIZE); | ||
521 | |||
522 | status = i2c_attach_client(&tps->client); | ||
523 | if (status < 0) { | ||
524 | dev_dbg(&bus->dev, "can't attach %s to device %d, err %d\n", | ||
525 | DRIVER_NAME, address, status); | ||
526 | fail1: | ||
527 | kfree(tps); | ||
528 | return 0; | ||
529 | } | ||
530 | |||
531 | #ifdef CONFIG_ARM | ||
532 | if (machine_is_omap_h2()) { | ||
533 | tps->model = TPS65010; | ||
534 | omap_cfg_reg(W4_GPIO58); | ||
535 | tps->irq = OMAP_GPIO_IRQ(58); | ||
536 | omap_request_gpio(58); | ||
537 | omap_set_gpio_direction(58, 1); | ||
538 | omap_set_gpio_edge_ctrl(58, OMAP_GPIO_FALLING_EDGE); | ||
539 | } | ||
540 | if (machine_is_omap_osk()) { | ||
541 | tps->model = TPS65010; | ||
542 | // omap_cfg_reg(U19_1610_MPUIO1); | ||
543 | tps->irq = OMAP_GPIO_IRQ(OMAP_MPUIO(1)); | ||
544 | omap_request_gpio(OMAP_MPUIO(1)); | ||
545 | omap_set_gpio_direction(OMAP_MPUIO(1), 1); | ||
546 | omap_set_gpio_edge_ctrl(OMAP_MPUIO(1), OMAP_GPIO_FALLING_EDGE); | ||
547 | } | ||
548 | if (machine_is_omap_h3()) { | ||
549 | tps->model = TPS65013; | ||
550 | |||
551 | // FIXME set up this board's IRQ ... | ||
552 | } | ||
553 | #else | ||
554 | #define set_irq_type(num,trigger) do{}while(0) | ||
555 | #endif | ||
556 | |||
557 | if (tps->irq > 0) { | ||
558 | set_irq_type(tps->irq, IRQT_LOW); | ||
559 | status = request_irq(tps->irq, tps65010_irq, | ||
560 | SA_SAMPLE_RANDOM, DRIVER_NAME, tps); | ||
561 | if (status < 0) { | ||
562 | dev_dbg(&tps->client.dev, "can't get IRQ %d, err %d\n", | ||
563 | tps->irq, status); | ||
564 | i2c_detach_client(&tps->client); | ||
565 | goto fail1; | ||
566 | } | ||
567 | #ifdef CONFIG_ARM | ||
568 | /* annoying race here, ideally we'd have an option | ||
569 | * to claim the irq now and enable it later. | ||
570 | */ | ||
571 | disable_irq(tps->irq); | ||
572 | set_bit(FLAG_IRQ_ENABLE, &tps->flags); | ||
573 | #endif | ||
574 | } else | ||
575 | printk(KERN_WARNING "%s: IRQ not configured!\n", | ||
576 | DRIVER_NAME); | ||
577 | |||
578 | |||
579 | switch (tps->model) { | ||
580 | case TPS65010: | ||
581 | case TPS65012: | ||
582 | tps->por = 1; | ||
583 | break; | ||
584 | case TPS_UNKNOWN: | ||
585 | printk(KERN_WARNING "%s: unknown TPS chip\n", DRIVER_NAME); | ||
586 | break; | ||
587 | /* else CHGCONFIG.POR is replaced by AUA, enabling a WAIT mode */ | ||
588 | } | ||
589 | tps->chgconf = i2c_smbus_read_byte_data(&tps->client, TPS_CHGCONFIG); | ||
590 | show_chgconfig(tps->por, "conf/init", tps->chgconf); | ||
591 | |||
592 | show_chgstatus("chg/init", | ||
593 | i2c_smbus_read_byte_data(&tps->client, TPS_CHGSTATUS)); | ||
594 | show_regstatus("reg/init", | ||
595 | i2c_smbus_read_byte_data(&tps->client, TPS_REGSTATUS)); | ||
596 | |||
597 | pr_debug("%s: vdcdc1 0x%02x, vdcdc2 %02x, vregs1 %02x\n", DRIVER_NAME, | ||
598 | i2c_smbus_read_byte_data(&tps->client, TPS_VDCDC1), | ||
599 | i2c_smbus_read_byte_data(&tps->client, TPS_VDCDC2), | ||
600 | i2c_smbus_read_byte_data(&tps->client, TPS_VREGS1)); | ||
601 | pr_debug("%s: defgpio 0x%02x, mask3 0x%02x\n", DRIVER_NAME, | ||
602 | i2c_smbus_read_byte_data(&tps->client, TPS_DEFGPIO), | ||
603 | i2c_smbus_read_byte_data(&tps->client, TPS_MASK3)); | ||
604 | |||
605 | tps65010_driver.attach_adapter = tps65010_noscan; | ||
606 | the_tps = tps; | ||
607 | |||
608 | #if defined(CONFIG_USB_GADGET) && !defined(CONFIG_USB_OTG) | ||
609 | /* USB hosts can't draw VBUS. OTG devices could, later | ||
610 | * when OTG infrastructure enables it. USB peripherals | ||
611 | * could be relying on VBUS while booting, though. | ||
612 | */ | ||
613 | tps->vbus = 100; | ||
614 | #endif | ||
615 | |||
616 | /* unmask the "interesting" irqs, then poll once to | ||
617 | * kickstart monitoring, initialize shadowed status | ||
618 | * registers, and maybe disable VBUS draw. | ||
619 | */ | ||
620 | tps->nmask1 = ~0; | ||
621 | (void) i2c_smbus_write_byte_data(&tps->client, TPS_MASK1, ~tps->nmask1); | ||
622 | |||
623 | tps->nmask2 = TPS_REG_ONOFF; | ||
624 | if (tps->model == TPS65013) | ||
625 | tps->nmask2 |= TPS_REG_NO_CHG; | ||
626 | (void) i2c_smbus_write_byte_data(&tps->client, TPS_MASK2, ~tps->nmask2); | ||
627 | |||
628 | (void) i2c_smbus_write_byte_data(&tps->client, TPS_MASK3, 0x0f | ||
629 | | i2c_smbus_read_byte_data(&tps->client, TPS_MASK3)); | ||
630 | |||
631 | tps65010_work(tps); | ||
632 | |||
633 | tps->file = debugfs_create_file(DRIVER_NAME, S_IRUGO, NULL, | ||
634 | tps, DEBUG_FOPS); | ||
635 | return 0; | ||
636 | } | ||
637 | |||
638 | static int __init tps65010_scan_bus(struct i2c_adapter *bus) | ||
639 | { | ||
640 | if (!i2c_check_functionality(bus, I2C_FUNC_SMBUS_BYTE_DATA)) | ||
641 | return -EINVAL; | ||
642 | return i2c_probe(bus, &addr_data, tps65010_probe); | ||
643 | } | ||
644 | |||
645 | static struct i2c_driver tps65010_driver = { | ||
646 | .owner = THIS_MODULE, | ||
647 | .name = "tps65010", | ||
648 | .id = 888, /* FIXME assign "official" value */ | ||
649 | .flags = I2C_DF_NOTIFY, | ||
650 | .attach_adapter = tps65010_scan_bus, | ||
651 | .detach_client = __exit_p(tps65010_detach_client), | ||
652 | }; | ||
653 | |||
654 | /*-------------------------------------------------------------------------*/ | ||
655 | |||
656 | /* Draw from VBUS: | ||
657 | * 0 mA -- DON'T DRAW (might supply power instead) | ||
658 | * 100 mA -- usb unit load (slowest charge rate) | ||
659 | * 500 mA -- usb high power (fast battery charge) | ||
660 | */ | ||
661 | int tps65010_set_vbus_draw(unsigned mA) | ||
662 | { | ||
663 | unsigned long flags; | ||
664 | |||
665 | if (!the_tps) | ||
666 | return -ENODEV; | ||
667 | |||
668 | /* assumes non-SMP */ | ||
669 | local_irq_save(flags); | ||
670 | if (mA >= 500) | ||
671 | mA = 500; | ||
672 | else if (mA >= 100) | ||
673 | mA = 100; | ||
674 | else | ||
675 | mA = 0; | ||
676 | the_tps->vbus = mA; | ||
677 | if ((the_tps->chgstatus & TPS_CHG_USB) | ||
678 | && test_and_set_bit( | ||
679 | FLAG_VBUS_CHANGED, &the_tps->flags)) { | ||
680 | /* gadget drivers call this in_irq() */ | ||
681 | (void) schedule_work(&the_tps->work); | ||
682 | } | ||
683 | local_irq_restore(flags); | ||
684 | |||
685 | return 0; | ||
686 | } | ||
687 | EXPORT_SYMBOL(tps65010_set_vbus_draw); | ||
688 | |||
689 | /*-------------------------------------------------------------------------*/ | ||
690 | /* tps65010_set_gpio_out_value parameter: | ||
691 | * gpio: GPIO1, GPIO2, GPIO3 or GPIO4 | ||
692 | * value: LOW or HIGH | ||
693 | */ | ||
694 | int tps65010_set_gpio_out_value(unsigned gpio, unsigned value) | ||
695 | { | ||
696 | int status; | ||
697 | unsigned defgpio; | ||
698 | |||
699 | if (!the_tps) | ||
700 | return -ENODEV; | ||
701 | if ((gpio < GPIO1) || (gpio > GPIO4)) | ||
702 | return -EINVAL; | ||
703 | |||
704 | down(&the_tps->lock); | ||
705 | |||
706 | defgpio = i2c_smbus_read_byte_data(&the_tps->client, TPS_DEFGPIO); | ||
707 | |||
708 | /* Configure GPIO for output */ | ||
709 | defgpio |= 1 << (gpio + 3); | ||
710 | |||
711 | /* Writing 1 forces a logic 0 on that GPIO and vice versa */ | ||
712 | switch (value) { | ||
713 | case LOW: | ||
714 | defgpio |= 1 << (gpio - 1); /* set GPIO low by writing 1 */ | ||
715 | break; | ||
716 | /* case HIGH: */ | ||
717 | default: | ||
718 | defgpio &= ~(1 << (gpio - 1)); /* set GPIO high by writing 0 */ | ||
719 | break; | ||
720 | } | ||
721 | |||
722 | status = i2c_smbus_write_byte_data(&the_tps->client, | ||
723 | TPS_DEFGPIO, defgpio); | ||
724 | |||
725 | pr_debug("%s: gpio%dout = %s, defgpio 0x%02x\n", DRIVER_NAME, | ||
726 | gpio, value ? "high" : "low", | ||
727 | i2c_smbus_read_byte_data(&the_tps->client, TPS_DEFGPIO)); | ||
728 | |||
729 | up(&the_tps->lock); | ||
730 | return status; | ||
731 | } | ||
732 | EXPORT_SYMBOL(tps65010_set_gpio_out_value); | ||
733 | |||
734 | /*-------------------------------------------------------------------------*/ | ||
735 | /* tps65010_set_led parameter: | ||
736 | * led: LED1 or LED2 | ||
737 | * mode: ON, OFF or BLINK | ||
738 | */ | ||
739 | int tps65010_set_led(unsigned led, unsigned mode) | ||
740 | { | ||
741 | int status; | ||
742 | unsigned led_on, led_per, offs; | ||
743 | |||
744 | if (!the_tps) | ||
745 | return -ENODEV; | ||
746 | |||
747 | if(led == LED1) | ||
748 | offs = 0; | ||
749 | else { | ||
750 | offs = 2; | ||
751 | led = LED2; | ||
752 | } | ||
753 | |||
754 | down(&the_tps->lock); | ||
755 | |||
756 | dev_dbg (&the_tps->client.dev, "led%i_on 0x%02x\n", led, | ||
757 | i2c_smbus_read_byte_data(&the_tps->client, TPS_LED1_ON + offs)); | ||
758 | |||
759 | dev_dbg (&the_tps->client.dev, "led%i_per 0x%02x\n", led, | ||
760 | i2c_smbus_read_byte_data(&the_tps->client, TPS_LED1_PER + offs)); | ||
761 | |||
762 | switch (mode) { | ||
763 | case OFF: | ||
764 | led_on = 1 << 7; | ||
765 | led_per = 0 << 7; | ||
766 | break; | ||
767 | case ON: | ||
768 | led_on = 1 << 7; | ||
769 | led_per = 1 << 7; | ||
770 | break; | ||
771 | case BLINK: | ||
772 | led_on = 0x30 | (0 << 7); | ||
773 | led_per = 0x08 | (1 << 7); | ||
774 | break; | ||
775 | default: | ||
776 | printk(KERN_ERR "%s: Wrong mode parameter for tps65010_set_led()\n", | ||
777 | DRIVER_NAME); | ||
778 | up(&the_tps->lock); | ||
779 | return -EINVAL; | ||
780 | } | ||
781 | |||
782 | status = i2c_smbus_write_byte_data(&the_tps->client, | ||
783 | TPS_LED1_ON + offs, led_on); | ||
784 | |||
785 | if (status != 0) { | ||
786 | printk(KERN_ERR "%s: Failed to write led%i_on register\n", | ||
787 | DRIVER_NAME, led); | ||
788 | up(&the_tps->lock); | ||
789 | return status; | ||
790 | } | ||
791 | |||
792 | dev_dbg (&the_tps->client.dev, "led%i_on 0x%02x\n", led, | ||
793 | i2c_smbus_read_byte_data(&the_tps->client, TPS_LED1_ON + offs)); | ||
794 | |||
795 | status = i2c_smbus_write_byte_data(&the_tps->client, | ||
796 | TPS_LED1_PER + offs, led_per); | ||
797 | |||
798 | if (status != 0) { | ||
799 | printk(KERN_ERR "%s: Failed to write led%i_per register\n", | ||
800 | DRIVER_NAME, led); | ||
801 | up(&the_tps->lock); | ||
802 | return status; | ||
803 | } | ||
804 | |||
805 | dev_dbg (&the_tps->client.dev, "led%i_per 0x%02x\n", led, | ||
806 | i2c_smbus_read_byte_data(&the_tps->client, TPS_LED1_PER + offs)); | ||
807 | |||
808 | up(&the_tps->lock); | ||
809 | |||
810 | return status; | ||
811 | } | ||
812 | EXPORT_SYMBOL(tps65010_set_led); | ||
813 | |||
814 | /*-------------------------------------------------------------------------*/ | ||
815 | /* tps65010_set_vib parameter: | ||
816 | * value: ON or OFF | ||
817 | */ | ||
818 | int tps65010_set_vib(unsigned value) | ||
819 | { | ||
820 | int status; | ||
821 | unsigned vdcdc2; | ||
822 | |||
823 | if (!the_tps) | ||
824 | return -ENODEV; | ||
825 | |||
826 | down(&the_tps->lock); | ||
827 | |||
828 | vdcdc2 = i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC2); | ||
829 | vdcdc2 &= ~(1 << 1); | ||
830 | if (value) | ||
831 | vdcdc2 |= (1 << 1); | ||
832 | status = i2c_smbus_write_byte_data(&the_tps->client, | ||
833 | TPS_VDCDC2, vdcdc2); | ||
834 | |||
835 | pr_debug("%s: vibrator %s\n", DRIVER_NAME, value ? "on" : "off"); | ||
836 | |||
837 | up(&the_tps->lock); | ||
838 | return status; | ||
839 | } | ||
840 | EXPORT_SYMBOL(tps65010_set_vib); | ||
841 | |||
842 | /*-------------------------------------------------------------------------*/ | ||
843 | /* tps65010_set_low_pwr parameter: | ||
844 | * mode: ON or OFF | ||
845 | */ | ||
846 | int tps65010_set_low_pwr(unsigned mode) | ||
847 | { | ||
848 | int status; | ||
849 | unsigned vdcdc1; | ||
850 | |||
851 | if (!the_tps) | ||
852 | return -ENODEV; | ||
853 | |||
854 | down(&the_tps->lock); | ||
855 | |||
856 | pr_debug("%s: %s low_pwr, vdcdc1 0x%02x\n", DRIVER_NAME, | ||
857 | mode ? "enable" : "disable", | ||
858 | i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1)); | ||
859 | |||
860 | vdcdc1 = i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1); | ||
861 | |||
862 | switch (mode) { | ||
863 | case OFF: | ||
864 | vdcdc1 &= ~TPS_ENABLE_LP; /* disable ENABLE_LP bit */ | ||
865 | break; | ||
866 | /* case ON: */ | ||
867 | default: | ||
868 | vdcdc1 |= TPS_ENABLE_LP; /* enable ENABLE_LP bit */ | ||
869 | break; | ||
870 | } | ||
871 | |||
872 | status = i2c_smbus_write_byte_data(&the_tps->client, | ||
873 | TPS_VDCDC1, vdcdc1); | ||
874 | |||
875 | if (status != 0) | ||
876 | printk(KERN_ERR "%s: Failed to write vdcdc1 register\n", | ||
877 | DRIVER_NAME); | ||
878 | else | ||
879 | pr_debug("%s: vdcdc1 0x%02x\n", DRIVER_NAME, | ||
880 | i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1)); | ||
881 | |||
882 | up(&the_tps->lock); | ||
883 | |||
884 | return status; | ||
885 | } | ||
886 | EXPORT_SYMBOL(tps65010_set_low_pwr); | ||
887 | |||
888 | /*-------------------------------------------------------------------------*/ | ||
889 | /* tps65010_config_vregs1 parameter: | ||
890 | * value to be written to VREGS1 register | ||
891 | * Note: The complete register is written, set all bits you need | ||
892 | */ | ||
893 | int tps65010_config_vregs1(unsigned value) | ||
894 | { | ||
895 | int status; | ||
896 | |||
897 | if (!the_tps) | ||
898 | return -ENODEV; | ||
899 | |||
900 | down(&the_tps->lock); | ||
901 | |||
902 | pr_debug("%s: vregs1 0x%02x\n", DRIVER_NAME, | ||
903 | i2c_smbus_read_byte_data(&the_tps->client, TPS_VREGS1)); | ||
904 | |||
905 | status = i2c_smbus_write_byte_data(&the_tps->client, | ||
906 | TPS_VREGS1, value); | ||
907 | |||
908 | if (status != 0) | ||
909 | printk(KERN_ERR "%s: Failed to write vregs1 register\n", | ||
910 | DRIVER_NAME); | ||
911 | else | ||
912 | pr_debug("%s: vregs1 0x%02x\n", DRIVER_NAME, | ||
913 | i2c_smbus_read_byte_data(&the_tps->client, TPS_VREGS1)); | ||
914 | |||
915 | up(&the_tps->lock); | ||
916 | |||
917 | return status; | ||
918 | } | ||
919 | EXPORT_SYMBOL(tps65010_config_vregs1); | ||
920 | |||
921 | /*-------------------------------------------------------------------------*/ | ||
922 | /* tps65013_set_low_pwr parameter: | ||
923 | * mode: ON or OFF | ||
924 | */ | ||
925 | |||
926 | /* FIXME: Assumes AC or USB power is present. Setting AUA bit is not | ||
927 | required if power supply is through a battery */ | ||
928 | |||
929 | int tps65013_set_low_pwr(unsigned mode) | ||
930 | { | ||
931 | int status; | ||
932 | unsigned vdcdc1, chgconfig; | ||
933 | |||
934 | if (!the_tps || the_tps->por) | ||
935 | return -ENODEV; | ||
936 | |||
937 | down(&the_tps->lock); | ||
938 | |||
939 | pr_debug("%s: %s low_pwr, chgconfig 0x%02x vdcdc1 0x%02x\n", | ||
940 | DRIVER_NAME, | ||
941 | mode ? "enable" : "disable", | ||
942 | i2c_smbus_read_byte_data(&the_tps->client, TPS_CHGCONFIG), | ||
943 | i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1)); | ||
944 | |||
945 | chgconfig = i2c_smbus_read_byte_data(&the_tps->client, TPS_CHGCONFIG); | ||
946 | vdcdc1 = i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1); | ||
947 | |||
948 | switch (mode) { | ||
949 | case OFF: | ||
950 | chgconfig &= ~TPS65013_AUA; /* disable AUA bit */ | ||
951 | vdcdc1 &= ~TPS_ENABLE_LP; /* disable ENABLE_LP bit */ | ||
952 | break; | ||
953 | /* case ON: */ | ||
954 | default: | ||
955 | chgconfig |= TPS65013_AUA; /* enable AUA bit */ | ||
956 | vdcdc1 |= TPS_ENABLE_LP; /* enable ENABLE_LP bit */ | ||
957 | break; | ||
958 | } | ||
959 | |||
960 | status = i2c_smbus_write_byte_data(&the_tps->client, | ||
961 | TPS_CHGCONFIG, chgconfig); | ||
962 | if (status != 0) { | ||
963 | printk(KERN_ERR "%s: Failed to write chconfig register\n", | ||
964 | DRIVER_NAME); | ||
965 | up(&the_tps->lock); | ||
966 | return status; | ||
967 | } | ||
968 | |||
969 | chgconfig = i2c_smbus_read_byte_data(&the_tps->client, TPS_CHGCONFIG); | ||
970 | the_tps->chgconf = chgconfig; | ||
971 | show_chgconfig(0, "chgconf", chgconfig); | ||
972 | |||
973 | status = i2c_smbus_write_byte_data(&the_tps->client, | ||
974 | TPS_VDCDC1, vdcdc1); | ||
975 | |||
976 | if (status != 0) | ||
977 | printk(KERN_ERR "%s: Failed to write vdcdc1 register\n", | ||
978 | DRIVER_NAME); | ||
979 | else | ||
980 | pr_debug("%s: vdcdc1 0x%02x\n", DRIVER_NAME, | ||
981 | i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1)); | ||
982 | |||
983 | up(&the_tps->lock); | ||
984 | |||
985 | return status; | ||
986 | } | ||
987 | EXPORT_SYMBOL(tps65013_set_low_pwr); | ||
988 | |||
989 | /*-------------------------------------------------------------------------*/ | ||
990 | |||
991 | static int __init tps_init(void) | ||
992 | { | ||
993 | u32 tries = 3; | ||
994 | int status = -ENODEV; | ||
995 | |||
996 | printk(KERN_INFO "%s: version %s\n", DRIVER_NAME, DRIVER_VERSION); | ||
997 | |||
998 | /* some boards have startup glitches */ | ||
999 | while (tries--) { | ||
1000 | status = i2c_add_driver(&tps65010_driver); | ||
1001 | if (the_tps) | ||
1002 | break; | ||
1003 | i2c_del_driver(&tps65010_driver); | ||
1004 | if (!tries) { | ||
1005 | printk(KERN_ERR "%s: no chip?\n", DRIVER_NAME); | ||
1006 | return -ENODEV; | ||
1007 | } | ||
1008 | pr_debug("%s: re-probe ...\n", DRIVER_NAME); | ||
1009 | msleep(10); | ||
1010 | } | ||
1011 | |||
1012 | #if defined(CONFIG_ARM) | ||
1013 | if (machine_is_omap_osk()) { | ||
1014 | |||
1015 | // FIXME: More should be placed in the initialization code | ||
1016 | // of the submodules (DSP, ethernet, power management, | ||
1017 | // board-osk.c). Careful: I2C is initialized "late". | ||
1018 | |||
1019 | /* Let LED1 (D9) blink */ | ||
1020 | tps65010_set_led(LED1, BLINK); | ||
1021 | |||
1022 | /* Disable LED 2 (D2) */ | ||
1023 | tps65010_set_led(LED2, OFF); | ||
1024 | |||
1025 | /* Set GPIO 1 HIGH to disable VBUS power supply; | ||
1026 | * OHCI driver powers it up/down as needed. | ||
1027 | */ | ||
1028 | tps65010_set_gpio_out_value(GPIO1, HIGH); | ||
1029 | |||
1030 | /* Set GPIO 2 low to turn on LED D3 */ | ||
1031 | tps65010_set_gpio_out_value(GPIO2, HIGH); | ||
1032 | |||
1033 | /* Set GPIO 3 low to take ethernet out of reset */ | ||
1034 | tps65010_set_gpio_out_value(GPIO3, LOW); | ||
1035 | |||
1036 | /* gpio4 for VDD_DSP */ | ||
1037 | |||
1038 | /* Enable LOW_PWR */ | ||
1039 | tps65010_set_low_pwr(ON); | ||
1040 | |||
1041 | /* Switch VLDO2 to 3.0V for AIC23 */ | ||
1042 | tps65010_config_vregs1(TPS_LDO2_ENABLE | TPS_VLDO2_3_0V | TPS_LDO1_ENABLE); | ||
1043 | |||
1044 | } else if (machine_is_omap_h2()) { | ||
1045 | /* gpio3 for SD, gpio4 for VDD_DSP */ | ||
1046 | |||
1047 | /* Enable LOW_PWR */ | ||
1048 | tps65010_set_low_pwr(ON); | ||
1049 | } else if (machine_is_omap_h3()) { | ||
1050 | /* gpio4 for SD, gpio3 for VDD_DSP */ | ||
1051 | #ifdef CONFIG_PM | ||
1052 | /* Enable LOW_PWR */ | ||
1053 | tps65013_set_low_pwr(ON); | ||
1054 | #endif | ||
1055 | } | ||
1056 | #endif | ||
1057 | |||
1058 | return status; | ||
1059 | } | ||
1060 | /* NOTE: this MUST be initialized before the other parts of the system | ||
1061 | * that rely on it ... but after the i2c bus on which this relies. | ||
1062 | * That is, much earlier than on PC-type systems, which don't often use | ||
1063 | * I2C as a core system bus. | ||
1064 | */ | ||
1065 | subsys_initcall(tps_init); | ||
1066 | |||
1067 | static void __exit tps_exit(void) | ||
1068 | { | ||
1069 | i2c_del_driver(&tps65010_driver); | ||
1070 | } | ||
1071 | module_exit(tps_exit); | ||
1072 | |||
diff --git a/drivers/i2c/chips/via686a.c b/drivers/i2c/chips/via686a.c index fefc24a9251a..137d9b7cacd4 100644 --- a/drivers/i2c/chips/via686a.c +++ b/drivers/i2c/chips/via686a.c | |||
@@ -1,12 +1,12 @@ | |||
1 | /* | 1 | /* |
2 | via686a.c - Part of lm_sensors, Linux kernel modules | 2 | via686a.c - Part of lm_sensors, Linux kernel modules |
3 | for hardware monitoring | 3 | for hardware monitoring |
4 | 4 | ||
5 | Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>, | 5 | Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>, |
6 | Kyösti Mälkki <kmalkki@cc.hut.fi>, | 6 | Kyösti Mälkki <kmalkki@cc.hut.fi>, |
7 | Mark Studebaker <mdsxyz123@yahoo.com>, | 7 | Mark Studebaker <mdsxyz123@yahoo.com>, |
8 | and Bob Dougherty <bobd@stanford.edu> | 8 | and Bob Dougherty <bobd@stanford.edu> |
9 | (Some conversion-factor data were contributed by Jonathan Teh Soon Yew | 9 | (Some conversion-factor data were contributed by Jonathan Teh Soon Yew |
10 | <j.teh@iname.com> and Alex van Kaam <darkside@chello.nl>.) | 10 | <j.teh@iname.com> and Alex van Kaam <darkside@chello.nl>.) |
11 | 11 | ||
12 | This program is free software; you can redistribute it and/or modify | 12 | This program is free software; you can redistribute it and/or modify |
@@ -30,11 +30,9 @@ | |||
30 | Warning - only supports a single device. | 30 | Warning - only supports a single device. |
31 | */ | 31 | */ |
32 | 32 | ||
33 | #include <linux/config.h> | ||
34 | #include <linux/module.h> | 33 | #include <linux/module.h> |
35 | #include <linux/slab.h> | 34 | #include <linux/slab.h> |
36 | #include <linux/pci.h> | 35 | #include <linux/pci.h> |
37 | #include <linux/delay.h> | ||
38 | #include <linux/jiffies.h> | 36 | #include <linux/jiffies.h> |
39 | #include <linux/i2c.h> | 37 | #include <linux/i2c.h> |
40 | #include <linux/i2c-sensor.h> | 38 | #include <linux/i2c-sensor.h> |
@@ -66,49 +64,46 @@ SENSORS_INSMOD_1(via686a); | |||
66 | /* Many VIA686A constants specified below */ | 64 | /* Many VIA686A constants specified below */ |
67 | 65 | ||
68 | /* Length of ISA address segment */ | 66 | /* Length of ISA address segment */ |
69 | #define VIA686A_EXTENT 0x80 | 67 | #define VIA686A_EXTENT 0x80 |
70 | #define VIA686A_BASE_REG 0x70 | 68 | #define VIA686A_BASE_REG 0x70 |
71 | #define VIA686A_ENABLE_REG 0x74 | 69 | #define VIA686A_ENABLE_REG 0x74 |
72 | 70 | ||
73 | /* The VIA686A registers */ | 71 | /* The VIA686A registers */ |
74 | /* ins numbered 0-4 */ | 72 | /* ins numbered 0-4 */ |
75 | #define VIA686A_REG_IN_MAX(nr) (0x2b + ((nr) * 2)) | 73 | #define VIA686A_REG_IN_MAX(nr) (0x2b + ((nr) * 2)) |
76 | #define VIA686A_REG_IN_MIN(nr) (0x2c + ((nr) * 2)) | 74 | #define VIA686A_REG_IN_MIN(nr) (0x2c + ((nr) * 2)) |
77 | #define VIA686A_REG_IN(nr) (0x22 + (nr)) | 75 | #define VIA686A_REG_IN(nr) (0x22 + (nr)) |
78 | 76 | ||
79 | /* fans numbered 1-2 */ | 77 | /* fans numbered 1-2 */ |
80 | #define VIA686A_REG_FAN_MIN(nr) (0x3a + (nr)) | 78 | #define VIA686A_REG_FAN_MIN(nr) (0x3a + (nr)) |
81 | #define VIA686A_REG_FAN(nr) (0x28 + (nr)) | 79 | #define VIA686A_REG_FAN(nr) (0x28 + (nr)) |
82 | |||
83 | /* the following values are as speced by VIA: */ | ||
84 | static const u8 regtemp[] = { 0x20, 0x21, 0x1f }; | ||
85 | static const u8 regover[] = { 0x39, 0x3d, 0x1d }; | ||
86 | static const u8 reghyst[] = { 0x3a, 0x3e, 0x1e }; | ||
87 | 80 | ||
88 | /* temps numbered 1-3 */ | 81 | /* temps numbered 1-3 */ |
89 | #define VIA686A_REG_TEMP(nr) (regtemp[nr]) | 82 | static const u8 VIA686A_REG_TEMP[] = { 0x20, 0x21, 0x1f }; |
90 | #define VIA686A_REG_TEMP_OVER(nr) (regover[nr]) | 83 | static const u8 VIA686A_REG_TEMP_OVER[] = { 0x39, 0x3d, 0x1d }; |
91 | #define VIA686A_REG_TEMP_HYST(nr) (reghyst[nr]) | 84 | static const u8 VIA686A_REG_TEMP_HYST[] = { 0x3a, 0x3e, 0x1e }; |
92 | #define VIA686A_REG_TEMP_LOW1 0x4b // bits 7-6 | 85 | /* bits 7-6 */ |
93 | #define VIA686A_REG_TEMP_LOW23 0x49 // 2 = bits 5-4, 3 = bits 7-6 | 86 | #define VIA686A_REG_TEMP_LOW1 0x4b |
94 | 87 | /* 2 = bits 5-4, 3 = bits 7-6 */ | |
95 | #define VIA686A_REG_ALARM1 0x41 | 88 | #define VIA686A_REG_TEMP_LOW23 0x49 |
96 | #define VIA686A_REG_ALARM2 0x42 | 89 | |
97 | #define VIA686A_REG_FANDIV 0x47 | 90 | #define VIA686A_REG_ALARM1 0x41 |
98 | #define VIA686A_REG_CONFIG 0x40 | 91 | #define VIA686A_REG_ALARM2 0x42 |
99 | /* The following register sets temp interrupt mode (bits 1-0 for temp1, | 92 | #define VIA686A_REG_FANDIV 0x47 |
93 | #define VIA686A_REG_CONFIG 0x40 | ||
94 | /* The following register sets temp interrupt mode (bits 1-0 for temp1, | ||
100 | 3-2 for temp2, 5-4 for temp3). Modes are: | 95 | 3-2 for temp2, 5-4 for temp3). Modes are: |
101 | 00 interrupt stays as long as value is out-of-range | 96 | 00 interrupt stays as long as value is out-of-range |
102 | 01 interrupt is cleared once register is read (default) | 97 | 01 interrupt is cleared once register is read (default) |
103 | 10 comparator mode- like 00, but ignores hysteresis | 98 | 10 comparator mode- like 00, but ignores hysteresis |
104 | 11 same as 00 */ | 99 | 11 same as 00 */ |
105 | #define VIA686A_REG_TEMP_MODE 0x4b | 100 | #define VIA686A_REG_TEMP_MODE 0x4b |
106 | /* We'll just assume that you want to set all 3 simultaneously: */ | 101 | /* We'll just assume that you want to set all 3 simultaneously: */ |
107 | #define VIA686A_TEMP_MODE_MASK 0x3F | 102 | #define VIA686A_TEMP_MODE_MASK 0x3F |
108 | #define VIA686A_TEMP_MODE_CONTINUOUS (0x00) | 103 | #define VIA686A_TEMP_MODE_CONTINUOUS 0x00 |
109 | 104 | ||
110 | /* Conversions. Limit checking is only done on the TO_REG | 105 | /* Conversions. Limit checking is only done on the TO_REG |
111 | variants. | 106 | variants. |
112 | 107 | ||
113 | ********* VOLTAGE CONVERSIONS (Bob Dougherty) ******** | 108 | ********* VOLTAGE CONVERSIONS (Bob Dougherty) ******** |
114 | From HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew): | 109 | From HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew): |
@@ -121,7 +116,7 @@ static const u8 reghyst[] = { 0x3a, 0x3e, 0x1e }; | |||
121 | That is: | 116 | That is: |
122 | volts = (25*regVal+133)*factor | 117 | volts = (25*regVal+133)*factor |
123 | regVal = (volts/factor-133)/25 | 118 | regVal = (volts/factor-133)/25 |
124 | (These conversions were contributed by Jonathan Teh Soon Yew | 119 | (These conversions were contributed by Jonathan Teh Soon Yew |
125 | <j.teh@iname.com>) */ | 120 | <j.teh@iname.com>) */ |
126 | static inline u8 IN_TO_REG(long val, int inNum) | 121 | static inline u8 IN_TO_REG(long val, int inNum) |
127 | { | 122 | { |
@@ -182,55 +177,55 @@ static inline u8 FAN_TO_REG(long rpm, int div) | |||
182 | else | 177 | else |
183 | return double(temp)*0.924-127.33; | 178 | return double(temp)*0.924-127.33; |
184 | 179 | ||
185 | A fifth-order polynomial fits the unofficial data (provided by Alex van | 180 | A fifth-order polynomial fits the unofficial data (provided by Alex van |
186 | Kaam <darkside@chello.nl>) a bit better. It also give more reasonable | 181 | Kaam <darkside@chello.nl>) a bit better. It also give more reasonable |
187 | numbers on my machine (ie. they agree with what my BIOS tells me). | 182 | numbers on my machine (ie. they agree with what my BIOS tells me). |
188 | Here's the fifth-order fit to the 8-bit data: | 183 | Here's the fifth-order fit to the 8-bit data: |
189 | temp = 1.625093e-10*val^5 - 1.001632e-07*val^4 + 2.457653e-05*val^3 - | 184 | temp = 1.625093e-10*val^5 - 1.001632e-07*val^4 + 2.457653e-05*val^3 - |
190 | 2.967619e-03*val^2 + 2.175144e-01*val - 7.090067e+0. | 185 | 2.967619e-03*val^2 + 2.175144e-01*val - 7.090067e+0. |
191 | 186 | ||
192 | (2000-10-25- RFD: thanks to Uwe Andersen <uandersen@mayah.com> for | 187 | (2000-10-25- RFD: thanks to Uwe Andersen <uandersen@mayah.com> for |
193 | finding my typos in this formula!) | 188 | finding my typos in this formula!) |
194 | 189 | ||
195 | Alas, none of the elegant function-fit solutions will work because we | 190 | Alas, none of the elegant function-fit solutions will work because we |
196 | aren't allowed to use floating point in the kernel and doing it with | 191 | aren't allowed to use floating point in the kernel and doing it with |
197 | integers doesn't rpovide enough precision. So we'll do boring old | 192 | integers doesn't provide enough precision. So we'll do boring old |
198 | look-up table stuff. The unofficial data (see below) have effectively | 193 | look-up table stuff. The unofficial data (see below) have effectively |
199 | 7-bit resolution (they are rounded to the nearest degree). I'm assuming | 194 | 7-bit resolution (they are rounded to the nearest degree). I'm assuming |
200 | that the transfer function of the device is monotonic and smooth, so a | 195 | that the transfer function of the device is monotonic and smooth, so a |
201 | smooth function fit to the data will allow us to get better precision. | 196 | smooth function fit to the data will allow us to get better precision. |
202 | I used the 5th-order poly fit described above and solved for | 197 | I used the 5th-order poly fit described above and solved for |
203 | VIA register values 0-255. I *10 before rounding, so we get tenth-degree | 198 | VIA register values 0-255. I *10 before rounding, so we get tenth-degree |
204 | precision. (I could have done all 1024 values for our 10-bit readings, | 199 | precision. (I could have done all 1024 values for our 10-bit readings, |
205 | but the function is very linear in the useful range (0-80 deg C), so | 200 | but the function is very linear in the useful range (0-80 deg C), so |
206 | we'll just use linear interpolation for 10-bit readings.) So, tempLUT | 201 | we'll just use linear interpolation for 10-bit readings.) So, tempLUT |
207 | is the temp at via register values 0-255: */ | 202 | is the temp at via register values 0-255: */ |
208 | static const long tempLUT[] = | 203 | static const long tempLUT[] = |
209 | { -709, -688, -667, -646, -627, -607, -589, -570, -553, -536, -519, | 204 | { -709, -688, -667, -646, -627, -607, -589, -570, -553, -536, -519, |
210 | -503, -487, -471, -456, -442, -428, -414, -400, -387, -375, | 205 | -503, -487, -471, -456, -442, -428, -414, -400, -387, -375, |
211 | -362, -350, -339, -327, -316, -305, -295, -285, -275, -265, | 206 | -362, -350, -339, -327, -316, -305, -295, -285, -275, -265, |
212 | -255, -246, -237, -229, -220, -212, -204, -196, -188, -180, | 207 | -255, -246, -237, -229, -220, -212, -204, -196, -188, -180, |
213 | -173, -166, -159, -152, -145, -139, -132, -126, -120, -114, | 208 | -173, -166, -159, -152, -145, -139, -132, -126, -120, -114, |
214 | -108, -102, -96, -91, -85, -80, -74, -69, -64, -59, -54, -49, | 209 | -108, -102, -96, -91, -85, -80, -74, -69, -64, -59, -54, -49, |
215 | -44, -39, -34, -29, -25, -20, -15, -11, -6, -2, 3, 7, 12, 16, | 210 | -44, -39, -34, -29, -25, -20, -15, -11, -6, -2, 3, 7, 12, 16, |
216 | 20, 25, 29, 33, 37, 42, 46, 50, 54, 59, 63, 67, 71, 75, 79, 84, | 211 | 20, 25, 29, 33, 37, 42, 46, 50, 54, 59, 63, 67, 71, 75, 79, 84, |
217 | 88, 92, 96, 100, 104, 109, 113, 117, 121, 125, 130, 134, 138, | 212 | 88, 92, 96, 100, 104, 109, 113, 117, 121, 125, 130, 134, 138, |
218 | 142, 146, 151, 155, 159, 163, 168, 172, 176, 181, 185, 189, | 213 | 142, 146, 151, 155, 159, 163, 168, 172, 176, 181, 185, 189, |
219 | 193, 198, 202, 206, 211, 215, 219, 224, 228, 232, 237, 241, | 214 | 193, 198, 202, 206, 211, 215, 219, 224, 228, 232, 237, 241, |
220 | 245, 250, 254, 259, 263, 267, 272, 276, 281, 285, 290, 294, | 215 | 245, 250, 254, 259, 263, 267, 272, 276, 281, 285, 290, 294, |
221 | 299, 303, 307, 312, 316, 321, 325, 330, 334, 339, 344, 348, | 216 | 299, 303, 307, 312, 316, 321, 325, 330, 334, 339, 344, 348, |
222 | 353, 357, 362, 366, 371, 376, 380, 385, 390, 395, 399, 404, | 217 | 353, 357, 362, 366, 371, 376, 380, 385, 390, 395, 399, 404, |
223 | 409, 414, 419, 423, 428, 433, 438, 443, 449, 454, 459, 464, | 218 | 409, 414, 419, 423, 428, 433, 438, 443, 449, 454, 459, 464, |
224 | 469, 475, 480, 486, 491, 497, 502, 508, 514, 520, 526, 532, | 219 | 469, 475, 480, 486, 491, 497, 502, 508, 514, 520, 526, 532, |
225 | 538, 544, 551, 557, 564, 571, 578, 584, 592, 599, 606, 614, | 220 | 538, 544, 551, 557, 564, 571, 578, 584, 592, 599, 606, 614, |
226 | 621, 629, 637, 645, 654, 662, 671, 680, 689, 698, 708, 718, | 221 | 621, 629, 637, 645, 654, 662, 671, 680, 689, 698, 708, 718, |
227 | 728, 738, 749, 759, 770, 782, 793, 805, 818, 830, 843, 856, | 222 | 728, 738, 749, 759, 770, 782, 793, 805, 818, 830, 843, 856, |
228 | 870, 883, 898, 912, 927, 943, 958, 975, 991, 1008, 1026, 1044, | 223 | 870, 883, 898, 912, 927, 943, 958, 975, 991, 1008, 1026, 1044, |
229 | 1062, 1081, 1101, 1121, 1141, 1162, 1184, 1206, 1229, 1252, | 224 | 1062, 1081, 1101, 1121, 1141, 1162, 1184, 1206, 1229, 1252, |
230 | 1276, 1301, 1326, 1352, 1378, 1406, 1434, 1462 | 225 | 1276, 1301, 1326, 1352, 1378, 1406, 1434, 1462 |
231 | }; | 226 | }; |
232 | 227 | ||
233 | /* the original LUT values from Alex van Kaam <darkside@chello.nl> | 228 | /* the original LUT values from Alex van Kaam <darkside@chello.nl> |
234 | (for via register values 12-240): | 229 | (for via register values 12-240): |
235 | {-50,-49,-47,-45,-43,-41,-39,-38,-37,-35,-34,-33,-32,-31, | 230 | {-50,-49,-47,-45,-43,-41,-39,-38,-37,-35,-34,-33,-32,-31, |
236 | -30,-29,-28,-27,-26,-25,-24,-24,-23,-22,-21,-20,-20,-19,-18,-17,-17,-16,-15, | 231 | -30,-29,-28,-27,-26,-25,-24,-24,-23,-22,-21,-20,-20,-19,-18,-17,-17,-16,-15, |
@@ -245,26 +240,26 @@ static const long tempLUT[] = | |||
245 | 240 | ||
246 | 241 | ||
247 | Here's the reverse LUT. I got it by doing a 6-th order poly fit (needed | 242 | Here's the reverse LUT. I got it by doing a 6-th order poly fit (needed |
248 | an extra term for a good fit to these inverse data!) and then | 243 | an extra term for a good fit to these inverse data!) and then |
249 | solving for each temp value from -50 to 110 (the useable range for | 244 | solving for each temp value from -50 to 110 (the useable range for |
250 | this chip). Here's the fit: | 245 | this chip). Here's the fit: |
251 | viaRegVal = -1.160370e-10*val^6 +3.193693e-08*val^5 - 1.464447e-06*val^4 | 246 | viaRegVal = -1.160370e-10*val^6 +3.193693e-08*val^5 - 1.464447e-06*val^4 |
252 | - 2.525453e-04*val^3 + 1.424593e-02*val^2 + 2.148941e+00*val +7.275808e+01) | 247 | - 2.525453e-04*val^3 + 1.424593e-02*val^2 + 2.148941e+00*val +7.275808e+01) |
253 | Note that n=161: */ | 248 | Note that n=161: */ |
254 | static const u8 viaLUT[] = | 249 | static const u8 viaLUT[] = |
255 | { 12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 18, 19, 20, 20, 21, 22, 23, | 250 | { 12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 18, 19, 20, 20, 21, 22, 23, |
256 | 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 39, 40, | 251 | 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 39, 40, |
257 | 41, 43, 45, 46, 48, 49, 51, 53, 55, 57, 59, 60, 62, 64, 66, | 252 | 41, 43, 45, 46, 48, 49, 51, 53, 55, 57, 59, 60, 62, 64, 66, |
258 | 69, 71, 73, 75, 77, 79, 82, 84, 86, 88, 91, 93, 95, 98, 100, | 253 | 69, 71, 73, 75, 77, 79, 82, 84, 86, 88, 91, 93, 95, 98, 100, |
259 | 103, 105, 107, 110, 112, 115, 117, 119, 122, 124, 126, 129, | 254 | 103, 105, 107, 110, 112, 115, 117, 119, 122, 124, 126, 129, |
260 | 131, 134, 136, 138, 140, 143, 145, 147, 150, 152, 154, 156, | 255 | 131, 134, 136, 138, 140, 143, 145, 147, 150, 152, 154, 156, |
261 | 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, | 256 | 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, |
262 | 182, 183, 185, 187, 188, 190, 192, 193, 195, 196, 198, 199, | 257 | 182, 183, 185, 187, 188, 190, 192, 193, 195, 196, 198, 199, |
263 | 200, 202, 203, 205, 206, 207, 208, 209, 210, 211, 212, 213, | 258 | 200, 202, 203, 205, 206, 207, 208, 209, 210, 211, 212, 213, |
264 | 214, 215, 216, 217, 218, 219, 220, 221, 222, 222, 223, 224, | 259 | 214, 215, 216, 217, 218, 219, 220, 221, 222, 222, 223, 224, |
265 | 225, 226, 226, 227, 228, 228, 229, 230, 230, 231, 232, 232, | 260 | 225, 226, 226, 227, 228, 228, 229, 230, 230, 231, 232, 232, |
266 | 233, 233, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, | 261 | 233, 233, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, |
267 | 239, 240 | 262 | 239, 240 |
268 | }; | 263 | }; |
269 | 264 | ||
270 | /* Converting temps to (8-bit) hyst and over registers | 265 | /* Converting temps to (8-bit) hyst and over registers |
@@ -272,7 +267,7 @@ static const u8 viaLUT[] = | |||
272 | The +50 is because the temps start at -50 */ | 267 | The +50 is because the temps start at -50 */ |
273 | static inline u8 TEMP_TO_REG(long val) | 268 | static inline u8 TEMP_TO_REG(long val) |
274 | { | 269 | { |
275 | return viaLUT[val <= -50000 ? 0 : val >= 110000 ? 160 : | 270 | return viaLUT[val <= -50000 ? 0 : val >= 110000 ? 160 : |
276 | (val < 0 ? val - 500 : val + 500) / 1000 + 50]; | 271 | (val < 0 ? val - 500 : val + 500) / 1000 + 50]; |
277 | } | 272 | } |
278 | 273 | ||
@@ -291,11 +286,9 @@ static inline long TEMP_FROM_REG10(u16 val) | |||
291 | 286 | ||
292 | /* do some linear interpolation */ | 287 | /* do some linear interpolation */ |
293 | return (tempLUT[eightBits] * (4 - twoBits) + | 288 | return (tempLUT[eightBits] * (4 - twoBits) + |
294 | tempLUT[eightBits + 1] * twoBits) * 25; | 289 | tempLUT[eightBits + 1] * twoBits) * 25; |
295 | } | 290 | } |
296 | 291 | ||
297 | #define ALARMS_FROM_REG(val) (val) | ||
298 | |||
299 | #define DIV_FROM_REG(val) (1 << (val)) | 292 | #define DIV_FROM_REG(val) (1 << (val)) |
300 | #define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1) | 293 | #define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1) |
301 | 294 | ||
@@ -358,28 +351,28 @@ static ssize_t show_in_max(struct device *dev, char *buf, int nr) { | |||
358 | return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_max[nr], nr)); | 351 | return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_max[nr], nr)); |
359 | } | 352 | } |
360 | 353 | ||
361 | static ssize_t set_in_min(struct device *dev, const char *buf, | 354 | static ssize_t set_in_min(struct device *dev, const char *buf, |
362 | size_t count, int nr) { | 355 | size_t count, int nr) { |
363 | struct i2c_client *client = to_i2c_client(dev); | 356 | struct i2c_client *client = to_i2c_client(dev); |
364 | struct via686a_data *data = i2c_get_clientdata(client); | 357 | struct via686a_data *data = i2c_get_clientdata(client); |
365 | unsigned long val = simple_strtoul(buf, NULL, 10); | 358 | unsigned long val = simple_strtoul(buf, NULL, 10); |
366 | 359 | ||
367 | down(&data->update_lock); | 360 | down(&data->update_lock); |
368 | data->in_min[nr] = IN_TO_REG(val,nr); | 361 | data->in_min[nr] = IN_TO_REG(val, nr); |
369 | via686a_write_value(client, VIA686A_REG_IN_MIN(nr), | 362 | via686a_write_value(client, VIA686A_REG_IN_MIN(nr), |
370 | data->in_min[nr]); | 363 | data->in_min[nr]); |
371 | up(&data->update_lock); | 364 | up(&data->update_lock); |
372 | return count; | 365 | return count; |
373 | } | 366 | } |
374 | static ssize_t set_in_max(struct device *dev, const char *buf, | 367 | static ssize_t set_in_max(struct device *dev, const char *buf, |
375 | size_t count, int nr) { | 368 | size_t count, int nr) { |
376 | struct i2c_client *client = to_i2c_client(dev); | 369 | struct i2c_client *client = to_i2c_client(dev); |
377 | struct via686a_data *data = i2c_get_clientdata(client); | 370 | struct via686a_data *data = i2c_get_clientdata(client); |
378 | unsigned long val = simple_strtoul(buf, NULL, 10); | 371 | unsigned long val = simple_strtoul(buf, NULL, 10); |
379 | 372 | ||
380 | down(&data->update_lock); | 373 | down(&data->update_lock); |
381 | data->in_max[nr] = IN_TO_REG(val,nr); | 374 | data->in_max[nr] = IN_TO_REG(val, nr); |
382 | via686a_write_value(client, VIA686A_REG_IN_MAX(nr), | 375 | via686a_write_value(client, VIA686A_REG_IN_MAX(nr), |
383 | data->in_max[nr]); | 376 | data->in_max[nr]); |
384 | up(&data->update_lock); | 377 | up(&data->update_lock); |
385 | return count; | 378 | return count; |
@@ -435,7 +428,7 @@ static ssize_t show_temp_hyst(struct device *dev, char *buf, int nr) { | |||
435 | struct via686a_data *data = via686a_update_device(dev); | 428 | struct via686a_data *data = via686a_update_device(dev); |
436 | return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_hyst[nr])); | 429 | return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_hyst[nr])); |
437 | } | 430 | } |
438 | static ssize_t set_temp_over(struct device *dev, const char *buf, | 431 | static ssize_t set_temp_over(struct device *dev, const char *buf, |
439 | size_t count, int nr) { | 432 | size_t count, int nr) { |
440 | struct i2c_client *client = to_i2c_client(dev); | 433 | struct i2c_client *client = to_i2c_client(dev); |
441 | struct via686a_data *data = i2c_get_clientdata(client); | 434 | struct via686a_data *data = i2c_get_clientdata(client); |
@@ -443,11 +436,12 @@ static ssize_t set_temp_over(struct device *dev, const char *buf, | |||
443 | 436 | ||
444 | down(&data->update_lock); | 437 | down(&data->update_lock); |
445 | data->temp_over[nr] = TEMP_TO_REG(val); | 438 | data->temp_over[nr] = TEMP_TO_REG(val); |
446 | via686a_write_value(client, VIA686A_REG_TEMP_OVER(nr), data->temp_over[nr]); | 439 | via686a_write_value(client, VIA686A_REG_TEMP_OVER[nr], |
440 | data->temp_over[nr]); | ||
447 | up(&data->update_lock); | 441 | up(&data->update_lock); |
448 | return count; | 442 | return count; |
449 | } | 443 | } |
450 | static ssize_t set_temp_hyst(struct device *dev, const char *buf, | 444 | static ssize_t set_temp_hyst(struct device *dev, const char *buf, |
451 | size_t count, int nr) { | 445 | size_t count, int nr) { |
452 | struct i2c_client *client = to_i2c_client(dev); | 446 | struct i2c_client *client = to_i2c_client(dev); |
453 | struct via686a_data *data = i2c_get_clientdata(client); | 447 | struct via686a_data *data = i2c_get_clientdata(client); |
@@ -455,7 +449,8 @@ static ssize_t set_temp_hyst(struct device *dev, const char *buf, | |||
455 | 449 | ||
456 | down(&data->update_lock); | 450 | down(&data->update_lock); |
457 | data->temp_hyst[nr] = TEMP_TO_REG(val); | 451 | data->temp_hyst[nr] = TEMP_TO_REG(val); |
458 | via686a_write_value(client, VIA686A_REG_TEMP_HYST(nr), data->temp_hyst[nr]); | 452 | via686a_write_value(client, VIA686A_REG_TEMP_HYST[nr], |
453 | data->temp_hyst[nr]); | ||
459 | up(&data->update_lock); | 454 | up(&data->update_lock); |
460 | return count; | 455 | return count; |
461 | } | 456 | } |
@@ -488,7 +483,7 @@ static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, NULL);\ | |||
488 | static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ | 483 | static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ |
489 | show_temp_##offset##_over, set_temp_##offset##_over); \ | 484 | show_temp_##offset##_over, set_temp_##offset##_over); \ |
490 | static DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR, \ | 485 | static DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR, \ |
491 | show_temp_##offset##_hyst, set_temp_##offset##_hyst); | 486 | show_temp_##offset##_hyst, set_temp_##offset##_hyst); |
492 | 487 | ||
493 | show_temp_offset(1); | 488 | show_temp_offset(1); |
494 | show_temp_offset(2); | 489 | show_temp_offset(2); |
@@ -497,19 +492,19 @@ show_temp_offset(3); | |||
497 | /* 2 Fans */ | 492 | /* 2 Fans */ |
498 | static ssize_t show_fan(struct device *dev, char *buf, int nr) { | 493 | static ssize_t show_fan(struct device *dev, char *buf, int nr) { |
499 | struct via686a_data *data = via686a_update_device(dev); | 494 | struct via686a_data *data = via686a_update_device(dev); |
500 | return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan[nr], | 495 | return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], |
501 | DIV_FROM_REG(data->fan_div[nr])) ); | 496 | DIV_FROM_REG(data->fan_div[nr])) ); |
502 | } | 497 | } |
503 | static ssize_t show_fan_min(struct device *dev, char *buf, int nr) { | 498 | static ssize_t show_fan_min(struct device *dev, char *buf, int nr) { |
504 | struct via686a_data *data = via686a_update_device(dev); | 499 | struct via686a_data *data = via686a_update_device(dev); |
505 | return sprintf(buf,"%d\n", | 500 | return sprintf(buf, "%d\n", |
506 | FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])) ); | 501 | FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])) ); |
507 | } | 502 | } |
508 | static ssize_t show_fan_div(struct device *dev, char *buf, int nr) { | 503 | static ssize_t show_fan_div(struct device *dev, char *buf, int nr) { |
509 | struct via686a_data *data = via686a_update_device(dev); | 504 | struct via686a_data *data = via686a_update_device(dev); |
510 | return sprintf(buf,"%d\n", DIV_FROM_REG(data->fan_div[nr]) ); | 505 | return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]) ); |
511 | } | 506 | } |
512 | static ssize_t set_fan_min(struct device *dev, const char *buf, | 507 | static ssize_t set_fan_min(struct device *dev, const char *buf, |
513 | size_t count, int nr) { | 508 | size_t count, int nr) { |
514 | struct i2c_client *client = to_i2c_client(dev); | 509 | struct i2c_client *client = to_i2c_client(dev); |
515 | struct via686a_data *data = i2c_get_clientdata(client); | 510 | struct via686a_data *data = i2c_get_clientdata(client); |
@@ -521,7 +516,7 @@ static ssize_t set_fan_min(struct device *dev, const char *buf, | |||
521 | up(&data->update_lock); | 516 | up(&data->update_lock); |
522 | return count; | 517 | return count; |
523 | } | 518 | } |
524 | static ssize_t set_fan_div(struct device *dev, const char *buf, | 519 | static ssize_t set_fan_div(struct device *dev, const char *buf, |
525 | size_t count, int nr) { | 520 | size_t count, int nr) { |
526 | struct i2c_client *client = to_i2c_client(dev); | 521 | struct i2c_client *client = to_i2c_client(dev); |
527 | struct via686a_data *data = i2c_get_clientdata(client); | 522 | struct via686a_data *data = i2c_get_clientdata(client); |
@@ -572,7 +567,7 @@ show_fan_offset(2); | |||
572 | /* Alarms */ | 567 | /* Alarms */ |
573 | static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) { | 568 | static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) { |
574 | struct via686a_data *data = via686a_update_device(dev); | 569 | struct via686a_data *data = via686a_update_device(dev); |
575 | return sprintf(buf,"%d\n", ALARMS_FROM_REG(data->alarms)); | 570 | return sprintf(buf, "%u\n", data->alarms); |
576 | } | 571 | } |
577 | static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); | 572 | static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); |
578 | 573 | ||
@@ -612,11 +607,12 @@ static int via686a_detect(struct i2c_adapter *adapter, int address, int kind) | |||
612 | } | 607 | } |
613 | 608 | ||
614 | /* 8231 requires multiple of 256, we enforce that on 686 as well */ | 609 | /* 8231 requires multiple of 256, we enforce that on 686 as well */ |
615 | if(force_addr) | 610 | if (force_addr) |
616 | address = force_addr & 0xFF00; | 611 | address = force_addr & 0xFF00; |
617 | 612 | ||
618 | if(force_addr) { | 613 | if (force_addr) { |
619 | dev_warn(&adapter->dev,"forcing ISA address 0x%04X\n", address); | 614 | dev_warn(&adapter->dev, "forcing ISA address 0x%04X\n", |
615 | address); | ||
620 | if (PCIBIOS_SUCCESSFUL != | 616 | if (PCIBIOS_SUCCESSFUL != |
621 | pci_write_config_word(s_bridge, VIA686A_BASE_REG, address)) | 617 | pci_write_config_word(s_bridge, VIA686A_BASE_REG, address)) |
622 | return -ENODEV; | 618 | return -ENODEV; |
@@ -625,17 +621,17 @@ static int via686a_detect(struct i2c_adapter *adapter, int address, int kind) | |||
625 | pci_read_config_word(s_bridge, VIA686A_ENABLE_REG, &val)) | 621 | pci_read_config_word(s_bridge, VIA686A_ENABLE_REG, &val)) |
626 | return -ENODEV; | 622 | return -ENODEV; |
627 | if (!(val & 0x0001)) { | 623 | if (!(val & 0x0001)) { |
628 | dev_warn(&adapter->dev,"enabling sensors\n"); | 624 | dev_warn(&adapter->dev, "enabling sensors\n"); |
629 | if (PCIBIOS_SUCCESSFUL != | 625 | if (PCIBIOS_SUCCESSFUL != |
630 | pci_write_config_word(s_bridge, VIA686A_ENABLE_REG, | 626 | pci_write_config_word(s_bridge, VIA686A_ENABLE_REG, |
631 | val | 0x0001)) | 627 | val | 0x0001)) |
632 | return -ENODEV; | 628 | return -ENODEV; |
633 | } | 629 | } |
634 | 630 | ||
635 | /* Reserve the ISA region */ | 631 | /* Reserve the ISA region */ |
636 | if (!request_region(address, VIA686A_EXTENT, via686a_driver.name)) { | 632 | if (!request_region(address, VIA686A_EXTENT, via686a_driver.name)) { |
637 | dev_err(&adapter->dev,"region 0x%x already in use!\n", | 633 | dev_err(&adapter->dev, "region 0x%x already in use!\n", |
638 | address); | 634 | address); |
639 | return -ENODEV; | 635 | return -ENODEV; |
640 | } | 636 | } |
641 | 637 | ||
@@ -660,7 +656,7 @@ static int via686a_detect(struct i2c_adapter *adapter, int address, int kind) | |||
660 | /* Tell the I2C layer a new client has arrived */ | 656 | /* Tell the I2C layer a new client has arrived */ |
661 | if ((err = i2c_attach_client(new_client))) | 657 | if ((err = i2c_attach_client(new_client))) |
662 | goto ERROR3; | 658 | goto ERROR3; |
663 | 659 | ||
664 | /* Initialize the VIA686A chip */ | 660 | /* Initialize the VIA686A chip */ |
665 | via686a_init_client(new_client); | 661 | via686a_init_client(new_client); |
666 | 662 | ||
@@ -699,9 +695,9 @@ static int via686a_detect(struct i2c_adapter *adapter, int address, int kind) | |||
699 | 695 | ||
700 | return 0; | 696 | return 0; |
701 | 697 | ||
702 | ERROR3: | 698 | ERROR3: |
703 | kfree(data); | 699 | kfree(data); |
704 | ERROR0: | 700 | ERROR0: |
705 | release_region(address, VIA686A_EXTENT); | 701 | release_region(address, VIA686A_EXTENT); |
706 | return err; | 702 | return err; |
707 | } | 703 | } |
@@ -732,7 +728,7 @@ static void via686a_init_client(struct i2c_client *client) | |||
732 | via686a_write_value(client, VIA686A_REG_CONFIG, (reg|0x01)&0x7F); | 728 | via686a_write_value(client, VIA686A_REG_CONFIG, (reg|0x01)&0x7F); |
733 | 729 | ||
734 | /* Configure temp interrupt mode for continuous-interrupt operation */ | 730 | /* Configure temp interrupt mode for continuous-interrupt operation */ |
735 | via686a_write_value(client, VIA686A_REG_TEMP_MODE, | 731 | via686a_write_value(client, VIA686A_REG_TEMP_MODE, |
736 | via686a_read_value(client, VIA686A_REG_TEMP_MODE) & | 732 | via686a_read_value(client, VIA686A_REG_TEMP_MODE) & |
737 | !(VIA686A_TEMP_MODE_MASK | VIA686A_TEMP_MODE_CONTINUOUS)); | 733 | !(VIA686A_TEMP_MODE_MASK | VIA686A_TEMP_MODE_CONTINUOUS)); |
738 | } | 734 | } |
@@ -764,15 +760,15 @@ static struct via686a_data *via686a_update_device(struct device *dev) | |||
764 | } | 760 | } |
765 | for (i = 0; i <= 2; i++) { | 761 | for (i = 0; i <= 2; i++) { |
766 | data->temp[i] = via686a_read_value(client, | 762 | data->temp[i] = via686a_read_value(client, |
767 | VIA686A_REG_TEMP(i)) << 2; | 763 | VIA686A_REG_TEMP[i]) << 2; |
768 | data->temp_over[i] = | 764 | data->temp_over[i] = |
769 | via686a_read_value(client, | 765 | via686a_read_value(client, |
770 | VIA686A_REG_TEMP_OVER(i)); | 766 | VIA686A_REG_TEMP_OVER[i]); |
771 | data->temp_hyst[i] = | 767 | data->temp_hyst[i] = |
772 | via686a_read_value(client, | 768 | via686a_read_value(client, |
773 | VIA686A_REG_TEMP_HYST(i)); | 769 | VIA686A_REG_TEMP_HYST[i]); |
774 | } | 770 | } |
775 | /* add in lower 2 bits | 771 | /* add in lower 2 bits |
776 | temp1 uses bits 7-6 of VIA686A_REG_TEMP_LOW1 | 772 | temp1 uses bits 7-6 of VIA686A_REG_TEMP_LOW1 |
777 | temp2 uses bits 5-4 of VIA686A_REG_TEMP_LOW23 | 773 | temp2 uses bits 5-4 of VIA686A_REG_TEMP_LOW23 |
778 | temp3 uses bits 7-6 of VIA686A_REG_TEMP_LOW23 | 774 | temp3 uses bits 7-6 of VIA686A_REG_TEMP_LOW23 |
@@ -804,35 +800,36 @@ static struct via686a_data *via686a_update_device(struct device *dev) | |||
804 | } | 800 | } |
805 | 801 | ||
806 | static struct pci_device_id via686a_pci_ids[] = { | 802 | static struct pci_device_id via686a_pci_ids[] = { |
807 | { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4) }, | 803 | { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4) }, |
808 | { 0, } | 804 | { 0, } |
809 | }; | 805 | }; |
810 | 806 | ||
811 | MODULE_DEVICE_TABLE(pci, via686a_pci_ids); | 807 | MODULE_DEVICE_TABLE(pci, via686a_pci_ids); |
812 | 808 | ||
813 | static int __devinit via686a_pci_probe(struct pci_dev *dev, | 809 | static int __devinit via686a_pci_probe(struct pci_dev *dev, |
814 | const struct pci_device_id *id) | 810 | const struct pci_device_id *id) |
815 | { | 811 | { |
816 | u16 val; | 812 | u16 val; |
817 | int addr = 0; | 813 | int addr = 0; |
818 | 814 | ||
819 | if (PCIBIOS_SUCCESSFUL != | 815 | if (PCIBIOS_SUCCESSFUL != |
820 | pci_read_config_word(dev, VIA686A_BASE_REG, &val)) | 816 | pci_read_config_word(dev, VIA686A_BASE_REG, &val)) |
821 | return -ENODEV; | 817 | return -ENODEV; |
822 | 818 | ||
823 | addr = val & ~(VIA686A_EXTENT - 1); | 819 | addr = val & ~(VIA686A_EXTENT - 1); |
824 | if (addr == 0 && force_addr == 0) { | 820 | if (addr == 0 && force_addr == 0) { |
825 | dev_err(&dev->dev,"base address not set - upgrade BIOS or use force_addr=0xaddr\n"); | 821 | dev_err(&dev->dev, "base address not set - upgrade BIOS " |
826 | return -ENODEV; | 822 | "or use force_addr=0xaddr\n"); |
827 | } | 823 | return -ENODEV; |
828 | if (force_addr) | 824 | } |
829 | addr = force_addr; /* so detect will get called */ | 825 | if (force_addr) |
830 | 826 | addr = force_addr; /* so detect will get called */ | |
831 | if (!addr) { | 827 | |
832 | dev_err(&dev->dev,"No Via 686A sensors found.\n"); | 828 | if (!addr) { |
833 | return -ENODEV; | 829 | dev_err(&dev->dev, "No Via 686A sensors found.\n"); |
834 | } | 830 | return -ENODEV; |
835 | normal_isa[0] = addr; | 831 | } |
832 | normal_isa[0] = addr; | ||
836 | 833 | ||
837 | s_bridge = pci_dev_get(dev); | 834 | s_bridge = pci_dev_get(dev); |
838 | if (i2c_add_driver(&via686a_driver)) { | 835 | if (i2c_add_driver(&via686a_driver)) { |
@@ -848,14 +845,14 @@ static int __devinit via686a_pci_probe(struct pci_dev *dev, | |||
848 | } | 845 | } |
849 | 846 | ||
850 | static struct pci_driver via686a_pci_driver = { | 847 | static struct pci_driver via686a_pci_driver = { |
851 | .name = "via686a", | 848 | .name = "via686a", |
852 | .id_table = via686a_pci_ids, | 849 | .id_table = via686a_pci_ids, |
853 | .probe = via686a_pci_probe, | 850 | .probe = via686a_pci_probe, |
854 | }; | 851 | }; |
855 | 852 | ||
856 | static int __init sm_via686a_init(void) | 853 | static int __init sm_via686a_init(void) |
857 | { | 854 | { |
858 | return pci_register_driver(&via686a_pci_driver); | 855 | return pci_register_driver(&via686a_pci_driver); |
859 | } | 856 | } |
860 | 857 | ||
861 | static void __exit sm_via686a_exit(void) | 858 | static void __exit sm_via686a_exit(void) |
@@ -869,8 +866,8 @@ static void __exit sm_via686a_exit(void) | |||
869 | } | 866 | } |
870 | 867 | ||
871 | MODULE_AUTHOR("Kyösti Mälkki <kmalkki@cc.hut.fi>, " | 868 | MODULE_AUTHOR("Kyösti Mälkki <kmalkki@cc.hut.fi>, " |
872 | "Mark Studebaker <mdsxyz123@yahoo.com> " | 869 | "Mark Studebaker <mdsxyz123@yahoo.com> " |
873 | "and Bob Dougherty <bobd@stanford.edu>"); | 870 | "and Bob Dougherty <bobd@stanford.edu>"); |
874 | MODULE_DESCRIPTION("VIA 686A Sensor device"); | 871 | MODULE_DESCRIPTION("VIA 686A Sensor device"); |
875 | MODULE_LICENSE("GPL"); | 872 | MODULE_LICENSE("GPL"); |
876 | 873 | ||
diff --git a/drivers/i2c/chips/w83627ehf.c b/drivers/i2c/chips/w83627ehf.c new file mode 100644 index 000000000000..8a40b6976e1a --- /dev/null +++ b/drivers/i2c/chips/w83627ehf.c | |||
@@ -0,0 +1,846 @@ | |||
1 | /* | ||
2 | w83627ehf - Driver for the hardware monitoring functionality of | ||
3 | the Winbond W83627EHF Super-I/O chip | ||
4 | Copyright (C) 2005 Jean Delvare <khali@linux-fr.org> | ||
5 | |||
6 | Shamelessly ripped from the w83627hf driver | ||
7 | Copyright (C) 2003 Mark Studebaker | ||
8 | |||
9 | Thanks to Leon Moonen, Steve Cliffe and Grant Coady for their help | ||
10 | in testing and debugging this driver. | ||
11 | |||
12 | This program is free software; you can redistribute it and/or modify | ||
13 | it under the terms of the GNU General Public License as published by | ||
14 | the Free Software Foundation; either version 2 of the License, or | ||
15 | (at your option) any later version. | ||
16 | |||
17 | This program is distributed in the hope that it will be useful, | ||
18 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | GNU General Public License for more details. | ||
21 | |||
22 | You should have received a copy of the GNU General Public License | ||
23 | along with this program; if not, write to the Free Software | ||
24 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | |||
26 | |||
27 | Supports the following chips: | ||
28 | |||
29 | Chip #vin #fan #pwm #temp chip_id man_id | ||
30 | w83627ehf - 5 - 3 0x88 0x5ca3 | ||
31 | |||
32 | This is a preliminary version of the driver, only supporting the | ||
33 | fan and temperature inputs. The chip does much more than that. | ||
34 | */ | ||
35 | |||
36 | #include <linux/module.h> | ||
37 | #include <linux/init.h> | ||
38 | #include <linux/slab.h> | ||
39 | #include <linux/i2c.h> | ||
40 | #include <linux/i2c-sensor.h> | ||
41 | #include <asm/io.h> | ||
42 | #include "lm75.h" | ||
43 | |||
44 | /* Addresses to scan | ||
45 | The actual ISA address is read from Super-I/O configuration space */ | ||
46 | static unsigned short normal_i2c[] = { I2C_CLIENT_END }; | ||
47 | static unsigned int normal_isa[] = { 0, I2C_CLIENT_ISA_END }; | ||
48 | |||
49 | /* Insmod parameters */ | ||
50 | SENSORS_INSMOD_1(w83627ehf); | ||
51 | |||
52 | /* | ||
53 | * Super-I/O constants and functions | ||
54 | */ | ||
55 | |||
56 | static int REG; /* The register to read/write */ | ||
57 | static int VAL; /* The value to read/write */ | ||
58 | |||
59 | #define W83627EHF_LD_HWM 0x0b | ||
60 | |||
61 | #define SIO_REG_LDSEL 0x07 /* Logical device select */ | ||
62 | #define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */ | ||
63 | #define SIO_REG_ENABLE 0x30 /* Logical device enable */ | ||
64 | #define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */ | ||
65 | |||
66 | #define SIO_W83627EHF_ID 0x8840 | ||
67 | #define SIO_ID_MASK 0xFFC0 | ||
68 | |||
69 | static inline void | ||
70 | superio_outb(int reg, int val) | ||
71 | { | ||
72 | outb(reg, REG); | ||
73 | outb(val, VAL); | ||
74 | } | ||
75 | |||
76 | static inline int | ||
77 | superio_inb(int reg) | ||
78 | { | ||
79 | outb(reg, REG); | ||
80 | return inb(VAL); | ||
81 | } | ||
82 | |||
83 | static inline void | ||
84 | superio_select(int ld) | ||
85 | { | ||
86 | outb(SIO_REG_LDSEL, REG); | ||
87 | outb(ld, VAL); | ||
88 | } | ||
89 | |||
90 | static inline void | ||
91 | superio_enter(void) | ||
92 | { | ||
93 | outb(0x87, REG); | ||
94 | outb(0x87, REG); | ||
95 | } | ||
96 | |||
97 | static inline void | ||
98 | superio_exit(void) | ||
99 | { | ||
100 | outb(0x02, REG); | ||
101 | outb(0x02, VAL); | ||
102 | } | ||
103 | |||
104 | /* | ||
105 | * ISA constants | ||
106 | */ | ||
107 | |||
108 | #define REGION_LENGTH 8 | ||
109 | #define ADDR_REG_OFFSET 5 | ||
110 | #define DATA_REG_OFFSET 6 | ||
111 | |||
112 | #define W83627EHF_REG_BANK 0x4E | ||
113 | #define W83627EHF_REG_CONFIG 0x40 | ||
114 | #define W83627EHF_REG_CHIP_ID 0x49 | ||
115 | #define W83627EHF_REG_MAN_ID 0x4F | ||
116 | |||
117 | static const u16 W83627EHF_REG_FAN[] = { 0x28, 0x29, 0x2a, 0x3f, 0x553 }; | ||
118 | static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c }; | ||
119 | |||
120 | #define W83627EHF_REG_TEMP1 0x27 | ||
121 | #define W83627EHF_REG_TEMP1_HYST 0x3a | ||
122 | #define W83627EHF_REG_TEMP1_OVER 0x39 | ||
123 | static const u16 W83627EHF_REG_TEMP[] = { 0x150, 0x250 }; | ||
124 | static const u16 W83627EHF_REG_TEMP_HYST[] = { 0x153, 0x253 }; | ||
125 | static const u16 W83627EHF_REG_TEMP_OVER[] = { 0x155, 0x255 }; | ||
126 | static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0x152, 0x252 }; | ||
127 | |||
128 | /* Fan clock dividers are spread over the following five registers */ | ||
129 | #define W83627EHF_REG_FANDIV1 0x47 | ||
130 | #define W83627EHF_REG_FANDIV2 0x4B | ||
131 | #define W83627EHF_REG_VBAT 0x5D | ||
132 | #define W83627EHF_REG_DIODE 0x59 | ||
133 | #define W83627EHF_REG_SMI_OVT 0x4C | ||
134 | |||
135 | /* | ||
136 | * Conversions | ||
137 | */ | ||
138 | |||
139 | static inline unsigned int | ||
140 | fan_from_reg(u8 reg, unsigned int div) | ||
141 | { | ||
142 | if (reg == 0 || reg == 255) | ||
143 | return 0; | ||
144 | return 1350000U / (reg * div); | ||
145 | } | ||
146 | |||
147 | static inline unsigned int | ||
148 | div_from_reg(u8 reg) | ||
149 | { | ||
150 | return 1 << reg; | ||
151 | } | ||
152 | |||
153 | static inline int | ||
154 | temp1_from_reg(s8 reg) | ||
155 | { | ||
156 | return reg * 1000; | ||
157 | } | ||
158 | |||
159 | static inline s8 | ||
160 | temp1_to_reg(int temp) | ||
161 | { | ||
162 | if (temp <= -128000) | ||
163 | return -128; | ||
164 | if (temp >= 127000) | ||
165 | return 127; | ||
166 | if (temp < 0) | ||
167 | return (temp - 500) / 1000; | ||
168 | return (temp + 500) / 1000; | ||
169 | } | ||
170 | |||
171 | /* | ||
172 | * Data structures and manipulation thereof | ||
173 | */ | ||
174 | |||
175 | struct w83627ehf_data { | ||
176 | struct i2c_client client; | ||
177 | struct semaphore lock; | ||
178 | |||
179 | struct semaphore update_lock; | ||
180 | char valid; /* !=0 if following fields are valid */ | ||
181 | unsigned long last_updated; /* In jiffies */ | ||
182 | |||
183 | /* Register values */ | ||
184 | u8 fan[5]; | ||
185 | u8 fan_min[5]; | ||
186 | u8 fan_div[5]; | ||
187 | u8 has_fan; /* some fan inputs can be disabled */ | ||
188 | s8 temp1; | ||
189 | s8 temp1_max; | ||
190 | s8 temp1_max_hyst; | ||
191 | s16 temp[2]; | ||
192 | s16 temp_max[2]; | ||
193 | s16 temp_max_hyst[2]; | ||
194 | }; | ||
195 | |||
196 | static inline int is_word_sized(u16 reg) | ||
197 | { | ||
198 | return (((reg & 0xff00) == 0x100 | ||
199 | || (reg & 0xff00) == 0x200) | ||
200 | && ((reg & 0x00ff) == 0x50 | ||
201 | || (reg & 0x00ff) == 0x53 | ||
202 | || (reg & 0x00ff) == 0x55)); | ||
203 | } | ||
204 | |||
205 | /* We assume that the default bank is 0, thus the following two functions do | ||
206 | nothing for registers which live in bank 0. For others, they respectively | ||
207 | set the bank register to the correct value (before the register is | ||
208 | accessed), and back to 0 (afterwards). */ | ||
209 | static inline void w83627ehf_set_bank(struct i2c_client *client, u16 reg) | ||
210 | { | ||
211 | if (reg & 0xff00) { | ||
212 | outb_p(W83627EHF_REG_BANK, client->addr + ADDR_REG_OFFSET); | ||
213 | outb_p(reg >> 8, client->addr + DATA_REG_OFFSET); | ||
214 | } | ||
215 | } | ||
216 | |||
217 | static inline void w83627ehf_reset_bank(struct i2c_client *client, u16 reg) | ||
218 | { | ||
219 | if (reg & 0xff00) { | ||
220 | outb_p(W83627EHF_REG_BANK, client->addr + ADDR_REG_OFFSET); | ||
221 | outb_p(0, client->addr + DATA_REG_OFFSET); | ||
222 | } | ||
223 | } | ||
224 | |||
225 | static u16 w83627ehf_read_value(struct i2c_client *client, u16 reg) | ||
226 | { | ||
227 | struct w83627ehf_data *data = i2c_get_clientdata(client); | ||
228 | int res, word_sized = is_word_sized(reg); | ||
229 | |||
230 | down(&data->lock); | ||
231 | |||
232 | w83627ehf_set_bank(client, reg); | ||
233 | outb_p(reg & 0xff, client->addr + ADDR_REG_OFFSET); | ||
234 | res = inb_p(client->addr + DATA_REG_OFFSET); | ||
235 | if (word_sized) { | ||
236 | outb_p((reg & 0xff) + 1, | ||
237 | client->addr + ADDR_REG_OFFSET); | ||
238 | res = (res << 8) + inb_p(client->addr + DATA_REG_OFFSET); | ||
239 | } | ||
240 | w83627ehf_reset_bank(client, reg); | ||
241 | |||
242 | up(&data->lock); | ||
243 | |||
244 | return res; | ||
245 | } | ||
246 | |||
247 | static int w83627ehf_write_value(struct i2c_client *client, u16 reg, u16 value) | ||
248 | { | ||
249 | struct w83627ehf_data *data = i2c_get_clientdata(client); | ||
250 | int word_sized = is_word_sized(reg); | ||
251 | |||
252 | down(&data->lock); | ||
253 | |||
254 | w83627ehf_set_bank(client, reg); | ||
255 | outb_p(reg & 0xff, client->addr + ADDR_REG_OFFSET); | ||
256 | if (word_sized) { | ||
257 | outb_p(value >> 8, client->addr + DATA_REG_OFFSET); | ||
258 | outb_p((reg & 0xff) + 1, | ||
259 | client->addr + ADDR_REG_OFFSET); | ||
260 | } | ||
261 | outb_p(value & 0xff, client->addr + DATA_REG_OFFSET); | ||
262 | w83627ehf_reset_bank(client, reg); | ||
263 | |||
264 | up(&data->lock); | ||
265 | return 0; | ||
266 | } | ||
267 | |||
268 | /* This function assumes that the caller holds data->update_lock */ | ||
269 | static void w83627ehf_write_fan_div(struct i2c_client *client, int nr) | ||
270 | { | ||
271 | struct w83627ehf_data *data = i2c_get_clientdata(client); | ||
272 | u8 reg; | ||
273 | |||
274 | switch (nr) { | ||
275 | case 0: | ||
276 | reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) & 0xcf) | ||
277 | | ((data->fan_div[0] & 0x03) << 4); | ||
278 | w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg); | ||
279 | reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0xdf) | ||
280 | | ((data->fan_div[0] & 0x04) << 3); | ||
281 | w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg); | ||
282 | break; | ||
283 | case 1: | ||
284 | reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) & 0x3f) | ||
285 | | ((data->fan_div[1] & 0x03) << 6); | ||
286 | w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg); | ||
287 | reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0xbf) | ||
288 | | ((data->fan_div[1] & 0x04) << 4); | ||
289 | w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg); | ||
290 | break; | ||
291 | case 2: | ||
292 | reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV2) & 0x3f) | ||
293 | | ((data->fan_div[2] & 0x03) << 6); | ||
294 | w83627ehf_write_value(client, W83627EHF_REG_FANDIV2, reg); | ||
295 | reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0x7f) | ||
296 | | ((data->fan_div[2] & 0x04) << 5); | ||
297 | w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg); | ||
298 | break; | ||
299 | case 3: | ||
300 | reg = (w83627ehf_read_value(client, W83627EHF_REG_DIODE) & 0xfc) | ||
301 | | (data->fan_div[3] & 0x03); | ||
302 | w83627ehf_write_value(client, W83627EHF_REG_DIODE, reg); | ||
303 | reg = (w83627ehf_read_value(client, W83627EHF_REG_SMI_OVT) & 0x7f) | ||
304 | | ((data->fan_div[3] & 0x04) << 5); | ||
305 | w83627ehf_write_value(client, W83627EHF_REG_SMI_OVT, reg); | ||
306 | break; | ||
307 | case 4: | ||
308 | reg = (w83627ehf_read_value(client, W83627EHF_REG_DIODE) & 0x73) | ||
309 | | ((data->fan_div[4] & 0x03) << 3) | ||
310 | | ((data->fan_div[4] & 0x04) << 5); | ||
311 | w83627ehf_write_value(client, W83627EHF_REG_DIODE, reg); | ||
312 | break; | ||
313 | } | ||
314 | } | ||
315 | |||
316 | static struct w83627ehf_data *w83627ehf_update_device(struct device *dev) | ||
317 | { | ||
318 | struct i2c_client *client = to_i2c_client(dev); | ||
319 | struct w83627ehf_data *data = i2c_get_clientdata(client); | ||
320 | int i; | ||
321 | |||
322 | down(&data->update_lock); | ||
323 | |||
324 | if (time_after(jiffies, data->last_updated + HZ) | ||
325 | || !data->valid) { | ||
326 | /* Fan clock dividers */ | ||
327 | i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1); | ||
328 | data->fan_div[0] = (i >> 4) & 0x03; | ||
329 | data->fan_div[1] = (i >> 6) & 0x03; | ||
330 | i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV2); | ||
331 | data->fan_div[2] = (i >> 6) & 0x03; | ||
332 | i = w83627ehf_read_value(client, W83627EHF_REG_VBAT); | ||
333 | data->fan_div[0] |= (i >> 3) & 0x04; | ||
334 | data->fan_div[1] |= (i >> 4) & 0x04; | ||
335 | data->fan_div[2] |= (i >> 5) & 0x04; | ||
336 | if (data->has_fan & ((1 << 3) | (1 << 4))) { | ||
337 | i = w83627ehf_read_value(client, W83627EHF_REG_DIODE); | ||
338 | data->fan_div[3] = i & 0x03; | ||
339 | data->fan_div[4] = ((i >> 2) & 0x03) | ||
340 | | ((i >> 5) & 0x04); | ||
341 | } | ||
342 | if (data->has_fan & (1 << 3)) { | ||
343 | i = w83627ehf_read_value(client, W83627EHF_REG_SMI_OVT); | ||
344 | data->fan_div[3] |= (i >> 5) & 0x04; | ||
345 | } | ||
346 | |||
347 | /* Measured fan speeds and limits */ | ||
348 | for (i = 0; i < 5; i++) { | ||
349 | if (!(data->has_fan & (1 << i))) | ||
350 | continue; | ||
351 | |||
352 | data->fan[i] = w83627ehf_read_value(client, | ||
353 | W83627EHF_REG_FAN[i]); | ||
354 | data->fan_min[i] = w83627ehf_read_value(client, | ||
355 | W83627EHF_REG_FAN_MIN[i]); | ||
356 | |||
357 | /* If we failed to measure the fan speed and clock | ||
358 | divider can be increased, let's try that for next | ||
359 | time */ | ||
360 | if (data->fan[i] == 0xff | ||
361 | && data->fan_div[i] < 0x07) { | ||
362 | dev_dbg(&client->dev, "Increasing fan %d " | ||
363 | "clock divider from %u to %u\n", | ||
364 | i, div_from_reg(data->fan_div[i]), | ||
365 | div_from_reg(data->fan_div[i] + 1)); | ||
366 | data->fan_div[i]++; | ||
367 | w83627ehf_write_fan_div(client, i); | ||
368 | /* Preserve min limit if possible */ | ||
369 | if (data->fan_min[i] >= 2 | ||
370 | && data->fan_min[i] != 255) | ||
371 | w83627ehf_write_value(client, | ||
372 | W83627EHF_REG_FAN_MIN[i], | ||
373 | (data->fan_min[i] /= 2)); | ||
374 | } | ||
375 | } | ||
376 | |||
377 | /* Measured temperatures and limits */ | ||
378 | data->temp1 = w83627ehf_read_value(client, | ||
379 | W83627EHF_REG_TEMP1); | ||
380 | data->temp1_max = w83627ehf_read_value(client, | ||
381 | W83627EHF_REG_TEMP1_OVER); | ||
382 | data->temp1_max_hyst = w83627ehf_read_value(client, | ||
383 | W83627EHF_REG_TEMP1_HYST); | ||
384 | for (i = 0; i < 2; i++) { | ||
385 | data->temp[i] = w83627ehf_read_value(client, | ||
386 | W83627EHF_REG_TEMP[i]); | ||
387 | data->temp_max[i] = w83627ehf_read_value(client, | ||
388 | W83627EHF_REG_TEMP_OVER[i]); | ||
389 | data->temp_max_hyst[i] = w83627ehf_read_value(client, | ||
390 | W83627EHF_REG_TEMP_HYST[i]); | ||
391 | } | ||
392 | |||
393 | data->last_updated = jiffies; | ||
394 | data->valid = 1; | ||
395 | } | ||
396 | |||
397 | up(&data->update_lock); | ||
398 | return data; | ||
399 | } | ||
400 | |||
401 | /* | ||
402 | * Sysfs callback functions | ||
403 | */ | ||
404 | |||
405 | #define show_fan_reg(reg) \ | ||
406 | static ssize_t \ | ||
407 | show_##reg(struct device *dev, char *buf, int nr) \ | ||
408 | { \ | ||
409 | struct w83627ehf_data *data = w83627ehf_update_device(dev); \ | ||
410 | return sprintf(buf, "%d\n", \ | ||
411 | fan_from_reg(data->reg[nr], \ | ||
412 | div_from_reg(data->fan_div[nr]))); \ | ||
413 | } | ||
414 | show_fan_reg(fan); | ||
415 | show_fan_reg(fan_min); | ||
416 | |||
417 | static ssize_t | ||
418 | show_fan_div(struct device *dev, char *buf, int nr) | ||
419 | { | ||
420 | struct w83627ehf_data *data = w83627ehf_update_device(dev); | ||
421 | return sprintf(buf, "%u\n", | ||
422 | div_from_reg(data->fan_div[nr])); | ||
423 | } | ||
424 | |||
425 | static ssize_t | ||
426 | store_fan_min(struct device *dev, const char *buf, size_t count, int nr) | ||
427 | { | ||
428 | struct i2c_client *client = to_i2c_client(dev); | ||
429 | struct w83627ehf_data *data = i2c_get_clientdata(client); | ||
430 | unsigned int val = simple_strtoul(buf, NULL, 10); | ||
431 | unsigned int reg; | ||
432 | u8 new_div; | ||
433 | |||
434 | down(&data->update_lock); | ||
435 | if (!val) { | ||
436 | /* No min limit, alarm disabled */ | ||
437 | data->fan_min[nr] = 255; | ||
438 | new_div = data->fan_div[nr]; /* No change */ | ||
439 | dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1); | ||
440 | } else if ((reg = 1350000U / val) >= 128 * 255) { | ||
441 | /* Speed below this value cannot possibly be represented, | ||
442 | even with the highest divider (128) */ | ||
443 | data->fan_min[nr] = 254; | ||
444 | new_div = 7; /* 128 == (1 << 7) */ | ||
445 | dev_warn(dev, "fan%u low limit %u below minimum %u, set to " | ||
446 | "minimum\n", nr + 1, val, fan_from_reg(254, 128)); | ||
447 | } else if (!reg) { | ||
448 | /* Speed above this value cannot possibly be represented, | ||
449 | even with the lowest divider (1) */ | ||
450 | data->fan_min[nr] = 1; | ||
451 | new_div = 0; /* 1 == (1 << 0) */ | ||
452 | dev_warn(dev, "fan%u low limit %u above maximum %u, set to " | ||
453 | "maximum\n", nr + 1, val, fan_from_reg(1, 1)); | ||
454 | } else { | ||
455 | /* Automatically pick the best divider, i.e. the one such | ||
456 | that the min limit will correspond to a register value | ||
457 | in the 96..192 range */ | ||
458 | new_div = 0; | ||
459 | while (reg > 192 && new_div < 7) { | ||
460 | reg >>= 1; | ||
461 | new_div++; | ||
462 | } | ||
463 | data->fan_min[nr] = reg; | ||
464 | } | ||
465 | |||
466 | /* Write both the fan clock divider (if it changed) and the new | ||
467 | fan min (unconditionally) */ | ||
468 | if (new_div != data->fan_div[nr]) { | ||
469 | if (new_div > data->fan_div[nr]) | ||
470 | data->fan[nr] >>= (data->fan_div[nr] - new_div); | ||
471 | else | ||
472 | data->fan[nr] <<= (new_div - data->fan_div[nr]); | ||
473 | |||
474 | dev_dbg(dev, "fan%u clock divider changed from %u to %u\n", | ||
475 | nr + 1, div_from_reg(data->fan_div[nr]), | ||
476 | div_from_reg(new_div)); | ||
477 | data->fan_div[nr] = new_div; | ||
478 | w83627ehf_write_fan_div(client, nr); | ||
479 | } | ||
480 | w83627ehf_write_value(client, W83627EHF_REG_FAN_MIN[nr], | ||
481 | data->fan_min[nr]); | ||
482 | up(&data->update_lock); | ||
483 | |||
484 | return count; | ||
485 | } | ||
486 | |||
487 | #define sysfs_fan_offset(offset) \ | ||
488 | static ssize_t \ | ||
489 | show_reg_fan_##offset(struct device *dev, struct device_attribute *attr, \ | ||
490 | char *buf) \ | ||
491 | { \ | ||
492 | return show_fan(dev, buf, offset-1); \ | ||
493 | } \ | ||
494 | static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ | ||
495 | show_reg_fan_##offset, NULL); | ||
496 | |||
497 | #define sysfs_fan_min_offset(offset) \ | ||
498 | static ssize_t \ | ||
499 | show_reg_fan##offset##_min(struct device *dev, struct device_attribute *attr, \ | ||
500 | char *buf) \ | ||
501 | { \ | ||
502 | return show_fan_min(dev, buf, offset-1); \ | ||
503 | } \ | ||
504 | static ssize_t \ | ||
505 | store_reg_fan##offset##_min(struct device *dev, struct device_attribute *attr, \ | ||
506 | const char *buf, size_t count) \ | ||
507 | { \ | ||
508 | return store_fan_min(dev, buf, count, offset-1); \ | ||
509 | } \ | ||
510 | static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ | ||
511 | show_reg_fan##offset##_min, \ | ||
512 | store_reg_fan##offset##_min); | ||
513 | |||
514 | #define sysfs_fan_div_offset(offset) \ | ||
515 | static ssize_t \ | ||
516 | show_reg_fan##offset##_div(struct device *dev, struct device_attribute *attr, \ | ||
517 | char *buf) \ | ||
518 | { \ | ||
519 | return show_fan_div(dev, buf, offset - 1); \ | ||
520 | } \ | ||
521 | static DEVICE_ATTR(fan##offset##_div, S_IRUGO, \ | ||
522 | show_reg_fan##offset##_div, NULL); | ||
523 | |||
524 | sysfs_fan_offset(1); | ||
525 | sysfs_fan_min_offset(1); | ||
526 | sysfs_fan_div_offset(1); | ||
527 | sysfs_fan_offset(2); | ||
528 | sysfs_fan_min_offset(2); | ||
529 | sysfs_fan_div_offset(2); | ||
530 | sysfs_fan_offset(3); | ||
531 | sysfs_fan_min_offset(3); | ||
532 | sysfs_fan_div_offset(3); | ||
533 | sysfs_fan_offset(4); | ||
534 | sysfs_fan_min_offset(4); | ||
535 | sysfs_fan_div_offset(4); | ||
536 | sysfs_fan_offset(5); | ||
537 | sysfs_fan_min_offset(5); | ||
538 | sysfs_fan_div_offset(5); | ||
539 | |||
540 | #define show_temp1_reg(reg) \ | ||
541 | static ssize_t \ | ||
542 | show_##reg(struct device *dev, struct device_attribute *attr, \ | ||
543 | char *buf) \ | ||
544 | { \ | ||
545 | struct w83627ehf_data *data = w83627ehf_update_device(dev); \ | ||
546 | return sprintf(buf, "%d\n", temp1_from_reg(data->reg)); \ | ||
547 | } | ||
548 | show_temp1_reg(temp1); | ||
549 | show_temp1_reg(temp1_max); | ||
550 | show_temp1_reg(temp1_max_hyst); | ||
551 | |||
552 | #define store_temp1_reg(REG, reg) \ | ||
553 | static ssize_t \ | ||
554 | store_temp1_##reg(struct device *dev, struct device_attribute *attr, \ | ||
555 | const char *buf, size_t count) \ | ||
556 | { \ | ||
557 | struct i2c_client *client = to_i2c_client(dev); \ | ||
558 | struct w83627ehf_data *data = i2c_get_clientdata(client); \ | ||
559 | u32 val = simple_strtoul(buf, NULL, 10); \ | ||
560 | \ | ||
561 | down(&data->update_lock); \ | ||
562 | data->temp1_##reg = temp1_to_reg(val); \ | ||
563 | w83627ehf_write_value(client, W83627EHF_REG_TEMP1_##REG, \ | ||
564 | data->temp1_##reg); \ | ||
565 | up(&data->update_lock); \ | ||
566 | return count; \ | ||
567 | } | ||
568 | store_temp1_reg(OVER, max); | ||
569 | store_temp1_reg(HYST, max_hyst); | ||
570 | |||
571 | static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp1, NULL); | ||
572 | static DEVICE_ATTR(temp1_max, S_IRUGO| S_IWUSR, | ||
573 | show_temp1_max, store_temp1_max); | ||
574 | static DEVICE_ATTR(temp1_max_hyst, S_IRUGO| S_IWUSR, | ||
575 | show_temp1_max_hyst, store_temp1_max_hyst); | ||
576 | |||
577 | #define show_temp_reg(reg) \ | ||
578 | static ssize_t \ | ||
579 | show_##reg (struct device *dev, char *buf, int nr) \ | ||
580 | { \ | ||
581 | struct w83627ehf_data *data = w83627ehf_update_device(dev); \ | ||
582 | return sprintf(buf, "%d\n", \ | ||
583 | LM75_TEMP_FROM_REG(data->reg[nr])); \ | ||
584 | } | ||
585 | show_temp_reg(temp); | ||
586 | show_temp_reg(temp_max); | ||
587 | show_temp_reg(temp_max_hyst); | ||
588 | |||
589 | #define store_temp_reg(REG, reg) \ | ||
590 | static ssize_t \ | ||
591 | store_##reg (struct device *dev, const char *buf, size_t count, int nr) \ | ||
592 | { \ | ||
593 | struct i2c_client *client = to_i2c_client(dev); \ | ||
594 | struct w83627ehf_data *data = i2c_get_clientdata(client); \ | ||
595 | u32 val = simple_strtoul(buf, NULL, 10); \ | ||
596 | \ | ||
597 | down(&data->update_lock); \ | ||
598 | data->reg[nr] = LM75_TEMP_TO_REG(val); \ | ||
599 | w83627ehf_write_value(client, W83627EHF_REG_TEMP_##REG[nr], \ | ||
600 | data->reg[nr]); \ | ||
601 | up(&data->update_lock); \ | ||
602 | return count; \ | ||
603 | } | ||
604 | store_temp_reg(OVER, temp_max); | ||
605 | store_temp_reg(HYST, temp_max_hyst); | ||
606 | |||
607 | #define sysfs_temp_offset(offset) \ | ||
608 | static ssize_t \ | ||
609 | show_reg_temp##offset (struct device *dev, struct device_attribute *attr, \ | ||
610 | char *buf) \ | ||
611 | { \ | ||
612 | return show_temp(dev, buf, offset - 2); \ | ||
613 | } \ | ||
614 | static DEVICE_ATTR(temp##offset##_input, S_IRUGO, \ | ||
615 | show_reg_temp##offset, NULL); | ||
616 | |||
617 | #define sysfs_temp_reg_offset(reg, offset) \ | ||
618 | static ssize_t \ | ||
619 | show_reg_temp##offset##_##reg(struct device *dev, struct device_attribute *attr, \ | ||
620 | char *buf) \ | ||
621 | { \ | ||
622 | return show_temp_##reg(dev, buf, offset - 2); \ | ||
623 | } \ | ||
624 | static ssize_t \ | ||
625 | store_reg_temp##offset##_##reg(struct device *dev, struct device_attribute *attr, \ | ||
626 | const char *buf, size_t count) \ | ||
627 | { \ | ||
628 | return store_temp_##reg(dev, buf, count, offset - 2); \ | ||
629 | } \ | ||
630 | static DEVICE_ATTR(temp##offset##_##reg, S_IRUGO| S_IWUSR, \ | ||
631 | show_reg_temp##offset##_##reg, \ | ||
632 | store_reg_temp##offset##_##reg); | ||
633 | |||
634 | sysfs_temp_offset(2); | ||
635 | sysfs_temp_reg_offset(max, 2); | ||
636 | sysfs_temp_reg_offset(max_hyst, 2); | ||
637 | sysfs_temp_offset(3); | ||
638 | sysfs_temp_reg_offset(max, 3); | ||
639 | sysfs_temp_reg_offset(max_hyst, 3); | ||
640 | |||
641 | /* | ||
642 | * Driver and client management | ||
643 | */ | ||
644 | |||
645 | static struct i2c_driver w83627ehf_driver; | ||
646 | |||
647 | static void w83627ehf_init_client(struct i2c_client *client) | ||
648 | { | ||
649 | int i; | ||
650 | u8 tmp; | ||
651 | |||
652 | /* Start monitoring is needed */ | ||
653 | tmp = w83627ehf_read_value(client, W83627EHF_REG_CONFIG); | ||
654 | if (!(tmp & 0x01)) | ||
655 | w83627ehf_write_value(client, W83627EHF_REG_CONFIG, | ||
656 | tmp | 0x01); | ||
657 | |||
658 | /* Enable temp2 and temp3 if needed */ | ||
659 | for (i = 0; i < 2; i++) { | ||
660 | tmp = w83627ehf_read_value(client, | ||
661 | W83627EHF_REG_TEMP_CONFIG[i]); | ||
662 | if (tmp & 0x01) | ||
663 | w83627ehf_write_value(client, | ||
664 | W83627EHF_REG_TEMP_CONFIG[i], | ||
665 | tmp & 0xfe); | ||
666 | } | ||
667 | } | ||
668 | |||
669 | static int w83627ehf_detect(struct i2c_adapter *adapter, int address, int kind) | ||
670 | { | ||
671 | struct i2c_client *client; | ||
672 | struct w83627ehf_data *data; | ||
673 | int i, err = 0; | ||
674 | |||
675 | if (!i2c_is_isa_adapter(adapter)) | ||
676 | return 0; | ||
677 | |||
678 | if (!request_region(address, REGION_LENGTH, w83627ehf_driver.name)) { | ||
679 | err = -EBUSY; | ||
680 | goto exit; | ||
681 | } | ||
682 | |||
683 | if (!(data = kmalloc(sizeof(struct w83627ehf_data), GFP_KERNEL))) { | ||
684 | err = -ENOMEM; | ||
685 | goto exit_release; | ||
686 | } | ||
687 | memset(data, 0, sizeof(struct w83627ehf_data)); | ||
688 | |||
689 | client = &data->client; | ||
690 | i2c_set_clientdata(client, data); | ||
691 | client->addr = address; | ||
692 | init_MUTEX(&data->lock); | ||
693 | client->adapter = adapter; | ||
694 | client->driver = &w83627ehf_driver; | ||
695 | client->flags = 0; | ||
696 | |||
697 | strlcpy(client->name, "w83627ehf", I2C_NAME_SIZE); | ||
698 | data->valid = 0; | ||
699 | init_MUTEX(&data->update_lock); | ||
700 | |||
701 | /* Tell the i2c layer a new client has arrived */ | ||
702 | if ((err = i2c_attach_client(client))) | ||
703 | goto exit_free; | ||
704 | |||
705 | /* Initialize the chip */ | ||
706 | w83627ehf_init_client(client); | ||
707 | |||
708 | /* A few vars need to be filled upon startup */ | ||
709 | for (i = 0; i < 5; i++) | ||
710 | data->fan_min[i] = w83627ehf_read_value(client, | ||
711 | W83627EHF_REG_FAN_MIN[i]); | ||
712 | |||
713 | /* It looks like fan4 and fan5 pins can be alternatively used | ||
714 | as fan on/off switches */ | ||
715 | data->has_fan = 0x07; /* fan1, fan2 and fan3 */ | ||
716 | i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1); | ||
717 | if (i & (1 << 2)) | ||
718 | data->has_fan |= (1 << 3); | ||
719 | if (i & (1 << 0)) | ||
720 | data->has_fan |= (1 << 4); | ||
721 | |||
722 | /* Register sysfs hooks */ | ||
723 | device_create_file(&client->dev, &dev_attr_fan1_input); | ||
724 | device_create_file(&client->dev, &dev_attr_fan1_min); | ||
725 | device_create_file(&client->dev, &dev_attr_fan1_div); | ||
726 | device_create_file(&client->dev, &dev_attr_fan2_input); | ||
727 | device_create_file(&client->dev, &dev_attr_fan2_min); | ||
728 | device_create_file(&client->dev, &dev_attr_fan2_div); | ||
729 | device_create_file(&client->dev, &dev_attr_fan3_input); | ||
730 | device_create_file(&client->dev, &dev_attr_fan3_min); | ||
731 | device_create_file(&client->dev, &dev_attr_fan3_div); | ||
732 | |||
733 | if (data->has_fan & (1 << 3)) { | ||
734 | device_create_file(&client->dev, &dev_attr_fan4_input); | ||
735 | device_create_file(&client->dev, &dev_attr_fan4_min); | ||
736 | device_create_file(&client->dev, &dev_attr_fan4_div); | ||
737 | } | ||
738 | if (data->has_fan & (1 << 4)) { | ||
739 | device_create_file(&client->dev, &dev_attr_fan5_input); | ||
740 | device_create_file(&client->dev, &dev_attr_fan5_min); | ||
741 | device_create_file(&client->dev, &dev_attr_fan5_div); | ||
742 | } | ||
743 | |||
744 | device_create_file(&client->dev, &dev_attr_temp1_input); | ||
745 | device_create_file(&client->dev, &dev_attr_temp1_max); | ||
746 | device_create_file(&client->dev, &dev_attr_temp1_max_hyst); | ||
747 | device_create_file(&client->dev, &dev_attr_temp2_input); | ||
748 | device_create_file(&client->dev, &dev_attr_temp2_max); | ||
749 | device_create_file(&client->dev, &dev_attr_temp2_max_hyst); | ||
750 | device_create_file(&client->dev, &dev_attr_temp3_input); | ||
751 | device_create_file(&client->dev, &dev_attr_temp3_max); | ||
752 | device_create_file(&client->dev, &dev_attr_temp3_max_hyst); | ||
753 | |||
754 | return 0; | ||
755 | |||
756 | exit_free: | ||
757 | kfree(data); | ||
758 | exit_release: | ||
759 | release_region(address, REGION_LENGTH); | ||
760 | exit: | ||
761 | return err; | ||
762 | } | ||
763 | |||
764 | static int w83627ehf_attach_adapter(struct i2c_adapter *adapter) | ||
765 | { | ||
766 | if (!(adapter->class & I2C_CLASS_HWMON)) | ||
767 | return 0; | ||
768 | return i2c_detect(adapter, &addr_data, w83627ehf_detect); | ||
769 | } | ||
770 | |||
771 | static int w83627ehf_detach_client(struct i2c_client *client) | ||
772 | { | ||
773 | int err; | ||
774 | |||
775 | if ((err = i2c_detach_client(client))) { | ||
776 | dev_err(&client->dev, "Client deregistration failed, " | ||
777 | "client not detached.\n"); | ||
778 | return err; | ||
779 | } | ||
780 | release_region(client->addr, REGION_LENGTH); | ||
781 | kfree(i2c_get_clientdata(client)); | ||
782 | |||
783 | return 0; | ||
784 | } | ||
785 | |||
786 | static struct i2c_driver w83627ehf_driver = { | ||
787 | .owner = THIS_MODULE, | ||
788 | .name = "w83627ehf", | ||
789 | .flags = I2C_DF_NOTIFY, | ||
790 | .attach_adapter = w83627ehf_attach_adapter, | ||
791 | .detach_client = w83627ehf_detach_client, | ||
792 | }; | ||
793 | |||
794 | static int __init w83627ehf_find(int sioaddr, int *address) | ||
795 | { | ||
796 | u16 val; | ||
797 | |||
798 | REG = sioaddr; | ||
799 | VAL = sioaddr + 1; | ||
800 | superio_enter(); | ||
801 | |||
802 | val = (superio_inb(SIO_REG_DEVID) << 8) | ||
803 | | superio_inb(SIO_REG_DEVID + 1); | ||
804 | if ((val & SIO_ID_MASK) != SIO_W83627EHF_ID) { | ||
805 | superio_exit(); | ||
806 | return -ENODEV; | ||
807 | } | ||
808 | |||
809 | superio_select(W83627EHF_LD_HWM); | ||
810 | val = (superio_inb(SIO_REG_ADDR) << 8) | ||
811 | | superio_inb(SIO_REG_ADDR + 1); | ||
812 | *address = val & ~(REGION_LENGTH - 1); | ||
813 | if (*address == 0) { | ||
814 | superio_exit(); | ||
815 | return -ENODEV; | ||
816 | } | ||
817 | |||
818 | /* Activate logical device if needed */ | ||
819 | val = superio_inb(SIO_REG_ENABLE); | ||
820 | if (!(val & 0x01)) | ||
821 | superio_outb(SIO_REG_ENABLE, val | 0x01); | ||
822 | |||
823 | superio_exit(); | ||
824 | return 0; | ||
825 | } | ||
826 | |||
827 | static int __init sensors_w83627ehf_init(void) | ||
828 | { | ||
829 | if (w83627ehf_find(0x2e, &normal_isa[0]) | ||
830 | && w83627ehf_find(0x4e, &normal_isa[0])) | ||
831 | return -ENODEV; | ||
832 | |||
833 | return i2c_add_driver(&w83627ehf_driver); | ||
834 | } | ||
835 | |||
836 | static void __exit sensors_w83627ehf_exit(void) | ||
837 | { | ||
838 | i2c_del_driver(&w83627ehf_driver); | ||
839 | } | ||
840 | |||
841 | MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>"); | ||
842 | MODULE_DESCRIPTION("W83627EHF driver"); | ||
843 | MODULE_LICENSE("GPL"); | ||
844 | |||
845 | module_init(sensors_w83627ehf_init); | ||
846 | module_exit(sensors_w83627ehf_exit); | ||
diff --git a/drivers/i2c/chips/w83627hf.c b/drivers/i2c/chips/w83627hf.c index 4f1bff572c1c..bd87a42e068a 100644 --- a/drivers/i2c/chips/w83627hf.c +++ b/drivers/i2c/chips/w83627hf.c | |||
@@ -264,7 +264,7 @@ static inline u8 DIV_TO_REG(long val) | |||
264 | { | 264 | { |
265 | int i; | 265 | int i; |
266 | val = SENSORS_LIMIT(val, 1, 128) >> 1; | 266 | val = SENSORS_LIMIT(val, 1, 128) >> 1; |
267 | for (i = 0; i < 6; i++) { | 267 | for (i = 0; i < 7; i++) { |
268 | if (val == 0) | 268 | if (val == 0) |
269 | break; | 269 | break; |
270 | val >>= 1; | 270 | val >>= 1; |
diff --git a/drivers/i2c/chips/w83781d.c b/drivers/i2c/chips/w83781d.c index c3926d2d8ac6..0bb131ce09eb 100644 --- a/drivers/i2c/chips/w83781d.c +++ b/drivers/i2c/chips/w83781d.c | |||
@@ -28,14 +28,11 @@ | |||
28 | as99127f rev.2 (type_name = as99127f) 0x31 0x5ca3 yes no | 28 | as99127f rev.2 (type_name = as99127f) 0x31 0x5ca3 yes no |
29 | w83781d 7 3 0 3 0x10-1 0x5ca3 yes yes | 29 | w83781d 7 3 0 3 0x10-1 0x5ca3 yes yes |
30 | w83627hf 9 3 2 3 0x21 0x5ca3 yes yes(LPC) | 30 | w83627hf 9 3 2 3 0x21 0x5ca3 yes yes(LPC) |
31 | w83627thf 9 3 2 3 0x90 0x5ca3 no yes(LPC) | ||
32 | w83782d 9 3 2-4 3 0x30 0x5ca3 yes yes | 31 | w83782d 9 3 2-4 3 0x30 0x5ca3 yes yes |
33 | w83783s 5-6 3 2 1-2 0x40 0x5ca3 yes no | 32 | w83783s 5-6 3 2 1-2 0x40 0x5ca3 yes no |
34 | w83697hf 8 2 2 2 0x60 0x5ca3 no yes(LPC) | ||
35 | 33 | ||
36 | */ | 34 | */ |
37 | 35 | ||
38 | #include <linux/config.h> | ||
39 | #include <linux/module.h> | 36 | #include <linux/module.h> |
40 | #include <linux/init.h> | 37 | #include <linux/init.h> |
41 | #include <linux/slab.h> | 38 | #include <linux/slab.h> |
@@ -53,7 +50,7 @@ static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, | |||
53 | static unsigned int normal_isa[] = { 0x0290, I2C_CLIENT_ISA_END }; | 50 | static unsigned int normal_isa[] = { 0x0290, I2C_CLIENT_ISA_END }; |
54 | 51 | ||
55 | /* Insmod parameters */ | 52 | /* Insmod parameters */ |
56 | SENSORS_INSMOD_6(w83781d, w83782d, w83783s, w83627hf, as99127f, w83697hf); | 53 | SENSORS_INSMOD_5(w83781d, w83782d, w83783s, w83627hf, as99127f); |
57 | I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: " | 54 | I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: " |
58 | "{bus, clientaddr, subclientaddr1, subclientaddr2}"); | 55 | "{bus, clientaddr, subclientaddr1, subclientaddr2}"); |
59 | 56 | ||
@@ -173,7 +170,6 @@ FAN_TO_REG(long rpm, int div) | |||
173 | : (val)) / 1000, 0, 0xff)) | 170 | : (val)) / 1000, 0, 0xff)) |
174 | #define TEMP_FROM_REG(val) (((val) & 0x80 ? (val)-0x100 : (val)) * 1000) | 171 | #define TEMP_FROM_REG(val) (((val) & 0x80 ? (val)-0x100 : (val)) * 1000) |
175 | 172 | ||
176 | #define ALARMS_FROM_REG(val) (val) | ||
177 | #define PWM_FROM_REG(val) (val) | 173 | #define PWM_FROM_REG(val) (val) |
178 | #define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255)) | 174 | #define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255)) |
179 | #define BEEP_MASK_FROM_REG(val,type) ((type) == as99127f ? \ | 175 | #define BEEP_MASK_FROM_REG(val,type) ((type) == as99127f ? \ |
@@ -193,7 +189,7 @@ DIV_TO_REG(long val, enum chips type) | |||
193 | val = SENSORS_LIMIT(val, 1, | 189 | val = SENSORS_LIMIT(val, 1, |
194 | ((type == w83781d | 190 | ((type == w83781d |
195 | || type == as99127f) ? 8 : 128)) >> 1; | 191 | || type == as99127f) ? 8 : 128)) >> 1; |
196 | for (i = 0; i < 6; i++) { | 192 | for (i = 0; i < 7; i++) { |
197 | if (val == 0) | 193 | if (val == 0) |
198 | break; | 194 | break; |
199 | val >>= 1; | 195 | val >>= 1; |
@@ -524,7 +520,7 @@ static ssize_t | |||
524 | show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) | 520 | show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) |
525 | { | 521 | { |
526 | struct w83781d_data *data = w83781d_update_device(dev); | 522 | struct w83781d_data *data = w83781d_update_device(dev); |
527 | return sprintf(buf, "%ld\n", (long) ALARMS_FROM_REG(data->alarms)); | 523 | return sprintf(buf, "%u\n", data->alarms); |
528 | } | 524 | } |
529 | 525 | ||
530 | static | 526 | static |
@@ -1000,13 +996,6 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) | |||
1000 | err = -EINVAL; | 996 | err = -EINVAL; |
1001 | goto ERROR0; | 997 | goto ERROR0; |
1002 | } | 998 | } |
1003 | if (!is_isa && kind == w83697hf) { | ||
1004 | dev_err(&adapter->dev, | ||
1005 | "Cannot force ISA-only chip for I2C address 0x%02x.\n", | ||
1006 | address); | ||
1007 | err = -EINVAL; | ||
1008 | goto ERROR0; | ||
1009 | } | ||
1010 | 999 | ||
1011 | if (is_isa) | 1000 | if (is_isa) |
1012 | if (!request_region(address, W83781D_EXTENT, | 1001 | if (!request_region(address, W83781D_EXTENT, |
@@ -1139,12 +1128,10 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) | |||
1139 | else if (val1 == 0x40 && vendid == winbond && !is_isa | 1128 | else if (val1 == 0x40 && vendid == winbond && !is_isa |
1140 | && address == 0x2d) | 1129 | && address == 0x2d) |
1141 | kind = w83783s; | 1130 | kind = w83783s; |
1142 | else if ((val1 == 0x21 || val1 == 0x90) && vendid == winbond) | 1131 | else if (val1 == 0x21 && vendid == winbond) |
1143 | kind = w83627hf; | 1132 | kind = w83627hf; |
1144 | else if (val1 == 0x31 && !is_isa && address >= 0x28) | 1133 | else if (val1 == 0x31 && !is_isa && address >= 0x28) |
1145 | kind = as99127f; | 1134 | kind = as99127f; |
1146 | else if (val1 == 0x60 && vendid == winbond && is_isa) | ||
1147 | kind = w83697hf; | ||
1148 | else { | 1135 | else { |
1149 | if (kind == 0) | 1136 | if (kind == 0) |
1150 | dev_warn(&new_client->dev, "Ignoring 'force' " | 1137 | dev_warn(&new_client->dev, "Ignoring 'force' " |
@@ -1163,14 +1150,9 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) | |||
1163 | } else if (kind == w83783s) { | 1150 | } else if (kind == w83783s) { |
1164 | client_name = "w83783s"; | 1151 | client_name = "w83783s"; |
1165 | } else if (kind == w83627hf) { | 1152 | } else if (kind == w83627hf) { |
1166 | if (val1 == 0x90) | 1153 | client_name = "w83627hf"; |
1167 | client_name = "w83627thf"; | ||
1168 | else | ||
1169 | client_name = "w83627hf"; | ||
1170 | } else if (kind == as99127f) { | 1154 | } else if (kind == as99127f) { |
1171 | client_name = "as99127f"; | 1155 | client_name = "as99127f"; |
1172 | } else if (kind == w83697hf) { | ||
1173 | client_name = "w83697hf"; | ||
1174 | } | 1156 | } |
1175 | 1157 | ||
1176 | /* Fill in the remaining client fields and put into the global list */ | 1158 | /* Fill in the remaining client fields and put into the global list */ |
@@ -1208,7 +1190,7 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) | |||
1208 | 1190 | ||
1209 | /* Register sysfs hooks */ | 1191 | /* Register sysfs hooks */ |
1210 | device_create_file_in(new_client, 0); | 1192 | device_create_file_in(new_client, 0); |
1211 | if (kind != w83783s && kind != w83697hf) | 1193 | if (kind != w83783s) |
1212 | device_create_file_in(new_client, 1); | 1194 | device_create_file_in(new_client, 1); |
1213 | device_create_file_in(new_client, 2); | 1195 | device_create_file_in(new_client, 2); |
1214 | device_create_file_in(new_client, 3); | 1196 | device_create_file_in(new_client, 3); |
@@ -1222,24 +1204,19 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) | |||
1222 | 1204 | ||
1223 | device_create_file_fan(new_client, 1); | 1205 | device_create_file_fan(new_client, 1); |
1224 | device_create_file_fan(new_client, 2); | 1206 | device_create_file_fan(new_client, 2); |
1225 | if (kind != w83697hf) | 1207 | device_create_file_fan(new_client, 3); |
1226 | device_create_file_fan(new_client, 3); | ||
1227 | 1208 | ||
1228 | device_create_file_temp(new_client, 1); | 1209 | device_create_file_temp(new_client, 1); |
1229 | device_create_file_temp(new_client, 2); | 1210 | device_create_file_temp(new_client, 2); |
1230 | if (kind != w83783s && kind != w83697hf) | 1211 | if (kind != w83783s) |
1231 | device_create_file_temp(new_client, 3); | 1212 | device_create_file_temp(new_client, 3); |
1232 | 1213 | ||
1233 | if (kind != w83697hf) | 1214 | device_create_file_vid(new_client); |
1234 | device_create_file_vid(new_client); | 1215 | device_create_file_vrm(new_client); |
1235 | |||
1236 | if (kind != w83697hf) | ||
1237 | device_create_file_vrm(new_client); | ||
1238 | 1216 | ||
1239 | device_create_file_fan_div(new_client, 1); | 1217 | device_create_file_fan_div(new_client, 1); |
1240 | device_create_file_fan_div(new_client, 2); | 1218 | device_create_file_fan_div(new_client, 2); |
1241 | if (kind != w83697hf) | 1219 | device_create_file_fan_div(new_client, 3); |
1242 | device_create_file_fan_div(new_client, 3); | ||
1243 | 1220 | ||
1244 | device_create_file_alarms(new_client); | 1221 | device_create_file_alarms(new_client); |
1245 | 1222 | ||
@@ -1258,7 +1235,7 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) | |||
1258 | if (kind != as99127f && kind != w83781d) { | 1235 | if (kind != as99127f && kind != w83781d) { |
1259 | device_create_file_sensor(new_client, 1); | 1236 | device_create_file_sensor(new_client, 1); |
1260 | device_create_file_sensor(new_client, 2); | 1237 | device_create_file_sensor(new_client, 2); |
1261 | if (kind != w83783s && kind != w83697hf) | 1238 | if (kind != w83783s) |
1262 | device_create_file_sensor(new_client, 3); | 1239 | device_create_file_sensor(new_client, 3); |
1263 | } | 1240 | } |
1264 | 1241 | ||
@@ -1481,7 +1458,7 @@ w83781d_init_client(struct i2c_client *client) | |||
1481 | else | 1458 | else |
1482 | data->sens[i - 1] = 2; | 1459 | data->sens[i - 1] = 2; |
1483 | } | 1460 | } |
1484 | if ((type == w83783s || type == w83697hf) && (i == 2)) | 1461 | if (type == w83783s && i == 2) |
1485 | break; | 1462 | break; |
1486 | } | 1463 | } |
1487 | } | 1464 | } |
@@ -1497,7 +1474,7 @@ w83781d_init_client(struct i2c_client *client) | |||
1497 | } | 1474 | } |
1498 | 1475 | ||
1499 | /* Enable temp3 */ | 1476 | /* Enable temp3 */ |
1500 | if (type != w83783s && type != w83697hf) { | 1477 | if (type != w83783s) { |
1501 | tmp = w83781d_read_value(client, | 1478 | tmp = w83781d_read_value(client, |
1502 | W83781D_REG_TEMP3_CONFIG); | 1479 | W83781D_REG_TEMP3_CONFIG); |
1503 | if (tmp & 0x01) { | 1480 | if (tmp & 0x01) { |
@@ -1538,8 +1515,7 @@ static struct w83781d_data *w83781d_update_device(struct device *dev) | |||
1538 | dev_dbg(dev, "Starting device update\n"); | 1515 | dev_dbg(dev, "Starting device update\n"); |
1539 | 1516 | ||
1540 | for (i = 0; i <= 8; i++) { | 1517 | for (i = 0; i <= 8; i++) { |
1541 | if ((data->type == w83783s || data->type == w83697hf) | 1518 | if (data->type == w83783s && i == 1) |
1542 | && (i == 1)) | ||
1543 | continue; /* 783S has no in1 */ | 1519 | continue; /* 783S has no in1 */ |
1544 | data->in[i] = | 1520 | data->in[i] = |
1545 | w83781d_read_value(client, W83781D_REG_IN(i)); | 1521 | w83781d_read_value(client, W83781D_REG_IN(i)); |
@@ -1547,7 +1523,7 @@ static struct w83781d_data *w83781d_update_device(struct device *dev) | |||
1547 | w83781d_read_value(client, W83781D_REG_IN_MIN(i)); | 1523 | w83781d_read_value(client, W83781D_REG_IN_MIN(i)); |
1548 | data->in_max[i] = | 1524 | data->in_max[i] = |
1549 | w83781d_read_value(client, W83781D_REG_IN_MAX(i)); | 1525 | w83781d_read_value(client, W83781D_REG_IN_MAX(i)); |
1550 | if ((data->type != w83782d) && (data->type != w83697hf) | 1526 | if ((data->type != w83782d) |
1551 | && (data->type != w83627hf) && (i == 6)) | 1527 | && (data->type != w83627hf) && (i == 6)) |
1552 | break; | 1528 | break; |
1553 | } | 1529 | } |
@@ -1583,7 +1559,7 @@ static struct w83781d_data *w83781d_update_device(struct device *dev) | |||
1583 | w83781d_read_value(client, W83781D_REG_TEMP_OVER(2)); | 1559 | w83781d_read_value(client, W83781D_REG_TEMP_OVER(2)); |
1584 | data->temp_max_hyst_add[0] = | 1560 | data->temp_max_hyst_add[0] = |
1585 | w83781d_read_value(client, W83781D_REG_TEMP_HYST(2)); | 1561 | w83781d_read_value(client, W83781D_REG_TEMP_HYST(2)); |
1586 | if (data->type != w83783s && data->type != w83697hf) { | 1562 | if (data->type != w83783s) { |
1587 | data->temp_add[1] = | 1563 | data->temp_add[1] = |
1588 | w83781d_read_value(client, W83781D_REG_TEMP(3)); | 1564 | w83781d_read_value(client, W83781D_REG_TEMP(3)); |
1589 | data->temp_max_add[1] = | 1565 | data->temp_max_add[1] = |
@@ -1594,26 +1570,18 @@ static struct w83781d_data *w83781d_update_device(struct device *dev) | |||
1594 | W83781D_REG_TEMP_HYST(3)); | 1570 | W83781D_REG_TEMP_HYST(3)); |
1595 | } | 1571 | } |
1596 | i = w83781d_read_value(client, W83781D_REG_VID_FANDIV); | 1572 | i = w83781d_read_value(client, W83781D_REG_VID_FANDIV); |
1597 | if (data->type != w83697hf) { | 1573 | data->vid = i & 0x0f; |
1598 | data->vid = i & 0x0f; | 1574 | data->vid |= (w83781d_read_value(client, |
1599 | data->vid |= | 1575 | W83781D_REG_CHIPID) & 0x01) << 4; |
1600 | (w83781d_read_value(client, W83781D_REG_CHIPID) & | ||
1601 | 0x01) | ||
1602 | << 4; | ||
1603 | } | ||
1604 | data->fan_div[0] = (i >> 4) & 0x03; | 1576 | data->fan_div[0] = (i >> 4) & 0x03; |
1605 | data->fan_div[1] = (i >> 6) & 0x03; | 1577 | data->fan_div[1] = (i >> 6) & 0x03; |
1606 | if (data->type != w83697hf) { | 1578 | data->fan_div[2] = (w83781d_read_value(client, |
1607 | data->fan_div[2] = (w83781d_read_value(client, | 1579 | W83781D_REG_PIN) >> 6) & 0x03; |
1608 | W83781D_REG_PIN) | ||
1609 | >> 6) & 0x03; | ||
1610 | } | ||
1611 | if ((data->type != w83781d) && (data->type != as99127f)) { | 1580 | if ((data->type != w83781d) && (data->type != as99127f)) { |
1612 | i = w83781d_read_value(client, W83781D_REG_VBAT); | 1581 | i = w83781d_read_value(client, W83781D_REG_VBAT); |
1613 | data->fan_div[0] |= (i >> 3) & 0x04; | 1582 | data->fan_div[0] |= (i >> 3) & 0x04; |
1614 | data->fan_div[1] |= (i >> 4) & 0x04; | 1583 | data->fan_div[1] |= (i >> 4) & 0x04; |
1615 | if (data->type != w83697hf) | 1584 | data->fan_div[2] |= (i >> 5) & 0x04; |
1616 | data->fan_div[2] |= (i >> 5) & 0x04; | ||
1617 | } | 1585 | } |
1618 | data->alarms = | 1586 | data->alarms = |
1619 | w83781d_read_value(client, | 1587 | w83781d_read_value(client, |
diff --git a/drivers/i2c/chips/w83l785ts.c b/drivers/i2c/chips/w83l785ts.c index 74d4b58e4237..4469d52aba4c 100644 --- a/drivers/i2c/chips/w83l785ts.c +++ b/drivers/i2c/chips/w83l785ts.c | |||
@@ -30,7 +30,6 @@ | |||
30 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 30 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
31 | */ | 31 | */ |
32 | 32 | ||
33 | #include <linux/config.h> | ||
34 | #include <linux/module.h> | 33 | #include <linux/module.h> |
35 | #include <linux/delay.h> | 34 | #include <linux/delay.h> |
36 | #include <linux/init.h> | 35 | #include <linux/init.h> |
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index a22e53badacb..51ce268998cd 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c | |||
@@ -21,7 +21,6 @@ | |||
21 | All SMBus-related things are written by Frodo Looijaard <frodol@dds.nl> | 21 | All SMBus-related things are written by Frodo Looijaard <frodol@dds.nl> |
22 | SMBus 2.0 support by Mark Studebaker <mdsxyz123@yahoo.com> */ | 22 | SMBus 2.0 support by Mark Studebaker <mdsxyz123@yahoo.com> */ |
23 | 23 | ||
24 | #include <linux/config.h> | ||
25 | #include <linux/module.h> | 24 | #include <linux/module.h> |
26 | #include <linux/kernel.h> | 25 | #include <linux/kernel.h> |
27 | #include <linux/errno.h> | 26 | #include <linux/errno.h> |
@@ -239,7 +238,7 @@ int i2c_del_adapter(struct i2c_adapter *adap) | |||
239 | } | 238 | } |
240 | 239 | ||
241 | /* detach any active clients. This must be done first, because | 240 | /* detach any active clients. This must be done first, because |
242 | * it can fail; in which case we give upp. */ | 241 | * it can fail; in which case we give up. */ |
243 | list_for_each_safe(item, _n, &adap->clients) { | 242 | list_for_each_safe(item, _n, &adap->clients) { |
244 | client = list_entry(item, struct i2c_client, list); | 243 | client = list_entry(item, struct i2c_client, list); |
245 | 244 | ||
@@ -612,27 +611,16 @@ int i2c_master_send(struct i2c_client *client,const char *buf ,int count) | |||
612 | struct i2c_adapter *adap=client->adapter; | 611 | struct i2c_adapter *adap=client->adapter; |
613 | struct i2c_msg msg; | 612 | struct i2c_msg msg; |
614 | 613 | ||
615 | if (client->adapter->algo->master_xfer) { | 614 | msg.addr = client->addr; |
616 | msg.addr = client->addr; | 615 | msg.flags = client->flags & I2C_M_TEN; |
617 | msg.flags = client->flags & I2C_M_TEN; | 616 | msg.len = count; |
618 | msg.len = count; | 617 | msg.buf = (char *)buf; |
619 | msg.buf = (char *)buf; | ||
620 | 618 | ||
621 | dev_dbg(&client->adapter->dev, "master_send: writing %d bytes.\n", | 619 | ret = i2c_transfer(adap, &msg, 1); |
622 | count); | ||
623 | |||
624 | down(&adap->bus_lock); | ||
625 | ret = adap->algo->master_xfer(adap,&msg,1); | ||
626 | up(&adap->bus_lock); | ||
627 | 620 | ||
628 | /* if everything went ok (i.e. 1 msg transmitted), return #bytes | 621 | /* If everything went ok (i.e. 1 msg transmitted), return #bytes |
629 | * transmitted, else error code. | 622 | transmitted, else error code. */ |
630 | */ | 623 | return (ret == 1) ? count : ret; |
631 | return (ret == 1 )? count : ret; | ||
632 | } else { | ||
633 | dev_err(&client->adapter->dev, "I2C level transfers not supported\n"); | ||
634 | return -ENOSYS; | ||
635 | } | ||
636 | } | 624 | } |
637 | 625 | ||
638 | int i2c_master_recv(struct i2c_client *client, char *buf ,int count) | 626 | int i2c_master_recv(struct i2c_client *client, char *buf ,int count) |
@@ -640,31 +628,18 @@ int i2c_master_recv(struct i2c_client *client, char *buf ,int count) | |||
640 | struct i2c_adapter *adap=client->adapter; | 628 | struct i2c_adapter *adap=client->adapter; |
641 | struct i2c_msg msg; | 629 | struct i2c_msg msg; |
642 | int ret; | 630 | int ret; |
643 | if (client->adapter->algo->master_xfer) { | 631 | |
644 | msg.addr = client->addr; | 632 | msg.addr = client->addr; |
645 | msg.flags = client->flags & I2C_M_TEN; | 633 | msg.flags = client->flags & I2C_M_TEN; |
646 | msg.flags |= I2C_M_RD; | 634 | msg.flags |= I2C_M_RD; |
647 | msg.len = count; | 635 | msg.len = count; |
648 | msg.buf = buf; | 636 | msg.buf = buf; |
649 | 637 | ||
650 | dev_dbg(&client->adapter->dev, "master_recv: reading %d bytes.\n", | 638 | ret = i2c_transfer(adap, &msg, 1); |
651 | count); | 639 | |
652 | 640 | /* If everything went ok (i.e. 1 msg transmitted), return #bytes | |
653 | down(&adap->bus_lock); | 641 | transmitted, else error code. */ |
654 | ret = adap->algo->master_xfer(adap,&msg,1); | 642 | return (ret == 1) ? count : ret; |
655 | up(&adap->bus_lock); | ||
656 | |||
657 | dev_dbg(&client->adapter->dev, "master_recv: return:%d (count:%d, addr:0x%02x)\n", | ||
658 | ret, count, client->addr); | ||
659 | |||
660 | /* if everything went ok (i.e. 1 msg transmitted), return #bytes | ||
661 | * transmitted, else error code. | ||
662 | */ | ||
663 | return (ret == 1 )? count : ret; | ||
664 | } else { | ||
665 | dev_err(&client->adapter->dev, "I2C level transfers not supported\n"); | ||
666 | return -ENOSYS; | ||
667 | } | ||
668 | } | 643 | } |
669 | 644 | ||
670 | 645 | ||
@@ -742,18 +717,6 @@ int i2c_probe(struct i2c_adapter *adapter, | |||
742 | found = 1; | 717 | found = 1; |
743 | } | 718 | } |
744 | } | 719 | } |
745 | for (i = 0; | ||
746 | !found && (address_data->ignore_range[i] != I2C_CLIENT_END); | ||
747 | i += 3) { | ||
748 | if (((adap_id == address_data->ignore_range[i]) || | ||
749 | ((address_data->ignore_range[i]==ANY_I2C_BUS))) && | ||
750 | (addr >= address_data->ignore_range[i+1]) && | ||
751 | (addr <= address_data->ignore_range[i+2])) { | ||
752 | dev_dbg(&adapter->dev, "found ignore_range parameter for adapter %d, " | ||
753 | "addr %04x\n", adap_id,addr); | ||
754 | found = 1; | ||
755 | } | ||
756 | } | ||
757 | if (found) | 720 | if (found) |
758 | continue; | 721 | continue; |
759 | 722 | ||
@@ -770,17 +733,6 @@ int i2c_probe(struct i2c_adapter *adapter, | |||
770 | } | 733 | } |
771 | 734 | ||
772 | for (i = 0; | 735 | for (i = 0; |
773 | !found && (address_data->normal_i2c_range[i] != I2C_CLIENT_END); | ||
774 | i += 2) { | ||
775 | if ((addr >= address_data->normal_i2c_range[i]) && | ||
776 | (addr <= address_data->normal_i2c_range[i+1])) { | ||
777 | found = 1; | ||
778 | dev_dbg(&adapter->dev, "found normal i2c_range entry for adapter %d, " | ||
779 | "addr %04x\n", adap_id,addr); | ||
780 | } | ||
781 | } | ||
782 | |||
783 | for (i = 0; | ||
784 | !found && (address_data->probe[i] != I2C_CLIENT_END); | 736 | !found && (address_data->probe[i] != I2C_CLIENT_END); |
785 | i += 2) { | 737 | i += 2) { |
786 | if (((adap_id == address_data->probe[i]) || | 738 | if (((adap_id == address_data->probe[i]) || |
@@ -791,18 +743,6 @@ int i2c_probe(struct i2c_adapter *adapter, | |||
791 | "addr %04x\n", adap_id,addr); | 743 | "addr %04x\n", adap_id,addr); |
792 | } | 744 | } |
793 | } | 745 | } |
794 | for (i = 0; | ||
795 | !found && (address_data->probe_range[i] != I2C_CLIENT_END); | ||
796 | i += 3) { | ||
797 | if (((adap_id == address_data->probe_range[i]) || | ||
798 | (address_data->probe_range[i] == ANY_I2C_BUS)) && | ||
799 | (addr >= address_data->probe_range[i+1]) && | ||
800 | (addr <= address_data->probe_range[i+2])) { | ||
801 | found = 1; | ||
802 | dev_dbg(&adapter->dev, "found probe_range parameter for adapter %d, " | ||
803 | "addr %04x\n", adap_id,addr); | ||
804 | } | ||
805 | } | ||
806 | if (!found) | 746 | if (!found) |
807 | continue; | 747 | continue; |
808 | 748 | ||
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index 86c4d0149e82..bc5d557e5dd9 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c | |||
@@ -29,7 +29,6 @@ | |||
29 | /* The devfs code is contributed by Philipp Matthias Hahn | 29 | /* The devfs code is contributed by Philipp Matthias Hahn |
30 | <pmhahn@titan.lahn.de> */ | 30 | <pmhahn@titan.lahn.de> */ |
31 | 31 | ||
32 | #include <linux/config.h> | ||
33 | #include <linux/kernel.h> | 32 | #include <linux/kernel.h> |
34 | #include <linux/module.h> | 33 | #include <linux/module.h> |
35 | #include <linux/fs.h> | 34 | #include <linux/fs.h> |
@@ -214,7 +213,7 @@ static int i2cdev_ioctl(struct inode *inode, struct file *file, | |||
214 | sizeof(rdwr_arg))) | 213 | sizeof(rdwr_arg))) |
215 | return -EFAULT; | 214 | return -EFAULT; |
216 | 215 | ||
217 | /* Put an arbritrary limit on the number of messages that can | 216 | /* Put an arbitrary limit on the number of messages that can |
218 | * be sent at once */ | 217 | * be sent at once */ |
219 | if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS) | 218 | if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS) |
220 | return -EINVAL; | 219 | return -EINVAL; |
diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c index 0bdb47f08c2a..61400f04015e 100644 --- a/drivers/macintosh/therm_windtunnel.c +++ b/drivers/macintosh/therm_windtunnel.c | |||
@@ -51,8 +51,10 @@ | |||
51 | static int do_probe( struct i2c_adapter *adapter, int addr, int kind); | 51 | static int do_probe( struct i2c_adapter *adapter, int addr, int kind); |
52 | 52 | ||
53 | /* scan 0x48-0x4f (DS1775) and 0x2c-2x2f (ADM1030) */ | 53 | /* scan 0x48-0x4f (DS1775) and 0x2c-2x2f (ADM1030) */ |
54 | static unsigned short normal_i2c[] = { 0x49, 0x2c, I2C_CLIENT_END }; | 54 | static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, |
55 | static unsigned short normal_i2c_range[] = { 0x48, 0x4f, 0x2c, 0x2f, I2C_CLIENT_END }; | 55 | 0x4c, 0x4d, 0x4e, 0x4f, |
56 | 0x2c, 0x2d, 0x2e, 0x2f, | ||
57 | I2C_CLIENT_END }; | ||
56 | 58 | ||
57 | I2C_CLIENT_INSMOD; | 59 | I2C_CLIENT_INSMOD; |
58 | 60 | ||
diff --git a/drivers/media/video/adv7170.c b/drivers/media/video/adv7170.c index 80254caa444c..48989eda2400 100644 --- a/drivers/media/video/adv7170.c +++ b/drivers/media/video/adv7170.c | |||
@@ -384,22 +384,14 @@ static unsigned short normal_i2c[] = | |||
384 | I2C_ADV7171 >> 1, (I2C_ADV7171 >> 1) + 1, | 384 | I2C_ADV7171 >> 1, (I2C_ADV7171 >> 1) + 1, |
385 | I2C_CLIENT_END | 385 | I2C_CLIENT_END |
386 | }; | 386 | }; |
387 | static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; | ||
388 | 387 | ||
389 | static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; | 388 | static unsigned short ignore = I2C_CLIENT_END; |
390 | static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; | ||
391 | static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; | ||
392 | static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; | ||
393 | static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; | ||
394 | 389 | ||
395 | static struct i2c_client_address_data addr_data = { | 390 | static struct i2c_client_address_data addr_data = { |
396 | .normal_i2c = normal_i2c, | 391 | .normal_i2c = normal_i2c, |
397 | .normal_i2c_range = normal_i2c_range, | 392 | .probe = &ignore, |
398 | .probe = probe, | 393 | .ignore = &ignore, |
399 | .probe_range = probe_range, | 394 | .force = &ignore, |
400 | .ignore = ignore, | ||
401 | .ignore_range = ignore_range, | ||
402 | .force = force | ||
403 | }; | 395 | }; |
404 | 396 | ||
405 | static struct i2c_driver i2c_driver_adv7170; | 397 | static struct i2c_driver i2c_driver_adv7170; |
diff --git a/drivers/media/video/adv7175.c b/drivers/media/video/adv7175.c index 95d0974b0ab5..f898b6586374 100644 --- a/drivers/media/video/adv7175.c +++ b/drivers/media/video/adv7175.c | |||
@@ -434,22 +434,14 @@ static unsigned short normal_i2c[] = | |||
434 | I2C_ADV7176 >> 1, (I2C_ADV7176 >> 1) + 1, | 434 | I2C_ADV7176 >> 1, (I2C_ADV7176 >> 1) + 1, |
435 | I2C_CLIENT_END | 435 | I2C_CLIENT_END |
436 | }; | 436 | }; |
437 | static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; | ||
438 | 437 | ||
439 | static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; | 438 | static unsigned short ignore = I2C_CLIENT_END; |
440 | static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; | ||
441 | static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; | ||
442 | static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; | ||
443 | static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; | ||
444 | 439 | ||
445 | static struct i2c_client_address_data addr_data = { | 440 | static struct i2c_client_address_data addr_data = { |
446 | .normal_i2c = normal_i2c, | 441 | .normal_i2c = normal_i2c, |
447 | .normal_i2c_range = normal_i2c_range, | 442 | .probe = &ignore, |
448 | .probe = probe, | 443 | .ignore = &ignore, |
449 | .probe_range = probe_range, | 444 | .force = &ignore, |
450 | .ignore = ignore, | ||
451 | .ignore_range = ignore_range, | ||
452 | .force = force | ||
453 | }; | 445 | }; |
454 | 446 | ||
455 | static struct i2c_driver i2c_driver_adv7175; | 447 | static struct i2c_driver i2c_driver_adv7175; |
diff --git a/drivers/media/video/bt819.c b/drivers/media/video/bt819.c index cf0db2554a80..8733588f6db3 100644 --- a/drivers/media/video/bt819.c +++ b/drivers/media/video/bt819.c | |||
@@ -500,22 +500,14 @@ static unsigned short normal_i2c[] = { | |||
500 | I2C_BT819 >> 1, | 500 | I2C_BT819 >> 1, |
501 | I2C_CLIENT_END, | 501 | I2C_CLIENT_END, |
502 | }; | 502 | }; |
503 | static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; | ||
504 | 503 | ||
505 | static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; | 504 | static unsigned short ignore = I2C_CLIENT_END; |
506 | static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; | ||
507 | static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; | ||
508 | static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; | ||
509 | static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; | ||
510 | 505 | ||
511 | static struct i2c_client_address_data addr_data = { | 506 | static struct i2c_client_address_data addr_data = { |
512 | .normal_i2c = normal_i2c, | 507 | .normal_i2c = normal_i2c, |
513 | .normal_i2c_range = normal_i2c_range, | 508 | .probe = &ignore, |
514 | .probe = probe, | 509 | .ignore = &ignore, |
515 | .probe_range = probe_range, | 510 | .force = &ignore, |
516 | .ignore = ignore, | ||
517 | .ignore_range = ignore_range, | ||
518 | .force = force | ||
519 | }; | 511 | }; |
520 | 512 | ||
521 | static struct i2c_driver i2c_driver_bt819; | 513 | static struct i2c_driver i2c_driver_bt819; |
diff --git a/drivers/media/video/bt832.c b/drivers/media/video/bt832.c index efe605a113a1..07f72f64c5f7 100644 --- a/drivers/media/video/bt832.c +++ b/drivers/media/video/bt832.c | |||
@@ -39,8 +39,8 @@ | |||
39 | MODULE_LICENSE("GPL"); | 39 | MODULE_LICENSE("GPL"); |
40 | 40 | ||
41 | /* Addresses to scan */ | 41 | /* Addresses to scan */ |
42 | static unsigned short normal_i2c[] = {I2C_CLIENT_END}; | 42 | static unsigned short normal_i2c[] = { I2C_BT832_ALT1>>1, I2C_BT832_ALT2>>1, |
43 | static unsigned short normal_i2c_range[] = {I2C_BT832_ALT1>>1,I2C_BT832_ALT2>>1,I2C_CLIENT_END}; | 43 | I2C_CLIENT_END }; |
44 | I2C_CLIENT_INSMOD; | 44 | I2C_CLIENT_INSMOD; |
45 | 45 | ||
46 | /* ---------------------------------------------------------------------- */ | 46 | /* ---------------------------------------------------------------------- */ |
diff --git a/drivers/media/video/bt856.c b/drivers/media/video/bt856.c index 72c7eb0f8c24..a5d529ccf3ad 100644 --- a/drivers/media/video/bt856.c +++ b/drivers/media/video/bt856.c | |||
@@ -288,22 +288,14 @@ bt856_command (struct i2c_client *client, | |||
288 | * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' | 288 | * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' |
289 | */ | 289 | */ |
290 | static unsigned short normal_i2c[] = { I2C_BT856 >> 1, I2C_CLIENT_END }; | 290 | static unsigned short normal_i2c[] = { I2C_BT856 >> 1, I2C_CLIENT_END }; |
291 | static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; | ||
292 | 291 | ||
293 | static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; | 292 | static unsigned short ignore = I2C_CLIENT_END; |
294 | static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; | ||
295 | static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; | ||
296 | static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; | ||
297 | static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; | ||
298 | 293 | ||
299 | static struct i2c_client_address_data addr_data = { | 294 | static struct i2c_client_address_data addr_data = { |
300 | .normal_i2c = normal_i2c, | 295 | .normal_i2c = normal_i2c, |
301 | .normal_i2c_range = normal_i2c_range, | 296 | .probe = &ignore, |
302 | .probe = probe, | 297 | .ignore = &ignore, |
303 | .probe_range = probe_range, | 298 | .force = &ignore, |
304 | .ignore = ignore, | ||
305 | .ignore_range = ignore_range, | ||
306 | .force = force | ||
307 | }; | 299 | }; |
308 | 300 | ||
309 | static struct i2c_driver i2c_driver_bt856; | 301 | static struct i2c_driver i2c_driver_bt856; |
diff --git a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c index 7fbb8581a87d..09464d624a6b 100644 --- a/drivers/media/video/msp3400.c +++ b/drivers/media/video/msp3400.c | |||
@@ -147,7 +147,6 @@ static unsigned short normal_i2c[] = { | |||
147 | I2C_MSP3400C_ALT >> 1, | 147 | I2C_MSP3400C_ALT >> 1, |
148 | I2C_CLIENT_END | 148 | I2C_CLIENT_END |
149 | }; | 149 | }; |
150 | static unsigned short normal_i2c_range[] = {I2C_CLIENT_END,I2C_CLIENT_END}; | ||
151 | I2C_CLIENT_INSMOD; | 150 | I2C_CLIENT_INSMOD; |
152 | 151 | ||
153 | /* ----------------------------------------------------------------------- */ | 152 | /* ----------------------------------------------------------------------- */ |
diff --git a/drivers/media/video/saa5246a.c b/drivers/media/video/saa5246a.c index ba69f09cbdd1..b8054da31ffd 100644 --- a/drivers/media/video/saa5246a.c +++ b/drivers/media/video/saa5246a.c | |||
@@ -64,7 +64,6 @@ static struct video_device saa_template; /* Declared near bottom */ | |||
64 | 64 | ||
65 | /* Addresses to scan */ | 65 | /* Addresses to scan */ |
66 | static unsigned short normal_i2c[] = { I2C_ADDRESS, I2C_CLIENT_END }; | 66 | static unsigned short normal_i2c[] = { I2C_ADDRESS, I2C_CLIENT_END }; |
67 | static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; | ||
68 | I2C_CLIENT_INSMOD; | 67 | I2C_CLIENT_INSMOD; |
69 | 68 | ||
70 | static struct i2c_client client_template; | 69 | static struct i2c_client client_template; |
diff --git a/drivers/media/video/saa5249.c b/drivers/media/video/saa5249.c index d74caa139f0a..7ffa2e9a9bf3 100644 --- a/drivers/media/video/saa5249.c +++ b/drivers/media/video/saa5249.c | |||
@@ -132,7 +132,6 @@ static struct video_device saa_template; /* Declared near bottom */ | |||
132 | 132 | ||
133 | /* Addresses to scan */ | 133 | /* Addresses to scan */ |
134 | static unsigned short normal_i2c[] = {34>>1,I2C_CLIENT_END}; | 134 | static unsigned short normal_i2c[] = {34>>1,I2C_CLIENT_END}; |
135 | static unsigned short normal_i2c_range[] = {I2C_CLIENT_END}; | ||
136 | I2C_CLIENT_INSMOD; | 135 | I2C_CLIENT_INSMOD; |
137 | 136 | ||
138 | static struct i2c_client client_template; | 137 | static struct i2c_client client_template; |
diff --git a/drivers/media/video/saa7110.c b/drivers/media/video/saa7110.c index 64273b438530..22d055d8a695 100644 --- a/drivers/media/video/saa7110.c +++ b/drivers/media/video/saa7110.c | |||
@@ -463,22 +463,14 @@ static unsigned short normal_i2c[] = { | |||
463 | (I2C_SAA7110 >> 1) + 1, | 463 | (I2C_SAA7110 >> 1) + 1, |
464 | I2C_CLIENT_END | 464 | I2C_CLIENT_END |
465 | }; | 465 | }; |
466 | static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; | ||
467 | 466 | ||
468 | static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; | 467 | static unsigned short ignore = I2C_CLIENT_END; |
469 | static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; | ||
470 | static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; | ||
471 | static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; | ||
472 | static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; | ||
473 | 468 | ||
474 | static struct i2c_client_address_data addr_data = { | 469 | static struct i2c_client_address_data addr_data = { |
475 | .normal_i2c = normal_i2c, | 470 | .normal_i2c = normal_i2c, |
476 | .normal_i2c_range = normal_i2c_range, | 471 | .probe = &ignore, |
477 | .probe = probe, | 472 | .ignore = &ignore, |
478 | .probe_range = probe_range, | 473 | .force = &ignore, |
479 | .ignore = ignore, | ||
480 | .ignore_range = ignore_range, | ||
481 | .force = force | ||
482 | }; | 474 | }; |
483 | 475 | ||
484 | static struct i2c_driver i2c_driver_saa7110; | 476 | static struct i2c_driver i2c_driver_saa7110; |
diff --git a/drivers/media/video/saa7111.c b/drivers/media/video/saa7111.c index 0a873112ae23..fcd897382fcf 100644 --- a/drivers/media/video/saa7111.c +++ b/drivers/media/video/saa7111.c | |||
@@ -482,22 +482,14 @@ saa7111_command (struct i2c_client *client, | |||
482 | * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' | 482 | * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' |
483 | */ | 483 | */ |
484 | static unsigned short normal_i2c[] = { I2C_SAA7111 >> 1, I2C_CLIENT_END }; | 484 | static unsigned short normal_i2c[] = { I2C_SAA7111 >> 1, I2C_CLIENT_END }; |
485 | static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; | ||
486 | 485 | ||
487 | static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; | 486 | static unsigned short ignore = I2C_CLIENT_END; |
488 | static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; | ||
489 | static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; | ||
490 | static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; | ||
491 | static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; | ||
492 | 487 | ||
493 | static struct i2c_client_address_data addr_data = { | 488 | static struct i2c_client_address_data addr_data = { |
494 | .normal_i2c = normal_i2c, | 489 | .normal_i2c = normal_i2c, |
495 | .normal_i2c_range = normal_i2c_range, | 490 | .probe = &ignore, |
496 | .probe = probe, | 491 | .ignore = &ignore, |
497 | .probe_range = probe_range, | 492 | .force = &ignore, |
498 | .ignore = ignore, | ||
499 | .ignore_range = ignore_range, | ||
500 | .force = force | ||
501 | }; | 493 | }; |
502 | 494 | ||
503 | static struct i2c_driver i2c_driver_saa7111; | 495 | static struct i2c_driver i2c_driver_saa7111; |
diff --git a/drivers/media/video/saa7114.c b/drivers/media/video/saa7114.c index e73023695e58..2ba997f5ef1d 100644 --- a/drivers/media/video/saa7114.c +++ b/drivers/media/video/saa7114.c | |||
@@ -820,22 +820,14 @@ saa7114_command (struct i2c_client *client, | |||
820 | */ | 820 | */ |
821 | static unsigned short normal_i2c[] = | 821 | static unsigned short normal_i2c[] = |
822 | { I2C_SAA7114 >> 1, I2C_SAA7114A >> 1, I2C_CLIENT_END }; | 822 | { I2C_SAA7114 >> 1, I2C_SAA7114A >> 1, I2C_CLIENT_END }; |
823 | static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; | ||
824 | 823 | ||
825 | static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; | 824 | static unsigned short ignore = I2C_CLIENT_END; |
826 | static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; | ||
827 | static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; | ||
828 | static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; | ||
829 | static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; | ||
830 | 825 | ||
831 | static struct i2c_client_address_data addr_data = { | 826 | static struct i2c_client_address_data addr_data = { |
832 | .normal_i2c = normal_i2c, | 827 | .normal_i2c = normal_i2c, |
833 | .normal_i2c_range = normal_i2c_range, | 828 | .probe = &ignore, |
834 | .probe = probe, | 829 | .ignore = &ignore, |
835 | .probe_range = probe_range, | 830 | .force = &ignore, |
836 | .ignore = ignore, | ||
837 | .ignore_range = ignore_range, | ||
838 | .force = force | ||
839 | }; | 831 | }; |
840 | 832 | ||
841 | static struct i2c_driver i2c_driver_saa7114; | 833 | static struct i2c_driver i2c_driver_saa7114; |
diff --git a/drivers/media/video/saa7134/saa6752hs.c b/drivers/media/video/saa7134/saa6752hs.c index 1db022682980..42c2b565c9fe 100644 --- a/drivers/media/video/saa7134/saa6752hs.c +++ b/drivers/media/video/saa7134/saa6752hs.c | |||
@@ -22,7 +22,6 @@ | |||
22 | 22 | ||
23 | /* Addresses to scan */ | 23 | /* Addresses to scan */ |
24 | static unsigned short normal_i2c[] = {0x20, I2C_CLIENT_END}; | 24 | static unsigned short normal_i2c[] = {0x20, I2C_CLIENT_END}; |
25 | static unsigned short normal_i2c_range[] = {I2C_CLIENT_END}; | ||
26 | I2C_CLIENT_INSMOD; | 25 | I2C_CLIENT_INSMOD; |
27 | 26 | ||
28 | MODULE_DESCRIPTION("device driver for saa6752hs MPEG2 encoder"); | 27 | MODULE_DESCRIPTION("device driver for saa6752hs MPEG2 encoder"); |
diff --git a/drivers/media/video/saa7185.c b/drivers/media/video/saa7185.c index 5f0b224c3cb6..108e7a4a0273 100644 --- a/drivers/media/video/saa7185.c +++ b/drivers/media/video/saa7185.c | |||
@@ -380,22 +380,14 @@ saa7185_command (struct i2c_client *client, | |||
380 | * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' | 380 | * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' |
381 | */ | 381 | */ |
382 | static unsigned short normal_i2c[] = { I2C_SAA7185 >> 1, I2C_CLIENT_END }; | 382 | static unsigned short normal_i2c[] = { I2C_SAA7185 >> 1, I2C_CLIENT_END }; |
383 | static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; | ||
384 | 383 | ||
385 | static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; | 384 | static unsigned short ignore = I2C_CLIENT_END; |
386 | static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; | ||
387 | static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; | ||
388 | static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; | ||
389 | static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; | ||
390 | 385 | ||
391 | static struct i2c_client_address_data addr_data = { | 386 | static struct i2c_client_address_data addr_data = { |
392 | .normal_i2c = normal_i2c, | 387 | .normal_i2c = normal_i2c, |
393 | .normal_i2c_range = normal_i2c_range, | 388 | .probe = &ignore, |
394 | .probe = probe, | 389 | .ignore = &ignore, |
395 | .probe_range = probe_range, | 390 | .force = &ignore, |
396 | .ignore = ignore, | ||
397 | .ignore_range = ignore_range, | ||
398 | .force = force | ||
399 | }; | 391 | }; |
400 | 392 | ||
401 | static struct i2c_driver i2c_driver_saa7185; | 393 | static struct i2c_driver i2c_driver_saa7185; |
diff --git a/drivers/media/video/tda7432.c b/drivers/media/video/tda7432.c index 376a4a439e9b..07ba6d3ed08c 100644 --- a/drivers/media/video/tda7432.c +++ b/drivers/media/video/tda7432.c | |||
@@ -74,7 +74,6 @@ static unsigned short normal_i2c[] = { | |||
74 | I2C_TDA7432 >> 1, | 74 | I2C_TDA7432 >> 1, |
75 | I2C_CLIENT_END, | 75 | I2C_CLIENT_END, |
76 | }; | 76 | }; |
77 | static unsigned short normal_i2c_range[] = { I2C_CLIENT_END, I2C_CLIENT_END }; | ||
78 | I2C_CLIENT_INSMOD; | 77 | I2C_CLIENT_INSMOD; |
79 | 78 | ||
80 | /* Structure of address and subaddresses for the tda7432 */ | 79 | /* Structure of address and subaddresses for the tda7432 */ |
diff --git a/drivers/media/video/tda9840.c b/drivers/media/video/tda9840.c index b5177c6f54f6..c29bdfc3244e 100644 --- a/drivers/media/video/tda9840.c +++ b/drivers/media/video/tda9840.c | |||
@@ -43,7 +43,6 @@ MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off)."); | |||
43 | 43 | ||
44 | /* addresses to scan, found only at 0x42 (7-Bit) */ | 44 | /* addresses to scan, found only at 0x42 (7-Bit) */ |
45 | static unsigned short normal_i2c[] = { I2C_TDA9840, I2C_CLIENT_END }; | 45 | static unsigned short normal_i2c[] = { I2C_TDA9840, I2C_CLIENT_END }; |
46 | static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; | ||
47 | 46 | ||
48 | /* magic definition of all other variables and things */ | 47 | /* magic definition of all other variables and things */ |
49 | I2C_CLIENT_INSMOD; | 48 | I2C_CLIENT_INSMOD; |
diff --git a/drivers/media/video/tda9875.c b/drivers/media/video/tda9875.c index 4f1114c033a1..97b113e070f3 100644 --- a/drivers/media/video/tda9875.c +++ b/drivers/media/video/tda9875.c | |||
@@ -44,7 +44,6 @@ static unsigned short normal_i2c[] = { | |||
44 | I2C_TDA9875 >> 1, | 44 | I2C_TDA9875 >> 1, |
45 | I2C_CLIENT_END | 45 | I2C_CLIENT_END |
46 | }; | 46 | }; |
47 | static unsigned short normal_i2c_range[] = {I2C_CLIENT_END}; | ||
48 | I2C_CLIENT_INSMOD; | 47 | I2C_CLIENT_INSMOD; |
49 | 48 | ||
50 | /* This is a superset of the TDA9875 */ | 49 | /* This is a superset of the TDA9875 */ |
diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index debef1910c37..7e6e6dd966a2 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c | |||
@@ -33,7 +33,6 @@ static unsigned short normal_i2c[] = { | |||
33 | 0x96 >>1, | 33 | 0x96 >>1, |
34 | I2C_CLIENT_END, | 34 | I2C_CLIENT_END, |
35 | }; | 35 | }; |
36 | static unsigned short normal_i2c_range[] = {I2C_CLIENT_END,I2C_CLIENT_END}; | ||
37 | I2C_CLIENT_INSMOD; | 36 | I2C_CLIENT_INSMOD; |
38 | 37 | ||
39 | /* insmod options */ | 38 | /* insmod options */ |
diff --git a/drivers/media/video/tea6415c.c b/drivers/media/video/tea6415c.c index 3ec39550bf46..b44db8a7b94d 100644 --- a/drivers/media/video/tea6415c.c +++ b/drivers/media/video/tea6415c.c | |||
@@ -43,7 +43,6 @@ MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off)."); | |||
43 | 43 | ||
44 | /* addresses to scan, found only at 0x03 and/or 0x43 (7-bit) */ | 44 | /* addresses to scan, found only at 0x03 and/or 0x43 (7-bit) */ |
45 | static unsigned short normal_i2c[] = { I2C_TEA6415C_1, I2C_TEA6415C_2, I2C_CLIENT_END }; | 45 | static unsigned short normal_i2c[] = { I2C_TEA6415C_1, I2C_TEA6415C_2, I2C_CLIENT_END }; |
46 | static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; | ||
47 | 46 | ||
48 | /* magic definition of all other variables and things */ | 47 | /* magic definition of all other variables and things */ |
49 | I2C_CLIENT_INSMOD; | 48 | I2C_CLIENT_INSMOD; |
diff --git a/drivers/media/video/tea6420.c b/drivers/media/video/tea6420.c index bd10710fd909..48d4db7d507b 100644 --- a/drivers/media/video/tea6420.c +++ b/drivers/media/video/tea6420.c | |||
@@ -40,7 +40,6 @@ MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off)."); | |||
40 | 40 | ||
41 | /* addresses to scan, found only at 0x4c and/or 0x4d (7-Bit) */ | 41 | /* addresses to scan, found only at 0x4c and/or 0x4d (7-Bit) */ |
42 | static unsigned short normal_i2c[] = { I2C_TEA6420_1, I2C_TEA6420_2, I2C_CLIENT_END }; | 42 | static unsigned short normal_i2c[] = { I2C_TEA6420_1, I2C_TEA6420_2, I2C_CLIENT_END }; |
43 | static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; | ||
44 | 43 | ||
45 | /* magic definition of all other variables and things */ | 44 | /* magic definition of all other variables and things */ |
46 | I2C_CLIENT_INSMOD; | 45 | I2C_CLIENT_INSMOD; |
diff --git a/drivers/media/video/tuner-3036.c b/drivers/media/video/tuner-3036.c index 6b20aa902a8f..51748c6578d1 100644 --- a/drivers/media/video/tuner-3036.c +++ b/drivers/media/video/tuner-3036.c | |||
@@ -34,19 +34,14 @@ static int this_adap; | |||
34 | static struct i2c_client client_template; | 34 | static struct i2c_client client_template; |
35 | 35 | ||
36 | /* Addresses to scan */ | 36 | /* Addresses to scan */ |
37 | static unsigned short normal_i2c[] = {I2C_CLIENT_END}; | 37 | static unsigned short normal_i2c[] = { 0x60, 0x61, I2C_CLIENT_END }; |
38 | static unsigned short normal_i2c_range[] = {0x60, 0x61, I2C_CLIENT_END}; | 38 | static unsigned short ignore = I2C_CLIENT_END; |
39 | static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; | ||
40 | static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; | ||
41 | static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; | ||
42 | static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; | ||
43 | static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; | ||
44 | 39 | ||
45 | static struct i2c_client_address_data addr_data = { | 40 | static struct i2c_client_address_data addr_data = { |
46 | normal_i2c, normal_i2c_range, | 41 | .normal_i2c = normal_i2c, |
47 | probe, probe_range, | 42 | .probe = &ignore, |
48 | ignore, ignore_range, | 43 | .ignore = &ignore, |
49 | force | 44 | .force = &ignore, |
50 | }; | 45 | }; |
51 | 46 | ||
52 | /* ---------------------------------------------------------------------- */ | 47 | /* ---------------------------------------------------------------------- */ |
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 6212388edb75..81882ddab859 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c | |||
@@ -28,10 +28,8 @@ | |||
28 | /* standard i2c insmod options */ | 28 | /* standard i2c insmod options */ |
29 | static unsigned short normal_i2c[] = { | 29 | static unsigned short normal_i2c[] = { |
30 | 0x4b, /* tda8290 */ | 30 | 0x4b, /* tda8290 */ |
31 | I2C_CLIENT_END | 31 | 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, |
32 | }; | 32 | 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, |
33 | static unsigned short normal_i2c_range[] = { | ||
34 | 0x60, 0x6f, | ||
35 | I2C_CLIENT_END | 33 | I2C_CLIENT_END |
36 | }; | 34 | }; |
37 | I2C_CLIENT_INSMOD; | 35 | I2C_CLIENT_INSMOD; |
@@ -225,9 +223,8 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) | |||
225 | static int tuner_probe(struct i2c_adapter *adap) | 223 | static int tuner_probe(struct i2c_adapter *adap) |
226 | { | 224 | { |
227 | if (0 != addr) { | 225 | if (0 != addr) { |
228 | normal_i2c[0] = addr; | 226 | normal_i2c[0] = addr; |
229 | normal_i2c_range[0] = addr; | 227 | normal_i2c[1] = I2C_CLIENT_END; |
230 | normal_i2c_range[1] = addr; | ||
231 | } | 228 | } |
232 | this_adap = 0; | 229 | this_adap = 0; |
233 | 230 | ||
diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c index 80dc34f18c2c..41b635e0d3c6 100644 --- a/drivers/media/video/tvaudio.c +++ b/drivers/media/video/tvaudio.c | |||
@@ -148,7 +148,6 @@ static unsigned short normal_i2c[] = { | |||
148 | I2C_TDA9874 >> 1, | 148 | I2C_TDA9874 >> 1, |
149 | I2C_PIC16C54 >> 1, | 149 | I2C_PIC16C54 >> 1, |
150 | I2C_CLIENT_END }; | 150 | I2C_CLIENT_END }; |
151 | static unsigned short normal_i2c_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; | ||
152 | I2C_CLIENT_INSMOD; | 151 | I2C_CLIENT_INSMOD; |
153 | 152 | ||
154 | static struct i2c_driver driver; | 153 | static struct i2c_driver driver; |
diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c index e1443a0937e3..3d216973798c 100644 --- a/drivers/media/video/tveeprom.c +++ b/drivers/media/video/tveeprom.c | |||
@@ -482,7 +482,6 @@ static unsigned short normal_i2c[] = { | |||
482 | 0xa0 >> 1, | 482 | 0xa0 >> 1, |
483 | I2C_CLIENT_END, | 483 | I2C_CLIENT_END, |
484 | }; | 484 | }; |
485 | static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; | ||
486 | I2C_CLIENT_INSMOD; | 485 | I2C_CLIENT_INSMOD; |
487 | 486 | ||
488 | struct i2c_driver i2c_driver_tveeprom; | 487 | struct i2c_driver i2c_driver_tveeprom; |
diff --git a/drivers/media/video/vpx3220.c b/drivers/media/video/vpx3220.c index 0fd6c9a70917..5dbd9f6bf353 100644 --- a/drivers/media/video/vpx3220.c +++ b/drivers/media/video/vpx3220.c | |||
@@ -569,22 +569,14 @@ static unsigned short normal_i2c[] = | |||
569 | { I2C_VPX3220 >> 1, (I2C_VPX3220 >> 1) + 4, | 569 | { I2C_VPX3220 >> 1, (I2C_VPX3220 >> 1) + 4, |
570 | I2C_CLIENT_END | 570 | I2C_CLIENT_END |
571 | }; | 571 | }; |
572 | static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; | ||
573 | 572 | ||
574 | static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; | 573 | static unsigned short ignore = I2C_CLIENT_END; |
575 | static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; | ||
576 | static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; | ||
577 | static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; | ||
578 | static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; | ||
579 | 574 | ||
580 | static struct i2c_client_address_data addr_data = { | 575 | static struct i2c_client_address_data addr_data = { |
581 | .normal_i2c = normal_i2c, | 576 | .normal_i2c = normal_i2c, |
582 | .normal_i2c_range = normal_i2c_range, | 577 | .probe = &ignore, |
583 | .probe = probe, | 578 | .ignore = &ignore, |
584 | .probe_range = probe_range, | 579 | .force = &ignore, |
585 | .ignore = ignore, | ||
586 | .ignore_range = ignore_range, | ||
587 | .force = force | ||
588 | }; | 580 | }; |
589 | 581 | ||
590 | static struct i2c_driver vpx3220_i2c_driver; | 582 | static struct i2c_driver vpx3220_i2c_driver; |
diff --git a/drivers/video/matrox/matroxfb_maven.c b/drivers/video/matrox/matroxfb_maven.c index e529841cd83d..67f85344f0cc 100644 --- a/drivers/video/matrox/matroxfb_maven.c +++ b/drivers/video/matrox/matroxfb_maven.c | |||
@@ -1230,7 +1230,6 @@ static int maven_shutdown_client(struct i2c_client* clnt) { | |||
1230 | } | 1230 | } |
1231 | 1231 | ||
1232 | static unsigned short normal_i2c[] = { MAVEN_I2CID, I2C_CLIENT_END }; | 1232 | static unsigned short normal_i2c[] = { MAVEN_I2CID, I2C_CLIENT_END }; |
1233 | static unsigned short normal_i2c_range[] = { MAVEN_I2CID, MAVEN_I2CID, I2C_CLIENT_END }; | ||
1234 | I2C_CLIENT_INSMOD; | 1233 | I2C_CLIENT_INSMOD; |
1235 | 1234 | ||
1236 | static struct i2c_driver maven_driver; | 1235 | static struct i2c_driver maven_driver; |
diff --git a/drivers/w1/Kconfig b/drivers/w1/Kconfig index 2ab65c902fe5..4f120796273e 100644 --- a/drivers/w1/Kconfig +++ b/drivers/w1/Kconfig | |||
@@ -3,9 +3,9 @@ menu "Dallas's 1-wire bus" | |||
3 | config W1 | 3 | config W1 |
4 | tristate "Dallas's 1-wire support" | 4 | tristate "Dallas's 1-wire support" |
5 | ---help--- | 5 | ---help--- |
6 | Dallas's 1-wire bus is usefull to connect slow 1-pin devices | 6 | Dallas's 1-wire bus is usefull to connect slow 1-pin devices |
7 | such as iButtons and thermal sensors. | 7 | such as iButtons and thermal sensors. |
8 | 8 | ||
9 | If you want W1 support, you should say Y here. | 9 | If you want W1 support, you should say Y here. |
10 | 10 | ||
11 | This W1 support can also be built as a module. If so, the module | 11 | This W1 support can also be built as a module. If so, the module |
@@ -17,8 +17,8 @@ config W1_MATROX | |||
17 | help | 17 | help |
18 | Say Y here if you want to communicate with your 1-wire devices | 18 | Say Y here if you want to communicate with your 1-wire devices |
19 | using Matrox's G400 GPIO pins. | 19 | using Matrox's G400 GPIO pins. |
20 | 20 | ||
21 | This support is also available as a module. If so, the module | 21 | This support is also available as a module. If so, the module |
22 | will be called matrox_w1.ko. | 22 | will be called matrox_w1.ko. |
23 | 23 | ||
24 | config W1_DS9490 | 24 | config W1_DS9490 |
@@ -27,17 +27,17 @@ config W1_DS9490 | |||
27 | help | 27 | help |
28 | Say Y here if you want to have a driver for DS9490R UWB <-> W1 bridge. | 28 | Say Y here if you want to have a driver for DS9490R UWB <-> W1 bridge. |
29 | 29 | ||
30 | This support is also available as a module. If so, the module | 30 | This support is also available as a module. If so, the module |
31 | will be called ds9490r.ko. | 31 | will be called ds9490r.ko. |
32 | 32 | ||
33 | config W1_DS9490_BRIDGE | 33 | config W1_DS9490R_BRIDGE |
34 | tristate "DS9490R USB <-> W1 transport layer for 1-wire" | 34 | tristate "DS9490R USB <-> W1 transport layer for 1-wire" |
35 | depends on W1_DS9490 | 35 | depends on W1_DS9490 |
36 | help | 36 | help |
37 | Say Y here if you want to communicate with your 1-wire devices | 37 | Say Y here if you want to communicate with your 1-wire devices |
38 | using DS9490R USB bridge. | 38 | using DS9490R USB bridge. |
39 | 39 | ||
40 | This support is also available as a module. If so, the module | 40 | This support is also available as a module. If so, the module |
41 | will be called ds_w1_bridge.ko. | 41 | will be called ds_w1_bridge.ko. |
42 | 42 | ||
43 | config W1_THERM | 43 | config W1_THERM |
@@ -51,7 +51,7 @@ config W1_SMEM | |||
51 | tristate "Simple 64bit memory family implementation" | 51 | tristate "Simple 64bit memory family implementation" |
52 | depends on W1 | 52 | depends on W1 |
53 | help | 53 | help |
54 | Say Y here if you want to connect 1-wire | 54 | Say Y here if you want to connect 1-wire |
55 | simple 64bit memory rom(ds2401/ds2411/ds1990*) to you wire. | 55 | simple 64bit memory rom(ds2401/ds2411/ds1990*) to you wire. |
56 | 56 | ||
57 | endmenu | 57 | endmenu |
diff --git a/drivers/w1/ds_w1_bridge.c b/drivers/w1/ds_w1_bridge.c index 0baaeb5fd630..7bddd8ac7d7f 100644 --- a/drivers/w1/ds_w1_bridge.c +++ b/drivers/w1/ds_w1_bridge.c | |||
@@ -83,11 +83,11 @@ static u8 ds9490r_read_byte(unsigned long data) | |||
83 | return byte; | 83 | return byte; |
84 | } | 84 | } |
85 | 85 | ||
86 | static void ds9490r_write_block(unsigned long data, u8 *buf, int len) | 86 | static void ds9490r_write_block(unsigned long data, const u8 *buf, int len) |
87 | { | 87 | { |
88 | struct ds_device *dev = (struct ds_device *)data; | 88 | struct ds_device *dev = (struct ds_device *)data; |
89 | 89 | ||
90 | ds_write_block(dev, buf, len); | 90 | ds_write_block(dev, (u8 *)buf, len); |
91 | } | 91 | } |
92 | 92 | ||
93 | static u8 ds9490r_read_block(unsigned long data, u8 *buf, int len) | 93 | static u8 ds9490r_read_block(unsigned long data, u8 *buf, int len) |
diff --git a/drivers/w1/matrox_w1.c b/drivers/w1/matrox_w1.c index e565416458ea..0b03f8f93f63 100644 --- a/drivers/w1/matrox_w1.c +++ b/drivers/w1/matrox_w1.c | |||
@@ -1,8 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * matrox_w1.c | 2 | * matrox_w1.c |
3 | * | 3 | * |
4 | * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru> | 4 | * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru> |
5 | * | 5 | * |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by | 8 | * it under the terms of the GNU General Public License as published by |
@@ -59,7 +59,7 @@ static struct pci_driver matrox_w1_pci_driver = { | |||
59 | .remove = __devexit_p(matrox_w1_remove), | 59 | .remove = __devexit_p(matrox_w1_remove), |
60 | }; | 60 | }; |
61 | 61 | ||
62 | /* | 62 | /* |
63 | * Matrox G400 DDC registers. | 63 | * Matrox G400 DDC registers. |
64 | */ | 64 | */ |
65 | 65 | ||
@@ -177,8 +177,8 @@ static int __devinit matrox_w1_probe(struct pci_dev *pdev, const struct pci_devi | |||
177 | 177 | ||
178 | dev->bus_master = (struct w1_bus_master *)(dev + 1); | 178 | dev->bus_master = (struct w1_bus_master *)(dev + 1); |
179 | 179 | ||
180 | /* | 180 | /* |
181 | * True for G400, for some other we need resource 0, see drivers/video/matrox/matroxfb_base.c | 181 | * True for G400, for some other we need resource 0, see drivers/video/matrox/matroxfb_base.c |
182 | */ | 182 | */ |
183 | 183 | ||
184 | dev->phys_addr = pci_resource_start(pdev, 1); | 184 | dev->phys_addr = pci_resource_start(pdev, 1); |
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index 24a192e3b8b4..b460927ec32a 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c | |||
@@ -1,8 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * w1.c | 2 | * w1.c |
3 | * | 3 | * |
4 | * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru> | 4 | * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru> |
5 | * | 5 | * |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by | 8 | * it under the terms of the GNU General Public License as published by |
@@ -59,6 +59,19 @@ static pid_t control_thread; | |||
59 | static int control_needs_exit; | 59 | static int control_needs_exit; |
60 | static DECLARE_COMPLETION(w1_control_complete); | 60 | static DECLARE_COMPLETION(w1_control_complete); |
61 | 61 | ||
62 | /* stuff for the default family */ | ||
63 | static ssize_t w1_famdefault_read_name(struct device *dev, struct device_attribute *attr, char *buf) | ||
64 | { | ||
65 | struct w1_slave *sl = container_of(dev, struct w1_slave, dev); | ||
66 | return(sprintf(buf, "%s\n", sl->name)); | ||
67 | } | ||
68 | static struct w1_family_ops w1_default_fops = { | ||
69 | .rname = &w1_famdefault_read_name, | ||
70 | }; | ||
71 | static struct w1_family w1_default_family = { | ||
72 | .fops = &w1_default_fops, | ||
73 | }; | ||
74 | |||
62 | static int w1_master_match(struct device *dev, struct device_driver *drv) | 75 | static int w1_master_match(struct device *dev, struct device_driver *drv) |
63 | { | 76 | { |
64 | return 1; | 77 | return 1; |
@@ -99,6 +112,20 @@ static ssize_t w1_default_read_bin(struct kobject *kobj, char *buf, loff_t off, | |||
99 | return sprintf(buf, "No family registered.\n"); | 112 | return sprintf(buf, "No family registered.\n"); |
100 | } | 113 | } |
101 | 114 | ||
115 | static struct device_attribute w1_slave_attribute = | ||
116 | __ATTR(name, S_IRUGO, w1_default_read_name, NULL); | ||
117 | |||
118 | static struct bin_attribute w1_slave_bin_attribute = { | ||
119 | .attr = { | ||
120 | .name = "w1_slave", | ||
121 | .mode = S_IRUGO, | ||
122 | .owner = THIS_MODULE, | ||
123 | }, | ||
124 | .size = W1_SLAVE_DATA_SIZE, | ||
125 | .read = &w1_default_read_bin, | ||
126 | }; | ||
127 | |||
128 | |||
102 | static struct bus_type w1_bus_type = { | 129 | static struct bus_type w1_bus_type = { |
103 | .name = "w1", | 130 | .name = "w1", |
104 | .match = w1_master_match, | 131 | .match = w1_master_match, |
@@ -119,34 +146,49 @@ struct device w1_device = { | |||
119 | .release = &w1_master_release | 146 | .release = &w1_master_release |
120 | }; | 147 | }; |
121 | 148 | ||
122 | static struct device_attribute w1_slave_attribute = { | ||
123 | .attr = { | ||
124 | .name = "name", | ||
125 | .mode = S_IRUGO, | ||
126 | .owner = THIS_MODULE | ||
127 | }, | ||
128 | .show = &w1_default_read_name, | ||
129 | }; | ||
130 | |||
131 | static struct device_attribute w1_slave_attribute_val = { | ||
132 | .attr = { | ||
133 | .name = "value", | ||
134 | .mode = S_IRUGO, | ||
135 | .owner = THIS_MODULE | ||
136 | }, | ||
137 | .show = &w1_default_read_name, | ||
138 | }; | ||
139 | |||
140 | static ssize_t w1_master_attribute_show_name(struct device *dev, struct device_attribute *attr, char *buf) | 149 | static ssize_t w1_master_attribute_show_name(struct device *dev, struct device_attribute *attr, char *buf) |
141 | { | 150 | { |
142 | struct w1_master *md = container_of (dev, struct w1_master, dev); | 151 | struct w1_master *md = container_of(dev, struct w1_master, dev); |
143 | ssize_t count; | 152 | ssize_t count; |
144 | 153 | ||
145 | if (down_interruptible (&md->mutex)) | 154 | if (down_interruptible (&md->mutex)) |
146 | return -EBUSY; | 155 | return -EBUSY; |
147 | 156 | ||
148 | count = sprintf(buf, "%s\n", md->name); | 157 | count = sprintf(buf, "%s\n", md->name); |
149 | 158 | ||
159 | up(&md->mutex); | ||
160 | |||
161 | return count; | ||
162 | } | ||
163 | |||
164 | static ssize_t w1_master_attribute_store_search(struct device * dev, | ||
165 | struct device_attribute *attr, | ||
166 | const char * buf, size_t count) | ||
167 | { | ||
168 | struct w1_master *md = container_of(dev, struct w1_master, dev); | ||
169 | |||
170 | if (down_interruptible (&md->mutex)) | ||
171 | return -EBUSY; | ||
172 | |||
173 | md->search_count = simple_strtol(buf, NULL, 0); | ||
174 | |||
175 | up(&md->mutex); | ||
176 | |||
177 | return count; | ||
178 | } | ||
179 | |||
180 | static ssize_t w1_master_attribute_show_search(struct device *dev, | ||
181 | struct device_attribute *attr, | ||
182 | char *buf) | ||
183 | { | ||
184 | struct w1_master *md = container_of(dev, struct w1_master, dev); | ||
185 | ssize_t count; | ||
186 | |||
187 | if (down_interruptible (&md->mutex)) | ||
188 | return -EBUSY; | ||
189 | |||
190 | count = sprintf(buf, "%d\n", md->search_count); | ||
191 | |||
150 | up(&md->mutex); | 192 | up(&md->mutex); |
151 | 193 | ||
152 | return count; | 194 | return count; |
@@ -156,12 +198,12 @@ static ssize_t w1_master_attribute_show_pointer(struct device *dev, struct devic | |||
156 | { | 198 | { |
157 | struct w1_master *md = container_of(dev, struct w1_master, dev); | 199 | struct w1_master *md = container_of(dev, struct w1_master, dev); |
158 | ssize_t count; | 200 | ssize_t count; |
159 | 201 | ||
160 | if (down_interruptible(&md->mutex)) | 202 | if (down_interruptible(&md->mutex)) |
161 | return -EBUSY; | 203 | return -EBUSY; |
162 | 204 | ||
163 | count = sprintf(buf, "0x%p\n", md->bus_master); | 205 | count = sprintf(buf, "0x%p\n", md->bus_master); |
164 | 206 | ||
165 | up(&md->mutex); | 207 | up(&md->mutex); |
166 | return count; | 208 | return count; |
167 | } | 209 | } |
@@ -177,12 +219,12 @@ static ssize_t w1_master_attribute_show_max_slave_count(struct device *dev, stru | |||
177 | { | 219 | { |
178 | struct w1_master *md = container_of(dev, struct w1_master, dev); | 220 | struct w1_master *md = container_of(dev, struct w1_master, dev); |
179 | ssize_t count; | 221 | ssize_t count; |
180 | 222 | ||
181 | if (down_interruptible(&md->mutex)) | 223 | if (down_interruptible(&md->mutex)) |
182 | return -EBUSY; | 224 | return -EBUSY; |
183 | 225 | ||
184 | count = sprintf(buf, "%d\n", md->max_slave_count); | 226 | count = sprintf(buf, "%d\n", md->max_slave_count); |
185 | 227 | ||
186 | up(&md->mutex); | 228 | up(&md->mutex); |
187 | return count; | 229 | return count; |
188 | } | 230 | } |
@@ -191,12 +233,12 @@ static ssize_t w1_master_attribute_show_attempts(struct device *dev, struct devi | |||
191 | { | 233 | { |
192 | struct w1_master *md = container_of(dev, struct w1_master, dev); | 234 | struct w1_master *md = container_of(dev, struct w1_master, dev); |
193 | ssize_t count; | 235 | ssize_t count; |
194 | 236 | ||
195 | if (down_interruptible(&md->mutex)) | 237 | if (down_interruptible(&md->mutex)) |
196 | return -EBUSY; | 238 | return -EBUSY; |
197 | 239 | ||
198 | count = sprintf(buf, "%lu\n", md->attempts); | 240 | count = sprintf(buf, "%lu\n", md->attempts); |
199 | 241 | ||
200 | up(&md->mutex); | 242 | up(&md->mutex); |
201 | return count; | 243 | return count; |
202 | } | 244 | } |
@@ -205,18 +247,17 @@ static ssize_t w1_master_attribute_show_slave_count(struct device *dev, struct d | |||
205 | { | 247 | { |
206 | struct w1_master *md = container_of(dev, struct w1_master, dev); | 248 | struct w1_master *md = container_of(dev, struct w1_master, dev); |
207 | ssize_t count; | 249 | ssize_t count; |
208 | 250 | ||
209 | if (down_interruptible(&md->mutex)) | 251 | if (down_interruptible(&md->mutex)) |
210 | return -EBUSY; | 252 | return -EBUSY; |
211 | 253 | ||
212 | count = sprintf(buf, "%d\n", md->slave_count); | 254 | count = sprintf(buf, "%d\n", md->slave_count); |
213 | 255 | ||
214 | up(&md->mutex); | 256 | up(&md->mutex); |
215 | return count; | 257 | return count; |
216 | } | 258 | } |
217 | 259 | ||
218 | static ssize_t w1_master_attribute_show_slaves(struct device *dev, struct device_attribute *attr, char *buf) | 260 | static ssize_t w1_master_attribute_show_slaves(struct device *dev, struct device_attribute *attr, char *buf) |
219 | |||
220 | { | 261 | { |
221 | struct w1_master *md = container_of(dev, struct w1_master, dev); | 262 | struct w1_master *md = container_of(dev, struct w1_master, dev); |
222 | int c = PAGE_SIZE; | 263 | int c = PAGE_SIZE; |
@@ -233,7 +274,7 @@ static ssize_t w1_master_attribute_show_slaves(struct device *dev, struct device | |||
233 | list_for_each_safe(ent, n, &md->slist) { | 274 | list_for_each_safe(ent, n, &md->slist) { |
234 | sl = list_entry(ent, struct w1_slave, w1_slave_entry); | 275 | sl = list_entry(ent, struct w1_slave, w1_slave_entry); |
235 | 276 | ||
236 | c -= snprintf(buf + PAGE_SIZE - c, c, "%s\n", sl->name); | 277 | c -= snprintf(buf + PAGE_SIZE - c, c, "%s\n", sl->name); |
237 | } | 278 | } |
238 | } | 279 | } |
239 | 280 | ||
@@ -242,73 +283,52 @@ static ssize_t w1_master_attribute_show_slaves(struct device *dev, struct device | |||
242 | return PAGE_SIZE - c; | 283 | return PAGE_SIZE - c; |
243 | } | 284 | } |
244 | 285 | ||
245 | static struct device_attribute w1_master_attribute_slaves = { | 286 | #define W1_MASTER_ATTR_RO(_name, _mode) \ |
246 | .attr = { | 287 | struct device_attribute w1_master_attribute_##_name = \ |
247 | .name = "w1_master_slaves", | 288 | __ATTR(w1_master_##_name, _mode, \ |
248 | .mode = S_IRUGO, | 289 | w1_master_attribute_show_##_name, NULL) |
249 | .owner = THIS_MODULE, | 290 | |
250 | }, | 291 | #define W1_MASTER_ATTR_RW(_name, _mode) \ |
251 | .show = &w1_master_attribute_show_slaves, | 292 | struct device_attribute w1_master_attribute_##_name = \ |
252 | }; | 293 | __ATTR(w1_master_##_name, _mode, \ |
253 | static struct device_attribute w1_master_attribute_slave_count = { | 294 | w1_master_attribute_show_##_name, \ |
254 | .attr = { | 295 | w1_master_attribute_store_##_name) |
255 | .name = "w1_master_slave_count", | 296 | |
256 | .mode = S_IRUGO, | 297 | static W1_MASTER_ATTR_RO(name, S_IRUGO); |
257 | .owner = THIS_MODULE | 298 | static W1_MASTER_ATTR_RO(slaves, S_IRUGO); |
258 | }, | 299 | static W1_MASTER_ATTR_RO(slave_count, S_IRUGO); |
259 | .show = &w1_master_attribute_show_slave_count, | 300 | static W1_MASTER_ATTR_RO(max_slave_count, S_IRUGO); |
260 | }; | 301 | static W1_MASTER_ATTR_RO(attempts, S_IRUGO); |
261 | static struct device_attribute w1_master_attribute_attempts = { | 302 | static W1_MASTER_ATTR_RO(timeout, S_IRUGO); |
262 | .attr = { | 303 | static W1_MASTER_ATTR_RO(pointer, S_IRUGO); |
263 | .name = "w1_master_attempts", | 304 | static W1_MASTER_ATTR_RW(search, S_IRUGO | S_IWUGO); |
264 | .mode = S_IRUGO, | 305 | |
265 | .owner = THIS_MODULE | 306 | static struct attribute *w1_master_default_attrs[] = { |
266 | }, | 307 | &w1_master_attribute_name.attr, |
267 | .show = &w1_master_attribute_show_attempts, | 308 | &w1_master_attribute_slaves.attr, |
268 | }; | 309 | &w1_master_attribute_slave_count.attr, |
269 | static struct device_attribute w1_master_attribute_max_slave_count = { | 310 | &w1_master_attribute_max_slave_count.attr, |
270 | .attr = { | 311 | &w1_master_attribute_attempts.attr, |
271 | .name = "w1_master_max_slave_count", | 312 | &w1_master_attribute_timeout.attr, |
272 | .mode = S_IRUGO, | 313 | &w1_master_attribute_pointer.attr, |
273 | .owner = THIS_MODULE | 314 | &w1_master_attribute_search.attr, |
274 | }, | 315 | NULL |
275 | .show = &w1_master_attribute_show_max_slave_count, | ||
276 | }; | ||
277 | static struct device_attribute w1_master_attribute_timeout = { | ||
278 | .attr = { | ||
279 | .name = "w1_master_timeout", | ||
280 | .mode = S_IRUGO, | ||
281 | .owner = THIS_MODULE | ||
282 | }, | ||
283 | .show = &w1_master_attribute_show_timeout, | ||
284 | }; | ||
285 | static struct device_attribute w1_master_attribute_pointer = { | ||
286 | .attr = { | ||
287 | .name = "w1_master_pointer", | ||
288 | .mode = S_IRUGO, | ||
289 | .owner = THIS_MODULE | ||
290 | }, | ||
291 | .show = &w1_master_attribute_show_pointer, | ||
292 | }; | ||
293 | static struct device_attribute w1_master_attribute_name = { | ||
294 | .attr = { | ||
295 | .name = "w1_master_name", | ||
296 | .mode = S_IRUGO, | ||
297 | .owner = THIS_MODULE | ||
298 | }, | ||
299 | .show = &w1_master_attribute_show_name, | ||
300 | }; | 316 | }; |
301 | 317 | ||
302 | static struct bin_attribute w1_slave_bin_attribute = { | 318 | static struct attribute_group w1_master_defattr_group = { |
303 | .attr = { | 319 | .attrs = w1_master_default_attrs, |
304 | .name = "w1_slave", | ||
305 | .mode = S_IRUGO, | ||
306 | .owner = THIS_MODULE, | ||
307 | }, | ||
308 | .size = W1_SLAVE_DATA_SIZE, | ||
309 | .read = &w1_default_read_bin, | ||
310 | }; | 320 | }; |
311 | 321 | ||
322 | int w1_create_master_attributes(struct w1_master *master) | ||
323 | { | ||
324 | return sysfs_create_group(&master->dev.kobj, &w1_master_defattr_group); | ||
325 | } | ||
326 | |||
327 | void w1_destroy_master_attributes(struct w1_master *master) | ||
328 | { | ||
329 | sysfs_remove_group(&master->dev.kobj, &w1_master_defattr_group); | ||
330 | } | ||
331 | |||
312 | static int __w1_attach_slave_device(struct w1_slave *sl) | 332 | static int __w1_attach_slave_device(struct w1_slave *sl) |
313 | { | 333 | { |
314 | int err; | 334 | int err; |
@@ -319,13 +339,13 @@ static int __w1_attach_slave_device(struct w1_slave *sl) | |||
319 | sl->dev.release = &w1_slave_release; | 339 | sl->dev.release = &w1_slave_release; |
320 | 340 | ||
321 | snprintf(&sl->dev.bus_id[0], sizeof(sl->dev.bus_id), | 341 | snprintf(&sl->dev.bus_id[0], sizeof(sl->dev.bus_id), |
322 | "%02x-%012llx", | 342 | "%02x-%012llx", |
323 | (unsigned int) sl->reg_num.family, | 343 | (unsigned int) sl->reg_num.family, |
324 | (unsigned long long) sl->reg_num.id); | 344 | (unsigned long long) sl->reg_num.id); |
325 | snprintf (&sl->name[0], sizeof(sl->name), | 345 | snprintf(&sl->name[0], sizeof(sl->name), |
326 | "%02x-%012llx", | 346 | "%02x-%012llx", |
327 | (unsigned int) sl->reg_num.family, | 347 | (unsigned int) sl->reg_num.family, |
328 | (unsigned long long) sl->reg_num.id); | 348 | (unsigned long long) sl->reg_num.id); |
329 | 349 | ||
330 | dev_dbg(&sl->dev, "%s: registering %s.\n", __func__, | 350 | dev_dbg(&sl->dev, "%s: registering %s.\n", __func__, |
331 | &sl->dev.bus_id[0]); | 351 | &sl->dev.bus_id[0]); |
@@ -333,48 +353,36 @@ static int __w1_attach_slave_device(struct w1_slave *sl) | |||
333 | err = device_register(&sl->dev); | 353 | err = device_register(&sl->dev); |
334 | if (err < 0) { | 354 | if (err < 0) { |
335 | dev_err(&sl->dev, | 355 | dev_err(&sl->dev, |
336 | "Device registration [%s] failed. err=%d\n", | 356 | "Device registration [%s] failed. err=%d\n", |
337 | sl->dev.bus_id, err); | 357 | sl->dev.bus_id, err); |
338 | return err; | 358 | return err; |
339 | } | 359 | } |
340 | 360 | ||
341 | memcpy(&sl->attr_bin, &w1_slave_bin_attribute, sizeof(sl->attr_bin)); | 361 | memcpy(&sl->attr_bin, &w1_slave_bin_attribute, sizeof(sl->attr_bin)); |
342 | memcpy(&sl->attr_name, &w1_slave_attribute, sizeof(sl->attr_name)); | 362 | memcpy(&sl->attr_name, &w1_slave_attribute, sizeof(sl->attr_name)); |
343 | memcpy(&sl->attr_val, &w1_slave_attribute_val, sizeof(sl->attr_val)); | 363 | |
344 | |||
345 | sl->attr_bin.read = sl->family->fops->rbin; | 364 | sl->attr_bin.read = sl->family->fops->rbin; |
346 | sl->attr_name.show = sl->family->fops->rname; | 365 | sl->attr_name.show = sl->family->fops->rname; |
347 | sl->attr_val.show = sl->family->fops->rval; | ||
348 | sl->attr_val.attr.name = sl->family->fops->rvalname; | ||
349 | 366 | ||
350 | err = device_create_file(&sl->dev, &sl->attr_name); | 367 | err = device_create_file(&sl->dev, &sl->attr_name); |
351 | if (err < 0) { | 368 | if (err < 0) { |
352 | dev_err(&sl->dev, | 369 | dev_err(&sl->dev, |
353 | "sysfs file creation for [%s] failed. err=%d\n", | 370 | "sysfs file creation for [%s] failed. err=%d\n", |
354 | sl->dev.bus_id, err); | 371 | sl->dev.bus_id, err); |
355 | device_unregister(&sl->dev); | ||
356 | return err; | ||
357 | } | ||
358 | |||
359 | err = device_create_file(&sl->dev, &sl->attr_val); | ||
360 | if (err < 0) { | ||
361 | dev_err(&sl->dev, | ||
362 | "sysfs file creation for [%s] failed. err=%d\n", | ||
363 | sl->dev.bus_id, err); | ||
364 | device_remove_file(&sl->dev, &sl->attr_name); | ||
365 | device_unregister(&sl->dev); | 372 | device_unregister(&sl->dev); |
366 | return err; | 373 | return err; |
367 | } | 374 | } |
368 | 375 | ||
369 | err = sysfs_create_bin_file(&sl->dev.kobj, &sl->attr_bin); | 376 | if ( sl->attr_bin.read ) { |
370 | if (err < 0) { | 377 | err = sysfs_create_bin_file(&sl->dev.kobj, &sl->attr_bin); |
371 | dev_err(&sl->dev, | 378 | if (err < 0) { |
372 | "sysfs file creation for [%s] failed. err=%d\n", | 379 | dev_err(&sl->dev, |
373 | sl->dev.bus_id, err); | 380 | "sysfs file creation for [%s] failed. err=%d\n", |
374 | device_remove_file(&sl->dev, &sl->attr_name); | 381 | sl->dev.bus_id, err); |
375 | device_remove_file(&sl->dev, &sl->attr_val); | 382 | device_remove_file(&sl->dev, &sl->attr_name); |
376 | device_unregister(&sl->dev); | 383 | device_unregister(&sl->dev); |
377 | return err; | 384 | return err; |
385 | } | ||
378 | } | 386 | } |
379 | 387 | ||
380 | list_add_tail(&sl->w1_slave_entry, &sl->master->slist); | 388 | list_add_tail(&sl->w1_slave_entry, &sl->master->slist); |
@@ -410,12 +418,10 @@ static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn) | |||
410 | spin_lock(&w1_flock); | 418 | spin_lock(&w1_flock); |
411 | f = w1_family_registered(rn->family); | 419 | f = w1_family_registered(rn->family); |
412 | if (!f) { | 420 | if (!f) { |
413 | spin_unlock(&w1_flock); | 421 | f= &w1_default_family; |
414 | dev_info(&dev->dev, "Family %x for %02x.%012llx.%02x is not registered.\n", | 422 | dev_info(&dev->dev, "Family %x for %02x.%012llx.%02x is not registered.\n", |
415 | rn->family, rn->family, | 423 | rn->family, rn->family, |
416 | (unsigned long long)rn->id, rn->crc); | 424 | (unsigned long long)rn->id, rn->crc); |
417 | kfree(sl); | ||
418 | return -ENODEV; | ||
419 | } | 425 | } |
420 | __w1_family_get(f); | 426 | __w1_family_get(f); |
421 | spin_unlock(&w1_flock); | 427 | spin_unlock(&w1_flock); |
@@ -445,7 +451,7 @@ static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn) | |||
445 | static void w1_slave_detach(struct w1_slave *sl) | 451 | static void w1_slave_detach(struct w1_slave *sl) |
446 | { | 452 | { |
447 | struct w1_netlink_msg msg; | 453 | struct w1_netlink_msg msg; |
448 | 454 | ||
449 | dev_info(&sl->dev, "%s: detaching %s.\n", __func__, sl->name); | 455 | dev_info(&sl->dev, "%s: detaching %s.\n", __func__, sl->name); |
450 | 456 | ||
451 | while (atomic_read(&sl->refcnt)) { | 457 | while (atomic_read(&sl->refcnt)) { |
@@ -456,12 +462,15 @@ static void w1_slave_detach(struct w1_slave *sl) | |||
456 | flush_signals(current); | 462 | flush_signals(current); |
457 | } | 463 | } |
458 | 464 | ||
459 | sysfs_remove_bin_file (&sl->dev.kobj, &sl->attr_bin); | 465 | if ( sl->attr_bin.read ) { |
466 | sysfs_remove_bin_file (&sl->dev.kobj, &sl->attr_bin); | ||
467 | } | ||
460 | device_remove_file(&sl->dev, &sl->attr_name); | 468 | device_remove_file(&sl->dev, &sl->attr_name); |
461 | device_remove_file(&sl->dev, &sl->attr_val); | ||
462 | device_unregister(&sl->dev); | 469 | device_unregister(&sl->dev); |
463 | w1_family_put(sl->family); | 470 | w1_family_put(sl->family); |
464 | 471 | ||
472 | sl->master->slave_count--; | ||
473 | |||
465 | memcpy(&msg.id.id, &sl->reg_num, sizeof(msg.id.id)); | 474 | memcpy(&msg.id.id, &sl->reg_num, sizeof(msg.id.id)); |
466 | msg.type = W1_SLAVE_REMOVE; | 475 | msg.type = W1_SLAVE_REMOVE; |
467 | w1_netlink_send(sl->master, &msg); | 476 | w1_netlink_send(sl->master, &msg); |
@@ -471,8 +480,8 @@ static struct w1_master *w1_search_master(unsigned long data) | |||
471 | { | 480 | { |
472 | struct w1_master *dev; | 481 | struct w1_master *dev; |
473 | int found = 0; | 482 | int found = 0; |
474 | 483 | ||
475 | spin_lock_irq(&w1_mlock); | 484 | spin_lock_bh(&w1_mlock); |
476 | list_for_each_entry(dev, &w1_masters, w1_master_entry) { | 485 | list_for_each_entry(dev, &w1_masters, w1_master_entry) { |
477 | if (dev->bus_master->data == data) { | 486 | if (dev->bus_master->data == data) { |
478 | found = 1; | 487 | found = 1; |
@@ -480,12 +489,26 @@ static struct w1_master *w1_search_master(unsigned long data) | |||
480 | break; | 489 | break; |
481 | } | 490 | } |
482 | } | 491 | } |
483 | spin_unlock_irq(&w1_mlock); | 492 | spin_unlock_bh(&w1_mlock); |
484 | 493 | ||
485 | return (found)?dev:NULL; | 494 | return (found)?dev:NULL; |
486 | } | 495 | } |
487 | 496 | ||
488 | void w1_slave_found(unsigned long data, u64 rn) | 497 | void w1_reconnect_slaves(struct w1_family *f) |
498 | { | ||
499 | struct w1_master *dev; | ||
500 | |||
501 | spin_lock_bh(&w1_mlock); | ||
502 | list_for_each_entry(dev, &w1_masters, w1_master_entry) { | ||
503 | dev_info(&dev->dev, "Reconnecting slaves in %s into new family %02x.\n", | ||
504 | dev->name, f->fid); | ||
505 | set_bit(W1_MASTER_NEED_RECONNECT, &dev->flags); | ||
506 | } | ||
507 | spin_unlock_bh(&w1_mlock); | ||
508 | } | ||
509 | |||
510 | |||
511 | static void w1_slave_found(unsigned long data, u64 rn) | ||
489 | { | 512 | { |
490 | int slave_count; | 513 | int slave_count; |
491 | struct w1_slave *sl; | 514 | struct w1_slave *sl; |
@@ -500,7 +523,7 @@ void w1_slave_found(unsigned long data, u64 rn) | |||
500 | data); | 523 | data); |
501 | return; | 524 | return; |
502 | } | 525 | } |
503 | 526 | ||
504 | tmp = (struct w1_reg_num *) &rn; | 527 | tmp = (struct w1_reg_num *) &rn; |
505 | 528 | ||
506 | slave_count = 0; | 529 | slave_count = 0; |
@@ -513,8 +536,7 @@ void w1_slave_found(unsigned long data, u64 rn) | |||
513 | sl->reg_num.crc == tmp->crc) { | 536 | sl->reg_num.crc == tmp->crc) { |
514 | set_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags); | 537 | set_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags); |
515 | break; | 538 | break; |
516 | } | 539 | } else if (sl->reg_num.family == tmp->family) { |
517 | else if (sl->reg_num.family == tmp->family) { | ||
518 | family_found = 1; | 540 | family_found = 1; |
519 | break; | 541 | break; |
520 | } | 542 | } |
@@ -528,30 +550,43 @@ void w1_slave_found(unsigned long data, u64 rn) | |||
528 | rn && ((le64_to_cpu(rn) >> 56) & 0xff) == w1_calc_crc8((u8 *)&rn, 7)) { | 550 | rn && ((le64_to_cpu(rn) >> 56) & 0xff) == w1_calc_crc8((u8 *)&rn, 7)) { |
529 | w1_attach_slave_device(dev, tmp); | 551 | w1_attach_slave_device(dev, tmp); |
530 | } | 552 | } |
531 | 553 | ||
532 | atomic_dec(&dev->refcnt); | 554 | atomic_dec(&dev->refcnt); |
533 | } | 555 | } |
534 | 556 | ||
535 | void w1_search(struct w1_master *dev) | 557 | /** |
558 | * Performs a ROM Search & registers any devices found. | ||
559 | * The 1-wire search is a simple binary tree search. | ||
560 | * For each bit of the address, we read two bits and write one bit. | ||
561 | * The bit written will put to sleep all devies that don't match that bit. | ||
562 | * When the two reads differ, the direction choice is obvious. | ||
563 | * When both bits are 0, we must choose a path to take. | ||
564 | * When we can scan all 64 bits without having to choose a path, we are done. | ||
565 | * | ||
566 | * See "Application note 187 1-wire search algorithm" at www.maxim-ic.com | ||
567 | * | ||
568 | * @dev The master device to search | ||
569 | * @cb Function to call when a device is found | ||
570 | */ | ||
571 | void w1_search(struct w1_master *dev, w1_slave_found_callback cb) | ||
536 | { | 572 | { |
537 | u64 last, rn, tmp; | 573 | u64 last_rn, rn, tmp64; |
538 | int i, count = 0; | 574 | int i, slave_count = 0; |
539 | int last_family_desc, last_zero, last_device; | 575 | int last_zero, last_device; |
540 | int search_bit, id_bit, comp_bit, desc_bit; | 576 | int search_bit, desc_bit; |
577 | u8 triplet_ret = 0; | ||
541 | 578 | ||
542 | search_bit = id_bit = comp_bit = 0; | 579 | search_bit = 0; |
543 | rn = tmp = last = 0; | 580 | rn = last_rn = 0; |
544 | last_device = last_zero = last_family_desc = 0; | 581 | last_device = 0; |
582 | last_zero = -1; | ||
545 | 583 | ||
546 | desc_bit = 64; | 584 | desc_bit = 64; |
547 | 585 | ||
548 | while (!(id_bit && comp_bit) && !last_device | 586 | while ( !last_device && (slave_count++ < dev->max_slave_count) ) { |
549 | && count++ < dev->max_slave_count) { | 587 | last_rn = rn; |
550 | last = rn; | ||
551 | rn = 0; | 588 | rn = 0; |
552 | 589 | ||
553 | last_family_desc = 0; | ||
554 | |||
555 | /* | 590 | /* |
556 | * Reset bus and all 1-wire device state machines | 591 | * Reset bus and all 1-wire device state machines |
557 | * so they can respond to our requests. | 592 | * so they can respond to our requests. |
@@ -563,94 +598,46 @@ void w1_search(struct w1_master *dev) | |||
563 | break; | 598 | break; |
564 | } | 599 | } |
565 | 600 | ||
566 | #if 1 | 601 | /* Start the search */ |
567 | w1_write_8(dev, W1_SEARCH); | 602 | w1_write_8(dev, W1_SEARCH); |
568 | for (i = 0; i < 64; ++i) { | 603 | for (i = 0; i < 64; ++i) { |
569 | /* | 604 | /* Determine the direction/search bit */ |
570 | * Read 2 bits from bus. | 605 | if (i == desc_bit) |
571 | * All who don't sleep must send ID bit and COMPLEMENT ID bit. | 606 | search_bit = 1; /* took the 0 path last time, so take the 1 path */ |
572 | * They actually are ANDed between all senders. | 607 | else if (i > desc_bit) |
573 | */ | 608 | search_bit = 0; /* take the 0 path on the next branch */ |
574 | id_bit = w1_touch_bit(dev, 1); | ||
575 | comp_bit = w1_touch_bit(dev, 1); | ||
576 | |||
577 | if (id_bit && comp_bit) | ||
578 | break; | ||
579 | |||
580 | if (id_bit == 0 && comp_bit == 0) { | ||
581 | if (i == desc_bit) | ||
582 | search_bit = 1; | ||
583 | else if (i > desc_bit) | ||
584 | search_bit = 0; | ||
585 | else | ||
586 | search_bit = ((last >> i) & 0x1); | ||
587 | |||
588 | if (search_bit == 0) { | ||
589 | last_zero = i; | ||
590 | if (last_zero < 9) | ||
591 | last_family_desc = last_zero; | ||
592 | } | ||
593 | |||
594 | } | ||
595 | else | 609 | else |
596 | search_bit = id_bit; | 610 | search_bit = ((last_rn >> i) & 0x1); |
597 | 611 | ||
598 | tmp = search_bit; | 612 | /** Read two bits and write one bit */ |
599 | rn |= (tmp << i); | 613 | triplet_ret = w1_triplet(dev, search_bit); |
600 | 614 | ||
601 | /* | 615 | /* quit if no device responded */ |
602 | * Write 1 bit to bus | 616 | if ( (triplet_ret & 0x03) == 0x03 ) |
603 | * and make all who don't have "search_bit" in "i"'th position | 617 | break; |
604 | * in it's registration number sleep. | ||
605 | */ | ||
606 | if (dev->bus_master->touch_bit) | ||
607 | w1_touch_bit(dev, search_bit); | ||
608 | else | ||
609 | w1_write_bit(dev, search_bit); | ||
610 | 618 | ||
611 | } | 619 | /* If both directions were valid, and we took the 0 path... */ |
612 | #endif | 620 | if (triplet_ret == 0) |
621 | last_zero = i; | ||
613 | 622 | ||
614 | if (desc_bit == last_zero) | 623 | /* extract the direction taken & update the device number */ |
615 | last_device = 1; | 624 | tmp64 = (triplet_ret >> 2); |
625 | rn |= (tmp64 << i); | ||
626 | } | ||
616 | 627 | ||
617 | desc_bit = last_zero; | 628 | if ( (triplet_ret & 0x03) != 0x03 ) { |
618 | 629 | if ( (desc_bit == last_zero) || (last_zero < 0)) | |
619 | w1_slave_found(dev->bus_master->data, rn); | 630 | last_device = 1; |
631 | desc_bit = last_zero; | ||
632 | cb(dev->bus_master->data, rn); | ||
633 | } | ||
620 | } | 634 | } |
621 | } | 635 | } |
622 | 636 | ||
623 | int w1_create_master_attributes(struct w1_master *dev) | 637 | static int w1_control(void *data) |
624 | { | ||
625 | if ( device_create_file(&dev->dev, &w1_master_attribute_slaves) < 0 || | ||
626 | device_create_file(&dev->dev, &w1_master_attribute_slave_count) < 0 || | ||
627 | device_create_file(&dev->dev, &w1_master_attribute_attempts) < 0 || | ||
628 | device_create_file(&dev->dev, &w1_master_attribute_max_slave_count) < 0 || | ||
629 | device_create_file(&dev->dev, &w1_master_attribute_timeout) < 0|| | ||
630 | device_create_file(&dev->dev, &w1_master_attribute_pointer) < 0|| | ||
631 | device_create_file(&dev->dev, &w1_master_attribute_name) < 0) | ||
632 | return -EINVAL; | ||
633 | |||
634 | return 0; | ||
635 | } | ||
636 | |||
637 | void w1_destroy_master_attributes(struct w1_master *dev) | ||
638 | { | 638 | { |
639 | device_remove_file(&dev->dev, &w1_master_attribute_slaves); | 639 | struct w1_slave *sl, *sln; |
640 | device_remove_file(&dev->dev, &w1_master_attribute_slave_count); | 640 | struct w1_master *dev, *n; |
641 | device_remove_file(&dev->dev, &w1_master_attribute_attempts); | ||
642 | device_remove_file(&dev->dev, &w1_master_attribute_max_slave_count); | ||
643 | device_remove_file(&dev->dev, &w1_master_attribute_timeout); | ||
644 | device_remove_file(&dev->dev, &w1_master_attribute_pointer); | ||
645 | device_remove_file(&dev->dev, &w1_master_attribute_name); | ||
646 | } | ||
647 | |||
648 | |||
649 | int w1_control(void *data) | ||
650 | { | ||
651 | struct w1_slave *sl; | ||
652 | struct w1_master *dev; | ||
653 | struct list_head *ent, *ment, *n, *mn; | ||
654 | int err, have_to_wait = 0; | 641 | int err, have_to_wait = 0; |
655 | 642 | ||
656 | daemonize("w1_control"); | 643 | daemonize("w1_control"); |
@@ -665,10 +652,8 @@ int w1_control(void *data) | |||
665 | if (signal_pending(current)) | 652 | if (signal_pending(current)) |
666 | flush_signals(current); | 653 | flush_signals(current); |
667 | 654 | ||
668 | list_for_each_safe(ment, mn, &w1_masters) { | 655 | list_for_each_entry_safe(dev, n, &w1_masters, w1_master_entry) { |
669 | dev = list_entry(ment, struct w1_master, w1_master_entry); | 656 | if (!control_needs_exit && !dev->flags) |
670 | |||
671 | if (!control_needs_exit && !dev->need_exit) | ||
672 | continue; | 657 | continue; |
673 | /* | 658 | /* |
674 | * Little race: we can create thread but not set the flag. | 659 | * Little race: we can create thread but not set the flag. |
@@ -679,12 +664,8 @@ int w1_control(void *data) | |||
679 | continue; | 664 | continue; |
680 | } | 665 | } |
681 | 666 | ||
682 | spin_lock(&w1_mlock); | ||
683 | list_del(&dev->w1_master_entry); | ||
684 | spin_unlock(&w1_mlock); | ||
685 | |||
686 | if (control_needs_exit) { | 667 | if (control_needs_exit) { |
687 | dev->need_exit = 1; | 668 | set_bit(W1_MASTER_NEED_EXIT, &dev->flags); |
688 | 669 | ||
689 | err = kill_proc(dev->kpid, SIGTERM, 1); | 670 | err = kill_proc(dev->kpid, SIGTERM, 1); |
690 | if (err) | 671 | if (err) |
@@ -693,24 +674,42 @@ int w1_control(void *data) | |||
693 | dev->kpid); | 674 | dev->kpid); |
694 | } | 675 | } |
695 | 676 | ||
696 | wait_for_completion(&dev->dev_exited); | 677 | if (test_bit(W1_MASTER_NEED_EXIT, &dev->flags)) { |
697 | 678 | wait_for_completion(&dev->dev_exited); | |
698 | list_for_each_safe(ent, n, &dev->slist) { | 679 | spin_lock_bh(&w1_mlock); |
699 | sl = list_entry(ent, struct w1_slave, w1_slave_entry); | 680 | list_del(&dev->w1_master_entry); |
681 | spin_unlock_bh(&w1_mlock); | ||
700 | 682 | ||
701 | if (!sl) | 683 | list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) { |
702 | dev_warn(&dev->dev, | ||
703 | "%s: slave entry is NULL.\n", | ||
704 | __func__); | ||
705 | else { | ||
706 | list_del(&sl->w1_slave_entry); | 684 | list_del(&sl->w1_slave_entry); |
707 | 685 | ||
708 | w1_slave_detach(sl); | 686 | w1_slave_detach(sl); |
709 | kfree(sl); | 687 | kfree(sl); |
710 | } | 688 | } |
689 | w1_destroy_master_attributes(dev); | ||
690 | atomic_dec(&dev->refcnt); | ||
691 | continue; | ||
692 | } | ||
693 | |||
694 | if (test_bit(W1_MASTER_NEED_RECONNECT, &dev->flags)) { | ||
695 | dev_info(&dev->dev, "Reconnecting slaves in device %s.\n", dev->name); | ||
696 | down(&dev->mutex); | ||
697 | list_for_each_entry(sl, &dev->slist, w1_slave_entry) { | ||
698 | if (sl->family->fid == W1_FAMILY_DEFAULT) { | ||
699 | struct w1_reg_num rn; | ||
700 | list_del(&sl->w1_slave_entry); | ||
701 | w1_slave_detach(sl); | ||
702 | |||
703 | memcpy(&rn, &sl->reg_num, sizeof(rn)); | ||
704 | |||
705 | kfree(sl); | ||
706 | |||
707 | w1_attach_slave_device(dev, &rn); | ||
708 | } | ||
709 | } | ||
710 | clear_bit(W1_MASTER_NEED_RECONNECT, &dev->flags); | ||
711 | up(&dev->mutex); | ||
711 | } | 712 | } |
712 | w1_destroy_master_attributes(dev); | ||
713 | atomic_dec(&dev->refcnt); | ||
714 | } | 713 | } |
715 | } | 714 | } |
716 | 715 | ||
@@ -720,51 +719,50 @@ int w1_control(void *data) | |||
720 | int w1_process(void *data) | 719 | int w1_process(void *data) |
721 | { | 720 | { |
722 | struct w1_master *dev = (struct w1_master *) data; | 721 | struct w1_master *dev = (struct w1_master *) data; |
723 | struct list_head *ent, *n; | 722 | struct w1_slave *sl, *sln; |
724 | struct w1_slave *sl; | ||
725 | 723 | ||
726 | daemonize("%s", dev->name); | 724 | daemonize("%s", dev->name); |
727 | allow_signal(SIGTERM); | 725 | allow_signal(SIGTERM); |
728 | 726 | ||
729 | while (!dev->need_exit) { | 727 | while (!test_bit(W1_MASTER_NEED_EXIT, &dev->flags)) { |
730 | try_to_freeze(PF_FREEZE); | 728 | try_to_freeze(PF_FREEZE); |
731 | msleep_interruptible(w1_timeout * 1000); | 729 | msleep_interruptible(w1_timeout * 1000); |
732 | 730 | ||
733 | if (signal_pending(current)) | 731 | if (signal_pending(current)) |
734 | flush_signals(current); | 732 | flush_signals(current); |
735 | 733 | ||
736 | if (dev->need_exit) | 734 | if (test_bit(W1_MASTER_NEED_EXIT, &dev->flags)) |
737 | break; | 735 | break; |
738 | 736 | ||
739 | if (!dev->initialized) | 737 | if (!dev->initialized) |
740 | continue; | 738 | continue; |
741 | 739 | ||
740 | if (dev->search_count == 0) | ||
741 | continue; | ||
742 | |||
742 | if (down_interruptible(&dev->mutex)) | 743 | if (down_interruptible(&dev->mutex)) |
743 | continue; | 744 | continue; |
744 | 745 | ||
745 | list_for_each_safe(ent, n, &dev->slist) { | 746 | list_for_each_entry(sl, &dev->slist, w1_slave_entry) |
746 | sl = list_entry(ent, struct w1_slave, w1_slave_entry); | 747 | clear_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags); |
747 | 748 | ||
748 | if (sl) | ||
749 | clear_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags); | ||
750 | } | ||
751 | |||
752 | w1_search_devices(dev, w1_slave_found); | 749 | w1_search_devices(dev, w1_slave_found); |
753 | 750 | ||
754 | list_for_each_safe(ent, n, &dev->slist) { | 751 | list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) { |
755 | sl = list_entry(ent, struct w1_slave, w1_slave_entry); | 752 | if (!test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags) && !--sl->ttl) { |
756 | |||
757 | if (sl && !test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags) && !--sl->ttl) { | ||
758 | list_del (&sl->w1_slave_entry); | 753 | list_del (&sl->w1_slave_entry); |
759 | 754 | ||
760 | w1_slave_detach (sl); | 755 | w1_slave_detach (sl); |
761 | kfree (sl); | 756 | kfree (sl); |
762 | 757 | ||
763 | dev->slave_count--; | 758 | dev->slave_count--; |
764 | } | 759 | } else if (test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags)) |
765 | else if (test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags)) | ||
766 | sl->ttl = dev->slave_ttl; | 760 | sl->ttl = dev->slave_ttl; |
767 | } | 761 | } |
762 | |||
763 | if (dev->search_count > 0) | ||
764 | dev->search_count--; | ||
765 | |||
768 | up(&dev->mutex); | 766 | up(&dev->mutex); |
769 | } | 767 | } |
770 | 768 | ||
@@ -774,7 +772,7 @@ int w1_process(void *data) | |||
774 | return 0; | 772 | return 0; |
775 | } | 773 | } |
776 | 774 | ||
777 | int w1_init(void) | 775 | static int w1_init(void) |
778 | { | 776 | { |
779 | int retval; | 777 | int retval; |
780 | 778 | ||
@@ -814,18 +812,14 @@ err_out_exit_init: | |||
814 | return retval; | 812 | return retval; |
815 | } | 813 | } |
816 | 814 | ||
817 | void w1_fini(void) | 815 | static void w1_fini(void) |
818 | { | 816 | { |
819 | struct w1_master *dev; | 817 | struct w1_master *dev; |
820 | struct list_head *ent, *n; | ||
821 | 818 | ||
822 | list_for_each_safe(ent, n, &w1_masters) { | 819 | list_for_each_entry(dev, &w1_masters, w1_master_entry) |
823 | dev = list_entry(ent, struct w1_master, w1_master_entry); | ||
824 | __w1_remove_master_device(dev); | 820 | __w1_remove_master_device(dev); |
825 | } | ||
826 | 821 | ||
827 | control_needs_exit = 1; | 822 | control_needs_exit = 1; |
828 | |||
829 | wait_for_completion(&w1_control_complete); | 823 | wait_for_completion(&w1_control_complete); |
830 | 824 | ||
831 | driver_unregister(&w1_driver); | 825 | driver_unregister(&w1_driver); |
diff --git a/drivers/w1/w1.h b/drivers/w1/w1.h index abbddaf3f8e2..4f0a986e33e3 100644 --- a/drivers/w1/w1.h +++ b/drivers/w1/w1.h | |||
@@ -1,8 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * w1.h | 2 | * w1.h |
3 | * | 3 | * |
4 | * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru> | 4 | * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru> |
5 | * | 5 | * |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by | 8 | * it under the terms of the GNU General Public License as published by |
@@ -74,36 +74,86 @@ struct w1_slave | |||
74 | int ttl; | 74 | int ttl; |
75 | 75 | ||
76 | struct w1_master *master; | 76 | struct w1_master *master; |
77 | struct w1_family *family; | 77 | struct w1_family *family; |
78 | struct device dev; | 78 | struct device dev; |
79 | struct completion dev_released; | 79 | struct completion dev_released; |
80 | 80 | ||
81 | struct bin_attribute attr_bin; | 81 | struct bin_attribute attr_bin; |
82 | struct device_attribute attr_name, attr_val; | 82 | struct device_attribute attr_name; |
83 | }; | 83 | }; |
84 | 84 | ||
85 | typedef void (* w1_slave_found_callback)(unsigned long, u64); | 85 | typedef void (* w1_slave_found_callback)(unsigned long, u64); |
86 | 86 | ||
87 | |||
88 | /** | ||
89 | * Note: read_bit and write_bit are very low level functions and should only | ||
90 | * be used with hardware that doesn't really support 1-wire operations, | ||
91 | * like a parallel/serial port. | ||
92 | * Either define read_bit and write_bit OR define, at minimum, touch_bit and | ||
93 | * reset_bus. | ||
94 | */ | ||
87 | struct w1_bus_master | 95 | struct w1_bus_master |
88 | { | 96 | { |
89 | unsigned long data; | 97 | /** the first parameter in all the functions below */ |
90 | 98 | unsigned long data; | |
91 | u8 (*read_bit)(unsigned long); | 99 | |
92 | void (*write_bit)(unsigned long, u8); | 100 | /** |
93 | 101 | * Sample the line level | |
94 | u8 (*read_byte)(unsigned long); | 102 | * @return the level read (0 or 1) |
95 | void (*write_byte)(unsigned long, u8); | 103 | */ |
96 | 104 | u8 (*read_bit)(unsigned long); | |
97 | u8 (*read_block)(unsigned long, u8 *, int); | 105 | |
98 | void (*write_block)(unsigned long, u8 *, int); | 106 | /** Sets the line level */ |
99 | 107 | void (*write_bit)(unsigned long, u8); | |
100 | u8 (*touch_bit)(unsigned long, u8); | 108 | |
101 | 109 | /** | |
102 | u8 (*reset_bus)(unsigned long); | 110 | * touch_bit is the lowest-level function for devices that really |
103 | 111 | * support the 1-wire protocol. | |
104 | void (*search)(unsigned long, w1_slave_found_callback); | 112 | * touch_bit(0) = write-0 cycle |
113 | * touch_bit(1) = write-1 / read cycle | ||
114 | * @return the bit read (0 or 1) | ||
115 | */ | ||
116 | u8 (*touch_bit)(unsigned long, u8); | ||
117 | |||
118 | /** | ||
119 | * Reads a bytes. Same as 8 touch_bit(1) calls. | ||
120 | * @return the byte read | ||
121 | */ | ||
122 | u8 (*read_byte)(unsigned long); | ||
123 | |||
124 | /** | ||
125 | * Writes a byte. Same as 8 touch_bit(x) calls. | ||
126 | */ | ||
127 | void (*write_byte)(unsigned long, u8); | ||
128 | |||
129 | /** | ||
130 | * Same as a series of read_byte() calls | ||
131 | * @return the number of bytes read | ||
132 | */ | ||
133 | u8 (*read_block)(unsigned long, u8 *, int); | ||
134 | |||
135 | /** Same as a series of write_byte() calls */ | ||
136 | void (*write_block)(unsigned long, const u8 *, int); | ||
137 | |||
138 | /** | ||
139 | * Combines two reads and a smart write for ROM searches | ||
140 | * @return bit0=Id bit1=comp_id bit2=dir_taken | ||
141 | */ | ||
142 | u8 (*triplet)(unsigned long, u8); | ||
143 | |||
144 | /** | ||
145 | * long write-0 with a read for the presence pulse detection | ||
146 | * @return -1=Error, 0=Device present, 1=No device present | ||
147 | */ | ||
148 | u8 (*reset_bus)(unsigned long); | ||
149 | |||
150 | /** Really nice hardware can handles the ROM searches */ | ||
151 | void (*search)(unsigned long, w1_slave_found_callback); | ||
105 | }; | 152 | }; |
106 | 153 | ||
154 | #define W1_MASTER_NEED_EXIT 0 | ||
155 | #define W1_MASTER_NEED_RECONNECT 1 | ||
156 | |||
107 | struct w1_master | 157 | struct w1_master |
108 | { | 158 | { |
109 | struct list_head w1_master_entry; | 159 | struct list_head w1_master_entry; |
@@ -115,30 +165,31 @@ struct w1_master | |||
115 | int slave_ttl; | 165 | int slave_ttl; |
116 | int initialized; | 166 | int initialized; |
117 | u32 id; | 167 | u32 id; |
168 | int search_count; | ||
118 | 169 | ||
119 | atomic_t refcnt; | 170 | atomic_t refcnt; |
120 | 171 | ||
121 | void *priv; | 172 | void *priv; |
122 | int priv_size; | 173 | int priv_size; |
123 | 174 | ||
124 | int need_exit; | 175 | long flags; |
176 | |||
125 | pid_t kpid; | 177 | pid_t kpid; |
126 | struct semaphore mutex; | 178 | struct semaphore mutex; |
127 | 179 | ||
128 | struct device_driver *driver; | 180 | struct device_driver *driver; |
129 | struct device dev; | 181 | struct device dev; |
130 | struct completion dev_released; | 182 | struct completion dev_released; |
131 | struct completion dev_exited; | 183 | struct completion dev_exited; |
132 | 184 | ||
133 | struct w1_bus_master *bus_master; | 185 | struct w1_bus_master *bus_master; |
134 | 186 | ||
135 | u32 seq, groups; | 187 | u32 seq, groups; |
136 | struct sock *nls; | 188 | struct sock *nls; |
137 | }; | 189 | }; |
138 | 190 | ||
139 | int w1_create_master_attributes(struct w1_master *); | 191 | int w1_create_master_attributes(struct w1_master *); |
140 | void w1_destroy_master_attributes(struct w1_master *); | 192 | void w1_search(struct w1_master *dev, w1_slave_found_callback cb); |
141 | void w1_search(struct w1_master *dev); | ||
142 | 193 | ||
143 | #endif /* __KERNEL__ */ | 194 | #endif /* __KERNEL__ */ |
144 | 195 | ||
diff --git a/drivers/w1/w1_family.c b/drivers/w1/w1_family.c index d1d56eca1061..02eee57d3c0c 100644 --- a/drivers/w1/w1_family.c +++ b/drivers/w1/w1_family.c | |||
@@ -1,8 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * w1_family.c | 2 | * w1_family.c |
3 | * | 3 | * |
4 | * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru> | 4 | * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru> |
5 | * | 5 | * |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by | 8 | * it under the terms of the GNU General Public License as published by |
@@ -27,10 +27,11 @@ | |||
27 | 27 | ||
28 | DEFINE_SPINLOCK(w1_flock); | 28 | DEFINE_SPINLOCK(w1_flock); |
29 | static LIST_HEAD(w1_families); | 29 | static LIST_HEAD(w1_families); |
30 | extern void w1_reconnect_slaves(struct w1_family *f); | ||
30 | 31 | ||
31 | static int w1_check_family(struct w1_family *f) | 32 | static int w1_check_family(struct w1_family *f) |
32 | { | 33 | { |
33 | if (!f->fops->rname || !f->fops->rbin || !f->fops->rval || !f->fops->rvalname) | 34 | if (!f->fops->rname || !f->fops->rbin) |
34 | return -EINVAL; | 35 | return -EINVAL; |
35 | 36 | ||
36 | return 0; | 37 | return 0; |
@@ -60,9 +61,10 @@ int w1_register_family(struct w1_family *newf) | |||
60 | newf->need_exit = 0; | 61 | newf->need_exit = 0; |
61 | list_add_tail(&newf->family_entry, &w1_families); | 62 | list_add_tail(&newf->family_entry, &w1_families); |
62 | } | 63 | } |
63 | |||
64 | spin_unlock(&w1_flock); | 64 | spin_unlock(&w1_flock); |
65 | 65 | ||
66 | w1_reconnect_slaves(newf); | ||
67 | |||
66 | return ret; | 68 | return ret; |
67 | } | 69 | } |
68 | 70 | ||
diff --git a/drivers/w1/w1_family.h b/drivers/w1/w1_family.h index 07fa49412a90..b26da01bbc38 100644 --- a/drivers/w1/w1_family.h +++ b/drivers/w1/w1_family.h | |||
@@ -1,8 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * w1_family.h | 2 | * w1_family.h |
3 | * | 3 | * |
4 | * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru> | 4 | * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru> |
5 | * | 5 | * |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by | 8 | * it under the terms of the GNU General Public License as published by |
@@ -27,8 +27,11 @@ | |||
27 | #include <asm/atomic.h> | 27 | #include <asm/atomic.h> |
28 | 28 | ||
29 | #define W1_FAMILY_DEFAULT 0 | 29 | #define W1_FAMILY_DEFAULT 0 |
30 | #define W1_FAMILY_THERM 0x10 | 30 | #define W1_FAMILY_SMEM_01 0x01 |
31 | #define W1_FAMILY_SMEM 0x01 | 31 | #define W1_FAMILY_SMEM_81 0x81 |
32 | #define W1_THERM_DS18S20 0x10 | ||
33 | #define W1_THERM_DS1822 0x22 | ||
34 | #define W1_THERM_DS18B20 0x28 | ||
32 | 35 | ||
33 | #define MAXNAMELEN 32 | 36 | #define MAXNAMELEN 32 |
34 | 37 | ||
@@ -36,18 +39,15 @@ struct w1_family_ops | |||
36 | { | 39 | { |
37 | ssize_t (* rname)(struct device *, struct device_attribute *, char *); | 40 | ssize_t (* rname)(struct device *, struct device_attribute *, char *); |
38 | ssize_t (* rbin)(struct kobject *, char *, loff_t, size_t); | 41 | ssize_t (* rbin)(struct kobject *, char *, loff_t, size_t); |
39 | |||
40 | ssize_t (* rval)(struct device *, struct device_attribute *, char *); | ||
41 | unsigned char rvalname[MAXNAMELEN]; | ||
42 | }; | 42 | }; |
43 | 43 | ||
44 | struct w1_family | 44 | struct w1_family |
45 | { | 45 | { |
46 | struct list_head family_entry; | 46 | struct list_head family_entry; |
47 | u8 fid; | 47 | u8 fid; |
48 | 48 | ||
49 | struct w1_family_ops *fops; | 49 | struct w1_family_ops *fops; |
50 | 50 | ||
51 | atomic_t refcnt; | 51 | atomic_t refcnt; |
52 | u8 need_exit; | 52 | u8 need_exit; |
53 | }; | 53 | }; |
diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c index 5f0bafbbd575..35e85d961702 100644 --- a/drivers/w1/w1_int.c +++ b/drivers/w1/w1_int.c | |||
@@ -1,8 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * w1_int.c | 2 | * w1_int.c |
3 | * | 3 | * |
4 | * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru> | 4 | * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru> |
5 | * | 5 | * |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by | 8 | * it under the terms of the GNU General Public License as published by |
@@ -39,8 +39,9 @@ extern spinlock_t w1_mlock; | |||
39 | 39 | ||
40 | extern int w1_process(void *); | 40 | extern int w1_process(void *); |
41 | 41 | ||
42 | struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl, | 42 | static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl, |
43 | struct device_driver *driver, struct device *device) | 43 | struct device_driver *driver, |
44 | struct device *device) | ||
44 | { | 45 | { |
45 | struct w1_master *dev; | 46 | struct w1_master *dev; |
46 | int err; | 47 | int err; |
@@ -60,14 +61,15 @@ struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl, | |||
60 | 61 | ||
61 | dev->bus_master = (struct w1_bus_master *)(dev + 1); | 62 | dev->bus_master = (struct w1_bus_master *)(dev + 1); |
62 | 63 | ||
63 | dev->owner = THIS_MODULE; | 64 | dev->owner = THIS_MODULE; |
64 | dev->max_slave_count = slave_count; | 65 | dev->max_slave_count = slave_count; |
65 | dev->slave_count = 0; | 66 | dev->slave_count = 0; |
66 | dev->attempts = 0; | 67 | dev->attempts = 0; |
67 | dev->kpid = -1; | 68 | dev->kpid = -1; |
68 | dev->initialized = 0; | 69 | dev->initialized = 0; |
69 | dev->id = id; | 70 | dev->id = id; |
70 | dev->slave_ttl = slave_ttl; | 71 | dev->slave_ttl = slave_ttl; |
72 | dev->search_count = -1; /* continual scan */ | ||
71 | 73 | ||
72 | atomic_set(&dev->refcnt, 2); | 74 | atomic_set(&dev->refcnt, 2); |
73 | 75 | ||
@@ -105,7 +107,7 @@ struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl, | |||
105 | return dev; | 107 | return dev; |
106 | } | 108 | } |
107 | 109 | ||
108 | void w1_free_dev(struct w1_master *dev) | 110 | static void w1_free_dev(struct w1_master *dev) |
109 | { | 111 | { |
110 | device_unregister(&dev->dev); | 112 | device_unregister(&dev->dev); |
111 | if (dev->nls && dev->nls->sk_socket) | 113 | if (dev->nls && dev->nls->sk_socket) |
@@ -120,6 +122,13 @@ int w1_add_master_device(struct w1_bus_master *master) | |||
120 | int retval = 0; | 122 | int retval = 0; |
121 | struct w1_netlink_msg msg; | 123 | struct w1_netlink_msg msg; |
122 | 124 | ||
125 | /* validate minimum functionality */ | ||
126 | if (!(master->touch_bit && master->reset_bus) && | ||
127 | !(master->write_bit && master->read_bit)) { | ||
128 | printk(KERN_ERR "w1_add_master_device: invalid function set\n"); | ||
129 | return(-EINVAL); | ||
130 | } | ||
131 | |||
123 | dev = w1_alloc_dev(w1_ids++, w1_max_slave_count, w1_max_slave_ttl, &w1_driver, &w1_device); | 132 | dev = w1_alloc_dev(w1_ids++, w1_max_slave_count, w1_max_slave_ttl, &w1_driver, &w1_device); |
124 | if (!dev) | 133 | if (!dev) |
125 | return -ENOMEM; | 134 | return -ENOMEM; |
@@ -153,7 +162,7 @@ int w1_add_master_device(struct w1_bus_master *master) | |||
153 | return 0; | 162 | return 0; |
154 | 163 | ||
155 | err_out_kill_thread: | 164 | err_out_kill_thread: |
156 | dev->need_exit = 1; | 165 | set_bit(W1_MASTER_NEED_EXIT, &dev->flags); |
157 | if (kill_proc(dev->kpid, SIGTERM, 1)) | 166 | if (kill_proc(dev->kpid, SIGTERM, 1)) |
158 | dev_err(&dev->dev, | 167 | dev_err(&dev->dev, |
159 | "Failed to send signal to w1 kernel thread %d.\n", | 168 | "Failed to send signal to w1 kernel thread %d.\n", |
@@ -171,7 +180,7 @@ void __w1_remove_master_device(struct w1_master *dev) | |||
171 | int err; | 180 | int err; |
172 | struct w1_netlink_msg msg; | 181 | struct w1_netlink_msg msg; |
173 | 182 | ||
174 | dev->need_exit = 1; | 183 | set_bit(W1_MASTER_NEED_EXIT, &dev->flags); |
175 | err = kill_proc(dev->kpid, SIGTERM, 1); | 184 | err = kill_proc(dev->kpid, SIGTERM, 1); |
176 | if (err) | 185 | if (err) |
177 | dev_err(&dev->dev, | 186 | dev_err(&dev->dev, |
@@ -197,10 +206,8 @@ void __w1_remove_master_device(struct w1_master *dev) | |||
197 | void w1_remove_master_device(struct w1_bus_master *bm) | 206 | void w1_remove_master_device(struct w1_bus_master *bm) |
198 | { | 207 | { |
199 | struct w1_master *dev = NULL; | 208 | struct w1_master *dev = NULL; |
200 | struct list_head *ent, *n; | ||
201 | 209 | ||
202 | list_for_each_safe(ent, n, &w1_masters) { | 210 | list_for_each_entry(dev, &w1_masters, w1_master_entry) { |
203 | dev = list_entry(ent, struct w1_master, w1_master_entry); | ||
204 | if (!dev->initialized) | 211 | if (!dev->initialized) |
205 | continue; | 212 | continue; |
206 | 213 | ||
diff --git a/drivers/w1/w1_int.h b/drivers/w1/w1_int.h index fdb531e87faa..4274082d2262 100644 --- a/drivers/w1/w1_int.h +++ b/drivers/w1/w1_int.h | |||
@@ -1,8 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * w1_int.h | 2 | * w1_int.h |
3 | * | 3 | * |
4 | * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru> | 4 | * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru> |
5 | * | 5 | * |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by | 8 | * it under the terms of the GNU General Public License as published by |
@@ -27,8 +27,6 @@ | |||
27 | 27 | ||
28 | #include "w1.h" | 28 | #include "w1.h" |
29 | 29 | ||
30 | struct w1_master * w1_alloc_dev(u32, int, int, struct device_driver *, struct device *); | ||
31 | void w1_free_dev(struct w1_master *dev); | ||
32 | int w1_add_master_device(struct w1_bus_master *); | 30 | int w1_add_master_device(struct w1_bus_master *); |
33 | void w1_remove_master_device(struct w1_bus_master *); | 31 | void w1_remove_master_device(struct w1_bus_master *); |
34 | void __w1_remove_master_device(struct w1_master *); | 32 | void __w1_remove_master_device(struct w1_master *); |
diff --git a/drivers/w1/w1_io.c b/drivers/w1/w1_io.c index 02796b5a39f6..00f032220173 100644 --- a/drivers/w1/w1_io.c +++ b/drivers/w1/w1_io.c | |||
@@ -1,8 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * w1_io.c | 2 | * w1_io.c |
3 | * | 3 | * |
4 | * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru> | 4 | * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru> |
5 | * | 5 | * |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by | 8 | * it under the terms of the GNU General Public License as published by |
@@ -55,15 +55,29 @@ void w1_delay(unsigned long tm) | |||
55 | udelay(tm * w1_delay_parm); | 55 | udelay(tm * w1_delay_parm); |
56 | } | 56 | } |
57 | 57 | ||
58 | static void w1_write_bit(struct w1_master *dev, int bit); | ||
59 | static u8 w1_read_bit(struct w1_master *dev); | ||
60 | |||
61 | /** | ||
62 | * Generates a write-0 or write-1 cycle and samples the level. | ||
63 | */ | ||
58 | u8 w1_touch_bit(struct w1_master *dev, int bit) | 64 | u8 w1_touch_bit(struct w1_master *dev, int bit) |
59 | { | 65 | { |
60 | if (dev->bus_master->touch_bit) | 66 | if (dev->bus_master->touch_bit) |
61 | return dev->bus_master->touch_bit(dev->bus_master->data, bit); | 67 | return dev->bus_master->touch_bit(dev->bus_master->data, bit); |
62 | else | 68 | else if (bit) |
63 | return w1_read_bit(dev); | 69 | return w1_read_bit(dev); |
70 | else { | ||
71 | w1_write_bit(dev, 0); | ||
72 | return(0); | ||
73 | } | ||
64 | } | 74 | } |
65 | 75 | ||
66 | void w1_write_bit(struct w1_master *dev, int bit) | 76 | /** |
77 | * Generates a write-0 or write-1 cycle. | ||
78 | * Only call if dev->bus_master->touch_bit is NULL | ||
79 | */ | ||
80 | static void w1_write_bit(struct w1_master *dev, int bit) | ||
67 | { | 81 | { |
68 | if (bit) { | 82 | if (bit) { |
69 | dev->bus_master->write_bit(dev->bus_master->data, 0); | 83 | dev->bus_master->write_bit(dev->bus_master->data, 0); |
@@ -78,6 +92,12 @@ void w1_write_bit(struct w1_master *dev, int bit) | |||
78 | } | 92 | } |
79 | } | 93 | } |
80 | 94 | ||
95 | /** | ||
96 | * Writes 8 bits. | ||
97 | * | ||
98 | * @param dev the master device | ||
99 | * @param byte the byte to write | ||
100 | */ | ||
81 | void w1_write_8(struct w1_master *dev, u8 byte) | 101 | void w1_write_8(struct w1_master *dev, u8 byte) |
82 | { | 102 | { |
83 | int i; | 103 | int i; |
@@ -86,10 +106,15 @@ void w1_write_8(struct w1_master *dev, u8 byte) | |||
86 | dev->bus_master->write_byte(dev->bus_master->data, byte); | 106 | dev->bus_master->write_byte(dev->bus_master->data, byte); |
87 | else | 107 | else |
88 | for (i = 0; i < 8; ++i) | 108 | for (i = 0; i < 8; ++i) |
89 | w1_write_bit(dev, (byte >> i) & 0x1); | 109 | w1_touch_bit(dev, (byte >> i) & 0x1); |
90 | } | 110 | } |
91 | 111 | ||
92 | u8 w1_read_bit(struct w1_master *dev) | 112 | |
113 | /** | ||
114 | * Generates a write-1 cycle and samples the level. | ||
115 | * Only call if dev->bus_master->touch_bit is NULL | ||
116 | */ | ||
117 | static u8 w1_read_bit(struct w1_master *dev) | ||
93 | { | 118 | { |
94 | int result; | 119 | int result; |
95 | 120 | ||
@@ -104,6 +129,53 @@ u8 w1_read_bit(struct w1_master *dev) | |||
104 | return result & 0x1; | 129 | return result & 0x1; |
105 | } | 130 | } |
106 | 131 | ||
132 | /** | ||
133 | * Does a triplet - used for searching ROM addresses. | ||
134 | * Return bits: | ||
135 | * bit 0 = id_bit | ||
136 | * bit 1 = comp_bit | ||
137 | * bit 2 = dir_taken | ||
138 | * If both bits 0 & 1 are set, the search should be restarted. | ||
139 | * | ||
140 | * @param dev the master device | ||
141 | * @param bdir the bit to write if both id_bit and comp_bit are 0 | ||
142 | * @return bit fields - see above | ||
143 | */ | ||
144 | u8 w1_triplet(struct w1_master *dev, int bdir) | ||
145 | { | ||
146 | if ( dev->bus_master->triplet ) | ||
147 | return(dev->bus_master->triplet(dev->bus_master->data, bdir)); | ||
148 | else { | ||
149 | u8 id_bit = w1_touch_bit(dev, 1); | ||
150 | u8 comp_bit = w1_touch_bit(dev, 1); | ||
151 | u8 retval; | ||
152 | |||
153 | if ( id_bit && comp_bit ) | ||
154 | return(0x03); /* error */ | ||
155 | |||
156 | if ( !id_bit && !comp_bit ) { | ||
157 | /* Both bits are valid, take the direction given */ | ||
158 | retval = bdir ? 0x04 : 0; | ||
159 | } else { | ||
160 | /* Only one bit is valid, take that direction */ | ||
161 | bdir = id_bit; | ||
162 | retval = id_bit ? 0x05 : 0x02; | ||
163 | } | ||
164 | |||
165 | if ( dev->bus_master->touch_bit ) | ||
166 | w1_touch_bit(dev, bdir); | ||
167 | else | ||
168 | w1_write_bit(dev, bdir); | ||
169 | return(retval); | ||
170 | } | ||
171 | } | ||
172 | |||
173 | /** | ||
174 | * Reads 8 bits. | ||
175 | * | ||
176 | * @param dev the master device | ||
177 | * @return the byte read | ||
178 | */ | ||
107 | u8 w1_read_8(struct w1_master * dev) | 179 | u8 w1_read_8(struct w1_master * dev) |
108 | { | 180 | { |
109 | int i; | 181 | int i; |
@@ -113,12 +185,20 @@ u8 w1_read_8(struct w1_master * dev) | |||
113 | res = dev->bus_master->read_byte(dev->bus_master->data); | 185 | res = dev->bus_master->read_byte(dev->bus_master->data); |
114 | else | 186 | else |
115 | for (i = 0; i < 8; ++i) | 187 | for (i = 0; i < 8; ++i) |
116 | res |= (w1_read_bit(dev) << i); | 188 | res |= (w1_touch_bit(dev,1) << i); |
117 | 189 | ||
118 | return res; | 190 | return res; |
119 | } | 191 | } |
120 | 192 | ||
121 | void w1_write_block(struct w1_master *dev, u8 *buf, int len) | 193 | /** |
194 | * Writes a series of bytes. | ||
195 | * | ||
196 | * @param dev the master device | ||
197 | * @param buf pointer to the data to write | ||
198 | * @param len the number of bytes to write | ||
199 | * @return the byte read | ||
200 | */ | ||
201 | void w1_write_block(struct w1_master *dev, const u8 *buf, int len) | ||
122 | { | 202 | { |
123 | int i; | 203 | int i; |
124 | 204 | ||
@@ -129,6 +209,14 @@ void w1_write_block(struct w1_master *dev, u8 *buf, int len) | |||
129 | w1_write_8(dev, buf[i]); | 209 | w1_write_8(dev, buf[i]); |
130 | } | 210 | } |
131 | 211 | ||
212 | /** | ||
213 | * Reads a series of bytes. | ||
214 | * | ||
215 | * @param dev the master device | ||
216 | * @param buf pointer to the buffer to fill | ||
217 | * @param len the number of bytes to read | ||
218 | * @return the number of bytes read | ||
219 | */ | ||
132 | u8 w1_read_block(struct w1_master *dev, u8 *buf, int len) | 220 | u8 w1_read_block(struct w1_master *dev, u8 *buf, int len) |
133 | { | 221 | { |
134 | int i; | 222 | int i; |
@@ -145,9 +233,15 @@ u8 w1_read_block(struct w1_master *dev, u8 *buf, int len) | |||
145 | return ret; | 233 | return ret; |
146 | } | 234 | } |
147 | 235 | ||
236 | /** | ||
237 | * Issues a reset bus sequence. | ||
238 | * | ||
239 | * @param dev The bus master pointer | ||
240 | * @return 0=Device present, 1=No device present or error | ||
241 | */ | ||
148 | int w1_reset_bus(struct w1_master *dev) | 242 | int w1_reset_bus(struct w1_master *dev) |
149 | { | 243 | { |
150 | int result = 0; | 244 | int result; |
151 | 245 | ||
152 | if (dev->bus_master->reset_bus) | 246 | if (dev->bus_master->reset_bus) |
153 | result = dev->bus_master->reset_bus(dev->bus_master->data) & 0x1; | 247 | result = dev->bus_master->reset_bus(dev->bus_master->data) & 0x1; |
@@ -180,12 +274,11 @@ void w1_search_devices(struct w1_master *dev, w1_slave_found_callback cb) | |||
180 | if (dev->bus_master->search) | 274 | if (dev->bus_master->search) |
181 | dev->bus_master->search(dev->bus_master->data, cb); | 275 | dev->bus_master->search(dev->bus_master->data, cb); |
182 | else | 276 | else |
183 | w1_search(dev); | 277 | w1_search(dev, cb); |
184 | } | 278 | } |
185 | 279 | ||
186 | EXPORT_SYMBOL(w1_write_bit); | 280 | EXPORT_SYMBOL(w1_touch_bit); |
187 | EXPORT_SYMBOL(w1_write_8); | 281 | EXPORT_SYMBOL(w1_write_8); |
188 | EXPORT_SYMBOL(w1_read_bit); | ||
189 | EXPORT_SYMBOL(w1_read_8); | 282 | EXPORT_SYMBOL(w1_read_8); |
190 | EXPORT_SYMBOL(w1_reset_bus); | 283 | EXPORT_SYMBOL(w1_reset_bus); |
191 | EXPORT_SYMBOL(w1_calc_crc8); | 284 | EXPORT_SYMBOL(w1_calc_crc8); |
diff --git a/drivers/w1/w1_io.h b/drivers/w1/w1_io.h index 6c573005a712..af5829778aaa 100644 --- a/drivers/w1/w1_io.h +++ b/drivers/w1/w1_io.h | |||
@@ -1,8 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * w1_io.h | 2 | * w1_io.h |
3 | * | 3 | * |
4 | * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru> | 4 | * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru> |
5 | * | 5 | * |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by | 8 | * it under the terms of the GNU General Public License as published by |
@@ -26,13 +26,12 @@ | |||
26 | 26 | ||
27 | void w1_delay(unsigned long); | 27 | void w1_delay(unsigned long); |
28 | u8 w1_touch_bit(struct w1_master *, int); | 28 | u8 w1_touch_bit(struct w1_master *, int); |
29 | void w1_write_bit(struct w1_master *, int); | 29 | u8 w1_triplet(struct w1_master *dev, int bdir); |
30 | void w1_write_8(struct w1_master *, u8); | 30 | void w1_write_8(struct w1_master *, u8); |
31 | u8 w1_read_bit(struct w1_master *); | ||
32 | u8 w1_read_8(struct w1_master *); | 31 | u8 w1_read_8(struct w1_master *); |
33 | int w1_reset_bus(struct w1_master *); | 32 | int w1_reset_bus(struct w1_master *); |
34 | u8 w1_calc_crc8(u8 *, int); | 33 | u8 w1_calc_crc8(u8 *, int); |
35 | void w1_write_block(struct w1_master *, u8 *, int); | 34 | void w1_write_block(struct w1_master *, const u8 *, int); |
36 | u8 w1_read_block(struct w1_master *, u8 *, int); | 35 | u8 w1_read_block(struct w1_master *, u8 *, int); |
37 | void w1_search_devices(struct w1_master *dev, w1_slave_found_callback cb); | 36 | void w1_search_devices(struct w1_master *dev, w1_slave_found_callback cb); |
38 | 37 | ||
diff --git a/drivers/w1/w1_log.h b/drivers/w1/w1_log.h index a6bf6f44dce2..fe6bdf43380f 100644 --- a/drivers/w1/w1_log.h +++ b/drivers/w1/w1_log.h | |||
@@ -1,8 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * w1_log.h | 2 | * w1_log.h |
3 | * | 3 | * |
4 | * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru> | 4 | * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru> |
5 | * | 5 | * |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by | 8 | * it under the terms of the GNU General Public License as published by |
diff --git a/drivers/w1/w1_netlink.h b/drivers/w1/w1_netlink.h index ea1b530abad0..8615756946df 100644 --- a/drivers/w1/w1_netlink.h +++ b/drivers/w1/w1_netlink.h | |||
@@ -33,13 +33,13 @@ enum w1_netlink_message_types { | |||
33 | W1_MASTER_REMOVE, | 33 | W1_MASTER_REMOVE, |
34 | }; | 34 | }; |
35 | 35 | ||
36 | struct w1_netlink_msg | 36 | struct w1_netlink_msg |
37 | { | 37 | { |
38 | __u8 type; | 38 | __u8 type; |
39 | __u8 reserved[3]; | 39 | __u8 reserved[3]; |
40 | union | 40 | union |
41 | { | 41 | { |
42 | struct w1_reg_num id; | 42 | struct w1_reg_num id; |
43 | __u64 w1_id; | 43 | __u64 w1_id; |
44 | struct | 44 | struct |
45 | { | 45 | { |
diff --git a/drivers/w1/w1_smem.c b/drivers/w1/w1_smem.c index 674eb75a9bad..70d2d469963c 100644 --- a/drivers/w1/w1_smem.c +++ b/drivers/w1/w1_smem.c | |||
@@ -1,8 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * w1_smem.c | 2 | * w1_smem.c |
3 | * | 3 | * |
4 | * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru> | 4 | * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru> |
5 | * | 5 | * |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the smems of the GNU General Public License as published by | 8 | * it under the smems of the GNU General Public License as published by |
@@ -37,14 +37,11 @@ MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>"); | |||
37 | MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol, 64bit memory family."); | 37 | MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol, 64bit memory family."); |
38 | 38 | ||
39 | static ssize_t w1_smem_read_name(struct device *, struct device_attribute *attr, char *); | 39 | static ssize_t w1_smem_read_name(struct device *, struct device_attribute *attr, char *); |
40 | static ssize_t w1_smem_read_val(struct device *, struct device_attribute *attr, char *); | ||
41 | static ssize_t w1_smem_read_bin(struct kobject *, char *, loff_t, size_t); | 40 | static ssize_t w1_smem_read_bin(struct kobject *, char *, loff_t, size_t); |
42 | 41 | ||
43 | static struct w1_family_ops w1_smem_fops = { | 42 | static struct w1_family_ops w1_smem_fops = { |
44 | .rname = &w1_smem_read_name, | 43 | .rname = &w1_smem_read_name, |
45 | .rbin = &w1_smem_read_bin, | 44 | .rbin = &w1_smem_read_bin, |
46 | .rval = &w1_smem_read_val, | ||
47 | .rvalname = "id", | ||
48 | }; | 45 | }; |
49 | 46 | ||
50 | static ssize_t w1_smem_read_name(struct device *dev, struct device_attribute *attr, char *buf) | 47 | static ssize_t w1_smem_read_name(struct device *dev, struct device_attribute *attr, char *buf) |
@@ -54,23 +51,10 @@ static ssize_t w1_smem_read_name(struct device *dev, struct device_attribute *at | |||
54 | return sprintf(buf, "%s\n", sl->name); | 51 | return sprintf(buf, "%s\n", sl->name); |
55 | } | 52 | } |
56 | 53 | ||
57 | static ssize_t w1_smem_read_val(struct device *dev, struct device_attribute *attr, char *buf) | ||
58 | { | ||
59 | struct w1_slave *sl = container_of(dev, struct w1_slave, dev); | ||
60 | int i; | ||
61 | ssize_t count = 0; | ||
62 | |||
63 | for (i = 0; i < 8; ++i) | ||
64 | count += sprintf(buf + count, "%02x ", ((u8 *)&sl->reg_num)[i]); | ||
65 | count += sprintf(buf + count, "\n"); | ||
66 | |||
67 | return count; | ||
68 | } | ||
69 | |||
70 | static ssize_t w1_smem_read_bin(struct kobject *kobj, char *buf, loff_t off, size_t count) | 54 | static ssize_t w1_smem_read_bin(struct kobject *kobj, char *buf, loff_t off, size_t count) |
71 | { | 55 | { |
72 | struct w1_slave *sl = container_of(container_of(kobj, struct device, kobj), | 56 | struct w1_slave *sl = container_of(container_of(kobj, struct device, kobj), |
73 | struct w1_slave, dev); | 57 | struct w1_slave, dev); |
74 | int i; | 58 | int i; |
75 | 59 | ||
76 | atomic_inc(&sl->refcnt); | 60 | atomic_inc(&sl->refcnt); |
@@ -90,7 +74,7 @@ static ssize_t w1_smem_read_bin(struct kobject *kobj, char *buf, loff_t off, siz | |||
90 | for (i = 0; i < 8; ++i) | 74 | for (i = 0; i < 8; ++i) |
91 | count += sprintf(buf + count, "%02x ", ((u8 *)&sl->reg_num)[i]); | 75 | count += sprintf(buf + count, "%02x ", ((u8 *)&sl->reg_num)[i]); |
92 | count += sprintf(buf + count, "\n"); | 76 | count += sprintf(buf + count, "\n"); |
93 | 77 | ||
94 | out: | 78 | out: |
95 | up(&sl->master->mutex); | 79 | up(&sl->master->mutex); |
96 | out_dec: | 80 | out_dec: |
@@ -99,19 +83,37 @@ out_dec: | |||
99 | return count; | 83 | return count; |
100 | } | 84 | } |
101 | 85 | ||
102 | static struct w1_family w1_smem_family = { | 86 | static struct w1_family w1_smem_family_01 = { |
103 | .fid = W1_FAMILY_SMEM, | 87 | .fid = W1_FAMILY_SMEM_01, |
88 | .fops = &w1_smem_fops, | ||
89 | }; | ||
90 | |||
91 | static struct w1_family w1_smem_family_81 = { | ||
92 | .fid = W1_FAMILY_SMEM_81, | ||
104 | .fops = &w1_smem_fops, | 93 | .fops = &w1_smem_fops, |
105 | }; | 94 | }; |
106 | 95 | ||
107 | static int __init w1_smem_init(void) | 96 | static int __init w1_smem_init(void) |
108 | { | 97 | { |
109 | return w1_register_family(&w1_smem_family); | 98 | int err; |
99 | |||
100 | err = w1_register_family(&w1_smem_family_01); | ||
101 | if (err) | ||
102 | return err; | ||
103 | |||
104 | err = w1_register_family(&w1_smem_family_81); | ||
105 | if (err) { | ||
106 | w1_unregister_family(&w1_smem_family_01); | ||
107 | return err; | ||
108 | } | ||
109 | |||
110 | return 0; | ||
110 | } | 111 | } |
111 | 112 | ||
112 | static void __exit w1_smem_fini(void) | 113 | static void __exit w1_smem_fini(void) |
113 | { | 114 | { |
114 | w1_unregister_family(&w1_smem_family); | 115 | w1_unregister_family(&w1_smem_family_01); |
116 | w1_unregister_family(&w1_smem_family_81); | ||
115 | } | 117 | } |
116 | 118 | ||
117 | module_init(w1_smem_init); | 119 | module_init(w1_smem_init); |
diff --git a/drivers/w1/w1_therm.c b/drivers/w1/w1_therm.c index 70310f7a722e..165526c9360a 100644 --- a/drivers/w1/w1_therm.c +++ b/drivers/w1/w1_therm.c | |||
@@ -1,8 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * w1_therm.c | 2 | * w1_therm.c |
3 | * | 3 | * |
4 | * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru> | 4 | * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru> |
5 | * | 5 | * |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the therms of the GNU General Public License as published by | 8 | * it under the therms of the GNU General Public License as published by |
@@ -38,19 +38,56 @@ MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>"); | |||
38 | MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol, temperature family."); | 38 | MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol, temperature family."); |
39 | 39 | ||
40 | static u8 bad_roms[][9] = { | 40 | static u8 bad_roms[][9] = { |
41 | {0xaa, 0x00, 0x4b, 0x46, 0xff, 0xff, 0x0c, 0x10, 0x87}, | 41 | {0xaa, 0x00, 0x4b, 0x46, 0xff, 0xff, 0x0c, 0x10, 0x87}, |
42 | {} | 42 | {} |
43 | }; | 43 | }; |
44 | 44 | ||
45 | static ssize_t w1_therm_read_name(struct device *, struct device_attribute *attr, char *); | 45 | static ssize_t w1_therm_read_name(struct device *, struct device_attribute *attr, char *); |
46 | static ssize_t w1_therm_read_temp(struct device *, struct device_attribute *attr, char *); | ||
47 | static ssize_t w1_therm_read_bin(struct kobject *, char *, loff_t, size_t); | 46 | static ssize_t w1_therm_read_bin(struct kobject *, char *, loff_t, size_t); |
48 | 47 | ||
49 | static struct w1_family_ops w1_therm_fops = { | 48 | static struct w1_family_ops w1_therm_fops = { |
50 | .rname = &w1_therm_read_name, | 49 | .rname = &w1_therm_read_name, |
51 | .rbin = &w1_therm_read_bin, | 50 | .rbin = &w1_therm_read_bin, |
52 | .rval = &w1_therm_read_temp, | 51 | }; |
53 | .rvalname = "temp1_input", | 52 | |
53 | static struct w1_family w1_therm_family_DS18S20 = { | ||
54 | .fid = W1_THERM_DS18S20, | ||
55 | .fops = &w1_therm_fops, | ||
56 | }; | ||
57 | |||
58 | static struct w1_family w1_therm_family_DS18B20 = { | ||
59 | .fid = W1_THERM_DS18B20, | ||
60 | .fops = &w1_therm_fops, | ||
61 | }; | ||
62 | static struct w1_family w1_therm_family_DS1822 = { | ||
63 | .fid = W1_THERM_DS1822, | ||
64 | .fops = &w1_therm_fops, | ||
65 | }; | ||
66 | |||
67 | struct w1_therm_family_converter | ||
68 | { | ||
69 | u8 broken; | ||
70 | u16 reserved; | ||
71 | struct w1_family *f; | ||
72 | int (*convert)(u8 rom[9]); | ||
73 | }; | ||
74 | |||
75 | static inline int w1_DS18B20_convert_temp(u8 rom[9]); | ||
76 | static inline int w1_DS18S20_convert_temp(u8 rom[9]); | ||
77 | |||
78 | static struct w1_therm_family_converter w1_therm_families[] = { | ||
79 | { | ||
80 | .f = &w1_therm_family_DS18S20, | ||
81 | .convert = w1_DS18S20_convert_temp | ||
82 | }, | ||
83 | { | ||
84 | .f = &w1_therm_family_DS1822, | ||
85 | .convert = w1_DS18B20_convert_temp | ||
86 | }, | ||
87 | { | ||
88 | .f = &w1_therm_family_DS18B20, | ||
89 | .convert = w1_DS18B20_convert_temp | ||
90 | }, | ||
54 | }; | 91 | }; |
55 | 92 | ||
56 | static ssize_t w1_therm_read_name(struct device *dev, struct device_attribute *attr, char *buf) | 93 | static ssize_t w1_therm_read_name(struct device *dev, struct device_attribute *attr, char *buf) |
@@ -60,9 +97,19 @@ static ssize_t w1_therm_read_name(struct device *dev, struct device_attribute *a | |||
60 | return sprintf(buf, "%s\n", sl->name); | 97 | return sprintf(buf, "%s\n", sl->name); |
61 | } | 98 | } |
62 | 99 | ||
63 | static inline int w1_convert_temp(u8 rom[9]) | 100 | static inline int w1_DS18B20_convert_temp(u8 rom[9]) |
101 | { | ||
102 | int t = (rom[1] << 8) | rom[0]; | ||
103 | t /= 16; | ||
104 | return t; | ||
105 | } | ||
106 | |||
107 | static inline int w1_DS18S20_convert_temp(u8 rom[9]) | ||
64 | { | 108 | { |
65 | int t, h; | 109 | int t, h; |
110 | |||
111 | if (!rom[7]) | ||
112 | return 0; | ||
66 | 113 | ||
67 | if (rom[1] == 0) | 114 | if (rom[1] == 0) |
68 | t = ((s32)rom[0] >> 1)*1000; | 115 | t = ((s32)rom[0] >> 1)*1000; |
@@ -77,11 +124,15 @@ static inline int w1_convert_temp(u8 rom[9]) | |||
77 | return t; | 124 | return t; |
78 | } | 125 | } |
79 | 126 | ||
80 | static ssize_t w1_therm_read_temp(struct device *dev, struct device_attribute *attr, char *buf) | 127 | static inline int w1_convert_temp(u8 rom[9], u8 fid) |
81 | { | 128 | { |
82 | struct w1_slave *sl = container_of(dev, struct w1_slave, dev); | 129 | int i; |
130 | |||
131 | for (i=0; i<sizeof(w1_therm_families)/sizeof(w1_therm_families[0]); ++i) | ||
132 | if (w1_therm_families[i].f->fid == fid) | ||
133 | return w1_therm_families[i].convert(rom); | ||
83 | 134 | ||
84 | return sprintf(buf, "%d\n", w1_convert_temp(sl->rom)); | 135 | return 0; |
85 | } | 136 | } |
86 | 137 | ||
87 | static int w1_therm_check_rom(u8 rom[9]) | 138 | static int w1_therm_check_rom(u8 rom[9]) |
@@ -98,7 +149,7 @@ static int w1_therm_check_rom(u8 rom[9]) | |||
98 | static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, size_t count) | 149 | static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, size_t count) |
99 | { | 150 | { |
100 | struct w1_slave *sl = container_of(container_of(kobj, struct device, kobj), | 151 | struct w1_slave *sl = container_of(container_of(kobj, struct device, kobj), |
101 | struct w1_slave, dev); | 152 | struct w1_slave, dev); |
102 | struct w1_master *dev = sl->master; | 153 | struct w1_master *dev = sl->master; |
103 | u8 rom[9], crc, verdict; | 154 | u8 rom[9], crc, verdict; |
104 | int i, max_trying = 10; | 155 | int i, max_trying = 10; |
@@ -133,7 +184,7 @@ static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, si | |||
133 | unsigned int tm = 750; | 184 | unsigned int tm = 750; |
134 | 185 | ||
135 | memcpy(&match[1], (u64 *) & sl->reg_num, 8); | 186 | memcpy(&match[1], (u64 *) & sl->reg_num, 8); |
136 | 187 | ||
137 | w1_write_block(dev, match, 9); | 188 | w1_write_block(dev, match, 9); |
138 | 189 | ||
139 | w1_write_8(dev, W1_CONVERT_TEMP); | 190 | w1_write_8(dev, W1_CONVERT_TEMP); |
@@ -146,7 +197,7 @@ static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, si | |||
146 | 197 | ||
147 | if (!w1_reset_bus (dev)) { | 198 | if (!w1_reset_bus (dev)) { |
148 | w1_write_block(dev, match, 9); | 199 | w1_write_block(dev, match, 9); |
149 | 200 | ||
150 | w1_write_8(dev, W1_READ_SCRATCHPAD); | 201 | w1_write_8(dev, W1_READ_SCRATCHPAD); |
151 | if ((count = w1_read_block(dev, rom, 9)) != 9) { | 202 | if ((count = w1_read_block(dev, rom, 9)) != 9) { |
152 | dev_warn(&dev->dev, "w1_read_block() returned %d instead of 9.\n", count); | 203 | dev_warn(&dev->dev, "w1_read_block() returned %d instead of 9.\n", count); |
@@ -176,7 +227,7 @@ static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, si | |||
176 | for (i = 0; i < 9; ++i) | 227 | for (i = 0; i < 9; ++i) |
177 | count += sprintf(buf + count, "%02x ", sl->rom[i]); | 228 | count += sprintf(buf + count, "%02x ", sl->rom[i]); |
178 | 229 | ||
179 | count += sprintf(buf + count, "t=%d\n", w1_convert_temp(rom)); | 230 | count += sprintf(buf + count, "t=%d\n", w1_convert_temp(rom, sl->family->fid)); |
180 | out: | 231 | out: |
181 | up(&dev->mutex); | 232 | up(&dev->mutex); |
182 | out_dec: | 233 | out_dec: |
@@ -186,19 +237,26 @@ out_dec: | |||
186 | return count; | 237 | return count; |
187 | } | 238 | } |
188 | 239 | ||
189 | static struct w1_family w1_therm_family = { | ||
190 | .fid = W1_FAMILY_THERM, | ||
191 | .fops = &w1_therm_fops, | ||
192 | }; | ||
193 | |||
194 | static int __init w1_therm_init(void) | 240 | static int __init w1_therm_init(void) |
195 | { | 241 | { |
196 | return w1_register_family(&w1_therm_family); | 242 | int err, i; |
243 | |||
244 | for (i=0; i<sizeof(w1_therm_families)/sizeof(w1_therm_families[0]); ++i) { | ||
245 | err = w1_register_family(w1_therm_families[i].f); | ||
246 | if (err) | ||
247 | w1_therm_families[i].broken = 1; | ||
248 | } | ||
249 | |||
250 | return 0; | ||
197 | } | 251 | } |
198 | 252 | ||
199 | static void __exit w1_therm_fini(void) | 253 | static void __exit w1_therm_fini(void) |
200 | { | 254 | { |
201 | w1_unregister_family(&w1_therm_family); | 255 | int i; |
256 | |||
257 | for (i=0; i<sizeof(w1_therm_families)/sizeof(w1_therm_families[0]); ++i) | ||
258 | if (!w1_therm_families[i].broken) | ||
259 | w1_unregister_family(w1_therm_families[i].f); | ||
202 | } | 260 | } |
203 | 261 | ||
204 | module_init(w1_therm_init); | 262 | module_init(w1_therm_init); |
diff --git a/fs/Kconfig b/fs/Kconfig index 178e27494b74..a7c0cc3203cb 100644 --- a/fs/Kconfig +++ b/fs/Kconfig | |||
@@ -1268,6 +1268,7 @@ config NFS_FS | |||
1268 | depends on INET | 1268 | depends on INET |
1269 | select LOCKD | 1269 | select LOCKD |
1270 | select SUNRPC | 1270 | select SUNRPC |
1271 | select NFS_ACL_SUPPORT if NFS_V3_ACL | ||
1271 | help | 1272 | help |
1272 | If you are connected to some other (usually local) Unix computer | 1273 | If you are connected to some other (usually local) Unix computer |
1273 | (using SLIP, PLIP, PPP or Ethernet) and want to mount files residing | 1274 | (using SLIP, PLIP, PPP or Ethernet) and want to mount files residing |
@@ -1310,6 +1311,16 @@ config NFS_V3 | |||
1310 | 1311 | ||
1311 | If unsure, say Y. | 1312 | If unsure, say Y. |
1312 | 1313 | ||
1314 | config NFS_V3_ACL | ||
1315 | bool "Provide client support for the NFSv3 ACL protocol extension" | ||
1316 | depends on NFS_V3 | ||
1317 | help | ||
1318 | Implement the NFSv3 ACL protocol extension for manipulating POSIX | ||
1319 | Access Control Lists. The server should also be compiled with | ||
1320 | the NFSv3 ACL protocol extension; see the CONFIG_NFSD_V3_ACL option. | ||
1321 | |||
1322 | If unsure, say N. | ||
1323 | |||
1313 | config NFS_V4 | 1324 | config NFS_V4 |
1314 | bool "Provide NFSv4 client support (EXPERIMENTAL)" | 1325 | bool "Provide NFSv4 client support (EXPERIMENTAL)" |
1315 | depends on NFS_FS && EXPERIMENTAL | 1326 | depends on NFS_FS && EXPERIMENTAL |
@@ -1353,6 +1364,7 @@ config NFSD | |||
1353 | select LOCKD | 1364 | select LOCKD |
1354 | select SUNRPC | 1365 | select SUNRPC |
1355 | select EXPORTFS | 1366 | select EXPORTFS |
1367 | select NFS_ACL_SUPPORT if NFSD_V3_ACL || NFSD_V2_ACL | ||
1356 | help | 1368 | help |
1357 | If you want your Linux box to act as an NFS *server*, so that other | 1369 | If you want your Linux box to act as an NFS *server*, so that other |
1358 | computers on your local network which support NFS can access certain | 1370 | computers on your local network which support NFS can access certain |
@@ -1376,6 +1388,10 @@ config NFSD | |||
1376 | To compile the NFS server support as a module, choose M here: the | 1388 | To compile the NFS server support as a module, choose M here: the |
1377 | module will be called nfsd. If unsure, say N. | 1389 | module will be called nfsd. If unsure, say N. |
1378 | 1390 | ||
1391 | config NFSD_V2_ACL | ||
1392 | bool | ||
1393 | depends on NFSD | ||
1394 | |||
1379 | config NFSD_V3 | 1395 | config NFSD_V3 |
1380 | bool "Provide NFSv3 server support" | 1396 | bool "Provide NFSv3 server support" |
1381 | depends on NFSD | 1397 | depends on NFSD |
@@ -1383,6 +1399,16 @@ config NFSD_V3 | |||
1383 | If you would like to include the NFSv3 server as well as the NFSv2 | 1399 | If you would like to include the NFSv3 server as well as the NFSv2 |
1384 | server, say Y here. If unsure, say Y. | 1400 | server, say Y here. If unsure, say Y. |
1385 | 1401 | ||
1402 | config NFSD_V3_ACL | ||
1403 | bool "Provide server support for the NFSv3 ACL protocol extension" | ||
1404 | depends on NFSD_V3 | ||
1405 | select NFSD_V2_ACL | ||
1406 | help | ||
1407 | Implement the NFSv3 ACL protocol extension for manipulating POSIX | ||
1408 | Access Control Lists on exported file systems. NFS clients should | ||
1409 | be compiled with the NFSv3 ACL protocol extension; see the | ||
1410 | CONFIG_NFS_V3_ACL option. If unsure, say N. | ||
1411 | |||
1386 | config NFSD_V4 | 1412 | config NFSD_V4 |
1387 | bool "Provide NFSv4 server support (EXPERIMENTAL)" | 1413 | bool "Provide NFSv4 server support (EXPERIMENTAL)" |
1388 | depends on NFSD_V3 && EXPERIMENTAL | 1414 | depends on NFSD_V3 && EXPERIMENTAL |
@@ -1427,6 +1453,15 @@ config LOCKD_V4 | |||
1427 | config EXPORTFS | 1453 | config EXPORTFS |
1428 | tristate | 1454 | tristate |
1429 | 1455 | ||
1456 | config NFS_ACL_SUPPORT | ||
1457 | tristate | ||
1458 | select FS_POSIX_ACL | ||
1459 | |||
1460 | config NFS_COMMON | ||
1461 | bool | ||
1462 | depends on NFSD || NFS_FS | ||
1463 | default y | ||
1464 | |||
1430 | config SUNRPC | 1465 | config SUNRPC |
1431 | tristate | 1466 | tristate |
1432 | 1467 | ||
diff --git a/fs/Makefile b/fs/Makefile index 443f2bc56ccf..fc92e59e9faf 100644 --- a/fs/Makefile +++ b/fs/Makefile | |||
@@ -31,6 +31,7 @@ obj-$(CONFIG_BINFMT_FLAT) += binfmt_flat.o | |||
31 | 31 | ||
32 | obj-$(CONFIG_FS_MBCACHE) += mbcache.o | 32 | obj-$(CONFIG_FS_MBCACHE) += mbcache.o |
33 | obj-$(CONFIG_FS_POSIX_ACL) += posix_acl.o xattr_acl.o | 33 | obj-$(CONFIG_FS_POSIX_ACL) += posix_acl.o xattr_acl.o |
34 | obj-$(CONFIG_NFS_COMMON) += nfs_common/ | ||
34 | 35 | ||
35 | obj-$(CONFIG_QUOTA) += dquot.o | 36 | obj-$(CONFIG_QUOTA) += dquot.o |
36 | obj-$(CONFIG_QFMT_V1) += quota_v1.o | 37 | obj-$(CONFIG_QFMT_V1) += quota_v1.o |
diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c index ef7103b8c5bd..006bb9e14579 100644 --- a/fs/lockd/clntlock.c +++ b/fs/lockd/clntlock.c | |||
@@ -31,7 +31,7 @@ static int reclaimer(void *ptr); | |||
31 | * This is the representation of a blocked client lock. | 31 | * This is the representation of a blocked client lock. |
32 | */ | 32 | */ |
33 | struct nlm_wait { | 33 | struct nlm_wait { |
34 | struct nlm_wait * b_next; /* linked list */ | 34 | struct list_head b_list; /* linked list */ |
35 | wait_queue_head_t b_wait; /* where to wait on */ | 35 | wait_queue_head_t b_wait; /* where to wait on */ |
36 | struct nlm_host * b_host; | 36 | struct nlm_host * b_host; |
37 | struct file_lock * b_lock; /* local file lock */ | 37 | struct file_lock * b_lock; /* local file lock */ |
@@ -39,27 +39,54 @@ struct nlm_wait { | |||
39 | u32 b_status; /* grant callback status */ | 39 | u32 b_status; /* grant callback status */ |
40 | }; | 40 | }; |
41 | 41 | ||
42 | static struct nlm_wait * nlm_blocked; | 42 | static LIST_HEAD(nlm_blocked); |
43 | 43 | ||
44 | /* | 44 | /* |
45 | * Block on a lock | 45 | * Queue up a lock for blocking so that the GRANTED request can see it |
46 | */ | 46 | */ |
47 | int | 47 | int nlmclnt_prepare_block(struct nlm_rqst *req, struct nlm_host *host, struct file_lock *fl) |
48 | nlmclnt_block(struct nlm_host *host, struct file_lock *fl, u32 *statp) | 48 | { |
49 | struct nlm_wait *block; | ||
50 | |||
51 | BUG_ON(req->a_block != NULL); | ||
52 | block = kmalloc(sizeof(*block), GFP_KERNEL); | ||
53 | if (block == NULL) | ||
54 | return -ENOMEM; | ||
55 | block->b_host = host; | ||
56 | block->b_lock = fl; | ||
57 | init_waitqueue_head(&block->b_wait); | ||
58 | block->b_status = NLM_LCK_BLOCKED; | ||
59 | |||
60 | list_add(&block->b_list, &nlm_blocked); | ||
61 | req->a_block = block; | ||
62 | |||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | void nlmclnt_finish_block(struct nlm_rqst *req) | ||
49 | { | 67 | { |
50 | struct nlm_wait block, **head; | 68 | struct nlm_wait *block = req->a_block; |
51 | int err; | ||
52 | u32 pstate; | ||
53 | 69 | ||
54 | block.b_host = host; | 70 | if (block == NULL) |
55 | block.b_lock = fl; | 71 | return; |
56 | init_waitqueue_head(&block.b_wait); | 72 | req->a_block = NULL; |
57 | block.b_status = NLM_LCK_BLOCKED; | 73 | list_del(&block->b_list); |
58 | block.b_next = nlm_blocked; | 74 | kfree(block); |
59 | nlm_blocked = █ | 75 | } |
76 | |||
77 | /* | ||
78 | * Block on a lock | ||
79 | */ | ||
80 | long nlmclnt_block(struct nlm_rqst *req, long timeout) | ||
81 | { | ||
82 | struct nlm_wait *block = req->a_block; | ||
83 | long ret; | ||
60 | 84 | ||
61 | /* Remember pseudo nsm state */ | 85 | /* A borken server might ask us to block even if we didn't |
62 | pstate = host->h_state; | 86 | * request it. Just say no! |
87 | */ | ||
88 | if (!req->a_args.block) | ||
89 | return -EAGAIN; | ||
63 | 90 | ||
64 | /* Go to sleep waiting for GRANT callback. Some servers seem | 91 | /* Go to sleep waiting for GRANT callback. Some servers seem |
65 | * to lose callbacks, however, so we're going to poll from | 92 | * to lose callbacks, however, so we're going to poll from |
@@ -69,28 +96,16 @@ nlmclnt_block(struct nlm_host *host, struct file_lock *fl, u32 *statp) | |||
69 | * a 1 minute timeout would do. See the comment before | 96 | * a 1 minute timeout would do. See the comment before |
70 | * nlmclnt_lock for an explanation. | 97 | * nlmclnt_lock for an explanation. |
71 | */ | 98 | */ |
72 | sleep_on_timeout(&block.b_wait, 30*HZ); | 99 | ret = wait_event_interruptible_timeout(block->b_wait, |
73 | 100 | block->b_status != NLM_LCK_BLOCKED, | |
74 | for (head = &nlm_blocked; *head; head = &(*head)->b_next) { | 101 | timeout); |
75 | if (*head == &block) { | ||
76 | *head = block.b_next; | ||
77 | break; | ||
78 | } | ||
79 | } | ||
80 | 102 | ||
81 | if (!signalled()) { | 103 | if (block->b_status != NLM_LCK_BLOCKED) { |
82 | *statp = block.b_status; | 104 | req->a_res.status = block->b_status; |
83 | return 0; | 105 | block->b_status = NLM_LCK_BLOCKED; |
84 | } | 106 | } |
85 | 107 | ||
86 | /* Okay, we were interrupted. Cancel the pending request | 108 | return ret; |
87 | * unless the server has rebooted. | ||
88 | */ | ||
89 | if (pstate == host->h_state && (err = nlmclnt_cancel(host, fl)) < 0) | ||
90 | printk(KERN_NOTICE | ||
91 | "lockd: CANCEL call failed (errno %d)\n", -err); | ||
92 | |||
93 | return -ERESTARTSYS; | ||
94 | } | 109 | } |
95 | 110 | ||
96 | /* | 111 | /* |
@@ -100,27 +115,23 @@ u32 | |||
100 | nlmclnt_grant(struct nlm_lock *lock) | 115 | nlmclnt_grant(struct nlm_lock *lock) |
101 | { | 116 | { |
102 | struct nlm_wait *block; | 117 | struct nlm_wait *block; |
118 | u32 res = nlm_lck_denied; | ||
103 | 119 | ||
104 | /* | 120 | /* |
105 | * Look up blocked request based on arguments. | 121 | * Look up blocked request based on arguments. |
106 | * Warning: must not use cookie to match it! | 122 | * Warning: must not use cookie to match it! |
107 | */ | 123 | */ |
108 | for (block = nlm_blocked; block; block = block->b_next) { | 124 | list_for_each_entry(block, &nlm_blocked, b_list) { |
109 | if (nlm_compare_locks(block->b_lock, &lock->fl)) | 125 | if (nlm_compare_locks(block->b_lock, &lock->fl)) { |
110 | break; | 126 | /* Alright, we found a lock. Set the return status |
127 | * and wake up the caller | ||
128 | */ | ||
129 | block->b_status = NLM_LCK_GRANTED; | ||
130 | wake_up(&block->b_wait); | ||
131 | res = nlm_granted; | ||
132 | } | ||
111 | } | 133 | } |
112 | 134 | return res; | |
113 | /* Ooops, no blocked request found. */ | ||
114 | if (block == NULL) | ||
115 | return nlm_lck_denied; | ||
116 | |||
117 | /* Alright, we found the lock. Set the return status and | ||
118 | * wake up the caller. | ||
119 | */ | ||
120 | block->b_status = NLM_LCK_GRANTED; | ||
121 | wake_up(&block->b_wait); | ||
122 | |||
123 | return nlm_granted; | ||
124 | } | 135 | } |
125 | 136 | ||
126 | /* | 137 | /* |
@@ -230,7 +241,7 @@ restart: | |||
230 | host->h_reclaiming = 0; | 241 | host->h_reclaiming = 0; |
231 | 242 | ||
232 | /* Now, wake up all processes that sleep on a blocked lock */ | 243 | /* Now, wake up all processes that sleep on a blocked lock */ |
233 | for (block = nlm_blocked; block; block = block->b_next) { | 244 | list_for_each_entry(block, &nlm_blocked, b_list) { |
234 | if (block->b_host == host) { | 245 | if (block->b_host == host) { |
235 | block->b_status = NLM_LCK_DENIED_GRACE_PERIOD; | 246 | block->b_status = NLM_LCK_DENIED_GRACE_PERIOD; |
236 | wake_up(&block->b_wait); | 247 | wake_up(&block->b_wait); |
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index a4407619b1f1..fd77ed1d710d 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c | |||
@@ -21,6 +21,7 @@ | |||
21 | 21 | ||
22 | #define NLMDBG_FACILITY NLMDBG_CLIENT | 22 | #define NLMDBG_FACILITY NLMDBG_CLIENT |
23 | #define NLMCLNT_GRACE_WAIT (5*HZ) | 23 | #define NLMCLNT_GRACE_WAIT (5*HZ) |
24 | #define NLMCLNT_POLL_TIMEOUT (30*HZ) | ||
24 | 25 | ||
25 | static int nlmclnt_test(struct nlm_rqst *, struct file_lock *); | 26 | static int nlmclnt_test(struct nlm_rqst *, struct file_lock *); |
26 | static int nlmclnt_lock(struct nlm_rqst *, struct file_lock *); | 27 | static int nlmclnt_lock(struct nlm_rqst *, struct file_lock *); |
@@ -553,7 +554,8 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) | |||
553 | { | 554 | { |
554 | struct nlm_host *host = req->a_host; | 555 | struct nlm_host *host = req->a_host; |
555 | struct nlm_res *resp = &req->a_res; | 556 | struct nlm_res *resp = &req->a_res; |
556 | int status; | 557 | long timeout; |
558 | int status; | ||
557 | 559 | ||
558 | if (!host->h_monitored && nsm_monitor(host) < 0) { | 560 | if (!host->h_monitored && nsm_monitor(host) < 0) { |
559 | printk(KERN_NOTICE "lockd: failed to monitor %s\n", | 561 | printk(KERN_NOTICE "lockd: failed to monitor %s\n", |
@@ -562,15 +564,32 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) | |||
562 | goto out; | 564 | goto out; |
563 | } | 565 | } |
564 | 566 | ||
565 | do { | 567 | if (req->a_args.block) { |
566 | if ((status = nlmclnt_call(req, NLMPROC_LOCK)) >= 0) { | 568 | status = nlmclnt_prepare_block(req, host, fl); |
567 | if (resp->status != NLM_LCK_BLOCKED) | ||
568 | break; | ||
569 | status = nlmclnt_block(host, fl, &resp->status); | ||
570 | } | ||
571 | if (status < 0) | 569 | if (status < 0) |
572 | goto out; | 570 | goto out; |
573 | } while (resp->status == NLM_LCK_BLOCKED && req->a_args.block); | 571 | } |
572 | for(;;) { | ||
573 | status = nlmclnt_call(req, NLMPROC_LOCK); | ||
574 | if (status < 0) | ||
575 | goto out_unblock; | ||
576 | if (resp->status != NLM_LCK_BLOCKED) | ||
577 | break; | ||
578 | /* Wait on an NLM blocking lock */ | ||
579 | timeout = nlmclnt_block(req, NLMCLNT_POLL_TIMEOUT); | ||
580 | /* Did a reclaimer thread notify us of a server reboot? */ | ||
581 | if (resp->status == NLM_LCK_DENIED_GRACE_PERIOD) | ||
582 | continue; | ||
583 | if (resp->status != NLM_LCK_BLOCKED) | ||
584 | break; | ||
585 | if (timeout >= 0) | ||
586 | continue; | ||
587 | /* We were interrupted. Send a CANCEL request to the server | ||
588 | * and exit | ||
589 | */ | ||
590 | status = (int)timeout; | ||
591 | goto out_unblock; | ||
592 | } | ||
574 | 593 | ||
575 | if (resp->status == NLM_LCK_GRANTED) { | 594 | if (resp->status == NLM_LCK_GRANTED) { |
576 | fl->fl_u.nfs_fl.state = host->h_state; | 595 | fl->fl_u.nfs_fl.state = host->h_state; |
@@ -579,6 +598,11 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) | |||
579 | do_vfs_lock(fl); | 598 | do_vfs_lock(fl); |
580 | } | 599 | } |
581 | status = nlm_stat_to_errno(resp->status); | 600 | status = nlm_stat_to_errno(resp->status); |
601 | out_unblock: | ||
602 | nlmclnt_finish_block(req); | ||
603 | /* Cancel the blocked request if it is still pending */ | ||
604 | if (resp->status == NLM_LCK_BLOCKED) | ||
605 | nlmclnt_cancel(host, fl); | ||
582 | out: | 606 | out: |
583 | nlmclnt_release_lockargs(req); | 607 | nlmclnt_release_lockargs(req); |
584 | return status; | 608 | return status; |
diff --git a/fs/lockd/host.c b/fs/lockd/host.c index 52707c5ad6ea..82c77df81c5f 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c | |||
@@ -189,17 +189,15 @@ nlm_bind_host(struct nlm_host *host) | |||
189 | goto forgetit; | 189 | goto forgetit; |
190 | 190 | ||
191 | xprt_set_timeout(&xprt->timeout, 5, nlmsvc_timeout); | 191 | xprt_set_timeout(&xprt->timeout, 5, nlmsvc_timeout); |
192 | xprt->nocong = 1; /* No congestion control for NLM */ | ||
193 | xprt->resvport = 1; /* NLM requires a reserved port */ | ||
192 | 194 | ||
193 | /* Existing NLM servers accept AUTH_UNIX only */ | 195 | /* Existing NLM servers accept AUTH_UNIX only */ |
194 | clnt = rpc_create_client(xprt, host->h_name, &nlm_program, | 196 | clnt = rpc_create_client(xprt, host->h_name, &nlm_program, |
195 | host->h_version, RPC_AUTH_UNIX); | 197 | host->h_version, RPC_AUTH_UNIX); |
196 | if (IS_ERR(clnt)) { | 198 | if (IS_ERR(clnt)) |
197 | xprt_destroy(xprt); | ||
198 | goto forgetit; | 199 | goto forgetit; |
199 | } | ||
200 | clnt->cl_autobind = 1; /* turn on pmap queries */ | 200 | clnt->cl_autobind = 1; /* turn on pmap queries */ |
201 | xprt->nocong = 1; /* No congestion control for NLM */ | ||
202 | xprt->resvport = 1; /* NLM requires a reserved port */ | ||
203 | 201 | ||
204 | host->h_rpcclnt = clnt; | 202 | host->h_rpcclnt = clnt; |
205 | } | 203 | } |
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index 6fc1bebeec1d..2d144abe84ad 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c | |||
@@ -115,20 +115,19 @@ nsm_create(void) | |||
115 | xprt = xprt_create_proto(IPPROTO_UDP, &sin, NULL); | 115 | xprt = xprt_create_proto(IPPROTO_UDP, &sin, NULL); |
116 | if (IS_ERR(xprt)) | 116 | if (IS_ERR(xprt)) |
117 | return (struct rpc_clnt *)xprt; | 117 | return (struct rpc_clnt *)xprt; |
118 | xprt->resvport = 1; /* NSM requires a reserved port */ | ||
118 | 119 | ||
119 | clnt = rpc_create_client(xprt, "localhost", | 120 | clnt = rpc_create_client(xprt, "localhost", |
120 | &nsm_program, SM_VERSION, | 121 | &nsm_program, SM_VERSION, |
121 | RPC_AUTH_NULL); | 122 | RPC_AUTH_NULL); |
122 | if (IS_ERR(clnt)) | 123 | if (IS_ERR(clnt)) |
123 | goto out_destroy; | 124 | goto out_err; |
124 | clnt->cl_softrtry = 1; | 125 | clnt->cl_softrtry = 1; |
125 | clnt->cl_chatty = 1; | 126 | clnt->cl_chatty = 1; |
126 | clnt->cl_oneshot = 1; | 127 | clnt->cl_oneshot = 1; |
127 | xprt->resvport = 1; /* NSM requires a reserved port */ | ||
128 | return clnt; | 128 | return clnt; |
129 | 129 | ||
130 | out_destroy: | 130 | out_err: |
131 | xprt_destroy(xprt); | ||
132 | return clnt; | 131 | return clnt; |
133 | } | 132 | } |
134 | 133 | ||
diff --git a/fs/locks.c b/fs/locks.c index 3fa6a7ce57a7..a0bc03495bd4 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
@@ -1548,6 +1548,8 @@ int fcntl_getlk(struct file *filp, struct flock __user *l) | |||
1548 | 1548 | ||
1549 | if (filp->f_op && filp->f_op->lock) { | 1549 | if (filp->f_op && filp->f_op->lock) { |
1550 | error = filp->f_op->lock(filp, F_GETLK, &file_lock); | 1550 | error = filp->f_op->lock(filp, F_GETLK, &file_lock); |
1551 | if (file_lock.fl_ops && file_lock.fl_ops->fl_release_private) | ||
1552 | file_lock.fl_ops->fl_release_private(&file_lock); | ||
1551 | if (error < 0) | 1553 | if (error < 0) |
1552 | goto out; | 1554 | goto out; |
1553 | else | 1555 | else |
@@ -1690,6 +1692,8 @@ int fcntl_getlk64(struct file *filp, struct flock64 __user *l) | |||
1690 | 1692 | ||
1691 | if (filp->f_op && filp->f_op->lock) { | 1693 | if (filp->f_op && filp->f_op->lock) { |
1692 | error = filp->f_op->lock(filp, F_GETLK, &file_lock); | 1694 | error = filp->f_op->lock(filp, F_GETLK, &file_lock); |
1695 | if (file_lock.fl_ops && file_lock.fl_ops->fl_release_private) | ||
1696 | file_lock.fl_ops->fl_release_private(&file_lock); | ||
1693 | if (error < 0) | 1697 | if (error < 0) |
1694 | goto out; | 1698 | goto out; |
1695 | else | 1699 | else |
@@ -1873,6 +1877,8 @@ void locks_remove_flock(struct file *filp) | |||
1873 | .fl_end = OFFSET_MAX, | 1877 | .fl_end = OFFSET_MAX, |
1874 | }; | 1878 | }; |
1875 | filp->f_op->flock(filp, F_SETLKW, &fl); | 1879 | filp->f_op->flock(filp, F_SETLKW, &fl); |
1880 | if (fl.fl_ops && fl.fl_ops->fl_release_private) | ||
1881 | fl.fl_ops->fl_release_private(&fl); | ||
1876 | } | 1882 | } |
1877 | 1883 | ||
1878 | lock_kernel(); | 1884 | lock_kernel(); |
diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile index b4baa031edf4..8b3bb715d177 100644 --- a/fs/nfs/Makefile +++ b/fs/nfs/Makefile | |||
@@ -8,6 +8,7 @@ nfs-y := dir.o file.o inode.o nfs2xdr.o pagelist.o \ | |||
8 | proc.o read.o symlink.o unlink.o write.o | 8 | proc.o read.o symlink.o unlink.o write.o |
9 | nfs-$(CONFIG_ROOT_NFS) += nfsroot.o mount_clnt.o | 9 | nfs-$(CONFIG_ROOT_NFS) += nfsroot.o mount_clnt.o |
10 | nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o | 10 | nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o |
11 | nfs-$(CONFIG_NFS_V3_ACL) += nfs3acl.o | ||
11 | nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \ | 12 | nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \ |
12 | delegation.o idmap.o \ | 13 | delegation.o idmap.o \ |
13 | callback.o callback_xdr.o callback_proc.o | 14 | callback.o callback_xdr.o callback_proc.o |
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index 560d6175dd58..f2ca782aba33 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/sunrpc/svc.h> | 14 | #include <linux/sunrpc/svc.h> |
15 | #include <linux/sunrpc/svcsock.h> | 15 | #include <linux/sunrpc/svcsock.h> |
16 | #include <linux/nfs_fs.h> | 16 | #include <linux/nfs_fs.h> |
17 | #include "nfs4_fs.h" | ||
17 | #include "callback.h" | 18 | #include "callback.h" |
18 | 19 | ||
19 | #define NFSDBG_FACILITY NFSDBG_CALLBACK | 20 | #define NFSDBG_FACILITY NFSDBG_CALLBACK |
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index ece27e42b93b..65f1e19e4d19 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c | |||
@@ -8,6 +8,7 @@ | |||
8 | #include <linux/config.h> | 8 | #include <linux/config.h> |
9 | #include <linux/nfs4.h> | 9 | #include <linux/nfs4.h> |
10 | #include <linux/nfs_fs.h> | 10 | #include <linux/nfs_fs.h> |
11 | #include "nfs4_fs.h" | ||
11 | #include "callback.h" | 12 | #include "callback.h" |
12 | #include "delegation.h" | 13 | #include "delegation.h" |
13 | 14 | ||
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index d271df9df2b2..7c33b9a81a94 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/sunrpc/svc.h> | 10 | #include <linux/sunrpc/svc.h> |
11 | #include <linux/nfs4.h> | 11 | #include <linux/nfs4.h> |
12 | #include <linux/nfs_fs.h> | 12 | #include <linux/nfs_fs.h> |
13 | #include "nfs4_fs.h" | ||
13 | #include "callback.h" | 14 | #include "callback.h" |
14 | 15 | ||
15 | #define CB_OP_TAGLEN_MAXSZ (512) | 16 | #define CB_OP_TAGLEN_MAXSZ (512) |
@@ -410,7 +411,6 @@ static int nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *resp | |||
410 | xdr_init_decode(&xdr_in, &rqstp->rq_arg, rqstp->rq_arg.head[0].iov_base); | 411 | xdr_init_decode(&xdr_in, &rqstp->rq_arg, rqstp->rq_arg.head[0].iov_base); |
411 | 412 | ||
412 | p = (uint32_t*)((char *)rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len); | 413 | p = (uint32_t*)((char *)rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len); |
413 | rqstp->rq_res.head[0].iov_len = PAGE_SIZE; | ||
414 | xdr_init_encode(&xdr_out, &rqstp->rq_res, p); | 414 | xdr_init_encode(&xdr_out, &rqstp->rq_res, p); |
415 | 415 | ||
416 | decode_compound_hdr_arg(&xdr_in, &hdr_arg); | 416 | decode_compound_hdr_arg(&xdr_in, &hdr_arg); |
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 5b9c60f97791..d7f7eb669d03 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/nfs_fs.h> | 16 | #include <linux/nfs_fs.h> |
17 | #include <linux/nfs_xdr.h> | 17 | #include <linux/nfs_xdr.h> |
18 | 18 | ||
19 | #include "nfs4_fs.h" | ||
19 | #include "delegation.h" | 20 | #include "delegation.h" |
20 | 21 | ||
21 | static struct nfs_delegation *nfs_alloc_delegation(void) | 22 | static struct nfs_delegation *nfs_alloc_delegation(void) |
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index ff6155f5e8d9..b38a57e78a63 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/smp_lock.h> | 32 | #include <linux/smp_lock.h> |
33 | #include <linux/namei.h> | 33 | #include <linux/namei.h> |
34 | 34 | ||
35 | #include "nfs4_fs.h" | ||
35 | #include "delegation.h" | 36 | #include "delegation.h" |
36 | 37 | ||
37 | #define NFS_PARANOIA 1 | 38 | #define NFS_PARANOIA 1 |
@@ -50,8 +51,10 @@ static int nfs_mknod(struct inode *, struct dentry *, int, dev_t); | |||
50 | static int nfs_rename(struct inode *, struct dentry *, | 51 | static int nfs_rename(struct inode *, struct dentry *, |
51 | struct inode *, struct dentry *); | 52 | struct inode *, struct dentry *); |
52 | static int nfs_fsync_dir(struct file *, struct dentry *, int); | 53 | static int nfs_fsync_dir(struct file *, struct dentry *, int); |
54 | static loff_t nfs_llseek_dir(struct file *, loff_t, int); | ||
53 | 55 | ||
54 | struct file_operations nfs_dir_operations = { | 56 | struct file_operations nfs_dir_operations = { |
57 | .llseek = nfs_llseek_dir, | ||
55 | .read = generic_read_dir, | 58 | .read = generic_read_dir, |
56 | .readdir = nfs_readdir, | 59 | .readdir = nfs_readdir, |
57 | .open = nfs_opendir, | 60 | .open = nfs_opendir, |
@@ -74,6 +77,27 @@ struct inode_operations nfs_dir_inode_operations = { | |||
74 | .setattr = nfs_setattr, | 77 | .setattr = nfs_setattr, |
75 | }; | 78 | }; |
76 | 79 | ||
80 | #ifdef CONFIG_NFS_V3 | ||
81 | struct inode_operations nfs3_dir_inode_operations = { | ||
82 | .create = nfs_create, | ||
83 | .lookup = nfs_lookup, | ||
84 | .link = nfs_link, | ||
85 | .unlink = nfs_unlink, | ||
86 | .symlink = nfs_symlink, | ||
87 | .mkdir = nfs_mkdir, | ||
88 | .rmdir = nfs_rmdir, | ||
89 | .mknod = nfs_mknod, | ||
90 | .rename = nfs_rename, | ||
91 | .permission = nfs_permission, | ||
92 | .getattr = nfs_getattr, | ||
93 | .setattr = nfs_setattr, | ||
94 | .listxattr = nfs3_listxattr, | ||
95 | .getxattr = nfs3_getxattr, | ||
96 | .setxattr = nfs3_setxattr, | ||
97 | .removexattr = nfs3_removexattr, | ||
98 | }; | ||
99 | #endif /* CONFIG_NFS_V3 */ | ||
100 | |||
77 | #ifdef CONFIG_NFS_V4 | 101 | #ifdef CONFIG_NFS_V4 |
78 | 102 | ||
79 | static struct dentry *nfs_atomic_lookup(struct inode *, struct dentry *, struct nameidata *); | 103 | static struct dentry *nfs_atomic_lookup(struct inode *, struct dentry *, struct nameidata *); |
@@ -90,6 +114,9 @@ struct inode_operations nfs4_dir_inode_operations = { | |||
90 | .permission = nfs_permission, | 114 | .permission = nfs_permission, |
91 | .getattr = nfs_getattr, | 115 | .getattr = nfs_getattr, |
92 | .setattr = nfs_setattr, | 116 | .setattr = nfs_setattr, |
117 | .getxattr = nfs4_getxattr, | ||
118 | .setxattr = nfs4_setxattr, | ||
119 | .listxattr = nfs4_listxattr, | ||
93 | }; | 120 | }; |
94 | 121 | ||
95 | #endif /* CONFIG_NFS_V4 */ | 122 | #endif /* CONFIG_NFS_V4 */ |
@@ -116,7 +143,8 @@ typedef struct { | |||
116 | struct page *page; | 143 | struct page *page; |
117 | unsigned long page_index; | 144 | unsigned long page_index; |
118 | u32 *ptr; | 145 | u32 *ptr; |
119 | u64 target; | 146 | u64 *dir_cookie; |
147 | loff_t current_index; | ||
120 | struct nfs_entry *entry; | 148 | struct nfs_entry *entry; |
121 | decode_dirent_t decode; | 149 | decode_dirent_t decode; |
122 | int plus; | 150 | int plus; |
@@ -164,12 +192,10 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page) | |||
164 | NFS_FLAGS(inode) |= NFS_INO_INVALID_ATIME; | 192 | NFS_FLAGS(inode) |= NFS_INO_INVALID_ATIME; |
165 | /* Ensure consistent page alignment of the data. | 193 | /* Ensure consistent page alignment of the data. |
166 | * Note: assumes we have exclusive access to this mapping either | 194 | * Note: assumes we have exclusive access to this mapping either |
167 | * throught inode->i_sem or some other mechanism. | 195 | * through inode->i_sem or some other mechanism. |
168 | */ | 196 | */ |
169 | if (page->index == 0) { | 197 | if (page->index == 0) |
170 | invalidate_inode_pages(inode->i_mapping); | 198 | invalidate_inode_pages2_range(inode->i_mapping, PAGE_CACHE_SIZE, -1); |
171 | NFS_I(inode)->readdir_timestamp = timestamp; | ||
172 | } | ||
173 | unlock_page(page); | 199 | unlock_page(page); |
174 | return 0; | 200 | return 0; |
175 | error: | 201 | error: |
@@ -202,22 +228,22 @@ void dir_page_release(nfs_readdir_descriptor_t *desc) | |||
202 | 228 | ||
203 | /* | 229 | /* |
204 | * Given a pointer to a buffer that has already been filled by a call | 230 | * Given a pointer to a buffer that has already been filled by a call |
205 | * to readdir, find the next entry. | 231 | * to readdir, find the next entry with cookie '*desc->dir_cookie'. |
206 | * | 232 | * |
207 | * If the end of the buffer has been reached, return -EAGAIN, if not, | 233 | * If the end of the buffer has been reached, return -EAGAIN, if not, |
208 | * return the offset within the buffer of the next entry to be | 234 | * return the offset within the buffer of the next entry to be |
209 | * read. | 235 | * read. |
210 | */ | 236 | */ |
211 | static inline | 237 | static inline |
212 | int find_dirent(nfs_readdir_descriptor_t *desc, struct page *page) | 238 | int find_dirent(nfs_readdir_descriptor_t *desc) |
213 | { | 239 | { |
214 | struct nfs_entry *entry = desc->entry; | 240 | struct nfs_entry *entry = desc->entry; |
215 | int loop_count = 0, | 241 | int loop_count = 0, |
216 | status; | 242 | status; |
217 | 243 | ||
218 | while((status = dir_decode(desc)) == 0) { | 244 | while((status = dir_decode(desc)) == 0) { |
219 | dfprintk(VFS, "NFS: found cookie %Lu\n", (long long)entry->cookie); | 245 | dfprintk(VFS, "NFS: found cookie %Lu\n", (unsigned long long)entry->cookie); |
220 | if (entry->prev_cookie == desc->target) | 246 | if (entry->prev_cookie == *desc->dir_cookie) |
221 | break; | 247 | break; |
222 | if (loop_count++ > 200) { | 248 | if (loop_count++ > 200) { |
223 | loop_count = 0; | 249 | loop_count = 0; |
@@ -229,8 +255,44 @@ int find_dirent(nfs_readdir_descriptor_t *desc, struct page *page) | |||
229 | } | 255 | } |
230 | 256 | ||
231 | /* | 257 | /* |
232 | * Find the given page, and call find_dirent() in order to try to | 258 | * Given a pointer to a buffer that has already been filled by a call |
233 | * return the next entry. | 259 | * to readdir, find the entry at offset 'desc->file->f_pos'. |
260 | * | ||
261 | * If the end of the buffer has been reached, return -EAGAIN, if not, | ||
262 | * return the offset within the buffer of the next entry to be | ||
263 | * read. | ||
264 | */ | ||
265 | static inline | ||
266 | int find_dirent_index(nfs_readdir_descriptor_t *desc) | ||
267 | { | ||
268 | struct nfs_entry *entry = desc->entry; | ||
269 | int loop_count = 0, | ||
270 | status; | ||
271 | |||
272 | for(;;) { | ||
273 | status = dir_decode(desc); | ||
274 | if (status) | ||
275 | break; | ||
276 | |||
277 | dfprintk(VFS, "NFS: found cookie %Lu at index %Ld\n", (unsigned long long)entry->cookie, desc->current_index); | ||
278 | |||
279 | if (desc->file->f_pos == desc->current_index) { | ||
280 | *desc->dir_cookie = entry->cookie; | ||
281 | break; | ||
282 | } | ||
283 | desc->current_index++; | ||
284 | if (loop_count++ > 200) { | ||
285 | loop_count = 0; | ||
286 | schedule(); | ||
287 | } | ||
288 | } | ||
289 | dfprintk(VFS, "NFS: find_dirent_index() returns %d\n", status); | ||
290 | return status; | ||
291 | } | ||
292 | |||
293 | /* | ||
294 | * Find the given page, and call find_dirent() or find_dirent_index in | ||
295 | * order to try to return the next entry. | ||
234 | */ | 296 | */ |
235 | static inline | 297 | static inline |
236 | int find_dirent_page(nfs_readdir_descriptor_t *desc) | 298 | int find_dirent_page(nfs_readdir_descriptor_t *desc) |
@@ -253,7 +315,10 @@ int find_dirent_page(nfs_readdir_descriptor_t *desc) | |||
253 | /* NOTE: Someone else may have changed the READDIRPLUS flag */ | 315 | /* NOTE: Someone else may have changed the READDIRPLUS flag */ |
254 | desc->page = page; | 316 | desc->page = page; |
255 | desc->ptr = kmap(page); /* matching kunmap in nfs_do_filldir */ | 317 | desc->ptr = kmap(page); /* matching kunmap in nfs_do_filldir */ |
256 | status = find_dirent(desc, page); | 318 | if (*desc->dir_cookie != 0) |
319 | status = find_dirent(desc); | ||
320 | else | ||
321 | status = find_dirent_index(desc); | ||
257 | if (status < 0) | 322 | if (status < 0) |
258 | dir_page_release(desc); | 323 | dir_page_release(desc); |
259 | out: | 324 | out: |
@@ -268,7 +333,8 @@ int find_dirent_page(nfs_readdir_descriptor_t *desc) | |||
268 | * Recurse through the page cache pages, and return a | 333 | * Recurse through the page cache pages, and return a |
269 | * filled nfs_entry structure of the next directory entry if possible. | 334 | * filled nfs_entry structure of the next directory entry if possible. |
270 | * | 335 | * |
271 | * The target for the search is 'desc->target'. | 336 | * The target for the search is '*desc->dir_cookie' if non-0, |
337 | * 'desc->file->f_pos' otherwise | ||
272 | */ | 338 | */ |
273 | static inline | 339 | static inline |
274 | int readdir_search_pagecache(nfs_readdir_descriptor_t *desc) | 340 | int readdir_search_pagecache(nfs_readdir_descriptor_t *desc) |
@@ -276,7 +342,16 @@ int readdir_search_pagecache(nfs_readdir_descriptor_t *desc) | |||
276 | int loop_count = 0; | 342 | int loop_count = 0; |
277 | int res; | 343 | int res; |
278 | 344 | ||
279 | dfprintk(VFS, "NFS: readdir_search_pagecache() searching for cookie %Lu\n", (long long)desc->target); | 345 | /* Always search-by-index from the beginning of the cache */ |
346 | if (*desc->dir_cookie == 0) { | ||
347 | dfprintk(VFS, "NFS: readdir_search_pagecache() searching for offset %Ld\n", (long long)desc->file->f_pos); | ||
348 | desc->page_index = 0; | ||
349 | desc->entry->cookie = desc->entry->prev_cookie = 0; | ||
350 | desc->entry->eof = 0; | ||
351 | desc->current_index = 0; | ||
352 | } else | ||
353 | dfprintk(VFS, "NFS: readdir_search_pagecache() searching for cookie %Lu\n", (unsigned long long)*desc->dir_cookie); | ||
354 | |||
280 | for (;;) { | 355 | for (;;) { |
281 | res = find_dirent_page(desc); | 356 | res = find_dirent_page(desc); |
282 | if (res != -EAGAIN) | 357 | if (res != -EAGAIN) |
@@ -313,7 +388,7 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent, | |||
313 | int loop_count = 0, | 388 | int loop_count = 0, |
314 | res; | 389 | res; |
315 | 390 | ||
316 | dfprintk(VFS, "NFS: nfs_do_filldir() filling starting @ cookie %Lu\n", (long long)desc->target); | 391 | dfprintk(VFS, "NFS: nfs_do_filldir() filling starting @ cookie %Lu\n", (long long)entry->cookie); |
317 | 392 | ||
318 | for(;;) { | 393 | for(;;) { |
319 | unsigned d_type = DT_UNKNOWN; | 394 | unsigned d_type = DT_UNKNOWN; |
@@ -333,10 +408,11 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent, | |||
333 | } | 408 | } |
334 | 409 | ||
335 | res = filldir(dirent, entry->name, entry->len, | 410 | res = filldir(dirent, entry->name, entry->len, |
336 | entry->prev_cookie, fileid, d_type); | 411 | file->f_pos, fileid, d_type); |
337 | if (res < 0) | 412 | if (res < 0) |
338 | break; | 413 | break; |
339 | file->f_pos = desc->target = entry->cookie; | 414 | file->f_pos++; |
415 | *desc->dir_cookie = entry->cookie; | ||
340 | if (dir_decode(desc) != 0) { | 416 | if (dir_decode(desc) != 0) { |
341 | desc->page_index ++; | 417 | desc->page_index ++; |
342 | break; | 418 | break; |
@@ -349,7 +425,7 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent, | |||
349 | dir_page_release(desc); | 425 | dir_page_release(desc); |
350 | if (dentry != NULL) | 426 | if (dentry != NULL) |
351 | dput(dentry); | 427 | dput(dentry); |
352 | dfprintk(VFS, "NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d\n", (long long)desc->target, res); | 428 | dfprintk(VFS, "NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d\n", (unsigned long long)*desc->dir_cookie, res); |
353 | return res; | 429 | return res; |
354 | } | 430 | } |
355 | 431 | ||
@@ -375,14 +451,14 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent, | |||
375 | struct page *page = NULL; | 451 | struct page *page = NULL; |
376 | int status; | 452 | int status; |
377 | 453 | ||
378 | dfprintk(VFS, "NFS: uncached_readdir() searching for cookie %Lu\n", (long long)desc->target); | 454 | dfprintk(VFS, "NFS: uncached_readdir() searching for cookie %Lu\n", (unsigned long long)*desc->dir_cookie); |
379 | 455 | ||
380 | page = alloc_page(GFP_HIGHUSER); | 456 | page = alloc_page(GFP_HIGHUSER); |
381 | if (!page) { | 457 | if (!page) { |
382 | status = -ENOMEM; | 458 | status = -ENOMEM; |
383 | goto out; | 459 | goto out; |
384 | } | 460 | } |
385 | desc->error = NFS_PROTO(inode)->readdir(file->f_dentry, cred, desc->target, | 461 | desc->error = NFS_PROTO(inode)->readdir(file->f_dentry, cred, *desc->dir_cookie, |
386 | page, | 462 | page, |
387 | NFS_SERVER(inode)->dtsize, | 463 | NFS_SERVER(inode)->dtsize, |
388 | desc->plus); | 464 | desc->plus); |
@@ -391,7 +467,7 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent, | |||
391 | desc->ptr = kmap(page); /* matching kunmap in nfs_do_filldir */ | 467 | desc->ptr = kmap(page); /* matching kunmap in nfs_do_filldir */ |
392 | if (desc->error >= 0) { | 468 | if (desc->error >= 0) { |
393 | if ((status = dir_decode(desc)) == 0) | 469 | if ((status = dir_decode(desc)) == 0) |
394 | desc->entry->prev_cookie = desc->target; | 470 | desc->entry->prev_cookie = *desc->dir_cookie; |
395 | } else | 471 | } else |
396 | status = -EIO; | 472 | status = -EIO; |
397 | if (status < 0) | 473 | if (status < 0) |
@@ -412,8 +488,9 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent, | |||
412 | goto out; | 488 | goto out; |
413 | } | 489 | } |
414 | 490 | ||
415 | /* The file offset position is now represented as a true offset into the | 491 | /* The file offset position represents the dirent entry number. A |
416 | * page cache as is the case in most of the other filesystems. | 492 | last cookie cache takes care of the common case of reading the |
493 | whole directory. | ||
417 | */ | 494 | */ |
418 | static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | 495 | static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) |
419 | { | 496 | { |
@@ -435,15 +512,15 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
435 | } | 512 | } |
436 | 513 | ||
437 | /* | 514 | /* |
438 | * filp->f_pos points to the file offset in the page cache. | 515 | * filp->f_pos points to the dirent entry number. |
439 | * but if the cache has meanwhile been zapped, we need to | 516 | * *desc->dir_cookie has the cookie for the next entry. We have |
440 | * read from the last dirent to revalidate f_pos | 517 | * to either find the entry with the appropriate number or |
441 | * itself. | 518 | * revalidate the cookie. |
442 | */ | 519 | */ |
443 | memset(desc, 0, sizeof(*desc)); | 520 | memset(desc, 0, sizeof(*desc)); |
444 | 521 | ||
445 | desc->file = filp; | 522 | desc->file = filp; |
446 | desc->target = filp->f_pos; | 523 | desc->dir_cookie = &((struct nfs_open_context *)filp->private_data)->dir_cookie; |
447 | desc->decode = NFS_PROTO(inode)->decode_dirent; | 524 | desc->decode = NFS_PROTO(inode)->decode_dirent; |
448 | desc->plus = NFS_USE_READDIRPLUS(inode); | 525 | desc->plus = NFS_USE_READDIRPLUS(inode); |
449 | 526 | ||
@@ -455,9 +532,10 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
455 | 532 | ||
456 | while(!desc->entry->eof) { | 533 | while(!desc->entry->eof) { |
457 | res = readdir_search_pagecache(desc); | 534 | res = readdir_search_pagecache(desc); |
535 | |||
458 | if (res == -EBADCOOKIE) { | 536 | if (res == -EBADCOOKIE) { |
459 | /* This means either end of directory */ | 537 | /* This means either end of directory */ |
460 | if (desc->entry->cookie != desc->target) { | 538 | if (*desc->dir_cookie && desc->entry->cookie != *desc->dir_cookie) { |
461 | /* Or that the server has 'lost' a cookie */ | 539 | /* Or that the server has 'lost' a cookie */ |
462 | res = uncached_readdir(desc, dirent, filldir); | 540 | res = uncached_readdir(desc, dirent, filldir); |
463 | if (res >= 0) | 541 | if (res >= 0) |
@@ -490,6 +568,28 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
490 | return 0; | 568 | return 0; |
491 | } | 569 | } |
492 | 570 | ||
571 | loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin) | ||
572 | { | ||
573 | down(&filp->f_dentry->d_inode->i_sem); | ||
574 | switch (origin) { | ||
575 | case 1: | ||
576 | offset += filp->f_pos; | ||
577 | case 0: | ||
578 | if (offset >= 0) | ||
579 | break; | ||
580 | default: | ||
581 | offset = -EINVAL; | ||
582 | goto out; | ||
583 | } | ||
584 | if (offset != filp->f_pos) { | ||
585 | filp->f_pos = offset; | ||
586 | ((struct nfs_open_context *)filp->private_data)->dir_cookie = 0; | ||
587 | } | ||
588 | out: | ||
589 | up(&filp->f_dentry->d_inode->i_sem); | ||
590 | return offset; | ||
591 | } | ||
592 | |||
493 | /* | 593 | /* |
494 | * All directory operations under NFS are synchronous, so fsync() | 594 | * All directory operations under NFS are synchronous, so fsync() |
495 | * is a dummy operation. | 595 | * is a dummy operation. |
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 68df803f27ca..d6a30c844de3 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
@@ -517,7 +517,7 @@ retry: | |||
517 | result = tot_bytes; | 517 | result = tot_bytes; |
518 | 518 | ||
519 | out: | 519 | out: |
520 | nfs_end_data_update_defer(inode); | 520 | nfs_end_data_update(inode); |
521 | nfs_writedata_free(wdata); | 521 | nfs_writedata_free(wdata); |
522 | return result; | 522 | return result; |
523 | 523 | ||
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 55c907592490..5621ba9885f4 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
@@ -71,6 +71,18 @@ struct inode_operations nfs_file_inode_operations = { | |||
71 | .setattr = nfs_setattr, | 71 | .setattr = nfs_setattr, |
72 | }; | 72 | }; |
73 | 73 | ||
74 | #ifdef CONFIG_NFS_V3 | ||
75 | struct inode_operations nfs3_file_inode_operations = { | ||
76 | .permission = nfs_permission, | ||
77 | .getattr = nfs_getattr, | ||
78 | .setattr = nfs_setattr, | ||
79 | .listxattr = nfs3_listxattr, | ||
80 | .getxattr = nfs3_getxattr, | ||
81 | .setxattr = nfs3_setxattr, | ||
82 | .removexattr = nfs3_removexattr, | ||
83 | }; | ||
84 | #endif /* CONFIG_NFS_v3 */ | ||
85 | |||
74 | /* Hack for future NFS swap support */ | 86 | /* Hack for future NFS swap support */ |
75 | #ifndef IS_SWAPFILE | 87 | #ifndef IS_SWAPFILE |
76 | # define IS_SWAPFILE(inode) (0) | 88 | # define IS_SWAPFILE(inode) (0) |
@@ -116,6 +128,21 @@ nfs_file_release(struct inode *inode, struct file *filp) | |||
116 | } | 128 | } |
117 | 129 | ||
118 | /** | 130 | /** |
131 | * nfs_revalidate_file - Revalidate the page cache & related metadata | ||
132 | * @inode - pointer to inode struct | ||
133 | * @file - pointer to file | ||
134 | */ | ||
135 | static int nfs_revalidate_file(struct inode *inode, struct file *filp) | ||
136 | { | ||
137 | int retval = 0; | ||
138 | |||
139 | if ((NFS_FLAGS(inode) & NFS_INO_REVAL_PAGECACHE) || nfs_attribute_timeout(inode)) | ||
140 | retval = __nfs_revalidate_inode(NFS_SERVER(inode), inode); | ||
141 | nfs_revalidate_mapping(inode, filp->f_mapping); | ||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | /** | ||
119 | * nfs_revalidate_size - Revalidate the file size | 146 | * nfs_revalidate_size - Revalidate the file size |
120 | * @inode - pointer to inode struct | 147 | * @inode - pointer to inode struct |
121 | * @file - pointer to struct file | 148 | * @file - pointer to struct file |
@@ -137,7 +164,8 @@ static int nfs_revalidate_file_size(struct inode *inode, struct file *filp) | |||
137 | goto force_reval; | 164 | goto force_reval; |
138 | if (nfsi->npages != 0) | 165 | if (nfsi->npages != 0) |
139 | return 0; | 166 | return 0; |
140 | return nfs_revalidate_inode(server, inode); | 167 | if (!(NFS_FLAGS(inode) & NFS_INO_REVAL_PAGECACHE) && !nfs_attribute_timeout(inode)) |
168 | return 0; | ||
141 | force_reval: | 169 | force_reval: |
142 | return __nfs_revalidate_inode(server, inode); | 170 | return __nfs_revalidate_inode(server, inode); |
143 | } | 171 | } |
@@ -198,7 +226,7 @@ nfs_file_read(struct kiocb *iocb, char __user * buf, size_t count, loff_t pos) | |||
198 | dentry->d_parent->d_name.name, dentry->d_name.name, | 226 | dentry->d_parent->d_name.name, dentry->d_name.name, |
199 | (unsigned long) count, (unsigned long) pos); | 227 | (unsigned long) count, (unsigned long) pos); |
200 | 228 | ||
201 | result = nfs_revalidate_inode(NFS_SERVER(inode), inode); | 229 | result = nfs_revalidate_file(inode, iocb->ki_filp); |
202 | if (!result) | 230 | if (!result) |
203 | result = generic_file_aio_read(iocb, buf, count, pos); | 231 | result = generic_file_aio_read(iocb, buf, count, pos); |
204 | return result; | 232 | return result; |
@@ -216,7 +244,7 @@ nfs_file_sendfile(struct file *filp, loff_t *ppos, size_t count, | |||
216 | dentry->d_parent->d_name.name, dentry->d_name.name, | 244 | dentry->d_parent->d_name.name, dentry->d_name.name, |
217 | (unsigned long) count, (unsigned long long) *ppos); | 245 | (unsigned long) count, (unsigned long long) *ppos); |
218 | 246 | ||
219 | res = nfs_revalidate_inode(NFS_SERVER(inode), inode); | 247 | res = nfs_revalidate_file(inode, filp); |
220 | if (!res) | 248 | if (!res) |
221 | res = generic_file_sendfile(filp, ppos, count, actor, target); | 249 | res = generic_file_sendfile(filp, ppos, count, actor, target); |
222 | return res; | 250 | return res; |
@@ -232,7 +260,7 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma) | |||
232 | dfprintk(VFS, "nfs: mmap(%s/%s)\n", | 260 | dfprintk(VFS, "nfs: mmap(%s/%s)\n", |
233 | dentry->d_parent->d_name.name, dentry->d_name.name); | 261 | dentry->d_parent->d_name.name, dentry->d_name.name); |
234 | 262 | ||
235 | status = nfs_revalidate_inode(NFS_SERVER(inode), inode); | 263 | status = nfs_revalidate_file(inode, file); |
236 | if (!status) | 264 | if (!status) |
237 | status = generic_file_mmap(file, vma); | 265 | status = generic_file_mmap(file, vma); |
238 | return status; | 266 | return status; |
@@ -321,9 +349,15 @@ nfs_file_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t | |||
321 | result = -EBUSY; | 349 | result = -EBUSY; |
322 | if (IS_SWAPFILE(inode)) | 350 | if (IS_SWAPFILE(inode)) |
323 | goto out_swapfile; | 351 | goto out_swapfile; |
324 | result = nfs_revalidate_inode(NFS_SERVER(inode), inode); | 352 | /* |
325 | if (result) | 353 | * O_APPEND implies that we must revalidate the file length. |
326 | goto out; | 354 | */ |
355 | if (iocb->ki_filp->f_flags & O_APPEND) { | ||
356 | result = nfs_revalidate_file_size(inode, iocb->ki_filp); | ||
357 | if (result) | ||
358 | goto out; | ||
359 | } | ||
360 | nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping); | ||
327 | 361 | ||
328 | result = count; | 362 | result = count; |
329 | if (!count) | 363 | if (!count) |
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index 87f4f9aeac86..ffb8df91dc34 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c | |||
@@ -50,6 +50,7 @@ | |||
50 | #include <linux/nfs_fs.h> | 50 | #include <linux/nfs_fs.h> |
51 | 51 | ||
52 | #include <linux/nfs_idmap.h> | 52 | #include <linux/nfs_idmap.h> |
53 | #include "nfs4_fs.h" | ||
53 | 54 | ||
54 | #define IDMAP_HASH_SZ 128 | 55 | #define IDMAP_HASH_SZ 128 |
55 | 56 | ||
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index f2317f3e29f9..4845911f1c63 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <asm/system.h> | 39 | #include <asm/system.h> |
40 | #include <asm/uaccess.h> | 40 | #include <asm/uaccess.h> |
41 | 41 | ||
42 | #include "nfs4_fs.h" | ||
42 | #include "delegation.h" | 43 | #include "delegation.h" |
43 | 44 | ||
44 | #define NFSDBG_FACILITY NFSDBG_VFS | 45 | #define NFSDBG_FACILITY NFSDBG_VFS |
@@ -63,6 +64,7 @@ static void nfs_clear_inode(struct inode *); | |||
63 | static void nfs_umount_begin(struct super_block *); | 64 | static void nfs_umount_begin(struct super_block *); |
64 | static int nfs_statfs(struct super_block *, struct kstatfs *); | 65 | static int nfs_statfs(struct super_block *, struct kstatfs *); |
65 | static int nfs_show_options(struct seq_file *, struct vfsmount *); | 66 | static int nfs_show_options(struct seq_file *, struct vfsmount *); |
67 | static void nfs_zap_acl_cache(struct inode *); | ||
66 | 68 | ||
67 | static struct rpc_program nfs_program; | 69 | static struct rpc_program nfs_program; |
68 | 70 | ||
@@ -106,6 +108,21 @@ static struct rpc_program nfs_program = { | |||
106 | .pipe_dir_name = "/nfs", | 108 | .pipe_dir_name = "/nfs", |
107 | }; | 109 | }; |
108 | 110 | ||
111 | #ifdef CONFIG_NFS_V3_ACL | ||
112 | static struct rpc_stat nfsacl_rpcstat = { &nfsacl_program }; | ||
113 | static struct rpc_version * nfsacl_version[] = { | ||
114 | [3] = &nfsacl_version3, | ||
115 | }; | ||
116 | |||
117 | struct rpc_program nfsacl_program = { | ||
118 | .name = "nfsacl", | ||
119 | .number = NFS_ACL_PROGRAM, | ||
120 | .nrvers = sizeof(nfsacl_version) / sizeof(nfsacl_version[0]), | ||
121 | .version = nfsacl_version, | ||
122 | .stats = &nfsacl_rpcstat, | ||
123 | }; | ||
124 | #endif /* CONFIG_NFS_V3_ACL */ | ||
125 | |||
109 | static inline unsigned long | 126 | static inline unsigned long |
110 | nfs_fattr_to_ino_t(struct nfs_fattr *fattr) | 127 | nfs_fattr_to_ino_t(struct nfs_fattr *fattr) |
111 | { | 128 | { |
@@ -118,7 +135,7 @@ nfs_write_inode(struct inode *inode, int sync) | |||
118 | int flags = sync ? FLUSH_WAIT : 0; | 135 | int flags = sync ? FLUSH_WAIT : 0; |
119 | int ret; | 136 | int ret; |
120 | 137 | ||
121 | ret = nfs_commit_inode(inode, 0, 0, flags); | 138 | ret = nfs_commit_inode(inode, flags); |
122 | if (ret < 0) | 139 | if (ret < 0) |
123 | return ret; | 140 | return ret; |
124 | return 0; | 141 | return 0; |
@@ -140,10 +157,6 @@ nfs_delete_inode(struct inode * inode) | |||
140 | clear_inode(inode); | 157 | clear_inode(inode); |
141 | } | 158 | } |
142 | 159 | ||
143 | /* | ||
144 | * For the moment, the only task for the NFS clear_inode method is to | ||
145 | * release the mmap credential | ||
146 | */ | ||
147 | static void | 160 | static void |
148 | nfs_clear_inode(struct inode *inode) | 161 | nfs_clear_inode(struct inode *inode) |
149 | { | 162 | { |
@@ -152,6 +165,7 @@ nfs_clear_inode(struct inode *inode) | |||
152 | 165 | ||
153 | nfs_wb_all(inode); | 166 | nfs_wb_all(inode); |
154 | BUG_ON (!list_empty(&nfsi->open_files)); | 167 | BUG_ON (!list_empty(&nfsi->open_files)); |
168 | nfs_zap_acl_cache(inode); | ||
155 | cred = nfsi->cache_access.cred; | 169 | cred = nfsi->cache_access.cred; |
156 | if (cred) | 170 | if (cred) |
157 | put_rpccred(cred); | 171 | put_rpccred(cred); |
@@ -161,11 +175,13 @@ nfs_clear_inode(struct inode *inode) | |||
161 | void | 175 | void |
162 | nfs_umount_begin(struct super_block *sb) | 176 | nfs_umount_begin(struct super_block *sb) |
163 | { | 177 | { |
164 | struct nfs_server *server = NFS_SB(sb); | 178 | struct rpc_clnt *rpc = NFS_SB(sb)->client; |
165 | struct rpc_clnt *rpc; | ||
166 | 179 | ||
167 | /* -EIO all pending I/O */ | 180 | /* -EIO all pending I/O */ |
168 | if ((rpc = server->client) != NULL) | 181 | if (!IS_ERR(rpc)) |
182 | rpc_killall_tasks(rpc); | ||
183 | rpc = NFS_SB(sb)->client_acl; | ||
184 | if (!IS_ERR(rpc)) | ||
169 | rpc_killall_tasks(rpc); | 185 | rpc_killall_tasks(rpc); |
170 | } | 186 | } |
171 | 187 | ||
@@ -366,13 +382,15 @@ nfs_create_client(struct nfs_server *server, const struct nfs_mount_data *data) | |||
366 | xprt = xprt_create_proto(tcp ? IPPROTO_TCP : IPPROTO_UDP, | 382 | xprt = xprt_create_proto(tcp ? IPPROTO_TCP : IPPROTO_UDP, |
367 | &server->addr, &timeparms); | 383 | &server->addr, &timeparms); |
368 | if (IS_ERR(xprt)) { | 384 | if (IS_ERR(xprt)) { |
369 | printk(KERN_WARNING "NFS: cannot create RPC transport.\n"); | 385 | dprintk("%s: cannot create RPC transport. Error = %ld\n", |
386 | __FUNCTION__, PTR_ERR(xprt)); | ||
370 | return (struct rpc_clnt *)xprt; | 387 | return (struct rpc_clnt *)xprt; |
371 | } | 388 | } |
372 | clnt = rpc_create_client(xprt, server->hostname, &nfs_program, | 389 | clnt = rpc_create_client(xprt, server->hostname, &nfs_program, |
373 | server->rpc_ops->version, data->pseudoflavor); | 390 | server->rpc_ops->version, data->pseudoflavor); |
374 | if (IS_ERR(clnt)) { | 391 | if (IS_ERR(clnt)) { |
375 | printk(KERN_WARNING "NFS: cannot create RPC client.\n"); | 392 | dprintk("%s: cannot create RPC client. Error = %ld\n", |
393 | __FUNCTION__, PTR_ERR(xprt)); | ||
376 | goto out_fail; | 394 | goto out_fail; |
377 | } | 395 | } |
378 | 396 | ||
@@ -383,7 +401,6 @@ nfs_create_client(struct nfs_server *server, const struct nfs_mount_data *data) | |||
383 | return clnt; | 401 | return clnt; |
384 | 402 | ||
385 | out_fail: | 403 | out_fail: |
386 | xprt_destroy(xprt); | ||
387 | return clnt; | 404 | return clnt; |
388 | } | 405 | } |
389 | 406 | ||
@@ -427,21 +444,16 @@ nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data, int silent) | |||
427 | 444 | ||
428 | /* Check NFS protocol revision and initialize RPC op vector | 445 | /* Check NFS protocol revision and initialize RPC op vector |
429 | * and file handle pool. */ | 446 | * and file handle pool. */ |
430 | if (server->flags & NFS_MOUNT_VER3) { | ||
431 | #ifdef CONFIG_NFS_V3 | 447 | #ifdef CONFIG_NFS_V3 |
448 | if (server->flags & NFS_MOUNT_VER3) { | ||
432 | server->rpc_ops = &nfs_v3_clientops; | 449 | server->rpc_ops = &nfs_v3_clientops; |
433 | server->caps |= NFS_CAP_READDIRPLUS; | 450 | server->caps |= NFS_CAP_READDIRPLUS; |
434 | if (data->version < 4) { | ||
435 | printk(KERN_NOTICE "NFS: NFSv3 not supported by mount program.\n"); | ||
436 | return -EIO; | ||
437 | } | ||
438 | #else | ||
439 | printk(KERN_NOTICE "NFS: NFSv3 not supported.\n"); | ||
440 | return -EIO; | ||
441 | #endif | ||
442 | } else { | 451 | } else { |
443 | server->rpc_ops = &nfs_v2_clientops; | 452 | server->rpc_ops = &nfs_v2_clientops; |
444 | } | 453 | } |
454 | #else | ||
455 | server->rpc_ops = &nfs_v2_clientops; | ||
456 | #endif | ||
445 | 457 | ||
446 | /* Fill in pseudoflavor for mount version < 5 */ | 458 | /* Fill in pseudoflavor for mount version < 5 */ |
447 | if (!(data->flags & NFS_MOUNT_SECFLAVOUR)) | 459 | if (!(data->flags & NFS_MOUNT_SECFLAVOUR)) |
@@ -455,17 +467,34 @@ nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data, int silent) | |||
455 | return PTR_ERR(server->client); | 467 | return PTR_ERR(server->client); |
456 | /* RFC 2623, sec 2.3.2 */ | 468 | /* RFC 2623, sec 2.3.2 */ |
457 | if (authflavor != RPC_AUTH_UNIX) { | 469 | if (authflavor != RPC_AUTH_UNIX) { |
470 | struct rpc_auth *auth; | ||
471 | |||
458 | server->client_sys = rpc_clone_client(server->client); | 472 | server->client_sys = rpc_clone_client(server->client); |
459 | if (IS_ERR(server->client_sys)) | 473 | if (IS_ERR(server->client_sys)) |
460 | return PTR_ERR(server->client_sys); | 474 | return PTR_ERR(server->client_sys); |
461 | if (!rpcauth_create(RPC_AUTH_UNIX, server->client_sys)) | 475 | auth = rpcauth_create(RPC_AUTH_UNIX, server->client_sys); |
462 | return -ENOMEM; | 476 | if (IS_ERR(auth)) |
477 | return PTR_ERR(auth); | ||
463 | } else { | 478 | } else { |
464 | atomic_inc(&server->client->cl_count); | 479 | atomic_inc(&server->client->cl_count); |
465 | server->client_sys = server->client; | 480 | server->client_sys = server->client; |
466 | } | 481 | } |
467 | |||
468 | if (server->flags & NFS_MOUNT_VER3) { | 482 | if (server->flags & NFS_MOUNT_VER3) { |
483 | #ifdef CONFIG_NFS_V3_ACL | ||
484 | if (!(server->flags & NFS_MOUNT_NOACL)) { | ||
485 | server->client_acl = rpc_bind_new_program(server->client, &nfsacl_program, 3); | ||
486 | /* No errors! Assume that Sun nfsacls are supported */ | ||
487 | if (!IS_ERR(server->client_acl)) | ||
488 | server->caps |= NFS_CAP_ACLS; | ||
489 | } | ||
490 | #else | ||
491 | server->flags &= ~NFS_MOUNT_NOACL; | ||
492 | #endif /* CONFIG_NFS_V3_ACL */ | ||
493 | /* | ||
494 | * The VFS shouldn't apply the umask to mode bits. We will | ||
495 | * do so ourselves when necessary. | ||
496 | */ | ||
497 | sb->s_flags |= MS_POSIXACL; | ||
469 | if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN) | 498 | if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN) |
470 | server->namelen = NFS3_MAXNAMLEN; | 499 | server->namelen = NFS3_MAXNAMLEN; |
471 | sb->s_time_gran = 1; | 500 | sb->s_time_gran = 1; |
@@ -549,6 +578,7 @@ static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt) | |||
549 | { NFS_MOUNT_NOCTO, ",nocto", "" }, | 578 | { NFS_MOUNT_NOCTO, ",nocto", "" }, |
550 | { NFS_MOUNT_NOAC, ",noac", "" }, | 579 | { NFS_MOUNT_NOAC, ",noac", "" }, |
551 | { NFS_MOUNT_NONLM, ",nolock", ",lock" }, | 580 | { NFS_MOUNT_NONLM, ",nolock", ",lock" }, |
581 | { NFS_MOUNT_NOACL, ",noacl", "" }, | ||
552 | { 0, NULL, NULL } | 582 | { 0, NULL, NULL } |
553 | }; | 583 | }; |
554 | struct proc_nfs_info *nfs_infop; | 584 | struct proc_nfs_info *nfs_infop; |
@@ -590,9 +620,19 @@ nfs_zap_caches(struct inode *inode) | |||
590 | 620 | ||
591 | memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode))); | 621 | memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode))); |
592 | if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) | 622 | if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) |
593 | nfsi->flags |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS; | 623 | nfsi->flags |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE; |
594 | else | 624 | else |
595 | nfsi->flags |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS; | 625 | nfsi->flags |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE; |
626 | } | ||
627 | |||
628 | static void nfs_zap_acl_cache(struct inode *inode) | ||
629 | { | ||
630 | void (*clear_acl_cache)(struct inode *); | ||
631 | |||
632 | clear_acl_cache = NFS_PROTO(inode)->clear_acl_cache; | ||
633 | if (clear_acl_cache != NULL) | ||
634 | clear_acl_cache(inode); | ||
635 | NFS_I(inode)->flags &= ~NFS_INO_INVALID_ACL; | ||
596 | } | 636 | } |
597 | 637 | ||
598 | /* | 638 | /* |
@@ -689,7 +729,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) | |||
689 | /* Why so? Because we want revalidate for devices/FIFOs, and | 729 | /* Why so? Because we want revalidate for devices/FIFOs, and |
690 | * that's precisely what we have in nfs_file_inode_operations. | 730 | * that's precisely what we have in nfs_file_inode_operations. |
691 | */ | 731 | */ |
692 | inode->i_op = &nfs_file_inode_operations; | 732 | inode->i_op = NFS_SB(sb)->rpc_ops->file_inode_ops; |
693 | if (S_ISREG(inode->i_mode)) { | 733 | if (S_ISREG(inode->i_mode)) { |
694 | inode->i_fop = &nfs_file_operations; | 734 | inode->i_fop = &nfs_file_operations; |
695 | inode->i_data.a_ops = &nfs_file_aops; | 735 | inode->i_data.a_ops = &nfs_file_aops; |
@@ -792,7 +832,7 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
792 | } | 832 | } |
793 | } | 833 | } |
794 | if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0) | 834 | if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0) |
795 | NFS_FLAGS(inode) |= NFS_INO_INVALID_ACCESS; | 835 | NFS_FLAGS(inode) |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; |
796 | nfs_end_data_update(inode); | 836 | nfs_end_data_update(inode); |
797 | unlock_kernel(); | 837 | unlock_kernel(); |
798 | return error; | 838 | return error; |
@@ -851,7 +891,7 @@ struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry, struct rp | |||
851 | ctx->state = NULL; | 891 | ctx->state = NULL; |
852 | ctx->lockowner = current->files; | 892 | ctx->lockowner = current->files; |
853 | ctx->error = 0; | 893 | ctx->error = 0; |
854 | init_waitqueue_head(&ctx->waitq); | 894 | ctx->dir_cookie = 0; |
855 | } | 895 | } |
856 | return ctx; | 896 | return ctx; |
857 | } | 897 | } |
@@ -1015,6 +1055,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) | |||
1015 | goto out; | 1055 | goto out; |
1016 | } | 1056 | } |
1017 | flags = nfsi->flags; | 1057 | flags = nfsi->flags; |
1058 | nfsi->flags &= ~NFS_INO_REVAL_PAGECACHE; | ||
1018 | /* | 1059 | /* |
1019 | * We may need to keep the attributes marked as invalid if | 1060 | * We may need to keep the attributes marked as invalid if |
1020 | * we raced with nfs_end_attr_update(). | 1061 | * we raced with nfs_end_attr_update(). |
@@ -1022,21 +1063,9 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) | |||
1022 | if (verifier == nfsi->cache_change_attribute) | 1063 | if (verifier == nfsi->cache_change_attribute) |
1023 | nfsi->flags &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME); | 1064 | nfsi->flags &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME); |
1024 | /* Do the page cache invalidation */ | 1065 | /* Do the page cache invalidation */ |
1025 | if (flags & NFS_INO_INVALID_DATA) { | 1066 | nfs_revalidate_mapping(inode, inode->i_mapping); |
1026 | if (S_ISREG(inode->i_mode)) { | 1067 | if (flags & NFS_INO_INVALID_ACL) |
1027 | if (filemap_fdatawrite(inode->i_mapping) == 0) | 1068 | nfs_zap_acl_cache(inode); |
1028 | filemap_fdatawait(inode->i_mapping); | ||
1029 | nfs_wb_all(inode); | ||
1030 | } | ||
1031 | nfsi->flags &= ~NFS_INO_INVALID_DATA; | ||
1032 | invalidate_inode_pages2(inode->i_mapping); | ||
1033 | memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode))); | ||
1034 | dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated\n", | ||
1035 | inode->i_sb->s_id, | ||
1036 | (long long)NFS_FILEID(inode)); | ||
1037 | /* This ensures we revalidate dentries */ | ||
1038 | nfsi->cache_change_attribute++; | ||
1039 | } | ||
1040 | dfprintk(PAGECACHE, "NFS: (%s/%Ld) revalidation complete\n", | 1069 | dfprintk(PAGECACHE, "NFS: (%s/%Ld) revalidation complete\n", |
1041 | inode->i_sb->s_id, | 1070 | inode->i_sb->s_id, |
1042 | (long long)NFS_FILEID(inode)); | 1071 | (long long)NFS_FILEID(inode)); |
@@ -1074,6 +1103,34 @@ int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) | |||
1074 | } | 1103 | } |
1075 | 1104 | ||
1076 | /** | 1105 | /** |
1106 | * nfs_revalidate_mapping - Revalidate the pagecache | ||
1107 | * @inode - pointer to host inode | ||
1108 | * @mapping - pointer to mapping | ||
1109 | */ | ||
1110 | void nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping) | ||
1111 | { | ||
1112 | struct nfs_inode *nfsi = NFS_I(inode); | ||
1113 | |||
1114 | if (nfsi->flags & NFS_INO_INVALID_DATA) { | ||
1115 | if (S_ISREG(inode->i_mode)) { | ||
1116 | if (filemap_fdatawrite(mapping) == 0) | ||
1117 | filemap_fdatawait(mapping); | ||
1118 | nfs_wb_all(inode); | ||
1119 | } | ||
1120 | invalidate_inode_pages2(mapping); | ||
1121 | nfsi->flags &= ~NFS_INO_INVALID_DATA; | ||
1122 | if (S_ISDIR(inode->i_mode)) { | ||
1123 | memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf)); | ||
1124 | /* This ensures we revalidate child dentries */ | ||
1125 | nfsi->cache_change_attribute++; | ||
1126 | } | ||
1127 | dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated\n", | ||
1128 | inode->i_sb->s_id, | ||
1129 | (long long)NFS_FILEID(inode)); | ||
1130 | } | ||
1131 | } | ||
1132 | |||
1133 | /** | ||
1077 | * nfs_begin_data_update | 1134 | * nfs_begin_data_update |
1078 | * @inode - pointer to inode | 1135 | * @inode - pointer to inode |
1079 | * Declare that a set of operations will update file data on the server | 1136 | * Declare that a set of operations will update file data on the server |
@@ -1106,27 +1163,6 @@ void nfs_end_data_update(struct inode *inode) | |||
1106 | } | 1163 | } |
1107 | 1164 | ||
1108 | /** | 1165 | /** |
1109 | * nfs_end_data_update_defer | ||
1110 | * @inode - pointer to inode | ||
1111 | * Declare end of the operations that will update file data | ||
1112 | * This will defer marking the inode as needing revalidation | ||
1113 | * unless there are no other pending updates. | ||
1114 | */ | ||
1115 | void nfs_end_data_update_defer(struct inode *inode) | ||
1116 | { | ||
1117 | struct nfs_inode *nfsi = NFS_I(inode); | ||
1118 | |||
1119 | if (atomic_dec_and_test(&nfsi->data_updates)) { | ||
1120 | /* Mark the attribute cache for revalidation */ | ||
1121 | nfsi->flags |= NFS_INO_INVALID_ATTR; | ||
1122 | /* Directories and symlinks: invalidate page cache too */ | ||
1123 | if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) | ||
1124 | nfsi->flags |= NFS_INO_INVALID_DATA; | ||
1125 | nfsi->cache_change_attribute ++; | ||
1126 | } | ||
1127 | } | ||
1128 | |||
1129 | /** | ||
1130 | * nfs_refresh_inode - verify consistency of the inode attribute cache | 1166 | * nfs_refresh_inode - verify consistency of the inode attribute cache |
1131 | * @inode - pointer to inode | 1167 | * @inode - pointer to inode |
1132 | * @fattr - updated attributes | 1168 | * @fattr - updated attributes |
@@ -1152,8 +1188,11 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1152 | if ((fattr->valid & NFS_ATTR_PRE_CHANGE) != 0 | 1188 | if ((fattr->valid & NFS_ATTR_PRE_CHANGE) != 0 |
1153 | && nfsi->change_attr == fattr->pre_change_attr) | 1189 | && nfsi->change_attr == fattr->pre_change_attr) |
1154 | nfsi->change_attr = fattr->change_attr; | 1190 | nfsi->change_attr = fattr->change_attr; |
1155 | if (!data_unstable && nfsi->change_attr != fattr->change_attr) | 1191 | if (nfsi->change_attr != fattr->change_attr) { |
1156 | nfsi->flags |= NFS_INO_INVALID_ATTR; | 1192 | nfsi->flags |= NFS_INO_INVALID_ATTR; |
1193 | if (!data_unstable) | ||
1194 | nfsi->flags |= NFS_INO_REVAL_PAGECACHE; | ||
1195 | } | ||
1157 | } | 1196 | } |
1158 | 1197 | ||
1159 | if ((fattr->valid & NFS_ATTR_FATTR) == 0) | 1198 | if ((fattr->valid & NFS_ATTR_FATTR) == 0) |
@@ -1176,18 +1215,22 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1176 | } | 1215 | } |
1177 | 1216 | ||
1178 | /* Verify a few of the more important attributes */ | 1217 | /* Verify a few of the more important attributes */ |
1179 | if (!data_unstable) { | 1218 | if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) { |
1180 | if (!timespec_equal(&inode->i_mtime, &fattr->mtime) | 1219 | nfsi->flags |= NFS_INO_INVALID_ATTR; |
1181 | || cur_size != new_isize) | 1220 | if (!data_unstable) |
1182 | nfsi->flags |= NFS_INO_INVALID_ATTR; | 1221 | nfsi->flags |= NFS_INO_REVAL_PAGECACHE; |
1183 | } else if (S_ISREG(inode->i_mode) && new_isize > cur_size) | 1222 | } |
1184 | nfsi->flags |= NFS_INO_INVALID_ATTR; | 1223 | if (cur_size != new_isize) { |
1224 | nfsi->flags |= NFS_INO_INVALID_ATTR; | ||
1225 | if (nfsi->npages == 0) | ||
1226 | nfsi->flags |= NFS_INO_REVAL_PAGECACHE; | ||
1227 | } | ||
1185 | 1228 | ||
1186 | /* Have any file permissions changed? */ | 1229 | /* Have any file permissions changed? */ |
1187 | if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) | 1230 | if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) |
1188 | || inode->i_uid != fattr->uid | 1231 | || inode->i_uid != fattr->uid |
1189 | || inode->i_gid != fattr->gid) | 1232 | || inode->i_gid != fattr->gid) |
1190 | nfsi->flags |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS; | 1233 | nfsi->flags |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL; |
1191 | 1234 | ||
1192 | /* Has the link count changed? */ | 1235 | /* Has the link count changed? */ |
1193 | if (inode->i_nlink != fattr->nlink) | 1236 | if (inode->i_nlink != fattr->nlink) |
@@ -1215,10 +1258,8 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1215 | static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsigned long verifier) | 1258 | static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsigned long verifier) |
1216 | { | 1259 | { |
1217 | struct nfs_inode *nfsi = NFS_I(inode); | 1260 | struct nfs_inode *nfsi = NFS_I(inode); |
1218 | __u64 new_size; | 1261 | loff_t cur_isize, new_isize; |
1219 | loff_t new_isize; | ||
1220 | unsigned int invalid = 0; | 1262 | unsigned int invalid = 0; |
1221 | loff_t cur_isize; | ||
1222 | int data_unstable; | 1263 | int data_unstable; |
1223 | 1264 | ||
1224 | dfprintk(VFS, "NFS: %s(%s/%ld ct=%d info=0x%x)\n", | 1265 | dfprintk(VFS, "NFS: %s(%s/%ld ct=%d info=0x%x)\n", |
@@ -1251,61 +1292,56 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsign | |||
1251 | /* Are we racing with known updates of the metadata on the server? */ | 1292 | /* Are we racing with known updates of the metadata on the server? */ |
1252 | data_unstable = ! nfs_verify_change_attribute(inode, verifier); | 1293 | data_unstable = ! nfs_verify_change_attribute(inode, verifier); |
1253 | 1294 | ||
1254 | /* Check if the file size agrees */ | 1295 | /* Check if our cached file size is stale */ |
1255 | new_size = fattr->size; | ||
1256 | new_isize = nfs_size_to_loff_t(fattr->size); | 1296 | new_isize = nfs_size_to_loff_t(fattr->size); |
1257 | cur_isize = i_size_read(inode); | 1297 | cur_isize = i_size_read(inode); |
1258 | if (cur_isize != new_size) { | 1298 | if (new_isize != cur_isize) { |
1259 | #ifdef NFS_DEBUG_VERBOSE | 1299 | /* Do we perhaps have any outstanding writes? */ |
1260 | printk(KERN_DEBUG "NFS: isize change on %s/%ld\n", inode->i_sb->s_id, inode->i_ino); | 1300 | if (nfsi->npages == 0) { |
1261 | #endif | 1301 | /* No, but did we race with nfs_end_data_update()? */ |
1262 | /* | 1302 | if (verifier == nfsi->cache_change_attribute) { |
1263 | * If we have pending writebacks, things can get | ||
1264 | * messy. | ||
1265 | */ | ||
1266 | if (S_ISREG(inode->i_mode) && data_unstable) { | ||
1267 | if (new_isize > cur_isize) { | ||
1268 | inode->i_size = new_isize; | 1303 | inode->i_size = new_isize; |
1269 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; | 1304 | invalid |= NFS_INO_INVALID_DATA; |
1270 | } | 1305 | } |
1271 | } else { | 1306 | invalid |= NFS_INO_INVALID_ATTR; |
1307 | } else if (new_isize > cur_isize) { | ||
1272 | inode->i_size = new_isize; | 1308 | inode->i_size = new_isize; |
1273 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; | 1309 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; |
1274 | } | 1310 | } |
1311 | dprintk("NFS: isize change on server for file %s/%ld\n", | ||
1312 | inode->i_sb->s_id, inode->i_ino); | ||
1275 | } | 1313 | } |
1276 | 1314 | ||
1277 | /* | 1315 | /* Check if the mtime agrees */ |
1278 | * Note: we don't check inode->i_mtime since pipes etc. | ||
1279 | * can change this value in VFS without requiring a | ||
1280 | * cache revalidation. | ||
1281 | */ | ||
1282 | if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) { | 1316 | if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) { |
1283 | memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime)); | 1317 | memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime)); |
1284 | #ifdef NFS_DEBUG_VERBOSE | 1318 | dprintk("NFS: mtime change on server for file %s/%ld\n", |
1285 | printk(KERN_DEBUG "NFS: mtime change on %s/%ld\n", inode->i_sb->s_id, inode->i_ino); | 1319 | inode->i_sb->s_id, inode->i_ino); |
1286 | #endif | ||
1287 | if (!data_unstable) | 1320 | if (!data_unstable) |
1288 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; | 1321 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; |
1289 | } | 1322 | } |
1290 | 1323 | ||
1291 | if ((fattr->valid & NFS_ATTR_FATTR_V4) | 1324 | if ((fattr->valid & NFS_ATTR_FATTR_V4) |
1292 | && nfsi->change_attr != fattr->change_attr) { | 1325 | && nfsi->change_attr != fattr->change_attr) { |
1293 | #ifdef NFS_DEBUG_VERBOSE | 1326 | dprintk("NFS: change_attr change on server for file %s/%ld\n", |
1294 | printk(KERN_DEBUG "NFS: change_attr change on %s/%ld\n", | ||
1295 | inode->i_sb->s_id, inode->i_ino); | 1327 | inode->i_sb->s_id, inode->i_ino); |
1296 | #endif | ||
1297 | nfsi->change_attr = fattr->change_attr; | 1328 | nfsi->change_attr = fattr->change_attr; |
1298 | if (!data_unstable) | 1329 | if (!data_unstable) |
1299 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS; | 1330 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; |
1300 | } | 1331 | } |
1301 | 1332 | ||
1302 | memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime)); | 1333 | /* If ctime has changed we should definitely clear access+acl caches */ |
1334 | if (!timespec_equal(&inode->i_ctime, &fattr->ctime)) { | ||
1335 | if (!data_unstable) | ||
1336 | invalid |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; | ||
1337 | memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime)); | ||
1338 | } | ||
1303 | memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime)); | 1339 | memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime)); |
1304 | 1340 | ||
1305 | if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) || | 1341 | if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) || |
1306 | inode->i_uid != fattr->uid || | 1342 | inode->i_uid != fattr->uid || |
1307 | inode->i_gid != fattr->gid) | 1343 | inode->i_gid != fattr->gid) |
1308 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS; | 1344 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; |
1309 | 1345 | ||
1310 | inode->i_mode = fattr->mode; | 1346 | inode->i_mode = fattr->mode; |
1311 | inode->i_nlink = fattr->nlink; | 1347 | inode->i_nlink = fattr->nlink; |
@@ -1385,74 +1421,95 @@ static struct super_block *nfs_get_sb(struct file_system_type *fs_type, | |||
1385 | int flags, const char *dev_name, void *raw_data) | 1421 | int flags, const char *dev_name, void *raw_data) |
1386 | { | 1422 | { |
1387 | int error; | 1423 | int error; |
1388 | struct nfs_server *server; | 1424 | struct nfs_server *server = NULL; |
1389 | struct super_block *s; | 1425 | struct super_block *s; |
1390 | struct nfs_fh *root; | 1426 | struct nfs_fh *root; |
1391 | struct nfs_mount_data *data = raw_data; | 1427 | struct nfs_mount_data *data = raw_data; |
1392 | 1428 | ||
1393 | if (!data) { | 1429 | s = ERR_PTR(-EINVAL); |
1394 | printk("nfs_read_super: missing data argument\n"); | 1430 | if (data == NULL) { |
1395 | return ERR_PTR(-EINVAL); | 1431 | dprintk("%s: missing data argument\n", __FUNCTION__); |
1432 | goto out_err; | ||
1433 | } | ||
1434 | if (data->version <= 0 || data->version > NFS_MOUNT_VERSION) { | ||
1435 | dprintk("%s: bad mount version\n", __FUNCTION__); | ||
1436 | goto out_err; | ||
1396 | } | 1437 | } |
1438 | switch (data->version) { | ||
1439 | case 1: | ||
1440 | data->namlen = 0; | ||
1441 | case 2: | ||
1442 | data->bsize = 0; | ||
1443 | case 3: | ||
1444 | if (data->flags & NFS_MOUNT_VER3) { | ||
1445 | dprintk("%s: mount structure version %d does not support NFSv3\n", | ||
1446 | __FUNCTION__, | ||
1447 | data->version); | ||
1448 | goto out_err; | ||
1449 | } | ||
1450 | data->root.size = NFS2_FHSIZE; | ||
1451 | memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE); | ||
1452 | case 4: | ||
1453 | if (data->flags & NFS_MOUNT_SECFLAVOUR) { | ||
1454 | dprintk("%s: mount structure version %d does not support strong security\n", | ||
1455 | __FUNCTION__, | ||
1456 | data->version); | ||
1457 | goto out_err; | ||
1458 | } | ||
1459 | case 5: | ||
1460 | memset(data->context, 0, sizeof(data->context)); | ||
1461 | } | ||
1462 | #ifndef CONFIG_NFS_V3 | ||
1463 | /* If NFSv3 is not compiled in, return -EPROTONOSUPPORT */ | ||
1464 | s = ERR_PTR(-EPROTONOSUPPORT); | ||
1465 | if (data->flags & NFS_MOUNT_VER3) { | ||
1466 | dprintk("%s: NFSv3 not compiled into kernel\n", __FUNCTION__); | ||
1467 | goto out_err; | ||
1468 | } | ||
1469 | #endif /* CONFIG_NFS_V3 */ | ||
1397 | 1470 | ||
1471 | s = ERR_PTR(-ENOMEM); | ||
1398 | server = kmalloc(sizeof(struct nfs_server), GFP_KERNEL); | 1472 | server = kmalloc(sizeof(struct nfs_server), GFP_KERNEL); |
1399 | if (!server) | 1473 | if (!server) |
1400 | return ERR_PTR(-ENOMEM); | 1474 | goto out_err; |
1401 | memset(server, 0, sizeof(struct nfs_server)); | 1475 | memset(server, 0, sizeof(struct nfs_server)); |
1402 | /* Zero out the NFS state stuff */ | 1476 | /* Zero out the NFS state stuff */ |
1403 | init_nfsv4_state(server); | 1477 | init_nfsv4_state(server); |
1404 | 1478 | server->client = server->client_sys = server->client_acl = ERR_PTR(-EINVAL); | |
1405 | if (data->version != NFS_MOUNT_VERSION) { | ||
1406 | printk("nfs warning: mount version %s than kernel\n", | ||
1407 | data->version < NFS_MOUNT_VERSION ? "older" : "newer"); | ||
1408 | if (data->version < 2) | ||
1409 | data->namlen = 0; | ||
1410 | if (data->version < 3) | ||
1411 | data->bsize = 0; | ||
1412 | if (data->version < 4) { | ||
1413 | data->flags &= ~NFS_MOUNT_VER3; | ||
1414 | data->root.size = NFS2_FHSIZE; | ||
1415 | memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE); | ||
1416 | } | ||
1417 | if (data->version < 5) | ||
1418 | data->flags &= ~NFS_MOUNT_SECFLAVOUR; | ||
1419 | } | ||
1420 | 1479 | ||
1421 | root = &server->fh; | 1480 | root = &server->fh; |
1422 | if (data->flags & NFS_MOUNT_VER3) | 1481 | if (data->flags & NFS_MOUNT_VER3) |
1423 | root->size = data->root.size; | 1482 | root->size = data->root.size; |
1424 | else | 1483 | else |
1425 | root->size = NFS2_FHSIZE; | 1484 | root->size = NFS2_FHSIZE; |
1485 | s = ERR_PTR(-EINVAL); | ||
1426 | if (root->size > sizeof(root->data)) { | 1486 | if (root->size > sizeof(root->data)) { |
1427 | printk("nfs_get_sb: invalid root filehandle\n"); | 1487 | dprintk("%s: invalid root filehandle\n", __FUNCTION__); |
1428 | kfree(server); | 1488 | goto out_err; |
1429 | return ERR_PTR(-EINVAL); | ||
1430 | } | 1489 | } |
1431 | memcpy(root->data, data->root.data, root->size); | 1490 | memcpy(root->data, data->root.data, root->size); |
1432 | 1491 | ||
1433 | /* We now require that the mount process passes the remote address */ | 1492 | /* We now require that the mount process passes the remote address */ |
1434 | memcpy(&server->addr, &data->addr, sizeof(server->addr)); | 1493 | memcpy(&server->addr, &data->addr, sizeof(server->addr)); |
1435 | if (server->addr.sin_addr.s_addr == INADDR_ANY) { | 1494 | if (server->addr.sin_addr.s_addr == INADDR_ANY) { |
1436 | printk("NFS: mount program didn't pass remote address!\n"); | 1495 | dprintk("%s: mount program didn't pass remote address!\n", |
1437 | kfree(server); | 1496 | __FUNCTION__); |
1438 | return ERR_PTR(-EINVAL); | 1497 | goto out_err; |
1439 | } | 1498 | } |
1440 | 1499 | ||
1441 | s = sget(fs_type, nfs_compare_super, nfs_set_super, server); | 1500 | /* Fire up rpciod if not yet running */ |
1442 | 1501 | s = ERR_PTR(rpciod_up()); | |
1443 | if (IS_ERR(s) || s->s_root) { | 1502 | if (IS_ERR(s)) { |
1444 | kfree(server); | 1503 | dprintk("%s: couldn't start rpciod! Error = %ld\n", |
1445 | return s; | 1504 | __FUNCTION__, PTR_ERR(s)); |
1505 | goto out_err; | ||
1446 | } | 1506 | } |
1447 | 1507 | ||
1448 | s->s_flags = flags; | 1508 | s = sget(fs_type, nfs_compare_super, nfs_set_super, server); |
1509 | if (IS_ERR(s) || s->s_root) | ||
1510 | goto out_rpciod_down; | ||
1449 | 1511 | ||
1450 | /* Fire up rpciod if not yet running */ | 1512 | s->s_flags = flags; |
1451 | if (rpciod_up() != 0) { | ||
1452 | printk(KERN_WARNING "NFS: couldn't start rpciod!\n"); | ||
1453 | kfree(server); | ||
1454 | return ERR_PTR(-EIO); | ||
1455 | } | ||
1456 | 1513 | ||
1457 | error = nfs_fill_super(s, data, flags & MS_VERBOSE ? 1 : 0); | 1514 | error = nfs_fill_super(s, data, flags & MS_VERBOSE ? 1 : 0); |
1458 | if (error) { | 1515 | if (error) { |
@@ -1462,6 +1519,11 @@ static struct super_block *nfs_get_sb(struct file_system_type *fs_type, | |||
1462 | } | 1519 | } |
1463 | s->s_flags |= MS_ACTIVE; | 1520 | s->s_flags |= MS_ACTIVE; |
1464 | return s; | 1521 | return s; |
1522 | out_rpciod_down: | ||
1523 | rpciod_down(); | ||
1524 | out_err: | ||
1525 | kfree(server); | ||
1526 | return s; | ||
1465 | } | 1527 | } |
1466 | 1528 | ||
1467 | static void nfs_kill_super(struct super_block *s) | 1529 | static void nfs_kill_super(struct super_block *s) |
@@ -1470,10 +1532,12 @@ static void nfs_kill_super(struct super_block *s) | |||
1470 | 1532 | ||
1471 | kill_anon_super(s); | 1533 | kill_anon_super(s); |
1472 | 1534 | ||
1473 | if (server->client != NULL && !IS_ERR(server->client)) | 1535 | if (!IS_ERR(server->client)) |
1474 | rpc_shutdown_client(server->client); | 1536 | rpc_shutdown_client(server->client); |
1475 | if (server->client_sys != NULL && !IS_ERR(server->client_sys)) | 1537 | if (!IS_ERR(server->client_sys)) |
1476 | rpc_shutdown_client(server->client_sys); | 1538 | rpc_shutdown_client(server->client_sys); |
1539 | if (!IS_ERR(server->client_acl)) | ||
1540 | rpc_shutdown_client(server->client_acl); | ||
1477 | 1541 | ||
1478 | if (!(server->flags & NFS_MOUNT_NONLM)) | 1542 | if (!(server->flags & NFS_MOUNT_NONLM)) |
1479 | lockd_down(); /* release rpc.lockd */ | 1543 | lockd_down(); /* release rpc.lockd */ |
@@ -1594,15 +1658,19 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, | |||
1594 | 1658 | ||
1595 | clp = nfs4_get_client(&server->addr.sin_addr); | 1659 | clp = nfs4_get_client(&server->addr.sin_addr); |
1596 | if (!clp) { | 1660 | if (!clp) { |
1597 | printk(KERN_WARNING "NFS: failed to create NFS4 client.\n"); | 1661 | dprintk("%s: failed to create NFS4 client.\n", __FUNCTION__); |
1598 | return -EIO; | 1662 | return -EIO; |
1599 | } | 1663 | } |
1600 | 1664 | ||
1601 | /* Now create transport and client */ | 1665 | /* Now create transport and client */ |
1602 | authflavour = RPC_AUTH_UNIX; | 1666 | authflavour = RPC_AUTH_UNIX; |
1603 | if (data->auth_flavourlen != 0) { | 1667 | if (data->auth_flavourlen != 0) { |
1604 | if (data->auth_flavourlen > 1) | 1668 | if (data->auth_flavourlen != 1) { |
1605 | printk(KERN_INFO "NFS: cannot yet deal with multiple auth flavours.\n"); | 1669 | dprintk("%s: Invalid number of RPC auth flavours %d.\n", |
1670 | __FUNCTION__, data->auth_flavourlen); | ||
1671 | err = -EINVAL; | ||
1672 | goto out_fail; | ||
1673 | } | ||
1606 | if (copy_from_user(&authflavour, data->auth_flavours, sizeof(authflavour))) { | 1674 | if (copy_from_user(&authflavour, data->auth_flavours, sizeof(authflavour))) { |
1607 | err = -EFAULT; | 1675 | err = -EFAULT; |
1608 | goto out_fail; | 1676 | goto out_fail; |
@@ -1610,21 +1678,22 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, | |||
1610 | } | 1678 | } |
1611 | 1679 | ||
1612 | down_write(&clp->cl_sem); | 1680 | down_write(&clp->cl_sem); |
1613 | if (clp->cl_rpcclient == NULL) { | 1681 | if (IS_ERR(clp->cl_rpcclient)) { |
1614 | xprt = xprt_create_proto(proto, &server->addr, &timeparms); | 1682 | xprt = xprt_create_proto(proto, &server->addr, &timeparms); |
1615 | if (IS_ERR(xprt)) { | 1683 | if (IS_ERR(xprt)) { |
1616 | up_write(&clp->cl_sem); | 1684 | up_write(&clp->cl_sem); |
1617 | printk(KERN_WARNING "NFS: cannot create RPC transport.\n"); | ||
1618 | err = PTR_ERR(xprt); | 1685 | err = PTR_ERR(xprt); |
1686 | dprintk("%s: cannot create RPC transport. Error = %d\n", | ||
1687 | __FUNCTION__, err); | ||
1619 | goto out_fail; | 1688 | goto out_fail; |
1620 | } | 1689 | } |
1621 | clnt = rpc_create_client(xprt, server->hostname, &nfs_program, | 1690 | clnt = rpc_create_client(xprt, server->hostname, &nfs_program, |
1622 | server->rpc_ops->version, authflavour); | 1691 | server->rpc_ops->version, authflavour); |
1623 | if (IS_ERR(clnt)) { | 1692 | if (IS_ERR(clnt)) { |
1624 | up_write(&clp->cl_sem); | 1693 | up_write(&clp->cl_sem); |
1625 | printk(KERN_WARNING "NFS: cannot create RPC client.\n"); | ||
1626 | xprt_destroy(xprt); | ||
1627 | err = PTR_ERR(clnt); | 1694 | err = PTR_ERR(clnt); |
1695 | dprintk("%s: cannot create RPC client. Error = %d\n", | ||
1696 | __FUNCTION__, err); | ||
1628 | goto out_fail; | 1697 | goto out_fail; |
1629 | } | 1698 | } |
1630 | clnt->cl_intr = 1; | 1699 | clnt->cl_intr = 1; |
@@ -1656,21 +1725,26 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, | |||
1656 | clp = NULL; | 1725 | clp = NULL; |
1657 | 1726 | ||
1658 | if (IS_ERR(clnt)) { | 1727 | if (IS_ERR(clnt)) { |
1659 | printk(KERN_WARNING "NFS: cannot create RPC client.\n"); | 1728 | err = PTR_ERR(clnt); |
1660 | return PTR_ERR(clnt); | 1729 | dprintk("%s: cannot create RPC client. Error = %d\n", |
1730 | __FUNCTION__, err); | ||
1731 | return err; | ||
1661 | } | 1732 | } |
1662 | 1733 | ||
1663 | server->client = clnt; | 1734 | server->client = clnt; |
1664 | 1735 | ||
1665 | if (server->nfs4_state->cl_idmap == NULL) { | 1736 | if (server->nfs4_state->cl_idmap == NULL) { |
1666 | printk(KERN_WARNING "NFS: failed to create idmapper.\n"); | 1737 | dprintk("%s: failed to create idmapper.\n", __FUNCTION__); |
1667 | return -ENOMEM; | 1738 | return -ENOMEM; |
1668 | } | 1739 | } |
1669 | 1740 | ||
1670 | if (clnt->cl_auth->au_flavor != authflavour) { | 1741 | if (clnt->cl_auth->au_flavor != authflavour) { |
1671 | if (rpcauth_create(authflavour, clnt) == NULL) { | 1742 | struct rpc_auth *auth; |
1672 | printk(KERN_WARNING "NFS: couldn't create credcache!\n"); | 1743 | |
1673 | return -ENOMEM; | 1744 | auth = rpcauth_create(authflavour, clnt); |
1745 | if (IS_ERR(auth)) { | ||
1746 | dprintk("%s: couldn't create credcache!\n", __FUNCTION__); | ||
1747 | return PTR_ERR(auth); | ||
1674 | } | 1748 | } |
1675 | } | 1749 | } |
1676 | 1750 | ||
@@ -1730,8 +1804,12 @@ static struct super_block *nfs4_get_sb(struct file_system_type *fs_type, | |||
1730 | struct nfs4_mount_data *data = raw_data; | 1804 | struct nfs4_mount_data *data = raw_data; |
1731 | void *p; | 1805 | void *p; |
1732 | 1806 | ||
1733 | if (!data) { | 1807 | if (data == NULL) { |
1734 | printk("nfs_read_super: missing data argument\n"); | 1808 | dprintk("%s: missing data argument\n", __FUNCTION__); |
1809 | return ERR_PTR(-EINVAL); | ||
1810 | } | ||
1811 | if (data->version <= 0 || data->version > NFS4_MOUNT_VERSION) { | ||
1812 | dprintk("%s: bad mount version\n", __FUNCTION__); | ||
1735 | return ERR_PTR(-EINVAL); | 1813 | return ERR_PTR(-EINVAL); |
1736 | } | 1814 | } |
1737 | 1815 | ||
@@ -1741,11 +1819,7 @@ static struct super_block *nfs4_get_sb(struct file_system_type *fs_type, | |||
1741 | memset(server, 0, sizeof(struct nfs_server)); | 1819 | memset(server, 0, sizeof(struct nfs_server)); |
1742 | /* Zero out the NFS state stuff */ | 1820 | /* Zero out the NFS state stuff */ |
1743 | init_nfsv4_state(server); | 1821 | init_nfsv4_state(server); |
1744 | 1822 | server->client = server->client_sys = server->client_acl = ERR_PTR(-EINVAL); | |
1745 | if (data->version != NFS4_MOUNT_VERSION) { | ||
1746 | printk("nfs warning: mount version %s than kernel\n", | ||
1747 | data->version < NFS4_MOUNT_VERSION ? "older" : "newer"); | ||
1748 | } | ||
1749 | 1823 | ||
1750 | p = nfs_copy_user_string(NULL, &data->hostname, 256); | 1824 | p = nfs_copy_user_string(NULL, &data->hostname, 256); |
1751 | if (IS_ERR(p)) | 1825 | if (IS_ERR(p)) |
@@ -1773,11 +1847,20 @@ static struct super_block *nfs4_get_sb(struct file_system_type *fs_type, | |||
1773 | } | 1847 | } |
1774 | if (server->addr.sin_family != AF_INET || | 1848 | if (server->addr.sin_family != AF_INET || |
1775 | server->addr.sin_addr.s_addr == INADDR_ANY) { | 1849 | server->addr.sin_addr.s_addr == INADDR_ANY) { |
1776 | printk("NFS: mount program didn't pass remote IP address!\n"); | 1850 | dprintk("%s: mount program didn't pass remote IP address!\n", |
1851 | __FUNCTION__); | ||
1777 | s = ERR_PTR(-EINVAL); | 1852 | s = ERR_PTR(-EINVAL); |
1778 | goto out_free; | 1853 | goto out_free; |
1779 | } | 1854 | } |
1780 | 1855 | ||
1856 | /* Fire up rpciod if not yet running */ | ||
1857 | s = ERR_PTR(rpciod_up()); | ||
1858 | if (IS_ERR(s)) { | ||
1859 | dprintk("%s: couldn't start rpciod! Error = %ld\n", | ||
1860 | __FUNCTION__, PTR_ERR(s)); | ||
1861 | goto out_free; | ||
1862 | } | ||
1863 | |||
1781 | s = sget(fs_type, nfs4_compare_super, nfs_set_super, server); | 1864 | s = sget(fs_type, nfs4_compare_super, nfs_set_super, server); |
1782 | 1865 | ||
1783 | if (IS_ERR(s) || s->s_root) | 1866 | if (IS_ERR(s) || s->s_root) |
@@ -1785,13 +1868,6 @@ static struct super_block *nfs4_get_sb(struct file_system_type *fs_type, | |||
1785 | 1868 | ||
1786 | s->s_flags = flags; | 1869 | s->s_flags = flags; |
1787 | 1870 | ||
1788 | /* Fire up rpciod if not yet running */ | ||
1789 | if (rpciod_up() != 0) { | ||
1790 | printk(KERN_WARNING "NFS: couldn't start rpciod!\n"); | ||
1791 | s = ERR_PTR(-EIO); | ||
1792 | goto out_free; | ||
1793 | } | ||
1794 | |||
1795 | error = nfs4_fill_super(s, data, flags & MS_VERBOSE ? 1 : 0); | 1871 | error = nfs4_fill_super(s, data, flags & MS_VERBOSE ? 1 : 0); |
1796 | if (error) { | 1872 | if (error) { |
1797 | up_write(&s->s_umount); | 1873 | up_write(&s->s_umount); |
@@ -1875,6 +1951,13 @@ static struct inode *nfs_alloc_inode(struct super_block *sb) | |||
1875 | if (!nfsi) | 1951 | if (!nfsi) |
1876 | return NULL; | 1952 | return NULL; |
1877 | nfsi->flags = 0; | 1953 | nfsi->flags = 0; |
1954 | #ifdef CONFIG_NFS_V3_ACL | ||
1955 | nfsi->acl_access = ERR_PTR(-EAGAIN); | ||
1956 | nfsi->acl_default = ERR_PTR(-EAGAIN); | ||
1957 | #endif | ||
1958 | #ifdef CONFIG_NFS_V4 | ||
1959 | nfsi->nfs4_acl = NULL; | ||
1960 | #endif /* CONFIG_NFS_V4 */ | ||
1878 | return &nfsi->vfs_inode; | 1961 | return &nfsi->vfs_inode; |
1879 | } | 1962 | } |
1880 | 1963 | ||
diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c index 9d3ddad96d9e..0e82617f2de0 100644 --- a/fs/nfs/mount_clnt.c +++ b/fs/nfs/mount_clnt.c | |||
@@ -80,9 +80,7 @@ mnt_create(char *hostname, struct sockaddr_in *srvaddr, int version, | |||
80 | clnt = rpc_create_client(xprt, hostname, | 80 | clnt = rpc_create_client(xprt, hostname, |
81 | &mnt_program, version, | 81 | &mnt_program, version, |
82 | RPC_AUTH_UNIX); | 82 | RPC_AUTH_UNIX); |
83 | if (IS_ERR(clnt)) { | 83 | if (!IS_ERR(clnt)) { |
84 | xprt_destroy(xprt); | ||
85 | } else { | ||
86 | clnt->cl_softrtry = 1; | 84 | clnt->cl_softrtry = 1; |
87 | clnt->cl_chatty = 1; | 85 | clnt->cl_chatty = 1; |
88 | clnt->cl_oneshot = 1; | 86 | clnt->cl_oneshot = 1; |
diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c new file mode 100644 index 000000000000..ee3536fc84a3 --- /dev/null +++ b/fs/nfs/nfs3acl.c | |||
@@ -0,0 +1,403 @@ | |||
1 | #include <linux/fs.h> | ||
2 | #include <linux/nfs.h> | ||
3 | #include <linux/nfs3.h> | ||
4 | #include <linux/nfs_fs.h> | ||
5 | #include <linux/xattr_acl.h> | ||
6 | #include <linux/nfsacl.h> | ||
7 | |||
8 | #define NFSDBG_FACILITY NFSDBG_PROC | ||
9 | |||
10 | ssize_t nfs3_listxattr(struct dentry *dentry, char *buffer, size_t size) | ||
11 | { | ||
12 | struct inode *inode = dentry->d_inode; | ||
13 | struct posix_acl *acl; | ||
14 | int pos=0, len=0; | ||
15 | |||
16 | # define output(s) do { \ | ||
17 | if (pos + sizeof(s) <= size) { \ | ||
18 | memcpy(buffer + pos, s, sizeof(s)); \ | ||
19 | pos += sizeof(s); \ | ||
20 | } \ | ||
21 | len += sizeof(s); \ | ||
22 | } while(0) | ||
23 | |||
24 | acl = nfs3_proc_getacl(inode, ACL_TYPE_ACCESS); | ||
25 | if (IS_ERR(acl)) | ||
26 | return PTR_ERR(acl); | ||
27 | if (acl) { | ||
28 | output("system.posix_acl_access"); | ||
29 | posix_acl_release(acl); | ||
30 | } | ||
31 | |||
32 | if (S_ISDIR(inode->i_mode)) { | ||
33 | acl = nfs3_proc_getacl(inode, ACL_TYPE_DEFAULT); | ||
34 | if (IS_ERR(acl)) | ||
35 | return PTR_ERR(acl); | ||
36 | if (acl) { | ||
37 | output("system.posix_acl_default"); | ||
38 | posix_acl_release(acl); | ||
39 | } | ||
40 | } | ||
41 | |||
42 | # undef output | ||
43 | |||
44 | if (!buffer || len <= size) | ||
45 | return len; | ||
46 | return -ERANGE; | ||
47 | } | ||
48 | |||
49 | ssize_t nfs3_getxattr(struct dentry *dentry, const char *name, | ||
50 | void *buffer, size_t size) | ||
51 | { | ||
52 | struct inode *inode = dentry->d_inode; | ||
53 | struct posix_acl *acl; | ||
54 | int type, error = 0; | ||
55 | |||
56 | if (strcmp(name, XATTR_NAME_ACL_ACCESS) == 0) | ||
57 | type = ACL_TYPE_ACCESS; | ||
58 | else if (strcmp(name, XATTR_NAME_ACL_DEFAULT) == 0) | ||
59 | type = ACL_TYPE_DEFAULT; | ||
60 | else | ||
61 | return -EOPNOTSUPP; | ||
62 | |||
63 | acl = nfs3_proc_getacl(inode, type); | ||
64 | if (IS_ERR(acl)) | ||
65 | return PTR_ERR(acl); | ||
66 | else if (acl) { | ||
67 | if (type == ACL_TYPE_ACCESS && acl->a_count == 0) | ||
68 | error = -ENODATA; | ||
69 | else | ||
70 | error = posix_acl_to_xattr(acl, buffer, size); | ||
71 | posix_acl_release(acl); | ||
72 | } else | ||
73 | error = -ENODATA; | ||
74 | |||
75 | return error; | ||
76 | } | ||
77 | |||
78 | int nfs3_setxattr(struct dentry *dentry, const char *name, | ||
79 | const void *value, size_t size, int flags) | ||
80 | { | ||
81 | struct inode *inode = dentry->d_inode; | ||
82 | struct posix_acl *acl; | ||
83 | int type, error; | ||
84 | |||
85 | if (strcmp(name, XATTR_NAME_ACL_ACCESS) == 0) | ||
86 | type = ACL_TYPE_ACCESS; | ||
87 | else if (strcmp(name, XATTR_NAME_ACL_DEFAULT) == 0) | ||
88 | type = ACL_TYPE_DEFAULT; | ||
89 | else | ||
90 | return -EOPNOTSUPP; | ||
91 | |||
92 | acl = posix_acl_from_xattr(value, size); | ||
93 | if (IS_ERR(acl)) | ||
94 | return PTR_ERR(acl); | ||
95 | error = nfs3_proc_setacl(inode, type, acl); | ||
96 | posix_acl_release(acl); | ||
97 | |||
98 | return error; | ||
99 | } | ||
100 | |||
101 | int nfs3_removexattr(struct dentry *dentry, const char *name) | ||
102 | { | ||
103 | struct inode *inode = dentry->d_inode; | ||
104 | int type; | ||
105 | |||
106 | if (strcmp(name, XATTR_NAME_ACL_ACCESS) == 0) | ||
107 | type = ACL_TYPE_ACCESS; | ||
108 | else if (strcmp(name, XATTR_NAME_ACL_DEFAULT) == 0) | ||
109 | type = ACL_TYPE_DEFAULT; | ||
110 | else | ||
111 | return -EOPNOTSUPP; | ||
112 | |||
113 | return nfs3_proc_setacl(inode, type, NULL); | ||
114 | } | ||
115 | |||
116 | static void __nfs3_forget_cached_acls(struct nfs_inode *nfsi) | ||
117 | { | ||
118 | if (!IS_ERR(nfsi->acl_access)) { | ||
119 | posix_acl_release(nfsi->acl_access); | ||
120 | nfsi->acl_access = ERR_PTR(-EAGAIN); | ||
121 | } | ||
122 | if (!IS_ERR(nfsi->acl_default)) { | ||
123 | posix_acl_release(nfsi->acl_default); | ||
124 | nfsi->acl_default = ERR_PTR(-EAGAIN); | ||
125 | } | ||
126 | } | ||
127 | |||
128 | void nfs3_forget_cached_acls(struct inode *inode) | ||
129 | { | ||
130 | dprintk("NFS: nfs3_forget_cached_acls(%s/%ld)\n", inode->i_sb->s_id, | ||
131 | inode->i_ino); | ||
132 | spin_lock(&inode->i_lock); | ||
133 | __nfs3_forget_cached_acls(NFS_I(inode)); | ||
134 | spin_unlock(&inode->i_lock); | ||
135 | } | ||
136 | |||
137 | static struct posix_acl *nfs3_get_cached_acl(struct inode *inode, int type) | ||
138 | { | ||
139 | struct nfs_inode *nfsi = NFS_I(inode); | ||
140 | struct posix_acl *acl = ERR_PTR(-EINVAL); | ||
141 | |||
142 | spin_lock(&inode->i_lock); | ||
143 | switch(type) { | ||
144 | case ACL_TYPE_ACCESS: | ||
145 | acl = nfsi->acl_access; | ||
146 | break; | ||
147 | |||
148 | case ACL_TYPE_DEFAULT: | ||
149 | acl = nfsi->acl_default; | ||
150 | break; | ||
151 | |||
152 | default: | ||
153 | goto out; | ||
154 | } | ||
155 | if (IS_ERR(acl)) | ||
156 | acl = ERR_PTR(-EAGAIN); | ||
157 | else | ||
158 | acl = posix_acl_dup(acl); | ||
159 | out: | ||
160 | spin_unlock(&inode->i_lock); | ||
161 | dprintk("NFS: nfs3_get_cached_acl(%s/%ld, %d) = %p\n", inode->i_sb->s_id, | ||
162 | inode->i_ino, type, acl); | ||
163 | return acl; | ||
164 | } | ||
165 | |||
166 | static void nfs3_cache_acls(struct inode *inode, struct posix_acl *acl, | ||
167 | struct posix_acl *dfacl) | ||
168 | { | ||
169 | struct nfs_inode *nfsi = NFS_I(inode); | ||
170 | |||
171 | dprintk("nfs3_cache_acls(%s/%ld, %p, %p)\n", inode->i_sb->s_id, | ||
172 | inode->i_ino, acl, dfacl); | ||
173 | spin_lock(&inode->i_lock); | ||
174 | __nfs3_forget_cached_acls(NFS_I(inode)); | ||
175 | nfsi->acl_access = posix_acl_dup(acl); | ||
176 | nfsi->acl_default = posix_acl_dup(dfacl); | ||
177 | spin_unlock(&inode->i_lock); | ||
178 | } | ||
179 | |||
180 | struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) | ||
181 | { | ||
182 | struct nfs_server *server = NFS_SERVER(inode); | ||
183 | struct nfs_fattr fattr; | ||
184 | struct page *pages[NFSACL_MAXPAGES] = { }; | ||
185 | struct nfs3_getaclargs args = { | ||
186 | .fh = NFS_FH(inode), | ||
187 | /* The xdr layer may allocate pages here. */ | ||
188 | .pages = pages, | ||
189 | }; | ||
190 | struct nfs3_getaclres res = { | ||
191 | .fattr = &fattr, | ||
192 | }; | ||
193 | struct posix_acl *acl; | ||
194 | int status, count; | ||
195 | |||
196 | if (!nfs_server_capable(inode, NFS_CAP_ACLS)) | ||
197 | return ERR_PTR(-EOPNOTSUPP); | ||
198 | |||
199 | status = nfs_revalidate_inode(server, inode); | ||
200 | if (status < 0) | ||
201 | return ERR_PTR(status); | ||
202 | acl = nfs3_get_cached_acl(inode, type); | ||
203 | if (acl != ERR_PTR(-EAGAIN)) | ||
204 | return acl; | ||
205 | acl = NULL; | ||
206 | |||
207 | /* | ||
208 | * Only get the access acl when explicitly requested: We don't | ||
209 | * need it for access decisions, and only some applications use | ||
210 | * it. Applications which request the access acl first are not | ||
211 | * penalized from this optimization. | ||
212 | */ | ||
213 | if (type == ACL_TYPE_ACCESS) | ||
214 | args.mask |= NFS_ACLCNT|NFS_ACL; | ||
215 | if (S_ISDIR(inode->i_mode)) | ||
216 | args.mask |= NFS_DFACLCNT|NFS_DFACL; | ||
217 | if (args.mask == 0) | ||
218 | return NULL; | ||
219 | |||
220 | dprintk("NFS call getacl\n"); | ||
221 | status = rpc_call(server->client_acl, ACLPROC3_GETACL, | ||
222 | &args, &res, 0); | ||
223 | dprintk("NFS reply getacl: %d\n", status); | ||
224 | |||
225 | /* pages may have been allocated at the xdr layer. */ | ||
226 | for (count = 0; count < NFSACL_MAXPAGES && args.pages[count]; count++) | ||
227 | __free_page(args.pages[count]); | ||
228 | |||
229 | switch (status) { | ||
230 | case 0: | ||
231 | status = nfs_refresh_inode(inode, &fattr); | ||
232 | break; | ||
233 | case -EPFNOSUPPORT: | ||
234 | case -EPROTONOSUPPORT: | ||
235 | dprintk("NFS_V3_ACL extension not supported; disabling\n"); | ||
236 | server->caps &= ~NFS_CAP_ACLS; | ||
237 | case -ENOTSUPP: | ||
238 | status = -EOPNOTSUPP; | ||
239 | default: | ||
240 | goto getout; | ||
241 | } | ||
242 | if ((args.mask & res.mask) != args.mask) { | ||
243 | status = -EIO; | ||
244 | goto getout; | ||
245 | } | ||
246 | |||
247 | if (res.acl_access != NULL) { | ||
248 | if (posix_acl_equiv_mode(res.acl_access, NULL) == 0) { | ||
249 | posix_acl_release(res.acl_access); | ||
250 | res.acl_access = NULL; | ||
251 | } | ||
252 | } | ||
253 | nfs3_cache_acls(inode, res.acl_access, res.acl_default); | ||
254 | |||
255 | switch(type) { | ||
256 | case ACL_TYPE_ACCESS: | ||
257 | acl = res.acl_access; | ||
258 | res.acl_access = NULL; | ||
259 | break; | ||
260 | |||
261 | case ACL_TYPE_DEFAULT: | ||
262 | acl = res.acl_default; | ||
263 | res.acl_default = NULL; | ||
264 | } | ||
265 | |||
266 | getout: | ||
267 | posix_acl_release(res.acl_access); | ||
268 | posix_acl_release(res.acl_default); | ||
269 | |||
270 | if (status != 0) { | ||
271 | posix_acl_release(acl); | ||
272 | acl = ERR_PTR(status); | ||
273 | } | ||
274 | return acl; | ||
275 | } | ||
276 | |||
277 | static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, | ||
278 | struct posix_acl *dfacl) | ||
279 | { | ||
280 | struct nfs_server *server = NFS_SERVER(inode); | ||
281 | struct nfs_fattr fattr; | ||
282 | struct page *pages[NFSACL_MAXPAGES] = { }; | ||
283 | struct nfs3_setaclargs args = { | ||
284 | .inode = inode, | ||
285 | .mask = NFS_ACL, | ||
286 | .acl_access = acl, | ||
287 | .pages = pages, | ||
288 | }; | ||
289 | int status, count; | ||
290 | |||
291 | status = -EOPNOTSUPP; | ||
292 | if (!nfs_server_capable(inode, NFS_CAP_ACLS)) | ||
293 | goto out; | ||
294 | |||
295 | /* We are doing this here, because XDR marshalling can only | ||
296 | return -ENOMEM. */ | ||
297 | status = -ENOSPC; | ||
298 | if (acl != NULL && acl->a_count > NFS_ACL_MAX_ENTRIES) | ||
299 | goto out; | ||
300 | if (dfacl != NULL && dfacl->a_count > NFS_ACL_MAX_ENTRIES) | ||
301 | goto out; | ||
302 | if (S_ISDIR(inode->i_mode)) { | ||
303 | args.mask |= NFS_DFACL; | ||
304 | args.acl_default = dfacl; | ||
305 | } | ||
306 | |||
307 | dprintk("NFS call setacl\n"); | ||
308 | nfs_begin_data_update(inode); | ||
309 | status = rpc_call(server->client_acl, ACLPROC3_SETACL, | ||
310 | &args, &fattr, 0); | ||
311 | NFS_FLAGS(inode) |= NFS_INO_INVALID_ACCESS; | ||
312 | nfs_end_data_update(inode); | ||
313 | dprintk("NFS reply setacl: %d\n", status); | ||
314 | |||
315 | /* pages may have been allocated at the xdr layer. */ | ||
316 | for (count = 0; count < NFSACL_MAXPAGES && args.pages[count]; count++) | ||
317 | __free_page(args.pages[count]); | ||
318 | |||
319 | switch (status) { | ||
320 | case 0: | ||
321 | status = nfs_refresh_inode(inode, &fattr); | ||
322 | break; | ||
323 | case -EPFNOSUPPORT: | ||
324 | case -EPROTONOSUPPORT: | ||
325 | dprintk("NFS_V3_ACL SETACL RPC not supported" | ||
326 | "(will not retry)\n"); | ||
327 | server->caps &= ~NFS_CAP_ACLS; | ||
328 | case -ENOTSUPP: | ||
329 | status = -EOPNOTSUPP; | ||
330 | } | ||
331 | out: | ||
332 | return status; | ||
333 | } | ||
334 | |||
335 | int nfs3_proc_setacl(struct inode *inode, int type, struct posix_acl *acl) | ||
336 | { | ||
337 | struct posix_acl *alloc = NULL, *dfacl = NULL; | ||
338 | int status; | ||
339 | |||
340 | if (S_ISDIR(inode->i_mode)) { | ||
341 | switch(type) { | ||
342 | case ACL_TYPE_ACCESS: | ||
343 | alloc = dfacl = nfs3_proc_getacl(inode, | ||
344 | ACL_TYPE_DEFAULT); | ||
345 | if (IS_ERR(alloc)) | ||
346 | goto fail; | ||
347 | break; | ||
348 | |||
349 | case ACL_TYPE_DEFAULT: | ||
350 | dfacl = acl; | ||
351 | alloc = acl = nfs3_proc_getacl(inode, | ||
352 | ACL_TYPE_ACCESS); | ||
353 | if (IS_ERR(alloc)) | ||
354 | goto fail; | ||
355 | break; | ||
356 | |||
357 | default: | ||
358 | return -EINVAL; | ||
359 | } | ||
360 | } else if (type != ACL_TYPE_ACCESS) | ||
361 | return -EINVAL; | ||
362 | |||
363 | if (acl == NULL) { | ||
364 | alloc = acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); | ||
365 | if (IS_ERR(alloc)) | ||
366 | goto fail; | ||
367 | } | ||
368 | status = nfs3_proc_setacls(inode, acl, dfacl); | ||
369 | posix_acl_release(alloc); | ||
370 | return status; | ||
371 | |||
372 | fail: | ||
373 | return PTR_ERR(alloc); | ||
374 | } | ||
375 | |||
376 | int nfs3_proc_set_default_acl(struct inode *dir, struct inode *inode, | ||
377 | mode_t mode) | ||
378 | { | ||
379 | struct posix_acl *dfacl, *acl; | ||
380 | int error = 0; | ||
381 | |||
382 | dfacl = nfs3_proc_getacl(dir, ACL_TYPE_DEFAULT); | ||
383 | if (IS_ERR(dfacl)) { | ||
384 | error = PTR_ERR(dfacl); | ||
385 | return (error == -EOPNOTSUPP) ? 0 : error; | ||
386 | } | ||
387 | if (!dfacl) | ||
388 | return 0; | ||
389 | acl = posix_acl_clone(dfacl, GFP_KERNEL); | ||
390 | error = -ENOMEM; | ||
391 | if (!acl) | ||
392 | goto out_release_dfacl; | ||
393 | error = posix_acl_create_masq(acl, &mode); | ||
394 | if (error < 0) | ||
395 | goto out_release_acl; | ||
396 | error = nfs3_proc_setacls(inode, acl, S_ISDIR(inode->i_mode) ? | ||
397 | dfacl : NULL); | ||
398 | out_release_acl: | ||
399 | posix_acl_release(acl); | ||
400 | out_release_dfacl: | ||
401 | posix_acl_release(dfacl); | ||
402 | return error; | ||
403 | } | ||
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index 3878494dfc2c..7851569b31c6 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/nfs_page.h> | 17 | #include <linux/nfs_page.h> |
18 | #include <linux/lockd/bind.h> | 18 | #include <linux/lockd/bind.h> |
19 | #include <linux/smp_lock.h> | 19 | #include <linux/smp_lock.h> |
20 | #include <linux/nfs_mount.h> | ||
20 | 21 | ||
21 | #define NFSDBG_FACILITY NFSDBG_PROC | 22 | #define NFSDBG_FACILITY NFSDBG_PROC |
22 | 23 | ||
@@ -45,7 +46,7 @@ static inline int | |||
45 | nfs3_rpc_call_wrapper(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, int flags) | 46 | nfs3_rpc_call_wrapper(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, int flags) |
46 | { | 47 | { |
47 | struct rpc_message msg = { | 48 | struct rpc_message msg = { |
48 | .rpc_proc = &nfs3_procedures[proc], | 49 | .rpc_proc = &clnt->cl_procinfo[proc], |
49 | .rpc_argp = argp, | 50 | .rpc_argp = argp, |
50 | .rpc_resp = resp, | 51 | .rpc_resp = resp, |
51 | }; | 52 | }; |
@@ -313,7 +314,8 @@ nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
313 | .fh = &fhandle, | 314 | .fh = &fhandle, |
314 | .fattr = &fattr | 315 | .fattr = &fattr |
315 | }; | 316 | }; |
316 | int status; | 317 | mode_t mode = sattr->ia_mode; |
318 | int status; | ||
317 | 319 | ||
318 | dprintk("NFS call create %s\n", dentry->d_name.name); | 320 | dprintk("NFS call create %s\n", dentry->d_name.name); |
319 | arg.createmode = NFS3_CREATE_UNCHECKED; | 321 | arg.createmode = NFS3_CREATE_UNCHECKED; |
@@ -323,6 +325,8 @@ nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
323 | arg.verifier[1] = current->pid; | 325 | arg.verifier[1] = current->pid; |
324 | } | 326 | } |
325 | 327 | ||
328 | sattr->ia_mode &= ~current->fs->umask; | ||
329 | |||
326 | again: | 330 | again: |
327 | dir_attr.valid = 0; | 331 | dir_attr.valid = 0; |
328 | fattr.valid = 0; | 332 | fattr.valid = 0; |
@@ -369,6 +373,9 @@ again: | |||
369 | nfs_refresh_inode(dentry->d_inode, &fattr); | 373 | nfs_refresh_inode(dentry->d_inode, &fattr); |
370 | dprintk("NFS reply setattr (post-create): %d\n", status); | 374 | dprintk("NFS reply setattr (post-create): %d\n", status); |
371 | } | 375 | } |
376 | if (status != 0) | ||
377 | goto out; | ||
378 | status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode); | ||
372 | out: | 379 | out: |
373 | dprintk("NFS reply create: %d\n", status); | 380 | dprintk("NFS reply create: %d\n", status); |
374 | return status; | 381 | return status; |
@@ -538,15 +545,24 @@ nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr) | |||
538 | .fh = &fhandle, | 545 | .fh = &fhandle, |
539 | .fattr = &fattr | 546 | .fattr = &fattr |
540 | }; | 547 | }; |
541 | int status; | 548 | int mode = sattr->ia_mode; |
549 | int status; | ||
542 | 550 | ||
543 | dprintk("NFS call mkdir %s\n", dentry->d_name.name); | 551 | dprintk("NFS call mkdir %s\n", dentry->d_name.name); |
544 | dir_attr.valid = 0; | 552 | dir_attr.valid = 0; |
545 | fattr.valid = 0; | 553 | fattr.valid = 0; |
554 | |||
555 | sattr->ia_mode &= ~current->fs->umask; | ||
556 | |||
546 | status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKDIR, &arg, &res, 0); | 557 | status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKDIR, &arg, &res, 0); |
547 | nfs_refresh_inode(dir, &dir_attr); | 558 | nfs_refresh_inode(dir, &dir_attr); |
548 | if (status == 0) | 559 | if (status != 0) |
549 | status = nfs_instantiate(dentry, &fhandle, &fattr); | 560 | goto out; |
561 | status = nfs_instantiate(dentry, &fhandle, &fattr); | ||
562 | if (status != 0) | ||
563 | goto out; | ||
564 | status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode); | ||
565 | out: | ||
550 | dprintk("NFS reply mkdir: %d\n", status); | 566 | dprintk("NFS reply mkdir: %d\n", status); |
551 | return status; | 567 | return status; |
552 | } | 568 | } |
@@ -641,6 +657,7 @@ nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
641 | .fh = &fh, | 657 | .fh = &fh, |
642 | .fattr = &fattr | 658 | .fattr = &fattr |
643 | }; | 659 | }; |
660 | mode_t mode = sattr->ia_mode; | ||
644 | int status; | 661 | int status; |
645 | 662 | ||
646 | switch (sattr->ia_mode & S_IFMT) { | 663 | switch (sattr->ia_mode & S_IFMT) { |
@@ -653,12 +670,20 @@ nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
653 | 670 | ||
654 | dprintk("NFS call mknod %s %u:%u\n", dentry->d_name.name, | 671 | dprintk("NFS call mknod %s %u:%u\n", dentry->d_name.name, |
655 | MAJOR(rdev), MINOR(rdev)); | 672 | MAJOR(rdev), MINOR(rdev)); |
673 | |||
674 | sattr->ia_mode &= ~current->fs->umask; | ||
675 | |||
656 | dir_attr.valid = 0; | 676 | dir_attr.valid = 0; |
657 | fattr.valid = 0; | 677 | fattr.valid = 0; |
658 | status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKNOD, &arg, &res, 0); | 678 | status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKNOD, &arg, &res, 0); |
659 | nfs_refresh_inode(dir, &dir_attr); | 679 | nfs_refresh_inode(dir, &dir_attr); |
660 | if (status == 0) | 680 | if (status != 0) |
661 | status = nfs_instantiate(dentry, &fh, &fattr); | 681 | goto out; |
682 | status = nfs_instantiate(dentry, &fh, &fattr); | ||
683 | if (status != 0) | ||
684 | goto out; | ||
685 | status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode); | ||
686 | out: | ||
662 | dprintk("NFS reply mknod: %d\n", status); | 687 | dprintk("NFS reply mknod: %d\n", status); |
663 | return status; | 688 | return status; |
664 | } | 689 | } |
@@ -825,7 +850,8 @@ nfs3_proc_lock(struct file *filp, int cmd, struct file_lock *fl) | |||
825 | struct nfs_rpc_ops nfs_v3_clientops = { | 850 | struct nfs_rpc_ops nfs_v3_clientops = { |
826 | .version = 3, /* protocol version */ | 851 | .version = 3, /* protocol version */ |
827 | .dentry_ops = &nfs_dentry_operations, | 852 | .dentry_ops = &nfs_dentry_operations, |
828 | .dir_inode_ops = &nfs_dir_inode_operations, | 853 | .dir_inode_ops = &nfs3_dir_inode_operations, |
854 | .file_inode_ops = &nfs3_file_inode_operations, | ||
829 | .getroot = nfs3_proc_get_root, | 855 | .getroot = nfs3_proc_get_root, |
830 | .getattr = nfs3_proc_getattr, | 856 | .getattr = nfs3_proc_getattr, |
831 | .setattr = nfs3_proc_setattr, | 857 | .setattr = nfs3_proc_setattr, |
@@ -856,4 +882,5 @@ struct nfs_rpc_ops nfs_v3_clientops = { | |||
856 | .file_open = nfs_open, | 882 | .file_open = nfs_open, |
857 | .file_release = nfs_release, | 883 | .file_release = nfs_release, |
858 | .lock = nfs3_proc_lock, | 884 | .lock = nfs3_proc_lock, |
885 | .clear_acl_cache = nfs3_forget_cached_acls, | ||
859 | }; | 886 | }; |
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c index a3593d47e5ab..db4a904810a4 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/nfs.h> | 21 | #include <linux/nfs.h> |
22 | #include <linux/nfs3.h> | 22 | #include <linux/nfs3.h> |
23 | #include <linux/nfs_fs.h> | 23 | #include <linux/nfs_fs.h> |
24 | #include <linux/nfsacl.h> | ||
24 | 25 | ||
25 | #define NFSDBG_FACILITY NFSDBG_XDR | 26 | #define NFSDBG_FACILITY NFSDBG_XDR |
26 | 27 | ||
@@ -79,6 +80,11 @@ extern int nfs_stat_to_errno(int); | |||
79 | #define NFS3_pathconfres_sz (1+NFS3_post_op_attr_sz+6) | 80 | #define NFS3_pathconfres_sz (1+NFS3_post_op_attr_sz+6) |
80 | #define NFS3_commitres_sz (1+NFS3_wcc_data_sz+2) | 81 | #define NFS3_commitres_sz (1+NFS3_wcc_data_sz+2) |
81 | 82 | ||
83 | #define ACL3_getaclargs_sz (NFS3_fh_sz+1) | ||
84 | #define ACL3_setaclargs_sz (NFS3_fh_sz+1+2*(2+5*3)) | ||
85 | #define ACL3_getaclres_sz (1+NFS3_post_op_attr_sz+1+2*(2+5*3)) | ||
86 | #define ACL3_setaclres_sz (1+NFS3_post_op_attr_sz) | ||
87 | |||
82 | /* | 88 | /* |
83 | * Map file type to S_IFMT bits | 89 | * Map file type to S_IFMT bits |
84 | */ | 90 | */ |
@@ -627,6 +633,74 @@ nfs3_xdr_commitargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args) | |||
627 | return 0; | 633 | return 0; |
628 | } | 634 | } |
629 | 635 | ||
636 | #ifdef CONFIG_NFS_V3_ACL | ||
637 | /* | ||
638 | * Encode GETACL arguments | ||
639 | */ | ||
640 | static int | ||
641 | nfs3_xdr_getaclargs(struct rpc_rqst *req, u32 *p, | ||
642 | struct nfs3_getaclargs *args) | ||
643 | { | ||
644 | struct rpc_auth *auth = req->rq_task->tk_auth; | ||
645 | unsigned int replen; | ||
646 | |||
647 | p = xdr_encode_fhandle(p, args->fh); | ||
648 | *p++ = htonl(args->mask); | ||
649 | req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); | ||
650 | |||
651 | if (args->mask & (NFS_ACL | NFS_DFACL)) { | ||
652 | /* Inline the page array */ | ||
653 | replen = (RPC_REPHDRSIZE + auth->au_rslack + | ||
654 | ACL3_getaclres_sz) << 2; | ||
655 | xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, | ||
656 | NFSACL_MAXPAGES << PAGE_SHIFT); | ||
657 | } | ||
658 | return 0; | ||
659 | } | ||
660 | |||
661 | /* | ||
662 | * Encode SETACL arguments | ||
663 | */ | ||
664 | static int | ||
665 | nfs3_xdr_setaclargs(struct rpc_rqst *req, u32 *p, | ||
666 | struct nfs3_setaclargs *args) | ||
667 | { | ||
668 | struct xdr_buf *buf = &req->rq_snd_buf; | ||
669 | unsigned int base, len_in_head, len = nfsacl_size( | ||
670 | (args->mask & NFS_ACL) ? args->acl_access : NULL, | ||
671 | (args->mask & NFS_DFACL) ? args->acl_default : NULL); | ||
672 | int count, err; | ||
673 | |||
674 | p = xdr_encode_fhandle(p, NFS_FH(args->inode)); | ||
675 | *p++ = htonl(args->mask); | ||
676 | base = (char *)p - (char *)buf->head->iov_base; | ||
677 | /* put as much of the acls into head as possible. */ | ||
678 | len_in_head = min_t(unsigned int, buf->head->iov_len - base, len); | ||
679 | len -= len_in_head; | ||
680 | req->rq_slen = xdr_adjust_iovec(req->rq_svec, p + (len_in_head >> 2)); | ||
681 | |||
682 | for (count = 0; (count << PAGE_SHIFT) < len; count++) { | ||
683 | args->pages[count] = alloc_page(GFP_KERNEL); | ||
684 | if (!args->pages[count]) { | ||
685 | while (count) | ||
686 | __free_page(args->pages[--count]); | ||
687 | return -ENOMEM; | ||
688 | } | ||
689 | } | ||
690 | xdr_encode_pages(buf, args->pages, 0, len); | ||
691 | |||
692 | err = nfsacl_encode(buf, base, args->inode, | ||
693 | (args->mask & NFS_ACL) ? | ||
694 | args->acl_access : NULL, 1, 0); | ||
695 | if (err > 0) | ||
696 | err = nfsacl_encode(buf, base + err, args->inode, | ||
697 | (args->mask & NFS_DFACL) ? | ||
698 | args->acl_default : NULL, 1, | ||
699 | NFS_ACL_DEFAULT); | ||
700 | return (err > 0) ? 0 : err; | ||
701 | } | ||
702 | #endif /* CONFIG_NFS_V3_ACL */ | ||
703 | |||
630 | /* | 704 | /* |
631 | * NFS XDR decode functions | 705 | * NFS XDR decode functions |
632 | */ | 706 | */ |
@@ -978,6 +1052,54 @@ nfs3_xdr_commitres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res) | |||
978 | return 0; | 1052 | return 0; |
979 | } | 1053 | } |
980 | 1054 | ||
1055 | #ifdef CONFIG_NFS_V3_ACL | ||
1056 | /* | ||
1057 | * Decode GETACL reply | ||
1058 | */ | ||
1059 | static int | ||
1060 | nfs3_xdr_getaclres(struct rpc_rqst *req, u32 *p, | ||
1061 | struct nfs3_getaclres *res) | ||
1062 | { | ||
1063 | struct xdr_buf *buf = &req->rq_rcv_buf; | ||
1064 | int status = ntohl(*p++); | ||
1065 | struct posix_acl **acl; | ||
1066 | unsigned int *aclcnt; | ||
1067 | int err, base; | ||
1068 | |||
1069 | if (status != 0) | ||
1070 | return -nfs_stat_to_errno(status); | ||
1071 | p = xdr_decode_post_op_attr(p, res->fattr); | ||
1072 | res->mask = ntohl(*p++); | ||
1073 | if (res->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) | ||
1074 | return -EINVAL; | ||
1075 | base = (char *)p - (char *)req->rq_rcv_buf.head->iov_base; | ||
1076 | |||
1077 | acl = (res->mask & NFS_ACL) ? &res->acl_access : NULL; | ||
1078 | aclcnt = (res->mask & NFS_ACLCNT) ? &res->acl_access_count : NULL; | ||
1079 | err = nfsacl_decode(buf, base, aclcnt, acl); | ||
1080 | |||
1081 | acl = (res->mask & NFS_DFACL) ? &res->acl_default : NULL; | ||
1082 | aclcnt = (res->mask & NFS_DFACLCNT) ? &res->acl_default_count : NULL; | ||
1083 | if (err > 0) | ||
1084 | err = nfsacl_decode(buf, base + err, aclcnt, acl); | ||
1085 | return (err > 0) ? 0 : err; | ||
1086 | } | ||
1087 | |||
1088 | /* | ||
1089 | * Decode setacl reply. | ||
1090 | */ | ||
1091 | static int | ||
1092 | nfs3_xdr_setaclres(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr) | ||
1093 | { | ||
1094 | int status = ntohl(*p++); | ||
1095 | |||
1096 | if (status) | ||
1097 | return -nfs_stat_to_errno(status); | ||
1098 | xdr_decode_post_op_attr(p, fattr); | ||
1099 | return 0; | ||
1100 | } | ||
1101 | #endif /* CONFIG_NFS_V3_ACL */ | ||
1102 | |||
981 | #ifndef MAX | 1103 | #ifndef MAX |
982 | # define MAX(a, b) (((a) > (b))? (a) : (b)) | 1104 | # define MAX(a, b) (((a) > (b))? (a) : (b)) |
983 | #endif | 1105 | #endif |
@@ -1021,3 +1143,28 @@ struct rpc_version nfs_version3 = { | |||
1021 | .procs = nfs3_procedures | 1143 | .procs = nfs3_procedures |
1022 | }; | 1144 | }; |
1023 | 1145 | ||
1146 | #ifdef CONFIG_NFS_V3_ACL | ||
1147 | static struct rpc_procinfo nfs3_acl_procedures[] = { | ||
1148 | [ACLPROC3_GETACL] = { | ||
1149 | .p_proc = ACLPROC3_GETACL, | ||
1150 | .p_encode = (kxdrproc_t) nfs3_xdr_getaclargs, | ||
1151 | .p_decode = (kxdrproc_t) nfs3_xdr_getaclres, | ||
1152 | .p_bufsiz = MAX(ACL3_getaclargs_sz, ACL3_getaclres_sz) << 2, | ||
1153 | .p_timer = 1, | ||
1154 | }, | ||
1155 | [ACLPROC3_SETACL] = { | ||
1156 | .p_proc = ACLPROC3_SETACL, | ||
1157 | .p_encode = (kxdrproc_t) nfs3_xdr_setaclargs, | ||
1158 | .p_decode = (kxdrproc_t) nfs3_xdr_setaclres, | ||
1159 | .p_bufsiz = MAX(ACL3_setaclargs_sz, ACL3_setaclres_sz) << 2, | ||
1160 | .p_timer = 0, | ||
1161 | }, | ||
1162 | }; | ||
1163 | |||
1164 | struct rpc_version nfsacl_version3 = { | ||
1165 | .number = 3, | ||
1166 | .nrprocs = sizeof(nfs3_acl_procedures)/ | ||
1167 | sizeof(nfs3_acl_procedures[0]), | ||
1168 | .procs = nfs3_acl_procedures, | ||
1169 | }; | ||
1170 | #endif /* CONFIG_NFS_V3_ACL */ | ||
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h new file mode 100644 index 000000000000..ec1a22d7b876 --- /dev/null +++ b/fs/nfs/nfs4_fs.h | |||
@@ -0,0 +1,253 @@ | |||
1 | /* | ||
2 | * linux/fs/nfs/nfs4_fs.h | ||
3 | * | ||
4 | * Copyright (C) 2005 Trond Myklebust | ||
5 | * | ||
6 | * NFSv4-specific filesystem definitions and declarations | ||
7 | */ | ||
8 | |||
9 | #ifndef __LINUX_FS_NFS_NFS4_FS_H | ||
10 | #define __LINUX_FS_NFS_NFS4_FS_H | ||
11 | |||
12 | #ifdef CONFIG_NFS_V4 | ||
13 | |||
14 | struct idmap; | ||
15 | |||
16 | /* | ||
17 | * In a seqid-mutating op, this macro controls which error return | ||
18 | * values trigger incrementation of the seqid. | ||
19 | * | ||
20 | * from rfc 3010: | ||
21 | * The client MUST monotonically increment the sequence number for the | ||
22 | * CLOSE, LOCK, LOCKU, OPEN, OPEN_CONFIRM, and OPEN_DOWNGRADE | ||
23 | * operations. This is true even in the event that the previous | ||
24 | * operation that used the sequence number received an error. The only | ||
25 | * exception to this rule is if the previous operation received one of | ||
26 | * the following errors: NFSERR_STALE_CLIENTID, NFSERR_STALE_STATEID, | ||
27 | * NFSERR_BAD_STATEID, NFSERR_BAD_SEQID, NFSERR_BADXDR, | ||
28 | * NFSERR_RESOURCE, NFSERR_NOFILEHANDLE. | ||
29 | * | ||
30 | */ | ||
31 | #define seqid_mutating_err(err) \ | ||
32 | (((err) != NFSERR_STALE_CLIENTID) && \ | ||
33 | ((err) != NFSERR_STALE_STATEID) && \ | ||
34 | ((err) != NFSERR_BAD_STATEID) && \ | ||
35 | ((err) != NFSERR_BAD_SEQID) && \ | ||
36 | ((err) != NFSERR_BAD_XDR) && \ | ||
37 | ((err) != NFSERR_RESOURCE) && \ | ||
38 | ((err) != NFSERR_NOFILEHANDLE)) | ||
39 | |||
40 | enum nfs4_client_state { | ||
41 | NFS4CLNT_OK = 0, | ||
42 | }; | ||
43 | |||
44 | /* | ||
45 | * The nfs4_client identifies our client state to the server. | ||
46 | */ | ||
47 | struct nfs4_client { | ||
48 | struct list_head cl_servers; /* Global list of servers */ | ||
49 | struct in_addr cl_addr; /* Server identifier */ | ||
50 | u64 cl_clientid; /* constant */ | ||
51 | nfs4_verifier cl_confirm; | ||
52 | unsigned long cl_state; | ||
53 | |||
54 | u32 cl_lockowner_id; | ||
55 | |||
56 | /* | ||
57 | * The following rwsem ensures exclusive access to the server | ||
58 | * while we recover the state following a lease expiration. | ||
59 | */ | ||
60 | struct rw_semaphore cl_sem; | ||
61 | |||
62 | struct list_head cl_delegations; | ||
63 | struct list_head cl_state_owners; | ||
64 | struct list_head cl_unused; | ||
65 | int cl_nunused; | ||
66 | spinlock_t cl_lock; | ||
67 | atomic_t cl_count; | ||
68 | |||
69 | struct rpc_clnt * cl_rpcclient; | ||
70 | struct rpc_cred * cl_cred; | ||
71 | |||
72 | struct list_head cl_superblocks; /* List of nfs_server structs */ | ||
73 | |||
74 | unsigned long cl_lease_time; | ||
75 | unsigned long cl_last_renewal; | ||
76 | struct work_struct cl_renewd; | ||
77 | struct work_struct cl_recoverd; | ||
78 | |||
79 | wait_queue_head_t cl_waitq; | ||
80 | struct rpc_wait_queue cl_rpcwaitq; | ||
81 | |||
82 | /* used for the setclientid verifier */ | ||
83 | struct timespec cl_boot_time; | ||
84 | |||
85 | /* idmapper */ | ||
86 | struct idmap * cl_idmap; | ||
87 | |||
88 | /* Our own IP address, as a null-terminated string. | ||
89 | * This is used to generate the clientid, and the callback address. | ||
90 | */ | ||
91 | char cl_ipaddr[16]; | ||
92 | unsigned char cl_id_uniquifier; | ||
93 | }; | ||
94 | |||
95 | /* | ||
96 | * NFS4 state_owners and lock_owners are simply labels for ordered | ||
97 | * sequences of RPC calls. Their sole purpose is to provide once-only | ||
98 | * semantics by allowing the server to identify replayed requests. | ||
99 | * | ||
100 | * The ->so_sema is held during all state_owner seqid-mutating operations: | ||
101 | * OPEN, OPEN_DOWNGRADE, and CLOSE. Its purpose is to properly serialize | ||
102 | * so_seqid. | ||
103 | */ | ||
104 | struct nfs4_state_owner { | ||
105 | struct list_head so_list; /* per-clientid list of state_owners */ | ||
106 | struct nfs4_client *so_client; | ||
107 | u32 so_id; /* 32-bit identifier, unique */ | ||
108 | struct semaphore so_sema; | ||
109 | u32 so_seqid; /* protected by so_sema */ | ||
110 | atomic_t so_count; | ||
111 | |||
112 | struct rpc_cred *so_cred; /* Associated cred */ | ||
113 | struct list_head so_states; | ||
114 | struct list_head so_delegations; | ||
115 | }; | ||
116 | |||
117 | /* | ||
118 | * struct nfs4_state maintains the client-side state for a given | ||
119 | * (state_owner,inode) tuple (OPEN) or state_owner (LOCK). | ||
120 | * | ||
121 | * OPEN: | ||
122 | * In order to know when to OPEN_DOWNGRADE or CLOSE the state on the server, | ||
123 | * we need to know how many files are open for reading or writing on a | ||
124 | * given inode. This information too is stored here. | ||
125 | * | ||
126 | * LOCK: one nfs4_state (LOCK) to hold the lock stateid nfs4_state(OPEN) | ||
127 | */ | ||
128 | |||
129 | struct nfs4_lock_state { | ||
130 | struct list_head ls_locks; /* Other lock stateids */ | ||
131 | struct nfs4_state * ls_state; /* Pointer to open state */ | ||
132 | fl_owner_t ls_owner; /* POSIX lock owner */ | ||
133 | #define NFS_LOCK_INITIALIZED 1 | ||
134 | int ls_flags; | ||
135 | u32 ls_seqid; | ||
136 | u32 ls_id; | ||
137 | nfs4_stateid ls_stateid; | ||
138 | atomic_t ls_count; | ||
139 | }; | ||
140 | |||
141 | /* bits for nfs4_state->flags */ | ||
142 | enum { | ||
143 | LK_STATE_IN_USE, | ||
144 | NFS_DELEGATED_STATE, | ||
145 | }; | ||
146 | |||
147 | struct nfs4_state { | ||
148 | struct list_head open_states; /* List of states for the same state_owner */ | ||
149 | struct list_head inode_states; /* List of states for the same inode */ | ||
150 | struct list_head lock_states; /* List of subservient lock stateids */ | ||
151 | |||
152 | struct nfs4_state_owner *owner; /* Pointer to the open owner */ | ||
153 | struct inode *inode; /* Pointer to the inode */ | ||
154 | |||
155 | unsigned long flags; /* Do we hold any locks? */ | ||
156 | struct semaphore lock_sema; /* Serializes file locking operations */ | ||
157 | spinlock_t state_lock; /* Protects the lock_states list */ | ||
158 | |||
159 | nfs4_stateid stateid; | ||
160 | |||
161 | unsigned int nreaders; | ||
162 | unsigned int nwriters; | ||
163 | int state; /* State on the server (R,W, or RW) */ | ||
164 | atomic_t count; | ||
165 | }; | ||
166 | |||
167 | |||
168 | struct nfs4_exception { | ||
169 | long timeout; | ||
170 | int retry; | ||
171 | }; | ||
172 | |||
173 | struct nfs4_state_recovery_ops { | ||
174 | int (*recover_open)(struct nfs4_state_owner *, struct nfs4_state *); | ||
175 | int (*recover_lock)(struct nfs4_state *, struct file_lock *); | ||
176 | }; | ||
177 | |||
178 | extern struct dentry_operations nfs4_dentry_operations; | ||
179 | extern struct inode_operations nfs4_dir_inode_operations; | ||
180 | |||
181 | /* inode.c */ | ||
182 | extern ssize_t nfs4_getxattr(struct dentry *, const char *, void *, size_t); | ||
183 | extern int nfs4_setxattr(struct dentry *, const char *, const void *, size_t, int); | ||
184 | extern ssize_t nfs4_listxattr(struct dentry *, char *, size_t); | ||
185 | |||
186 | |||
187 | /* nfs4proc.c */ | ||
188 | extern int nfs4_map_errors(int err); | ||
189 | extern int nfs4_proc_setclientid(struct nfs4_client *, u32, unsigned short); | ||
190 | extern int nfs4_proc_setclientid_confirm(struct nfs4_client *); | ||
191 | extern int nfs4_proc_async_renew(struct nfs4_client *); | ||
192 | extern int nfs4_proc_renew(struct nfs4_client *); | ||
193 | extern int nfs4_do_close(struct inode *inode, struct nfs4_state *state, mode_t mode); | ||
194 | extern struct inode *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); | ||
195 | extern int nfs4_open_revalidate(struct inode *, struct dentry *, int); | ||
196 | |||
197 | extern struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops; | ||
198 | extern struct nfs4_state_recovery_ops nfs4_network_partition_recovery_ops; | ||
199 | |||
200 | extern const u32 nfs4_fattr_bitmap[2]; | ||
201 | extern const u32 nfs4_statfs_bitmap[2]; | ||
202 | extern const u32 nfs4_pathconf_bitmap[2]; | ||
203 | extern const u32 nfs4_fsinfo_bitmap[2]; | ||
204 | |||
205 | /* nfs4renewd.c */ | ||
206 | extern void nfs4_schedule_state_renewal(struct nfs4_client *); | ||
207 | extern void nfs4_renewd_prepare_shutdown(struct nfs_server *); | ||
208 | extern void nfs4_kill_renewd(struct nfs4_client *); | ||
209 | extern void nfs4_renew_state(void *); | ||
210 | |||
211 | /* nfs4state.c */ | ||
212 | extern void init_nfsv4_state(struct nfs_server *); | ||
213 | extern void destroy_nfsv4_state(struct nfs_server *); | ||
214 | extern struct nfs4_client *nfs4_get_client(struct in_addr *); | ||
215 | extern void nfs4_put_client(struct nfs4_client *clp); | ||
216 | extern int nfs4_init_client(struct nfs4_client *clp); | ||
217 | extern struct nfs4_client *nfs4_find_client(struct in_addr *); | ||
218 | extern u32 nfs4_alloc_lockowner_id(struct nfs4_client *); | ||
219 | |||
220 | extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *); | ||
221 | extern void nfs4_put_state_owner(struct nfs4_state_owner *); | ||
222 | extern void nfs4_drop_state_owner(struct nfs4_state_owner *); | ||
223 | extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state_owner *); | ||
224 | extern void nfs4_put_open_state(struct nfs4_state *); | ||
225 | extern void nfs4_close_state(struct nfs4_state *, mode_t); | ||
226 | extern struct nfs4_state *nfs4_find_state(struct inode *, struct rpc_cred *, mode_t mode); | ||
227 | extern void nfs4_increment_seqid(int status, struct nfs4_state_owner *sp); | ||
228 | extern void nfs4_schedule_state_recovery(struct nfs4_client *); | ||
229 | extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl); | ||
230 | extern void nfs4_increment_lock_seqid(int status, struct nfs4_lock_state *ls); | ||
231 | extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t); | ||
232 | |||
233 | extern const nfs4_stateid zero_stateid; | ||
234 | |||
235 | /* nfs4xdr.c */ | ||
236 | extern uint32_t *nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus); | ||
237 | extern struct rpc_procinfo nfs4_procedures[]; | ||
238 | |||
239 | struct nfs4_mount_data; | ||
240 | |||
241 | /* callback_xdr.c */ | ||
242 | extern struct svc_version nfs4_callback_version1; | ||
243 | |||
244 | #else | ||
245 | |||
246 | #define init_nfsv4_state(server) do { } while (0) | ||
247 | #define destroy_nfsv4_state(server) do { } while (0) | ||
248 | #define nfs4_put_state_owner(inode, owner) do { } while (0) | ||
249 | #define nfs4_put_open_state(state) do { } while (0) | ||
250 | #define nfs4_close_state(a, b) do { } while (0) | ||
251 | |||
252 | #endif /* CONFIG_NFS_V4 */ | ||
253 | #endif /* __LINUX_FS_NFS_NFS4_FS.H */ | ||
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 1d5cb3e80c3e..1b76f80aedb9 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -48,6 +48,7 @@ | |||
48 | #include <linux/smp_lock.h> | 48 | #include <linux/smp_lock.h> |
49 | #include <linux/namei.h> | 49 | #include <linux/namei.h> |
50 | 50 | ||
51 | #include "nfs4_fs.h" | ||
51 | #include "delegation.h" | 52 | #include "delegation.h" |
52 | 53 | ||
53 | #define NFSDBG_FACILITY NFSDBG_PROC | 54 | #define NFSDBG_FACILITY NFSDBG_PROC |
@@ -62,8 +63,6 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc | |||
62 | extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus); | 63 | extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus); |
63 | extern struct rpc_procinfo nfs4_procedures[]; | 64 | extern struct rpc_procinfo nfs4_procedures[]; |
64 | 65 | ||
65 | extern nfs4_stateid zero_stateid; | ||
66 | |||
67 | /* Prevent leaks of NFSv4 errors into userland */ | 66 | /* Prevent leaks of NFSv4 errors into userland */ |
68 | int nfs4_map_errors(int err) | 67 | int nfs4_map_errors(int err) |
69 | { | 68 | { |
@@ -104,7 +103,7 @@ const u32 nfs4_statfs_bitmap[2] = { | |||
104 | | FATTR4_WORD1_SPACE_TOTAL | 103 | | FATTR4_WORD1_SPACE_TOTAL |
105 | }; | 104 | }; |
106 | 105 | ||
107 | u32 nfs4_pathconf_bitmap[2] = { | 106 | const u32 nfs4_pathconf_bitmap[2] = { |
108 | FATTR4_WORD0_MAXLINK | 107 | FATTR4_WORD0_MAXLINK |
109 | | FATTR4_WORD0_MAXNAME, | 108 | | FATTR4_WORD0_MAXNAME, |
110 | 0 | 109 | 0 |
@@ -124,7 +123,7 @@ static void nfs4_setup_readdir(u64 cookie, u32 *verifier, struct dentry *dentry, | |||
124 | 123 | ||
125 | BUG_ON(readdir->count < 80); | 124 | BUG_ON(readdir->count < 80); |
126 | if (cookie > 2) { | 125 | if (cookie > 2) { |
127 | readdir->cookie = (cookie > 2) ? cookie : 0; | 126 | readdir->cookie = cookie; |
128 | memcpy(&readdir->verifier, verifier, sizeof(readdir->verifier)); | 127 | memcpy(&readdir->verifier, verifier, sizeof(readdir->verifier)); |
129 | return; | 128 | return; |
130 | } | 129 | } |
@@ -270,14 +269,9 @@ static int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *sta | |||
270 | int err; | 269 | int err; |
271 | do { | 270 | do { |
272 | err = _nfs4_open_reclaim(sp, state); | 271 | err = _nfs4_open_reclaim(sp, state); |
273 | switch (err) { | 272 | if (err != -NFS4ERR_DELAY) |
274 | case 0: | 273 | break; |
275 | case -NFS4ERR_STALE_CLIENTID: | 274 | nfs4_handle_exception(server, err, &exception); |
276 | case -NFS4ERR_STALE_STATEID: | ||
277 | case -NFS4ERR_EXPIRED: | ||
278 | return err; | ||
279 | } | ||
280 | err = nfs4_handle_exception(server, err, &exception); | ||
281 | } while (exception.retry); | 275 | } while (exception.retry); |
282 | return err; | 276 | return err; |
283 | } | 277 | } |
@@ -509,6 +503,20 @@ out_stale: | |||
509 | goto out_nodeleg; | 503 | goto out_nodeleg; |
510 | } | 504 | } |
511 | 505 | ||
506 | static inline int nfs4_do_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry) | ||
507 | { | ||
508 | struct nfs_server *server = NFS_SERVER(dentry->d_inode); | ||
509 | struct nfs4_exception exception = { }; | ||
510 | int err; | ||
511 | |||
512 | do { | ||
513 | err = _nfs4_open_expired(sp, state, dentry); | ||
514 | if (err == -NFS4ERR_DELAY) | ||
515 | nfs4_handle_exception(server, err, &exception); | ||
516 | } while (exception.retry); | ||
517 | return err; | ||
518 | } | ||
519 | |||
512 | static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state) | 520 | static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state) |
513 | { | 521 | { |
514 | struct nfs_inode *nfsi = NFS_I(state->inode); | 522 | struct nfs_inode *nfsi = NFS_I(state->inode); |
@@ -521,7 +529,7 @@ static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *sta | |||
521 | continue; | 529 | continue; |
522 | get_nfs_open_context(ctx); | 530 | get_nfs_open_context(ctx); |
523 | spin_unlock(&state->inode->i_lock); | 531 | spin_unlock(&state->inode->i_lock); |
524 | status = _nfs4_open_expired(sp, state, ctx->dentry); | 532 | status = nfs4_do_open_expired(sp, state, ctx->dentry); |
525 | put_nfs_open_context(ctx); | 533 | put_nfs_open_context(ctx); |
526 | return status; | 534 | return status; |
527 | } | 535 | } |
@@ -748,11 +756,10 @@ static int _nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr, | |||
748 | 756 | ||
749 | fattr->valid = 0; | 757 | fattr->valid = 0; |
750 | 758 | ||
751 | if (state != NULL) | 759 | if (state != NULL) { |
752 | msg.rpc_cred = state->owner->so_cred; | 760 | msg.rpc_cred = state->owner->so_cred; |
753 | if (sattr->ia_valid & ATTR_SIZE) | 761 | nfs4_copy_stateid(&arg.stateid, state, current->files); |
754 | nfs4_copy_stateid(&arg.stateid, state, NULL); | 762 | } else |
755 | else | ||
756 | memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); | 763 | memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); |
757 | 764 | ||
758 | return rpc_call_sync(server->client, &msg, 0); | 765 | return rpc_call_sync(server->client, &msg, 0); |
@@ -1116,47 +1123,31 @@ static int | |||
1116 | nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, | 1123 | nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, |
1117 | struct iattr *sattr) | 1124 | struct iattr *sattr) |
1118 | { | 1125 | { |
1119 | struct inode * inode = dentry->d_inode; | 1126 | struct rpc_cred *cred; |
1120 | int size_change = sattr->ia_valid & ATTR_SIZE; | 1127 | struct inode *inode = dentry->d_inode; |
1121 | struct nfs4_state *state = NULL; | 1128 | struct nfs4_state *state; |
1122 | int need_iput = 0; | ||
1123 | int status; | 1129 | int status; |
1124 | 1130 | ||
1125 | fattr->valid = 0; | 1131 | fattr->valid = 0; |
1126 | 1132 | ||
1127 | if (size_change) { | 1133 | cred = rpcauth_lookupcred(NFS_SERVER(inode)->client->cl_auth, 0); |
1128 | struct rpc_cred *cred = rpcauth_lookupcred(NFS_SERVER(inode)->client->cl_auth, 0); | 1134 | if (IS_ERR(cred)) |
1129 | if (IS_ERR(cred)) | 1135 | return PTR_ERR(cred); |
1130 | return PTR_ERR(cred); | 1136 | /* Search for an existing WRITE delegation first */ |
1137 | state = nfs4_open_delegated(inode, FMODE_WRITE, cred); | ||
1138 | if (!IS_ERR(state)) { | ||
1139 | /* NB: nfs4_open_delegated() bumps the inode->i_count */ | ||
1140 | iput(inode); | ||
1141 | } else { | ||
1142 | /* Search for an existing open(O_WRITE) stateid */ | ||
1131 | state = nfs4_find_state(inode, cred, FMODE_WRITE); | 1143 | state = nfs4_find_state(inode, cred, FMODE_WRITE); |
1132 | if (state == NULL) { | ||
1133 | state = nfs4_open_delegated(dentry->d_inode, | ||
1134 | FMODE_WRITE, cred); | ||
1135 | if (IS_ERR(state)) | ||
1136 | state = nfs4_do_open(dentry->d_parent->d_inode, | ||
1137 | dentry, FMODE_WRITE, | ||
1138 | NULL, cred); | ||
1139 | need_iput = 1; | ||
1140 | } | ||
1141 | put_rpccred(cred); | ||
1142 | if (IS_ERR(state)) | ||
1143 | return PTR_ERR(state); | ||
1144 | |||
1145 | if (state->inode != inode) { | ||
1146 | printk(KERN_WARNING "nfs: raced in setattr (%p != %p), returning -EIO\n", inode, state->inode); | ||
1147 | status = -EIO; | ||
1148 | goto out; | ||
1149 | } | ||
1150 | } | 1144 | } |
1145 | |||
1151 | status = nfs4_do_setattr(NFS_SERVER(inode), fattr, | 1146 | status = nfs4_do_setattr(NFS_SERVER(inode), fattr, |
1152 | NFS_FH(inode), sattr, state); | 1147 | NFS_FH(inode), sattr, state); |
1153 | out: | 1148 | if (state != NULL) |
1154 | if (state) { | ||
1155 | inode = state->inode; | ||
1156 | nfs4_close_state(state, FMODE_WRITE); | 1149 | nfs4_close_state(state, FMODE_WRITE); |
1157 | if (need_iput) | 1150 | put_rpccred(cred); |
1158 | iput(inode); | ||
1159 | } | ||
1160 | return status; | 1151 | return status; |
1161 | } | 1152 | } |
1162 | 1153 | ||
@@ -1731,6 +1722,10 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, | |||
1731 | }; | 1722 | }; |
1732 | int status; | 1723 | int status; |
1733 | 1724 | ||
1725 | dprintk("%s: dentry = %s/%s, cookie = %Lu\n", __FUNCTION__, | ||
1726 | dentry->d_parent->d_name.name, | ||
1727 | dentry->d_name.name, | ||
1728 | (unsigned long long)cookie); | ||
1734 | lock_kernel(); | 1729 | lock_kernel(); |
1735 | nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args); | 1730 | nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args); |
1736 | res.pgbase = args.pgbase; | 1731 | res.pgbase = args.pgbase; |
@@ -1738,6 +1733,7 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, | |||
1738 | if (status == 0) | 1733 | if (status == 0) |
1739 | memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE); | 1734 | memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE); |
1740 | unlock_kernel(); | 1735 | unlock_kernel(); |
1736 | dprintk("%s: returns %d\n", __FUNCTION__, status); | ||
1741 | return status; | 1737 | return status; |
1742 | } | 1738 | } |
1743 | 1739 | ||
@@ -2163,6 +2159,193 @@ nfs4_proc_file_release(struct inode *inode, struct file *filp) | |||
2163 | return 0; | 2159 | return 0; |
2164 | } | 2160 | } |
2165 | 2161 | ||
2162 | static inline int nfs4_server_supports_acls(struct nfs_server *server) | ||
2163 | { | ||
2164 | return (server->caps & NFS_CAP_ACLS) | ||
2165 | && (server->acl_bitmask & ACL4_SUPPORT_ALLOW_ACL) | ||
2166 | && (server->acl_bitmask & ACL4_SUPPORT_DENY_ACL); | ||
2167 | } | ||
2168 | |||
2169 | /* Assuming that XATTR_SIZE_MAX is a multiple of PAGE_CACHE_SIZE, and that | ||
2170 | * it's OK to put sizeof(void) * (XATTR_SIZE_MAX/PAGE_CACHE_SIZE) bytes on | ||
2171 | * the stack. | ||
2172 | */ | ||
2173 | #define NFS4ACL_MAXPAGES (XATTR_SIZE_MAX >> PAGE_CACHE_SHIFT) | ||
2174 | |||
2175 | static void buf_to_pages(const void *buf, size_t buflen, | ||
2176 | struct page **pages, unsigned int *pgbase) | ||
2177 | { | ||
2178 | const void *p = buf; | ||
2179 | |||
2180 | *pgbase = offset_in_page(buf); | ||
2181 | p -= *pgbase; | ||
2182 | while (p < buf + buflen) { | ||
2183 | *(pages++) = virt_to_page(p); | ||
2184 | p += PAGE_CACHE_SIZE; | ||
2185 | } | ||
2186 | } | ||
2187 | |||
2188 | struct nfs4_cached_acl { | ||
2189 | int cached; | ||
2190 | size_t len; | ||
2191 | char data[0]; | ||
2192 | }; | ||
2193 | |||
2194 | static void nfs4_set_cached_acl(struct inode *inode, struct nfs4_cached_acl *acl) | ||
2195 | { | ||
2196 | struct nfs_inode *nfsi = NFS_I(inode); | ||
2197 | |||
2198 | spin_lock(&inode->i_lock); | ||
2199 | kfree(nfsi->nfs4_acl); | ||
2200 | nfsi->nfs4_acl = acl; | ||
2201 | spin_unlock(&inode->i_lock); | ||
2202 | } | ||
2203 | |||
2204 | static void nfs4_zap_acl_attr(struct inode *inode) | ||
2205 | { | ||
2206 | nfs4_set_cached_acl(inode, NULL); | ||
2207 | } | ||
2208 | |||
2209 | static inline ssize_t nfs4_read_cached_acl(struct inode *inode, char *buf, size_t buflen) | ||
2210 | { | ||
2211 | struct nfs_inode *nfsi = NFS_I(inode); | ||
2212 | struct nfs4_cached_acl *acl; | ||
2213 | int ret = -ENOENT; | ||
2214 | |||
2215 | spin_lock(&inode->i_lock); | ||
2216 | acl = nfsi->nfs4_acl; | ||
2217 | if (acl == NULL) | ||
2218 | goto out; | ||
2219 | if (buf == NULL) /* user is just asking for length */ | ||
2220 | goto out_len; | ||
2221 | if (acl->cached == 0) | ||
2222 | goto out; | ||
2223 | ret = -ERANGE; /* see getxattr(2) man page */ | ||
2224 | if (acl->len > buflen) | ||
2225 | goto out; | ||
2226 | memcpy(buf, acl->data, acl->len); | ||
2227 | out_len: | ||
2228 | ret = acl->len; | ||
2229 | out: | ||
2230 | spin_unlock(&inode->i_lock); | ||
2231 | return ret; | ||
2232 | } | ||
2233 | |||
2234 | static void nfs4_write_cached_acl(struct inode *inode, const char *buf, size_t acl_len) | ||
2235 | { | ||
2236 | struct nfs4_cached_acl *acl; | ||
2237 | |||
2238 | if (buf && acl_len <= PAGE_SIZE) { | ||
2239 | acl = kmalloc(sizeof(*acl) + acl_len, GFP_KERNEL); | ||
2240 | if (acl == NULL) | ||
2241 | goto out; | ||
2242 | acl->cached = 1; | ||
2243 | memcpy(acl->data, buf, acl_len); | ||
2244 | } else { | ||
2245 | acl = kmalloc(sizeof(*acl), GFP_KERNEL); | ||
2246 | if (acl == NULL) | ||
2247 | goto out; | ||
2248 | acl->cached = 0; | ||
2249 | } | ||
2250 | acl->len = acl_len; | ||
2251 | out: | ||
2252 | nfs4_set_cached_acl(inode, acl); | ||
2253 | } | ||
2254 | |||
2255 | static inline ssize_t nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen) | ||
2256 | { | ||
2257 | struct page *pages[NFS4ACL_MAXPAGES]; | ||
2258 | struct nfs_getaclargs args = { | ||
2259 | .fh = NFS_FH(inode), | ||
2260 | .acl_pages = pages, | ||
2261 | .acl_len = buflen, | ||
2262 | }; | ||
2263 | size_t resp_len = buflen; | ||
2264 | void *resp_buf; | ||
2265 | struct rpc_message msg = { | ||
2266 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETACL], | ||
2267 | .rpc_argp = &args, | ||
2268 | .rpc_resp = &resp_len, | ||
2269 | }; | ||
2270 | struct page *localpage = NULL; | ||
2271 | int ret; | ||
2272 | |||
2273 | if (buflen < PAGE_SIZE) { | ||
2274 | /* As long as we're doing a round trip to the server anyway, | ||
2275 | * let's be prepared for a page of acl data. */ | ||
2276 | localpage = alloc_page(GFP_KERNEL); | ||
2277 | resp_buf = page_address(localpage); | ||
2278 | if (localpage == NULL) | ||
2279 | return -ENOMEM; | ||
2280 | args.acl_pages[0] = localpage; | ||
2281 | args.acl_pgbase = 0; | ||
2282 | args.acl_len = PAGE_SIZE; | ||
2283 | } else { | ||
2284 | resp_buf = buf; | ||
2285 | buf_to_pages(buf, buflen, args.acl_pages, &args.acl_pgbase); | ||
2286 | } | ||
2287 | ret = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); | ||
2288 | if (ret) | ||
2289 | goto out_free; | ||
2290 | if (resp_len > args.acl_len) | ||
2291 | nfs4_write_cached_acl(inode, NULL, resp_len); | ||
2292 | else | ||
2293 | nfs4_write_cached_acl(inode, resp_buf, resp_len); | ||
2294 | if (buf) { | ||
2295 | ret = -ERANGE; | ||
2296 | if (resp_len > buflen) | ||
2297 | goto out_free; | ||
2298 | if (localpage) | ||
2299 | memcpy(buf, resp_buf, resp_len); | ||
2300 | } | ||
2301 | ret = resp_len; | ||
2302 | out_free: | ||
2303 | if (localpage) | ||
2304 | __free_page(localpage); | ||
2305 | return ret; | ||
2306 | } | ||
2307 | |||
2308 | static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen) | ||
2309 | { | ||
2310 | struct nfs_server *server = NFS_SERVER(inode); | ||
2311 | int ret; | ||
2312 | |||
2313 | if (!nfs4_server_supports_acls(server)) | ||
2314 | return -EOPNOTSUPP; | ||
2315 | ret = nfs_revalidate_inode(server, inode); | ||
2316 | if (ret < 0) | ||
2317 | return ret; | ||
2318 | ret = nfs4_read_cached_acl(inode, buf, buflen); | ||
2319 | if (ret != -ENOENT) | ||
2320 | return ret; | ||
2321 | return nfs4_get_acl_uncached(inode, buf, buflen); | ||
2322 | } | ||
2323 | |||
2324 | static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen) | ||
2325 | { | ||
2326 | struct nfs_server *server = NFS_SERVER(inode); | ||
2327 | struct page *pages[NFS4ACL_MAXPAGES]; | ||
2328 | struct nfs_setaclargs arg = { | ||
2329 | .fh = NFS_FH(inode), | ||
2330 | .acl_pages = pages, | ||
2331 | .acl_len = buflen, | ||
2332 | }; | ||
2333 | struct rpc_message msg = { | ||
2334 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETACL], | ||
2335 | .rpc_argp = &arg, | ||
2336 | .rpc_resp = NULL, | ||
2337 | }; | ||
2338 | int ret; | ||
2339 | |||
2340 | if (!nfs4_server_supports_acls(server)) | ||
2341 | return -EOPNOTSUPP; | ||
2342 | buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase); | ||
2343 | ret = rpc_call_sync(NFS_SERVER(inode)->client, &msg, 0); | ||
2344 | if (ret == 0) | ||
2345 | nfs4_write_cached_acl(inode, buf, buflen); | ||
2346 | return ret; | ||
2347 | } | ||
2348 | |||
2166 | static int | 2349 | static int |
2167 | nfs4_async_handle_error(struct rpc_task *task, struct nfs_server *server) | 2350 | nfs4_async_handle_error(struct rpc_task *task, struct nfs_server *server) |
2168 | { | 2351 | { |
@@ -2448,14 +2631,11 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock | |||
2448 | down_read(&clp->cl_sem); | 2631 | down_read(&clp->cl_sem); |
2449 | nlo.clientid = clp->cl_clientid; | 2632 | nlo.clientid = clp->cl_clientid; |
2450 | down(&state->lock_sema); | 2633 | down(&state->lock_sema); |
2451 | lsp = nfs4_find_lock_state(state, request->fl_owner); | 2634 | status = nfs4_set_lock_state(state, request); |
2452 | if (lsp) | 2635 | if (status != 0) |
2453 | nlo.id = lsp->ls_id; | 2636 | goto out; |
2454 | else { | 2637 | lsp = request->fl_u.nfs4_fl.owner; |
2455 | spin_lock(&clp->cl_lock); | 2638 | nlo.id = lsp->ls_id; |
2456 | nlo.id = nfs4_alloc_lockowner_id(clp); | ||
2457 | spin_unlock(&clp->cl_lock); | ||
2458 | } | ||
2459 | arg.u.lockt = &nlo; | 2639 | arg.u.lockt = &nlo; |
2460 | status = rpc_call_sync(server->client, &msg, 0); | 2640 | status = rpc_call_sync(server->client, &msg, 0); |
2461 | if (!status) { | 2641 | if (!status) { |
@@ -2476,8 +2656,7 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock | |||
2476 | request->fl_pid = 0; | 2656 | request->fl_pid = 0; |
2477 | status = 0; | 2657 | status = 0; |
2478 | } | 2658 | } |
2479 | if (lsp) | 2659 | out: |
2480 | nfs4_put_lock_state(lsp); | ||
2481 | up(&state->lock_sema); | 2660 | up(&state->lock_sema); |
2482 | up_read(&clp->cl_sem); | 2661 | up_read(&clp->cl_sem); |
2483 | return status; | 2662 | return status; |
@@ -2537,28 +2716,26 @@ static int _nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock | |||
2537 | }; | 2716 | }; |
2538 | struct nfs4_lock_state *lsp; | 2717 | struct nfs4_lock_state *lsp; |
2539 | struct nfs_locku_opargs luargs; | 2718 | struct nfs_locku_opargs luargs; |
2540 | int status = 0; | 2719 | int status; |
2541 | 2720 | ||
2542 | down_read(&clp->cl_sem); | 2721 | down_read(&clp->cl_sem); |
2543 | down(&state->lock_sema); | 2722 | down(&state->lock_sema); |
2544 | lsp = nfs4_find_lock_state(state, request->fl_owner); | 2723 | status = nfs4_set_lock_state(state, request); |
2545 | if (!lsp) | 2724 | if (status != 0) |
2546 | goto out; | 2725 | goto out; |
2726 | lsp = request->fl_u.nfs4_fl.owner; | ||
2547 | /* We might have lost the locks! */ | 2727 | /* We might have lost the locks! */ |
2548 | if ((lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0) { | 2728 | if ((lsp->ls_flags & NFS_LOCK_INITIALIZED) == 0) |
2549 | luargs.seqid = lsp->ls_seqid; | 2729 | goto out; |
2550 | memcpy(&luargs.stateid, &lsp->ls_stateid, sizeof(luargs.stateid)); | 2730 | luargs.seqid = lsp->ls_seqid; |
2551 | arg.u.locku = &luargs; | 2731 | memcpy(&luargs.stateid, &lsp->ls_stateid, sizeof(luargs.stateid)); |
2552 | status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); | 2732 | arg.u.locku = &luargs; |
2553 | nfs4_increment_lock_seqid(status, lsp); | 2733 | status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); |
2554 | } | 2734 | nfs4_increment_lock_seqid(status, lsp); |
2555 | 2735 | ||
2556 | if (status == 0) { | 2736 | if (status == 0) |
2557 | memcpy(&lsp->ls_stateid, &res.u.stateid, | 2737 | memcpy(&lsp->ls_stateid, &res.u.stateid, |
2558 | sizeof(lsp->ls_stateid)); | 2738 | sizeof(lsp->ls_stateid)); |
2559 | nfs4_notify_unlck(state, request, lsp); | ||
2560 | } | ||
2561 | nfs4_put_lock_state(lsp); | ||
2562 | out: | 2739 | out: |
2563 | up(&state->lock_sema); | 2740 | up(&state->lock_sema); |
2564 | if (status == 0) | 2741 | if (status == 0) |
@@ -2584,7 +2761,7 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *r | |||
2584 | { | 2761 | { |
2585 | struct inode *inode = state->inode; | 2762 | struct inode *inode = state->inode; |
2586 | struct nfs_server *server = NFS_SERVER(inode); | 2763 | struct nfs_server *server = NFS_SERVER(inode); |
2587 | struct nfs4_lock_state *lsp; | 2764 | struct nfs4_lock_state *lsp = request->fl_u.nfs4_fl.owner; |
2588 | struct nfs_lockargs arg = { | 2765 | struct nfs_lockargs arg = { |
2589 | .fh = NFS_FH(inode), | 2766 | .fh = NFS_FH(inode), |
2590 | .type = nfs4_lck_type(cmd, request), | 2767 | .type = nfs4_lck_type(cmd, request), |
@@ -2606,9 +2783,6 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *r | |||
2606 | }; | 2783 | }; |
2607 | int status; | 2784 | int status; |
2608 | 2785 | ||
2609 | lsp = nfs4_get_lock_state(state, request->fl_owner); | ||
2610 | if (lsp == NULL) | ||
2611 | return -ENOMEM; | ||
2612 | if (!(lsp->ls_flags & NFS_LOCK_INITIALIZED)) { | 2786 | if (!(lsp->ls_flags & NFS_LOCK_INITIALIZED)) { |
2613 | struct nfs4_state_owner *owner = state->owner; | 2787 | struct nfs4_state_owner *owner = state->owner; |
2614 | struct nfs_open_to_lock otl = { | 2788 | struct nfs_open_to_lock otl = { |
@@ -2630,38 +2804,57 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *r | |||
2630 | * seqid mutating errors */ | 2804 | * seqid mutating errors */ |
2631 | nfs4_increment_seqid(status, owner); | 2805 | nfs4_increment_seqid(status, owner); |
2632 | up(&owner->so_sema); | 2806 | up(&owner->so_sema); |
2807 | if (status == 0) { | ||
2808 | lsp->ls_flags |= NFS_LOCK_INITIALIZED; | ||
2809 | lsp->ls_seqid++; | ||
2810 | } | ||
2633 | } else { | 2811 | } else { |
2634 | struct nfs_exist_lock el = { | 2812 | struct nfs_exist_lock el = { |
2635 | .seqid = lsp->ls_seqid, | 2813 | .seqid = lsp->ls_seqid, |
2636 | }; | 2814 | }; |
2637 | memcpy(&el.stateid, &lsp->ls_stateid, sizeof(el.stateid)); | 2815 | memcpy(&el.stateid, &lsp->ls_stateid, sizeof(el.stateid)); |
2638 | largs.u.exist_lock = ⪙ | 2816 | largs.u.exist_lock = ⪙ |
2639 | largs.new_lock_owner = 0; | ||
2640 | arg.u.lock = &largs; | 2817 | arg.u.lock = &largs; |
2641 | status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); | 2818 | status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); |
2819 | /* increment seqid on success, and * seqid mutating errors*/ | ||
2820 | nfs4_increment_lock_seqid(status, lsp); | ||
2642 | } | 2821 | } |
2643 | /* increment seqid on success, and * seqid mutating errors*/ | ||
2644 | nfs4_increment_lock_seqid(status, lsp); | ||
2645 | /* save the returned stateid. */ | 2822 | /* save the returned stateid. */ |
2646 | if (status == 0) { | 2823 | if (status == 0) |
2647 | memcpy(&lsp->ls_stateid, &res.u.stateid, sizeof(nfs4_stateid)); | 2824 | memcpy(&lsp->ls_stateid, &res.u.stateid, sizeof(nfs4_stateid)); |
2648 | lsp->ls_flags |= NFS_LOCK_INITIALIZED; | 2825 | else if (status == -NFS4ERR_DENIED) |
2649 | if (!reclaim) | ||
2650 | nfs4_notify_setlk(state, request, lsp); | ||
2651 | } else if (status == -NFS4ERR_DENIED) | ||
2652 | status = -EAGAIN; | 2826 | status = -EAGAIN; |
2653 | nfs4_put_lock_state(lsp); | ||
2654 | return status; | 2827 | return status; |
2655 | } | 2828 | } |
2656 | 2829 | ||
2657 | static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request) | 2830 | static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request) |
2658 | { | 2831 | { |
2659 | return _nfs4_do_setlk(state, F_SETLK, request, 1); | 2832 | struct nfs_server *server = NFS_SERVER(state->inode); |
2833 | struct nfs4_exception exception = { }; | ||
2834 | int err; | ||
2835 | |||
2836 | do { | ||
2837 | err = _nfs4_do_setlk(state, F_SETLK, request, 1); | ||
2838 | if (err != -NFS4ERR_DELAY) | ||
2839 | break; | ||
2840 | nfs4_handle_exception(server, err, &exception); | ||
2841 | } while (exception.retry); | ||
2842 | return err; | ||
2660 | } | 2843 | } |
2661 | 2844 | ||
2662 | static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request) | 2845 | static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request) |
2663 | { | 2846 | { |
2664 | return _nfs4_do_setlk(state, F_SETLK, request, 0); | 2847 | struct nfs_server *server = NFS_SERVER(state->inode); |
2848 | struct nfs4_exception exception = { }; | ||
2849 | int err; | ||
2850 | |||
2851 | do { | ||
2852 | err = _nfs4_do_setlk(state, F_SETLK, request, 0); | ||
2853 | if (err != -NFS4ERR_DELAY) | ||
2854 | break; | ||
2855 | nfs4_handle_exception(server, err, &exception); | ||
2856 | } while (exception.retry); | ||
2857 | return err; | ||
2665 | } | 2858 | } |
2666 | 2859 | ||
2667 | static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request) | 2860 | static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request) |
@@ -2671,7 +2864,9 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock | |||
2671 | 2864 | ||
2672 | down_read(&clp->cl_sem); | 2865 | down_read(&clp->cl_sem); |
2673 | down(&state->lock_sema); | 2866 | down(&state->lock_sema); |
2674 | status = _nfs4_do_setlk(state, cmd, request, 0); | 2867 | status = nfs4_set_lock_state(state, request); |
2868 | if (status == 0) | ||
2869 | status = _nfs4_do_setlk(state, cmd, request, 0); | ||
2675 | up(&state->lock_sema); | 2870 | up(&state->lock_sema); |
2676 | if (status == 0) { | 2871 | if (status == 0) { |
2677 | /* Note: we always want to sleep here! */ | 2872 | /* Note: we always want to sleep here! */ |
@@ -2729,10 +2924,53 @@ nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request) | |||
2729 | if (signalled()) | 2924 | if (signalled()) |
2730 | break; | 2925 | break; |
2731 | } while(status < 0); | 2926 | } while(status < 0); |
2732 | |||
2733 | return status; | 2927 | return status; |
2734 | } | 2928 | } |
2735 | 2929 | ||
2930 | |||
2931 | #define XATTR_NAME_NFSV4_ACL "system.nfs4_acl" | ||
2932 | |||
2933 | int nfs4_setxattr(struct dentry *dentry, const char *key, const void *buf, | ||
2934 | size_t buflen, int flags) | ||
2935 | { | ||
2936 | struct inode *inode = dentry->d_inode; | ||
2937 | |||
2938 | if (strcmp(key, XATTR_NAME_NFSV4_ACL) != 0) | ||
2939 | return -EOPNOTSUPP; | ||
2940 | |||
2941 | if (!S_ISREG(inode->i_mode) && | ||
2942 | (!S_ISDIR(inode->i_mode) || inode->i_mode & S_ISVTX)) | ||
2943 | return -EPERM; | ||
2944 | |||
2945 | return nfs4_proc_set_acl(inode, buf, buflen); | ||
2946 | } | ||
2947 | |||
2948 | /* The getxattr man page suggests returning -ENODATA for unknown attributes, | ||
2949 | * and that's what we'll do for e.g. user attributes that haven't been set. | ||
2950 | * But we'll follow ext2/ext3's lead by returning -EOPNOTSUPP for unsupported | ||
2951 | * attributes in kernel-managed attribute namespaces. */ | ||
2952 | ssize_t nfs4_getxattr(struct dentry *dentry, const char *key, void *buf, | ||
2953 | size_t buflen) | ||
2954 | { | ||
2955 | struct inode *inode = dentry->d_inode; | ||
2956 | |||
2957 | if (strcmp(key, XATTR_NAME_NFSV4_ACL) != 0) | ||
2958 | return -EOPNOTSUPP; | ||
2959 | |||
2960 | return nfs4_proc_get_acl(inode, buf, buflen); | ||
2961 | } | ||
2962 | |||
2963 | ssize_t nfs4_listxattr(struct dentry *dentry, char *buf, size_t buflen) | ||
2964 | { | ||
2965 | size_t len = strlen(XATTR_NAME_NFSV4_ACL) + 1; | ||
2966 | |||
2967 | if (buf && buflen < len) | ||
2968 | return -ERANGE; | ||
2969 | if (buf) | ||
2970 | memcpy(buf, XATTR_NAME_NFSV4_ACL, len); | ||
2971 | return len; | ||
2972 | } | ||
2973 | |||
2736 | struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = { | 2974 | struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = { |
2737 | .recover_open = nfs4_open_reclaim, | 2975 | .recover_open = nfs4_open_reclaim, |
2738 | .recover_lock = nfs4_lock_reclaim, | 2976 | .recover_lock = nfs4_lock_reclaim, |
@@ -2743,10 +2981,20 @@ struct nfs4_state_recovery_ops nfs4_network_partition_recovery_ops = { | |||
2743 | .recover_lock = nfs4_lock_expired, | 2981 | .recover_lock = nfs4_lock_expired, |
2744 | }; | 2982 | }; |
2745 | 2983 | ||
2984 | static struct inode_operations nfs4_file_inode_operations = { | ||
2985 | .permission = nfs_permission, | ||
2986 | .getattr = nfs_getattr, | ||
2987 | .setattr = nfs_setattr, | ||
2988 | .getxattr = nfs4_getxattr, | ||
2989 | .setxattr = nfs4_setxattr, | ||
2990 | .listxattr = nfs4_listxattr, | ||
2991 | }; | ||
2992 | |||
2746 | struct nfs_rpc_ops nfs_v4_clientops = { | 2993 | struct nfs_rpc_ops nfs_v4_clientops = { |
2747 | .version = 4, /* protocol version */ | 2994 | .version = 4, /* protocol version */ |
2748 | .dentry_ops = &nfs4_dentry_operations, | 2995 | .dentry_ops = &nfs4_dentry_operations, |
2749 | .dir_inode_ops = &nfs4_dir_inode_operations, | 2996 | .dir_inode_ops = &nfs4_dir_inode_operations, |
2997 | .file_inode_ops = &nfs4_file_inode_operations, | ||
2750 | .getroot = nfs4_proc_get_root, | 2998 | .getroot = nfs4_proc_get_root, |
2751 | .getattr = nfs4_proc_getattr, | 2999 | .getattr = nfs4_proc_getattr, |
2752 | .setattr = nfs4_proc_setattr, | 3000 | .setattr = nfs4_proc_setattr, |
@@ -2777,6 +3025,7 @@ struct nfs_rpc_ops nfs_v4_clientops = { | |||
2777 | .file_open = nfs4_proc_file_open, | 3025 | .file_open = nfs4_proc_file_open, |
2778 | .file_release = nfs4_proc_file_release, | 3026 | .file_release = nfs4_proc_file_release, |
2779 | .lock = nfs4_proc_lock, | 3027 | .lock = nfs4_proc_lock, |
3028 | .clear_acl_cache = nfs4_zap_acl_attr, | ||
2780 | }; | 3029 | }; |
2781 | 3030 | ||
2782 | /* | 3031 | /* |
diff --git a/fs/nfs/nfs4renewd.c b/fs/nfs/nfs4renewd.c index 667e06f1c647..a3001628ad32 100644 --- a/fs/nfs/nfs4renewd.c +++ b/fs/nfs/nfs4renewd.c | |||
@@ -53,6 +53,7 @@ | |||
53 | #include <linux/nfs.h> | 53 | #include <linux/nfs.h> |
54 | #include <linux/nfs4.h> | 54 | #include <linux/nfs4.h> |
55 | #include <linux/nfs_fs.h> | 55 | #include <linux/nfs_fs.h> |
56 | #include "nfs4_fs.h" | ||
56 | 57 | ||
57 | #define NFSDBG_FACILITY NFSDBG_PROC | 58 | #define NFSDBG_FACILITY NFSDBG_PROC |
58 | 59 | ||
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 231cebce3c87..afe587d82f1e 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -46,24 +46,18 @@ | |||
46 | #include <linux/workqueue.h> | 46 | #include <linux/workqueue.h> |
47 | #include <linux/bitops.h> | 47 | #include <linux/bitops.h> |
48 | 48 | ||
49 | #include "nfs4_fs.h" | ||
49 | #include "callback.h" | 50 | #include "callback.h" |
50 | #include "delegation.h" | 51 | #include "delegation.h" |
51 | 52 | ||
52 | #define OPENOWNER_POOL_SIZE 8 | 53 | #define OPENOWNER_POOL_SIZE 8 |
53 | 54 | ||
54 | static DEFINE_SPINLOCK(state_spinlock); | 55 | const nfs4_stateid zero_stateid; |
55 | |||
56 | nfs4_stateid zero_stateid; | ||
57 | |||
58 | #if 0 | ||
59 | nfs4_stateid one_stateid = | ||
60 | { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; | ||
61 | #endif | ||
62 | 56 | ||
57 | static DEFINE_SPINLOCK(state_spinlock); | ||
63 | static LIST_HEAD(nfs4_clientid_list); | 58 | static LIST_HEAD(nfs4_clientid_list); |
64 | 59 | ||
65 | static void nfs4_recover_state(void *); | 60 | static void nfs4_recover_state(void *); |
66 | extern void nfs4_renew_state(void *); | ||
67 | 61 | ||
68 | void | 62 | void |
69 | init_nfsv4_state(struct nfs_server *server) | 63 | init_nfsv4_state(struct nfs_server *server) |
@@ -116,6 +110,7 @@ nfs4_alloc_client(struct in_addr *addr) | |||
116 | INIT_LIST_HEAD(&clp->cl_superblocks); | 110 | INIT_LIST_HEAD(&clp->cl_superblocks); |
117 | init_waitqueue_head(&clp->cl_waitq); | 111 | init_waitqueue_head(&clp->cl_waitq); |
118 | rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS4 client"); | 112 | rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS4 client"); |
113 | clp->cl_rpcclient = ERR_PTR(-EINVAL); | ||
119 | clp->cl_boot_time = CURRENT_TIME; | 114 | clp->cl_boot_time = CURRENT_TIME; |
120 | clp->cl_state = 1 << NFS4CLNT_OK; | 115 | clp->cl_state = 1 << NFS4CLNT_OK; |
121 | return clp; | 116 | return clp; |
@@ -137,7 +132,7 @@ nfs4_free_client(struct nfs4_client *clp) | |||
137 | if (clp->cl_cred) | 132 | if (clp->cl_cred) |
138 | put_rpccred(clp->cl_cred); | 133 | put_rpccred(clp->cl_cred); |
139 | nfs_idmap_delete(clp); | 134 | nfs_idmap_delete(clp); |
140 | if (clp->cl_rpcclient) | 135 | if (!IS_ERR(clp->cl_rpcclient)) |
141 | rpc_shutdown_client(clp->cl_rpcclient); | 136 | rpc_shutdown_client(clp->cl_rpcclient); |
142 | kfree(clp); | 137 | kfree(clp); |
143 | nfs_callback_down(); | 138 | nfs_callback_down(); |
@@ -365,7 +360,7 @@ nfs4_alloc_open_state(void) | |||
365 | atomic_set(&state->count, 1); | 360 | atomic_set(&state->count, 1); |
366 | INIT_LIST_HEAD(&state->lock_states); | 361 | INIT_LIST_HEAD(&state->lock_states); |
367 | init_MUTEX(&state->lock_sema); | 362 | init_MUTEX(&state->lock_sema); |
368 | rwlock_init(&state->state_lock); | 363 | spin_lock_init(&state->state_lock); |
369 | return state; | 364 | return state; |
370 | } | 365 | } |
371 | 366 | ||
@@ -547,16 +542,6 @@ __nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner) | |||
547 | return NULL; | 542 | return NULL; |
548 | } | 543 | } |
549 | 544 | ||
550 | struct nfs4_lock_state * | ||
551 | nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner) | ||
552 | { | ||
553 | struct nfs4_lock_state *lsp; | ||
554 | read_lock(&state->state_lock); | ||
555 | lsp = __nfs4_find_lock_state(state, fl_owner); | ||
556 | read_unlock(&state->state_lock); | ||
557 | return lsp; | ||
558 | } | ||
559 | |||
560 | /* | 545 | /* |
561 | * Return a compatible lock_state. If no initialized lock_state structure | 546 | * Return a compatible lock_state. If no initialized lock_state structure |
562 | * exists, return an uninitialized one. | 547 | * exists, return an uninitialized one. |
@@ -573,14 +558,13 @@ static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, f | |||
573 | return NULL; | 558 | return NULL; |
574 | lsp->ls_flags = 0; | 559 | lsp->ls_flags = 0; |
575 | lsp->ls_seqid = 0; /* arbitrary */ | 560 | lsp->ls_seqid = 0; /* arbitrary */ |
576 | lsp->ls_id = -1; | ||
577 | memset(lsp->ls_stateid.data, 0, sizeof(lsp->ls_stateid.data)); | 561 | memset(lsp->ls_stateid.data, 0, sizeof(lsp->ls_stateid.data)); |
578 | atomic_set(&lsp->ls_count, 1); | 562 | atomic_set(&lsp->ls_count, 1); |
579 | lsp->ls_owner = fl_owner; | 563 | lsp->ls_owner = fl_owner; |
580 | INIT_LIST_HEAD(&lsp->ls_locks); | ||
581 | spin_lock(&clp->cl_lock); | 564 | spin_lock(&clp->cl_lock); |
582 | lsp->ls_id = nfs4_alloc_lockowner_id(clp); | 565 | lsp->ls_id = nfs4_alloc_lockowner_id(clp); |
583 | spin_unlock(&clp->cl_lock); | 566 | spin_unlock(&clp->cl_lock); |
567 | INIT_LIST_HEAD(&lsp->ls_locks); | ||
584 | return lsp; | 568 | return lsp; |
585 | } | 569 | } |
586 | 570 | ||
@@ -590,121 +574,112 @@ static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, f | |||
590 | * | 574 | * |
591 | * The caller must be holding state->lock_sema and clp->cl_sem | 575 | * The caller must be holding state->lock_sema and clp->cl_sem |
592 | */ | 576 | */ |
593 | struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_owner_t owner) | 577 | static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_owner_t owner) |
594 | { | 578 | { |
595 | struct nfs4_lock_state * lsp; | 579 | struct nfs4_lock_state *lsp, *new = NULL; |
596 | 580 | ||
597 | lsp = nfs4_find_lock_state(state, owner); | 581 | for(;;) { |
598 | if (lsp == NULL) | 582 | spin_lock(&state->state_lock); |
599 | lsp = nfs4_alloc_lock_state(state, owner); | 583 | lsp = __nfs4_find_lock_state(state, owner); |
584 | if (lsp != NULL) | ||
585 | break; | ||
586 | if (new != NULL) { | ||
587 | new->ls_state = state; | ||
588 | list_add(&new->ls_locks, &state->lock_states); | ||
589 | set_bit(LK_STATE_IN_USE, &state->flags); | ||
590 | lsp = new; | ||
591 | new = NULL; | ||
592 | break; | ||
593 | } | ||
594 | spin_unlock(&state->state_lock); | ||
595 | new = nfs4_alloc_lock_state(state, owner); | ||
596 | if (new == NULL) | ||
597 | return NULL; | ||
598 | } | ||
599 | spin_unlock(&state->state_lock); | ||
600 | kfree(new); | ||
600 | return lsp; | 601 | return lsp; |
601 | } | 602 | } |
602 | 603 | ||
603 | /* | 604 | /* |
604 | * Byte-range lock aware utility to initialize the stateid of read/write | 605 | * Release reference to lock_state, and free it if we see that |
605 | * requests. | 606 | * it is no longer in use |
606 | */ | 607 | */ |
607 | void | 608 | static void nfs4_put_lock_state(struct nfs4_lock_state *lsp) |
608 | nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t fl_owner) | ||
609 | { | 609 | { |
610 | if (test_bit(LK_STATE_IN_USE, &state->flags)) { | 610 | struct nfs4_state *state; |
611 | struct nfs4_lock_state *lsp; | ||
612 | 611 | ||
613 | lsp = nfs4_find_lock_state(state, fl_owner); | 612 | if (lsp == NULL) |
614 | if (lsp) { | 613 | return; |
615 | memcpy(dst, &lsp->ls_stateid, sizeof(*dst)); | 614 | state = lsp->ls_state; |
616 | nfs4_put_lock_state(lsp); | 615 | if (!atomic_dec_and_lock(&lsp->ls_count, &state->state_lock)) |
617 | return; | 616 | return; |
618 | } | 617 | list_del(&lsp->ls_locks); |
619 | } | 618 | if (list_empty(&state->lock_states)) |
620 | memcpy(dst, &state->stateid, sizeof(*dst)); | 619 | clear_bit(LK_STATE_IN_USE, &state->flags); |
620 | spin_unlock(&state->state_lock); | ||
621 | kfree(lsp); | ||
621 | } | 622 | } |
622 | 623 | ||
623 | /* | 624 | static void nfs4_fl_copy_lock(struct file_lock *dst, struct file_lock *src) |
624 | * Called with state->lock_sema and clp->cl_sem held. | ||
625 | */ | ||
626 | void nfs4_increment_lock_seqid(int status, struct nfs4_lock_state *lsp) | ||
627 | { | 625 | { |
628 | if (status == NFS_OK || seqid_mutating_err(-status)) | 626 | struct nfs4_lock_state *lsp = src->fl_u.nfs4_fl.owner; |
629 | lsp->ls_seqid++; | ||
630 | } | ||
631 | 627 | ||
632 | /* | 628 | dst->fl_u.nfs4_fl.owner = lsp; |
633 | * Check to see if the request lock (type FL_UNLK) effects the fl lock. | 629 | atomic_inc(&lsp->ls_count); |
634 | * | 630 | } |
635 | * fl and request must have the same posix owner | ||
636 | * | ||
637 | * return: | ||
638 | * 0 -> fl not effected by request | ||
639 | * 1 -> fl consumed by request | ||
640 | */ | ||
641 | 631 | ||
642 | static int | 632 | static void nfs4_fl_release_lock(struct file_lock *fl) |
643 | nfs4_check_unlock(struct file_lock *fl, struct file_lock *request) | ||
644 | { | 633 | { |
645 | if (fl->fl_start >= request->fl_start && fl->fl_end <= request->fl_end) | 634 | nfs4_put_lock_state(fl->fl_u.nfs4_fl.owner); |
646 | return 1; | ||
647 | return 0; | ||
648 | } | 635 | } |
649 | 636 | ||
650 | /* | 637 | static struct file_lock_operations nfs4_fl_lock_ops = { |
651 | * Post an initialized lock_state on the state->lock_states list. | 638 | .fl_copy_lock = nfs4_fl_copy_lock, |
652 | */ | 639 | .fl_release_private = nfs4_fl_release_lock, |
653 | void nfs4_notify_setlk(struct nfs4_state *state, struct file_lock *request, struct nfs4_lock_state *lsp) | 640 | }; |
641 | |||
642 | int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl) | ||
654 | { | 643 | { |
655 | if (!list_empty(&lsp->ls_locks)) | 644 | struct nfs4_lock_state *lsp; |
656 | return; | 645 | |
657 | atomic_inc(&lsp->ls_count); | 646 | if (fl->fl_ops != NULL) |
658 | write_lock(&state->state_lock); | 647 | return 0; |
659 | list_add(&lsp->ls_locks, &state->lock_states); | 648 | lsp = nfs4_get_lock_state(state, fl->fl_owner); |
660 | set_bit(LK_STATE_IN_USE, &state->flags); | 649 | if (lsp == NULL) |
661 | write_unlock(&state->state_lock); | 650 | return -ENOMEM; |
651 | fl->fl_u.nfs4_fl.owner = lsp; | ||
652 | fl->fl_ops = &nfs4_fl_lock_ops; | ||
653 | return 0; | ||
662 | } | 654 | } |
663 | 655 | ||
664 | /* | 656 | /* |
665 | * to decide to 'reap' lock state: | 657 | * Byte-range lock aware utility to initialize the stateid of read/write |
666 | * 1) search i_flock for file_locks with fl.lock_state = to ls. | 658 | * requests. |
667 | * 2) determine if unlock will consume found lock. | ||
668 | * if so, reap | ||
669 | * | ||
670 | * else, don't reap. | ||
671 | * | ||
672 | */ | 659 | */ |
673 | void | 660 | void nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t fl_owner) |
674 | nfs4_notify_unlck(struct nfs4_state *state, struct file_lock *request, struct nfs4_lock_state *lsp) | ||
675 | { | 661 | { |
676 | struct inode *inode = state->inode; | 662 | struct nfs4_lock_state *lsp; |
677 | struct file_lock *fl; | ||
678 | 663 | ||
679 | for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { | 664 | memcpy(dst, &state->stateid, sizeof(*dst)); |
680 | if (!(fl->fl_flags & FL_POSIX)) | 665 | if (test_bit(LK_STATE_IN_USE, &state->flags) == 0) |
681 | continue; | 666 | return; |
682 | if (fl->fl_owner != lsp->ls_owner) | ||
683 | continue; | ||
684 | /* Exit if we find at least one lock which is not consumed */ | ||
685 | if (nfs4_check_unlock(fl,request) == 0) | ||
686 | return; | ||
687 | } | ||
688 | 667 | ||
689 | write_lock(&state->state_lock); | 668 | spin_lock(&state->state_lock); |
690 | list_del_init(&lsp->ls_locks); | 669 | lsp = __nfs4_find_lock_state(state, fl_owner); |
691 | if (list_empty(&state->lock_states)) | 670 | if (lsp != NULL && (lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0) |
692 | clear_bit(LK_STATE_IN_USE, &state->flags); | 671 | memcpy(dst, &lsp->ls_stateid, sizeof(*dst)); |
693 | write_unlock(&state->state_lock); | 672 | spin_unlock(&state->state_lock); |
694 | nfs4_put_lock_state(lsp); | 673 | nfs4_put_lock_state(lsp); |
695 | } | 674 | } |
696 | 675 | ||
697 | /* | 676 | /* |
698 | * Release reference to lock_state, and free it if we see that | 677 | * Called with state->lock_sema and clp->cl_sem held. |
699 | * it is no longer in use | 678 | */ |
700 | */ | 679 | void nfs4_increment_lock_seqid(int status, struct nfs4_lock_state *lsp) |
701 | void | ||
702 | nfs4_put_lock_state(struct nfs4_lock_state *lsp) | ||
703 | { | 680 | { |
704 | if (!atomic_dec_and_test(&lsp->ls_count)) | 681 | if (status == NFS_OK || seqid_mutating_err(-status)) |
705 | return; | 682 | lsp->ls_seqid++; |
706 | BUG_ON (!list_empty(&lsp->ls_locks)); | ||
707 | kfree(lsp); | ||
708 | } | 683 | } |
709 | 684 | ||
710 | /* | 685 | /* |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 5f4de05763c9..6c564ef9489e 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -51,6 +51,7 @@ | |||
51 | #include <linux/nfs4.h> | 51 | #include <linux/nfs4.h> |
52 | #include <linux/nfs_fs.h> | 52 | #include <linux/nfs_fs.h> |
53 | #include <linux/nfs_idmap.h> | 53 | #include <linux/nfs_idmap.h> |
54 | #include "nfs4_fs.h" | ||
54 | 55 | ||
55 | #define NFSDBG_FACILITY NFSDBG_XDR | 56 | #define NFSDBG_FACILITY NFSDBG_XDR |
56 | 57 | ||
@@ -82,12 +83,16 @@ static int nfs_stat_to_errno(int); | |||
82 | #define encode_getfh_maxsz (op_encode_hdr_maxsz) | 83 | #define encode_getfh_maxsz (op_encode_hdr_maxsz) |
83 | #define decode_getfh_maxsz (op_decode_hdr_maxsz + 1 + \ | 84 | #define decode_getfh_maxsz (op_decode_hdr_maxsz + 1 + \ |
84 | ((3+NFS4_FHSIZE) >> 2)) | 85 | ((3+NFS4_FHSIZE) >> 2)) |
85 | #define encode_getattr_maxsz (op_encode_hdr_maxsz + 3) | 86 | #define nfs4_fattr_bitmap_maxsz 3 |
87 | #define encode_getattr_maxsz (op_encode_hdr_maxsz + nfs4_fattr_bitmap_maxsz) | ||
86 | #define nfs4_name_maxsz (1 + ((3 + NFS4_MAXNAMLEN) >> 2)) | 88 | #define nfs4_name_maxsz (1 + ((3 + NFS4_MAXNAMLEN) >> 2)) |
87 | #define nfs4_path_maxsz (1 + ((3 + NFS4_MAXPATHLEN) >> 2)) | 89 | #define nfs4_path_maxsz (1 + ((3 + NFS4_MAXPATHLEN) >> 2)) |
88 | #define nfs4_fattr_bitmap_maxsz (36 + 2 * nfs4_name_maxsz) | 90 | /* This is based on getfattr, which uses the most attributes: */ |
89 | #define decode_getattr_maxsz (op_decode_hdr_maxsz + 3 + \ | 91 | #define nfs4_fattr_value_maxsz (1 + (1 + 2 + 2 + 4 + 2 + 1 + 1 + 2 + 2 + \ |
90 | nfs4_fattr_bitmap_maxsz) | 92 | 3 + 3 + 3 + 2 * nfs4_name_maxsz)) |
93 | #define nfs4_fattr_maxsz (nfs4_fattr_bitmap_maxsz + \ | ||
94 | nfs4_fattr_value_maxsz) | ||
95 | #define decode_getattr_maxsz (op_decode_hdr_maxsz + nfs4_fattr_maxsz) | ||
91 | #define encode_savefh_maxsz (op_encode_hdr_maxsz) | 96 | #define encode_savefh_maxsz (op_encode_hdr_maxsz) |
92 | #define decode_savefh_maxsz (op_decode_hdr_maxsz) | 97 | #define decode_savefh_maxsz (op_decode_hdr_maxsz) |
93 | #define encode_fsinfo_maxsz (op_encode_hdr_maxsz + 2) | 98 | #define encode_fsinfo_maxsz (op_encode_hdr_maxsz + 2) |
@@ -122,11 +127,11 @@ static int nfs_stat_to_errno(int); | |||
122 | #define encode_symlink_maxsz (op_encode_hdr_maxsz + \ | 127 | #define encode_symlink_maxsz (op_encode_hdr_maxsz + \ |
123 | 1 + nfs4_name_maxsz + \ | 128 | 1 + nfs4_name_maxsz + \ |
124 | nfs4_path_maxsz + \ | 129 | nfs4_path_maxsz + \ |
125 | nfs4_fattr_bitmap_maxsz) | 130 | nfs4_fattr_maxsz) |
126 | #define decode_symlink_maxsz (op_decode_hdr_maxsz + 8) | 131 | #define decode_symlink_maxsz (op_decode_hdr_maxsz + 8) |
127 | #define encode_create_maxsz (op_encode_hdr_maxsz + \ | 132 | #define encode_create_maxsz (op_encode_hdr_maxsz + \ |
128 | 2 + nfs4_name_maxsz + \ | 133 | 2 + nfs4_name_maxsz + \ |
129 | nfs4_fattr_bitmap_maxsz) | 134 | nfs4_fattr_maxsz) |
130 | #define decode_create_maxsz (op_decode_hdr_maxsz + 8) | 135 | #define decode_create_maxsz (op_decode_hdr_maxsz + 8) |
131 | #define encode_delegreturn_maxsz (op_encode_hdr_maxsz + 4) | 136 | #define encode_delegreturn_maxsz (op_encode_hdr_maxsz + 4) |
132 | #define decode_delegreturn_maxsz (op_decode_hdr_maxsz) | 137 | #define decode_delegreturn_maxsz (op_decode_hdr_maxsz) |
@@ -205,7 +210,7 @@ static int nfs_stat_to_errno(int); | |||
205 | #define NFS4_enc_setattr_sz (compound_encode_hdr_maxsz + \ | 210 | #define NFS4_enc_setattr_sz (compound_encode_hdr_maxsz + \ |
206 | encode_putfh_maxsz + \ | 211 | encode_putfh_maxsz + \ |
207 | op_encode_hdr_maxsz + 4 + \ | 212 | op_encode_hdr_maxsz + 4 + \ |
208 | nfs4_fattr_bitmap_maxsz + \ | 213 | nfs4_fattr_maxsz + \ |
209 | encode_getattr_maxsz) | 214 | encode_getattr_maxsz) |
210 | #define NFS4_dec_setattr_sz (compound_decode_hdr_maxsz + \ | 215 | #define NFS4_dec_setattr_sz (compound_decode_hdr_maxsz + \ |
211 | decode_putfh_maxsz + \ | 216 | decode_putfh_maxsz + \ |
@@ -360,6 +365,20 @@ static int nfs_stat_to_errno(int); | |||
360 | encode_delegreturn_maxsz) | 365 | encode_delegreturn_maxsz) |
361 | #define NFS4_dec_delegreturn_sz (compound_decode_hdr_maxsz + \ | 366 | #define NFS4_dec_delegreturn_sz (compound_decode_hdr_maxsz + \ |
362 | decode_delegreturn_maxsz) | 367 | decode_delegreturn_maxsz) |
368 | #define NFS4_enc_getacl_sz (compound_encode_hdr_maxsz + \ | ||
369 | encode_putfh_maxsz + \ | ||
370 | encode_getattr_maxsz) | ||
371 | #define NFS4_dec_getacl_sz (compound_decode_hdr_maxsz + \ | ||
372 | decode_putfh_maxsz + \ | ||
373 | op_decode_hdr_maxsz + \ | ||
374 | nfs4_fattr_bitmap_maxsz + 1) | ||
375 | #define NFS4_enc_setacl_sz (compound_encode_hdr_maxsz + \ | ||
376 | encode_putfh_maxsz + \ | ||
377 | op_encode_hdr_maxsz + 4 + \ | ||
378 | nfs4_fattr_bitmap_maxsz + 1) | ||
379 | #define NFS4_dec_setacl_sz (compound_decode_hdr_maxsz + \ | ||
380 | decode_putfh_maxsz + \ | ||
381 | op_decode_hdr_maxsz + nfs4_fattr_bitmap_maxsz) | ||
363 | 382 | ||
364 | static struct { | 383 | static struct { |
365 | unsigned int mode; | 384 | unsigned int mode; |
@@ -459,7 +478,7 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s | |||
459 | * In the worst-case, this would be | 478 | * In the worst-case, this would be |
460 | * 12(bitmap) + 4(attrlen) + 8(size) + 4(mode) + 4(atime) + 4(mtime) | 479 | * 12(bitmap) + 4(attrlen) + 8(size) + 4(mode) + 4(atime) + 4(mtime) |
461 | * = 36 bytes, plus any contribution from variable-length fields | 480 | * = 36 bytes, plus any contribution from variable-length fields |
462 | * such as owner/group/acl's. | 481 | * such as owner/group. |
463 | */ | 482 | */ |
464 | len = 16; | 483 | len = 16; |
465 | 484 | ||
@@ -660,8 +679,6 @@ static int encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1 | |||
660 | 679 | ||
661 | static int encode_getfattr(struct xdr_stream *xdr, const u32* bitmask) | 680 | static int encode_getfattr(struct xdr_stream *xdr, const u32* bitmask) |
662 | { | 681 | { |
663 | extern u32 nfs4_fattr_bitmap[]; | ||
664 | |||
665 | return encode_getattr_two(xdr, | 682 | return encode_getattr_two(xdr, |
666 | bitmask[0] & nfs4_fattr_bitmap[0], | 683 | bitmask[0] & nfs4_fattr_bitmap[0], |
667 | bitmask[1] & nfs4_fattr_bitmap[1]); | 684 | bitmask[1] & nfs4_fattr_bitmap[1]); |
@@ -669,8 +686,6 @@ static int encode_getfattr(struct xdr_stream *xdr, const u32* bitmask) | |||
669 | 686 | ||
670 | static int encode_fsinfo(struct xdr_stream *xdr, const u32* bitmask) | 687 | static int encode_fsinfo(struct xdr_stream *xdr, const u32* bitmask) |
671 | { | 688 | { |
672 | extern u32 nfs4_fsinfo_bitmap[]; | ||
673 | |||
674 | return encode_getattr_two(xdr, bitmask[0] & nfs4_fsinfo_bitmap[0], | 689 | return encode_getattr_two(xdr, bitmask[0] & nfs4_fsinfo_bitmap[0], |
675 | bitmask[1] & nfs4_fsinfo_bitmap[1]); | 690 | bitmask[1] & nfs4_fsinfo_bitmap[1]); |
676 | } | 691 | } |
@@ -969,7 +984,6 @@ static int encode_putrootfh(struct xdr_stream *xdr) | |||
969 | 984 | ||
970 | static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx) | 985 | static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx) |
971 | { | 986 | { |
972 | extern nfs4_stateid zero_stateid; | ||
973 | nfs4_stateid stateid; | 987 | nfs4_stateid stateid; |
974 | uint32_t *p; | 988 | uint32_t *p; |
975 | 989 | ||
@@ -1000,6 +1014,10 @@ static int encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args) | |||
1000 | static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req) | 1014 | static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req) |
1001 | { | 1015 | { |
1002 | struct rpc_auth *auth = req->rq_task->tk_auth; | 1016 | struct rpc_auth *auth = req->rq_task->tk_auth; |
1017 | uint32_t attrs[2] = { | ||
1018 | FATTR4_WORD0_RDATTR_ERROR|FATTR4_WORD0_FILEID, | ||
1019 | FATTR4_WORD1_MOUNTED_ON_FILEID, | ||
1020 | }; | ||
1003 | int replen; | 1021 | int replen; |
1004 | uint32_t *p; | 1022 | uint32_t *p; |
1005 | 1023 | ||
@@ -1010,13 +1028,20 @@ static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg | |||
1010 | WRITE32(readdir->count >> 1); /* We're not doing readdirplus */ | 1028 | WRITE32(readdir->count >> 1); /* We're not doing readdirplus */ |
1011 | WRITE32(readdir->count); | 1029 | WRITE32(readdir->count); |
1012 | WRITE32(2); | 1030 | WRITE32(2); |
1013 | if (readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID) { | 1031 | /* Switch to mounted_on_fileid if the server supports it */ |
1014 | WRITE32(0); | 1032 | if (readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID) |
1015 | WRITE32(FATTR4_WORD1_MOUNTED_ON_FILEID); | 1033 | attrs[0] &= ~FATTR4_WORD0_FILEID; |
1016 | } else { | 1034 | else |
1017 | WRITE32(FATTR4_WORD0_FILEID); | 1035 | attrs[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID; |
1018 | WRITE32(0); | 1036 | WRITE32(attrs[0] & readdir->bitmask[0]); |
1019 | } | 1037 | WRITE32(attrs[1] & readdir->bitmask[1]); |
1038 | dprintk("%s: cookie = %Lu, verifier = 0x%x%x, bitmap = 0x%x%x\n", | ||
1039 | __FUNCTION__, | ||
1040 | (unsigned long long)readdir->cookie, | ||
1041 | ((u32 *)readdir->verifier.data)[0], | ||
1042 | ((u32 *)readdir->verifier.data)[1], | ||
1043 | attrs[0] & readdir->bitmask[0], | ||
1044 | attrs[1] & readdir->bitmask[1]); | ||
1020 | 1045 | ||
1021 | /* set up reply kvec | 1046 | /* set up reply kvec |
1022 | * toplevel_status + taglen + rescount + OP_PUTFH + status | 1047 | * toplevel_status + taglen + rescount + OP_PUTFH + status |
@@ -1025,6 +1050,9 @@ static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg | |||
1025 | replen = (RPC_REPHDRSIZE + auth->au_rslack + 9) << 2; | 1050 | replen = (RPC_REPHDRSIZE + auth->au_rslack + 9) << 2; |
1026 | xdr_inline_pages(&req->rq_rcv_buf, replen, readdir->pages, | 1051 | xdr_inline_pages(&req->rq_rcv_buf, replen, readdir->pages, |
1027 | readdir->pgbase, readdir->count); | 1052 | readdir->pgbase, readdir->count); |
1053 | dprintk("%s: inlined page args = (%u, %p, %u, %u)\n", | ||
1054 | __FUNCTION__, replen, readdir->pages, | ||
1055 | readdir->pgbase, readdir->count); | ||
1028 | 1056 | ||
1029 | return 0; | 1057 | return 0; |
1030 | } | 1058 | } |
@@ -1089,6 +1117,25 @@ static int encode_renew(struct xdr_stream *xdr, const struct nfs4_client *client | |||
1089 | } | 1117 | } |
1090 | 1118 | ||
1091 | static int | 1119 | static int |
1120 | encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg) | ||
1121 | { | ||
1122 | uint32_t *p; | ||
1123 | |||
1124 | RESERVE_SPACE(4+sizeof(zero_stateid.data)); | ||
1125 | WRITE32(OP_SETATTR); | ||
1126 | WRITEMEM(zero_stateid.data, sizeof(zero_stateid.data)); | ||
1127 | RESERVE_SPACE(2*4); | ||
1128 | WRITE32(1); | ||
1129 | WRITE32(FATTR4_WORD0_ACL); | ||
1130 | if (arg->acl_len % 4) | ||
1131 | return -EINVAL; | ||
1132 | RESERVE_SPACE(4); | ||
1133 | WRITE32(arg->acl_len); | ||
1134 | xdr_write_pages(xdr, arg->acl_pages, arg->acl_pgbase, arg->acl_len); | ||
1135 | return 0; | ||
1136 | } | ||
1137 | |||
1138 | static int | ||
1092 | encode_savefh(struct xdr_stream *xdr) | 1139 | encode_savefh(struct xdr_stream *xdr) |
1093 | { | 1140 | { |
1094 | uint32_t *p; | 1141 | uint32_t *p; |
@@ -1632,6 +1679,34 @@ out: | |||
1632 | } | 1679 | } |
1633 | 1680 | ||
1634 | /* | 1681 | /* |
1682 | * Encode a GETACL request | ||
1683 | */ | ||
1684 | static int | ||
1685 | nfs4_xdr_enc_getacl(struct rpc_rqst *req, uint32_t *p, | ||
1686 | struct nfs_getaclargs *args) | ||
1687 | { | ||
1688 | struct xdr_stream xdr; | ||
1689 | struct rpc_auth *auth = req->rq_task->tk_auth; | ||
1690 | struct compound_hdr hdr = { | ||
1691 | .nops = 2, | ||
1692 | }; | ||
1693 | int replen, status; | ||
1694 | |||
1695 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
1696 | encode_compound_hdr(&xdr, &hdr); | ||
1697 | status = encode_putfh(&xdr, args->fh); | ||
1698 | if (status) | ||
1699 | goto out; | ||
1700 | status = encode_getattr_two(&xdr, FATTR4_WORD0_ACL, 0); | ||
1701 | /* set up reply buffer: */ | ||
1702 | replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_getacl_sz) << 2; | ||
1703 | xdr_inline_pages(&req->rq_rcv_buf, replen, | ||
1704 | args->acl_pages, args->acl_pgbase, args->acl_len); | ||
1705 | out: | ||
1706 | return status; | ||
1707 | } | ||
1708 | |||
1709 | /* | ||
1635 | * Encode a WRITE request | 1710 | * Encode a WRITE request |
1636 | */ | 1711 | */ |
1637 | static int nfs4_xdr_enc_write(struct rpc_rqst *req, uint32_t *p, struct nfs_writeargs *args) | 1712 | static int nfs4_xdr_enc_write(struct rpc_rqst *req, uint32_t *p, struct nfs_writeargs *args) |
@@ -1697,7 +1772,6 @@ static int nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, uint32_t *p, struct nfs4_fs | |||
1697 | */ | 1772 | */ |
1698 | static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, uint32_t *p, const struct nfs4_pathconf_arg *args) | 1773 | static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, uint32_t *p, const struct nfs4_pathconf_arg *args) |
1699 | { | 1774 | { |
1700 | extern u32 nfs4_pathconf_bitmap[2]; | ||
1701 | struct xdr_stream xdr; | 1775 | struct xdr_stream xdr; |
1702 | struct compound_hdr hdr = { | 1776 | struct compound_hdr hdr = { |
1703 | .nops = 2, | 1777 | .nops = 2, |
@@ -1718,7 +1792,6 @@ static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, uint32_t *p, const struct | |||
1718 | */ | 1792 | */ |
1719 | static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, uint32_t *p, const struct nfs4_statfs_arg *args) | 1793 | static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, uint32_t *p, const struct nfs4_statfs_arg *args) |
1720 | { | 1794 | { |
1721 | extern u32 nfs4_statfs_bitmap[]; | ||
1722 | struct xdr_stream xdr; | 1795 | struct xdr_stream xdr; |
1723 | struct compound_hdr hdr = { | 1796 | struct compound_hdr hdr = { |
1724 | .nops = 2, | 1797 | .nops = 2, |
@@ -3003,6 +3076,11 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n | |||
3003 | return status; | 3076 | return status; |
3004 | READ_BUF(8); | 3077 | READ_BUF(8); |
3005 | COPYMEM(readdir->verifier.data, 8); | 3078 | COPYMEM(readdir->verifier.data, 8); |
3079 | dprintk("%s: verifier = 0x%x%x\n", | ||
3080 | __FUNCTION__, | ||
3081 | ((u32 *)readdir->verifier.data)[0], | ||
3082 | ((u32 *)readdir->verifier.data)[1]); | ||
3083 | |||
3006 | 3084 | ||
3007 | hdrlen = (char *) p - (char *) iov->iov_base; | 3085 | hdrlen = (char *) p - (char *) iov->iov_base; |
3008 | recvd = rcvbuf->len - hdrlen; | 3086 | recvd = rcvbuf->len - hdrlen; |
@@ -3017,12 +3095,14 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n | |||
3017 | for (nr = 0; *p++; nr++) { | 3095 | for (nr = 0; *p++; nr++) { |
3018 | if (p + 3 > end) | 3096 | if (p + 3 > end) |
3019 | goto short_pkt; | 3097 | goto short_pkt; |
3098 | dprintk("cookie = %Lu, ", *((unsigned long long *)p)); | ||
3020 | p += 2; /* cookie */ | 3099 | p += 2; /* cookie */ |
3021 | len = ntohl(*p++); /* filename length */ | 3100 | len = ntohl(*p++); /* filename length */ |
3022 | if (len > NFS4_MAXNAMLEN) { | 3101 | if (len > NFS4_MAXNAMLEN) { |
3023 | printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)\n", len); | 3102 | printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)\n", len); |
3024 | goto err_unmap; | 3103 | goto err_unmap; |
3025 | } | 3104 | } |
3105 | dprintk("filename = %*s\n", len, (char *)p); | ||
3026 | p += XDR_QUADLEN(len); | 3106 | p += XDR_QUADLEN(len); |
3027 | if (p + 1 > end) | 3107 | if (p + 1 > end) |
3028 | goto short_pkt; | 3108 | goto short_pkt; |
@@ -3042,6 +3122,7 @@ out: | |||
3042 | kunmap_atomic(kaddr, KM_USER0); | 3122 | kunmap_atomic(kaddr, KM_USER0); |
3043 | return 0; | 3123 | return 0; |
3044 | short_pkt: | 3124 | short_pkt: |
3125 | dprintk("%s: short packet at entry %d\n", __FUNCTION__, nr); | ||
3045 | entry[0] = entry[1] = 0; | 3126 | entry[0] = entry[1] = 0; |
3046 | /* truncate listing ? */ | 3127 | /* truncate listing ? */ |
3047 | if (!nr) { | 3128 | if (!nr) { |
@@ -3127,6 +3208,47 @@ static int decode_renew(struct xdr_stream *xdr) | |||
3127 | return decode_op_hdr(xdr, OP_RENEW); | 3208 | return decode_op_hdr(xdr, OP_RENEW); |
3128 | } | 3209 | } |
3129 | 3210 | ||
3211 | static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req, | ||
3212 | size_t *acl_len) | ||
3213 | { | ||
3214 | uint32_t *savep; | ||
3215 | uint32_t attrlen, | ||
3216 | bitmap[2] = {0}; | ||
3217 | struct kvec *iov = req->rq_rcv_buf.head; | ||
3218 | int status; | ||
3219 | |||
3220 | *acl_len = 0; | ||
3221 | if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0) | ||
3222 | goto out; | ||
3223 | if ((status = decode_attr_bitmap(xdr, bitmap)) != 0) | ||
3224 | goto out; | ||
3225 | if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0) | ||
3226 | goto out; | ||
3227 | |||
3228 | if (unlikely(bitmap[0] & (FATTR4_WORD0_ACL - 1U))) | ||
3229 | return -EIO; | ||
3230 | if (likely(bitmap[0] & FATTR4_WORD0_ACL)) { | ||
3231 | int hdrlen, recvd; | ||
3232 | |||
3233 | /* We ignore &savep and don't do consistency checks on | ||
3234 | * the attr length. Let userspace figure it out.... */ | ||
3235 | hdrlen = (u8 *)xdr->p - (u8 *)iov->iov_base; | ||
3236 | recvd = req->rq_rcv_buf.len - hdrlen; | ||
3237 | if (attrlen > recvd) { | ||
3238 | printk(KERN_WARNING "NFS: server cheating in getattr" | ||
3239 | " acl reply: attrlen %u > recvd %u\n", | ||
3240 | attrlen, recvd); | ||
3241 | return -EINVAL; | ||
3242 | } | ||
3243 | if (attrlen <= *acl_len) | ||
3244 | xdr_read_pages(xdr, attrlen); | ||
3245 | *acl_len = attrlen; | ||
3246 | } | ||
3247 | |||
3248 | out: | ||
3249 | return status; | ||
3250 | } | ||
3251 | |||
3130 | static int | 3252 | static int |
3131 | decode_savefh(struct xdr_stream *xdr) | 3253 | decode_savefh(struct xdr_stream *xdr) |
3132 | { | 3254 | { |
@@ -3418,6 +3540,71 @@ out: | |||
3418 | 3540 | ||
3419 | } | 3541 | } |
3420 | 3542 | ||
3543 | /* | ||
3544 | * Encode an SETACL request | ||
3545 | */ | ||
3546 | static int | ||
3547 | nfs4_xdr_enc_setacl(struct rpc_rqst *req, uint32_t *p, struct nfs_setaclargs *args) | ||
3548 | { | ||
3549 | struct xdr_stream xdr; | ||
3550 | struct compound_hdr hdr = { | ||
3551 | .nops = 2, | ||
3552 | }; | ||
3553 | int status; | ||
3554 | |||
3555 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
3556 | encode_compound_hdr(&xdr, &hdr); | ||
3557 | status = encode_putfh(&xdr, args->fh); | ||
3558 | if (status) | ||
3559 | goto out; | ||
3560 | status = encode_setacl(&xdr, args); | ||
3561 | out: | ||
3562 | return status; | ||
3563 | } | ||
3564 | /* | ||
3565 | * Decode SETACL response | ||
3566 | */ | ||
3567 | static int | ||
3568 | nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, uint32_t *p, void *res) | ||
3569 | { | ||
3570 | struct xdr_stream xdr; | ||
3571 | struct compound_hdr hdr; | ||
3572 | int status; | ||
3573 | |||
3574 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | ||
3575 | status = decode_compound_hdr(&xdr, &hdr); | ||
3576 | if (status) | ||
3577 | goto out; | ||
3578 | status = decode_putfh(&xdr); | ||
3579 | if (status) | ||
3580 | goto out; | ||
3581 | status = decode_setattr(&xdr, res); | ||
3582 | out: | ||
3583 | return status; | ||
3584 | } | ||
3585 | |||
3586 | /* | ||
3587 | * Decode GETACL response | ||
3588 | */ | ||
3589 | static int | ||
3590 | nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, uint32_t *p, size_t *acl_len) | ||
3591 | { | ||
3592 | struct xdr_stream xdr; | ||
3593 | struct compound_hdr hdr; | ||
3594 | int status; | ||
3595 | |||
3596 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | ||
3597 | status = decode_compound_hdr(&xdr, &hdr); | ||
3598 | if (status) | ||
3599 | goto out; | ||
3600 | status = decode_putfh(&xdr); | ||
3601 | if (status) | ||
3602 | goto out; | ||
3603 | status = decode_getacl(&xdr, rqstp, acl_len); | ||
3604 | |||
3605 | out: | ||
3606 | return status; | ||
3607 | } | ||
3421 | 3608 | ||
3422 | /* | 3609 | /* |
3423 | * Decode CLOSE response | 3610 | * Decode CLOSE response |
@@ -3895,6 +4082,12 @@ uint32_t *nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus) | |||
3895 | } | 4082 | } |
3896 | len = XDR_QUADLEN(ntohl(*p++)); /* attribute buffer length */ | 4083 | len = XDR_QUADLEN(ntohl(*p++)); /* attribute buffer length */ |
3897 | if (len > 0) { | 4084 | if (len > 0) { |
4085 | if (bitmap[0] & FATTR4_WORD0_RDATTR_ERROR) { | ||
4086 | bitmap[0] &= ~FATTR4_WORD0_RDATTR_ERROR; | ||
4087 | /* Ignore the return value of rdattr_error for now */ | ||
4088 | p++; | ||
4089 | len--; | ||
4090 | } | ||
3898 | if (bitmap[0] == 0 && bitmap[1] == FATTR4_WORD1_MOUNTED_ON_FILEID) | 4091 | if (bitmap[0] == 0 && bitmap[1] == FATTR4_WORD1_MOUNTED_ON_FILEID) |
3899 | xdr_decode_hyper(p, &entry->ino); | 4092 | xdr_decode_hyper(p, &entry->ino); |
3900 | else if (bitmap[0] == FATTR4_WORD0_FILEID) | 4093 | else if (bitmap[0] == FATTR4_WORD0_FILEID) |
@@ -3934,6 +4127,8 @@ static struct { | |||
3934 | { NFS4ERR_DQUOT, EDQUOT }, | 4127 | { NFS4ERR_DQUOT, EDQUOT }, |
3935 | { NFS4ERR_STALE, ESTALE }, | 4128 | { NFS4ERR_STALE, ESTALE }, |
3936 | { NFS4ERR_BADHANDLE, EBADHANDLE }, | 4129 | { NFS4ERR_BADHANDLE, EBADHANDLE }, |
4130 | { NFS4ERR_BADOWNER, EINVAL }, | ||
4131 | { NFS4ERR_BADNAME, EINVAL }, | ||
3937 | { NFS4ERR_BAD_COOKIE, EBADCOOKIE }, | 4132 | { NFS4ERR_BAD_COOKIE, EBADCOOKIE }, |
3938 | { NFS4ERR_NOTSUPP, ENOTSUPP }, | 4133 | { NFS4ERR_NOTSUPP, ENOTSUPP }, |
3939 | { NFS4ERR_TOOSMALL, ETOOSMALL }, | 4134 | { NFS4ERR_TOOSMALL, ETOOSMALL }, |
@@ -4019,6 +4214,8 @@ struct rpc_procinfo nfs4_procedures[] = { | |||
4019 | PROC(READDIR, enc_readdir, dec_readdir), | 4214 | PROC(READDIR, enc_readdir, dec_readdir), |
4020 | PROC(SERVER_CAPS, enc_server_caps, dec_server_caps), | 4215 | PROC(SERVER_CAPS, enc_server_caps, dec_server_caps), |
4021 | PROC(DELEGRETURN, enc_delegreturn, dec_delegreturn), | 4216 | PROC(DELEGRETURN, enc_delegreturn, dec_delegreturn), |
4217 | PROC(GETACL, enc_getacl, dec_getacl), | ||
4218 | PROC(SETACL, enc_setacl, dec_setacl), | ||
4022 | }; | 4219 | }; |
4023 | 4220 | ||
4024 | struct rpc_version nfs_version4 = { | 4221 | struct rpc_version nfs_version4 = { |
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c index fd5bc596fe8a..1b272a135a31 100644 --- a/fs/nfs/nfsroot.c +++ b/fs/nfs/nfsroot.c | |||
@@ -124,6 +124,7 @@ enum { | |||
124 | Opt_soft, Opt_hard, Opt_intr, | 124 | Opt_soft, Opt_hard, Opt_intr, |
125 | Opt_nointr, Opt_posix, Opt_noposix, Opt_cto, Opt_nocto, Opt_ac, | 125 | Opt_nointr, Opt_posix, Opt_noposix, Opt_cto, Opt_nocto, Opt_ac, |
126 | Opt_noac, Opt_lock, Opt_nolock, Opt_v2, Opt_v3, Opt_udp, Opt_tcp, | 126 | Opt_noac, Opt_lock, Opt_nolock, Opt_v2, Opt_v3, Opt_udp, Opt_tcp, |
127 | Opt_acl, Opt_noacl, | ||
127 | /* Error token */ | 128 | /* Error token */ |
128 | Opt_err | 129 | Opt_err |
129 | }; | 130 | }; |
@@ -158,6 +159,8 @@ static match_table_t __initdata tokens = { | |||
158 | {Opt_udp, "udp"}, | 159 | {Opt_udp, "udp"}, |
159 | {Opt_tcp, "proto=tcp"}, | 160 | {Opt_tcp, "proto=tcp"}, |
160 | {Opt_tcp, "tcp"}, | 161 | {Opt_tcp, "tcp"}, |
162 | {Opt_acl, "acl"}, | ||
163 | {Opt_noacl, "noacl"}, | ||
161 | {Opt_err, NULL} | 164 | {Opt_err, NULL} |
162 | 165 | ||
163 | }; | 166 | }; |
@@ -266,6 +269,12 @@ static int __init root_nfs_parse(char *name, char *buf) | |||
266 | case Opt_tcp: | 269 | case Opt_tcp: |
267 | nfs_data.flags |= NFS_MOUNT_TCP; | 270 | nfs_data.flags |= NFS_MOUNT_TCP; |
268 | break; | 271 | break; |
272 | case Opt_acl: | ||
273 | nfs_data.flags &= ~NFS_MOUNT_NOACL; | ||
274 | break; | ||
275 | case Opt_noacl: | ||
276 | nfs_data.flags |= NFS_MOUNT_NOACL; | ||
277 | break; | ||
269 | default : | 278 | default : |
270 | return 0; | 279 | return 0; |
271 | } | 280 | } |
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 4f1ba723848d..d53857b148e2 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c | |||
@@ -107,11 +107,38 @@ void nfs_unlock_request(struct nfs_page *req) | |||
107 | smp_mb__before_clear_bit(); | 107 | smp_mb__before_clear_bit(); |
108 | clear_bit(PG_BUSY, &req->wb_flags); | 108 | clear_bit(PG_BUSY, &req->wb_flags); |
109 | smp_mb__after_clear_bit(); | 109 | smp_mb__after_clear_bit(); |
110 | wake_up_all(&req->wb_context->waitq); | 110 | wake_up_bit(&req->wb_flags, PG_BUSY); |
111 | nfs_release_request(req); | 111 | nfs_release_request(req); |
112 | } | 112 | } |
113 | 113 | ||
114 | /** | 114 | /** |
115 | * nfs_set_page_writeback_locked - Lock a request for writeback | ||
116 | * @req: | ||
117 | */ | ||
118 | int nfs_set_page_writeback_locked(struct nfs_page *req) | ||
119 | { | ||
120 | struct nfs_inode *nfsi = NFS_I(req->wb_context->dentry->d_inode); | ||
121 | |||
122 | if (!nfs_lock_request(req)) | ||
123 | return 0; | ||
124 | radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_WRITEBACK); | ||
125 | return 1; | ||
126 | } | ||
127 | |||
128 | /** | ||
129 | * nfs_clear_page_writeback - Unlock request and wake up sleepers | ||
130 | */ | ||
131 | void nfs_clear_page_writeback(struct nfs_page *req) | ||
132 | { | ||
133 | struct nfs_inode *nfsi = NFS_I(req->wb_context->dentry->d_inode); | ||
134 | |||
135 | spin_lock(&nfsi->req_lock); | ||
136 | radix_tree_tag_clear(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_WRITEBACK); | ||
137 | spin_unlock(&nfsi->req_lock); | ||
138 | nfs_unlock_request(req); | ||
139 | } | ||
140 | |||
141 | /** | ||
115 | * nfs_clear_request - Free up all resources allocated to the request | 142 | * nfs_clear_request - Free up all resources allocated to the request |
116 | * @req: | 143 | * @req: |
117 | * | 144 | * |
@@ -150,34 +177,15 @@ nfs_release_request(struct nfs_page *req) | |||
150 | nfs_page_free(req); | 177 | nfs_page_free(req); |
151 | } | 178 | } |
152 | 179 | ||
153 | /** | 180 | static int nfs_wait_bit_interruptible(void *word) |
154 | * nfs_list_add_request - Insert a request into a sorted list | ||
155 | * @req: request | ||
156 | * @head: head of list into which to insert the request. | ||
157 | * | ||
158 | * Note that the wb_list is sorted by page index in order to facilitate | ||
159 | * coalescing of requests. | ||
160 | * We use an insertion sort that is optimized for the case of appended | ||
161 | * writes. | ||
162 | */ | ||
163 | void | ||
164 | nfs_list_add_request(struct nfs_page *req, struct list_head *head) | ||
165 | { | 181 | { |
166 | struct list_head *pos; | 182 | int ret = 0; |
167 | 183 | ||
168 | #ifdef NFS_PARANOIA | 184 | if (signal_pending(current)) |
169 | if (!list_empty(&req->wb_list)) { | 185 | ret = -ERESTARTSYS; |
170 | printk(KERN_ERR "NFS: Add to list failed!\n"); | 186 | else |
171 | BUG(); | 187 | schedule(); |
172 | } | 188 | return ret; |
173 | #endif | ||
174 | list_for_each_prev(pos, head) { | ||
175 | struct nfs_page *p = nfs_list_entry(pos); | ||
176 | if (p->wb_index < req->wb_index) | ||
177 | break; | ||
178 | } | ||
179 | list_add(&req->wb_list, pos); | ||
180 | req->wb_list_head = head; | ||
181 | } | 189 | } |
182 | 190 | ||
183 | /** | 191 | /** |
@@ -190,12 +198,22 @@ nfs_list_add_request(struct nfs_page *req, struct list_head *head) | |||
190 | int | 198 | int |
191 | nfs_wait_on_request(struct nfs_page *req) | 199 | nfs_wait_on_request(struct nfs_page *req) |
192 | { | 200 | { |
193 | struct inode *inode = req->wb_context->dentry->d_inode; | 201 | struct rpc_clnt *clnt = NFS_CLIENT(req->wb_context->dentry->d_inode); |
194 | struct rpc_clnt *clnt = NFS_CLIENT(inode); | 202 | sigset_t oldmask; |
195 | 203 | int ret = 0; | |
196 | if (!NFS_WBACK_BUSY(req)) | 204 | |
197 | return 0; | 205 | if (!test_bit(PG_BUSY, &req->wb_flags)) |
198 | return nfs_wait_event(clnt, req->wb_context->waitq, !NFS_WBACK_BUSY(req)); | 206 | goto out; |
207 | /* | ||
208 | * Note: the call to rpc_clnt_sigmask() suffices to ensure that we | ||
209 | * are not interrupted if intr flag is not set | ||
210 | */ | ||
211 | rpc_clnt_sigmask(clnt, &oldmask); | ||
212 | ret = out_of_line_wait_on_bit(&req->wb_flags, PG_BUSY, | ||
213 | nfs_wait_bit_interruptible, TASK_INTERRUPTIBLE); | ||
214 | rpc_clnt_sigunmask(clnt, &oldmask); | ||
215 | out: | ||
216 | return ret; | ||
199 | } | 217 | } |
200 | 218 | ||
201 | /** | 219 | /** |
@@ -243,6 +261,62 @@ nfs_coalesce_requests(struct list_head *head, struct list_head *dst, | |||
243 | return npages; | 261 | return npages; |
244 | } | 262 | } |
245 | 263 | ||
264 | #define NFS_SCAN_MAXENTRIES 16 | ||
265 | /** | ||
266 | * nfs_scan_lock_dirty - Scan the radix tree for dirty requests | ||
267 | * @nfsi: NFS inode | ||
268 | * @dst: Destination list | ||
269 | * @idx_start: lower bound of page->index to scan | ||
270 | * @npages: idx_start + npages sets the upper bound to scan. | ||
271 | * | ||
272 | * Moves elements from one of the inode request lists. | ||
273 | * If the number of requests is set to 0, the entire address_space | ||
274 | * starting at index idx_start, is scanned. | ||
275 | * The requests are *not* checked to ensure that they form a contiguous set. | ||
276 | * You must be holding the inode's req_lock when calling this function | ||
277 | */ | ||
278 | int | ||
279 | nfs_scan_lock_dirty(struct nfs_inode *nfsi, struct list_head *dst, | ||
280 | unsigned long idx_start, unsigned int npages) | ||
281 | { | ||
282 | struct nfs_page *pgvec[NFS_SCAN_MAXENTRIES]; | ||
283 | struct nfs_page *req; | ||
284 | unsigned long idx_end; | ||
285 | int found, i; | ||
286 | int res; | ||
287 | |||
288 | res = 0; | ||
289 | if (npages == 0) | ||
290 | idx_end = ~0; | ||
291 | else | ||
292 | idx_end = idx_start + npages - 1; | ||
293 | |||
294 | for (;;) { | ||
295 | found = radix_tree_gang_lookup_tag(&nfsi->nfs_page_tree, | ||
296 | (void **)&pgvec[0], idx_start, NFS_SCAN_MAXENTRIES, | ||
297 | NFS_PAGE_TAG_DIRTY); | ||
298 | if (found <= 0) | ||
299 | break; | ||
300 | for (i = 0; i < found; i++) { | ||
301 | req = pgvec[i]; | ||
302 | if (req->wb_index > idx_end) | ||
303 | goto out; | ||
304 | |||
305 | idx_start = req->wb_index + 1; | ||
306 | |||
307 | if (nfs_set_page_writeback_locked(req)) { | ||
308 | radix_tree_tag_clear(&nfsi->nfs_page_tree, | ||
309 | req->wb_index, NFS_PAGE_TAG_DIRTY); | ||
310 | nfs_list_remove_request(req); | ||
311 | nfs_list_add_request(req, dst); | ||
312 | res++; | ||
313 | } | ||
314 | } | ||
315 | } | ||
316 | out: | ||
317 | return res; | ||
318 | } | ||
319 | |||
246 | /** | 320 | /** |
247 | * nfs_scan_list - Scan a list for matching requests | 321 | * nfs_scan_list - Scan a list for matching requests |
248 | * @head: One of the NFS inode request lists | 322 | * @head: One of the NFS inode request lists |
@@ -280,7 +354,7 @@ nfs_scan_list(struct list_head *head, struct list_head *dst, | |||
280 | if (req->wb_index > idx_end) | 354 | if (req->wb_index > idx_end) |
281 | break; | 355 | break; |
282 | 356 | ||
283 | if (!nfs_lock_request(req)) | 357 | if (!nfs_set_page_writeback_locked(req)) |
284 | continue; | 358 | continue; |
285 | nfs_list_remove_request(req); | 359 | nfs_list_remove_request(req); |
286 | nfs_list_add_request(req, dst); | 360 | nfs_list_add_request(req, dst); |
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index d31b4d6e5a5e..cedf636bcf3c 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c | |||
@@ -622,6 +622,7 @@ struct nfs_rpc_ops nfs_v2_clientops = { | |||
622 | .version = 2, /* protocol version */ | 622 | .version = 2, /* protocol version */ |
623 | .dentry_ops = &nfs_dentry_operations, | 623 | .dentry_ops = &nfs_dentry_operations, |
624 | .dir_inode_ops = &nfs_dir_inode_operations, | 624 | .dir_inode_ops = &nfs_dir_inode_operations, |
625 | .file_inode_ops = &nfs_file_inode_operations, | ||
625 | .getroot = nfs_proc_get_root, | 626 | .getroot = nfs_proc_get_root, |
626 | .getattr = nfs_proc_getattr, | 627 | .getattr = nfs_proc_getattr, |
627 | .setattr = nfs_proc_setattr, | 628 | .setattr = nfs_proc_setattr, |
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index a0042fb58634..6f866b8aa2d5 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c | |||
@@ -173,7 +173,6 @@ static int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode, | |||
173 | if (len < PAGE_CACHE_SIZE) | 173 | if (len < PAGE_CACHE_SIZE) |
174 | memclear_highpage_flush(page, len, PAGE_CACHE_SIZE - len); | 174 | memclear_highpage_flush(page, len, PAGE_CACHE_SIZE - len); |
175 | 175 | ||
176 | nfs_lock_request(new); | ||
177 | nfs_list_add_request(new, &one_request); | 176 | nfs_list_add_request(new, &one_request); |
178 | nfs_pagein_one(&one_request, inode); | 177 | nfs_pagein_one(&one_request, inode); |
179 | return 0; | 178 | return 0; |
@@ -185,7 +184,6 @@ static void nfs_readpage_release(struct nfs_page *req) | |||
185 | 184 | ||
186 | nfs_clear_request(req); | 185 | nfs_clear_request(req); |
187 | nfs_release_request(req); | 186 | nfs_release_request(req); |
188 | nfs_unlock_request(req); | ||
189 | 187 | ||
190 | dprintk("NFS: read done (%s/%Ld %d@%Ld)\n", | 188 | dprintk("NFS: read done (%s/%Ld %d@%Ld)\n", |
191 | req->wb_context->dentry->d_inode->i_sb->s_id, | 189 | req->wb_context->dentry->d_inode->i_sb->s_id, |
@@ -553,7 +551,6 @@ readpage_async_filler(void *data, struct page *page) | |||
553 | } | 551 | } |
554 | if (len < PAGE_CACHE_SIZE) | 552 | if (len < PAGE_CACHE_SIZE) |
555 | memclear_highpage_flush(page, len, PAGE_CACHE_SIZE - len); | 553 | memclear_highpage_flush(page, len, PAGE_CACHE_SIZE - len); |
556 | nfs_lock_request(new); | ||
557 | nfs_list_add_request(new, desc->head); | 554 | nfs_list_add_request(new, desc->head); |
558 | return 0; | 555 | return 0; |
559 | } | 556 | } |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 6f7a4af3bc46..5130eda231d7 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -220,7 +220,7 @@ static int nfs_writepage_sync(struct nfs_open_context *ctx, struct inode *inode, | |||
220 | ClearPageError(page); | 220 | ClearPageError(page); |
221 | 221 | ||
222 | io_error: | 222 | io_error: |
223 | nfs_end_data_update_defer(inode); | 223 | nfs_end_data_update(inode); |
224 | nfs_writedata_free(wdata); | 224 | nfs_writedata_free(wdata); |
225 | return written ? written : result; | 225 | return written ? written : result; |
226 | } | 226 | } |
@@ -352,7 +352,7 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc) | |||
352 | if (err < 0) | 352 | if (err < 0) |
353 | goto out; | 353 | goto out; |
354 | } | 354 | } |
355 | err = nfs_commit_inode(inode, 0, 0, wb_priority(wbc)); | 355 | err = nfs_commit_inode(inode, wb_priority(wbc)); |
356 | if (err > 0) { | 356 | if (err > 0) { |
357 | wbc->nr_to_write -= err; | 357 | wbc->nr_to_write -= err; |
358 | err = 0; | 358 | err = 0; |
@@ -401,7 +401,7 @@ static void nfs_inode_remove_request(struct nfs_page *req) | |||
401 | nfsi->npages--; | 401 | nfsi->npages--; |
402 | if (!nfsi->npages) { | 402 | if (!nfsi->npages) { |
403 | spin_unlock(&nfsi->req_lock); | 403 | spin_unlock(&nfsi->req_lock); |
404 | nfs_end_data_update_defer(inode); | 404 | nfs_end_data_update(inode); |
405 | iput(inode); | 405 | iput(inode); |
406 | } else | 406 | } else |
407 | spin_unlock(&nfsi->req_lock); | 407 | spin_unlock(&nfsi->req_lock); |
@@ -446,6 +446,8 @@ nfs_mark_request_dirty(struct nfs_page *req) | |||
446 | struct nfs_inode *nfsi = NFS_I(inode); | 446 | struct nfs_inode *nfsi = NFS_I(inode); |
447 | 447 | ||
448 | spin_lock(&nfsi->req_lock); | 448 | spin_lock(&nfsi->req_lock); |
449 | radix_tree_tag_set(&nfsi->nfs_page_tree, | ||
450 | req->wb_index, NFS_PAGE_TAG_DIRTY); | ||
449 | nfs_list_add_request(req, &nfsi->dirty); | 451 | nfs_list_add_request(req, &nfsi->dirty); |
450 | nfsi->ndirty++; | 452 | nfsi->ndirty++; |
451 | spin_unlock(&nfsi->req_lock); | 453 | spin_unlock(&nfsi->req_lock); |
@@ -503,13 +505,12 @@ nfs_wait_on_requests(struct inode *inode, unsigned long idx_start, unsigned int | |||
503 | 505 | ||
504 | spin_lock(&nfsi->req_lock); | 506 | spin_lock(&nfsi->req_lock); |
505 | next = idx_start; | 507 | next = idx_start; |
506 | while (radix_tree_gang_lookup(&nfsi->nfs_page_tree, (void **)&req, next, 1)) { | 508 | while (radix_tree_gang_lookup_tag(&nfsi->nfs_page_tree, (void **)&req, next, 1, NFS_PAGE_TAG_WRITEBACK)) { |
507 | if (req->wb_index > idx_end) | 509 | if (req->wb_index > idx_end) |
508 | break; | 510 | break; |
509 | 511 | ||
510 | next = req->wb_index + 1; | 512 | next = req->wb_index + 1; |
511 | if (!NFS_WBACK_BUSY(req)) | 513 | BUG_ON(!NFS_WBACK_BUSY(req)); |
512 | continue; | ||
513 | 514 | ||
514 | atomic_inc(&req->wb_count); | 515 | atomic_inc(&req->wb_count); |
515 | spin_unlock(&nfsi->req_lock); | 516 | spin_unlock(&nfsi->req_lock); |
@@ -538,12 +539,15 @@ static int | |||
538 | nfs_scan_dirty(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages) | 539 | nfs_scan_dirty(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages) |
539 | { | 540 | { |
540 | struct nfs_inode *nfsi = NFS_I(inode); | 541 | struct nfs_inode *nfsi = NFS_I(inode); |
541 | int res; | 542 | int res = 0; |
542 | res = nfs_scan_list(&nfsi->dirty, dst, idx_start, npages); | 543 | |
543 | nfsi->ndirty -= res; | 544 | if (nfsi->ndirty != 0) { |
544 | sub_page_state(nr_dirty,res); | 545 | res = nfs_scan_lock_dirty(nfsi, dst, idx_start, npages); |
545 | if ((nfsi->ndirty == 0) != list_empty(&nfsi->dirty)) | 546 | nfsi->ndirty -= res; |
546 | printk(KERN_ERR "NFS: desynchronized value of nfs_i.ndirty.\n"); | 547 | sub_page_state(nr_dirty,res); |
548 | if ((nfsi->ndirty == 0) != list_empty(&nfsi->dirty)) | ||
549 | printk(KERN_ERR "NFS: desynchronized value of nfs_i.ndirty.\n"); | ||
550 | } | ||
547 | return res; | 551 | return res; |
548 | } | 552 | } |
549 | 553 | ||
@@ -562,11 +566,14 @@ static int | |||
562 | nfs_scan_commit(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages) | 566 | nfs_scan_commit(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages) |
563 | { | 567 | { |
564 | struct nfs_inode *nfsi = NFS_I(inode); | 568 | struct nfs_inode *nfsi = NFS_I(inode); |
565 | int res; | 569 | int res = 0; |
566 | res = nfs_scan_list(&nfsi->commit, dst, idx_start, npages); | 570 | |
567 | nfsi->ncommit -= res; | 571 | if (nfsi->ncommit != 0) { |
568 | if ((nfsi->ncommit == 0) != list_empty(&nfsi->commit)) | 572 | res = nfs_scan_list(&nfsi->commit, dst, idx_start, npages); |
569 | printk(KERN_ERR "NFS: desynchronized value of nfs_i.ncommit.\n"); | 573 | nfsi->ncommit -= res; |
574 | if ((nfsi->ncommit == 0) != list_empty(&nfsi->commit)) | ||
575 | printk(KERN_ERR "NFS: desynchronized value of nfs_i.ncommit.\n"); | ||
576 | } | ||
570 | return res; | 577 | return res; |
571 | } | 578 | } |
572 | #endif | 579 | #endif |
@@ -750,7 +757,7 @@ int nfs_updatepage(struct file *file, struct page *page, | |||
750 | * is entirely in cache, it may be more efficient to avoid | 757 | * is entirely in cache, it may be more efficient to avoid |
751 | * fragmenting write requests. | 758 | * fragmenting write requests. |
752 | */ | 759 | */ |
753 | if (PageUptodate(page) && inode->i_flock == NULL) { | 760 | if (PageUptodate(page) && inode->i_flock == NULL && !(file->f_mode & O_SYNC)) { |
754 | loff_t end_offs = i_size_read(inode) - 1; | 761 | loff_t end_offs = i_size_read(inode) - 1; |
755 | unsigned long end_index = end_offs >> PAGE_CACHE_SHIFT; | 762 | unsigned long end_index = end_offs >> PAGE_CACHE_SHIFT; |
756 | 763 | ||
@@ -821,7 +828,7 @@ out: | |||
821 | #else | 828 | #else |
822 | nfs_inode_remove_request(req); | 829 | nfs_inode_remove_request(req); |
823 | #endif | 830 | #endif |
824 | nfs_unlock_request(req); | 831 | nfs_clear_page_writeback(req); |
825 | } | 832 | } |
826 | 833 | ||
827 | static inline int flush_task_priority(int how) | 834 | static inline int flush_task_priority(int how) |
@@ -952,7 +959,7 @@ out_bad: | |||
952 | nfs_writedata_free(data); | 959 | nfs_writedata_free(data); |
953 | } | 960 | } |
954 | nfs_mark_request_dirty(req); | 961 | nfs_mark_request_dirty(req); |
955 | nfs_unlock_request(req); | 962 | nfs_clear_page_writeback(req); |
956 | return -ENOMEM; | 963 | return -ENOMEM; |
957 | } | 964 | } |
958 | 965 | ||
@@ -1002,7 +1009,7 @@ static int nfs_flush_one(struct list_head *head, struct inode *inode, int how) | |||
1002 | struct nfs_page *req = nfs_list_entry(head->next); | 1009 | struct nfs_page *req = nfs_list_entry(head->next); |
1003 | nfs_list_remove_request(req); | 1010 | nfs_list_remove_request(req); |
1004 | nfs_mark_request_dirty(req); | 1011 | nfs_mark_request_dirty(req); |
1005 | nfs_unlock_request(req); | 1012 | nfs_clear_page_writeback(req); |
1006 | } | 1013 | } |
1007 | return -ENOMEM; | 1014 | return -ENOMEM; |
1008 | } | 1015 | } |
@@ -1029,7 +1036,7 @@ nfs_flush_list(struct list_head *head, int wpages, int how) | |||
1029 | req = nfs_list_entry(head->next); | 1036 | req = nfs_list_entry(head->next); |
1030 | nfs_list_remove_request(req); | 1037 | nfs_list_remove_request(req); |
1031 | nfs_mark_request_dirty(req); | 1038 | nfs_mark_request_dirty(req); |
1032 | nfs_unlock_request(req); | 1039 | nfs_clear_page_writeback(req); |
1033 | } | 1040 | } |
1034 | return error; | 1041 | return error; |
1035 | } | 1042 | } |
@@ -1121,7 +1128,7 @@ static void nfs_writeback_done_full(struct nfs_write_data *data, int status) | |||
1121 | nfs_inode_remove_request(req); | 1128 | nfs_inode_remove_request(req); |
1122 | #endif | 1129 | #endif |
1123 | next: | 1130 | next: |
1124 | nfs_unlock_request(req); | 1131 | nfs_clear_page_writeback(req); |
1125 | } | 1132 | } |
1126 | } | 1133 | } |
1127 | 1134 | ||
@@ -1210,36 +1217,24 @@ static void nfs_commit_rpcsetup(struct list_head *head, | |||
1210 | struct nfs_write_data *data, int how) | 1217 | struct nfs_write_data *data, int how) |
1211 | { | 1218 | { |
1212 | struct rpc_task *task = &data->task; | 1219 | struct rpc_task *task = &data->task; |
1213 | struct nfs_page *first, *last; | 1220 | struct nfs_page *first; |
1214 | struct inode *inode; | 1221 | struct inode *inode; |
1215 | loff_t start, end, len; | ||
1216 | 1222 | ||
1217 | /* Set up the RPC argument and reply structs | 1223 | /* Set up the RPC argument and reply structs |
1218 | * NB: take care not to mess about with data->commit et al. */ | 1224 | * NB: take care not to mess about with data->commit et al. */ |
1219 | 1225 | ||
1220 | list_splice_init(head, &data->pages); | 1226 | list_splice_init(head, &data->pages); |
1221 | first = nfs_list_entry(data->pages.next); | 1227 | first = nfs_list_entry(data->pages.next); |
1222 | last = nfs_list_entry(data->pages.prev); | ||
1223 | inode = first->wb_context->dentry->d_inode; | 1228 | inode = first->wb_context->dentry->d_inode; |
1224 | 1229 | ||
1225 | /* | ||
1226 | * Determine the offset range of requests in the COMMIT call. | ||
1227 | * We rely on the fact that data->pages is an ordered list... | ||
1228 | */ | ||
1229 | start = req_offset(first); | ||
1230 | end = req_offset(last) + last->wb_bytes; | ||
1231 | len = end - start; | ||
1232 | /* If 'len' is not a 32-bit quantity, pass '0' in the COMMIT call */ | ||
1233 | if (end >= i_size_read(inode) || len < 0 || len > (~((u32)0) >> 1)) | ||
1234 | len = 0; | ||
1235 | |||
1236 | data->inode = inode; | 1230 | data->inode = inode; |
1237 | data->cred = first->wb_context->cred; | 1231 | data->cred = first->wb_context->cred; |
1238 | 1232 | ||
1239 | data->args.fh = NFS_FH(data->inode); | 1233 | data->args.fh = NFS_FH(data->inode); |
1240 | data->args.offset = start; | 1234 | /* Note: we always request a commit of the entire inode */ |
1241 | data->args.count = len; | 1235 | data->args.offset = 0; |
1242 | data->res.count = len; | 1236 | data->args.count = 0; |
1237 | data->res.count = 0; | ||
1243 | data->res.fattr = &data->fattr; | 1238 | data->res.fattr = &data->fattr; |
1244 | data->res.verf = &data->verf; | 1239 | data->res.verf = &data->verf; |
1245 | 1240 | ||
@@ -1278,7 +1273,7 @@ nfs_commit_list(struct list_head *head, int how) | |||
1278 | req = nfs_list_entry(head->next); | 1273 | req = nfs_list_entry(head->next); |
1279 | nfs_list_remove_request(req); | 1274 | nfs_list_remove_request(req); |
1280 | nfs_mark_request_commit(req); | 1275 | nfs_mark_request_commit(req); |
1281 | nfs_unlock_request(req); | 1276 | nfs_clear_page_writeback(req); |
1282 | } | 1277 | } |
1283 | return -ENOMEM; | 1278 | return -ENOMEM; |
1284 | } | 1279 | } |
@@ -1324,7 +1319,7 @@ nfs_commit_done(struct rpc_task *task) | |||
1324 | dprintk(" mismatch\n"); | 1319 | dprintk(" mismatch\n"); |
1325 | nfs_mark_request_dirty(req); | 1320 | nfs_mark_request_dirty(req); |
1326 | next: | 1321 | next: |
1327 | nfs_unlock_request(req); | 1322 | nfs_clear_page_writeback(req); |
1328 | res++; | 1323 | res++; |
1329 | } | 1324 | } |
1330 | sub_page_state(nr_unstable,res); | 1325 | sub_page_state(nr_unstable,res); |
@@ -1342,16 +1337,23 @@ static int nfs_flush_inode(struct inode *inode, unsigned long idx_start, | |||
1342 | spin_lock(&nfsi->req_lock); | 1337 | spin_lock(&nfsi->req_lock); |
1343 | res = nfs_scan_dirty(inode, &head, idx_start, npages); | 1338 | res = nfs_scan_dirty(inode, &head, idx_start, npages); |
1344 | spin_unlock(&nfsi->req_lock); | 1339 | spin_unlock(&nfsi->req_lock); |
1345 | if (res) | 1340 | if (res) { |
1346 | error = nfs_flush_list(&head, NFS_SERVER(inode)->wpages, how); | 1341 | struct nfs_server *server = NFS_SERVER(inode); |
1342 | |||
1343 | /* For single writes, FLUSH_STABLE is more efficient */ | ||
1344 | if (res == nfsi->npages && nfsi->npages <= server->wpages) { | ||
1345 | if (res > 1 || nfs_list_entry(head.next)->wb_bytes <= server->wsize) | ||
1346 | how |= FLUSH_STABLE; | ||
1347 | } | ||
1348 | error = nfs_flush_list(&head, server->wpages, how); | ||
1349 | } | ||
1347 | if (error < 0) | 1350 | if (error < 0) |
1348 | return error; | 1351 | return error; |
1349 | return res; | 1352 | return res; |
1350 | } | 1353 | } |
1351 | 1354 | ||
1352 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 1355 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
1353 | int nfs_commit_inode(struct inode *inode, unsigned long idx_start, | 1356 | int nfs_commit_inode(struct inode *inode, int how) |
1354 | unsigned int npages, int how) | ||
1355 | { | 1357 | { |
1356 | struct nfs_inode *nfsi = NFS_I(inode); | 1358 | struct nfs_inode *nfsi = NFS_I(inode); |
1357 | LIST_HEAD(head); | 1359 | LIST_HEAD(head); |
@@ -1359,15 +1361,13 @@ int nfs_commit_inode(struct inode *inode, unsigned long idx_start, | |||
1359 | error = 0; | 1361 | error = 0; |
1360 | 1362 | ||
1361 | spin_lock(&nfsi->req_lock); | 1363 | spin_lock(&nfsi->req_lock); |
1362 | res = nfs_scan_commit(inode, &head, idx_start, npages); | 1364 | res = nfs_scan_commit(inode, &head, 0, 0); |
1365 | spin_unlock(&nfsi->req_lock); | ||
1363 | if (res) { | 1366 | if (res) { |
1364 | res += nfs_scan_commit(inode, &head, 0, 0); | ||
1365 | spin_unlock(&nfsi->req_lock); | ||
1366 | error = nfs_commit_list(&head, how); | 1367 | error = nfs_commit_list(&head, how); |
1367 | } else | 1368 | if (error < 0) |
1368 | spin_unlock(&nfsi->req_lock); | 1369 | return error; |
1369 | if (error < 0) | 1370 | } |
1370 | return error; | ||
1371 | return res; | 1371 | return res; |
1372 | } | 1372 | } |
1373 | #endif | 1373 | #endif |
@@ -1389,7 +1389,7 @@ int nfs_sync_inode(struct inode *inode, unsigned long idx_start, | |||
1389 | error = nfs_flush_inode(inode, idx_start, npages, how); | 1389 | error = nfs_flush_inode(inode, idx_start, npages, how); |
1390 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 1390 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
1391 | if (error == 0) | 1391 | if (error == 0) |
1392 | error = nfs_commit_inode(inode, idx_start, npages, how); | 1392 | error = nfs_commit_inode(inode, how); |
1393 | #endif | 1393 | #endif |
1394 | } while (error > 0); | 1394 | } while (error > 0); |
1395 | return error; | 1395 | return error; |
diff --git a/fs/nfs_common/Makefile b/fs/nfs_common/Makefile new file mode 100644 index 000000000000..f689ed82af3a --- /dev/null +++ b/fs/nfs_common/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | # | ||
2 | # Makefile for Linux filesystem routines that are shared by client and server. | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_NFS_ACL_SUPPORT) += nfs_acl.o | ||
6 | |||
7 | nfs_acl-objs := nfsacl.o | ||
diff --git a/fs/nfs_common/nfsacl.c b/fs/nfs_common/nfsacl.c new file mode 100644 index 000000000000..18c58c32e326 --- /dev/null +++ b/fs/nfs_common/nfsacl.c | |||
@@ -0,0 +1,257 @@ | |||
1 | /* | ||
2 | * fs/nfs_common/nfsacl.c | ||
3 | * | ||
4 | * Copyright (C) 2002-2003 Andreas Gruenbacher <agruen@suse.de> | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * The Solaris nfsacl protocol represents some ACLs slightly differently | ||
9 | * than POSIX 1003.1e draft 17 does (and we do): | ||
10 | * | ||
11 | * - Minimal ACLs always have an ACL_MASK entry, so they have | ||
12 | * four instead of three entries. | ||
13 | * - The ACL_MASK entry in such minimal ACLs always has the same | ||
14 | * permissions as the ACL_GROUP_OBJ entry. (In extended ACLs | ||
15 | * the ACL_MASK and ACL_GROUP_OBJ entries may differ.) | ||
16 | * - The identifier fields of the ACL_USER_OBJ and ACL_GROUP_OBJ | ||
17 | * entries contain the identifiers of the owner and owning group. | ||
18 | * (In POSIX ACLs we always set them to ACL_UNDEFINED_ID). | ||
19 | * - ACL entries in the kernel are kept sorted in ascending order | ||
20 | * of (e_tag, e_id). Solaris ACLs are unsorted. | ||
21 | */ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/fs.h> | ||
25 | #include <linux/sunrpc/xdr.h> | ||
26 | #include <linux/nfsacl.h> | ||
27 | #include <linux/nfs3.h> | ||
28 | #include <linux/sort.h> | ||
29 | |||
30 | MODULE_LICENSE("GPL"); | ||
31 | |||
32 | EXPORT_SYMBOL(nfsacl_encode); | ||
33 | EXPORT_SYMBOL(nfsacl_decode); | ||
34 | |||
35 | struct nfsacl_encode_desc { | ||
36 | struct xdr_array2_desc desc; | ||
37 | unsigned int count; | ||
38 | struct posix_acl *acl; | ||
39 | int typeflag; | ||
40 | uid_t uid; | ||
41 | gid_t gid; | ||
42 | }; | ||
43 | |||
44 | static int | ||
45 | xdr_nfsace_encode(struct xdr_array2_desc *desc, void *elem) | ||
46 | { | ||
47 | struct nfsacl_encode_desc *nfsacl_desc = | ||
48 | (struct nfsacl_encode_desc *) desc; | ||
49 | u32 *p = (u32 *) elem; | ||
50 | |||
51 | if (nfsacl_desc->count < nfsacl_desc->acl->a_count) { | ||
52 | struct posix_acl_entry *entry = | ||
53 | &nfsacl_desc->acl->a_entries[nfsacl_desc->count++]; | ||
54 | |||
55 | *p++ = htonl(entry->e_tag | nfsacl_desc->typeflag); | ||
56 | switch(entry->e_tag) { | ||
57 | case ACL_USER_OBJ: | ||
58 | *p++ = htonl(nfsacl_desc->uid); | ||
59 | break; | ||
60 | case ACL_GROUP_OBJ: | ||
61 | *p++ = htonl(nfsacl_desc->gid); | ||
62 | break; | ||
63 | case ACL_USER: | ||
64 | case ACL_GROUP: | ||
65 | *p++ = htonl(entry->e_id); | ||
66 | break; | ||
67 | default: /* Solaris depends on that! */ | ||
68 | *p++ = 0; | ||
69 | break; | ||
70 | } | ||
71 | *p++ = htonl(entry->e_perm & S_IRWXO); | ||
72 | } else { | ||
73 | const struct posix_acl_entry *pa, *pe; | ||
74 | int group_obj_perm = ACL_READ|ACL_WRITE|ACL_EXECUTE; | ||
75 | |||
76 | FOREACH_ACL_ENTRY(pa, nfsacl_desc->acl, pe) { | ||
77 | if (pa->e_tag == ACL_GROUP_OBJ) { | ||
78 | group_obj_perm = pa->e_perm & S_IRWXO; | ||
79 | break; | ||
80 | } | ||
81 | } | ||
82 | /* fake up ACL_MASK entry */ | ||
83 | *p++ = htonl(ACL_MASK | nfsacl_desc->typeflag); | ||
84 | *p++ = htonl(0); | ||
85 | *p++ = htonl(group_obj_perm); | ||
86 | } | ||
87 | |||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | unsigned int | ||
92 | nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode, | ||
93 | struct posix_acl *acl, int encode_entries, int typeflag) | ||
94 | { | ||
95 | int entries = (acl && acl->a_count) ? max_t(int, acl->a_count, 4) : 0; | ||
96 | struct nfsacl_encode_desc nfsacl_desc = { | ||
97 | .desc = { | ||
98 | .elem_size = 12, | ||
99 | .array_len = encode_entries ? entries : 0, | ||
100 | .xcode = xdr_nfsace_encode, | ||
101 | }, | ||
102 | .acl = acl, | ||
103 | .typeflag = typeflag, | ||
104 | .uid = inode->i_uid, | ||
105 | .gid = inode->i_gid, | ||
106 | }; | ||
107 | int err; | ||
108 | |||
109 | if (entries > NFS_ACL_MAX_ENTRIES || | ||
110 | xdr_encode_word(buf, base, entries)) | ||
111 | return -EINVAL; | ||
112 | err = xdr_encode_array2(buf, base + 4, &nfsacl_desc.desc); | ||
113 | if (!err) | ||
114 | err = 8 + nfsacl_desc.desc.elem_size * | ||
115 | nfsacl_desc.desc.array_len; | ||
116 | return err; | ||
117 | } | ||
118 | |||
119 | struct nfsacl_decode_desc { | ||
120 | struct xdr_array2_desc desc; | ||
121 | unsigned int count; | ||
122 | struct posix_acl *acl; | ||
123 | }; | ||
124 | |||
125 | static int | ||
126 | xdr_nfsace_decode(struct xdr_array2_desc *desc, void *elem) | ||
127 | { | ||
128 | struct nfsacl_decode_desc *nfsacl_desc = | ||
129 | (struct nfsacl_decode_desc *) desc; | ||
130 | u32 *p = (u32 *) elem; | ||
131 | struct posix_acl_entry *entry; | ||
132 | |||
133 | if (!nfsacl_desc->acl) { | ||
134 | if (desc->array_len > NFS_ACL_MAX_ENTRIES) | ||
135 | return -EINVAL; | ||
136 | nfsacl_desc->acl = posix_acl_alloc(desc->array_len, GFP_KERNEL); | ||
137 | if (!nfsacl_desc->acl) | ||
138 | return -ENOMEM; | ||
139 | nfsacl_desc->count = 0; | ||
140 | } | ||
141 | |||
142 | entry = &nfsacl_desc->acl->a_entries[nfsacl_desc->count++]; | ||
143 | entry->e_tag = ntohl(*p++) & ~NFS_ACL_DEFAULT; | ||
144 | entry->e_id = ntohl(*p++); | ||
145 | entry->e_perm = ntohl(*p++); | ||
146 | |||
147 | switch(entry->e_tag) { | ||
148 | case ACL_USER_OBJ: | ||
149 | case ACL_USER: | ||
150 | case ACL_GROUP_OBJ: | ||
151 | case ACL_GROUP: | ||
152 | case ACL_OTHER: | ||
153 | if (entry->e_perm & ~S_IRWXO) | ||
154 | return -EINVAL; | ||
155 | break; | ||
156 | case ACL_MASK: | ||
157 | /* Solaris sometimes sets additonal bits in the mask */ | ||
158 | entry->e_perm &= S_IRWXO; | ||
159 | break; | ||
160 | default: | ||
161 | return -EINVAL; | ||
162 | } | ||
163 | |||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | static int | ||
168 | cmp_acl_entry(const void *x, const void *y) | ||
169 | { | ||
170 | const struct posix_acl_entry *a = x, *b = y; | ||
171 | |||
172 | if (a->e_tag != b->e_tag) | ||
173 | return a->e_tag - b->e_tag; | ||
174 | else if (a->e_id > b->e_id) | ||
175 | return 1; | ||
176 | else if (a->e_id < b->e_id) | ||
177 | return -1; | ||
178 | else | ||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | /* | ||
183 | * Convert from a Solaris ACL to a POSIX 1003.1e draft 17 ACL. | ||
184 | */ | ||
185 | static int | ||
186 | posix_acl_from_nfsacl(struct posix_acl *acl) | ||
187 | { | ||
188 | struct posix_acl_entry *pa, *pe, | ||
189 | *group_obj = NULL, *mask = NULL; | ||
190 | |||
191 | if (!acl) | ||
192 | return 0; | ||
193 | |||
194 | sort(acl->a_entries, acl->a_count, sizeof(struct posix_acl_entry), | ||
195 | cmp_acl_entry, NULL); | ||
196 | |||
197 | /* Clear undefined identifier fields and find the ACL_GROUP_OBJ | ||
198 | and ACL_MASK entries. */ | ||
199 | FOREACH_ACL_ENTRY(pa, acl, pe) { | ||
200 | switch(pa->e_tag) { | ||
201 | case ACL_USER_OBJ: | ||
202 | pa->e_id = ACL_UNDEFINED_ID; | ||
203 | break; | ||
204 | case ACL_GROUP_OBJ: | ||
205 | pa->e_id = ACL_UNDEFINED_ID; | ||
206 | group_obj = pa; | ||
207 | break; | ||
208 | case ACL_MASK: | ||
209 | mask = pa; | ||
210 | /* fall through */ | ||
211 | case ACL_OTHER: | ||
212 | pa->e_id = ACL_UNDEFINED_ID; | ||
213 | break; | ||
214 | } | ||
215 | } | ||
216 | if (acl->a_count == 4 && group_obj && mask && | ||
217 | mask->e_perm == group_obj->e_perm) { | ||
218 | /* remove bogus ACL_MASK entry */ | ||
219 | memmove(mask, mask+1, (3 - (mask - acl->a_entries)) * | ||
220 | sizeof(struct posix_acl_entry)); | ||
221 | acl->a_count = 3; | ||
222 | } | ||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | unsigned int | ||
227 | nfsacl_decode(struct xdr_buf *buf, unsigned int base, unsigned int *aclcnt, | ||
228 | struct posix_acl **pacl) | ||
229 | { | ||
230 | struct nfsacl_decode_desc nfsacl_desc = { | ||
231 | .desc = { | ||
232 | .elem_size = 12, | ||
233 | .xcode = pacl ? xdr_nfsace_decode : NULL, | ||
234 | }, | ||
235 | }; | ||
236 | u32 entries; | ||
237 | int err; | ||
238 | |||
239 | if (xdr_decode_word(buf, base, &entries) || | ||
240 | entries > NFS_ACL_MAX_ENTRIES) | ||
241 | return -EINVAL; | ||
242 | err = xdr_decode_array2(buf, base + 4, &nfsacl_desc.desc); | ||
243 | if (err) | ||
244 | return err; | ||
245 | if (pacl) { | ||
246 | if (entries != nfsacl_desc.desc.array_len || | ||
247 | posix_acl_from_nfsacl(nfsacl_desc.acl) != 0) { | ||
248 | posix_acl_release(nfsacl_desc.acl); | ||
249 | return -EINVAL; | ||
250 | } | ||
251 | *pacl = nfsacl_desc.acl; | ||
252 | } | ||
253 | if (aclcnt) | ||
254 | *aclcnt = entries; | ||
255 | return 8 + nfsacl_desc.desc.elem_size * | ||
256 | nfsacl_desc.desc.array_len; | ||
257 | } | ||
diff --git a/fs/nfsd/Makefile b/fs/nfsd/Makefile index b8680a247f8b..9f043f44c92f 100644 --- a/fs/nfsd/Makefile +++ b/fs/nfsd/Makefile | |||
@@ -6,7 +6,9 @@ obj-$(CONFIG_NFSD) += nfsd.o | |||
6 | 6 | ||
7 | nfsd-y := nfssvc.o nfsctl.o nfsproc.o nfsfh.o vfs.o \ | 7 | nfsd-y := nfssvc.o nfsctl.o nfsproc.o nfsfh.o vfs.o \ |
8 | export.o auth.o lockd.o nfscache.o nfsxdr.o stats.o | 8 | export.o auth.o lockd.o nfscache.o nfsxdr.o stats.o |
9 | nfsd-$(CONFIG_NFSD_V2_ACL) += nfs2acl.o | ||
9 | nfsd-$(CONFIG_NFSD_V3) += nfs3proc.o nfs3xdr.o | 10 | nfsd-$(CONFIG_NFSD_V3) += nfs3proc.o nfs3xdr.o |
11 | nfsd-$(CONFIG_NFSD_V3_ACL) += nfs3acl.o | ||
10 | nfsd-$(CONFIG_NFSD_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4idmap.o \ | 12 | nfsd-$(CONFIG_NFSD_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4idmap.o \ |
11 | nfs4acl.o nfs4callback.o | 13 | nfs4acl.o nfs4callback.o |
12 | nfsd-objs := $(nfsd-y) | 14 | nfsd-objs := $(nfsd-y) |
diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c new file mode 100644 index 000000000000..7cbf0682b2f0 --- /dev/null +++ b/fs/nfsd/nfs2acl.c | |||
@@ -0,0 +1,336 @@ | |||
1 | /* | ||
2 | * linux/fs/nfsd/nfsacl.c | ||
3 | * | ||
4 | * Process version 2 NFSACL requests. | ||
5 | * | ||
6 | * Copyright (C) 2002-2003 Andreas Gruenbacher <agruen@suse.de> | ||
7 | */ | ||
8 | |||
9 | #include <linux/sunrpc/svc.h> | ||
10 | #include <linux/nfs.h> | ||
11 | #include <linux/nfsd/nfsd.h> | ||
12 | #include <linux/nfsd/cache.h> | ||
13 | #include <linux/nfsd/xdr.h> | ||
14 | #include <linux/nfsd/xdr3.h> | ||
15 | #include <linux/posix_acl.h> | ||
16 | #include <linux/nfsacl.h> | ||
17 | |||
18 | #define NFSDDBG_FACILITY NFSDDBG_PROC | ||
19 | #define RETURN_STATUS(st) { resp->status = (st); return (st); } | ||
20 | |||
21 | /* | ||
22 | * NULL call. | ||
23 | */ | ||
24 | static int | ||
25 | nfsacld_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) | ||
26 | { | ||
27 | return nfs_ok; | ||
28 | } | ||
29 | |||
30 | /* | ||
31 | * Get the Access and/or Default ACL of a file. | ||
32 | */ | ||
33 | static int nfsacld_proc_getacl(struct svc_rqst * rqstp, | ||
34 | struct nfsd3_getaclargs *argp, struct nfsd3_getaclres *resp) | ||
35 | { | ||
36 | svc_fh *fh; | ||
37 | struct posix_acl *acl; | ||
38 | int nfserr = 0; | ||
39 | |||
40 | dprintk("nfsd: GETACL(2acl) %s\n", SVCFH_fmt(&argp->fh)); | ||
41 | |||
42 | fh = fh_copy(&resp->fh, &argp->fh); | ||
43 | if ((nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP))) | ||
44 | RETURN_STATUS(nfserr_inval); | ||
45 | |||
46 | if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) | ||
47 | RETURN_STATUS(nfserr_inval); | ||
48 | resp->mask = argp->mask; | ||
49 | |||
50 | if (resp->mask & (NFS_ACL|NFS_ACLCNT)) { | ||
51 | acl = nfsd_get_posix_acl(fh, ACL_TYPE_ACCESS); | ||
52 | if (IS_ERR(acl)) { | ||
53 | int err = PTR_ERR(acl); | ||
54 | |||
55 | if (err == -ENODATA || err == -EOPNOTSUPP) | ||
56 | acl = NULL; | ||
57 | else { | ||
58 | nfserr = nfserrno(err); | ||
59 | goto fail; | ||
60 | } | ||
61 | } | ||
62 | if (acl == NULL) { | ||
63 | /* Solaris returns the inode's minimum ACL. */ | ||
64 | |||
65 | struct inode *inode = fh->fh_dentry->d_inode; | ||
66 | acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); | ||
67 | } | ||
68 | resp->acl_access = acl; | ||
69 | } | ||
70 | if (resp->mask & (NFS_DFACL|NFS_DFACLCNT)) { | ||
71 | /* Check how Solaris handles requests for the Default ACL | ||
72 | of a non-directory! */ | ||
73 | |||
74 | acl = nfsd_get_posix_acl(fh, ACL_TYPE_DEFAULT); | ||
75 | if (IS_ERR(acl)) { | ||
76 | int err = PTR_ERR(acl); | ||
77 | |||
78 | if (err == -ENODATA || err == -EOPNOTSUPP) | ||
79 | acl = NULL; | ||
80 | else { | ||
81 | nfserr = nfserrno(err); | ||
82 | goto fail; | ||
83 | } | ||
84 | } | ||
85 | resp->acl_default = acl; | ||
86 | } | ||
87 | |||
88 | /* resp->acl_{access,default} are released in nfssvc_release_getacl. */ | ||
89 | RETURN_STATUS(0); | ||
90 | |||
91 | fail: | ||
92 | posix_acl_release(resp->acl_access); | ||
93 | posix_acl_release(resp->acl_default); | ||
94 | RETURN_STATUS(nfserr); | ||
95 | } | ||
96 | |||
97 | /* | ||
98 | * Set the Access and/or Default ACL of a file. | ||
99 | */ | ||
100 | static int nfsacld_proc_setacl(struct svc_rqst * rqstp, | ||
101 | struct nfsd3_setaclargs *argp, | ||
102 | struct nfsd_attrstat *resp) | ||
103 | { | ||
104 | svc_fh *fh; | ||
105 | int nfserr = 0; | ||
106 | |||
107 | dprintk("nfsd: SETACL(2acl) %s\n", SVCFH_fmt(&argp->fh)); | ||
108 | |||
109 | fh = fh_copy(&resp->fh, &argp->fh); | ||
110 | nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP); | ||
111 | |||
112 | if (!nfserr) { | ||
113 | nfserr = nfserrno( nfsd_set_posix_acl( | ||
114 | fh, ACL_TYPE_ACCESS, argp->acl_access) ); | ||
115 | } | ||
116 | if (!nfserr) { | ||
117 | nfserr = nfserrno( nfsd_set_posix_acl( | ||
118 | fh, ACL_TYPE_DEFAULT, argp->acl_default) ); | ||
119 | } | ||
120 | |||
121 | /* argp->acl_{access,default} may have been allocated in | ||
122 | nfssvc_decode_setaclargs. */ | ||
123 | posix_acl_release(argp->acl_access); | ||
124 | posix_acl_release(argp->acl_default); | ||
125 | return nfserr; | ||
126 | } | ||
127 | |||
128 | /* | ||
129 | * Check file attributes | ||
130 | */ | ||
131 | static int nfsacld_proc_getattr(struct svc_rqst * rqstp, | ||
132 | struct nfsd_fhandle *argp, struct nfsd_attrstat *resp) | ||
133 | { | ||
134 | dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh)); | ||
135 | |||
136 | fh_copy(&resp->fh, &argp->fh); | ||
137 | return fh_verify(rqstp, &resp->fh, 0, MAY_NOP); | ||
138 | } | ||
139 | |||
140 | /* | ||
141 | * Check file access | ||
142 | */ | ||
143 | static int nfsacld_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp, | ||
144 | struct nfsd3_accessres *resp) | ||
145 | { | ||
146 | int nfserr; | ||
147 | |||
148 | dprintk("nfsd: ACCESS(2acl) %s 0x%x\n", | ||
149 | SVCFH_fmt(&argp->fh), | ||
150 | argp->access); | ||
151 | |||
152 | fh_copy(&resp->fh, &argp->fh); | ||
153 | resp->access = argp->access; | ||
154 | nfserr = nfsd_access(rqstp, &resp->fh, &resp->access, NULL); | ||
155 | return nfserr; | ||
156 | } | ||
157 | |||
158 | /* | ||
159 | * XDR decode functions | ||
160 | */ | ||
161 | static int nfsaclsvc_decode_getaclargs(struct svc_rqst *rqstp, u32 *p, | ||
162 | struct nfsd3_getaclargs *argp) | ||
163 | { | ||
164 | if (!(p = nfs2svc_decode_fh(p, &argp->fh))) | ||
165 | return 0; | ||
166 | argp->mask = ntohl(*p); p++; | ||
167 | |||
168 | return xdr_argsize_check(rqstp, p); | ||
169 | } | ||
170 | |||
171 | |||
172 | static int nfsaclsvc_decode_setaclargs(struct svc_rqst *rqstp, u32 *p, | ||
173 | struct nfsd3_setaclargs *argp) | ||
174 | { | ||
175 | struct kvec *head = rqstp->rq_arg.head; | ||
176 | unsigned int base; | ||
177 | int n; | ||
178 | |||
179 | if (!(p = nfs2svc_decode_fh(p, &argp->fh))) | ||
180 | return 0; | ||
181 | argp->mask = ntohl(*p++); | ||
182 | if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT) || | ||
183 | !xdr_argsize_check(rqstp, p)) | ||
184 | return 0; | ||
185 | |||
186 | base = (char *)p - (char *)head->iov_base; | ||
187 | n = nfsacl_decode(&rqstp->rq_arg, base, NULL, | ||
188 | (argp->mask & NFS_ACL) ? | ||
189 | &argp->acl_access : NULL); | ||
190 | if (n > 0) | ||
191 | n = nfsacl_decode(&rqstp->rq_arg, base + n, NULL, | ||
192 | (argp->mask & NFS_DFACL) ? | ||
193 | &argp->acl_default : NULL); | ||
194 | return (n > 0); | ||
195 | } | ||
196 | |||
197 | static int nfsaclsvc_decode_fhandleargs(struct svc_rqst *rqstp, u32 *p, | ||
198 | struct nfsd_fhandle *argp) | ||
199 | { | ||
200 | if (!(p = nfs2svc_decode_fh(p, &argp->fh))) | ||
201 | return 0; | ||
202 | return xdr_argsize_check(rqstp, p); | ||
203 | } | ||
204 | |||
205 | static int nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, u32 *p, | ||
206 | struct nfsd3_accessargs *argp) | ||
207 | { | ||
208 | if (!(p = nfs2svc_decode_fh(p, &argp->fh))) | ||
209 | return 0; | ||
210 | argp->access = ntohl(*p++); | ||
211 | |||
212 | return xdr_argsize_check(rqstp, p); | ||
213 | } | ||
214 | |||
215 | /* | ||
216 | * XDR encode functions | ||
217 | */ | ||
218 | |||
219 | /* GETACL */ | ||
220 | static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, u32 *p, | ||
221 | struct nfsd3_getaclres *resp) | ||
222 | { | ||
223 | struct dentry *dentry = resp->fh.fh_dentry; | ||
224 | struct inode *inode = dentry->d_inode; | ||
225 | int w = nfsacl_size( | ||
226 | (resp->mask & NFS_ACL) ? resp->acl_access : NULL, | ||
227 | (resp->mask & NFS_DFACL) ? resp->acl_default : NULL); | ||
228 | struct kvec *head = rqstp->rq_res.head; | ||
229 | unsigned int base; | ||
230 | int n; | ||
231 | |||
232 | if (dentry == NULL || dentry->d_inode == NULL) | ||
233 | return 0; | ||
234 | inode = dentry->d_inode; | ||
235 | |||
236 | p = nfs2svc_encode_fattr(rqstp, p, &resp->fh); | ||
237 | *p++ = htonl(resp->mask); | ||
238 | if (!xdr_ressize_check(rqstp, p)) | ||
239 | return 0; | ||
240 | base = (char *)p - (char *)head->iov_base; | ||
241 | |||
242 | rqstp->rq_res.page_len = w; | ||
243 | while (w > 0) { | ||
244 | if (!svc_take_res_page(rqstp)) | ||
245 | return 0; | ||
246 | w -= PAGE_SIZE; | ||
247 | } | ||
248 | |||
249 | n = nfsacl_encode(&rqstp->rq_res, base, inode, | ||
250 | resp->acl_access, | ||
251 | resp->mask & NFS_ACL, 0); | ||
252 | if (n > 0) | ||
253 | n = nfsacl_encode(&rqstp->rq_res, base + n, inode, | ||
254 | resp->acl_default, | ||
255 | resp->mask & NFS_DFACL, | ||
256 | NFS_ACL_DEFAULT); | ||
257 | if (n <= 0) | ||
258 | return 0; | ||
259 | return 1; | ||
260 | } | ||
261 | |||
262 | static int nfsaclsvc_encode_attrstatres(struct svc_rqst *rqstp, u32 *p, | ||
263 | struct nfsd_attrstat *resp) | ||
264 | { | ||
265 | p = nfs2svc_encode_fattr(rqstp, p, &resp->fh); | ||
266 | return xdr_ressize_check(rqstp, p); | ||
267 | } | ||
268 | |||
269 | /* ACCESS */ | ||
270 | static int nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, u32 *p, | ||
271 | struct nfsd3_accessres *resp) | ||
272 | { | ||
273 | p = nfs2svc_encode_fattr(rqstp, p, &resp->fh); | ||
274 | *p++ = htonl(resp->access); | ||
275 | return xdr_ressize_check(rqstp, p); | ||
276 | } | ||
277 | |||
278 | /* | ||
279 | * XDR release functions | ||
280 | */ | ||
281 | static int nfsaclsvc_release_getacl(struct svc_rqst *rqstp, u32 *p, | ||
282 | struct nfsd3_getaclres *resp) | ||
283 | { | ||
284 | fh_put(&resp->fh); | ||
285 | posix_acl_release(resp->acl_access); | ||
286 | posix_acl_release(resp->acl_default); | ||
287 | return 1; | ||
288 | } | ||
289 | |||
290 | static int nfsaclsvc_release_fhandle(struct svc_rqst *rqstp, u32 *p, | ||
291 | struct nfsd_fhandle *resp) | ||
292 | { | ||
293 | fh_put(&resp->fh); | ||
294 | return 1; | ||
295 | } | ||
296 | |||
297 | #define nfsaclsvc_decode_voidargs NULL | ||
298 | #define nfsaclsvc_encode_voidres NULL | ||
299 | #define nfsaclsvc_release_void NULL | ||
300 | #define nfsd3_fhandleargs nfsd_fhandle | ||
301 | #define nfsd3_attrstatres nfsd_attrstat | ||
302 | #define nfsd3_voidres nfsd3_voidargs | ||
303 | struct nfsd3_voidargs { int dummy; }; | ||
304 | |||
305 | #define PROC(name, argt, rest, relt, cache, respsize) \ | ||
306 | { (svc_procfunc) nfsacld_proc_##name, \ | ||
307 | (kxdrproc_t) nfsaclsvc_decode_##argt##args, \ | ||
308 | (kxdrproc_t) nfsaclsvc_encode_##rest##res, \ | ||
309 | (kxdrproc_t) nfsaclsvc_release_##relt, \ | ||
310 | sizeof(struct nfsd3_##argt##args), \ | ||
311 | sizeof(struct nfsd3_##rest##res), \ | ||
312 | 0, \ | ||
313 | cache, \ | ||
314 | respsize, \ | ||
315 | } | ||
316 | |||
317 | #define ST 1 /* status*/ | ||
318 | #define AT 21 /* attributes */ | ||
319 | #define pAT (1+AT) /* post attributes - conditional */ | ||
320 | #define ACL (1+NFS_ACL_MAX_ENTRIES*3) /* Access Control List */ | ||
321 | |||
322 | static struct svc_procedure nfsd_acl_procedures2[] = { | ||
323 | PROC(null, void, void, void, RC_NOCACHE, ST), | ||
324 | PROC(getacl, getacl, getacl, getacl, RC_NOCACHE, ST+1+2*(1+ACL)), | ||
325 | PROC(setacl, setacl, attrstat, fhandle, RC_NOCACHE, ST+AT), | ||
326 | PROC(getattr, fhandle, attrstat, fhandle, RC_NOCACHE, ST+AT), | ||
327 | PROC(access, access, access, fhandle, RC_NOCACHE, ST+AT+1), | ||
328 | }; | ||
329 | |||
330 | struct svc_version nfsd_acl_version2 = { | ||
331 | .vs_vers = 2, | ||
332 | .vs_nproc = 5, | ||
333 | .vs_proc = nfsd_acl_procedures2, | ||
334 | .vs_dispatch = nfsd_dispatch, | ||
335 | .vs_xdrsize = NFS3_SVC_XDRSIZE, | ||
336 | }; | ||
diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c new file mode 100644 index 000000000000..64ba40572fea --- /dev/null +++ b/fs/nfsd/nfs3acl.c | |||
@@ -0,0 +1,267 @@ | |||
1 | /* | ||
2 | * linux/fs/nfsd/nfs3acl.c | ||
3 | * | ||
4 | * Process version 3 NFSACL requests. | ||
5 | * | ||
6 | * Copyright (C) 2002-2003 Andreas Gruenbacher <agruen@suse.de> | ||
7 | */ | ||
8 | |||
9 | #include <linux/sunrpc/svc.h> | ||
10 | #include <linux/nfs3.h> | ||
11 | #include <linux/nfsd/nfsd.h> | ||
12 | #include <linux/nfsd/cache.h> | ||
13 | #include <linux/nfsd/xdr3.h> | ||
14 | #include <linux/posix_acl.h> | ||
15 | #include <linux/nfsacl.h> | ||
16 | |||
17 | #define RETURN_STATUS(st) { resp->status = (st); return (st); } | ||
18 | |||
19 | /* | ||
20 | * NULL call. | ||
21 | */ | ||
22 | static int | ||
23 | nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) | ||
24 | { | ||
25 | return nfs_ok; | ||
26 | } | ||
27 | |||
28 | /* | ||
29 | * Get the Access and/or Default ACL of a file. | ||
30 | */ | ||
31 | static int nfsd3_proc_getacl(struct svc_rqst * rqstp, | ||
32 | struct nfsd3_getaclargs *argp, struct nfsd3_getaclres *resp) | ||
33 | { | ||
34 | svc_fh *fh; | ||
35 | struct posix_acl *acl; | ||
36 | int nfserr = 0; | ||
37 | |||
38 | fh = fh_copy(&resp->fh, &argp->fh); | ||
39 | if ((nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP))) | ||
40 | RETURN_STATUS(nfserr_inval); | ||
41 | |||
42 | if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) | ||
43 | RETURN_STATUS(nfserr_inval); | ||
44 | resp->mask = argp->mask; | ||
45 | |||
46 | if (resp->mask & (NFS_ACL|NFS_ACLCNT)) { | ||
47 | acl = nfsd_get_posix_acl(fh, ACL_TYPE_ACCESS); | ||
48 | if (IS_ERR(acl)) { | ||
49 | int err = PTR_ERR(acl); | ||
50 | |||
51 | if (err == -ENODATA || err == -EOPNOTSUPP) | ||
52 | acl = NULL; | ||
53 | else { | ||
54 | nfserr = nfserrno(err); | ||
55 | goto fail; | ||
56 | } | ||
57 | } | ||
58 | if (acl == NULL) { | ||
59 | /* Solaris returns the inode's minimum ACL. */ | ||
60 | |||
61 | struct inode *inode = fh->fh_dentry->d_inode; | ||
62 | acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); | ||
63 | } | ||
64 | resp->acl_access = acl; | ||
65 | } | ||
66 | if (resp->mask & (NFS_DFACL|NFS_DFACLCNT)) { | ||
67 | /* Check how Solaris handles requests for the Default ACL | ||
68 | of a non-directory! */ | ||
69 | |||
70 | acl = nfsd_get_posix_acl(fh, ACL_TYPE_DEFAULT); | ||
71 | if (IS_ERR(acl)) { | ||
72 | int err = PTR_ERR(acl); | ||
73 | |||
74 | if (err == -ENODATA || err == -EOPNOTSUPP) | ||
75 | acl = NULL; | ||
76 | else { | ||
77 | nfserr = nfserrno(err); | ||
78 | goto fail; | ||
79 | } | ||
80 | } | ||
81 | resp->acl_default = acl; | ||
82 | } | ||
83 | |||
84 | /* resp->acl_{access,default} are released in nfs3svc_release_getacl. */ | ||
85 | RETURN_STATUS(0); | ||
86 | |||
87 | fail: | ||
88 | posix_acl_release(resp->acl_access); | ||
89 | posix_acl_release(resp->acl_default); | ||
90 | RETURN_STATUS(nfserr); | ||
91 | } | ||
92 | |||
93 | /* | ||
94 | * Set the Access and/or Default ACL of a file. | ||
95 | */ | ||
96 | static int nfsd3_proc_setacl(struct svc_rqst * rqstp, | ||
97 | struct nfsd3_setaclargs *argp, | ||
98 | struct nfsd3_attrstat *resp) | ||
99 | { | ||
100 | svc_fh *fh; | ||
101 | int nfserr = 0; | ||
102 | |||
103 | fh = fh_copy(&resp->fh, &argp->fh); | ||
104 | nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP); | ||
105 | |||
106 | if (!nfserr) { | ||
107 | nfserr = nfserrno( nfsd_set_posix_acl( | ||
108 | fh, ACL_TYPE_ACCESS, argp->acl_access) ); | ||
109 | } | ||
110 | if (!nfserr) { | ||
111 | nfserr = nfserrno( nfsd_set_posix_acl( | ||
112 | fh, ACL_TYPE_DEFAULT, argp->acl_default) ); | ||
113 | } | ||
114 | |||
115 | /* argp->acl_{access,default} may have been allocated in | ||
116 | nfs3svc_decode_setaclargs. */ | ||
117 | posix_acl_release(argp->acl_access); | ||
118 | posix_acl_release(argp->acl_default); | ||
119 | RETURN_STATUS(nfserr); | ||
120 | } | ||
121 | |||
122 | /* | ||
123 | * XDR decode functions | ||
124 | */ | ||
125 | static int nfs3svc_decode_getaclargs(struct svc_rqst *rqstp, u32 *p, | ||
126 | struct nfsd3_getaclargs *args) | ||
127 | { | ||
128 | if (!(p = nfs3svc_decode_fh(p, &args->fh))) | ||
129 | return 0; | ||
130 | args->mask = ntohl(*p); p++; | ||
131 | |||
132 | return xdr_argsize_check(rqstp, p); | ||
133 | } | ||
134 | |||
135 | |||
136 | static int nfs3svc_decode_setaclargs(struct svc_rqst *rqstp, u32 *p, | ||
137 | struct nfsd3_setaclargs *args) | ||
138 | { | ||
139 | struct kvec *head = rqstp->rq_arg.head; | ||
140 | unsigned int base; | ||
141 | int n; | ||
142 | |||
143 | if (!(p = nfs3svc_decode_fh(p, &args->fh))) | ||
144 | return 0; | ||
145 | args->mask = ntohl(*p++); | ||
146 | if (args->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT) || | ||
147 | !xdr_argsize_check(rqstp, p)) | ||
148 | return 0; | ||
149 | |||
150 | base = (char *)p - (char *)head->iov_base; | ||
151 | n = nfsacl_decode(&rqstp->rq_arg, base, NULL, | ||
152 | (args->mask & NFS_ACL) ? | ||
153 | &args->acl_access : NULL); | ||
154 | if (n > 0) | ||
155 | n = nfsacl_decode(&rqstp->rq_arg, base + n, NULL, | ||
156 | (args->mask & NFS_DFACL) ? | ||
157 | &args->acl_default : NULL); | ||
158 | return (n > 0); | ||
159 | } | ||
160 | |||
161 | /* | ||
162 | * XDR encode functions | ||
163 | */ | ||
164 | |||
165 | /* GETACL */ | ||
166 | static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, u32 *p, | ||
167 | struct nfsd3_getaclres *resp) | ||
168 | { | ||
169 | struct dentry *dentry = resp->fh.fh_dentry; | ||
170 | |||
171 | p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh); | ||
172 | if (resp->status == 0 && dentry && dentry->d_inode) { | ||
173 | struct inode *inode = dentry->d_inode; | ||
174 | int w = nfsacl_size( | ||
175 | (resp->mask & NFS_ACL) ? resp->acl_access : NULL, | ||
176 | (resp->mask & NFS_DFACL) ? resp->acl_default : NULL); | ||
177 | struct kvec *head = rqstp->rq_res.head; | ||
178 | unsigned int base; | ||
179 | int n; | ||
180 | |||
181 | *p++ = htonl(resp->mask); | ||
182 | if (!xdr_ressize_check(rqstp, p)) | ||
183 | return 0; | ||
184 | base = (char *)p - (char *)head->iov_base; | ||
185 | |||
186 | rqstp->rq_res.page_len = w; | ||
187 | while (w > 0) { | ||
188 | if (!svc_take_res_page(rqstp)) | ||
189 | return 0; | ||
190 | w -= PAGE_SIZE; | ||
191 | } | ||
192 | |||
193 | n = nfsacl_encode(&rqstp->rq_res, base, inode, | ||
194 | resp->acl_access, | ||
195 | resp->mask & NFS_ACL, 0); | ||
196 | if (n > 0) | ||
197 | n = nfsacl_encode(&rqstp->rq_res, base + n, inode, | ||
198 | resp->acl_default, | ||
199 | resp->mask & NFS_DFACL, | ||
200 | NFS_ACL_DEFAULT); | ||
201 | if (n <= 0) | ||
202 | return 0; | ||
203 | } else | ||
204 | if (!xdr_ressize_check(rqstp, p)) | ||
205 | return 0; | ||
206 | |||
207 | return 1; | ||
208 | } | ||
209 | |||
210 | /* SETACL */ | ||
211 | static int nfs3svc_encode_setaclres(struct svc_rqst *rqstp, u32 *p, | ||
212 | struct nfsd3_attrstat *resp) | ||
213 | { | ||
214 | p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh); | ||
215 | |||
216 | return xdr_ressize_check(rqstp, p); | ||
217 | } | ||
218 | |||
219 | /* | ||
220 | * XDR release functions | ||
221 | */ | ||
222 | static int nfs3svc_release_getacl(struct svc_rqst *rqstp, u32 *p, | ||
223 | struct nfsd3_getaclres *resp) | ||
224 | { | ||
225 | fh_put(&resp->fh); | ||
226 | posix_acl_release(resp->acl_access); | ||
227 | posix_acl_release(resp->acl_default); | ||
228 | return 1; | ||
229 | } | ||
230 | |||
231 | #define nfs3svc_decode_voidargs NULL | ||
232 | #define nfs3svc_release_void NULL | ||
233 | #define nfsd3_setaclres nfsd3_attrstat | ||
234 | #define nfsd3_voidres nfsd3_voidargs | ||
235 | struct nfsd3_voidargs { int dummy; }; | ||
236 | |||
237 | #define PROC(name, argt, rest, relt, cache, respsize) \ | ||
238 | { (svc_procfunc) nfsd3_proc_##name, \ | ||
239 | (kxdrproc_t) nfs3svc_decode_##argt##args, \ | ||
240 | (kxdrproc_t) nfs3svc_encode_##rest##res, \ | ||
241 | (kxdrproc_t) nfs3svc_release_##relt, \ | ||
242 | sizeof(struct nfsd3_##argt##args), \ | ||
243 | sizeof(struct nfsd3_##rest##res), \ | ||
244 | 0, \ | ||
245 | cache, \ | ||
246 | respsize, \ | ||
247 | } | ||
248 | |||
249 | #define ST 1 /* status*/ | ||
250 | #define AT 21 /* attributes */ | ||
251 | #define pAT (1+AT) /* post attributes - conditional */ | ||
252 | #define ACL (1+NFS_ACL_MAX_ENTRIES*3) /* Access Control List */ | ||
253 | |||
254 | static struct svc_procedure nfsd_acl_procedures3[] = { | ||
255 | PROC(null, void, void, void, RC_NOCACHE, ST), | ||
256 | PROC(getacl, getacl, getacl, getacl, RC_NOCACHE, ST+1+2*(1+ACL)), | ||
257 | PROC(setacl, setacl, setacl, fhandle, RC_NOCACHE, ST+pAT), | ||
258 | }; | ||
259 | |||
260 | struct svc_version nfsd_acl_version3 = { | ||
261 | .vs_vers = 3, | ||
262 | .vs_nproc = 3, | ||
263 | .vs_proc = nfsd_acl_procedures3, | ||
264 | .vs_dispatch = nfsd_dispatch, | ||
265 | .vs_xdrsize = NFS3_SVC_XDRSIZE, | ||
266 | }; | ||
267 | |||
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index 11f806835c5a..e0e134d6baba 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c | |||
@@ -71,6 +71,12 @@ decode_fh(u32 *p, struct svc_fh *fhp) | |||
71 | return p + XDR_QUADLEN(size); | 71 | return p + XDR_QUADLEN(size); |
72 | } | 72 | } |
73 | 73 | ||
74 | /* Helper function for NFSv3 ACL code */ | ||
75 | u32 *nfs3svc_decode_fh(u32 *p, struct svc_fh *fhp) | ||
76 | { | ||
77 | return decode_fh(p, fhp); | ||
78 | } | ||
79 | |||
74 | static inline u32 * | 80 | static inline u32 * |
75 | encode_fh(u32 *p, struct svc_fh *fhp) | 81 | encode_fh(u32 *p, struct svc_fh *fhp) |
76 | { | 82 | { |
@@ -233,6 +239,13 @@ encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp) | |||
233 | return p; | 239 | return p; |
234 | } | 240 | } |
235 | 241 | ||
242 | /* Helper for NFSv3 ACLs */ | ||
243 | u32 * | ||
244 | nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp) | ||
245 | { | ||
246 | return encode_post_op_attr(rqstp, p, fhp); | ||
247 | } | ||
248 | |||
236 | /* | 249 | /* |
237 | * Enocde weak cache consistency data | 250 | * Enocde weak cache consistency data |
238 | */ | 251 | */ |
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 1a55dfcb74bc..634465e9cfc6 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c | |||
@@ -430,7 +430,7 @@ nfsd4_probe_callback(struct nfs4_client *clp) | |||
430 | clnt = rpc_create_client(xprt, hostname, program, 1, RPC_AUTH_UNIX); | 430 | clnt = rpc_create_client(xprt, hostname, program, 1, RPC_AUTH_UNIX); |
431 | if (IS_ERR(clnt)) { | 431 | if (IS_ERR(clnt)) { |
432 | dprintk("NFSD: couldn't create callback client\n"); | 432 | dprintk("NFSD: couldn't create callback client\n"); |
433 | goto out_xprt; | 433 | goto out_err; |
434 | } | 434 | } |
435 | clnt->cl_intr = 0; | 435 | clnt->cl_intr = 0; |
436 | clnt->cl_softrtry = 1; | 436 | clnt->cl_softrtry = 1; |
@@ -465,8 +465,6 @@ out_rpciod: | |||
465 | out_clnt: | 465 | out_clnt: |
466 | rpc_shutdown_client(clnt); | 466 | rpc_shutdown_client(clnt); |
467 | goto out_err; | 467 | goto out_err; |
468 | out_xprt: | ||
469 | xprt_destroy(xprt); | ||
470 | out_err: | 468 | out_err: |
471 | dprintk("NFSD: warning: no callback path to client %.*s\n", | 469 | dprintk("NFSD: warning: no callback path to client %.*s\n", |
472 | (int)clp->cl_name.len, clp->cl_name.data); | 470 | (int)clp->cl_name.len, clp->cl_name.data); |
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index 757f9d208034..0aa1b9603d7f 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c | |||
@@ -591,6 +591,7 @@ nfserrno (int errno) | |||
591 | { nfserr_dropit, -ENOMEM }, | 591 | { nfserr_dropit, -ENOMEM }, |
592 | { nfserr_badname, -ESRCH }, | 592 | { nfserr_badname, -ESRCH }, |
593 | { nfserr_io, -ETXTBSY }, | 593 | { nfserr_io, -ETXTBSY }, |
594 | { nfserr_notsupp, -EOPNOTSUPP }, | ||
594 | { -1, -EIO } | 595 | { -1, -EIO } |
595 | }; | 596 | }; |
596 | int i; | 597 | int i; |
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 02ded7cfbdcf..904df604e86b 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/nfsd/stats.h> | 31 | #include <linux/nfsd/stats.h> |
32 | #include <linux/nfsd/cache.h> | 32 | #include <linux/nfsd/cache.h> |
33 | #include <linux/lockd/bind.h> | 33 | #include <linux/lockd/bind.h> |
34 | #include <linux/nfsacl.h> | ||
34 | 35 | ||
35 | #define NFSDDBG_FACILITY NFSDDBG_SVC | 36 | #define NFSDDBG_FACILITY NFSDDBG_SVC |
36 | 37 | ||
@@ -362,6 +363,32 @@ nfsd_dispatch(struct svc_rqst *rqstp, u32 *statp) | |||
362 | return 1; | 363 | return 1; |
363 | } | 364 | } |
364 | 365 | ||
366 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) | ||
367 | static struct svc_stat nfsd_acl_svcstats; | ||
368 | static struct svc_version * nfsd_acl_version[] = { | ||
369 | [2] = &nfsd_acl_version2, | ||
370 | [3] = &nfsd_acl_version3, | ||
371 | }; | ||
372 | |||
373 | #define NFSD_ACL_NRVERS (sizeof(nfsd_acl_version)/sizeof(nfsd_acl_version[0])) | ||
374 | static struct svc_program nfsd_acl_program = { | ||
375 | .pg_prog = NFS_ACL_PROGRAM, | ||
376 | .pg_nvers = NFSD_ACL_NRVERS, | ||
377 | .pg_vers = nfsd_acl_version, | ||
378 | .pg_name = "nfsd", | ||
379 | .pg_class = "nfsd", | ||
380 | .pg_stats = &nfsd_acl_svcstats, | ||
381 | }; | ||
382 | |||
383 | static struct svc_stat nfsd_acl_svcstats = { | ||
384 | .program = &nfsd_acl_program, | ||
385 | }; | ||
386 | |||
387 | #define nfsd_acl_program_p &nfsd_acl_program | ||
388 | #else | ||
389 | #define nfsd_acl_program_p NULL | ||
390 | #endif /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */ | ||
391 | |||
365 | extern struct svc_version nfsd_version2, nfsd_version3, nfsd_version4; | 392 | extern struct svc_version nfsd_version2, nfsd_version3, nfsd_version4; |
366 | 393 | ||
367 | static struct svc_version * nfsd_version[] = { | 394 | static struct svc_version * nfsd_version[] = { |
@@ -376,6 +403,7 @@ static struct svc_version * nfsd_version[] = { | |||
376 | 403 | ||
377 | #define NFSD_NRVERS (sizeof(nfsd_version)/sizeof(nfsd_version[0])) | 404 | #define NFSD_NRVERS (sizeof(nfsd_version)/sizeof(nfsd_version[0])) |
378 | struct svc_program nfsd_program = { | 405 | struct svc_program nfsd_program = { |
406 | .pg_next = nfsd_acl_program_p, | ||
379 | .pg_prog = NFS_PROGRAM, /* program number */ | 407 | .pg_prog = NFS_PROGRAM, /* program number */ |
380 | .pg_nvers = NFSD_NRVERS, /* nr of entries in nfsd_version */ | 408 | .pg_nvers = NFSD_NRVERS, /* nr of entries in nfsd_version */ |
381 | .pg_vers = nfsd_version, /* version table */ | 409 | .pg_vers = nfsd_version, /* version table */ |
diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c index 948b08287c99..b45999ff33e6 100644 --- a/fs/nfsd/nfsxdr.c +++ b/fs/nfsd/nfsxdr.c | |||
@@ -49,6 +49,12 @@ decode_fh(u32 *p, struct svc_fh *fhp) | |||
49 | return p + (NFS_FHSIZE >> 2); | 49 | return p + (NFS_FHSIZE >> 2); |
50 | } | 50 | } |
51 | 51 | ||
52 | /* Helper function for NFSv2 ACL code */ | ||
53 | u32 *nfs2svc_decode_fh(u32 *p, struct svc_fh *fhp) | ||
54 | { | ||
55 | return decode_fh(p, fhp); | ||
56 | } | ||
57 | |||
52 | static inline u32 * | 58 | static inline u32 * |
53 | encode_fh(u32 *p, struct svc_fh *fhp) | 59 | encode_fh(u32 *p, struct svc_fh *fhp) |
54 | { | 60 | { |
@@ -190,6 +196,11 @@ encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp) | |||
190 | return p; | 196 | return p; |
191 | } | 197 | } |
192 | 198 | ||
199 | /* Helper function for NFSv2 ACL code */ | ||
200 | u32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp) | ||
201 | { | ||
202 | return encode_fattr(rqstp, p, fhp); | ||
203 | } | ||
193 | 204 | ||
194 | /* | 205 | /* |
195 | * XDR decode functions | 206 | * XDR decode functions |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index e3e9d217236e..ae3940dc85cc 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -46,8 +46,9 @@ | |||
46 | #include <linux/nfsd/nfsfh.h> | 46 | #include <linux/nfsd/nfsfh.h> |
47 | #include <linux/quotaops.h> | 47 | #include <linux/quotaops.h> |
48 | #include <linux/dnotify.h> | 48 | #include <linux/dnotify.h> |
49 | #ifdef CONFIG_NFSD_V4 | 49 | #include <linux/xattr_acl.h> |
50 | #include <linux/posix_acl.h> | 50 | #include <linux/posix_acl.h> |
51 | #ifdef CONFIG_NFSD_V4 | ||
51 | #include <linux/posix_acl_xattr.h> | 52 | #include <linux/posix_acl_xattr.h> |
52 | #include <linux/xattr_acl.h> | 53 | #include <linux/xattr_acl.h> |
53 | #include <linux/xattr.h> | 54 | #include <linux/xattr.h> |
@@ -1857,3 +1858,107 @@ nfsd_racache_init(int cache_size) | |||
1857 | nfsdstats.ra_size = cache_size; | 1858 | nfsdstats.ra_size = cache_size; |
1858 | return 0; | 1859 | return 0; |
1859 | } | 1860 | } |
1861 | |||
1862 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) | ||
1863 | struct posix_acl * | ||
1864 | nfsd_get_posix_acl(struct svc_fh *fhp, int type) | ||
1865 | { | ||
1866 | struct inode *inode = fhp->fh_dentry->d_inode; | ||
1867 | char *name; | ||
1868 | void *value = NULL; | ||
1869 | ssize_t size; | ||
1870 | struct posix_acl *acl; | ||
1871 | |||
1872 | if (!IS_POSIXACL(inode) || !inode->i_op || !inode->i_op->getxattr) | ||
1873 | return ERR_PTR(-EOPNOTSUPP); | ||
1874 | switch(type) { | ||
1875 | case ACL_TYPE_ACCESS: | ||
1876 | name = XATTR_NAME_ACL_ACCESS; | ||
1877 | break; | ||
1878 | case ACL_TYPE_DEFAULT: | ||
1879 | name = XATTR_NAME_ACL_DEFAULT; | ||
1880 | break; | ||
1881 | default: | ||
1882 | return ERR_PTR(-EOPNOTSUPP); | ||
1883 | } | ||
1884 | |||
1885 | size = inode->i_op->getxattr(fhp->fh_dentry, name, NULL, 0); | ||
1886 | |||
1887 | if (size < 0) { | ||
1888 | acl = ERR_PTR(size); | ||
1889 | goto getout; | ||
1890 | } else if (size > 0) { | ||
1891 | value = kmalloc(size, GFP_KERNEL); | ||
1892 | if (!value) { | ||
1893 | acl = ERR_PTR(-ENOMEM); | ||
1894 | goto getout; | ||
1895 | } | ||
1896 | size = inode->i_op->getxattr(fhp->fh_dentry, name, value, size); | ||
1897 | if (size < 0) { | ||
1898 | acl = ERR_PTR(size); | ||
1899 | goto getout; | ||
1900 | } | ||
1901 | } | ||
1902 | acl = posix_acl_from_xattr(value, size); | ||
1903 | |||
1904 | getout: | ||
1905 | kfree(value); | ||
1906 | return acl; | ||
1907 | } | ||
1908 | |||
1909 | int | ||
1910 | nfsd_set_posix_acl(struct svc_fh *fhp, int type, struct posix_acl *acl) | ||
1911 | { | ||
1912 | struct inode *inode = fhp->fh_dentry->d_inode; | ||
1913 | char *name; | ||
1914 | void *value = NULL; | ||
1915 | size_t size; | ||
1916 | int error; | ||
1917 | |||
1918 | if (!IS_POSIXACL(inode) || !inode->i_op || | ||
1919 | !inode->i_op->setxattr || !inode->i_op->removexattr) | ||
1920 | return -EOPNOTSUPP; | ||
1921 | switch(type) { | ||
1922 | case ACL_TYPE_ACCESS: | ||
1923 | name = XATTR_NAME_ACL_ACCESS; | ||
1924 | break; | ||
1925 | case ACL_TYPE_DEFAULT: | ||
1926 | name = XATTR_NAME_ACL_DEFAULT; | ||
1927 | break; | ||
1928 | default: | ||
1929 | return -EOPNOTSUPP; | ||
1930 | } | ||
1931 | |||
1932 | if (acl && acl->a_count) { | ||
1933 | size = xattr_acl_size(acl->a_count); | ||
1934 | value = kmalloc(size, GFP_KERNEL); | ||
1935 | if (!value) | ||
1936 | return -ENOMEM; | ||
1937 | size = posix_acl_to_xattr(acl, value, size); | ||
1938 | if (size < 0) { | ||
1939 | error = size; | ||
1940 | goto getout; | ||
1941 | } | ||
1942 | } else | ||
1943 | size = 0; | ||
1944 | |||
1945 | if (!fhp->fh_locked) | ||
1946 | fh_lock(fhp); /* unlocking is done automatically */ | ||
1947 | if (size) | ||
1948 | error = inode->i_op->setxattr(fhp->fh_dentry, name, | ||
1949 | value, size, 0); | ||
1950 | else { | ||
1951 | if (!S_ISDIR(inode->i_mode) && type == ACL_TYPE_DEFAULT) | ||
1952 | error = 0; | ||
1953 | else { | ||
1954 | error = inode->i_op->removexattr(fhp->fh_dentry, name); | ||
1955 | if (error == -ENODATA) | ||
1956 | error = 0; | ||
1957 | } | ||
1958 | } | ||
1959 | |||
1960 | getout: | ||
1961 | kfree(value); | ||
1962 | return error; | ||
1963 | } | ||
1964 | #endif /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */ | ||
diff --git a/include/asm-arm/arch-omap/tps65010.h b/include/asm-arm/arch-omap/tps65010.h index 0f97bb2e8fce..b9aa2b3a3909 100644 --- a/include/asm-arm/arch-omap/tps65010.h +++ b/include/asm-arm/arch-omap/tps65010.h | |||
@@ -30,6 +30,66 @@ | |||
30 | 30 | ||
31 | /* | 31 | /* |
32 | * ---------------------------------------------------------------------------- | 32 | * ---------------------------------------------------------------------------- |
33 | * Registers, all 8 bits | ||
34 | * ---------------------------------------------------------------------------- | ||
35 | */ | ||
36 | |||
37 | #define TPS_CHGSTATUS 0x01 | ||
38 | # define TPS_CHG_USB (1 << 7) | ||
39 | # define TPS_CHG_AC (1 << 6) | ||
40 | # define TPS_CHG_THERM (1 << 5) | ||
41 | # define TPS_CHG_TERM (1 << 4) | ||
42 | # define TPS_CHG_TAPER_TMO (1 << 3) | ||
43 | # define TPS_CHG_CHG_TMO (1 << 2) | ||
44 | # define TPS_CHG_PRECHG_TMO (1 << 1) | ||
45 | # define TPS_CHG_TEMP_ERR (1 << 0) | ||
46 | #define TPS_REGSTATUS 0x02 | ||
47 | # define TPS_REG_ONOFF (1 << 7) | ||
48 | # define TPS_REG_COVER (1 << 6) | ||
49 | # define TPS_REG_UVLO (1 << 5) | ||
50 | # define TPS_REG_NO_CHG (1 << 4) /* tps65013 */ | ||
51 | # define TPS_REG_PG_LD02 (1 << 3) | ||
52 | # define TPS_REG_PG_LD01 (1 << 2) | ||
53 | # define TPS_REG_PG_MAIN (1 << 1) | ||
54 | # define TPS_REG_PG_CORE (1 << 0) | ||
55 | #define TPS_MASK1 0x03 | ||
56 | #define TPS_MASK2 0x04 | ||
57 | #define TPS_ACKINT1 0x05 | ||
58 | #define TPS_ACKINT2 0x06 | ||
59 | #define TPS_CHGCONFIG 0x07 | ||
60 | # define TPS_CHARGE_POR (1 << 7) /* 65010/65012 */ | ||
61 | # define TPS65013_AUA (1 << 7) /* 65011/65013 */ | ||
62 | # define TPS_CHARGE_RESET (1 << 6) | ||
63 | # define TPS_CHARGE_FAST (1 << 5) | ||
64 | # define TPS_CHARGE_CURRENT (3 << 3) | ||
65 | # define TPS_VBUS_500MA (1 << 2) | ||
66 | # define TPS_VBUS_CHARGING (1 << 1) | ||
67 | # define TPS_CHARGE_ENABLE (1 << 0) | ||
68 | #define TPS_LED1_ON 0x08 | ||
69 | #define TPS_LED1_PER 0x09 | ||
70 | #define TPS_LED2_ON 0x0a | ||
71 | #define TPS_LED2_PER 0x0b | ||
72 | #define TPS_VDCDC1 0x0c | ||
73 | # define TPS_ENABLE_LP (1 << 3) | ||
74 | #define TPS_VDCDC2 0x0d | ||
75 | #define TPS_VREGS1 0x0e | ||
76 | # define TPS_LDO2_ENABLE (1 << 7) | ||
77 | # define TPS_LDO2_OFF (1 << 6) | ||
78 | # define TPS_VLDO2_3_0V (3 << 4) | ||
79 | # define TPS_VLDO2_2_75V (2 << 4) | ||
80 | # define TPS_VLDO2_2_5V (1 << 4) | ||
81 | # define TPS_VLDO2_1_8V (0 << 4) | ||
82 | # define TPS_LDO1_ENABLE (1 << 3) | ||
83 | # define TPS_LDO1_OFF (1 << 2) | ||
84 | # define TPS_VLDO1_3_0V (3 << 0) | ||
85 | # define TPS_VLDO1_2_75V (2 << 0) | ||
86 | # define TPS_VLDO1_2_5V (1 << 0) | ||
87 | # define TPS_VLDO1_ADJ (0 << 0) | ||
88 | #define TPS_MASK3 0x0f | ||
89 | #define TPS_DEFGPIO 0x10 | ||
90 | |||
91 | /* | ||
92 | * ---------------------------------------------------------------------------- | ||
33 | * Macros used by exported functions | 93 | * Macros used by exported functions |
34 | * ---------------------------------------------------------------------------- | 94 | * ---------------------------------------------------------------------------- |
35 | */ | 95 | */ |
@@ -71,10 +131,26 @@ extern int tps65010_set_gpio_out_value(unsigned gpio, unsigned value); | |||
71 | */ | 131 | */ |
72 | extern int tps65010_set_led(unsigned led, unsigned mode); | 132 | extern int tps65010_set_led(unsigned led, unsigned mode); |
73 | 133 | ||
134 | /* tps65010_set_vib parameter: | ||
135 | * value: ON or OFF | ||
136 | */ | ||
137 | extern int tps65010_set_vib(unsigned value); | ||
138 | |||
74 | /* tps65010_set_low_pwr parameter: | 139 | /* tps65010_set_low_pwr parameter: |
75 | * mode: ON or OFF | 140 | * mode: ON or OFF |
76 | */ | 141 | */ |
77 | extern int tps65010_set_low_pwr(unsigned mode); | 142 | extern int tps65010_set_low_pwr(unsigned mode); |
78 | 143 | ||
144 | /* tps65010_config_vregs1 parameter: | ||
145 | * value to be written to VREGS1 register | ||
146 | * Note: The complete register is written, set all bits you need | ||
147 | */ | ||
148 | extern int tps65010_config_vregs1(unsigned value); | ||
149 | |||
150 | /* tps65013_set_low_pwr parameter: | ||
151 | * mode: ON or OFF | ||
152 | */ | ||
153 | extern int tps65013_set_low_pwr(unsigned mode); | ||
154 | |||
79 | #endif /* __ASM_ARCH_TPS65010_H */ | 155 | #endif /* __ASM_ARCH_TPS65010_H */ |
80 | 156 | ||
diff --git a/include/linux/efi.h b/include/linux/efi.h index 047e7222df7a..73781ec165b4 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h | |||
@@ -315,7 +315,7 @@ extern struct efi_memory_map memmap; | |||
315 | */ | 315 | */ |
316 | static inline int efi_range_is_wc(unsigned long start, unsigned long len) | 316 | static inline int efi_range_is_wc(unsigned long start, unsigned long len) |
317 | { | 317 | { |
318 | int i; | 318 | unsigned long i; |
319 | 319 | ||
320 | for (i = 0; i < len; i += (1UL << EFI_PAGE_SHIFT)) { | 320 | for (i = 0; i < len; i += (1UL << EFI_PAGE_SHIFT)) { |
321 | unsigned long paddr = __pa(start + i); | 321 | unsigned long paddr = __pa(start + i); |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 9b8b696d4f15..e5a8db00df29 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -674,6 +674,7 @@ struct file_lock { | |||
674 | struct lock_manager_operations *fl_lmops; /* Callbacks for lockmanagers */ | 674 | struct lock_manager_operations *fl_lmops; /* Callbacks for lockmanagers */ |
675 | union { | 675 | union { |
676 | struct nfs_lock_info nfs_fl; | 676 | struct nfs_lock_info nfs_fl; |
677 | struct nfs4_lock_info nfs4_fl; | ||
677 | } fl_u; | 678 | } fl_u; |
678 | }; | 679 | }; |
679 | 680 | ||
diff --git a/include/linux/i2c-sysfs.h b/include/linux/hwmon-sysfs.h index d7bf6ce11679..1b5018a965f5 100644 --- a/include/linux/i2c-sysfs.h +++ b/include/linux/hwmon-sysfs.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * i2c-sysfs.h - i2c chip driver sysfs defines | 2 | * hwmon-sysfs.h - hardware monitoring chip driver sysfs defines |
3 | * | 3 | * |
4 | * Copyright (C) 2005 Yani Ioannou <yani.ioannou@gmail.com> | 4 | * Copyright (C) 2005 Yani Ioannou <yani.ioannou@gmail.com> |
5 | * | 5 | * |
@@ -17,8 +17,8 @@ | |||
17 | * along with this program; if not, write to the Free Software | 17 | * along with this program; if not, write to the Free Software |
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
19 | */ | 19 | */ |
20 | #ifndef _LINUX_I2C_SYSFS_H | 20 | #ifndef _LINUX_HWMON_SYSFS_H |
21 | #define _LINUX_I2C_SYSFS_H | 21 | #define _LINUX_HWMON_SYSFS_H |
22 | 22 | ||
23 | struct sensor_device_attribute{ | 23 | struct sensor_device_attribute{ |
24 | struct device_attribute dev_attr; | 24 | struct device_attribute dev_attr; |
@@ -33,4 +33,4 @@ struct sensor_device_attribute sensor_dev_attr_##_name = { \ | |||
33 | .index = _index, \ | 33 | .index = _index, \ |
34 | } | 34 | } |
35 | 35 | ||
36 | #endif /* _LINUX_I2C_SYSFS_H */ | 36 | #endif /* _LINUX_HWMON_SYSFS_H */ |
diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h index 89270ce51470..33f08258f22b 100644 --- a/include/linux/i2c-id.h +++ b/include/linux/i2c-id.h | |||
@@ -108,6 +108,7 @@ | |||
108 | #define I2C_DRIVERID_TDA7313 62 /* TDA7313 audio processor */ | 108 | #define I2C_DRIVERID_TDA7313 62 /* TDA7313 audio processor */ |
109 | #define I2C_DRIVERID_MAX6900 63 /* MAX6900 real-time clock */ | 109 | #define I2C_DRIVERID_MAX6900 63 /* MAX6900 real-time clock */ |
110 | #define I2C_DRIVERID_SAA7114H 64 /* video decoder */ | 110 | #define I2C_DRIVERID_SAA7114H 64 /* video decoder */ |
111 | #define I2C_DRIVERID_DS1374 65 /* DS1374 real time clock */ | ||
111 | 112 | ||
112 | 113 | ||
113 | #define I2C_DRIVERID_EXP0 0xF0 /* experimental use id's */ | 114 | #define I2C_DRIVERID_EXP0 0xF0 /* experimental use id's */ |
diff --git a/include/linux/i2c-vid.h b/include/linux/i2c-vid.h index 974835e3530f..41d0635e0ba9 100644 --- a/include/linux/i2c-vid.h +++ b/include/linux/i2c-vid.h | |||
@@ -97,3 +97,15 @@ static inline int vid_from_reg(int val, int vrm) | |||
97 | 2050 - (val) * 50); | 97 | 2050 - (val) * 50); |
98 | } | 98 | } |
99 | } | 99 | } |
100 | |||
101 | static inline int vid_to_reg(int val, int vrm) | ||
102 | { | ||
103 | switch (vrm) { | ||
104 | case 91: /* VRM 9.1 */ | ||
105 | case 90: /* VRM 9.0 */ | ||
106 | return ((val >= 1100) && (val <= 1850) ? | ||
107 | ((18499 - val * 10) / 25 + 5) / 10 : -1); | ||
108 | default: | ||
109 | return -1; | ||
110 | } | ||
111 | } | ||
diff --git a/include/linux/i2c.h b/include/linux/i2c.h index ebcd745f4cd6..be837b13f297 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h | |||
@@ -290,11 +290,8 @@ static inline void i2c_set_adapdata (struct i2c_adapter *dev, void *data) | |||
290 | */ | 290 | */ |
291 | struct i2c_client_address_data { | 291 | struct i2c_client_address_data { |
292 | unsigned short *normal_i2c; | 292 | unsigned short *normal_i2c; |
293 | unsigned short *normal_i2c_range; | ||
294 | unsigned short *probe; | 293 | unsigned short *probe; |
295 | unsigned short *probe_range; | ||
296 | unsigned short *ignore; | 294 | unsigned short *ignore; |
297 | unsigned short *ignore_range; | ||
298 | unsigned short *force; | 295 | unsigned short *force; |
299 | }; | 296 | }; |
300 | 297 | ||
@@ -563,24 +560,15 @@ union i2c_smbus_data { | |||
563 | #define I2C_CLIENT_INSMOD \ | 560 | #define I2C_CLIENT_INSMOD \ |
564 | I2C_CLIENT_MODULE_PARM(probe, \ | 561 | I2C_CLIENT_MODULE_PARM(probe, \ |
565 | "List of adapter,address pairs to scan additionally"); \ | 562 | "List of adapter,address pairs to scan additionally"); \ |
566 | I2C_CLIENT_MODULE_PARM(probe_range, \ | ||
567 | "List of adapter,start-addr,end-addr triples to scan " \ | ||
568 | "additionally"); \ | ||
569 | I2C_CLIENT_MODULE_PARM(ignore, \ | 563 | I2C_CLIENT_MODULE_PARM(ignore, \ |
570 | "List of adapter,address pairs not to scan"); \ | 564 | "List of adapter,address pairs not to scan"); \ |
571 | I2C_CLIENT_MODULE_PARM(ignore_range, \ | ||
572 | "List of adapter,start-addr,end-addr triples not to " \ | ||
573 | "scan"); \ | ||
574 | I2C_CLIENT_MODULE_PARM(force, \ | 565 | I2C_CLIENT_MODULE_PARM(force, \ |
575 | "List of adapter,address pairs to boldly assume " \ | 566 | "List of adapter,address pairs to boldly assume " \ |
576 | "to be present"); \ | 567 | "to be present"); \ |
577 | static struct i2c_client_address_data addr_data = { \ | 568 | static struct i2c_client_address_data addr_data = { \ |
578 | .normal_i2c = normal_i2c, \ | 569 | .normal_i2c = normal_i2c, \ |
579 | .normal_i2c_range = normal_i2c_range, \ | ||
580 | .probe = probe, \ | 570 | .probe = probe, \ |
581 | .probe_range = probe_range, \ | ||
582 | .ignore = ignore, \ | 571 | .ignore = ignore, \ |
583 | .ignore_range = ignore_range, \ | ||
584 | .force = force, \ | 572 | .force = force, \ |
585 | } | 573 | } |
586 | 574 | ||
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h index 0d9d22578212..16d4e5a08e1d 100644 --- a/include/linux/lockd/lockd.h +++ b/include/linux/lockd/lockd.h | |||
@@ -72,6 +72,8 @@ struct nlm_lockowner { | |||
72 | uint32_t pid; | 72 | uint32_t pid; |
73 | }; | 73 | }; |
74 | 74 | ||
75 | struct nlm_wait; | ||
76 | |||
75 | /* | 77 | /* |
76 | * Memory chunk for NLM client RPC request. | 78 | * Memory chunk for NLM client RPC request. |
77 | */ | 79 | */ |
@@ -81,6 +83,7 @@ struct nlm_rqst { | |||
81 | struct nlm_host * a_host; /* host handle */ | 83 | struct nlm_host * a_host; /* host handle */ |
82 | struct nlm_args a_args; /* arguments */ | 84 | struct nlm_args a_args; /* arguments */ |
83 | struct nlm_res a_res; /* result */ | 85 | struct nlm_res a_res; /* result */ |
86 | struct nlm_wait * a_block; | ||
84 | char a_owner[NLMCLNT_OHSIZE]; | 87 | char a_owner[NLMCLNT_OHSIZE]; |
85 | }; | 88 | }; |
86 | 89 | ||
@@ -142,7 +145,9 @@ extern unsigned long nlmsvc_timeout; | |||
142 | * Lockd client functions | 145 | * Lockd client functions |
143 | */ | 146 | */ |
144 | struct nlm_rqst * nlmclnt_alloc_call(void); | 147 | struct nlm_rqst * nlmclnt_alloc_call(void); |
145 | int nlmclnt_block(struct nlm_host *, struct file_lock *, u32 *); | 148 | int nlmclnt_prepare_block(struct nlm_rqst *req, struct nlm_host *host, struct file_lock *fl); |
149 | void nlmclnt_finish_block(struct nlm_rqst *req); | ||
150 | long nlmclnt_block(struct nlm_rqst *req, long timeout); | ||
146 | int nlmclnt_cancel(struct nlm_host *, struct file_lock *); | 151 | int nlmclnt_cancel(struct nlm_host *, struct file_lock *); |
147 | u32 nlmclnt_grant(struct nlm_lock *); | 152 | u32 nlmclnt_grant(struct nlm_lock *); |
148 | void nlmclnt_recovery(struct nlm_host *, u32); | 153 | void nlmclnt_recovery(struct nlm_host *, u32); |
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index 5ca8a8d8ccdf..5bb5b2fd7ba2 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h | |||
@@ -382,6 +382,8 @@ enum { | |||
382 | NFSPROC4_CLNT_READDIR, | 382 | NFSPROC4_CLNT_READDIR, |
383 | NFSPROC4_CLNT_SERVER_CAPS, | 383 | NFSPROC4_CLNT_SERVER_CAPS, |
384 | NFSPROC4_CLNT_DELEGRETURN, | 384 | NFSPROC4_CLNT_DELEGRETURN, |
385 | NFSPROC4_CLNT_GETACL, | ||
386 | NFSPROC4_CLNT_SETACL, | ||
385 | }; | 387 | }; |
386 | 388 | ||
387 | #endif | 389 | #endif |
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index dbac7f363e5d..8ea249110fb0 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h | |||
@@ -15,7 +15,6 @@ | |||
15 | #include <linux/pagemap.h> | 15 | #include <linux/pagemap.h> |
16 | #include <linux/rwsem.h> | 16 | #include <linux/rwsem.h> |
17 | #include <linux/wait.h> | 17 | #include <linux/wait.h> |
18 | #include <linux/uio.h> | ||
19 | 18 | ||
20 | #include <linux/nfs_fs_sb.h> | 19 | #include <linux/nfs_fs_sb.h> |
21 | 20 | ||
@@ -29,7 +28,6 @@ | |||
29 | #include <linux/nfs4.h> | 28 | #include <linux/nfs4.h> |
30 | #include <linux/nfs_xdr.h> | 29 | #include <linux/nfs_xdr.h> |
31 | #include <linux/rwsem.h> | 30 | #include <linux/rwsem.h> |
32 | #include <linux/workqueue.h> | ||
33 | #include <linux/mempool.h> | 31 | #include <linux/mempool.h> |
34 | 32 | ||
35 | /* | 33 | /* |
@@ -44,13 +42,6 @@ | |||
44 | #define NFS_DEF_FILE_IO_BUFFER_SIZE 4096 | 42 | #define NFS_DEF_FILE_IO_BUFFER_SIZE 4096 |
45 | 43 | ||
46 | /* | 44 | /* |
47 | * The upper limit on timeouts for the exponential backoff algorithm. | ||
48 | */ | ||
49 | #define NFS_WRITEBACK_DELAY (5*HZ) | ||
50 | #define NFS_WRITEBACK_LOCKDELAY (60*HZ) | ||
51 | #define NFS_COMMIT_DELAY (5*HZ) | ||
52 | |||
53 | /* | ||
54 | * superblock magic number for NFS | 45 | * superblock magic number for NFS |
55 | */ | 46 | */ |
56 | #define NFS_SUPER_MAGIC 0x6969 | 47 | #define NFS_SUPER_MAGIC 0x6969 |
@@ -60,9 +51,6 @@ | |||
60 | */ | 51 | */ |
61 | #define NFS_RPC_SWAPFLAGS (RPC_TASK_SWAPPER|RPC_TASK_ROOTCREDS) | 52 | #define NFS_RPC_SWAPFLAGS (RPC_TASK_SWAPPER|RPC_TASK_ROOTCREDS) |
62 | 53 | ||
63 | #define NFS_RW_SYNC 0x0001 /* O_SYNC handling */ | ||
64 | #define NFS_RW_SWAP 0x0002 /* This is a swap request */ | ||
65 | |||
66 | /* | 54 | /* |
67 | * When flushing a cluster of dirty pages, there can be different | 55 | * When flushing a cluster of dirty pages, there can be different |
68 | * strategies: | 56 | * strategies: |
@@ -96,7 +84,8 @@ struct nfs_open_context { | |||
96 | int error; | 84 | int error; |
97 | 85 | ||
98 | struct list_head list; | 86 | struct list_head list; |
99 | wait_queue_head_t waitq; | 87 | |
88 | __u64 dir_cookie; | ||
100 | }; | 89 | }; |
101 | 90 | ||
102 | /* | 91 | /* |
@@ -104,6 +93,8 @@ struct nfs_open_context { | |||
104 | */ | 93 | */ |
105 | struct nfs_delegation; | 94 | struct nfs_delegation; |
106 | 95 | ||
96 | struct posix_acl; | ||
97 | |||
107 | /* | 98 | /* |
108 | * nfs fs inode data in memory | 99 | * nfs fs inode data in memory |
109 | */ | 100 | */ |
@@ -140,7 +131,6 @@ struct nfs_inode { | |||
140 | * | 131 | * |
141 | * mtime != read_cache_mtime | 132 | * mtime != read_cache_mtime |
142 | */ | 133 | */ |
143 | unsigned long readdir_timestamp; | ||
144 | unsigned long read_cache_jiffies; | 134 | unsigned long read_cache_jiffies; |
145 | unsigned long attrtimeo; | 135 | unsigned long attrtimeo; |
146 | unsigned long attrtimeo_timestamp; | 136 | unsigned long attrtimeo_timestamp; |
@@ -158,6 +148,10 @@ struct nfs_inode { | |||
158 | atomic_t data_updates; | 148 | atomic_t data_updates; |
159 | 149 | ||
160 | struct nfs_access_entry cache_access; | 150 | struct nfs_access_entry cache_access; |
151 | #ifdef CONFIG_NFS_V3_ACL | ||
152 | struct posix_acl *acl_access; | ||
153 | struct posix_acl *acl_default; | ||
154 | #endif | ||
161 | 155 | ||
162 | /* | 156 | /* |
163 | * This is the cookie verifier used for NFSv3 readdir | 157 | * This is the cookie verifier used for NFSv3 readdir |
@@ -183,13 +177,13 @@ struct nfs_inode { | |||
183 | wait_queue_head_t nfs_i_wait; | 177 | wait_queue_head_t nfs_i_wait; |
184 | 178 | ||
185 | #ifdef CONFIG_NFS_V4 | 179 | #ifdef CONFIG_NFS_V4 |
180 | struct nfs4_cached_acl *nfs4_acl; | ||
186 | /* NFSv4 state */ | 181 | /* NFSv4 state */ |
187 | struct list_head open_states; | 182 | struct list_head open_states; |
188 | struct nfs_delegation *delegation; | 183 | struct nfs_delegation *delegation; |
189 | int delegation_state; | 184 | int delegation_state; |
190 | struct rw_semaphore rwsem; | 185 | struct rw_semaphore rwsem; |
191 | #endif /* CONFIG_NFS_V4*/ | 186 | #endif /* CONFIG_NFS_V4*/ |
192 | |||
193 | struct inode vfs_inode; | 187 | struct inode vfs_inode; |
194 | }; | 188 | }; |
195 | 189 | ||
@@ -203,6 +197,8 @@ struct nfs_inode { | |||
203 | #define NFS_INO_INVALID_DATA 0x0010 /* cached data is invalid */ | 197 | #define NFS_INO_INVALID_DATA 0x0010 /* cached data is invalid */ |
204 | #define NFS_INO_INVALID_ATIME 0x0020 /* cached atime is invalid */ | 198 | #define NFS_INO_INVALID_ATIME 0x0020 /* cached atime is invalid */ |
205 | #define NFS_INO_INVALID_ACCESS 0x0040 /* cached access cred invalid */ | 199 | #define NFS_INO_INVALID_ACCESS 0x0040 /* cached access cred invalid */ |
200 | #define NFS_INO_INVALID_ACL 0x0080 /* cached acls are invalid */ | ||
201 | #define NFS_INO_REVAL_PAGECACHE 0x1000 /* must revalidate pagecache */ | ||
206 | 202 | ||
207 | static inline struct nfs_inode *NFS_I(struct inode *inode) | 203 | static inline struct nfs_inode *NFS_I(struct inode *inode) |
208 | { | 204 | { |
@@ -294,12 +290,12 @@ extern int nfs_release(struct inode *, struct file *); | |||
294 | extern int nfs_attribute_timeout(struct inode *inode); | 290 | extern int nfs_attribute_timeout(struct inode *inode); |
295 | extern int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode); | 291 | extern int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode); |
296 | extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *); | 292 | extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *); |
293 | extern void nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping); | ||
297 | extern int nfs_setattr(struct dentry *, struct iattr *); | 294 | extern int nfs_setattr(struct dentry *, struct iattr *); |
298 | extern void nfs_begin_attr_update(struct inode *); | 295 | extern void nfs_begin_attr_update(struct inode *); |
299 | extern void nfs_end_attr_update(struct inode *); | 296 | extern void nfs_end_attr_update(struct inode *); |
300 | extern void nfs_begin_data_update(struct inode *); | 297 | extern void nfs_begin_data_update(struct inode *); |
301 | extern void nfs_end_data_update(struct inode *); | 298 | extern void nfs_end_data_update(struct inode *); |
302 | extern void nfs_end_data_update_defer(struct inode *); | ||
303 | extern struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry, struct rpc_cred *cred); | 299 | extern struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry, struct rpc_cred *cred); |
304 | extern struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx); | 300 | extern struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx); |
305 | extern void put_nfs_open_context(struct nfs_open_context *ctx); | 301 | extern void put_nfs_open_context(struct nfs_open_context *ctx); |
@@ -314,6 +310,9 @@ extern u32 root_nfs_parse_addr(char *name); /*__init*/ | |||
314 | * linux/fs/nfs/file.c | 310 | * linux/fs/nfs/file.c |
315 | */ | 311 | */ |
316 | extern struct inode_operations nfs_file_inode_operations; | 312 | extern struct inode_operations nfs_file_inode_operations; |
313 | #ifdef CONFIG_NFS_V3 | ||
314 | extern struct inode_operations nfs3_file_inode_operations; | ||
315 | #endif /* CONFIG_NFS_V3 */ | ||
317 | extern struct file_operations nfs_file_operations; | 316 | extern struct file_operations nfs_file_operations; |
318 | extern struct address_space_operations nfs_file_aops; | 317 | extern struct address_space_operations nfs_file_aops; |
319 | 318 | ||
@@ -329,6 +328,22 @@ static inline struct rpc_cred *nfs_file_cred(struct file *file) | |||
329 | } | 328 | } |
330 | 329 | ||
331 | /* | 330 | /* |
331 | * linux/fs/nfs/xattr.c | ||
332 | */ | ||
333 | #ifdef CONFIG_NFS_V3_ACL | ||
334 | extern ssize_t nfs3_listxattr(struct dentry *, char *, size_t); | ||
335 | extern ssize_t nfs3_getxattr(struct dentry *, const char *, void *, size_t); | ||
336 | extern int nfs3_setxattr(struct dentry *, const char *, | ||
337 | const void *, size_t, int); | ||
338 | extern int nfs3_removexattr (struct dentry *, const char *name); | ||
339 | #else | ||
340 | # define nfs3_listxattr NULL | ||
341 | # define nfs3_getxattr NULL | ||
342 | # define nfs3_setxattr NULL | ||
343 | # define nfs3_removexattr NULL | ||
344 | #endif | ||
345 | |||
346 | /* | ||
332 | * linux/fs/nfs/direct.c | 347 | * linux/fs/nfs/direct.c |
333 | */ | 348 | */ |
334 | extern ssize_t nfs_direct_IO(int, struct kiocb *, const struct iovec *, loff_t, | 349 | extern ssize_t nfs_direct_IO(int, struct kiocb *, const struct iovec *, loff_t, |
@@ -342,6 +357,9 @@ extern ssize_t nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, | |||
342 | * linux/fs/nfs/dir.c | 357 | * linux/fs/nfs/dir.c |
343 | */ | 358 | */ |
344 | extern struct inode_operations nfs_dir_inode_operations; | 359 | extern struct inode_operations nfs_dir_inode_operations; |
360 | #ifdef CONFIG_NFS_V3 | ||
361 | extern struct inode_operations nfs3_dir_inode_operations; | ||
362 | #endif /* CONFIG_NFS_V3 */ | ||
345 | extern struct file_operations nfs_dir_operations; | 363 | extern struct file_operations nfs_dir_operations; |
346 | extern struct dentry_operations nfs_dentry_operations; | 364 | extern struct dentry_operations nfs_dentry_operations; |
347 | 365 | ||
@@ -377,10 +395,10 @@ extern void nfs_commit_done(struct rpc_task *); | |||
377 | */ | 395 | */ |
378 | extern int nfs_sync_inode(struct inode *, unsigned long, unsigned int, int); | 396 | extern int nfs_sync_inode(struct inode *, unsigned long, unsigned int, int); |
379 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 397 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
380 | extern int nfs_commit_inode(struct inode *, unsigned long, unsigned int, int); | 398 | extern int nfs_commit_inode(struct inode *, int); |
381 | #else | 399 | #else |
382 | static inline int | 400 | static inline int |
383 | nfs_commit_inode(struct inode *inode, unsigned long idx_start, unsigned int npages, int how) | 401 | nfs_commit_inode(struct inode *inode, int how) |
384 | { | 402 | { |
385 | return 0; | 403 | return 0; |
386 | } | 404 | } |
@@ -434,11 +452,6 @@ static inline void nfs_writedata_free(struct nfs_write_data *p) | |||
434 | mempool_free(p, nfs_wdata_mempool); | 452 | mempool_free(p, nfs_wdata_mempool); |
435 | } | 453 | } |
436 | 454 | ||
437 | /* Hack for future NFS swap support */ | ||
438 | #ifndef IS_SWAPFILE | ||
439 | # define IS_SWAPFILE(inode) (0) | ||
440 | #endif | ||
441 | |||
442 | /* | 455 | /* |
443 | * linux/fs/nfs/read.c | 456 | * linux/fs/nfs/read.c |
444 | */ | 457 | */ |
@@ -468,6 +481,29 @@ static inline void nfs_readdata_free(struct nfs_read_data *p) | |||
468 | extern void nfs_readdata_release(struct rpc_task *task); | 481 | extern void nfs_readdata_release(struct rpc_task *task); |
469 | 482 | ||
470 | /* | 483 | /* |
484 | * linux/fs/nfs3proc.c | ||
485 | */ | ||
486 | #ifdef CONFIG_NFS_V3_ACL | ||
487 | extern struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type); | ||
488 | extern int nfs3_proc_setacl(struct inode *inode, int type, | ||
489 | struct posix_acl *acl); | ||
490 | extern int nfs3_proc_set_default_acl(struct inode *dir, struct inode *inode, | ||
491 | mode_t mode); | ||
492 | extern void nfs3_forget_cached_acls(struct inode *inode); | ||
493 | #else | ||
494 | static inline int nfs3_proc_set_default_acl(struct inode *dir, | ||
495 | struct inode *inode, | ||
496 | mode_t mode) | ||
497 | { | ||
498 | return 0; | ||
499 | } | ||
500 | |||
501 | static inline void nfs3_forget_cached_acls(struct inode *inode) | ||
502 | { | ||
503 | } | ||
504 | #endif /* CONFIG_NFS_V3_ACL */ | ||
505 | |||
506 | /* | ||
471 | * linux/fs/mount_clnt.c | 507 | * linux/fs/mount_clnt.c |
472 | * (Used only by nfsroot module) | 508 | * (Used only by nfsroot module) |
473 | */ | 509 | */ |
@@ -515,230 +551,6 @@ extern void * nfs_root_data(void); | |||
515 | 551 | ||
516 | #define NFS_JUKEBOX_RETRY_TIME (5 * HZ) | 552 | #define NFS_JUKEBOX_RETRY_TIME (5 * HZ) |
517 | 553 | ||
518 | #ifdef CONFIG_NFS_V4 | ||
519 | |||
520 | struct idmap; | ||
521 | |||
522 | /* | ||
523 | * In a seqid-mutating op, this macro controls which error return | ||
524 | * values trigger incrementation of the seqid. | ||
525 | * | ||
526 | * from rfc 3010: | ||
527 | * The client MUST monotonically increment the sequence number for the | ||
528 | * CLOSE, LOCK, LOCKU, OPEN, OPEN_CONFIRM, and OPEN_DOWNGRADE | ||
529 | * operations. This is true even in the event that the previous | ||
530 | * operation that used the sequence number received an error. The only | ||
531 | * exception to this rule is if the previous operation received one of | ||
532 | * the following errors: NFSERR_STALE_CLIENTID, NFSERR_STALE_STATEID, | ||
533 | * NFSERR_BAD_STATEID, NFSERR_BAD_SEQID, NFSERR_BADXDR, | ||
534 | * NFSERR_RESOURCE, NFSERR_NOFILEHANDLE. | ||
535 | * | ||
536 | */ | ||
537 | #define seqid_mutating_err(err) \ | ||
538 | (((err) != NFSERR_STALE_CLIENTID) && \ | ||
539 | ((err) != NFSERR_STALE_STATEID) && \ | ||
540 | ((err) != NFSERR_BAD_STATEID) && \ | ||
541 | ((err) != NFSERR_BAD_SEQID) && \ | ||
542 | ((err) != NFSERR_BAD_XDR) && \ | ||
543 | ((err) != NFSERR_RESOURCE) && \ | ||
544 | ((err) != NFSERR_NOFILEHANDLE)) | ||
545 | |||
546 | enum nfs4_client_state { | ||
547 | NFS4CLNT_OK = 0, | ||
548 | }; | ||
549 | |||
550 | /* | ||
551 | * The nfs4_client identifies our client state to the server. | ||
552 | */ | ||
553 | struct nfs4_client { | ||
554 | struct list_head cl_servers; /* Global list of servers */ | ||
555 | struct in_addr cl_addr; /* Server identifier */ | ||
556 | u64 cl_clientid; /* constant */ | ||
557 | nfs4_verifier cl_confirm; | ||
558 | unsigned long cl_state; | ||
559 | |||
560 | u32 cl_lockowner_id; | ||
561 | |||
562 | /* | ||
563 | * The following rwsem ensures exclusive access to the server | ||
564 | * while we recover the state following a lease expiration. | ||
565 | */ | ||
566 | struct rw_semaphore cl_sem; | ||
567 | |||
568 | struct list_head cl_delegations; | ||
569 | struct list_head cl_state_owners; | ||
570 | struct list_head cl_unused; | ||
571 | int cl_nunused; | ||
572 | spinlock_t cl_lock; | ||
573 | atomic_t cl_count; | ||
574 | |||
575 | struct rpc_clnt * cl_rpcclient; | ||
576 | struct rpc_cred * cl_cred; | ||
577 | |||
578 | struct list_head cl_superblocks; /* List of nfs_server structs */ | ||
579 | |||
580 | unsigned long cl_lease_time; | ||
581 | unsigned long cl_last_renewal; | ||
582 | struct work_struct cl_renewd; | ||
583 | struct work_struct cl_recoverd; | ||
584 | |||
585 | wait_queue_head_t cl_waitq; | ||
586 | struct rpc_wait_queue cl_rpcwaitq; | ||
587 | |||
588 | /* used for the setclientid verifier */ | ||
589 | struct timespec cl_boot_time; | ||
590 | |||
591 | /* idmapper */ | ||
592 | struct idmap * cl_idmap; | ||
593 | |||
594 | /* Our own IP address, as a null-terminated string. | ||
595 | * This is used to generate the clientid, and the callback address. | ||
596 | */ | ||
597 | char cl_ipaddr[16]; | ||
598 | unsigned char cl_id_uniquifier; | ||
599 | }; | ||
600 | |||
601 | /* | ||
602 | * NFS4 state_owners and lock_owners are simply labels for ordered | ||
603 | * sequences of RPC calls. Their sole purpose is to provide once-only | ||
604 | * semantics by allowing the server to identify replayed requests. | ||
605 | * | ||
606 | * The ->so_sema is held during all state_owner seqid-mutating operations: | ||
607 | * OPEN, OPEN_DOWNGRADE, and CLOSE. Its purpose is to properly serialize | ||
608 | * so_seqid. | ||
609 | */ | ||
610 | struct nfs4_state_owner { | ||
611 | struct list_head so_list; /* per-clientid list of state_owners */ | ||
612 | struct nfs4_client *so_client; | ||
613 | u32 so_id; /* 32-bit identifier, unique */ | ||
614 | struct semaphore so_sema; | ||
615 | u32 so_seqid; /* protected by so_sema */ | ||
616 | atomic_t so_count; | ||
617 | |||
618 | struct rpc_cred *so_cred; /* Associated cred */ | ||
619 | struct list_head so_states; | ||
620 | struct list_head so_delegations; | ||
621 | }; | ||
622 | |||
623 | /* | ||
624 | * struct nfs4_state maintains the client-side state for a given | ||
625 | * (state_owner,inode) tuple (OPEN) or state_owner (LOCK). | ||
626 | * | ||
627 | * OPEN: | ||
628 | * In order to know when to OPEN_DOWNGRADE or CLOSE the state on the server, | ||
629 | * we need to know how many files are open for reading or writing on a | ||
630 | * given inode. This information too is stored here. | ||
631 | * | ||
632 | * LOCK: one nfs4_state (LOCK) to hold the lock stateid nfs4_state(OPEN) | ||
633 | */ | ||
634 | |||
635 | struct nfs4_lock_state { | ||
636 | struct list_head ls_locks; /* Other lock stateids */ | ||
637 | fl_owner_t ls_owner; /* POSIX lock owner */ | ||
638 | #define NFS_LOCK_INITIALIZED 1 | ||
639 | int ls_flags; | ||
640 | u32 ls_seqid; | ||
641 | u32 ls_id; | ||
642 | nfs4_stateid ls_stateid; | ||
643 | atomic_t ls_count; | ||
644 | }; | ||
645 | |||
646 | /* bits for nfs4_state->flags */ | ||
647 | enum { | ||
648 | LK_STATE_IN_USE, | ||
649 | NFS_DELEGATED_STATE, | ||
650 | }; | ||
651 | |||
652 | struct nfs4_state { | ||
653 | struct list_head open_states; /* List of states for the same state_owner */ | ||
654 | struct list_head inode_states; /* List of states for the same inode */ | ||
655 | struct list_head lock_states; /* List of subservient lock stateids */ | ||
656 | |||
657 | struct nfs4_state_owner *owner; /* Pointer to the open owner */ | ||
658 | struct inode *inode; /* Pointer to the inode */ | ||
659 | |||
660 | unsigned long flags; /* Do we hold any locks? */ | ||
661 | struct semaphore lock_sema; /* Serializes file locking operations */ | ||
662 | rwlock_t state_lock; /* Protects the lock_states list */ | ||
663 | |||
664 | nfs4_stateid stateid; | ||
665 | |||
666 | unsigned int nreaders; | ||
667 | unsigned int nwriters; | ||
668 | int state; /* State on the server (R,W, or RW) */ | ||
669 | atomic_t count; | ||
670 | }; | ||
671 | |||
672 | |||
673 | struct nfs4_exception { | ||
674 | long timeout; | ||
675 | int retry; | ||
676 | }; | ||
677 | |||
678 | struct nfs4_state_recovery_ops { | ||
679 | int (*recover_open)(struct nfs4_state_owner *, struct nfs4_state *); | ||
680 | int (*recover_lock)(struct nfs4_state *, struct file_lock *); | ||
681 | }; | ||
682 | |||
683 | extern struct dentry_operations nfs4_dentry_operations; | ||
684 | extern struct inode_operations nfs4_dir_inode_operations; | ||
685 | |||
686 | /* nfs4proc.c */ | ||
687 | extern int nfs4_map_errors(int err); | ||
688 | extern int nfs4_proc_setclientid(struct nfs4_client *, u32, unsigned short); | ||
689 | extern int nfs4_proc_setclientid_confirm(struct nfs4_client *); | ||
690 | extern int nfs4_proc_async_renew(struct nfs4_client *); | ||
691 | extern int nfs4_proc_renew(struct nfs4_client *); | ||
692 | extern int nfs4_do_close(struct inode *inode, struct nfs4_state *state, mode_t mode); | ||
693 | extern struct inode *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); | ||
694 | extern int nfs4_open_revalidate(struct inode *, struct dentry *, int); | ||
695 | |||
696 | extern struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops; | ||
697 | extern struct nfs4_state_recovery_ops nfs4_network_partition_recovery_ops; | ||
698 | |||
699 | /* nfs4renewd.c */ | ||
700 | extern void nfs4_schedule_state_renewal(struct nfs4_client *); | ||
701 | extern void nfs4_renewd_prepare_shutdown(struct nfs_server *); | ||
702 | extern void nfs4_kill_renewd(struct nfs4_client *); | ||
703 | |||
704 | /* nfs4state.c */ | ||
705 | extern void init_nfsv4_state(struct nfs_server *); | ||
706 | extern void destroy_nfsv4_state(struct nfs_server *); | ||
707 | extern struct nfs4_client *nfs4_get_client(struct in_addr *); | ||
708 | extern void nfs4_put_client(struct nfs4_client *clp); | ||
709 | extern int nfs4_init_client(struct nfs4_client *clp); | ||
710 | extern struct nfs4_client *nfs4_find_client(struct in_addr *); | ||
711 | extern u32 nfs4_alloc_lockowner_id(struct nfs4_client *); | ||
712 | |||
713 | extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *); | ||
714 | extern void nfs4_put_state_owner(struct nfs4_state_owner *); | ||
715 | extern void nfs4_drop_state_owner(struct nfs4_state_owner *); | ||
716 | extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state_owner *); | ||
717 | extern void nfs4_put_open_state(struct nfs4_state *); | ||
718 | extern void nfs4_close_state(struct nfs4_state *, mode_t); | ||
719 | extern struct nfs4_state *nfs4_find_state(struct inode *, struct rpc_cred *, mode_t mode); | ||
720 | extern void nfs4_increment_seqid(int status, struct nfs4_state_owner *sp); | ||
721 | extern void nfs4_schedule_state_recovery(struct nfs4_client *); | ||
722 | extern struct nfs4_lock_state *nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t); | ||
723 | extern struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_owner_t); | ||
724 | extern void nfs4_put_lock_state(struct nfs4_lock_state *state); | ||
725 | extern void nfs4_increment_lock_seqid(int status, struct nfs4_lock_state *ls); | ||
726 | extern void nfs4_notify_setlk(struct nfs4_state *, struct file_lock *, struct nfs4_lock_state *); | ||
727 | extern void nfs4_notify_unlck(struct nfs4_state *, struct file_lock *, struct nfs4_lock_state *); | ||
728 | extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t); | ||
729 | |||
730 | |||
731 | |||
732 | struct nfs4_mount_data; | ||
733 | #else | ||
734 | #define init_nfsv4_state(server) do { } while (0) | ||
735 | #define destroy_nfsv4_state(server) do { } while (0) | ||
736 | #define nfs4_put_state_owner(inode, owner) do { } while (0) | ||
737 | #define nfs4_put_open_state(state) do { } while (0) | ||
738 | #define nfs4_close_state(a, b) do { } while (0) | ||
739 | #define nfs4_renewd_prepare_shutdown(server) do { } while (0) | ||
740 | #endif | ||
741 | |||
742 | #endif /* __KERNEL__ */ | 554 | #endif /* __KERNEL__ */ |
743 | 555 | ||
744 | /* | 556 | /* |
diff --git a/include/linux/nfs_fs_i.h b/include/linux/nfs_fs_i.h index e9a749588a7b..e2c18dabff86 100644 --- a/include/linux/nfs_fs_i.h +++ b/include/linux/nfs_fs_i.h | |||
@@ -16,6 +16,11 @@ struct nfs_lock_info { | |||
16 | struct nlm_lockowner *owner; | 16 | struct nlm_lockowner *owner; |
17 | }; | 17 | }; |
18 | 18 | ||
19 | struct nfs4_lock_state; | ||
20 | struct nfs4_lock_info { | ||
21 | struct nfs4_lock_state *owner; | ||
22 | }; | ||
23 | |||
19 | /* | 24 | /* |
20 | * Lock flag values | 25 | * Lock flag values |
21 | */ | 26 | */ |
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index fc51645d61ee..3d3a305488cf 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h | |||
@@ -10,6 +10,7 @@ | |||
10 | struct nfs_server { | 10 | struct nfs_server { |
11 | struct rpc_clnt * client; /* RPC client handle */ | 11 | struct rpc_clnt * client; /* RPC client handle */ |
12 | struct rpc_clnt * client_sys; /* 2nd handle for FSINFO */ | 12 | struct rpc_clnt * client_sys; /* 2nd handle for FSINFO */ |
13 | struct rpc_clnt * client_acl; /* ACL RPC client handle */ | ||
13 | struct nfs_rpc_ops * rpc_ops; /* NFS protocol vector */ | 14 | struct nfs_rpc_ops * rpc_ops; /* NFS protocol vector */ |
14 | struct backing_dev_info backing_dev_info; | 15 | struct backing_dev_info backing_dev_info; |
15 | int flags; /* various flags */ | 16 | int flags; /* various flags */ |
diff --git a/include/linux/nfs_mount.h b/include/linux/nfs_mount.h index 0071428231f9..659c75438454 100644 --- a/include/linux/nfs_mount.h +++ b/include/linux/nfs_mount.h | |||
@@ -58,6 +58,7 @@ struct nfs_mount_data { | |||
58 | #define NFS_MOUNT_KERBEROS 0x0100 /* 3 */ | 58 | #define NFS_MOUNT_KERBEROS 0x0100 /* 3 */ |
59 | #define NFS_MOUNT_NONLM 0x0200 /* 3 */ | 59 | #define NFS_MOUNT_NONLM 0x0200 /* 3 */ |
60 | #define NFS_MOUNT_BROKEN_SUID 0x0400 /* 4 */ | 60 | #define NFS_MOUNT_BROKEN_SUID 0x0400 /* 4 */ |
61 | #define NFS_MOUNT_NOACL 0x0800 /* 4 */ | ||
61 | #define NFS_MOUNT_STRICTLOCK 0x1000 /* reserved for NFSv4 */ | 62 | #define NFS_MOUNT_STRICTLOCK 0x1000 /* reserved for NFSv4 */ |
62 | #define NFS_MOUNT_SECFLAVOUR 0x2000 /* 5 */ | 63 | #define NFS_MOUNT_SECFLAVOUR 0x2000 /* 5 */ |
63 | #define NFS_MOUNT_FLAGMASK 0xFFFF | 64 | #define NFS_MOUNT_FLAGMASK 0xFFFF |
diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h index 39e4895bcdb4..da2e077b65e2 100644 --- a/include/linux/nfs_page.h +++ b/include/linux/nfs_page.h | |||
@@ -20,12 +20,19 @@ | |||
20 | #include <asm/atomic.h> | 20 | #include <asm/atomic.h> |
21 | 21 | ||
22 | /* | 22 | /* |
23 | * Valid flags for the radix tree | ||
24 | */ | ||
25 | #define NFS_PAGE_TAG_DIRTY 0 | ||
26 | #define NFS_PAGE_TAG_WRITEBACK 1 | ||
27 | |||
28 | /* | ||
23 | * Valid flags for a dirty buffer | 29 | * Valid flags for a dirty buffer |
24 | */ | 30 | */ |
25 | #define PG_BUSY 0 | 31 | #define PG_BUSY 0 |
26 | #define PG_NEED_COMMIT 1 | 32 | #define PG_NEED_COMMIT 1 |
27 | #define PG_NEED_RESCHED 2 | 33 | #define PG_NEED_RESCHED 2 |
28 | 34 | ||
35 | struct nfs_inode; | ||
29 | struct nfs_page { | 36 | struct nfs_page { |
30 | struct list_head wb_list, /* Defines state of page: */ | 37 | struct list_head wb_list, /* Defines state of page: */ |
31 | *wb_list_head; /* read/write/commit */ | 38 | *wb_list_head; /* read/write/commit */ |
@@ -54,14 +61,17 @@ extern void nfs_clear_request(struct nfs_page *req); | |||
54 | extern void nfs_release_request(struct nfs_page *req); | 61 | extern void nfs_release_request(struct nfs_page *req); |
55 | 62 | ||
56 | 63 | ||
57 | extern void nfs_list_add_request(struct nfs_page *, struct list_head *); | 64 | extern int nfs_scan_lock_dirty(struct nfs_inode *nfsi, struct list_head *dst, |
58 | 65 | unsigned long idx_start, unsigned int npages); | |
59 | extern int nfs_scan_list(struct list_head *, struct list_head *, | 66 | extern int nfs_scan_list(struct list_head *, struct list_head *, |
60 | unsigned long, unsigned int); | 67 | unsigned long, unsigned int); |
61 | extern int nfs_coalesce_requests(struct list_head *, struct list_head *, | 68 | extern int nfs_coalesce_requests(struct list_head *, struct list_head *, |
62 | unsigned int); | 69 | unsigned int); |
63 | extern int nfs_wait_on_request(struct nfs_page *); | 70 | extern int nfs_wait_on_request(struct nfs_page *); |
64 | extern void nfs_unlock_request(struct nfs_page *req); | 71 | extern void nfs_unlock_request(struct nfs_page *req); |
72 | extern int nfs_set_page_writeback_locked(struct nfs_page *req); | ||
73 | extern void nfs_clear_page_writeback(struct nfs_page *req); | ||
74 | |||
65 | 75 | ||
66 | /* | 76 | /* |
67 | * Lock the page of an asynchronous request without incrementing the wb_count | 77 | * Lock the page of an asynchronous request without incrementing the wb_count |
@@ -86,6 +96,18 @@ nfs_lock_request(struct nfs_page *req) | |||
86 | return 1; | 96 | return 1; |
87 | } | 97 | } |
88 | 98 | ||
99 | /** | ||
100 | * nfs_list_add_request - Insert a request into a list | ||
101 | * @req: request | ||
102 | * @head: head of list into which to insert the request. | ||
103 | */ | ||
104 | static inline void | ||
105 | nfs_list_add_request(struct nfs_page *req, struct list_head *head) | ||
106 | { | ||
107 | list_add_tail(&req->wb_list, head); | ||
108 | req->wb_list_head = head; | ||
109 | } | ||
110 | |||
89 | 111 | ||
90 | /** | 112 | /** |
91 | * nfs_list_remove_request - Remove a request from its wb_list | 113 | * nfs_list_remove_request - Remove a request from its wb_list |
@@ -96,10 +118,6 @@ nfs_list_remove_request(struct nfs_page *req) | |||
96 | { | 118 | { |
97 | if (list_empty(&req->wb_list)) | 119 | if (list_empty(&req->wb_list)) |
98 | return; | 120 | return; |
99 | if (!NFS_WBACK_BUSY(req)) { | ||
100 | printk(KERN_ERR "NFS: unlocked request attempted removed from list!\n"); | ||
101 | BUG(); | ||
102 | } | ||
103 | list_del_init(&req->wb_list); | 121 | list_del_init(&req->wb_list); |
104 | req->wb_list_head = NULL; | 122 | req->wb_list_head = NULL; |
105 | } | 123 | } |
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 47037d9521cb..a2bf6914ff1b 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h | |||
@@ -2,6 +2,7 @@ | |||
2 | #define _LINUX_NFS_XDR_H | 2 | #define _LINUX_NFS_XDR_H |
3 | 3 | ||
4 | #include <linux/sunrpc/xprt.h> | 4 | #include <linux/sunrpc/xprt.h> |
5 | #include <linux/nfsacl.h> | ||
5 | 6 | ||
6 | struct nfs4_fsid { | 7 | struct nfs4_fsid { |
7 | __u64 major; | 8 | __u64 major; |
@@ -326,6 +327,20 @@ struct nfs_setattrargs { | |||
326 | const u32 * bitmask; | 327 | const u32 * bitmask; |
327 | }; | 328 | }; |
328 | 329 | ||
330 | struct nfs_setaclargs { | ||
331 | struct nfs_fh * fh; | ||
332 | size_t acl_len; | ||
333 | unsigned int acl_pgbase; | ||
334 | struct page ** acl_pages; | ||
335 | }; | ||
336 | |||
337 | struct nfs_getaclargs { | ||
338 | struct nfs_fh * fh; | ||
339 | size_t acl_len; | ||
340 | unsigned int acl_pgbase; | ||
341 | struct page ** acl_pages; | ||
342 | }; | ||
343 | |||
329 | struct nfs_setattrres { | 344 | struct nfs_setattrres { |
330 | struct nfs_fattr * fattr; | 345 | struct nfs_fattr * fattr; |
331 | const struct nfs_server * server; | 346 | const struct nfs_server * server; |
@@ -354,6 +369,20 @@ struct nfs_readdirargs { | |||
354 | struct page ** pages; | 369 | struct page ** pages; |
355 | }; | 370 | }; |
356 | 371 | ||
372 | struct nfs3_getaclargs { | ||
373 | struct nfs_fh * fh; | ||
374 | int mask; | ||
375 | struct page ** pages; | ||
376 | }; | ||
377 | |||
378 | struct nfs3_setaclargs { | ||
379 | struct inode * inode; | ||
380 | int mask; | ||
381 | struct posix_acl * acl_access; | ||
382 | struct posix_acl * acl_default; | ||
383 | struct page ** pages; | ||
384 | }; | ||
385 | |||
357 | struct nfs_diropok { | 386 | struct nfs_diropok { |
358 | struct nfs_fh * fh; | 387 | struct nfs_fh * fh; |
359 | struct nfs_fattr * fattr; | 388 | struct nfs_fattr * fattr; |
@@ -477,6 +506,15 @@ struct nfs3_readdirres { | |||
477 | int plus; | 506 | int plus; |
478 | }; | 507 | }; |
479 | 508 | ||
509 | struct nfs3_getaclres { | ||
510 | struct nfs_fattr * fattr; | ||
511 | int mask; | ||
512 | unsigned int acl_access_count; | ||
513 | unsigned int acl_default_count; | ||
514 | struct posix_acl * acl_access; | ||
515 | struct posix_acl * acl_default; | ||
516 | }; | ||
517 | |||
480 | #ifdef CONFIG_NFS_V4 | 518 | #ifdef CONFIG_NFS_V4 |
481 | 519 | ||
482 | typedef u64 clientid4; | 520 | typedef u64 clientid4; |
@@ -667,6 +705,7 @@ struct nfs_rpc_ops { | |||
667 | int version; /* Protocol version */ | 705 | int version; /* Protocol version */ |
668 | struct dentry_operations *dentry_ops; | 706 | struct dentry_operations *dentry_ops; |
669 | struct inode_operations *dir_inode_ops; | 707 | struct inode_operations *dir_inode_ops; |
708 | struct inode_operations *file_inode_ops; | ||
670 | 709 | ||
671 | int (*getroot) (struct nfs_server *, struct nfs_fh *, | 710 | int (*getroot) (struct nfs_server *, struct nfs_fh *, |
672 | struct nfs_fsinfo *); | 711 | struct nfs_fsinfo *); |
@@ -713,6 +752,7 @@ struct nfs_rpc_ops { | |||
713 | int (*file_open) (struct inode *, struct file *); | 752 | int (*file_open) (struct inode *, struct file *); |
714 | int (*file_release) (struct inode *, struct file *); | 753 | int (*file_release) (struct inode *, struct file *); |
715 | int (*lock)(struct file *, int, struct file_lock *); | 754 | int (*lock)(struct file *, int, struct file_lock *); |
755 | void (*clear_acl_cache)(struct inode *); | ||
716 | }; | 756 | }; |
717 | 757 | ||
718 | /* | 758 | /* |
@@ -732,4 +772,7 @@ extern struct rpc_version nfs_version2; | |||
732 | extern struct rpc_version nfs_version3; | 772 | extern struct rpc_version nfs_version3; |
733 | extern struct rpc_version nfs_version4; | 773 | extern struct rpc_version nfs_version4; |
734 | 774 | ||
775 | extern struct rpc_version nfsacl_version3; | ||
776 | extern struct rpc_program nfsacl_program; | ||
777 | |||
735 | #endif | 778 | #endif |
diff --git a/include/linux/nfsacl.h b/include/linux/nfsacl.h new file mode 100644 index 000000000000..54487a99beb8 --- /dev/null +++ b/include/linux/nfsacl.h | |||
@@ -0,0 +1,58 @@ | |||
1 | /* | ||
2 | * File: linux/nfsacl.h | ||
3 | * | ||
4 | * (C) 2003 Andreas Gruenbacher <agruen@suse.de> | ||
5 | */ | ||
6 | #ifndef __LINUX_NFSACL_H | ||
7 | #define __LINUX_NFSACL_H | ||
8 | |||
9 | #define NFS_ACL_PROGRAM 100227 | ||
10 | |||
11 | #define ACLPROC2_GETACL 1 | ||
12 | #define ACLPROC2_SETACL 2 | ||
13 | #define ACLPROC2_GETATTR 3 | ||
14 | #define ACLPROC2_ACCESS 4 | ||
15 | |||
16 | #define ACLPROC3_GETACL 1 | ||
17 | #define ACLPROC3_SETACL 2 | ||
18 | |||
19 | |||
20 | /* Flags for the getacl/setacl mode */ | ||
21 | #define NFS_ACL 0x0001 | ||
22 | #define NFS_ACLCNT 0x0002 | ||
23 | #define NFS_DFACL 0x0004 | ||
24 | #define NFS_DFACLCNT 0x0008 | ||
25 | |||
26 | /* Flag for Default ACL entries */ | ||
27 | #define NFS_ACL_DEFAULT 0x1000 | ||
28 | |||
29 | #ifdef __KERNEL__ | ||
30 | |||
31 | #include <linux/posix_acl.h> | ||
32 | |||
33 | /* Maximum number of ACL entries over NFS */ | ||
34 | #define NFS_ACL_MAX_ENTRIES 1024 | ||
35 | |||
36 | #define NFSACL_MAXWORDS (2*(2+3*NFS_ACL_MAX_ENTRIES)) | ||
37 | #define NFSACL_MAXPAGES ((2*(8+12*NFS_ACL_MAX_ENTRIES) + PAGE_SIZE-1) \ | ||
38 | >> PAGE_SHIFT) | ||
39 | |||
40 | static inline unsigned int | ||
41 | nfsacl_size(struct posix_acl *acl_access, struct posix_acl *acl_default) | ||
42 | { | ||
43 | unsigned int w = 16; | ||
44 | w += max(acl_access ? (int)acl_access->a_count : 3, 4) * 12; | ||
45 | if (acl_default) | ||
46 | w += max((int)acl_default->a_count, 4) * 12; | ||
47 | return w; | ||
48 | } | ||
49 | |||
50 | extern unsigned int | ||
51 | nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode, | ||
52 | struct posix_acl *acl, int encode_entries, int typeflag); | ||
53 | extern unsigned int | ||
54 | nfsacl_decode(struct xdr_buf *buf, unsigned int base, unsigned int *aclcnt, | ||
55 | struct posix_acl **pacl); | ||
56 | |||
57 | #endif /* __KERNEL__ */ | ||
58 | #endif /* __LINUX_NFSACL_H */ | ||
diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h index 8f85d9a59607..4bf931d5ff56 100644 --- a/include/linux/nfsd/nfsd.h +++ b/include/linux/nfsd/nfsd.h | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/unistd.h> | 15 | #include <linux/unistd.h> |
16 | #include <linux/dirent.h> | 16 | #include <linux/dirent.h> |
17 | #include <linux/fs.h> | 17 | #include <linux/fs.h> |
18 | #include <linux/posix_acl.h> | ||
18 | #include <linux/mount.h> | 19 | #include <linux/mount.h> |
19 | 20 | ||
20 | #include <linux/nfsd/debug.h> | 21 | #include <linux/nfsd/debug.h> |
@@ -124,6 +125,21 @@ int nfsd_statfs(struct svc_rqst *, struct svc_fh *, | |||
124 | int nfsd_notify_change(struct inode *, struct iattr *); | 125 | int nfsd_notify_change(struct inode *, struct iattr *); |
125 | int nfsd_permission(struct svc_export *, struct dentry *, int); | 126 | int nfsd_permission(struct svc_export *, struct dentry *, int); |
126 | 127 | ||
128 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) | ||
129 | #ifdef CONFIG_NFSD_V2_ACL | ||
130 | extern struct svc_version nfsd_acl_version2; | ||
131 | #else | ||
132 | #define nfsd_acl_version2 NULL | ||
133 | #endif | ||
134 | #ifdef CONFIG_NFSD_V3_ACL | ||
135 | extern struct svc_version nfsd_acl_version3; | ||
136 | #else | ||
137 | #define nfsd_acl_version3 NULL | ||
138 | #endif | ||
139 | struct posix_acl *nfsd_get_posix_acl(struct svc_fh *, int); | ||
140 | int nfsd_set_posix_acl(struct svc_fh *, int, struct posix_acl *); | ||
141 | #endif | ||
142 | |||
127 | 143 | ||
128 | /* | 144 | /* |
129 | * NFSv4 State | 145 | * NFSv4 State |
diff --git a/include/linux/nfsd/xdr.h b/include/linux/nfsd/xdr.h index ecccef777dae..130d4f588a37 100644 --- a/include/linux/nfsd/xdr.h +++ b/include/linux/nfsd/xdr.h | |||
@@ -169,4 +169,8 @@ int nfssvc_encode_entry(struct readdir_cd *, const char *name, | |||
169 | 169 | ||
170 | int nfssvc_release_fhandle(struct svc_rqst *, u32 *, struct nfsd_fhandle *); | 170 | int nfssvc_release_fhandle(struct svc_rqst *, u32 *, struct nfsd_fhandle *); |
171 | 171 | ||
172 | /* Helper functions for NFSv2 ACL code */ | ||
173 | u32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp); | ||
174 | u32 *nfs2svc_decode_fh(u32 *p, struct svc_fh *fhp); | ||
175 | |||
172 | #endif /* LINUX_NFSD_H */ | 176 | #endif /* LINUX_NFSD_H */ |
diff --git a/include/linux/nfsd/xdr3.h b/include/linux/nfsd/xdr3.h index 0ae9e0ef5f68..21e18ce7ca63 100644 --- a/include/linux/nfsd/xdr3.h +++ b/include/linux/nfsd/xdr3.h | |||
@@ -110,6 +110,19 @@ struct nfsd3_commitargs { | |||
110 | __u32 count; | 110 | __u32 count; |
111 | }; | 111 | }; |
112 | 112 | ||
113 | struct nfsd3_getaclargs { | ||
114 | struct svc_fh fh; | ||
115 | int mask; | ||
116 | }; | ||
117 | |||
118 | struct posix_acl; | ||
119 | struct nfsd3_setaclargs { | ||
120 | struct svc_fh fh; | ||
121 | int mask; | ||
122 | struct posix_acl *acl_access; | ||
123 | struct posix_acl *acl_default; | ||
124 | }; | ||
125 | |||
113 | struct nfsd3_attrstat { | 126 | struct nfsd3_attrstat { |
114 | __u32 status; | 127 | __u32 status; |
115 | struct svc_fh fh; | 128 | struct svc_fh fh; |
@@ -209,6 +222,14 @@ struct nfsd3_commitres { | |||
209 | struct svc_fh fh; | 222 | struct svc_fh fh; |
210 | }; | 223 | }; |
211 | 224 | ||
225 | struct nfsd3_getaclres { | ||
226 | __u32 status; | ||
227 | struct svc_fh fh; | ||
228 | int mask; | ||
229 | struct posix_acl *acl_access; | ||
230 | struct posix_acl *acl_default; | ||
231 | }; | ||
232 | |||
212 | /* dummy type for release */ | 233 | /* dummy type for release */ |
213 | struct nfsd3_fhandle_pair { | 234 | struct nfsd3_fhandle_pair { |
214 | __u32 dummy; | 235 | __u32 dummy; |
@@ -241,6 +262,7 @@ union nfsd3_xdrstore { | |||
241 | struct nfsd3_fsinfores fsinfores; | 262 | struct nfsd3_fsinfores fsinfores; |
242 | struct nfsd3_pathconfres pathconfres; | 263 | struct nfsd3_pathconfres pathconfres; |
243 | struct nfsd3_commitres commitres; | 264 | struct nfsd3_commitres commitres; |
265 | struct nfsd3_getaclres getaclres; | ||
244 | }; | 266 | }; |
245 | 267 | ||
246 | #define NFS3_SVC_XDRSIZE sizeof(union nfsd3_xdrstore) | 268 | #define NFS3_SVC_XDRSIZE sizeof(union nfsd3_xdrstore) |
@@ -316,6 +338,10 @@ int nfs3svc_encode_entry(struct readdir_cd *, const char *name, | |||
316 | int nfs3svc_encode_entry_plus(struct readdir_cd *, const char *name, | 338 | int nfs3svc_encode_entry_plus(struct readdir_cd *, const char *name, |
317 | int namlen, loff_t offset, ino_t ino, | 339 | int namlen, loff_t offset, ino_t ino, |
318 | unsigned int); | 340 | unsigned int); |
341 | /* Helper functions for NFSv3 ACL code */ | ||
342 | u32 *nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, | ||
343 | struct svc_fh *fhp); | ||
344 | u32 *nfs3svc_decode_fh(u32 *p, struct svc_fh *fhp); | ||
319 | 345 | ||
320 | 346 | ||
321 | #endif /* _LINUX_NFSD_XDR3_H */ | 347 | #endif /* _LINUX_NFSD_XDR3_H */ |
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index 2709caf4d128..ab151bbb66df 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h | |||
@@ -111,6 +111,11 @@ struct rpc_procinfo { | |||
111 | struct rpc_clnt *rpc_create_client(struct rpc_xprt *xprt, char *servname, | 111 | struct rpc_clnt *rpc_create_client(struct rpc_xprt *xprt, char *servname, |
112 | struct rpc_program *info, | 112 | struct rpc_program *info, |
113 | u32 version, rpc_authflavor_t authflavor); | 113 | u32 version, rpc_authflavor_t authflavor); |
114 | struct rpc_clnt *rpc_new_client(struct rpc_xprt *xprt, char *servname, | ||
115 | struct rpc_program *info, | ||
116 | u32 version, rpc_authflavor_t authflavor); | ||
117 | struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *, | ||
118 | struct rpc_program *, int); | ||
114 | struct rpc_clnt *rpc_clone_client(struct rpc_clnt *); | 119 | struct rpc_clnt *rpc_clone_client(struct rpc_clnt *); |
115 | int rpc_shutdown_client(struct rpc_clnt *); | 120 | int rpc_shutdown_client(struct rpc_clnt *); |
116 | int rpc_destroy_client(struct rpc_clnt *); | 121 | int rpc_destroy_client(struct rpc_clnt *); |
@@ -129,6 +134,7 @@ void rpc_clnt_sigmask(struct rpc_clnt *clnt, sigset_t *oldset); | |||
129 | void rpc_clnt_sigunmask(struct rpc_clnt *clnt, sigset_t *oldset); | 134 | void rpc_clnt_sigunmask(struct rpc_clnt *clnt, sigset_t *oldset); |
130 | void rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int); | 135 | void rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int); |
131 | size_t rpc_max_payload(struct rpc_clnt *); | 136 | size_t rpc_max_payload(struct rpc_clnt *); |
137 | int rpc_ping(struct rpc_clnt *clnt, int flags); | ||
132 | 138 | ||
133 | static __inline__ | 139 | static __inline__ |
134 | int rpc_call(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, int flags) | 140 | int rpc_call(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, int flags) |
diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index 99d17ed7cebb..4d77e90d0b30 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h | |||
@@ -31,7 +31,6 @@ struct rpc_wait_queue; | |||
31 | struct rpc_wait { | 31 | struct rpc_wait { |
32 | struct list_head list; /* wait queue links */ | 32 | struct list_head list; /* wait queue links */ |
33 | struct list_head links; /* Links to related tasks */ | 33 | struct list_head links; /* Links to related tasks */ |
34 | wait_queue_head_t waitq; /* sync: sleep on this q */ | ||
35 | struct rpc_wait_queue * rpc_waitq; /* RPC wait queue we're on */ | 34 | struct rpc_wait_queue * rpc_waitq; /* RPC wait queue we're on */ |
36 | }; | 35 | }; |
37 | 36 | ||
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index 37003970cf2e..5af8800e0ce3 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h | |||
@@ -185,6 +185,17 @@ xdr_ressize_check(struct svc_rqst *rqstp, u32 *p) | |||
185 | return vec->iov_len <= PAGE_SIZE; | 185 | return vec->iov_len <= PAGE_SIZE; |
186 | } | 186 | } |
187 | 187 | ||
188 | static inline struct page * | ||
189 | svc_take_res_page(struct svc_rqst *rqstp) | ||
190 | { | ||
191 | if (rqstp->rq_arghi <= rqstp->rq_argused) | ||
192 | return NULL; | ||
193 | rqstp->rq_arghi--; | ||
194 | rqstp->rq_respages[rqstp->rq_resused] = | ||
195 | rqstp->rq_argpages[rqstp->rq_arghi]; | ||
196 | return rqstp->rq_respages[rqstp->rq_resused++]; | ||
197 | } | ||
198 | |||
188 | static inline int svc_take_page(struct svc_rqst *rqstp) | 199 | static inline int svc_take_page(struct svc_rqst *rqstp) |
189 | { | 200 | { |
190 | if (rqstp->rq_arghi <= rqstp->rq_argused) | 201 | if (rqstp->rq_arghi <= rqstp->rq_argused) |
@@ -240,9 +251,10 @@ struct svc_deferred_req { | |||
240 | }; | 251 | }; |
241 | 252 | ||
242 | /* | 253 | /* |
243 | * RPC program | 254 | * List of RPC programs on the same transport endpoint |
244 | */ | 255 | */ |
245 | struct svc_program { | 256 | struct svc_program { |
257 | struct svc_program * pg_next; /* other programs (same xprt) */ | ||
246 | u32 pg_prog; /* program number */ | 258 | u32 pg_prog; /* program number */ |
247 | unsigned int pg_lovers; /* lowest version */ | 259 | unsigned int pg_lovers; /* lowest version */ |
248 | unsigned int pg_hivers; /* lowest version */ | 260 | unsigned int pg_hivers; /* lowest version */ |
diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h index 541dcf838abf..34ec3e8d99b3 100644 --- a/include/linux/sunrpc/xdr.h +++ b/include/linux/sunrpc/xdr.h | |||
@@ -146,7 +146,8 @@ extern void xdr_shift_buf(struct xdr_buf *, size_t); | |||
146 | extern void xdr_buf_from_iov(struct kvec *, struct xdr_buf *); | 146 | extern void xdr_buf_from_iov(struct kvec *, struct xdr_buf *); |
147 | extern int xdr_buf_subsegment(struct xdr_buf *, struct xdr_buf *, int, int); | 147 | extern int xdr_buf_subsegment(struct xdr_buf *, struct xdr_buf *, int, int); |
148 | extern int xdr_buf_read_netobj(struct xdr_buf *, struct xdr_netobj *, int); | 148 | extern int xdr_buf_read_netobj(struct xdr_buf *, struct xdr_netobj *, int); |
149 | extern int read_bytes_from_xdr_buf(struct xdr_buf *buf, int base, void *obj, int len); | 149 | extern int read_bytes_from_xdr_buf(struct xdr_buf *, int, void *, int); |
150 | extern int write_bytes_to_xdr_buf(struct xdr_buf *, int, void *, int); | ||
150 | 151 | ||
151 | /* | 152 | /* |
152 | * Helper structure for copying from an sk_buff. | 153 | * Helper structure for copying from an sk_buff. |
@@ -160,7 +161,7 @@ typedef struct { | |||
160 | 161 | ||
161 | typedef size_t (*skb_read_actor_t)(skb_reader_t *desc, void *to, size_t len); | 162 | typedef size_t (*skb_read_actor_t)(skb_reader_t *desc, void *to, size_t len); |
162 | 163 | ||
163 | extern void xdr_partial_copy_from_skb(struct xdr_buf *, unsigned int, | 164 | extern ssize_t xdr_partial_copy_from_skb(struct xdr_buf *, unsigned int, |
164 | skb_reader_t *, skb_read_actor_t); | 165 | skb_reader_t *, skb_read_actor_t); |
165 | 166 | ||
166 | struct socket; | 167 | struct socket; |
@@ -168,6 +169,22 @@ struct sockaddr; | |||
168 | extern int xdr_sendpages(struct socket *, struct sockaddr *, int, | 169 | extern int xdr_sendpages(struct socket *, struct sockaddr *, int, |
169 | struct xdr_buf *, unsigned int, int); | 170 | struct xdr_buf *, unsigned int, int); |
170 | 171 | ||
172 | extern int xdr_encode_word(struct xdr_buf *, int, u32); | ||
173 | extern int xdr_decode_word(struct xdr_buf *, int, u32 *); | ||
174 | |||
175 | struct xdr_array2_desc; | ||
176 | typedef int (*xdr_xcode_elem_t)(struct xdr_array2_desc *desc, void *elem); | ||
177 | struct xdr_array2_desc { | ||
178 | unsigned int elem_size; | ||
179 | unsigned int array_len; | ||
180 | xdr_xcode_elem_t xcode; | ||
181 | }; | ||
182 | |||
183 | extern int xdr_decode_array2(struct xdr_buf *buf, unsigned int base, | ||
184 | struct xdr_array2_desc *desc); | ||
185 | extern int xdr_encode_array2(struct xdr_buf *buf, unsigned int base, | ||
186 | struct xdr_array2_desc *desc); | ||
187 | |||
171 | /* | 188 | /* |
172 | * Provide some simple tools for XDR buffer overflow-checking etc. | 189 | * Provide some simple tools for XDR buffer overflow-checking etc. |
173 | */ | 190 | */ |
diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h index 2433e279e071..1309c12b8f71 100644 --- a/include/sound/ac97_codec.h +++ b/include/sound/ac97_codec.h | |||
@@ -437,6 +437,7 @@ struct snd_ac97_build_ops { | |||
437 | void (*suspend) (ac97_t *ac97); | 437 | void (*suspend) (ac97_t *ac97); |
438 | void (*resume) (ac97_t *ac97); | 438 | void (*resume) (ac97_t *ac97); |
439 | #endif | 439 | #endif |
440 | void (*update_jacks) (ac97_t *ac97); /* for jack-sharing */ | ||
440 | }; | 441 | }; |
441 | 442 | ||
442 | struct _snd_ac97_bus_ops { | 443 | struct _snd_ac97_bus_ops { |
@@ -516,6 +517,9 @@ struct _snd_ac97 { | |||
516 | } ad18xx; | 517 | } ad18xx; |
517 | unsigned int dev_flags; /* device specific */ | 518 | unsigned int dev_flags; /* device specific */ |
518 | } spec; | 519 | } spec; |
520 | /* jack-sharing info */ | ||
521 | unsigned char indep_surround; | ||
522 | unsigned char channel_mode; | ||
519 | }; | 523 | }; |
520 | 524 | ||
521 | /* conditions */ | 525 | /* conditions */ |
@@ -569,8 +573,8 @@ enum { | |||
569 | }; | 573 | }; |
570 | 574 | ||
571 | struct ac97_quirk { | 575 | struct ac97_quirk { |
572 | unsigned short vendor; /* PCI vendor id */ | 576 | unsigned short subvendor; /* PCI subsystem vendor id */ |
573 | unsigned short device; /* PCI device id */ | 577 | unsigned short subdevice; /* PCI sybsystem device id */ |
574 | unsigned short mask; /* device id bit mask, 0 = accept all */ | 578 | unsigned short mask; /* device id bit mask, 0 = accept all */ |
575 | unsigned int codec_id; /* codec id (if any), 0 = accept all */ | 579 | unsigned int codec_id; /* codec id (if any), 0 = accept all */ |
576 | const char *name; /* name shown as info */ | 580 | const char *name; /* name shown as info */ |
diff --git a/include/sound/asound.h b/include/sound/asound.h index a4d149f34541..9974f83cca44 100644 --- a/include/sound/asound.h +++ b/include/sound/asound.h | |||
@@ -113,9 +113,10 @@ enum sndrv_hwdep_iface { | |||
113 | SNDRV_HWDEP_IFACE_BLUETOOTH, /* Bluetooth audio */ | 113 | SNDRV_HWDEP_IFACE_BLUETOOTH, /* Bluetooth audio */ |
114 | SNDRV_HWDEP_IFACE_USX2Y_PCM, /* Tascam US122, US224 & US428 rawusb pcm */ | 114 | SNDRV_HWDEP_IFACE_USX2Y_PCM, /* Tascam US122, US224 & US428 rawusb pcm */ |
115 | SNDRV_HWDEP_IFACE_PCXHR, /* Digigram PCXHR */ | 115 | SNDRV_HWDEP_IFACE_PCXHR, /* Digigram PCXHR */ |
116 | SNDRV_HWDEP_IFACE_SB_RC, /* SB Extigy/Audigy2NX remote control */ | ||
116 | 117 | ||
117 | /* Don't forget to change the following: */ | 118 | /* Don't forget to change the following: */ |
118 | SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_PCXHR | 119 | SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_SB_RC |
119 | }; | 120 | }; |
120 | 121 | ||
121 | struct sndrv_hwdep_info { | 122 | struct sndrv_hwdep_info { |
@@ -344,7 +345,7 @@ enum sndrv_pcm_hw_param { | |||
344 | SNDRV_PCM_HW_PARAM_LAST_INTERVAL = SNDRV_PCM_HW_PARAM_TICK_TIME | 345 | SNDRV_PCM_HW_PARAM_LAST_INTERVAL = SNDRV_PCM_HW_PARAM_TICK_TIME |
345 | }; | 346 | }; |
346 | 347 | ||
347 | #define SNDRV_PCM_HW_PARAMS_RUNTIME (1<<0) | 348 | #define SNDRV_PCM_HW_PARAMS_NORESAMPLE (1<<0) /* avoid rate resampling */ |
348 | 349 | ||
349 | struct sndrv_interval { | 350 | struct sndrv_interval { |
350 | unsigned int min, max; | 351 | unsigned int min, max; |
@@ -559,7 +560,7 @@ enum { | |||
559 | * Timer section - /dev/snd/timer | 560 | * Timer section - /dev/snd/timer |
560 | */ | 561 | */ |
561 | 562 | ||
562 | #define SNDRV_TIMER_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 2) | 563 | #define SNDRV_TIMER_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 4) |
563 | 564 | ||
564 | enum sndrv_timer_class { | 565 | enum sndrv_timer_class { |
565 | SNDRV_TIMER_CLASS_NONE = -1, | 566 | SNDRV_TIMER_CLASS_NONE = -1, |
@@ -672,10 +673,11 @@ enum { | |||
672 | SNDRV_TIMER_IOCTL_INFO = _IOR('T', 0x11, struct sndrv_timer_info), | 673 | SNDRV_TIMER_IOCTL_INFO = _IOR('T', 0x11, struct sndrv_timer_info), |
673 | SNDRV_TIMER_IOCTL_PARAMS = _IOW('T', 0x12, struct sndrv_timer_params), | 674 | SNDRV_TIMER_IOCTL_PARAMS = _IOW('T', 0x12, struct sndrv_timer_params), |
674 | SNDRV_TIMER_IOCTL_STATUS = _IOR('T', 0x14, struct sndrv_timer_status), | 675 | SNDRV_TIMER_IOCTL_STATUS = _IOR('T', 0x14, struct sndrv_timer_status), |
675 | SNDRV_TIMER_IOCTL_START = _IO('T', 0x20), | 676 | /* The following four ioctls are changed since 1.0.9 due to confliction */ |
676 | SNDRV_TIMER_IOCTL_STOP = _IO('T', 0x21), | 677 | SNDRV_TIMER_IOCTL_START = _IO('T', 0xa0), |
677 | SNDRV_TIMER_IOCTL_CONTINUE = _IO('T', 0x22), | 678 | SNDRV_TIMER_IOCTL_STOP = _IO('T', 0xa1), |
678 | SNDRV_TIMER_IOCTL_PAUSE = _IO('T', 0x23), | 679 | SNDRV_TIMER_IOCTL_CONTINUE = _IO('T', 0xa2), |
680 | SNDRV_TIMER_IOCTL_PAUSE = _IO('T', 0xa3), | ||
679 | }; | 681 | }; |
680 | 682 | ||
681 | struct sndrv_timer_read { | 683 | struct sndrv_timer_read { |
diff --git a/include/sound/control.h b/include/sound/control.h index 7b9444cd02f4..ef7903c7a327 100644 --- a/include/sound/control.h +++ b/include/sound/control.h | |||
@@ -106,7 +106,7 @@ typedef int (*snd_kctl_ioctl_func_t) (snd_card_t * card, | |||
106 | void snd_ctl_notify(snd_card_t * card, unsigned int mask, snd_ctl_elem_id_t * id); | 106 | void snd_ctl_notify(snd_card_t * card, unsigned int mask, snd_ctl_elem_id_t * id); |
107 | 107 | ||
108 | snd_kcontrol_t *snd_ctl_new(snd_kcontrol_t * kcontrol, unsigned int access); | 108 | snd_kcontrol_t *snd_ctl_new(snd_kcontrol_t * kcontrol, unsigned int access); |
109 | snd_kcontrol_t *snd_ctl_new1(snd_kcontrol_new_t * kcontrolnew, void * private_data); | 109 | snd_kcontrol_t *snd_ctl_new1(const snd_kcontrol_new_t * kcontrolnew, void * private_data); |
110 | void snd_ctl_free_one(snd_kcontrol_t * kcontrol); | 110 | void snd_ctl_free_one(snd_kcontrol_t * kcontrol); |
111 | int snd_ctl_add(snd_card_t * card, snd_kcontrol_t * kcontrol); | 111 | int snd_ctl_add(snd_card_t * card, snd_kcontrol_t * kcontrol); |
112 | int snd_ctl_remove(snd_card_t * card, snd_kcontrol_t * kcontrol); | 112 | int snd_ctl_remove(snd_card_t * card, snd_kcontrol_t * kcontrol); |
diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 43b6786abae5..c50b91958ff9 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h | |||
@@ -83,7 +83,8 @@ | |||
83 | #define IPR 0x08 /* Global interrupt pending register */ | 83 | #define IPR 0x08 /* Global interrupt pending register */ |
84 | /* Clear pending interrupts by writing a 1 to */ | 84 | /* Clear pending interrupts by writing a 1 to */ |
85 | /* the relevant bits and zero to the other bits */ | 85 | /* the relevant bits and zero to the other bits */ |
86 | 86 | #define IPR_P16V 0x80000000 /* Bit set when the CA0151 P16V chip wishes | |
87 | to interrupt */ | ||
87 | #define IPR_GPIOMSG 0x20000000 /* GPIO message interrupt (RE'd, still not sure | 88 | #define IPR_GPIOMSG 0x20000000 /* GPIO message interrupt (RE'd, still not sure |
88 | which INTE bits enable it) */ | 89 | which INTE bits enable it) */ |
89 | 90 | ||
@@ -746,6 +747,7 @@ | |||
746 | /* Assumes sample lock */ | 747 | /* Assumes sample lock */ |
747 | 748 | ||
748 | /* These three bitfields apply to CDSRCS, GPSRCS, and (except as noted) ZVSRCS. */ | 749 | /* These three bitfields apply to CDSRCS, GPSRCS, and (except as noted) ZVSRCS. */ |
750 | #define SRCS_SPDIFVALID 0x04000000 /* SPDIF stream valid */ | ||
749 | #define SRCS_SPDIFLOCKED 0x02000000 /* SPDIF stream locked */ | 751 | #define SRCS_SPDIFLOCKED 0x02000000 /* SPDIF stream locked */ |
750 | #define SRCS_RATELOCKED 0x01000000 /* Sample rate locked */ | 752 | #define SRCS_RATELOCKED 0x01000000 /* Sample rate locked */ |
751 | #define SRCS_ESTSAMPLERATE 0x0007ffff /* Do not modify this field. */ | 753 | #define SRCS_ESTSAMPLERATE 0x0007ffff /* Do not modify this field. */ |
@@ -803,10 +805,26 @@ | |||
803 | #define A_FXWC2 0x75 /* Selects 0x9f-0x80 for FX recording */ | 805 | #define A_FXWC2 0x75 /* Selects 0x9f-0x80 for FX recording */ |
804 | 806 | ||
805 | #define A_SPDIF_SAMPLERATE 0x76 /* Set the sample rate of SPDIF output */ | 807 | #define A_SPDIF_SAMPLERATE 0x76 /* Set the sample rate of SPDIF output */ |
806 | #define A_SPDIF_RATE_MASK 0x000000c0 | 808 | #define A_SAMPLE_RATE 0x76 /* Various sample rate settings. */ |
809 | #define A_SAMPLE_RATE_NOT_USED 0x0ffc111e /* Bits that are not used and cannot be set. */ | ||
810 | #define A_SAMPLE_RATE_UNKNOWN 0xf0030001 /* Bits that can be set, but have unknown use. */ | ||
811 | #define A_SPDIF_RATE_MASK 0x000000e0 /* Any other values for rates, just use 48000 */ | ||
807 | #define A_SPDIF_48000 0x00000000 | 812 | #define A_SPDIF_48000 0x00000000 |
808 | #define A_SPDIF_44100 0x00000080 | 813 | #define A_SPDIF_192000 0x00000020 |
809 | #define A_SPDIF_96000 0x00000040 | 814 | #define A_SPDIF_96000 0x00000040 |
815 | #define A_SPDIF_44100 0x00000080 | ||
816 | |||
817 | #define A_I2S_CAPTURE_RATE_MASK 0x00000e00 /* This sets the capture PCM rate, but it is */ | ||
818 | #define A_I2S_CAPTURE_48000 0x00000000 /* unclear if this sets the ADC rate as well. */ | ||
819 | #define A_I2S_CAPTURE_192000 0x00000200 | ||
820 | #define A_I2S_CAPTURE_96000 0x00000400 | ||
821 | #define A_I2S_CAPTURE_44100 0x00000800 | ||
822 | |||
823 | #define A_PCM_RATE_MASK 0x0000e000 /* This sets the playback PCM rate on the P16V */ | ||
824 | #define A_PCM_48000 0x00000000 | ||
825 | #define A_PCM_192000 0x00002000 | ||
826 | #define A_PCM_96000 0x00004000 | ||
827 | #define A_PCM_44100 0x00008000 | ||
810 | 828 | ||
811 | /* 0x77,0x78,0x79 "something i2s-related" - default to 0x01080000 on my audigy 2 ZS --rlrevell */ | 829 | /* 0x77,0x78,0x79 "something i2s-related" - default to 0x01080000 on my audigy 2 ZS --rlrevell */ |
812 | /* 0x7a, 0x7b - lookup tables */ | 830 | /* 0x7a, 0x7b - lookup tables */ |
@@ -1039,28 +1057,28 @@ typedef struct { | |||
1039 | u32 vendor; | 1057 | u32 vendor; |
1040 | u32 device; | 1058 | u32 device; |
1041 | u32 subsystem; | 1059 | u32 subsystem; |
1060 | unsigned char revision; | ||
1042 | unsigned char emu10k1_chip; /* Original SB Live. Not SB Live 24bit. */ | 1061 | unsigned char emu10k1_chip; /* Original SB Live. Not SB Live 24bit. */ |
1043 | unsigned char emu10k2_chip; /* Audigy 1 or Audigy 2. */ | 1062 | unsigned char emu10k2_chip; /* Audigy 1 or Audigy 2. */ |
1044 | unsigned char ca0102_chip; /* Audigy 1 or Audigy 2. Not SB Audigy 2 Value. */ | 1063 | unsigned char ca0102_chip; /* Audigy 1 or Audigy 2. Not SB Audigy 2 Value. */ |
1045 | unsigned char ca0108_chip; /* Audigy 2 Value */ | 1064 | unsigned char ca0108_chip; /* Audigy 2 Value */ |
1046 | unsigned char ca0151_chip; /* P16V */ | 1065 | unsigned char ca0151_chip; /* P16V */ |
1047 | unsigned char spk71; /* Has 7.1 speakers */ | 1066 | unsigned char spk71; /* Has 7.1 speakers */ |
1067 | unsigned char sblive51; /* SBLive! 5.1 - extout 0x11 -> center, 0x12 -> lfe */ | ||
1048 | unsigned char spdif_bug; /* Has Spdif phasing bug */ | 1068 | unsigned char spdif_bug; /* Has Spdif phasing bug */ |
1049 | unsigned char ac97_chip; /* Has an AC97 chip */ | 1069 | unsigned char ac97_chip; /* Has an AC97 chip */ |
1050 | unsigned char ecard; /* APS EEPROM */ | 1070 | unsigned char ecard; /* APS EEPROM */ |
1051 | char * driver; | 1071 | const char *driver; |
1052 | char * name; | 1072 | const char *name; |
1073 | const char *id; /* for backward compatibility - can be NULL if not needed */ | ||
1053 | } emu_chip_details_t; | 1074 | } emu_chip_details_t; |
1054 | 1075 | ||
1055 | struct _snd_emu10k1 { | 1076 | struct _snd_emu10k1 { |
1056 | int irq; | 1077 | int irq; |
1057 | 1078 | ||
1058 | unsigned long port; /* I/O port number */ | 1079 | unsigned long port; /* I/O port number */ |
1059 | unsigned int APS: 1, /* APS flag */ | 1080 | unsigned int tos_link: 1, /* tos link detected */ |
1060 | no_ac97: 1, /* no AC'97 */ | 1081 | rear_ac97: 1; /* rear channels are on AC'97 */ |
1061 | tos_link: 1, /* tos link detected */ | ||
1062 | rear_ac97: 1, /* rear channels are on AC'97 */ | ||
1063 | spk71:1; /* 7.1 configuration (Audigy 2 ZS) */ | ||
1064 | const emu_chip_details_t *card_capabilities; /* Contains profile of card capabilities */ | 1082 | const emu_chip_details_t *card_capabilities; /* Contains profile of card capabilities */ |
1065 | unsigned int audigy; /* is Audigy? */ | 1083 | unsigned int audigy; /* is Audigy? */ |
1066 | unsigned int revision; /* chip revision */ | 1084 | unsigned int revision; /* chip revision */ |
@@ -1109,7 +1127,10 @@ struct _snd_emu10k1 { | |||
1109 | 1127 | ||
1110 | emu10k1_voice_t voices[NUM_G]; | 1128 | emu10k1_voice_t voices[NUM_G]; |
1111 | emu10k1_voice_t p16v_voices[4]; | 1129 | emu10k1_voice_t p16v_voices[4]; |
1130 | emu10k1_voice_t p16v_capture_voice; | ||
1112 | int p16v_device_offset; | 1131 | int p16v_device_offset; |
1132 | u32 p16v_capture_source; | ||
1133 | u32 p16v_capture_channel; | ||
1113 | emu10k1_pcm_mixer_t pcm_mixer[32]; | 1134 | emu10k1_pcm_mixer_t pcm_mixer[32]; |
1114 | emu10k1_pcm_mixer_t efx_pcm_mixer[NUM_EFX_PLAYBACK]; | 1135 | emu10k1_pcm_mixer_t efx_pcm_mixer[NUM_EFX_PLAYBACK]; |
1115 | snd_kcontrol_t *ctl_send_routing; | 1136 | snd_kcontrol_t *ctl_send_routing; |
@@ -1453,7 +1474,6 @@ int snd_emu10k1_fx8010_unregister_irq_handler(emu10k1_t *emu, | |||
1453 | #endif | 1474 | #endif |
1454 | 1475 | ||
1455 | typedef struct { | 1476 | typedef struct { |
1456 | unsigned int card; /* card type */ | ||
1457 | unsigned int internal_tram_size; /* in samples */ | 1477 | unsigned int internal_tram_size; /* in samples */ |
1458 | unsigned int external_tram_size; /* in samples */ | 1478 | unsigned int external_tram_size; /* in samples */ |
1459 | char fxbus_names[16][32]; /* names of FXBUSes */ | 1479 | char fxbus_names[16][32]; /* names of FXBUSes */ |
diff --git a/include/sound/gus.h b/include/sound/gus.h index 8b6287a6fff5..b4b461ca173d 100644 --- a/include/sound/gus.h +++ b/include/sound/gus.h | |||
@@ -526,9 +526,6 @@ extern void snd_gf1_adlib_write(snd_gus_card_t * gus, unsigned char reg, unsigne | |||
526 | extern void snd_gf1_dram_addr(snd_gus_card_t * gus, unsigned int addr); | 526 | extern void snd_gf1_dram_addr(snd_gus_card_t * gus, unsigned int addr); |
527 | extern void snd_gf1_poke(snd_gus_card_t * gus, unsigned int addr, unsigned char data); | 527 | extern void snd_gf1_poke(snd_gus_card_t * gus, unsigned int addr, unsigned char data); |
528 | extern unsigned char snd_gf1_peek(snd_gus_card_t * gus, unsigned int addr); | 528 | extern unsigned char snd_gf1_peek(snd_gus_card_t * gus, unsigned int addr); |
529 | extern void snd_gf1_pokew(snd_gus_card_t * gus, unsigned int addr, unsigned short data); | ||
530 | extern unsigned short snd_gf1_peekw(snd_gus_card_t * gus, unsigned int addr); | ||
531 | extern void snd_gf1_dram_setmem(snd_gus_card_t * gus, unsigned int addr, unsigned short value, unsigned int count); | ||
532 | extern void snd_gf1_write_addr(snd_gus_card_t * gus, unsigned char reg, unsigned int addr, short w_16bit); | 529 | extern void snd_gf1_write_addr(snd_gus_card_t * gus, unsigned char reg, unsigned int addr, short w_16bit); |
533 | extern unsigned int snd_gf1_read_addr(snd_gus_card_t * gus, unsigned char reg, short w_16bit); | 530 | extern unsigned int snd_gf1_read_addr(snd_gus_card_t * gus, unsigned char reg, short w_16bit); |
534 | extern void snd_gf1_i_ctrl_stop(snd_gus_card_t * gus, unsigned char reg); | 531 | extern void snd_gf1_i_ctrl_stop(snd_gus_card_t * gus, unsigned char reg); |
@@ -544,9 +541,6 @@ extern inline unsigned short snd_gf1_i_read16(snd_gus_card_t * gus, unsigned cha | |||
544 | { | 541 | { |
545 | return snd_gf1_i_look16(gus, reg | 0x80); | 542 | return snd_gf1_i_look16(gus, reg | 0x80); |
546 | } | 543 | } |
547 | extern void snd_gf1_i_adlib_write(snd_gus_card_t * gus, unsigned char reg, unsigned char data); | ||
548 | extern void snd_gf1_i_write_addr(snd_gus_card_t * gus, unsigned char reg, unsigned int addr, short w_16bit); | ||
549 | extern unsigned int snd_gf1_i_read_addr(snd_gus_card_t * gus, unsigned char reg, short w_16bit); | ||
550 | 544 | ||
551 | extern void snd_gf1_select_active_voices(snd_gus_card_t * gus); | 545 | extern void snd_gf1_select_active_voices(snd_gus_card_t * gus); |
552 | 546 | ||
@@ -580,10 +574,6 @@ extern void snd_gf1_lfo_command(snd_gus_card_t * gus, int voice, unsigned char * | |||
580 | 574 | ||
581 | void snd_gf1_mem_lock(snd_gf1_mem_t * alloc, int xup); | 575 | void snd_gf1_mem_lock(snd_gf1_mem_t * alloc, int xup); |
582 | int snd_gf1_mem_xfree(snd_gf1_mem_t * alloc, snd_gf1_mem_block_t * block); | 576 | int snd_gf1_mem_xfree(snd_gf1_mem_t * alloc, snd_gf1_mem_block_t * block); |
583 | snd_gf1_mem_block_t *snd_gf1_mem_look(snd_gf1_mem_t * alloc, | ||
584 | unsigned int address); | ||
585 | snd_gf1_mem_block_t *snd_gf1_mem_share(snd_gf1_mem_t * alloc, | ||
586 | unsigned int *share_id); | ||
587 | snd_gf1_mem_block_t *snd_gf1_mem_alloc(snd_gf1_mem_t * alloc, int owner, | 577 | snd_gf1_mem_block_t *snd_gf1_mem_alloc(snd_gf1_mem_t * alloc, int owner, |
588 | char *name, int size, int w_16, | 578 | char *name, int size, int w_16, |
589 | int align, unsigned int *share_id); | 579 | int align, unsigned int *share_id); |
@@ -608,23 +598,13 @@ int snd_gf1_dma_transfer_block(snd_gus_card_t * gus, | |||
608 | /* gus_volume.c */ | 598 | /* gus_volume.c */ |
609 | 599 | ||
610 | unsigned short snd_gf1_lvol_to_gvol_raw(unsigned int vol); | 600 | unsigned short snd_gf1_lvol_to_gvol_raw(unsigned int vol); |
611 | unsigned int snd_gf1_gvol_to_lvol_raw(unsigned short gf1_vol); | ||
612 | unsigned int snd_gf1_calc_ramp_rate(snd_gus_card_t * gus, | ||
613 | unsigned short start, | ||
614 | unsigned short end, | ||
615 | unsigned int us); | ||
616 | unsigned short snd_gf1_translate_freq(snd_gus_card_t * gus, unsigned int freq2); | 601 | unsigned short snd_gf1_translate_freq(snd_gus_card_t * gus, unsigned int freq2); |
617 | unsigned short snd_gf1_compute_pitchbend(unsigned short pitchbend, unsigned short sens); | ||
618 | unsigned short snd_gf1_compute_freq(unsigned int freq, | ||
619 | unsigned int rate, | ||
620 | unsigned short mix_rate); | ||
621 | 602 | ||
622 | /* gus_reset.c */ | 603 | /* gus_reset.c */ |
623 | 604 | ||
624 | void snd_gf1_set_default_handlers(snd_gus_card_t * gus, unsigned int what); | 605 | void snd_gf1_set_default_handlers(snd_gus_card_t * gus, unsigned int what); |
625 | void snd_gf1_smart_stop_voice(snd_gus_card_t * gus, unsigned short voice); | 606 | void snd_gf1_smart_stop_voice(snd_gus_card_t * gus, unsigned short voice); |
626 | void snd_gf1_stop_voice(snd_gus_card_t * gus, unsigned short voice); | 607 | void snd_gf1_stop_voice(snd_gus_card_t * gus, unsigned short voice); |
627 | void snd_gf1_clear_voices(snd_gus_card_t * gus, unsigned short v_min, unsigned short v_max); | ||
628 | void snd_gf1_stop_voices(snd_gus_card_t * gus, unsigned short v_min, unsigned short v_max); | 608 | void snd_gf1_stop_voices(snd_gus_card_t * gus, unsigned short v_min, unsigned short v_max); |
629 | snd_gus_voice_t *snd_gf1_alloc_voice(snd_gus_card_t * gus, int type, int client, int port); | 609 | snd_gus_voice_t *snd_gf1_alloc_voice(snd_gus_card_t * gus, int type, int client, int port); |
630 | void snd_gf1_free_voice(snd_gus_card_t * gus, snd_gus_voice_t *voice); | 610 | void snd_gf1_free_voice(snd_gus_card_t * gus, snd_gus_voice_t *voice); |
@@ -641,9 +621,6 @@ int snd_gf1_pcm_new(snd_gus_card_t * gus, int pcm_dev, int control_index, snd_pc | |||
641 | 621 | ||
642 | #ifdef CONFIG_SND_DEBUG | 622 | #ifdef CONFIG_SND_DEBUG |
643 | extern void snd_gf1_print_voice_registers(snd_gus_card_t * gus); | 623 | extern void snd_gf1_print_voice_registers(snd_gus_card_t * gus); |
644 | extern void snd_gf1_print_global_registers(snd_gus_card_t * gus); | ||
645 | extern void snd_gf1_print_setup_registers(snd_gus_card_t * gus); | ||
646 | extern void snd_gf1_peek_print_block(snd_gus_card_t * gus, unsigned int addr, int count, int w_16bit); | ||
647 | #endif | 624 | #endif |
648 | 625 | ||
649 | /* gus.c */ | 626 | /* gus.c */ |
diff --git a/include/sound/hdspm.h b/include/sound/hdspm.h new file mode 100644 index 000000000000..c34427ccd0b3 --- /dev/null +++ b/include/sound/hdspm.h | |||
@@ -0,0 +1,131 @@ | |||
1 | #ifndef __SOUND_HDSPM_H /* -*- linux-c -*- */ | ||
2 | #define __SOUND_HDSPM_H | ||
3 | /* | ||
4 | * Copyright (C) 2003 Winfried Ritsch (IEM) | ||
5 | * based on hdsp.h from Thomas Charbonnel (thomas@undata.org) | ||
6 | * | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | */ | ||
22 | |||
23 | /* Maximum channels is 64 even on 56Mode you have 64playbacks to matrix */ | ||
24 | #define HDSPM_MAX_CHANNELS 64 | ||
25 | |||
26 | /* -------------------- IOCTL Peak/RMS Meters -------------------- */ | ||
27 | |||
28 | typedef struct _snd_hdspm_peak_rms hdspm_peak_rms_t; | ||
29 | |||
30 | /* peam rms level structure like we get from hardware | ||
31 | |||
32 | maybe in future we can memory map it so I just copy it | ||
33 | to user on ioctl call now an dont change anything | ||
34 | rms are made out of low and high values | ||
35 | where (long) ????_rms = (????_rms_l >> 8) + ((????_rms_h & 0xFFFFFF00)<<24) | ||
36 | (i asume so from the code) | ||
37 | */ | ||
38 | |||
39 | struct _snd_hdspm_peak_rms { | ||
40 | |||
41 | unsigned int level_offset[1024]; | ||
42 | |||
43 | unsigned int input_peak[64]; | ||
44 | unsigned int playback_peak[64]; | ||
45 | unsigned int output_peak[64]; | ||
46 | unsigned int xxx_peak[64]; /* not used */ | ||
47 | |||
48 | unsigned int reserved[256]; /* not used */ | ||
49 | |||
50 | unsigned int input_rms_l[64]; | ||
51 | unsigned int playback_rms_l[64]; | ||
52 | unsigned int output_rms_l[64]; | ||
53 | unsigned int xxx_rms_l[64]; /* not used */ | ||
54 | |||
55 | unsigned int input_rms_h[64]; | ||
56 | unsigned int playback_rms_h[64]; | ||
57 | unsigned int output_rms_h[64]; | ||
58 | unsigned int xxx_rms_h[64]; /* not used */ | ||
59 | }; | ||
60 | |||
61 | struct sndrv_hdspm_peak_rms_ioctl { | ||
62 | hdspm_peak_rms_t *peak; | ||
63 | }; | ||
64 | |||
65 | /* use indirect access due to the limit of ioctl bit size */ | ||
66 | #define SNDRV_HDSPM_IOCTL_GET_PEAK_RMS _IOR('H', 0x40, struct sndrv_hdspm_peak_rms_ioctl) | ||
67 | |||
68 | /* ------------ CONFIG block IOCTL ---------------------- */ | ||
69 | |||
70 | typedef struct _snd_hdspm_config_info hdspm_config_info_t; | ||
71 | |||
72 | struct _snd_hdspm_config_info { | ||
73 | unsigned char pref_sync_ref; | ||
74 | unsigned char wordclock_sync_check; | ||
75 | unsigned char madi_sync_check; | ||
76 | unsigned int system_sample_rate; | ||
77 | unsigned int autosync_sample_rate; | ||
78 | unsigned char system_clock_mode; | ||
79 | unsigned char clock_source; | ||
80 | unsigned char autosync_ref; | ||
81 | unsigned char line_out; | ||
82 | unsigned int passthru; | ||
83 | unsigned int analog_out; | ||
84 | }; | ||
85 | |||
86 | #define SNDRV_HDSPM_IOCTL_GET_CONFIG_INFO _IOR('H', 0x41, hdspm_config_info_t) | ||
87 | |||
88 | |||
89 | /* get Soundcard Version */ | ||
90 | |||
91 | typedef struct _snd_hdspm_version hdspm_version_t; | ||
92 | |||
93 | struct _snd_hdspm_version { | ||
94 | unsigned short firmware_rev; | ||
95 | }; | ||
96 | |||
97 | #define SNDRV_HDSPM_IOCTL_GET_VERSION _IOR('H', 0x43, hdspm_version_t) | ||
98 | |||
99 | |||
100 | /* ------------- get Matrix Mixer IOCTL --------------- */ | ||
101 | |||
102 | /* MADI mixer: 64inputs+64playback in 64outputs = 8192 => *4Byte = 32768 Bytes */ | ||
103 | |||
104 | /* organisation is 64 channelfader in a continous memory block */ | ||
105 | /* equivalent to hardware definition, maybe for future feature of mmap of them */ | ||
106 | /* each of 64 outputs has 64 infader and 64 outfader: | ||
107 | Ins to Outs mixer[out].in[in], Outstreams to Outs mixer[out].pb[pb] */ | ||
108 | |||
109 | #define HDSPM_MIXER_CHANNELS HDSPM_MAX_CHANNELS | ||
110 | |||
111 | typedef struct _snd_hdspm_channelfader snd_hdspm_channelfader_t; | ||
112 | |||
113 | struct _snd_hdspm_channelfader { | ||
114 | unsigned int in[HDSPM_MIXER_CHANNELS]; | ||
115 | unsigned int pb[HDSPM_MIXER_CHANNELS]; | ||
116 | }; | ||
117 | |||
118 | typedef struct _snd_hdspm_mixer hdspm_mixer_t; | ||
119 | |||
120 | struct _snd_hdspm_mixer { | ||
121 | snd_hdspm_channelfader_t ch[HDSPM_MIXER_CHANNELS]; | ||
122 | }; | ||
123 | |||
124 | struct sndrv_hdspm_mixer_ioctl { | ||
125 | hdspm_mixer_t *mixer; | ||
126 | }; | ||
127 | |||
128 | /* use indirect access due to the limit of ioctl bit size */ | ||
129 | #define SNDRV_HDSPM_IOCTL_GET_MIXER _IOR('H', 0x44, struct sndrv_hdspm_mixer_ioctl) | ||
130 | |||
131 | #endif /* __SOUND_HDSPM_H */ | ||
diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 53fc04d75bad..d935417575b5 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h | |||
@@ -848,23 +848,6 @@ int snd_interval_ratnum(snd_interval_t *i, | |||
848 | 848 | ||
849 | void _snd_pcm_hw_params_any(snd_pcm_hw_params_t *params); | 849 | void _snd_pcm_hw_params_any(snd_pcm_hw_params_t *params); |
850 | void _snd_pcm_hw_param_setempty(snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var); | 850 | void _snd_pcm_hw_param_setempty(snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var); |
851 | int snd_pcm_hw_param_min(snd_pcm_substream_t *substream, | ||
852 | snd_pcm_hw_params_t *params, | ||
853 | snd_pcm_hw_param_t var, | ||
854 | unsigned int val, int *dir); | ||
855 | int snd_pcm_hw_param_max(snd_pcm_substream_t *substream, | ||
856 | snd_pcm_hw_params_t *params, | ||
857 | snd_pcm_hw_param_t var, | ||
858 | unsigned int val, int *dir); | ||
859 | int snd_pcm_hw_param_setinteger(snd_pcm_substream_t *substream, | ||
860 | snd_pcm_hw_params_t *params, | ||
861 | snd_pcm_hw_param_t var); | ||
862 | int snd_pcm_hw_param_first(snd_pcm_substream_t *substream, | ||
863 | snd_pcm_hw_params_t *params, | ||
864 | snd_pcm_hw_param_t var, int *dir); | ||
865 | int snd_pcm_hw_param_last(snd_pcm_substream_t *substream, | ||
866 | snd_pcm_hw_params_t *params, | ||
867 | snd_pcm_hw_param_t var, int *dir); | ||
868 | int snd_pcm_hw_param_near(snd_pcm_substream_t *substream, | 851 | int snd_pcm_hw_param_near(snd_pcm_substream_t *substream, |
869 | snd_pcm_hw_params_t *params, | 852 | snd_pcm_hw_params_t *params, |
870 | snd_pcm_hw_param_t var, | 853 | snd_pcm_hw_param_t var, |
@@ -876,7 +859,6 @@ int snd_pcm_hw_param_set(snd_pcm_substream_t *pcm, | |||
876 | int snd_pcm_hw_params_choose(snd_pcm_substream_t *substream, snd_pcm_hw_params_t *params); | 859 | int snd_pcm_hw_params_choose(snd_pcm_substream_t *substream, snd_pcm_hw_params_t *params); |
877 | 860 | ||
878 | int snd_pcm_hw_refine(snd_pcm_substream_t *substream, snd_pcm_hw_params_t *params); | 861 | int snd_pcm_hw_refine(snd_pcm_substream_t *substream, snd_pcm_hw_params_t *params); |
879 | int snd_pcm_hw_params(snd_pcm_substream_t *substream, snd_pcm_hw_params_t *params); | ||
880 | 862 | ||
881 | int snd_pcm_hw_constraints_init(snd_pcm_substream_t *substream); | 863 | int snd_pcm_hw_constraints_init(snd_pcm_substream_t *substream); |
882 | int snd_pcm_hw_constraints_complete(snd_pcm_substream_t *substream); | 864 | int snd_pcm_hw_constraints_complete(snd_pcm_substream_t *substream); |
@@ -922,8 +904,22 @@ int snd_pcm_format_unsigned(snd_pcm_format_t format); | |||
922 | int snd_pcm_format_linear(snd_pcm_format_t format); | 904 | int snd_pcm_format_linear(snd_pcm_format_t format); |
923 | int snd_pcm_format_little_endian(snd_pcm_format_t format); | 905 | int snd_pcm_format_little_endian(snd_pcm_format_t format); |
924 | int snd_pcm_format_big_endian(snd_pcm_format_t format); | 906 | int snd_pcm_format_big_endian(snd_pcm_format_t format); |
907 | /** | ||
908 | * snd_pcm_format_cpu_endian - Check the PCM format is CPU-endian | ||
909 | * @format: the format to check | ||
910 | * | ||
911 | * Returns 1 if the given PCM format is CPU-endian, 0 if | ||
912 | * opposite, or a negative error code if endian not specified. | ||
913 | */ | ||
914 | /* int snd_pcm_format_cpu_endian(snd_pcm_format_t format); */ | ||
915 | #ifdef SNDRV_LITTLE_ENDIAN | ||
916 | #define snd_pcm_format_cpu_endian snd_pcm_format_little_endian | ||
917 | #else | ||
918 | #define snd_pcm_format_cpu_endian snd_pcm_format_big_endian | ||
919 | #endif | ||
925 | int snd_pcm_format_width(snd_pcm_format_t format); /* in bits */ | 920 | int snd_pcm_format_width(snd_pcm_format_t format); /* in bits */ |
926 | int snd_pcm_format_physical_width(snd_pcm_format_t format); /* in bits */ | 921 | int snd_pcm_format_physical_width(snd_pcm_format_t format); /* in bits */ |
922 | ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples); | ||
927 | const unsigned char *snd_pcm_format_silence_64(snd_pcm_format_t format); | 923 | const unsigned char *snd_pcm_format_silence_64(snd_pcm_format_t format); |
928 | int snd_pcm_format_set_silence(snd_pcm_format_t format, void *buf, unsigned int frames); | 924 | int snd_pcm_format_set_silence(snd_pcm_format_t format, void *buf, unsigned int frames); |
929 | snd_pcm_format_t snd_pcm_build_linear_format(int width, int unsignd, int big_endian); | 925 | snd_pcm_format_t snd_pcm_build_linear_format(int width, int unsignd, int big_endian); |
diff --git a/include/sound/seq_midi_event.h b/include/sound/seq_midi_event.h index 4357cac07500..8857e2bd31a5 100644 --- a/include/sound/seq_midi_event.h +++ b/include/sound/seq_midi_event.h | |||
@@ -41,9 +41,7 @@ struct snd_midi_event_t { | |||
41 | }; | 41 | }; |
42 | 42 | ||
43 | int snd_midi_event_new(int bufsize, snd_midi_event_t **rdev); | 43 | int snd_midi_event_new(int bufsize, snd_midi_event_t **rdev); |
44 | int snd_midi_event_resize_buffer(snd_midi_event_t *dev, int bufsize); | ||
45 | void snd_midi_event_free(snd_midi_event_t *dev); | 44 | void snd_midi_event_free(snd_midi_event_t *dev); |
46 | void snd_midi_event_init(snd_midi_event_t *dev); | ||
47 | void snd_midi_event_reset_encode(snd_midi_event_t *dev); | 45 | void snd_midi_event_reset_encode(snd_midi_event_t *dev); |
48 | void snd_midi_event_reset_decode(snd_midi_event_t *dev); | 46 | void snd_midi_event_reset_decode(snd_midi_event_t *dev); |
49 | void snd_midi_event_no_status(snd_midi_event_t *dev, int on); | 47 | void snd_midi_event_no_status(snd_midi_event_t *dev, int on); |
diff --git a/include/sound/seq_virmidi.h b/include/sound/seq_virmidi.h index cf4e2388103f..1ad27e859af3 100644 --- a/include/sound/seq_virmidi.h +++ b/include/sound/seq_virmidi.h | |||
@@ -79,6 +79,5 @@ struct _snd_virmidi_dev { | |||
79 | #define SNDRV_VIRMIDI_SEQ_DISPATCH 2 | 79 | #define SNDRV_VIRMIDI_SEQ_DISPATCH 2 |
80 | 80 | ||
81 | int snd_virmidi_new(snd_card_t *card, int device, snd_rawmidi_t **rrmidi); | 81 | int snd_virmidi_new(snd_card_t *card, int device, snd_rawmidi_t **rrmidi); |
82 | int snd_virmidi_receive(snd_rawmidi_t *rmidi, snd_seq_event_t *ev); | ||
83 | 82 | ||
84 | #endif /* __SOUND_SEQ_VIRMIDI */ | 83 | #endif /* __SOUND_SEQ_VIRMIDI */ |
diff --git a/include/sound/timer.h b/include/sound/timer.h index 57fde990606e..1898511a0f38 100644 --- a/include/sound/timer.h +++ b/include/sound/timer.h | |||
@@ -152,6 +152,4 @@ extern int snd_timer_pause(snd_timer_instance_t * timeri); | |||
152 | 152 | ||
153 | extern void snd_timer_interrupt(snd_timer_t * timer, unsigned long ticks_left); | 153 | extern void snd_timer_interrupt(snd_timer_t * timer, unsigned long ticks_left); |
154 | 154 | ||
155 | extern unsigned int snd_timer_system_resolution(void); | ||
156 | |||
157 | #endif /* __SOUND_TIMER_H */ | 155 | #endif /* __SOUND_TIMER_H */ |
diff --git a/include/sound/version.h b/include/sound/version.h index 98b4230778ed..46acfa8c9988 100644 --- a/include/sound/version.h +++ b/include/sound/version.h | |||
@@ -1,3 +1,3 @@ | |||
1 | /* include/version.h. Generated by configure. */ | 1 | /* include/version.h. Generated by configure. */ |
2 | #define CONFIG_SND_VERSION "1.0.9rc2" | 2 | #define CONFIG_SND_VERSION "1.0.9" |
3 | #define CONFIG_SND_DATE " (Thu Mar 24 10:33:39 2005 UTC)" | 3 | #define CONFIG_SND_DATE " (Sun May 29 07:31:02 2005 UTC)" |
diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index 05107e0dc145..567b03b1c349 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig | |||
@@ -2,7 +2,7 @@ | |||
2 | # IP configuration | 2 | # IP configuration |
3 | # | 3 | # |
4 | choice | 4 | choice |
5 | prompt "Choose IP: FIB lookup"" | 5 | prompt "Choose IP: FIB lookup" |
6 | depends on INET | 6 | depends on INET |
7 | default IP_FIB_HASH | 7 | default IP_FIB_HASH |
8 | 8 | ||
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index 9bcec9b927b9..505e2d4b3d62 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c | |||
@@ -66,10 +66,10 @@ rpcauth_create(rpc_authflavor_t pseudoflavor, struct rpc_clnt *clnt) | |||
66 | u32 flavor = pseudoflavor_to_flavor(pseudoflavor); | 66 | u32 flavor = pseudoflavor_to_flavor(pseudoflavor); |
67 | 67 | ||
68 | if (flavor >= RPC_AUTH_MAXFLAVOR || !(ops = auth_flavors[flavor])) | 68 | if (flavor >= RPC_AUTH_MAXFLAVOR || !(ops = auth_flavors[flavor])) |
69 | return NULL; | 69 | return ERR_PTR(-EINVAL); |
70 | auth = ops->create(clnt, pseudoflavor); | 70 | auth = ops->create(clnt, pseudoflavor); |
71 | if (!auth) | 71 | if (IS_ERR(auth)) |
72 | return NULL; | 72 | return auth; |
73 | if (clnt->cl_auth) | 73 | if (clnt->cl_auth) |
74 | rpcauth_destroy(clnt->cl_auth); | 74 | rpcauth_destroy(clnt->cl_auth); |
75 | clnt->cl_auth = auth; | 75 | clnt->cl_auth = auth; |
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index a33b627cbef4..2f7b867161d2 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c | |||
@@ -660,14 +660,16 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor) | |||
660 | { | 660 | { |
661 | struct gss_auth *gss_auth; | 661 | struct gss_auth *gss_auth; |
662 | struct rpc_auth * auth; | 662 | struct rpc_auth * auth; |
663 | int err = -ENOMEM; /* XXX? */ | ||
663 | 664 | ||
664 | dprintk("RPC: creating GSS authenticator for client %p\n",clnt); | 665 | dprintk("RPC: creating GSS authenticator for client %p\n",clnt); |
665 | 666 | ||
666 | if (!try_module_get(THIS_MODULE)) | 667 | if (!try_module_get(THIS_MODULE)) |
667 | return NULL; | 668 | return ERR_PTR(err); |
668 | if (!(gss_auth = kmalloc(sizeof(*gss_auth), GFP_KERNEL))) | 669 | if (!(gss_auth = kmalloc(sizeof(*gss_auth), GFP_KERNEL))) |
669 | goto out_dec; | 670 | goto out_dec; |
670 | gss_auth->client = clnt; | 671 | gss_auth->client = clnt; |
672 | err = -EINVAL; | ||
671 | gss_auth->mech = gss_mech_get_by_pseudoflavor(flavor); | 673 | gss_auth->mech = gss_mech_get_by_pseudoflavor(flavor); |
672 | if (!gss_auth->mech) { | 674 | if (!gss_auth->mech) { |
673 | printk(KERN_WARNING "%s: Pseudoflavor %d not found!", | 675 | printk(KERN_WARNING "%s: Pseudoflavor %d not found!", |
@@ -675,9 +677,8 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor) | |||
675 | goto err_free; | 677 | goto err_free; |
676 | } | 678 | } |
677 | gss_auth->service = gss_pseudoflavor_to_service(gss_auth->mech, flavor); | 679 | gss_auth->service = gss_pseudoflavor_to_service(gss_auth->mech, flavor); |
678 | /* FIXME: Will go away once privacy support is merged in */ | 680 | if (gss_auth->service == 0) |
679 | if (gss_auth->service == RPC_GSS_SVC_PRIVACY) | 681 | goto err_put_mech; |
680 | gss_auth->service = RPC_GSS_SVC_INTEGRITY; | ||
681 | INIT_LIST_HEAD(&gss_auth->upcalls); | 682 | INIT_LIST_HEAD(&gss_auth->upcalls); |
682 | spin_lock_init(&gss_auth->lock); | 683 | spin_lock_init(&gss_auth->lock); |
683 | auth = &gss_auth->rpc_auth; | 684 | auth = &gss_auth->rpc_auth; |
@@ -687,15 +688,18 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor) | |||
687 | auth->au_flavor = flavor; | 688 | auth->au_flavor = flavor; |
688 | atomic_set(&auth->au_count, 1); | 689 | atomic_set(&auth->au_count, 1); |
689 | 690 | ||
690 | if (rpcauth_init_credcache(auth, GSS_CRED_EXPIRE) < 0) | 691 | err = rpcauth_init_credcache(auth, GSS_CRED_EXPIRE); |
692 | if (err) | ||
691 | goto err_put_mech; | 693 | goto err_put_mech; |
692 | 694 | ||
693 | snprintf(gss_auth->path, sizeof(gss_auth->path), "%s/%s", | 695 | snprintf(gss_auth->path, sizeof(gss_auth->path), "%s/%s", |
694 | clnt->cl_pathname, | 696 | clnt->cl_pathname, |
695 | gss_auth->mech->gm_name); | 697 | gss_auth->mech->gm_name); |
696 | gss_auth->dentry = rpc_mkpipe(gss_auth->path, clnt, &gss_upcall_ops, RPC_PIPE_WAIT_FOR_OPEN); | 698 | gss_auth->dentry = rpc_mkpipe(gss_auth->path, clnt, &gss_upcall_ops, RPC_PIPE_WAIT_FOR_OPEN); |
697 | if (IS_ERR(gss_auth->dentry)) | 699 | if (IS_ERR(gss_auth->dentry)) { |
700 | err = PTR_ERR(gss_auth->dentry); | ||
698 | goto err_put_mech; | 701 | goto err_put_mech; |
702 | } | ||
699 | 703 | ||
700 | return auth; | 704 | return auth; |
701 | err_put_mech: | 705 | err_put_mech: |
@@ -704,7 +708,7 @@ err_free: | |||
704 | kfree(gss_auth); | 708 | kfree(gss_auth); |
705 | out_dec: | 709 | out_dec: |
706 | module_put(THIS_MODULE); | 710 | module_put(THIS_MODULE); |
707 | return NULL; | 711 | return ERR_PTR(err); |
708 | } | 712 | } |
709 | 713 | ||
710 | static void | 714 | static void |
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 02bc029d46fe..f17e6153b688 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
@@ -97,12 +97,13 @@ rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name) | |||
97 | * made to sleep too long. | 97 | * made to sleep too long. |
98 | */ | 98 | */ |
99 | struct rpc_clnt * | 99 | struct rpc_clnt * |
100 | rpc_create_client(struct rpc_xprt *xprt, char *servname, | 100 | rpc_new_client(struct rpc_xprt *xprt, char *servname, |
101 | struct rpc_program *program, u32 vers, | 101 | struct rpc_program *program, u32 vers, |
102 | rpc_authflavor_t flavor) | 102 | rpc_authflavor_t flavor) |
103 | { | 103 | { |
104 | struct rpc_version *version; | 104 | struct rpc_version *version; |
105 | struct rpc_clnt *clnt = NULL; | 105 | struct rpc_clnt *clnt = NULL; |
106 | struct rpc_auth *auth; | ||
106 | int err; | 107 | int err; |
107 | int len; | 108 | int len; |
108 | 109 | ||
@@ -157,10 +158,11 @@ rpc_create_client(struct rpc_xprt *xprt, char *servname, | |||
157 | if (err < 0) | 158 | if (err < 0) |
158 | goto out_no_path; | 159 | goto out_no_path; |
159 | 160 | ||
160 | err = -ENOMEM; | 161 | auth = rpcauth_create(flavor, clnt); |
161 | if (!rpcauth_create(flavor, clnt)) { | 162 | if (IS_ERR(auth)) { |
162 | printk(KERN_INFO "RPC: Couldn't create auth handle (flavor %u)\n", | 163 | printk(KERN_INFO "RPC: Couldn't create auth handle (flavor %u)\n", |
163 | flavor); | 164 | flavor); |
165 | err = PTR_ERR(auth); | ||
164 | goto out_no_auth; | 166 | goto out_no_auth; |
165 | } | 167 | } |
166 | 168 | ||
@@ -178,6 +180,37 @@ out_no_path: | |||
178 | kfree(clnt->cl_server); | 180 | kfree(clnt->cl_server); |
179 | kfree(clnt); | 181 | kfree(clnt); |
180 | out_err: | 182 | out_err: |
183 | xprt_destroy(xprt); | ||
184 | return ERR_PTR(err); | ||
185 | } | ||
186 | |||
187 | /** | ||
188 | * Create an RPC client | ||
189 | * @xprt - pointer to xprt struct | ||
190 | * @servname - name of server | ||
191 | * @info - rpc_program | ||
192 | * @version - rpc_program version | ||
193 | * @authflavor - rpc_auth flavour to use | ||
194 | * | ||
195 | * Creates an RPC client structure, then pings the server in order to | ||
196 | * determine if it is up, and if it supports this program and version. | ||
197 | * | ||
198 | * This function should never be called by asynchronous tasks such as | ||
199 | * the portmapper. | ||
200 | */ | ||
201 | struct rpc_clnt *rpc_create_client(struct rpc_xprt *xprt, char *servname, | ||
202 | struct rpc_program *info, u32 version, rpc_authflavor_t authflavor) | ||
203 | { | ||
204 | struct rpc_clnt *clnt; | ||
205 | int err; | ||
206 | |||
207 | clnt = rpc_new_client(xprt, servname, info, version, authflavor); | ||
208 | if (IS_ERR(clnt)) | ||
209 | return clnt; | ||
210 | err = rpc_ping(clnt, RPC_TASK_SOFT|RPC_TASK_NOINTR); | ||
211 | if (err == 0) | ||
212 | return clnt; | ||
213 | rpc_shutdown_client(clnt); | ||
181 | return ERR_PTR(err); | 214 | return ERR_PTR(err); |
182 | } | 215 | } |
183 | 216 | ||
@@ -208,6 +241,8 @@ rpc_clone_client(struct rpc_clnt *clnt) | |||
208 | rpc_init_rtt(&new->cl_rtt_default, clnt->cl_xprt->timeout.to_initval); | 241 | rpc_init_rtt(&new->cl_rtt_default, clnt->cl_xprt->timeout.to_initval); |
209 | if (new->cl_auth) | 242 | if (new->cl_auth) |
210 | atomic_inc(&new->cl_auth->au_count); | 243 | atomic_inc(&new->cl_auth->au_count); |
244 | new->cl_pmap = &new->cl_pmap_default; | ||
245 | rpc_init_wait_queue(&new->cl_pmap_default.pm_bindwait, "bindwait"); | ||
211 | return new; | 246 | return new; |
212 | out_no_clnt: | 247 | out_no_clnt: |
213 | printk(KERN_INFO "RPC: out of memory in %s\n", __FUNCTION__); | 248 | printk(KERN_INFO "RPC: out of memory in %s\n", __FUNCTION__); |
@@ -296,6 +331,44 @@ rpc_release_client(struct rpc_clnt *clnt) | |||
296 | rpc_destroy_client(clnt); | 331 | rpc_destroy_client(clnt); |
297 | } | 332 | } |
298 | 333 | ||
334 | /** | ||
335 | * rpc_bind_new_program - bind a new RPC program to an existing client | ||
336 | * @old - old rpc_client | ||
337 | * @program - rpc program to set | ||
338 | * @vers - rpc program version | ||
339 | * | ||
340 | * Clones the rpc client and sets up a new RPC program. This is mainly | ||
341 | * of use for enabling different RPC programs to share the same transport. | ||
342 | * The Sun NFSv2/v3 ACL protocol can do this. | ||
343 | */ | ||
344 | struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *old, | ||
345 | struct rpc_program *program, | ||
346 | int vers) | ||
347 | { | ||
348 | struct rpc_clnt *clnt; | ||
349 | struct rpc_version *version; | ||
350 | int err; | ||
351 | |||
352 | BUG_ON(vers >= program->nrvers || !program->version[vers]); | ||
353 | version = program->version[vers]; | ||
354 | clnt = rpc_clone_client(old); | ||
355 | if (IS_ERR(clnt)) | ||
356 | goto out; | ||
357 | clnt->cl_procinfo = version->procs; | ||
358 | clnt->cl_maxproc = version->nrprocs; | ||
359 | clnt->cl_protname = program->name; | ||
360 | clnt->cl_prog = program->number; | ||
361 | clnt->cl_vers = version->number; | ||
362 | clnt->cl_stats = program->stats; | ||
363 | err = rpc_ping(clnt, RPC_TASK_SOFT|RPC_TASK_NOINTR); | ||
364 | if (err != 0) { | ||
365 | rpc_shutdown_client(clnt); | ||
366 | clnt = ERR_PTR(err); | ||
367 | } | ||
368 | out: | ||
369 | return clnt; | ||
370 | } | ||
371 | |||
299 | /* | 372 | /* |
300 | * Default callback for async RPC calls | 373 | * Default callback for async RPC calls |
301 | */ | 374 | */ |
@@ -305,38 +378,41 @@ rpc_default_callback(struct rpc_task *task) | |||
305 | } | 378 | } |
306 | 379 | ||
307 | /* | 380 | /* |
308 | * Export the signal mask handling for aysnchronous code that | 381 | * Export the signal mask handling for synchronous code that |
309 | * sleeps on RPC calls | 382 | * sleeps on RPC calls |
310 | */ | 383 | */ |
384 | #define RPC_INTR_SIGNALS (sigmask(SIGINT) | sigmask(SIGQUIT) | sigmask(SIGKILL)) | ||
311 | 385 | ||
386 | static void rpc_save_sigmask(sigset_t *oldset, int intr) | ||
387 | { | ||
388 | unsigned long sigallow = 0; | ||
389 | sigset_t sigmask; | ||
390 | |||
391 | /* Block all signals except those listed in sigallow */ | ||
392 | if (intr) | ||
393 | sigallow |= RPC_INTR_SIGNALS; | ||
394 | siginitsetinv(&sigmask, sigallow); | ||
395 | sigprocmask(SIG_BLOCK, &sigmask, oldset); | ||
396 | } | ||
397 | |||
398 | static inline void rpc_task_sigmask(struct rpc_task *task, sigset_t *oldset) | ||
399 | { | ||
400 | rpc_save_sigmask(oldset, !RPC_TASK_UNINTERRUPTIBLE(task)); | ||
401 | } | ||
402 | |||
403 | static inline void rpc_restore_sigmask(sigset_t *oldset) | ||
404 | { | ||
405 | sigprocmask(SIG_SETMASK, oldset, NULL); | ||
406 | } | ||
407 | |||
312 | void rpc_clnt_sigmask(struct rpc_clnt *clnt, sigset_t *oldset) | 408 | void rpc_clnt_sigmask(struct rpc_clnt *clnt, sigset_t *oldset) |
313 | { | 409 | { |
314 | unsigned long sigallow = sigmask(SIGKILL); | 410 | rpc_save_sigmask(oldset, clnt->cl_intr); |
315 | unsigned long irqflags; | ||
316 | |||
317 | /* Turn off various signals */ | ||
318 | if (clnt->cl_intr) { | ||
319 | struct k_sigaction *action = current->sighand->action; | ||
320 | if (action[SIGINT-1].sa.sa_handler == SIG_DFL) | ||
321 | sigallow |= sigmask(SIGINT); | ||
322 | if (action[SIGQUIT-1].sa.sa_handler == SIG_DFL) | ||
323 | sigallow |= sigmask(SIGQUIT); | ||
324 | } | ||
325 | spin_lock_irqsave(¤t->sighand->siglock, irqflags); | ||
326 | *oldset = current->blocked; | ||
327 | siginitsetinv(¤t->blocked, sigallow & ~oldset->sig[0]); | ||
328 | recalc_sigpending(); | ||
329 | spin_unlock_irqrestore(¤t->sighand->siglock, irqflags); | ||
330 | } | 411 | } |
331 | 412 | ||
332 | void rpc_clnt_sigunmask(struct rpc_clnt *clnt, sigset_t *oldset) | 413 | void rpc_clnt_sigunmask(struct rpc_clnt *clnt, sigset_t *oldset) |
333 | { | 414 | { |
334 | unsigned long irqflags; | 415 | rpc_restore_sigmask(oldset); |
335 | |||
336 | spin_lock_irqsave(¤t->sighand->siglock, irqflags); | ||
337 | current->blocked = *oldset; | ||
338 | recalc_sigpending(); | ||
339 | spin_unlock_irqrestore(¤t->sighand->siglock, irqflags); | ||
340 | } | 416 | } |
341 | 417 | ||
342 | /* | 418 | /* |
@@ -354,26 +430,26 @@ int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg, int flags) | |||
354 | 430 | ||
355 | BUG_ON(flags & RPC_TASK_ASYNC); | 431 | BUG_ON(flags & RPC_TASK_ASYNC); |
356 | 432 | ||
357 | rpc_clnt_sigmask(clnt, &oldset); | ||
358 | |||
359 | status = -ENOMEM; | 433 | status = -ENOMEM; |
360 | task = rpc_new_task(clnt, NULL, flags); | 434 | task = rpc_new_task(clnt, NULL, flags); |
361 | if (task == NULL) | 435 | if (task == NULL) |
362 | goto out; | 436 | goto out; |
363 | 437 | ||
438 | /* Mask signals on RPC calls _and_ GSS_AUTH upcalls */ | ||
439 | rpc_task_sigmask(task, &oldset); | ||
440 | |||
364 | rpc_call_setup(task, msg, 0); | 441 | rpc_call_setup(task, msg, 0); |
365 | 442 | ||
366 | /* Set up the call info struct and execute the task */ | 443 | /* Set up the call info struct and execute the task */ |
367 | if (task->tk_status == 0) | 444 | if (task->tk_status == 0) { |
368 | status = rpc_execute(task); | 445 | status = rpc_execute(task); |
369 | else { | 446 | } else { |
370 | status = task->tk_status; | 447 | status = task->tk_status; |
371 | rpc_release_task(task); | 448 | rpc_release_task(task); |
372 | } | 449 | } |
373 | 450 | ||
451 | rpc_restore_sigmask(&oldset); | ||
374 | out: | 452 | out: |
375 | rpc_clnt_sigunmask(clnt, &oldset); | ||
376 | |||
377 | return status; | 453 | return status; |
378 | } | 454 | } |
379 | 455 | ||
@@ -394,8 +470,6 @@ rpc_call_async(struct rpc_clnt *clnt, struct rpc_message *msg, int flags, | |||
394 | 470 | ||
395 | flags |= RPC_TASK_ASYNC; | 471 | flags |= RPC_TASK_ASYNC; |
396 | 472 | ||
397 | rpc_clnt_sigmask(clnt, &oldset); | ||
398 | |||
399 | /* Create/initialize a new RPC task */ | 473 | /* Create/initialize a new RPC task */ |
400 | if (!callback) | 474 | if (!callback) |
401 | callback = rpc_default_callback; | 475 | callback = rpc_default_callback; |
@@ -404,6 +478,9 @@ rpc_call_async(struct rpc_clnt *clnt, struct rpc_message *msg, int flags, | |||
404 | goto out; | 478 | goto out; |
405 | task->tk_calldata = data; | 479 | task->tk_calldata = data; |
406 | 480 | ||
481 | /* Mask signals on GSS_AUTH upcalls */ | ||
482 | rpc_task_sigmask(task, &oldset); | ||
483 | |||
407 | rpc_call_setup(task, msg, 0); | 484 | rpc_call_setup(task, msg, 0); |
408 | 485 | ||
409 | /* Set up the call info struct and execute the task */ | 486 | /* Set up the call info struct and execute the task */ |
@@ -413,9 +490,8 @@ rpc_call_async(struct rpc_clnt *clnt, struct rpc_message *msg, int flags, | |||
413 | else | 490 | else |
414 | rpc_release_task(task); | 491 | rpc_release_task(task); |
415 | 492 | ||
493 | rpc_restore_sigmask(&oldset); | ||
416 | out: | 494 | out: |
417 | rpc_clnt_sigunmask(clnt, &oldset); | ||
418 | |||
419 | return status; | 495 | return status; |
420 | } | 496 | } |
421 | 497 | ||
@@ -593,7 +669,7 @@ call_allocate(struct rpc_task *task) | |||
593 | return; | 669 | return; |
594 | printk(KERN_INFO "RPC: buffer allocation failed for task %p\n", task); | 670 | printk(KERN_INFO "RPC: buffer allocation failed for task %p\n", task); |
595 | 671 | ||
596 | if (RPC_IS_ASYNC(task) || !(task->tk_client->cl_intr && signalled())) { | 672 | if (RPC_IS_ASYNC(task) || !signalled()) { |
597 | xprt_release(task); | 673 | xprt_release(task); |
598 | task->tk_action = call_reserve; | 674 | task->tk_action = call_reserve; |
599 | rpc_delay(task, HZ>>4); | 675 | rpc_delay(task, HZ>>4); |
@@ -957,7 +1033,9 @@ call_header(struct rpc_task *task) | |||
957 | *p++ = htonl(clnt->cl_prog); /* program number */ | 1033 | *p++ = htonl(clnt->cl_prog); /* program number */ |
958 | *p++ = htonl(clnt->cl_vers); /* program version */ | 1034 | *p++ = htonl(clnt->cl_vers); /* program version */ |
959 | *p++ = htonl(task->tk_msg.rpc_proc->p_proc); /* procedure */ | 1035 | *p++ = htonl(task->tk_msg.rpc_proc->p_proc); /* procedure */ |
960 | return rpcauth_marshcred(task, p); | 1036 | p = rpcauth_marshcred(task, p); |
1037 | req->rq_slen = xdr_adjust_iovec(&req->rq_svec[0], p); | ||
1038 | return p; | ||
961 | } | 1039 | } |
962 | 1040 | ||
963 | /* | 1041 | /* |
@@ -986,10 +1064,11 @@ call_verify(struct rpc_task *task) | |||
986 | case RPC_AUTH_ERROR: | 1064 | case RPC_AUTH_ERROR: |
987 | break; | 1065 | break; |
988 | case RPC_MISMATCH: | 1066 | case RPC_MISMATCH: |
989 | printk(KERN_WARNING "%s: RPC call version mismatch!\n", __FUNCTION__); | 1067 | dprintk("%s: RPC call version mismatch!\n", __FUNCTION__); |
990 | goto out_eio; | 1068 | error = -EPROTONOSUPPORT; |
1069 | goto out_err; | ||
991 | default: | 1070 | default: |
992 | printk(KERN_WARNING "%s: RPC call rejected, unknown error: %x\n", __FUNCTION__, n); | 1071 | dprintk("%s: RPC call rejected, unknown error: %x\n", __FUNCTION__, n); |
993 | goto out_eio; | 1072 | goto out_eio; |
994 | } | 1073 | } |
995 | if (--len < 0) | 1074 | if (--len < 0) |
@@ -1040,23 +1119,26 @@ call_verify(struct rpc_task *task) | |||
1040 | case RPC_SUCCESS: | 1119 | case RPC_SUCCESS: |
1041 | return p; | 1120 | return p; |
1042 | case RPC_PROG_UNAVAIL: | 1121 | case RPC_PROG_UNAVAIL: |
1043 | printk(KERN_WARNING "RPC: call_verify: program %u is unsupported by server %s\n", | 1122 | dprintk("RPC: call_verify: program %u is unsupported by server %s\n", |
1044 | (unsigned int)task->tk_client->cl_prog, | 1123 | (unsigned int)task->tk_client->cl_prog, |
1045 | task->tk_client->cl_server); | 1124 | task->tk_client->cl_server); |
1046 | goto out_eio; | 1125 | error = -EPFNOSUPPORT; |
1126 | goto out_err; | ||
1047 | case RPC_PROG_MISMATCH: | 1127 | case RPC_PROG_MISMATCH: |
1048 | printk(KERN_WARNING "RPC: call_verify: program %u, version %u unsupported by server %s\n", | 1128 | dprintk("RPC: call_verify: program %u, version %u unsupported by server %s\n", |
1049 | (unsigned int)task->tk_client->cl_prog, | 1129 | (unsigned int)task->tk_client->cl_prog, |
1050 | (unsigned int)task->tk_client->cl_vers, | 1130 | (unsigned int)task->tk_client->cl_vers, |
1051 | task->tk_client->cl_server); | 1131 | task->tk_client->cl_server); |
1052 | goto out_eio; | 1132 | error = -EPROTONOSUPPORT; |
1133 | goto out_err; | ||
1053 | case RPC_PROC_UNAVAIL: | 1134 | case RPC_PROC_UNAVAIL: |
1054 | printk(KERN_WARNING "RPC: call_verify: proc %p unsupported by program %u, version %u on server %s\n", | 1135 | dprintk("RPC: call_verify: proc %p unsupported by program %u, version %u on server %s\n", |
1055 | task->tk_msg.rpc_proc, | 1136 | task->tk_msg.rpc_proc, |
1056 | task->tk_client->cl_prog, | 1137 | task->tk_client->cl_prog, |
1057 | task->tk_client->cl_vers, | 1138 | task->tk_client->cl_vers, |
1058 | task->tk_client->cl_server); | 1139 | task->tk_client->cl_server); |
1059 | goto out_eio; | 1140 | error = -EOPNOTSUPP; |
1141 | goto out_err; | ||
1060 | case RPC_GARBAGE_ARGS: | 1142 | case RPC_GARBAGE_ARGS: |
1061 | dprintk("RPC: %4d %s: server saw garbage\n", task->tk_pid, __FUNCTION__); | 1143 | dprintk("RPC: %4d %s: server saw garbage\n", task->tk_pid, __FUNCTION__); |
1062 | break; /* retry */ | 1144 | break; /* retry */ |
@@ -1069,7 +1151,7 @@ out_retry: | |||
1069 | task->tk_client->cl_stats->rpcgarbage++; | 1151 | task->tk_client->cl_stats->rpcgarbage++; |
1070 | if (task->tk_garb_retry) { | 1152 | if (task->tk_garb_retry) { |
1071 | task->tk_garb_retry--; | 1153 | task->tk_garb_retry--; |
1072 | dprintk(KERN_WARNING "RPC %s: retrying %4d\n", __FUNCTION__, task->tk_pid); | 1154 | dprintk("RPC %s: retrying %4d\n", __FUNCTION__, task->tk_pid); |
1073 | task->tk_action = call_bind; | 1155 | task->tk_action = call_bind; |
1074 | return NULL; | 1156 | return NULL; |
1075 | } | 1157 | } |
@@ -1083,3 +1165,30 @@ out_overflow: | |||
1083 | printk(KERN_WARNING "RPC %s: server reply was truncated.\n", __FUNCTION__); | 1165 | printk(KERN_WARNING "RPC %s: server reply was truncated.\n", __FUNCTION__); |
1084 | goto out_retry; | 1166 | goto out_retry; |
1085 | } | 1167 | } |
1168 | |||
1169 | static int rpcproc_encode_null(void *rqstp, u32 *data, void *obj) | ||
1170 | { | ||
1171 | return 0; | ||
1172 | } | ||
1173 | |||
1174 | static int rpcproc_decode_null(void *rqstp, u32 *data, void *obj) | ||
1175 | { | ||
1176 | return 0; | ||
1177 | } | ||
1178 | |||
1179 | static struct rpc_procinfo rpcproc_null = { | ||
1180 | .p_encode = rpcproc_encode_null, | ||
1181 | .p_decode = rpcproc_decode_null, | ||
1182 | }; | ||
1183 | |||
1184 | int rpc_ping(struct rpc_clnt *clnt, int flags) | ||
1185 | { | ||
1186 | struct rpc_message msg = { | ||
1187 | .rpc_proc = &rpcproc_null, | ||
1188 | }; | ||
1189 | int err; | ||
1190 | msg.rpc_cred = authnull_ops.lookup_cred(NULL, NULL, 0); | ||
1191 | err = rpc_call_sync(clnt, &msg, flags); | ||
1192 | put_rpccred(msg.rpc_cred); | ||
1193 | return err; | ||
1194 | } | ||
diff --git a/net/sunrpc/pmap_clnt.c b/net/sunrpc/pmap_clnt.c index d0b1d2c34a4d..4e81f2766923 100644 --- a/net/sunrpc/pmap_clnt.c +++ b/net/sunrpc/pmap_clnt.c | |||
@@ -53,6 +53,9 @@ rpc_getport(struct rpc_task *task, struct rpc_clnt *clnt) | |||
53 | task->tk_pid, clnt->cl_server, | 53 | task->tk_pid, clnt->cl_server, |
54 | map->pm_prog, map->pm_vers, map->pm_prot); | 54 | map->pm_prog, map->pm_vers, map->pm_prot); |
55 | 55 | ||
56 | /* Autobind on cloned rpc clients is discouraged */ | ||
57 | BUG_ON(clnt->cl_parent != clnt); | ||
58 | |||
56 | spin_lock(&pmap_lock); | 59 | spin_lock(&pmap_lock); |
57 | if (map->pm_binding) { | 60 | if (map->pm_binding) { |
58 | rpc_sleep_on(&map->pm_bindwait, task, NULL, NULL); | 61 | rpc_sleep_on(&map->pm_bindwait, task, NULL, NULL); |
@@ -207,12 +210,10 @@ pmap_create(char *hostname, struct sockaddr_in *srvaddr, int proto) | |||
207 | xprt->addr.sin_port = htons(RPC_PMAP_PORT); | 210 | xprt->addr.sin_port = htons(RPC_PMAP_PORT); |
208 | 211 | ||
209 | /* printk("pmap: create clnt\n"); */ | 212 | /* printk("pmap: create clnt\n"); */ |
210 | clnt = rpc_create_client(xprt, hostname, | 213 | clnt = rpc_new_client(xprt, hostname, |
211 | &pmap_program, RPC_PMAP_VERSION, | 214 | &pmap_program, RPC_PMAP_VERSION, |
212 | RPC_AUTH_UNIX); | 215 | RPC_AUTH_UNIX); |
213 | if (IS_ERR(clnt)) { | 216 | if (!IS_ERR(clnt)) { |
214 | xprt_destroy(xprt); | ||
215 | } else { | ||
216 | clnt->cl_softrtry = 1; | 217 | clnt->cl_softrtry = 1; |
217 | clnt->cl_chatty = 1; | 218 | clnt->cl_chatty = 1; |
218 | clnt->cl_oneshot = 1; | 219 | clnt->cl_oneshot = 1; |
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index c06614d0e31d..2d9eb7fbd521 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c | |||
@@ -290,7 +290,7 @@ static void rpc_make_runnable(struct rpc_task *task) | |||
290 | return; | 290 | return; |
291 | } | 291 | } |
292 | } else | 292 | } else |
293 | wake_up(&task->u.tk_wait.waitq); | 293 | wake_up_bit(&task->tk_runstate, RPC_TASK_QUEUED); |
294 | } | 294 | } |
295 | 295 | ||
296 | /* | 296 | /* |
@@ -555,6 +555,38 @@ __rpc_atrun(struct rpc_task *task) | |||
555 | } | 555 | } |
556 | 556 | ||
557 | /* | 557 | /* |
558 | * Helper that calls task->tk_exit if it exists and then returns | ||
559 | * true if we should exit __rpc_execute. | ||
560 | */ | ||
561 | static inline int __rpc_do_exit(struct rpc_task *task) | ||
562 | { | ||
563 | if (task->tk_exit != NULL) { | ||
564 | lock_kernel(); | ||
565 | task->tk_exit(task); | ||
566 | unlock_kernel(); | ||
567 | /* If tk_action is non-null, we should restart the call */ | ||
568 | if (task->tk_action != NULL) { | ||
569 | if (!RPC_ASSASSINATED(task)) { | ||
570 | /* Release RPC slot and buffer memory */ | ||
571 | xprt_release(task); | ||
572 | rpc_free(task); | ||
573 | return 0; | ||
574 | } | ||
575 | printk(KERN_ERR "RPC: dead task tried to walk away.\n"); | ||
576 | } | ||
577 | } | ||
578 | return 1; | ||
579 | } | ||
580 | |||
581 | static int rpc_wait_bit_interruptible(void *word) | ||
582 | { | ||
583 | if (signal_pending(current)) | ||
584 | return -ERESTARTSYS; | ||
585 | schedule(); | ||
586 | return 0; | ||
587 | } | ||
588 | |||
589 | /* | ||
558 | * This is the RPC `scheduler' (or rather, the finite state machine). | 590 | * This is the RPC `scheduler' (or rather, the finite state machine). |
559 | */ | 591 | */ |
560 | static int __rpc_execute(struct rpc_task *task) | 592 | static int __rpc_execute(struct rpc_task *task) |
@@ -566,8 +598,7 @@ static int __rpc_execute(struct rpc_task *task) | |||
566 | 598 | ||
567 | BUG_ON(RPC_IS_QUEUED(task)); | 599 | BUG_ON(RPC_IS_QUEUED(task)); |
568 | 600 | ||
569 | restarted: | 601 | for (;;) { |
570 | while (1) { | ||
571 | /* | 602 | /* |
572 | * Garbage collection of pending timers... | 603 | * Garbage collection of pending timers... |
573 | */ | 604 | */ |
@@ -600,11 +631,12 @@ static int __rpc_execute(struct rpc_task *task) | |||
600 | * by someone else. | 631 | * by someone else. |
601 | */ | 632 | */ |
602 | if (!RPC_IS_QUEUED(task)) { | 633 | if (!RPC_IS_QUEUED(task)) { |
603 | if (!task->tk_action) | 634 | if (task->tk_action != NULL) { |
635 | lock_kernel(); | ||
636 | task->tk_action(task); | ||
637 | unlock_kernel(); | ||
638 | } else if (__rpc_do_exit(task)) | ||
604 | break; | 639 | break; |
605 | lock_kernel(); | ||
606 | task->tk_action(task); | ||
607 | unlock_kernel(); | ||
608 | } | 640 | } |
609 | 641 | ||
610 | /* | 642 | /* |
@@ -624,44 +656,26 @@ static int __rpc_execute(struct rpc_task *task) | |||
624 | 656 | ||
625 | /* sync task: sleep here */ | 657 | /* sync task: sleep here */ |
626 | dprintk("RPC: %4d sync task going to sleep\n", task->tk_pid); | 658 | dprintk("RPC: %4d sync task going to sleep\n", task->tk_pid); |
627 | if (RPC_TASK_UNINTERRUPTIBLE(task)) { | 659 | /* Note: Caller should be using rpc_clnt_sigmask() */ |
628 | __wait_event(task->u.tk_wait.waitq, !RPC_IS_QUEUED(task)); | 660 | status = out_of_line_wait_on_bit(&task->tk_runstate, |
629 | } else { | 661 | RPC_TASK_QUEUED, rpc_wait_bit_interruptible, |
630 | __wait_event_interruptible(task->u.tk_wait.waitq, !RPC_IS_QUEUED(task), status); | 662 | TASK_INTERRUPTIBLE); |
663 | if (status == -ERESTARTSYS) { | ||
631 | /* | 664 | /* |
632 | * When a sync task receives a signal, it exits with | 665 | * When a sync task receives a signal, it exits with |
633 | * -ERESTARTSYS. In order to catch any callbacks that | 666 | * -ERESTARTSYS. In order to catch any callbacks that |
634 | * clean up after sleeping on some queue, we don't | 667 | * clean up after sleeping on some queue, we don't |
635 | * break the loop here, but go around once more. | 668 | * break the loop here, but go around once more. |
636 | */ | 669 | */ |
637 | if (status == -ERESTARTSYS) { | 670 | dprintk("RPC: %4d got signal\n", task->tk_pid); |
638 | dprintk("RPC: %4d got signal\n", task->tk_pid); | 671 | task->tk_flags |= RPC_TASK_KILLED; |
639 | task->tk_flags |= RPC_TASK_KILLED; | 672 | rpc_exit(task, -ERESTARTSYS); |
640 | rpc_exit(task, -ERESTARTSYS); | 673 | rpc_wake_up_task(task); |
641 | rpc_wake_up_task(task); | ||
642 | } | ||
643 | } | 674 | } |
644 | rpc_set_running(task); | 675 | rpc_set_running(task); |
645 | dprintk("RPC: %4d sync task resuming\n", task->tk_pid); | 676 | dprintk("RPC: %4d sync task resuming\n", task->tk_pid); |
646 | } | 677 | } |
647 | 678 | ||
648 | if (task->tk_exit) { | ||
649 | lock_kernel(); | ||
650 | task->tk_exit(task); | ||
651 | unlock_kernel(); | ||
652 | /* If tk_action is non-null, the user wants us to restart */ | ||
653 | if (task->tk_action) { | ||
654 | if (!RPC_ASSASSINATED(task)) { | ||
655 | /* Release RPC slot and buffer memory */ | ||
656 | if (task->tk_rqstp) | ||
657 | xprt_release(task); | ||
658 | rpc_free(task); | ||
659 | goto restarted; | ||
660 | } | ||
661 | printk(KERN_ERR "RPC: dead task tries to walk away.\n"); | ||
662 | } | ||
663 | } | ||
664 | |||
665 | dprintk("RPC: %4d exit() = %d\n", task->tk_pid, task->tk_status); | 679 | dprintk("RPC: %4d exit() = %d\n", task->tk_pid, task->tk_status); |
666 | status = task->tk_status; | 680 | status = task->tk_status; |
667 | 681 | ||
@@ -759,8 +773,6 @@ void rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt, rpc_action call | |||
759 | 773 | ||
760 | /* Initialize workqueue for async tasks */ | 774 | /* Initialize workqueue for async tasks */ |
761 | task->tk_workqueue = rpciod_workqueue; | 775 | task->tk_workqueue = rpciod_workqueue; |
762 | if (!RPC_IS_ASYNC(task)) | ||
763 | init_waitqueue_head(&task->u.tk_wait.waitq); | ||
764 | 776 | ||
765 | if (clnt) { | 777 | if (clnt) { |
766 | atomic_inc(&clnt->cl_users); | 778 | atomic_inc(&clnt->cl_users); |
diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c index d4f26bf9e732..32e8acbc60fe 100644 --- a/net/sunrpc/sunrpc_syms.c +++ b/net/sunrpc/sunrpc_syms.c | |||
@@ -42,6 +42,7 @@ EXPORT_SYMBOL(rpc_release_task); | |||
42 | /* RPC client functions */ | 42 | /* RPC client functions */ |
43 | EXPORT_SYMBOL(rpc_create_client); | 43 | EXPORT_SYMBOL(rpc_create_client); |
44 | EXPORT_SYMBOL(rpc_clone_client); | 44 | EXPORT_SYMBOL(rpc_clone_client); |
45 | EXPORT_SYMBOL(rpc_bind_new_program); | ||
45 | EXPORT_SYMBOL(rpc_destroy_client); | 46 | EXPORT_SYMBOL(rpc_destroy_client); |
46 | EXPORT_SYMBOL(rpc_shutdown_client); | 47 | EXPORT_SYMBOL(rpc_shutdown_client); |
47 | EXPORT_SYMBOL(rpc_release_client); | 48 | EXPORT_SYMBOL(rpc_release_client); |
@@ -61,7 +62,6 @@ EXPORT_SYMBOL(rpc_mkpipe); | |||
61 | 62 | ||
62 | /* Client transport */ | 63 | /* Client transport */ |
63 | EXPORT_SYMBOL(xprt_create_proto); | 64 | EXPORT_SYMBOL(xprt_create_proto); |
64 | EXPORT_SYMBOL(xprt_destroy); | ||
65 | EXPORT_SYMBOL(xprt_set_timeout); | 65 | EXPORT_SYMBOL(xprt_set_timeout); |
66 | EXPORT_SYMBOL(xprt_udp_slot_table_entries); | 66 | EXPORT_SYMBOL(xprt_udp_slot_table_entries); |
67 | EXPORT_SYMBOL(xprt_tcp_slot_table_entries); | 67 | EXPORT_SYMBOL(xprt_tcp_slot_table_entries); |
@@ -129,6 +129,10 @@ EXPORT_SYMBOL(xdr_encode_netobj); | |||
129 | EXPORT_SYMBOL(xdr_encode_pages); | 129 | EXPORT_SYMBOL(xdr_encode_pages); |
130 | EXPORT_SYMBOL(xdr_inline_pages); | 130 | EXPORT_SYMBOL(xdr_inline_pages); |
131 | EXPORT_SYMBOL(xdr_shift_buf); | 131 | EXPORT_SYMBOL(xdr_shift_buf); |
132 | EXPORT_SYMBOL(xdr_encode_word); | ||
133 | EXPORT_SYMBOL(xdr_decode_word); | ||
134 | EXPORT_SYMBOL(xdr_encode_array2); | ||
135 | EXPORT_SYMBOL(xdr_decode_array2); | ||
132 | EXPORT_SYMBOL(xdr_buf_from_iov); | 136 | EXPORT_SYMBOL(xdr_buf_from_iov); |
133 | EXPORT_SYMBOL(xdr_buf_subsegment); | 137 | EXPORT_SYMBOL(xdr_buf_subsegment); |
134 | EXPORT_SYMBOL(xdr_buf_read_netobj); | 138 | EXPORT_SYMBOL(xdr_buf_read_netobj); |
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index bb2d99f33315..e9bd91265f70 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c | |||
@@ -35,20 +35,24 @@ svc_create(struct svc_program *prog, unsigned int bufsize) | |||
35 | if (!(serv = (struct svc_serv *) kmalloc(sizeof(*serv), GFP_KERNEL))) | 35 | if (!(serv = (struct svc_serv *) kmalloc(sizeof(*serv), GFP_KERNEL))) |
36 | return NULL; | 36 | return NULL; |
37 | memset(serv, 0, sizeof(*serv)); | 37 | memset(serv, 0, sizeof(*serv)); |
38 | serv->sv_name = prog->pg_name; | ||
38 | serv->sv_program = prog; | 39 | serv->sv_program = prog; |
39 | serv->sv_nrthreads = 1; | 40 | serv->sv_nrthreads = 1; |
40 | serv->sv_stats = prog->pg_stats; | 41 | serv->sv_stats = prog->pg_stats; |
41 | serv->sv_bufsz = bufsize? bufsize : 4096; | 42 | serv->sv_bufsz = bufsize? bufsize : 4096; |
42 | prog->pg_lovers = prog->pg_nvers-1; | ||
43 | xdrsize = 0; | 43 | xdrsize = 0; |
44 | for (vers=0; vers<prog->pg_nvers ; vers++) | 44 | while (prog) { |
45 | if (prog->pg_vers[vers]) { | 45 | prog->pg_lovers = prog->pg_nvers-1; |
46 | prog->pg_hivers = vers; | 46 | for (vers=0; vers<prog->pg_nvers ; vers++) |
47 | if (prog->pg_lovers > vers) | 47 | if (prog->pg_vers[vers]) { |
48 | prog->pg_lovers = vers; | 48 | prog->pg_hivers = vers; |
49 | if (prog->pg_vers[vers]->vs_xdrsize > xdrsize) | 49 | if (prog->pg_lovers > vers) |
50 | xdrsize = prog->pg_vers[vers]->vs_xdrsize; | 50 | prog->pg_lovers = vers; |
51 | } | 51 | if (prog->pg_vers[vers]->vs_xdrsize > xdrsize) |
52 | xdrsize = prog->pg_vers[vers]->vs_xdrsize; | ||
53 | } | ||
54 | prog = prog->pg_next; | ||
55 | } | ||
52 | serv->sv_xdrsize = xdrsize; | 56 | serv->sv_xdrsize = xdrsize; |
53 | INIT_LIST_HEAD(&serv->sv_threads); | 57 | INIT_LIST_HEAD(&serv->sv_threads); |
54 | INIT_LIST_HEAD(&serv->sv_sockets); | 58 | INIT_LIST_HEAD(&serv->sv_sockets); |
@@ -56,8 +60,6 @@ svc_create(struct svc_program *prog, unsigned int bufsize) | |||
56 | INIT_LIST_HEAD(&serv->sv_permsocks); | 60 | INIT_LIST_HEAD(&serv->sv_permsocks); |
57 | spin_lock_init(&serv->sv_lock); | 61 | spin_lock_init(&serv->sv_lock); |
58 | 62 | ||
59 | serv->sv_name = prog->pg_name; | ||
60 | |||
61 | /* Remove any stale portmap registrations */ | 63 | /* Remove any stale portmap registrations */ |
62 | svc_register(serv, 0, 0); | 64 | svc_register(serv, 0, 0); |
63 | 65 | ||
@@ -281,6 +283,7 @@ svc_process(struct svc_serv *serv, struct svc_rqst *rqstp) | |||
281 | rqstp->rq_res.len = 0; | 283 | rqstp->rq_res.len = 0; |
282 | rqstp->rq_res.page_base = 0; | 284 | rqstp->rq_res.page_base = 0; |
283 | rqstp->rq_res.page_len = 0; | 285 | rqstp->rq_res.page_len = 0; |
286 | rqstp->rq_res.buflen = PAGE_SIZE; | ||
284 | rqstp->rq_res.tail[0].iov_len = 0; | 287 | rqstp->rq_res.tail[0].iov_len = 0; |
285 | /* tcp needs a space for the record length... */ | 288 | /* tcp needs a space for the record length... */ |
286 | if (rqstp->rq_prot == IPPROTO_TCP) | 289 | if (rqstp->rq_prot == IPPROTO_TCP) |
@@ -338,7 +341,10 @@ svc_process(struct svc_serv *serv, struct svc_rqst *rqstp) | |||
338 | goto sendit; | 341 | goto sendit; |
339 | } | 342 | } |
340 | 343 | ||
341 | if (prog != progp->pg_prog) | 344 | for (progp = serv->sv_program; progp; progp = progp->pg_next) |
345 | if (prog == progp->pg_prog) | ||
346 | break; | ||
347 | if (progp == NULL) | ||
342 | goto err_bad_prog; | 348 | goto err_bad_prog; |
343 | 349 | ||
344 | if (vers >= progp->pg_nvers || | 350 | if (vers >= progp->pg_nvers || |
@@ -451,11 +457,7 @@ err_bad_auth: | |||
451 | goto sendit; | 457 | goto sendit; |
452 | 458 | ||
453 | err_bad_prog: | 459 | err_bad_prog: |
454 | #ifdef RPC_PARANOIA | 460 | dprintk("svc: unknown program %d\n", prog); |
455 | if (prog != 100227 || progp->pg_prog != 100003) | ||
456 | printk("svc: unknown program %d (me %d)\n", prog, progp->pg_prog); | ||
457 | /* else it is just a Solaris client seeing if ACLs are supported */ | ||
458 | #endif | ||
459 | serv->sv_stats->rpcbadfmt++; | 461 | serv->sv_stats->rpcbadfmt++; |
460 | svc_putu32(resv, rpc_prog_unavail); | 462 | svc_putu32(resv, rpc_prog_unavail); |
461 | goto sendit; | 463 | goto sendit; |
diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c index 67b9f035ba86..8a4d9c106af1 100644 --- a/net/sunrpc/xdr.c +++ b/net/sunrpc/xdr.c | |||
@@ -176,21 +176,23 @@ xdr_inline_pages(struct xdr_buf *xdr, unsigned int offset, | |||
176 | xdr->buflen += len; | 176 | xdr->buflen += len; |
177 | } | 177 | } |
178 | 178 | ||
179 | void | 179 | ssize_t |
180 | xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base, | 180 | xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base, |
181 | skb_reader_t *desc, | 181 | skb_reader_t *desc, |
182 | skb_read_actor_t copy_actor) | 182 | skb_read_actor_t copy_actor) |
183 | { | 183 | { |
184 | struct page **ppage = xdr->pages; | 184 | struct page **ppage = xdr->pages; |
185 | unsigned int len, pglen = xdr->page_len; | 185 | unsigned int len, pglen = xdr->page_len; |
186 | ssize_t copied = 0; | ||
186 | int ret; | 187 | int ret; |
187 | 188 | ||
188 | len = xdr->head[0].iov_len; | 189 | len = xdr->head[0].iov_len; |
189 | if (base < len) { | 190 | if (base < len) { |
190 | len -= base; | 191 | len -= base; |
191 | ret = copy_actor(desc, (char *)xdr->head[0].iov_base + base, len); | 192 | ret = copy_actor(desc, (char *)xdr->head[0].iov_base + base, len); |
193 | copied += ret; | ||
192 | if (ret != len || !desc->count) | 194 | if (ret != len || !desc->count) |
193 | return; | 195 | goto out; |
194 | base = 0; | 196 | base = 0; |
195 | } else | 197 | } else |
196 | base -= len; | 198 | base -= len; |
@@ -210,6 +212,17 @@ xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base, | |||
210 | do { | 212 | do { |
211 | char *kaddr; | 213 | char *kaddr; |
212 | 214 | ||
215 | /* ACL likes to be lazy in allocating pages - ACLs | ||
216 | * are small by default but can get huge. */ | ||
217 | if (unlikely(*ppage == NULL)) { | ||
218 | *ppage = alloc_page(GFP_ATOMIC); | ||
219 | if (unlikely(*ppage == NULL)) { | ||
220 | if (copied == 0) | ||
221 | copied = -ENOMEM; | ||
222 | goto out; | ||
223 | } | ||
224 | } | ||
225 | |||
213 | len = PAGE_CACHE_SIZE; | 226 | len = PAGE_CACHE_SIZE; |
214 | kaddr = kmap_atomic(*ppage, KM_SKB_SUNRPC_DATA); | 227 | kaddr = kmap_atomic(*ppage, KM_SKB_SUNRPC_DATA); |
215 | if (base) { | 228 | if (base) { |
@@ -225,14 +238,17 @@ xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base, | |||
225 | } | 238 | } |
226 | flush_dcache_page(*ppage); | 239 | flush_dcache_page(*ppage); |
227 | kunmap_atomic(kaddr, KM_SKB_SUNRPC_DATA); | 240 | kunmap_atomic(kaddr, KM_SKB_SUNRPC_DATA); |
241 | copied += ret; | ||
228 | if (ret != len || !desc->count) | 242 | if (ret != len || !desc->count) |
229 | return; | 243 | goto out; |
230 | ppage++; | 244 | ppage++; |
231 | } while ((pglen -= len) != 0); | 245 | } while ((pglen -= len) != 0); |
232 | copy_tail: | 246 | copy_tail: |
233 | len = xdr->tail[0].iov_len; | 247 | len = xdr->tail[0].iov_len; |
234 | if (base < len) | 248 | if (base < len) |
235 | copy_actor(desc, (char *)xdr->tail[0].iov_base + base, len - base); | 249 | copied += copy_actor(desc, (char *)xdr->tail[0].iov_base + base, len - base); |
250 | out: | ||
251 | return copied; | ||
236 | } | 252 | } |
237 | 253 | ||
238 | 254 | ||
@@ -616,12 +632,24 @@ xdr_shift_buf(struct xdr_buf *buf, size_t len) | |||
616 | void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p) | 632 | void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p) |
617 | { | 633 | { |
618 | struct kvec *iov = buf->head; | 634 | struct kvec *iov = buf->head; |
635 | int scratch_len = buf->buflen - buf->page_len - buf->tail[0].iov_len; | ||
619 | 636 | ||
637 | BUG_ON(scratch_len < 0); | ||
620 | xdr->buf = buf; | 638 | xdr->buf = buf; |
621 | xdr->iov = iov; | 639 | xdr->iov = iov; |
622 | xdr->end = (uint32_t *)((char *)iov->iov_base + iov->iov_len); | 640 | xdr->p = (uint32_t *)((char *)iov->iov_base + iov->iov_len); |
623 | buf->len = iov->iov_len = (char *)p - (char *)iov->iov_base; | 641 | xdr->end = (uint32_t *)((char *)iov->iov_base + scratch_len); |
624 | xdr->p = p; | 642 | BUG_ON(iov->iov_len > scratch_len); |
643 | |||
644 | if (p != xdr->p && p != NULL) { | ||
645 | size_t len; | ||
646 | |||
647 | BUG_ON(p < xdr->p || p > xdr->end); | ||
648 | len = (char *)p - (char *)xdr->p; | ||
649 | xdr->p = p; | ||
650 | buf->len += len; | ||
651 | iov->iov_len += len; | ||
652 | } | ||
625 | } | 653 | } |
626 | EXPORT_SYMBOL(xdr_init_encode); | 654 | EXPORT_SYMBOL(xdr_init_encode); |
627 | 655 | ||
@@ -859,8 +887,34 @@ out: | |||
859 | return status; | 887 | return status; |
860 | } | 888 | } |
861 | 889 | ||
862 | static int | 890 | /* obj is assumed to point to allocated memory of size at least len: */ |
863 | read_u32_from_xdr_buf(struct xdr_buf *buf, int base, u32 *obj) | 891 | int |
892 | write_bytes_to_xdr_buf(struct xdr_buf *buf, int base, void *obj, int len) | ||
893 | { | ||
894 | struct xdr_buf subbuf; | ||
895 | int this_len; | ||
896 | int status; | ||
897 | |||
898 | status = xdr_buf_subsegment(buf, &subbuf, base, len); | ||
899 | if (status) | ||
900 | goto out; | ||
901 | this_len = min(len, (int)subbuf.head[0].iov_len); | ||
902 | memcpy(subbuf.head[0].iov_base, obj, this_len); | ||
903 | len -= this_len; | ||
904 | obj += this_len; | ||
905 | this_len = min(len, (int)subbuf.page_len); | ||
906 | if (this_len) | ||
907 | _copy_to_pages(subbuf.pages, subbuf.page_base, obj, this_len); | ||
908 | len -= this_len; | ||
909 | obj += this_len; | ||
910 | this_len = min(len, (int)subbuf.tail[0].iov_len); | ||
911 | memcpy(subbuf.tail[0].iov_base, obj, this_len); | ||
912 | out: | ||
913 | return status; | ||
914 | } | ||
915 | |||
916 | int | ||
917 | xdr_decode_word(struct xdr_buf *buf, int base, u32 *obj) | ||
864 | { | 918 | { |
865 | u32 raw; | 919 | u32 raw; |
866 | int status; | 920 | int status; |
@@ -872,6 +926,14 @@ read_u32_from_xdr_buf(struct xdr_buf *buf, int base, u32 *obj) | |||
872 | return 0; | 926 | return 0; |
873 | } | 927 | } |
874 | 928 | ||
929 | int | ||
930 | xdr_encode_word(struct xdr_buf *buf, int base, u32 obj) | ||
931 | { | ||
932 | u32 raw = htonl(obj); | ||
933 | |||
934 | return write_bytes_to_xdr_buf(buf, base, &raw, sizeof(obj)); | ||
935 | } | ||
936 | |||
875 | /* If the netobj starting offset bytes from the start of xdr_buf is contained | 937 | /* If the netobj starting offset bytes from the start of xdr_buf is contained |
876 | * entirely in the head or the tail, set object to point to it; otherwise | 938 | * entirely in the head or the tail, set object to point to it; otherwise |
877 | * try to find space for it at the end of the tail, copy it there, and | 939 | * try to find space for it at the end of the tail, copy it there, and |
@@ -882,7 +944,7 @@ xdr_buf_read_netobj(struct xdr_buf *buf, struct xdr_netobj *obj, int offset) | |||
882 | u32 tail_offset = buf->head[0].iov_len + buf->page_len; | 944 | u32 tail_offset = buf->head[0].iov_len + buf->page_len; |
883 | u32 obj_end_offset; | 945 | u32 obj_end_offset; |
884 | 946 | ||
885 | if (read_u32_from_xdr_buf(buf, offset, &obj->len)) | 947 | if (xdr_decode_word(buf, offset, &obj->len)) |
886 | goto out; | 948 | goto out; |
887 | obj_end_offset = offset + 4 + obj->len; | 949 | obj_end_offset = offset + 4 + obj->len; |
888 | 950 | ||
@@ -915,3 +977,219 @@ xdr_buf_read_netobj(struct xdr_buf *buf, struct xdr_netobj *obj, int offset) | |||
915 | out: | 977 | out: |
916 | return -1; | 978 | return -1; |
917 | } | 979 | } |
980 | |||
981 | /* Returns 0 on success, or else a negative error code. */ | ||
982 | static int | ||
983 | xdr_xcode_array2(struct xdr_buf *buf, unsigned int base, | ||
984 | struct xdr_array2_desc *desc, int encode) | ||
985 | { | ||
986 | char *elem = NULL, *c; | ||
987 | unsigned int copied = 0, todo, avail_here; | ||
988 | struct page **ppages = NULL; | ||
989 | int err; | ||
990 | |||
991 | if (encode) { | ||
992 | if (xdr_encode_word(buf, base, desc->array_len) != 0) | ||
993 | return -EINVAL; | ||
994 | } else { | ||
995 | if (xdr_decode_word(buf, base, &desc->array_len) != 0 || | ||
996 | (unsigned long) base + 4 + desc->array_len * | ||
997 | desc->elem_size > buf->len) | ||
998 | return -EINVAL; | ||
999 | } | ||
1000 | base += 4; | ||
1001 | |||
1002 | if (!desc->xcode) | ||
1003 | return 0; | ||
1004 | |||
1005 | todo = desc->array_len * desc->elem_size; | ||
1006 | |||
1007 | /* process head */ | ||
1008 | if (todo && base < buf->head->iov_len) { | ||
1009 | c = buf->head->iov_base + base; | ||
1010 | avail_here = min_t(unsigned int, todo, | ||
1011 | buf->head->iov_len - base); | ||
1012 | todo -= avail_here; | ||
1013 | |||
1014 | while (avail_here >= desc->elem_size) { | ||
1015 | err = desc->xcode(desc, c); | ||
1016 | if (err) | ||
1017 | goto out; | ||
1018 | c += desc->elem_size; | ||
1019 | avail_here -= desc->elem_size; | ||
1020 | } | ||
1021 | if (avail_here) { | ||
1022 | if (!elem) { | ||
1023 | elem = kmalloc(desc->elem_size, GFP_KERNEL); | ||
1024 | err = -ENOMEM; | ||
1025 | if (!elem) | ||
1026 | goto out; | ||
1027 | } | ||
1028 | if (encode) { | ||
1029 | err = desc->xcode(desc, elem); | ||
1030 | if (err) | ||
1031 | goto out; | ||
1032 | memcpy(c, elem, avail_here); | ||
1033 | } else | ||
1034 | memcpy(elem, c, avail_here); | ||
1035 | copied = avail_here; | ||
1036 | } | ||
1037 | base = buf->head->iov_len; /* align to start of pages */ | ||
1038 | } | ||
1039 | |||
1040 | /* process pages array */ | ||
1041 | base -= buf->head->iov_len; | ||
1042 | if (todo && base < buf->page_len) { | ||
1043 | unsigned int avail_page; | ||
1044 | |||
1045 | avail_here = min(todo, buf->page_len - base); | ||
1046 | todo -= avail_here; | ||
1047 | |||
1048 | base += buf->page_base; | ||
1049 | ppages = buf->pages + (base >> PAGE_CACHE_SHIFT); | ||
1050 | base &= ~PAGE_CACHE_MASK; | ||
1051 | avail_page = min_t(unsigned int, PAGE_CACHE_SIZE - base, | ||
1052 | avail_here); | ||
1053 | c = kmap(*ppages) + base; | ||
1054 | |||
1055 | while (avail_here) { | ||
1056 | avail_here -= avail_page; | ||
1057 | if (copied || avail_page < desc->elem_size) { | ||
1058 | unsigned int l = min(avail_page, | ||
1059 | desc->elem_size - copied); | ||
1060 | if (!elem) { | ||
1061 | elem = kmalloc(desc->elem_size, | ||
1062 | GFP_KERNEL); | ||
1063 | err = -ENOMEM; | ||
1064 | if (!elem) | ||
1065 | goto out; | ||
1066 | } | ||
1067 | if (encode) { | ||
1068 | if (!copied) { | ||
1069 | err = desc->xcode(desc, elem); | ||
1070 | if (err) | ||
1071 | goto out; | ||
1072 | } | ||
1073 | memcpy(c, elem + copied, l); | ||
1074 | copied += l; | ||
1075 | if (copied == desc->elem_size) | ||
1076 | copied = 0; | ||
1077 | } else { | ||
1078 | memcpy(elem + copied, c, l); | ||
1079 | copied += l; | ||
1080 | if (copied == desc->elem_size) { | ||
1081 | err = desc->xcode(desc, elem); | ||
1082 | if (err) | ||
1083 | goto out; | ||
1084 | copied = 0; | ||
1085 | } | ||
1086 | } | ||
1087 | avail_page -= l; | ||
1088 | c += l; | ||
1089 | } | ||
1090 | while (avail_page >= desc->elem_size) { | ||
1091 | err = desc->xcode(desc, c); | ||
1092 | if (err) | ||
1093 | goto out; | ||
1094 | c += desc->elem_size; | ||
1095 | avail_page -= desc->elem_size; | ||
1096 | } | ||
1097 | if (avail_page) { | ||
1098 | unsigned int l = min(avail_page, | ||
1099 | desc->elem_size - copied); | ||
1100 | if (!elem) { | ||
1101 | elem = kmalloc(desc->elem_size, | ||
1102 | GFP_KERNEL); | ||
1103 | err = -ENOMEM; | ||
1104 | if (!elem) | ||
1105 | goto out; | ||
1106 | } | ||
1107 | if (encode) { | ||
1108 | if (!copied) { | ||
1109 | err = desc->xcode(desc, elem); | ||
1110 | if (err) | ||
1111 | goto out; | ||
1112 | } | ||
1113 | memcpy(c, elem + copied, l); | ||
1114 | copied += l; | ||
1115 | if (copied == desc->elem_size) | ||
1116 | copied = 0; | ||
1117 | } else { | ||
1118 | memcpy(elem + copied, c, l); | ||
1119 | copied += l; | ||
1120 | if (copied == desc->elem_size) { | ||
1121 | err = desc->xcode(desc, elem); | ||
1122 | if (err) | ||
1123 | goto out; | ||
1124 | copied = 0; | ||
1125 | } | ||
1126 | } | ||
1127 | } | ||
1128 | if (avail_here) { | ||
1129 | kunmap(*ppages); | ||
1130 | ppages++; | ||
1131 | c = kmap(*ppages); | ||
1132 | } | ||
1133 | |||
1134 | avail_page = min(avail_here, | ||
1135 | (unsigned int) PAGE_CACHE_SIZE); | ||
1136 | } | ||
1137 | base = buf->page_len; /* align to start of tail */ | ||
1138 | } | ||
1139 | |||
1140 | /* process tail */ | ||
1141 | base -= buf->page_len; | ||
1142 | if (todo) { | ||
1143 | c = buf->tail->iov_base + base; | ||
1144 | if (copied) { | ||
1145 | unsigned int l = desc->elem_size - copied; | ||
1146 | |||
1147 | if (encode) | ||
1148 | memcpy(c, elem + copied, l); | ||
1149 | else { | ||
1150 | memcpy(elem + copied, c, l); | ||
1151 | err = desc->xcode(desc, elem); | ||
1152 | if (err) | ||
1153 | goto out; | ||
1154 | } | ||
1155 | todo -= l; | ||
1156 | c += l; | ||
1157 | } | ||
1158 | while (todo) { | ||
1159 | err = desc->xcode(desc, c); | ||
1160 | if (err) | ||
1161 | goto out; | ||
1162 | c += desc->elem_size; | ||
1163 | todo -= desc->elem_size; | ||
1164 | } | ||
1165 | } | ||
1166 | err = 0; | ||
1167 | |||
1168 | out: | ||
1169 | if (elem) | ||
1170 | kfree(elem); | ||
1171 | if (ppages) | ||
1172 | kunmap(*ppages); | ||
1173 | return err; | ||
1174 | } | ||
1175 | |||
1176 | int | ||
1177 | xdr_decode_array2(struct xdr_buf *buf, unsigned int base, | ||
1178 | struct xdr_array2_desc *desc) | ||
1179 | { | ||
1180 | if (base >= buf->len) | ||
1181 | return -EINVAL; | ||
1182 | |||
1183 | return xdr_xcode_array2(buf, base, desc, 0); | ||
1184 | } | ||
1185 | |||
1186 | int | ||
1187 | xdr_encode_array2(struct xdr_buf *buf, unsigned int base, | ||
1188 | struct xdr_array2_desc *desc) | ||
1189 | { | ||
1190 | if ((unsigned long) base + 4 + desc->array_len * desc->elem_size > | ||
1191 | buf->head->iov_len + buf->page_len + buf->tail->iov_len) | ||
1192 | return -EINVAL; | ||
1193 | |||
1194 | return xdr_xcode_array2(buf, base, desc, 1); | ||
1195 | } | ||
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index c74a6bb94074..eca92405948f 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c | |||
@@ -569,8 +569,11 @@ void xprt_connect(struct rpc_task *task) | |||
569 | if (xprt->sock != NULL) | 569 | if (xprt->sock != NULL) |
570 | schedule_delayed_work(&xprt->sock_connect, | 570 | schedule_delayed_work(&xprt->sock_connect, |
571 | RPC_REESTABLISH_TIMEOUT); | 571 | RPC_REESTABLISH_TIMEOUT); |
572 | else | 572 | else { |
573 | schedule_work(&xprt->sock_connect); | 573 | schedule_work(&xprt->sock_connect); |
574 | if (!RPC_IS_ASYNC(task)) | ||
575 | flush_scheduled_work(); | ||
576 | } | ||
574 | } | 577 | } |
575 | return; | 578 | return; |
576 | out_write: | 579 | out_write: |
@@ -725,7 +728,8 @@ csum_partial_copy_to_xdr(struct xdr_buf *xdr, struct sk_buff *skb) | |||
725 | goto no_checksum; | 728 | goto no_checksum; |
726 | 729 | ||
727 | desc.csum = csum_partial(skb->data, desc.offset, skb->csum); | 730 | desc.csum = csum_partial(skb->data, desc.offset, skb->csum); |
728 | xdr_partial_copy_from_skb(xdr, 0, &desc, skb_read_and_csum_bits); | 731 | if (xdr_partial_copy_from_skb(xdr, 0, &desc, skb_read_and_csum_bits) < 0) |
732 | return -1; | ||
729 | if (desc.offset != skb->len) { | 733 | if (desc.offset != skb->len) { |
730 | unsigned int csum2; | 734 | unsigned int csum2; |
731 | csum2 = skb_checksum(skb, desc.offset, skb->len - desc.offset, 0); | 735 | csum2 = skb_checksum(skb, desc.offset, skb->len - desc.offset, 0); |
@@ -737,7 +741,8 @@ csum_partial_copy_to_xdr(struct xdr_buf *xdr, struct sk_buff *skb) | |||
737 | return -1; | 741 | return -1; |
738 | return 0; | 742 | return 0; |
739 | no_checksum: | 743 | no_checksum: |
740 | xdr_partial_copy_from_skb(xdr, 0, &desc, skb_read_bits); | 744 | if (xdr_partial_copy_from_skb(xdr, 0, &desc, skb_read_bits) < 0) |
745 | return -1; | ||
741 | if (desc.count) | 746 | if (desc.count) |
742 | return -1; | 747 | return -1; |
743 | return 0; | 748 | return 0; |
@@ -821,10 +826,15 @@ tcp_copy_data(skb_reader_t *desc, void *p, size_t len) | |||
821 | { | 826 | { |
822 | if (len > desc->count) | 827 | if (len > desc->count) |
823 | len = desc->count; | 828 | len = desc->count; |
824 | if (skb_copy_bits(desc->skb, desc->offset, p, len)) | 829 | if (skb_copy_bits(desc->skb, desc->offset, p, len)) { |
830 | dprintk("RPC: failed to copy %zu bytes from skb. %zu bytes remain\n", | ||
831 | len, desc->count); | ||
825 | return 0; | 832 | return 0; |
833 | } | ||
826 | desc->offset += len; | 834 | desc->offset += len; |
827 | desc->count -= len; | 835 | desc->count -= len; |
836 | dprintk("RPC: copied %zu bytes from skb. %zu bytes remain\n", | ||
837 | len, desc->count); | ||
828 | return len; | 838 | return len; |
829 | } | 839 | } |
830 | 840 | ||
@@ -863,6 +873,8 @@ tcp_read_fraghdr(struct rpc_xprt *xprt, skb_reader_t *desc) | |||
863 | static void | 873 | static void |
864 | tcp_check_recm(struct rpc_xprt *xprt) | 874 | tcp_check_recm(struct rpc_xprt *xprt) |
865 | { | 875 | { |
876 | dprintk("RPC: xprt = %p, tcp_copied = %lu, tcp_offset = %u, tcp_reclen = %u, tcp_flags = %lx\n", | ||
877 | xprt, xprt->tcp_copied, xprt->tcp_offset, xprt->tcp_reclen, xprt->tcp_flags); | ||
866 | if (xprt->tcp_offset == xprt->tcp_reclen) { | 878 | if (xprt->tcp_offset == xprt->tcp_reclen) { |
867 | xprt->tcp_flags |= XPRT_COPY_RECM; | 879 | xprt->tcp_flags |= XPRT_COPY_RECM; |
868 | xprt->tcp_offset = 0; | 880 | xprt->tcp_offset = 0; |
@@ -907,6 +919,7 @@ tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc) | |||
907 | struct rpc_rqst *req; | 919 | struct rpc_rqst *req; |
908 | struct xdr_buf *rcvbuf; | 920 | struct xdr_buf *rcvbuf; |
909 | size_t len; | 921 | size_t len; |
922 | ssize_t r; | ||
910 | 923 | ||
911 | /* Find and lock the request corresponding to this xid */ | 924 | /* Find and lock the request corresponding to this xid */ |
912 | spin_lock(&xprt->sock_lock); | 925 | spin_lock(&xprt->sock_lock); |
@@ -927,15 +940,40 @@ tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc) | |||
927 | len = xprt->tcp_reclen - xprt->tcp_offset; | 940 | len = xprt->tcp_reclen - xprt->tcp_offset; |
928 | memcpy(&my_desc, desc, sizeof(my_desc)); | 941 | memcpy(&my_desc, desc, sizeof(my_desc)); |
929 | my_desc.count = len; | 942 | my_desc.count = len; |
930 | xdr_partial_copy_from_skb(rcvbuf, xprt->tcp_copied, | 943 | r = xdr_partial_copy_from_skb(rcvbuf, xprt->tcp_copied, |
931 | &my_desc, tcp_copy_data); | 944 | &my_desc, tcp_copy_data); |
932 | desc->count -= len; | 945 | desc->count -= r; |
933 | desc->offset += len; | 946 | desc->offset += r; |
934 | } else | 947 | } else |
935 | xdr_partial_copy_from_skb(rcvbuf, xprt->tcp_copied, | 948 | r = xdr_partial_copy_from_skb(rcvbuf, xprt->tcp_copied, |
936 | desc, tcp_copy_data); | 949 | desc, tcp_copy_data); |
937 | xprt->tcp_copied += len; | 950 | |
938 | xprt->tcp_offset += len; | 951 | if (r > 0) { |
952 | xprt->tcp_copied += r; | ||
953 | xprt->tcp_offset += r; | ||
954 | } | ||
955 | if (r != len) { | ||
956 | /* Error when copying to the receive buffer, | ||
957 | * usually because we weren't able to allocate | ||
958 | * additional buffer pages. All we can do now | ||
959 | * is turn off XPRT_COPY_DATA, so the request | ||
960 | * will not receive any additional updates, | ||
961 | * and time out. | ||
962 | * Any remaining data from this record will | ||
963 | * be discarded. | ||
964 | */ | ||
965 | xprt->tcp_flags &= ~XPRT_COPY_DATA; | ||
966 | dprintk("RPC: XID %08x truncated request\n", | ||
967 | ntohl(xprt->tcp_xid)); | ||
968 | dprintk("RPC: xprt = %p, tcp_copied = %lu, tcp_offset = %u, tcp_reclen = %u\n", | ||
969 | xprt, xprt->tcp_copied, xprt->tcp_offset, xprt->tcp_reclen); | ||
970 | goto out; | ||
971 | } | ||
972 | |||
973 | dprintk("RPC: XID %08x read %u bytes\n", | ||
974 | ntohl(xprt->tcp_xid), r); | ||
975 | dprintk("RPC: xprt = %p, tcp_copied = %lu, tcp_offset = %u, tcp_reclen = %u\n", | ||
976 | xprt, xprt->tcp_copied, xprt->tcp_offset, xprt->tcp_reclen); | ||
939 | 977 | ||
940 | if (xprt->tcp_copied == req->rq_private_buf.buflen) | 978 | if (xprt->tcp_copied == req->rq_private_buf.buflen) |
941 | xprt->tcp_flags &= ~XPRT_COPY_DATA; | 979 | xprt->tcp_flags &= ~XPRT_COPY_DATA; |
@@ -944,6 +982,7 @@ tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc) | |||
944 | xprt->tcp_flags &= ~XPRT_COPY_DATA; | 982 | xprt->tcp_flags &= ~XPRT_COPY_DATA; |
945 | } | 983 | } |
946 | 984 | ||
985 | out: | ||
947 | if (!(xprt->tcp_flags & XPRT_COPY_DATA)) { | 986 | if (!(xprt->tcp_flags & XPRT_COPY_DATA)) { |
948 | dprintk("RPC: %4d received reply complete\n", | 987 | dprintk("RPC: %4d received reply complete\n", |
949 | req->rq_task->tk_pid); | 988 | req->rq_task->tk_pid); |
@@ -967,6 +1006,7 @@ tcp_read_discard(struct rpc_xprt *xprt, skb_reader_t *desc) | |||
967 | desc->count -= len; | 1006 | desc->count -= len; |
968 | desc->offset += len; | 1007 | desc->offset += len; |
969 | xprt->tcp_offset += len; | 1008 | xprt->tcp_offset += len; |
1009 | dprintk("RPC: discarded %u bytes\n", len); | ||
970 | tcp_check_recm(xprt); | 1010 | tcp_check_recm(xprt); |
971 | } | 1011 | } |
972 | 1012 | ||
@@ -1064,8 +1104,7 @@ tcp_state_change(struct sock *sk) | |||
1064 | case TCP_SYN_RECV: | 1104 | case TCP_SYN_RECV: |
1065 | break; | 1105 | break; |
1066 | default: | 1106 | default: |
1067 | if (xprt_test_and_clear_connected(xprt)) | 1107 | xprt_disconnect(xprt); |
1068 | rpc_wake_up_status(&xprt->pending, -ENOTCONN); | ||
1069 | break; | 1108 | break; |
1070 | } | 1109 | } |
1071 | out: | 1110 | out: |
@@ -1203,6 +1242,8 @@ xprt_transmit(struct rpc_task *task) | |||
1203 | list_add_tail(&req->rq_list, &xprt->recv); | 1242 | list_add_tail(&req->rq_list, &xprt->recv); |
1204 | spin_unlock_bh(&xprt->sock_lock); | 1243 | spin_unlock_bh(&xprt->sock_lock); |
1205 | xprt_reset_majortimeo(req); | 1244 | xprt_reset_majortimeo(req); |
1245 | /* Turn off autodisconnect */ | ||
1246 | del_singleshot_timer_sync(&xprt->timer); | ||
1206 | } | 1247 | } |
1207 | } else if (!req->rq_bytes_sent) | 1248 | } else if (!req->rq_bytes_sent) |
1208 | return; | 1249 | return; |
@@ -1333,8 +1374,6 @@ xprt_reserve(struct rpc_task *task) | |||
1333 | spin_lock(&xprt->xprt_lock); | 1374 | spin_lock(&xprt->xprt_lock); |
1334 | do_xprt_reserve(task); | 1375 | do_xprt_reserve(task); |
1335 | spin_unlock(&xprt->xprt_lock); | 1376 | spin_unlock(&xprt->xprt_lock); |
1336 | if (task->tk_rqstp) | ||
1337 | del_timer_sync(&xprt->timer); | ||
1338 | } | 1377 | } |
1339 | } | 1378 | } |
1340 | 1379 | ||
@@ -1649,6 +1688,10 @@ xprt_shutdown(struct rpc_xprt *xprt) | |||
1649 | rpc_wake_up(&xprt->backlog); | 1688 | rpc_wake_up(&xprt->backlog); |
1650 | wake_up(&xprt->cong_wait); | 1689 | wake_up(&xprt->cong_wait); |
1651 | del_timer_sync(&xprt->timer); | 1690 | del_timer_sync(&xprt->timer); |
1691 | |||
1692 | /* synchronously wait for connect worker to finish */ | ||
1693 | cancel_delayed_work(&xprt->sock_connect); | ||
1694 | flush_scheduled_work(); | ||
1652 | } | 1695 | } |
1653 | 1696 | ||
1654 | /* | 1697 | /* |
diff --git a/sound/Kconfig b/sound/Kconfig index 047d59ea0573..ee794ae06040 100644 --- a/sound/Kconfig +++ b/sound/Kconfig | |||
@@ -42,6 +42,11 @@ menu "Advanced Linux Sound Architecture" | |||
42 | config SND | 42 | config SND |
43 | tristate "Advanced Linux Sound Architecture" | 43 | tristate "Advanced Linux Sound Architecture" |
44 | depends on SOUND | 44 | depends on SOUND |
45 | help | ||
46 | Say 'Y' or 'M' to enable ALSA (Advanced Linux Sound Architecture), | ||
47 | the new base sound system. | ||
48 | |||
49 | For more information, see <http://www.alsa-project.org/> | ||
45 | 50 | ||
46 | source "sound/core/Kconfig" | 51 | source "sound/core/Kconfig" |
47 | 52 | ||
diff --git a/sound/arm/Kconfig b/sound/arm/Kconfig index cdacf4d3a387..34c1740aa6e9 100644 --- a/sound/arm/Kconfig +++ b/sound/arm/Kconfig | |||
@@ -14,5 +14,11 @@ config SND_SA11XX_UDA1341 | |||
14 | To compile this driver as a module, choose M here: the module | 14 | To compile this driver as a module, choose M here: the module |
15 | will be called snd-sa11xx-uda1341. | 15 | will be called snd-sa11xx-uda1341. |
16 | 16 | ||
17 | config SND_ARMAACI | ||
18 | tristate "ARM PrimeCell PL041 AC Link support" | ||
19 | depends on SND && ARM_AMBA | ||
20 | select SND_PCM | ||
21 | select SND_AC97_CODEC | ||
22 | |||
17 | endmenu | 23 | endmenu |
18 | 24 | ||
diff --git a/sound/arm/Makefile b/sound/arm/Makefile index d7e7dc0c3cdf..f74ec28e1068 100644 --- a/sound/arm/Makefile +++ b/sound/arm/Makefile | |||
@@ -6,3 +6,6 @@ snd-sa11xx-uda1341-objs := sa11xx-uda1341.o | |||
6 | 6 | ||
7 | # Toplevel Module Dependency | 7 | # Toplevel Module Dependency |
8 | obj-$(CONFIG_SND_SA11XX_UDA1341) += snd-sa11xx-uda1341.o | 8 | obj-$(CONFIG_SND_SA11XX_UDA1341) += snd-sa11xx-uda1341.o |
9 | |||
10 | obj-$(CONFIG_SND_ARMAACI) += snd-aaci.o | ||
11 | snd-aaci-objs := aaci.o devdma.o | ||
diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c new file mode 100644 index 000000000000..08cc3ddca96f --- /dev/null +++ b/sound/arm/aaci.c | |||
@@ -0,0 +1,968 @@ | |||
1 | /* | ||
2 | * linux/sound/arm/aaci.c - ARM PrimeCell AACI PL041 driver | ||
3 | * | ||
4 | * Copyright (C) 2003 Deep Blue Solutions Ltd, All Rights Reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * Documentation: ARM DDI 0173B | ||
11 | */ | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/delay.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/ioport.h> | ||
16 | #include <linux/device.h> | ||
17 | #include <linux/spinlock.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/err.h> | ||
20 | |||
21 | #include <asm/io.h> | ||
22 | #include <asm/irq.h> | ||
23 | #include <asm/hardware/amba.h> | ||
24 | |||
25 | #include <sound/driver.h> | ||
26 | #include <sound/core.h> | ||
27 | #include <sound/initval.h> | ||
28 | #include <sound/ac97_codec.h> | ||
29 | #include <sound/pcm.h> | ||
30 | #include <sound/pcm_params.h> | ||
31 | |||
32 | #include "aaci.h" | ||
33 | #include "devdma.h" | ||
34 | |||
35 | #define DRIVER_NAME "aaci-pl041" | ||
36 | |||
37 | /* | ||
38 | * PM support is not complete. Turn it off. | ||
39 | */ | ||
40 | #undef CONFIG_PM | ||
41 | |||
42 | static void aaci_ac97_select_codec(struct aaci *aaci, ac97_t *ac97) | ||
43 | { | ||
44 | u32 v, maincr = aaci->maincr | MAINCR_SCRA(ac97->num); | ||
45 | |||
46 | /* | ||
47 | * Ensure that the slot 1/2 RX registers are empty. | ||
48 | */ | ||
49 | v = readl(aaci->base + AACI_SLFR); | ||
50 | if (v & SLFR_2RXV) | ||
51 | readl(aaci->base + AACI_SL2RX); | ||
52 | if (v & SLFR_1RXV) | ||
53 | readl(aaci->base + AACI_SL1RX); | ||
54 | |||
55 | writel(maincr, aaci->base + AACI_MAINCR); | ||
56 | } | ||
57 | |||
58 | /* | ||
59 | * P29: | ||
60 | * The recommended use of programming the external codec through slot 1 | ||
61 | * and slot 2 data is to use the channels during setup routines and the | ||
62 | * slot register at any other time. The data written into slot 1, slot 2 | ||
63 | * and slot 12 registers is transmitted only when their corresponding | ||
64 | * SI1TxEn, SI2TxEn and SI12TxEn bits are set in the AACI_MAINCR | ||
65 | * register. | ||
66 | */ | ||
67 | static void aaci_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short val) | ||
68 | { | ||
69 | struct aaci *aaci = ac97->private_data; | ||
70 | u32 v; | ||
71 | |||
72 | if (ac97->num >= 4) | ||
73 | return; | ||
74 | |||
75 | down(&aaci->ac97_sem); | ||
76 | |||
77 | aaci_ac97_select_codec(aaci, ac97); | ||
78 | |||
79 | /* | ||
80 | * P54: You must ensure that AACI_SL2TX is always written | ||
81 | * to, if required, before data is written to AACI_SL1TX. | ||
82 | */ | ||
83 | writel(val << 4, aaci->base + AACI_SL2TX); | ||
84 | writel(reg << 12, aaci->base + AACI_SL1TX); | ||
85 | |||
86 | /* | ||
87 | * Wait for the transmission of both slots to complete. | ||
88 | */ | ||
89 | do { | ||
90 | v = readl(aaci->base + AACI_SLFR); | ||
91 | } while (v & (SLFR_1TXB|SLFR_2TXB)); | ||
92 | |||
93 | up(&aaci->ac97_sem); | ||
94 | } | ||
95 | |||
96 | /* | ||
97 | * Read an AC'97 register. | ||
98 | */ | ||
99 | static unsigned short aaci_ac97_read(ac97_t *ac97, unsigned short reg) | ||
100 | { | ||
101 | struct aaci *aaci = ac97->private_data; | ||
102 | u32 v; | ||
103 | |||
104 | if (ac97->num >= 4) | ||
105 | return ~0; | ||
106 | |||
107 | down(&aaci->ac97_sem); | ||
108 | |||
109 | aaci_ac97_select_codec(aaci, ac97); | ||
110 | |||
111 | /* | ||
112 | * Write the register address to slot 1. | ||
113 | */ | ||
114 | writel((reg << 12) | (1 << 19), aaci->base + AACI_SL1TX); | ||
115 | |||
116 | /* | ||
117 | * Wait for the transmission to complete. | ||
118 | */ | ||
119 | do { | ||
120 | v = readl(aaci->base + AACI_SLFR); | ||
121 | } while (v & SLFR_1TXB); | ||
122 | |||
123 | /* | ||
124 | * Give the AC'97 codec more than enough time | ||
125 | * to respond. (42us = ~2 frames at 48kHz.) | ||
126 | */ | ||
127 | udelay(42); | ||
128 | |||
129 | /* | ||
130 | * Wait for slot 2 to indicate data. | ||
131 | */ | ||
132 | do { | ||
133 | cond_resched(); | ||
134 | v = readl(aaci->base + AACI_SLFR) & (SLFR_1RXV|SLFR_2RXV); | ||
135 | } while (v != (SLFR_1RXV|SLFR_2RXV)); | ||
136 | |||
137 | v = readl(aaci->base + AACI_SL1RX) >> 12; | ||
138 | if (v == reg) { | ||
139 | v = readl(aaci->base + AACI_SL2RX) >> 4; | ||
140 | } else { | ||
141 | dev_err(&aaci->dev->dev, | ||
142 | "wrong ac97 register read back (%x != %x)\n", | ||
143 | v, reg); | ||
144 | v = ~0; | ||
145 | } | ||
146 | |||
147 | up(&aaci->ac97_sem); | ||
148 | return v; | ||
149 | } | ||
150 | |||
151 | static inline void aaci_chan_wait_ready(struct aaci_runtime *aacirun) | ||
152 | { | ||
153 | u32 val; | ||
154 | int timeout = 5000; | ||
155 | |||
156 | do { | ||
157 | val = readl(aacirun->base + AACI_SR); | ||
158 | } while (val & (SR_TXB|SR_RXB) && timeout--); | ||
159 | } | ||
160 | |||
161 | |||
162 | |||
163 | /* | ||
164 | * Interrupt support. | ||
165 | */ | ||
166 | static void aaci_fifo_irq(struct aaci *aaci, u32 mask) | ||
167 | { | ||
168 | if (mask & ISR_URINTR) { | ||
169 | writel(ICLR_TXUEC1, aaci->base + AACI_INTCLR); | ||
170 | } | ||
171 | |||
172 | if (mask & ISR_TXINTR) { | ||
173 | struct aaci_runtime *aacirun = &aaci->playback; | ||
174 | void *ptr; | ||
175 | |||
176 | if (!aacirun->substream || !aacirun->start) { | ||
177 | dev_warn(&aaci->dev->dev, "TX interrupt???"); | ||
178 | writel(0, aacirun->base + AACI_IE); | ||
179 | return; | ||
180 | } | ||
181 | |||
182 | ptr = aacirun->ptr; | ||
183 | do { | ||
184 | unsigned int len = aacirun->fifosz; | ||
185 | u32 val; | ||
186 | |||
187 | if (aacirun->bytes <= 0) { | ||
188 | aacirun->bytes += aacirun->period; | ||
189 | aacirun->ptr = ptr; | ||
190 | spin_unlock(&aaci->lock); | ||
191 | snd_pcm_period_elapsed(aacirun->substream); | ||
192 | spin_lock(&aaci->lock); | ||
193 | } | ||
194 | if (!(aacirun->cr & TXCR_TXEN)) | ||
195 | break; | ||
196 | |||
197 | val = readl(aacirun->base + AACI_SR); | ||
198 | if (!(val & SR_TXHE)) | ||
199 | break; | ||
200 | if (!(val & SR_TXFE)) | ||
201 | len >>= 1; | ||
202 | |||
203 | aacirun->bytes -= len; | ||
204 | |||
205 | /* writing 16 bytes at a time */ | ||
206 | for ( ; len > 0; len -= 16) { | ||
207 | asm( | ||
208 | "ldmia %0!, {r0, r1, r2, r3}\n\t" | ||
209 | "stmia %1, {r0, r1, r2, r3}" | ||
210 | : "+r" (ptr) | ||
211 | : "r" (aacirun->fifo) | ||
212 | : "r0", "r1", "r2", "r3", "cc"); | ||
213 | |||
214 | if (ptr >= aacirun->end) | ||
215 | ptr = aacirun->start; | ||
216 | } | ||
217 | } while (1); | ||
218 | |||
219 | aacirun->ptr = ptr; | ||
220 | } | ||
221 | } | ||
222 | |||
223 | static irqreturn_t aaci_irq(int irq, void *devid, struct pt_regs *regs) | ||
224 | { | ||
225 | struct aaci *aaci = devid; | ||
226 | u32 mask; | ||
227 | int i; | ||
228 | |||
229 | spin_lock(&aaci->lock); | ||
230 | mask = readl(aaci->base + AACI_ALLINTS); | ||
231 | if (mask) { | ||
232 | u32 m = mask; | ||
233 | for (i = 0; i < 4; i++, m >>= 7) { | ||
234 | if (m & 0x7f) { | ||
235 | aaci_fifo_irq(aaci, m); | ||
236 | } | ||
237 | } | ||
238 | } | ||
239 | spin_unlock(&aaci->lock); | ||
240 | |||
241 | return mask ? IRQ_HANDLED : IRQ_NONE; | ||
242 | } | ||
243 | |||
244 | |||
245 | |||
246 | /* | ||
247 | * ALSA support. | ||
248 | */ | ||
249 | |||
250 | struct aaci_stream { | ||
251 | unsigned char codec_idx; | ||
252 | unsigned char rate_idx; | ||
253 | }; | ||
254 | |||
255 | static struct aaci_stream aaci_streams[] = { | ||
256 | [ACSTREAM_FRONT] = { | ||
257 | .codec_idx = 0, | ||
258 | .rate_idx = AC97_RATES_FRONT_DAC, | ||
259 | }, | ||
260 | [ACSTREAM_SURROUND] = { | ||
261 | .codec_idx = 0, | ||
262 | .rate_idx = AC97_RATES_SURR_DAC, | ||
263 | }, | ||
264 | [ACSTREAM_LFE] = { | ||
265 | .codec_idx = 0, | ||
266 | .rate_idx = AC97_RATES_LFE_DAC, | ||
267 | }, | ||
268 | }; | ||
269 | |||
270 | static inline unsigned int aaci_rate_mask(struct aaci *aaci, int streamid) | ||
271 | { | ||
272 | struct aaci_stream *s = aaci_streams + streamid; | ||
273 | return aaci->ac97_bus->codec[s->codec_idx]->rates[s->rate_idx]; | ||
274 | } | ||
275 | |||
276 | static unsigned int rate_list[] = { | ||
277 | 5512, 8000, 11025, 16000, 22050, 32000, 44100, | ||
278 | 48000, 64000, 88200, 96000, 176400, 192000 | ||
279 | }; | ||
280 | |||
281 | /* | ||
282 | * Double-rate rule: we can support double rate iff channels == 2 | ||
283 | * (unimplemented) | ||
284 | */ | ||
285 | static int | ||
286 | aaci_rule_rate_by_channels(snd_pcm_hw_params_t *p, snd_pcm_hw_rule_t *rule) | ||
287 | { | ||
288 | struct aaci *aaci = rule->private; | ||
289 | unsigned int rate_mask = SNDRV_PCM_RATE_8000_48000|SNDRV_PCM_RATE_5512; | ||
290 | snd_interval_t *c = hw_param_interval(p, SNDRV_PCM_HW_PARAM_CHANNELS); | ||
291 | |||
292 | switch (c->max) { | ||
293 | case 6: | ||
294 | rate_mask &= aaci_rate_mask(aaci, ACSTREAM_LFE); | ||
295 | case 4: | ||
296 | rate_mask &= aaci_rate_mask(aaci, ACSTREAM_SURROUND); | ||
297 | case 2: | ||
298 | rate_mask &= aaci_rate_mask(aaci, ACSTREAM_FRONT); | ||
299 | } | ||
300 | |||
301 | return snd_interval_list(hw_param_interval(p, rule->var), | ||
302 | ARRAY_SIZE(rate_list), rate_list, | ||
303 | rate_mask); | ||
304 | } | ||
305 | |||
306 | static snd_pcm_hardware_t aaci_hw_info = { | ||
307 | .info = SNDRV_PCM_INFO_MMAP | | ||
308 | SNDRV_PCM_INFO_MMAP_VALID | | ||
309 | SNDRV_PCM_INFO_INTERLEAVED | | ||
310 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
311 | SNDRV_PCM_INFO_RESUME, | ||
312 | |||
313 | /* | ||
314 | * ALSA doesn't support 18-bit or 20-bit packed into 32-bit | ||
315 | * words. It also doesn't support 12-bit at all. | ||
316 | */ | ||
317 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
318 | |||
319 | /* should this be continuous or knot? */ | ||
320 | .rates = SNDRV_PCM_RATE_CONTINUOUS, | ||
321 | .rate_max = 48000, | ||
322 | .rate_min = 4000, | ||
323 | .channels_min = 2, | ||
324 | .channels_max = 6, | ||
325 | .buffer_bytes_max = 64 * 1024, | ||
326 | .period_bytes_min = 256, | ||
327 | .period_bytes_max = PAGE_SIZE, | ||
328 | .periods_min = 4, | ||
329 | .periods_max = PAGE_SIZE / 16, | ||
330 | }; | ||
331 | |||
332 | static int aaci_pcm_open(struct aaci *aaci, snd_pcm_substream_t *substream, | ||
333 | struct aaci_runtime *aacirun) | ||
334 | { | ||
335 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
336 | int ret; | ||
337 | |||
338 | aacirun->substream = substream; | ||
339 | runtime->private_data = aacirun; | ||
340 | runtime->hw = aaci_hw_info; | ||
341 | |||
342 | /* | ||
343 | * FIXME: ALSA specifies fifo_size in bytes. If we're in normal | ||
344 | * mode, each 32-bit word contains one sample. If we're in | ||
345 | * compact mode, each 32-bit word contains two samples, effectively | ||
346 | * halving the FIFO size. However, we don't know for sure which | ||
347 | * we'll be using at this point. We set this to the lower limit. | ||
348 | */ | ||
349 | runtime->hw.fifo_size = aaci->fifosize * 2; | ||
350 | |||
351 | /* | ||
352 | * Add rule describing hardware rate dependency | ||
353 | * on the number of channels. | ||
354 | */ | ||
355 | ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, | ||
356 | aaci_rule_rate_by_channels, aaci, | ||
357 | SNDRV_PCM_HW_PARAM_CHANNELS, | ||
358 | SNDRV_PCM_HW_PARAM_RATE, -1); | ||
359 | if (ret) | ||
360 | goto out; | ||
361 | |||
362 | ret = request_irq(aaci->dev->irq[0], aaci_irq, SA_SHIRQ|SA_INTERRUPT, | ||
363 | DRIVER_NAME, aaci); | ||
364 | if (ret) | ||
365 | goto out; | ||
366 | |||
367 | return 0; | ||
368 | |||
369 | out: | ||
370 | return ret; | ||
371 | } | ||
372 | |||
373 | |||
374 | /* | ||
375 | * Common ALSA stuff | ||
376 | */ | ||
377 | static int aaci_pcm_close(snd_pcm_substream_t *substream) | ||
378 | { | ||
379 | struct aaci *aaci = substream->private_data; | ||
380 | struct aaci_runtime *aacirun = substream->runtime->private_data; | ||
381 | |||
382 | WARN_ON(aacirun->cr & TXCR_TXEN); | ||
383 | |||
384 | aacirun->substream = NULL; | ||
385 | free_irq(aaci->dev->irq[0], aaci); | ||
386 | |||
387 | return 0; | ||
388 | } | ||
389 | |||
390 | static int aaci_pcm_hw_free(snd_pcm_substream_t *substream) | ||
391 | { | ||
392 | struct aaci_runtime *aacirun = substream->runtime->private_data; | ||
393 | |||
394 | /* | ||
395 | * This must not be called with the device enabled. | ||
396 | */ | ||
397 | WARN_ON(aacirun->cr & TXCR_TXEN); | ||
398 | |||
399 | if (aacirun->pcm_open) | ||
400 | snd_ac97_pcm_close(aacirun->pcm); | ||
401 | aacirun->pcm_open = 0; | ||
402 | |||
403 | /* | ||
404 | * Clear out the DMA and any allocated buffers. | ||
405 | */ | ||
406 | devdma_hw_free(NULL, substream); | ||
407 | |||
408 | return 0; | ||
409 | } | ||
410 | |||
411 | static int aaci_pcm_hw_params(snd_pcm_substream_t *substream, | ||
412 | struct aaci_runtime *aacirun, | ||
413 | snd_pcm_hw_params_t *params) | ||
414 | { | ||
415 | int err; | ||
416 | |||
417 | aaci_pcm_hw_free(substream); | ||
418 | |||
419 | err = devdma_hw_alloc(NULL, substream, | ||
420 | params_buffer_bytes(params)); | ||
421 | if (err < 0) | ||
422 | goto out; | ||
423 | |||
424 | err = snd_ac97_pcm_open(aacirun->pcm, params_rate(params), | ||
425 | params_channels(params), | ||
426 | aacirun->pcm->r[0].slots); | ||
427 | if (err) | ||
428 | goto out; | ||
429 | |||
430 | aacirun->pcm_open = 1; | ||
431 | |||
432 | out: | ||
433 | return err; | ||
434 | } | ||
435 | |||
436 | static int aaci_pcm_prepare(snd_pcm_substream_t *substream) | ||
437 | { | ||
438 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
439 | struct aaci_runtime *aacirun = runtime->private_data; | ||
440 | |||
441 | aacirun->start = (void *)runtime->dma_area; | ||
442 | aacirun->end = aacirun->start + runtime->dma_bytes; | ||
443 | aacirun->ptr = aacirun->start; | ||
444 | aacirun->period = | ||
445 | aacirun->bytes = frames_to_bytes(runtime, runtime->period_size); | ||
446 | |||
447 | return 0; | ||
448 | } | ||
449 | |||
450 | static snd_pcm_uframes_t aaci_pcm_pointer(snd_pcm_substream_t *substream) | ||
451 | { | ||
452 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
453 | struct aaci_runtime *aacirun = runtime->private_data; | ||
454 | ssize_t bytes = aacirun->ptr - aacirun->start; | ||
455 | |||
456 | return bytes_to_frames(runtime, bytes); | ||
457 | } | ||
458 | |||
459 | static int aaci_pcm_mmap(snd_pcm_substream_t *substream, struct vm_area_struct *vma) | ||
460 | { | ||
461 | return devdma_mmap(NULL, substream, vma); | ||
462 | } | ||
463 | |||
464 | |||
465 | /* | ||
466 | * Playback specific ALSA stuff | ||
467 | */ | ||
468 | static const u32 channels_to_txmask[] = { | ||
469 | [2] = TXCR_TX3 | TXCR_TX4, | ||
470 | [4] = TXCR_TX3 | TXCR_TX4 | TXCR_TX7 | TXCR_TX8, | ||
471 | [6] = TXCR_TX3 | TXCR_TX4 | TXCR_TX7 | TXCR_TX8 | TXCR_TX6 | TXCR_TX9, | ||
472 | }; | ||
473 | |||
474 | /* | ||
475 | * We can support two and four channel audio. Unfortunately | ||
476 | * six channel audio requires a non-standard channel ordering: | ||
477 | * 2 -> FL(3), FR(4) | ||
478 | * 4 -> FL(3), FR(4), SL(7), SR(8) | ||
479 | * 6 -> FL(3), FR(4), SL(7), SR(8), C(6), LFE(9) (required) | ||
480 | * FL(3), FR(4), C(6), SL(7), SR(8), LFE(9) (actual) | ||
481 | * This requires an ALSA configuration file to correct. | ||
482 | */ | ||
483 | static unsigned int channel_list[] = { 2, 4, 6 }; | ||
484 | |||
485 | static int | ||
486 | aaci_rule_channels(snd_pcm_hw_params_t *p, snd_pcm_hw_rule_t *rule) | ||
487 | { | ||
488 | struct aaci *aaci = rule->private; | ||
489 | unsigned int chan_mask = 1 << 0, slots; | ||
490 | |||
491 | /* | ||
492 | * pcms[0] is the our 5.1 PCM instance. | ||
493 | */ | ||
494 | slots = aaci->ac97_bus->pcms[0].r[0].slots; | ||
495 | if (slots & (1 << AC97_SLOT_PCM_SLEFT)) { | ||
496 | chan_mask |= 1 << 1; | ||
497 | if (slots & (1 << AC97_SLOT_LFE)) | ||
498 | chan_mask |= 1 << 2; | ||
499 | } | ||
500 | |||
501 | return snd_interval_list(hw_param_interval(p, rule->var), | ||
502 | ARRAY_SIZE(channel_list), channel_list, | ||
503 | chan_mask); | ||
504 | } | ||
505 | |||
506 | static int aaci_pcm_playback_open(snd_pcm_substream_t *substream) | ||
507 | { | ||
508 | struct aaci *aaci = substream->private_data; | ||
509 | int ret; | ||
510 | |||
511 | /* | ||
512 | * Add rule describing channel dependency. | ||
513 | */ | ||
514 | ret = snd_pcm_hw_rule_add(substream->runtime, 0, | ||
515 | SNDRV_PCM_HW_PARAM_CHANNELS, | ||
516 | aaci_rule_channels, aaci, | ||
517 | SNDRV_PCM_HW_PARAM_CHANNELS, -1); | ||
518 | if (ret) | ||
519 | return ret; | ||
520 | |||
521 | return aaci_pcm_open(aaci, substream, &aaci->playback); | ||
522 | } | ||
523 | |||
524 | static int aaci_pcm_playback_hw_params(snd_pcm_substream_t *substream, | ||
525 | snd_pcm_hw_params_t *params) | ||
526 | { | ||
527 | struct aaci *aaci = substream->private_data; | ||
528 | struct aaci_runtime *aacirun = substream->runtime->private_data; | ||
529 | unsigned int channels = params_channels(params); | ||
530 | int ret; | ||
531 | |||
532 | WARN_ON(channels >= ARRAY_SIZE(channels_to_txmask) || | ||
533 | !channels_to_txmask[channels]); | ||
534 | |||
535 | ret = aaci_pcm_hw_params(substream, aacirun, params); | ||
536 | |||
537 | /* | ||
538 | * Enable FIFO, compact mode, 16 bits per sample. | ||
539 | * FIXME: double rate slots? | ||
540 | */ | ||
541 | if (ret >= 0) { | ||
542 | aacirun->cr = TXCR_FEN | TXCR_COMPACT | TXCR_TSZ16; | ||
543 | aacirun->cr |= channels_to_txmask[channels]; | ||
544 | |||
545 | aacirun->fifosz = aaci->fifosize * 4; | ||
546 | if (aacirun->cr & TXCR_COMPACT) | ||
547 | aacirun->fifosz >>= 1; | ||
548 | } | ||
549 | return ret; | ||
550 | } | ||
551 | |||
552 | static void aaci_pcm_playback_stop(struct aaci_runtime *aacirun) | ||
553 | { | ||
554 | u32 ie; | ||
555 | |||
556 | ie = readl(aacirun->base + AACI_IE); | ||
557 | ie &= ~(IE_URIE|IE_TXIE); | ||
558 | writel(ie, aacirun->base + AACI_IE); | ||
559 | aacirun->cr &= ~TXCR_TXEN; | ||
560 | aaci_chan_wait_ready(aacirun); | ||
561 | writel(aacirun->cr, aacirun->base + AACI_TXCR); | ||
562 | } | ||
563 | |||
564 | static void aaci_pcm_playback_start(struct aaci_runtime *aacirun) | ||
565 | { | ||
566 | u32 ie; | ||
567 | |||
568 | aaci_chan_wait_ready(aacirun); | ||
569 | aacirun->cr |= TXCR_TXEN; | ||
570 | |||
571 | ie = readl(aacirun->base + AACI_IE); | ||
572 | ie |= IE_URIE | IE_TXIE; | ||
573 | writel(ie, aacirun->base + AACI_IE); | ||
574 | writel(aacirun->cr, aacirun->base + AACI_TXCR); | ||
575 | } | ||
576 | |||
577 | static int aaci_pcm_playback_trigger(snd_pcm_substream_t *substream, int cmd) | ||
578 | { | ||
579 | struct aaci *aaci = substream->private_data; | ||
580 | struct aaci_runtime *aacirun = substream->runtime->private_data; | ||
581 | unsigned long flags; | ||
582 | int ret = 0; | ||
583 | |||
584 | spin_lock_irqsave(&aaci->lock, flags); | ||
585 | switch (cmd) { | ||
586 | case SNDRV_PCM_TRIGGER_START: | ||
587 | aaci_pcm_playback_start(aacirun); | ||
588 | break; | ||
589 | |||
590 | case SNDRV_PCM_TRIGGER_RESUME: | ||
591 | aaci_pcm_playback_start(aacirun); | ||
592 | break; | ||
593 | |||
594 | case SNDRV_PCM_TRIGGER_STOP: | ||
595 | aaci_pcm_playback_stop(aacirun); | ||
596 | break; | ||
597 | |||
598 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
599 | aaci_pcm_playback_stop(aacirun); | ||
600 | break; | ||
601 | |||
602 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
603 | break; | ||
604 | |||
605 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
606 | break; | ||
607 | |||
608 | default: | ||
609 | ret = -EINVAL; | ||
610 | } | ||
611 | spin_unlock_irqrestore(&aaci->lock, flags); | ||
612 | |||
613 | return ret; | ||
614 | } | ||
615 | |||
616 | static snd_pcm_ops_t aaci_playback_ops = { | ||
617 | .open = aaci_pcm_playback_open, | ||
618 | .close = aaci_pcm_close, | ||
619 | .ioctl = snd_pcm_lib_ioctl, | ||
620 | .hw_params = aaci_pcm_playback_hw_params, | ||
621 | .hw_free = aaci_pcm_hw_free, | ||
622 | .prepare = aaci_pcm_prepare, | ||
623 | .trigger = aaci_pcm_playback_trigger, | ||
624 | .pointer = aaci_pcm_pointer, | ||
625 | .mmap = aaci_pcm_mmap, | ||
626 | }; | ||
627 | |||
628 | |||
629 | |||
630 | /* | ||
631 | * Power Management. | ||
632 | */ | ||
633 | #ifdef CONFIG_PM | ||
634 | static int aaci_do_suspend(snd_card_t *card, unsigned int state) | ||
635 | { | ||
636 | struct aaci *aaci = card->private_data; | ||
637 | if (aaci->card->power_state != SNDRV_CTL_POWER_D3cold) { | ||
638 | snd_pcm_suspend_all(aaci->pcm); | ||
639 | snd_power_change_state(aaci->card, SNDRV_CTL_POWER_D3cold); | ||
640 | } | ||
641 | return 0; | ||
642 | } | ||
643 | |||
644 | static int aaci_do_resume(snd_card_t *card, unsigned int state) | ||
645 | { | ||
646 | struct aaci *aaci = card->private_data; | ||
647 | if (aaci->card->power_state != SNDRV_CTL_POWER_D0) { | ||
648 | snd_power_change_state(aaci->card, SNDRV_CTL_POWER_D0); | ||
649 | } | ||
650 | return 0; | ||
651 | } | ||
652 | |||
653 | static int aaci_suspend(struct amba_device *dev, u32 state) | ||
654 | { | ||
655 | snd_card_t *card = amba_get_drvdata(dev); | ||
656 | return card ? aaci_do_suspend(card) : 0; | ||
657 | } | ||
658 | |||
659 | static int aaci_resume(struct amba_device *dev) | ||
660 | { | ||
661 | snd_card_t *card = amba_get_drvdata(dev); | ||
662 | return card ? aaci_do_resume(card) : 0; | ||
663 | } | ||
664 | #else | ||
665 | #define aaci_do_suspend NULL | ||
666 | #define aaci_do_resume NULL | ||
667 | #define aaci_suspend NULL | ||
668 | #define aaci_resume NULL | ||
669 | #endif | ||
670 | |||
671 | |||
672 | static struct ac97_pcm ac97_defs[] __devinitdata = { | ||
673 | [0] = { /* Front PCM */ | ||
674 | .exclusive = 1, | ||
675 | .r = { | ||
676 | [0] = { | ||
677 | .slots = (1 << AC97_SLOT_PCM_LEFT) | | ||
678 | (1 << AC97_SLOT_PCM_RIGHT) | | ||
679 | (1 << AC97_SLOT_PCM_CENTER) | | ||
680 | (1 << AC97_SLOT_PCM_SLEFT) | | ||
681 | (1 << AC97_SLOT_PCM_SRIGHT) | | ||
682 | (1 << AC97_SLOT_LFE), | ||
683 | }, | ||
684 | }, | ||
685 | }, | ||
686 | [1] = { /* PCM in */ | ||
687 | .stream = 1, | ||
688 | .exclusive = 1, | ||
689 | .r = { | ||
690 | [0] = { | ||
691 | .slots = (1 << AC97_SLOT_PCM_LEFT) | | ||
692 | (1 << AC97_SLOT_PCM_RIGHT), | ||
693 | }, | ||
694 | }, | ||
695 | }, | ||
696 | [2] = { /* Mic in */ | ||
697 | .stream = 1, | ||
698 | .exclusive = 1, | ||
699 | .r = { | ||
700 | [0] = { | ||
701 | .slots = (1 << AC97_SLOT_MIC), | ||
702 | }, | ||
703 | }, | ||
704 | } | ||
705 | }; | ||
706 | |||
707 | static ac97_bus_ops_t aaci_bus_ops = { | ||
708 | .write = aaci_ac97_write, | ||
709 | .read = aaci_ac97_read, | ||
710 | }; | ||
711 | |||
712 | static int __devinit aaci_probe_ac97(struct aaci *aaci) | ||
713 | { | ||
714 | ac97_template_t ac97_template; | ||
715 | ac97_bus_t *ac97_bus; | ||
716 | ac97_t *ac97; | ||
717 | int ret; | ||
718 | |||
719 | /* | ||
720 | * Assert AACIRESET for 2us | ||
721 | */ | ||
722 | writel(0, aaci->base + AACI_RESET); | ||
723 | udelay(2); | ||
724 | writel(RESET_NRST, aaci->base + AACI_RESET); | ||
725 | |||
726 | /* | ||
727 | * Give the AC'97 codec more than enough time | ||
728 | * to wake up. (42us = ~2 frames at 48kHz.) | ||
729 | */ | ||
730 | udelay(42); | ||
731 | |||
732 | ret = snd_ac97_bus(aaci->card, 0, &aaci_bus_ops, aaci, &ac97_bus); | ||
733 | if (ret) | ||
734 | goto out; | ||
735 | |||
736 | ac97_bus->clock = 48000; | ||
737 | aaci->ac97_bus = ac97_bus; | ||
738 | |||
739 | memset(&ac97_template, 0, sizeof(ac97_template_t)); | ||
740 | ac97_template.private_data = aaci; | ||
741 | ac97_template.num = 0; | ||
742 | ac97_template.scaps = AC97_SCAP_SKIP_MODEM; | ||
743 | |||
744 | ret = snd_ac97_mixer(ac97_bus, &ac97_template, &ac97); | ||
745 | if (ret) | ||
746 | goto out; | ||
747 | |||
748 | /* | ||
749 | * Disable AC97 PC Beep input on audio codecs. | ||
750 | */ | ||
751 | if (ac97_is_audio(ac97)) | ||
752 | snd_ac97_write_cache(ac97, AC97_PC_BEEP, 0x801e); | ||
753 | |||
754 | ret = snd_ac97_pcm_assign(ac97_bus, ARRAY_SIZE(ac97_defs), ac97_defs); | ||
755 | if (ret) | ||
756 | goto out; | ||
757 | |||
758 | aaci->playback.pcm = &ac97_bus->pcms[0]; | ||
759 | |||
760 | out: | ||
761 | return ret; | ||
762 | } | ||
763 | |||
764 | static void aaci_free_card(snd_card_t *card) | ||
765 | { | ||
766 | struct aaci *aaci = card->private_data; | ||
767 | if (aaci->base) | ||
768 | iounmap(aaci->base); | ||
769 | } | ||
770 | |||
771 | static struct aaci * __devinit aaci_init_card(struct amba_device *dev) | ||
772 | { | ||
773 | struct aaci *aaci; | ||
774 | snd_card_t *card; | ||
775 | |||
776 | card = snd_card_new(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, | ||
777 | THIS_MODULE, sizeof(struct aaci)); | ||
778 | if (card == NULL) | ||
779 | return ERR_PTR(-ENOMEM); | ||
780 | |||
781 | card->private_free = aaci_free_card; | ||
782 | snd_card_set_pm_callback(card, aaci_do_suspend, aaci_do_resume, NULL); | ||
783 | |||
784 | strlcpy(card->driver, DRIVER_NAME, sizeof(card->driver)); | ||
785 | strlcpy(card->shortname, "ARM AC'97 Interface", sizeof(card->shortname)); | ||
786 | snprintf(card->longname, sizeof(card->longname), | ||
787 | "%s at 0x%08lx, irq %d", | ||
788 | card->shortname, dev->res.start, dev->irq[0]); | ||
789 | |||
790 | aaci = card->private_data; | ||
791 | init_MUTEX(&aaci->ac97_sem); | ||
792 | spin_lock_init(&aaci->lock); | ||
793 | aaci->card = card; | ||
794 | aaci->dev = dev; | ||
795 | |||
796 | /* Set MAINCR to allow slot 1 and 2 data IO */ | ||
797 | aaci->maincr = MAINCR_IE | MAINCR_SL1RXEN | MAINCR_SL1TXEN | | ||
798 | MAINCR_SL2RXEN | MAINCR_SL2TXEN; | ||
799 | |||
800 | return aaci; | ||
801 | } | ||
802 | |||
803 | static int __devinit aaci_init_pcm(struct aaci *aaci) | ||
804 | { | ||
805 | snd_pcm_t *pcm; | ||
806 | int ret; | ||
807 | |||
808 | ret = snd_pcm_new(aaci->card, "AACI AC'97", 0, 1, 0, &pcm); | ||
809 | if (ret == 0) { | ||
810 | aaci->pcm = pcm; | ||
811 | pcm->private_data = aaci; | ||
812 | pcm->info_flags = 0; | ||
813 | |||
814 | strlcpy(pcm->name, DRIVER_NAME, sizeof(pcm->name)); | ||
815 | |||
816 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &aaci_playback_ops); | ||
817 | } | ||
818 | |||
819 | return ret; | ||
820 | } | ||
821 | |||
822 | static unsigned int __devinit aaci_size_fifo(struct aaci *aaci) | ||
823 | { | ||
824 | void *base = aaci->base + AACI_CSCH1; | ||
825 | int i; | ||
826 | |||
827 | writel(TXCR_FEN | TXCR_TSZ16 | TXCR_TXEN, base + AACI_TXCR); | ||
828 | |||
829 | for (i = 0; !(readl(base + AACI_SR) & SR_TXFF) && i < 4096; i++) | ||
830 | writel(0, aaci->base + AACI_DR1); | ||
831 | |||
832 | writel(0, base + AACI_TXCR); | ||
833 | |||
834 | /* | ||
835 | * Re-initialise the AACI after the FIFO depth test, to | ||
836 | * ensure that the FIFOs are empty. Unfortunately, merely | ||
837 | * disabling the channel doesn't clear the FIFO. | ||
838 | */ | ||
839 | writel(aaci->maincr & ~MAINCR_IE, aaci->base + AACI_MAINCR); | ||
840 | writel(aaci->maincr, aaci->base + AACI_MAINCR); | ||
841 | |||
842 | /* | ||
843 | * If we hit 4096, we failed. Go back to the specified | ||
844 | * fifo depth. | ||
845 | */ | ||
846 | if (i == 4096) | ||
847 | i = 8; | ||
848 | |||
849 | return i; | ||
850 | } | ||
851 | |||
852 | static int __devinit aaci_probe(struct amba_device *dev, void *id) | ||
853 | { | ||
854 | struct aaci *aaci; | ||
855 | int ret, i; | ||
856 | |||
857 | ret = amba_request_regions(dev, NULL); | ||
858 | if (ret) | ||
859 | return ret; | ||
860 | |||
861 | aaci = aaci_init_card(dev); | ||
862 | if (IS_ERR(aaci)) { | ||
863 | ret = PTR_ERR(aaci); | ||
864 | goto out; | ||
865 | } | ||
866 | |||
867 | aaci->base = ioremap(dev->res.start, SZ_4K); | ||
868 | if (!aaci->base) { | ||
869 | ret = -ENOMEM; | ||
870 | goto out; | ||
871 | } | ||
872 | |||
873 | /* | ||
874 | * Playback uses AACI channel 0 | ||
875 | */ | ||
876 | aaci->playback.base = aaci->base + AACI_CSCH1; | ||
877 | aaci->playback.fifo = aaci->base + AACI_DR1; | ||
878 | |||
879 | for (i = 0; i < 4; i++) { | ||
880 | void *base = aaci->base + i * 0x14; | ||
881 | |||
882 | writel(0, base + AACI_IE); | ||
883 | writel(0, base + AACI_TXCR); | ||
884 | writel(0, base + AACI_RXCR); | ||
885 | } | ||
886 | |||
887 | writel(0x1fff, aaci->base + AACI_INTCLR); | ||
888 | writel(aaci->maincr, aaci->base + AACI_MAINCR); | ||
889 | |||
890 | /* | ||
891 | * Size the FIFOs. | ||
892 | */ | ||
893 | aaci->fifosize = aaci_size_fifo(aaci); | ||
894 | |||
895 | ret = aaci_probe_ac97(aaci); | ||
896 | if (ret) | ||
897 | goto out; | ||
898 | |||
899 | ret = aaci_init_pcm(aaci); | ||
900 | if (ret) | ||
901 | goto out; | ||
902 | |||
903 | ret = snd_card_register(aaci->card); | ||
904 | if (ret == 0) { | ||
905 | dev_info(&dev->dev, "%s, fifo %d\n", aaci->card->longname, | ||
906 | aaci->fifosize); | ||
907 | amba_set_drvdata(dev, aaci->card); | ||
908 | return ret; | ||
909 | } | ||
910 | |||
911 | out: | ||
912 | if (aaci) | ||
913 | snd_card_free(aaci->card); | ||
914 | amba_release_regions(dev); | ||
915 | return ret; | ||
916 | } | ||
917 | |||
918 | static int __devexit aaci_remove(struct amba_device *dev) | ||
919 | { | ||
920 | snd_card_t *card = amba_get_drvdata(dev); | ||
921 | |||
922 | amba_set_drvdata(dev, NULL); | ||
923 | |||
924 | if (card) { | ||
925 | struct aaci *aaci = card->private_data; | ||
926 | writel(0, aaci->base + AACI_MAINCR); | ||
927 | |||
928 | snd_card_free(card); | ||
929 | amba_release_regions(dev); | ||
930 | } | ||
931 | |||
932 | return 0; | ||
933 | } | ||
934 | |||
935 | static struct amba_id aaci_ids[] = { | ||
936 | { | ||
937 | .id = 0x00041041, | ||
938 | .mask = 0x000fffff, | ||
939 | }, | ||
940 | { 0, 0 }, | ||
941 | }; | ||
942 | |||
943 | static struct amba_driver aaci_driver = { | ||
944 | .drv = { | ||
945 | .name = DRIVER_NAME, | ||
946 | }, | ||
947 | .probe = aaci_probe, | ||
948 | .remove = __devexit_p(aaci_remove), | ||
949 | .suspend = aaci_suspend, | ||
950 | .resume = aaci_resume, | ||
951 | .id_table = aaci_ids, | ||
952 | }; | ||
953 | |||
954 | static int __init aaci_init(void) | ||
955 | { | ||
956 | return amba_driver_register(&aaci_driver); | ||
957 | } | ||
958 | |||
959 | static void __exit aaci_exit(void) | ||
960 | { | ||
961 | amba_driver_unregister(&aaci_driver); | ||
962 | } | ||
963 | |||
964 | module_init(aaci_init); | ||
965 | module_exit(aaci_exit); | ||
966 | |||
967 | MODULE_LICENSE("GPL"); | ||
968 | MODULE_DESCRIPTION("ARM PrimeCell PL041 Advanced Audio CODEC Interface driver"); | ||
diff --git a/sound/arm/aaci.h b/sound/arm/aaci.h new file mode 100644 index 000000000000..d752e6426894 --- /dev/null +++ b/sound/arm/aaci.h | |||
@@ -0,0 +1,246 @@ | |||
1 | /* | ||
2 | * linux/sound/arm/aaci.c - ARM PrimeCell AACI PL041 driver | ||
3 | * | ||
4 | * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | #ifndef AACI_H | ||
11 | #define AACI_H | ||
12 | |||
13 | /* | ||
14 | * Control and status register offsets | ||
15 | * P39. | ||
16 | */ | ||
17 | #define AACI_CSCH1 0x000 | ||
18 | #define AACI_CSCH2 0x014 | ||
19 | #define AACI_CSCH3 0x028 | ||
20 | #define AACI_CSCH4 0x03c | ||
21 | |||
22 | #define AACI_RXCR 0x000 /* 29 bits Control Rx FIFO */ | ||
23 | #define AACI_TXCR 0x004 /* 17 bits Control Tx FIFO */ | ||
24 | #define AACI_SR 0x008 /* 12 bits Status */ | ||
25 | #define AACI_ISR 0x00c /* 7 bits Int Status */ | ||
26 | #define AACI_IE 0x010 /* 7 bits Int Enable */ | ||
27 | |||
28 | /* | ||
29 | * Other registers | ||
30 | */ | ||
31 | #define AACI_SL1RX 0x050 | ||
32 | #define AACI_SL1TX 0x054 | ||
33 | #define AACI_SL2RX 0x058 | ||
34 | #define AACI_SL2TX 0x05c | ||
35 | #define AACI_SL12RX 0x060 | ||
36 | #define AACI_SL12TX 0x064 | ||
37 | #define AACI_SLFR 0x068 /* slot flags */ | ||
38 | #define AACI_SLISTAT 0x06c /* slot interrupt status */ | ||
39 | #define AACI_SLIEN 0x070 /* slot interrupt enable */ | ||
40 | #define AACI_INTCLR 0x074 /* interrupt clear */ | ||
41 | #define AACI_MAINCR 0x078 /* main control */ | ||
42 | #define AACI_RESET 0x07c /* reset control */ | ||
43 | #define AACI_SYNC 0x080 /* sync control */ | ||
44 | #define AACI_ALLINTS 0x084 /* all fifo interrupt status */ | ||
45 | #define AACI_MAINFR 0x088 /* main flag register */ | ||
46 | #define AACI_DR1 0x090 /* data read/written fifo 1 */ | ||
47 | #define AACI_DR2 0x0b0 /* data read/written fifo 2 */ | ||
48 | #define AACI_DR3 0x0d0 /* data read/written fifo 3 */ | ||
49 | #define AACI_DR4 0x0f0 /* data read/written fifo 4 */ | ||
50 | |||
51 | /* | ||
52 | * transmit fifo control register. P48 | ||
53 | */ | ||
54 | #define TXCR_FEN (1 << 16) /* fifo enable */ | ||
55 | #define TXCR_COMPACT (1 << 15) /* compact mode */ | ||
56 | #define TXCR_TSZ16 (0 << 13) /* 16 bits */ | ||
57 | #define TXCR_TSZ18 (1 << 13) /* 18 bits */ | ||
58 | #define TXCR_TSZ20 (2 << 13) /* 20 bits */ | ||
59 | #define TXCR_TSZ12 (3 << 13) /* 12 bits */ | ||
60 | #define TXCR_TX12 (1 << 12) /* transmits slot 12 */ | ||
61 | #define TXCR_TX11 (1 << 11) /* transmits slot 12 */ | ||
62 | #define TXCR_TX10 (1 << 10) /* transmits slot 12 */ | ||
63 | #define TXCR_TX9 (1 << 9) /* transmits slot 12 */ | ||
64 | #define TXCR_TX8 (1 << 8) /* transmits slot 12 */ | ||
65 | #define TXCR_TX7 (1 << 7) /* transmits slot 12 */ | ||
66 | #define TXCR_TX6 (1 << 6) /* transmits slot 12 */ | ||
67 | #define TXCR_TX5 (1 << 5) /* transmits slot 12 */ | ||
68 | #define TXCR_TX4 (1 << 4) /* transmits slot 12 */ | ||
69 | #define TXCR_TX3 (1 << 3) /* transmits slot 12 */ | ||
70 | #define TXCR_TX2 (1 << 2) /* transmits slot 12 */ | ||
71 | #define TXCR_TX1 (1 << 1) /* transmits slot 12 */ | ||
72 | #define TXCR_TXEN (1 << 0) /* transmit enable */ | ||
73 | |||
74 | /* | ||
75 | * status register bits. P49 | ||
76 | */ | ||
77 | #define SR_RXTOFE (1 << 11) /* rx timeout fifo empty */ | ||
78 | #define SR_TXTO (1 << 10) /* rx timeout fifo nonempty */ | ||
79 | #define SR_TXU (1 << 9) /* tx underrun */ | ||
80 | #define SR_RXO (1 << 8) /* rx overrun */ | ||
81 | #define SR_TXB (1 << 7) /* tx busy */ | ||
82 | #define SR_RXB (1 << 6) /* rx busy */ | ||
83 | #define SR_TXFF (1 << 5) /* tx fifo full */ | ||
84 | #define SR_RXFF (1 << 4) /* rx fifo full */ | ||
85 | #define SR_TXHE (1 << 3) /* tx fifo half empty */ | ||
86 | #define SR_RXHF (1 << 2) /* rx fifo half full */ | ||
87 | #define SR_TXFE (1 << 1) /* tx fifo empty */ | ||
88 | #define SR_RXFE (1 << 0) /* rx fifo empty */ | ||
89 | |||
90 | /* | ||
91 | * interrupt status register bits. | ||
92 | */ | ||
93 | #define ISR_RXTOFEINTR (1 << 6) /* rx fifo empty */ | ||
94 | #define ISR_URINTR (1 << 5) /* tx underflow */ | ||
95 | #define ISR_ORINTR (1 << 4) /* rx overflow */ | ||
96 | #define ISR_RXINTR (1 << 3) /* rx fifo */ | ||
97 | #define ISR_TXINTR (1 << 2) /* tx fifo intr */ | ||
98 | #define ISR_RXTOINTR (1 << 1) /* tx timeout */ | ||
99 | #define ISR_TXCINTR (1 << 0) /* tx complete */ | ||
100 | |||
101 | /* | ||
102 | * interrupt enable register bits. | ||
103 | */ | ||
104 | #define IE_RXTOIE (1 << 6) | ||
105 | #define IE_URIE (1 << 5) | ||
106 | #define IE_ORIE (1 << 4) | ||
107 | #define IE_RXIE (1 << 3) | ||
108 | #define IE_TXIE (1 << 2) | ||
109 | #define IE_RXTIE (1 << 1) | ||
110 | #define IE_TXCIE (1 << 0) | ||
111 | |||
112 | /* | ||
113 | * interrupt status. P51 | ||
114 | */ | ||
115 | #define ISR_RXTOFE (1 << 6) /* rx timeout fifo empty */ | ||
116 | #define ISR_UR (1 << 5) /* tx fifo underrun */ | ||
117 | #define ISR_OR (1 << 4) /* rx fifo overrun */ | ||
118 | #define ISR_RX (1 << 3) /* rx interrupt status */ | ||
119 | #define ISR_TX (1 << 2) /* tx interrupt status */ | ||
120 | #define ISR_RXTO (1 << 1) /* rx timeout */ | ||
121 | #define ISR_TXC (1 << 0) /* tx complete */ | ||
122 | |||
123 | /* | ||
124 | * interrupt enable. P52 | ||
125 | */ | ||
126 | #define IE_RXTOFE (1 << 6) /* rx timeout fifo empty */ | ||
127 | #define IE_UR (1 << 5) /* tx fifo underrun */ | ||
128 | #define IE_OR (1 << 4) /* rx fifo overrun */ | ||
129 | #define IE_RX (1 << 3) /* rx interrupt status */ | ||
130 | #define IE_TX (1 << 2) /* tx interrupt status */ | ||
131 | #define IE_RXTO (1 << 1) /* rx timeout */ | ||
132 | #define IE_TXC (1 << 0) /* tx complete */ | ||
133 | |||
134 | /* | ||
135 | * slot flag register bits. P56 | ||
136 | */ | ||
137 | #define SLFR_RWIS (1 << 13) /* raw wake-up interrupt status */ | ||
138 | #define SLFR_RGPIOINTR (1 << 12) /* raw gpio interrupt */ | ||
139 | #define SLFR_12TXE (1 << 11) /* slot 12 tx empty */ | ||
140 | #define SLFR_12RXV (1 << 10) /* slot 12 rx valid */ | ||
141 | #define SLFR_2TXE (1 << 9) /* slot 2 tx empty */ | ||
142 | #define SLFR_2RXV (1 << 8) /* slot 2 rx valid */ | ||
143 | #define SLFR_1TXE (1 << 7) /* slot 1 tx empty */ | ||
144 | #define SLFR_1RXV (1 << 6) /* slot 1 rx valid */ | ||
145 | #define SLFR_12TXB (1 << 5) /* slot 12 tx busy */ | ||
146 | #define SLFR_12RXB (1 << 4) /* slot 12 rx busy */ | ||
147 | #define SLFR_2TXB (1 << 3) /* slot 2 tx busy */ | ||
148 | #define SLFR_2RXB (1 << 2) /* slot 2 rx busy */ | ||
149 | #define SLFR_1TXB (1 << 1) /* slot 1 tx busy */ | ||
150 | #define SLFR_1RXB (1 << 0) /* slot 1 rx busy */ | ||
151 | |||
152 | /* | ||
153 | * Interrupt clear register. | ||
154 | */ | ||
155 | #define ICLR_RXTOFEC4 (1 << 12) | ||
156 | #define ICLR_RXTOFEC3 (1 << 11) | ||
157 | #define ICLR_RXTOFEC2 (1 << 10) | ||
158 | #define ICLR_RXTOFEC1 (1 << 9) | ||
159 | #define ICLR_TXUEC4 (1 << 8) | ||
160 | #define ICLR_TXUEC3 (1 << 7) | ||
161 | #define ICLR_TXUEC2 (1 << 6) | ||
162 | #define ICLR_TXUEC1 (1 << 5) | ||
163 | #define ICLR_RXOEC4 (1 << 4) | ||
164 | #define ICLR_RXOEC3 (1 << 3) | ||
165 | #define ICLR_RXOEC2 (1 << 2) | ||
166 | #define ICLR_RXOEC1 (1 << 1) | ||
167 | #define ICLR_WISC (1 << 0) | ||
168 | |||
169 | /* | ||
170 | * Main control register bits. P62 | ||
171 | */ | ||
172 | #define MAINCR_SCRA(x) ((x) << 10) /* secondary codec reg access */ | ||
173 | #define MAINCR_DMAEN (1 << 9) /* dma enable */ | ||
174 | #define MAINCR_SL12TXEN (1 << 8) /* slot 12 transmit enable */ | ||
175 | #define MAINCR_SL12RXEN (1 << 7) /* slot 12 receive enable */ | ||
176 | #define MAINCR_SL2TXEN (1 << 6) /* slot 2 transmit enable */ | ||
177 | #define MAINCR_SL2RXEN (1 << 5) /* slot 2 receive enable */ | ||
178 | #define MAINCR_SL1TXEN (1 << 4) /* slot 1 transmit enable */ | ||
179 | #define MAINCR_SL1RXEN (1 << 3) /* slot 1 receive enable */ | ||
180 | #define MAINCR_LPM (1 << 2) /* low power mode */ | ||
181 | #define MAINCR_LOOPBK (1 << 1) /* loopback */ | ||
182 | #define MAINCR_IE (1 << 0) /* aaci interface enable */ | ||
183 | |||
184 | /* | ||
185 | * Reset register bits. P65 | ||
186 | */ | ||
187 | #define RESET_NRST (1 << 0) | ||
188 | |||
189 | /* | ||
190 | * Sync register bits. P65 | ||
191 | */ | ||
192 | #define SYNC_FORCE (1 << 0) | ||
193 | |||
194 | /* | ||
195 | * Main flag register bits. P66 | ||
196 | */ | ||
197 | #define MAINFR_TXB (1 << 1) /* transmit busy */ | ||
198 | #define MAINFR_RXB (1 << 0) /* receive busy */ | ||
199 | |||
200 | |||
201 | |||
202 | struct aaci_runtime { | ||
203 | void *base; | ||
204 | void *fifo; | ||
205 | |||
206 | struct ac97_pcm *pcm; | ||
207 | int pcm_open; | ||
208 | |||
209 | u32 cr; | ||
210 | snd_pcm_substream_t *substream; | ||
211 | |||
212 | /* | ||
213 | * PIO support | ||
214 | */ | ||
215 | void *start; | ||
216 | void *end; | ||
217 | void *ptr; | ||
218 | int bytes; | ||
219 | unsigned int period; | ||
220 | unsigned int fifosz; | ||
221 | }; | ||
222 | |||
223 | struct aaci { | ||
224 | struct amba_device *dev; | ||
225 | snd_card_t *card; | ||
226 | void *base; | ||
227 | unsigned int fifosize; | ||
228 | |||
229 | /* AC'97 */ | ||
230 | struct semaphore ac97_sem; | ||
231 | ac97_bus_t *ac97_bus; | ||
232 | |||
233 | u32 maincr; | ||
234 | spinlock_t lock; | ||
235 | |||
236 | struct aaci_runtime playback; | ||
237 | struct aaci_runtime capture; | ||
238 | |||
239 | snd_pcm_t *pcm; | ||
240 | }; | ||
241 | |||
242 | #define ACSTREAM_FRONT 0 | ||
243 | #define ACSTREAM_SURROUND 1 | ||
244 | #define ACSTREAM_LFE 2 | ||
245 | |||
246 | #endif | ||
diff --git a/sound/arm/devdma.c b/sound/arm/devdma.c new file mode 100644 index 000000000000..60826a5324b4 --- /dev/null +++ b/sound/arm/devdma.c | |||
@@ -0,0 +1,81 @@ | |||
1 | /* | ||
2 | * linux/sound/arm/devdma.c | ||
3 | * | ||
4 | * Copyright (C) 2003-2004 Russell King, All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * ARM DMA shim for ALSA. | ||
11 | */ | ||
12 | #include <linux/device.h> | ||
13 | #include <linux/dma-mapping.h> | ||
14 | |||
15 | #include <sound/driver.h> | ||
16 | #include <sound/core.h> | ||
17 | #include <sound/pcm.h> | ||
18 | |||
19 | #include "devdma.h" | ||
20 | |||
21 | void devdma_hw_free(struct device *dev, snd_pcm_substream_t *substream) | ||
22 | { | ||
23 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
24 | struct snd_dma_buffer *buf = runtime->dma_buffer_p; | ||
25 | |||
26 | if (runtime->dma_area == NULL) | ||
27 | return; | ||
28 | |||
29 | if (buf != &substream->dma_buffer) { | ||
30 | dma_free_coherent(buf->dev.dev, buf->bytes, buf->area, buf->addr); | ||
31 | kfree(runtime->dma_buffer_p); | ||
32 | } | ||
33 | |||
34 | snd_pcm_set_runtime_buffer(substream, NULL); | ||
35 | } | ||
36 | |||
37 | int devdma_hw_alloc(struct device *dev, snd_pcm_substream_t *substream, size_t size) | ||
38 | { | ||
39 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
40 | struct snd_dma_buffer *buf = runtime->dma_buffer_p; | ||
41 | int ret = 0; | ||
42 | |||
43 | if (buf) { | ||
44 | if (buf->bytes >= size) | ||
45 | goto out; | ||
46 | devdma_hw_free(dev, substream); | ||
47 | } | ||
48 | |||
49 | if (substream->dma_buffer.area != NULL && substream->dma_buffer.bytes >= size) { | ||
50 | buf = &substream->dma_buffer; | ||
51 | } else { | ||
52 | buf = kmalloc(sizeof(struct snd_dma_buffer), GFP_KERNEL); | ||
53 | if (!buf) | ||
54 | goto nomem; | ||
55 | |||
56 | buf->dev.type = SNDRV_DMA_TYPE_DEV; | ||
57 | buf->dev.dev = dev; | ||
58 | buf->area = dma_alloc_coherent(dev, size, &buf->addr, GFP_KERNEL); | ||
59 | buf->bytes = size; | ||
60 | buf->private_data = NULL; | ||
61 | |||
62 | if (!buf->area) | ||
63 | goto free; | ||
64 | } | ||
65 | snd_pcm_set_runtime_buffer(substream, buf); | ||
66 | ret = 1; | ||
67 | out: | ||
68 | runtime->dma_bytes = size; | ||
69 | return ret; | ||
70 | |||
71 | free: | ||
72 | kfree(buf); | ||
73 | nomem: | ||
74 | return -ENOMEM; | ||
75 | } | ||
76 | |||
77 | int devdma_mmap(struct device *dev, snd_pcm_substream_t *substream, struct vm_area_struct *vma) | ||
78 | { | ||
79 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
80 | return dma_mmap_coherent(dev, vma, runtime->dma_area, runtime->dma_addr, runtime->dma_bytes); | ||
81 | } | ||
diff --git a/sound/arm/devdma.h b/sound/arm/devdma.h new file mode 100644 index 000000000000..5a33b6bacc34 --- /dev/null +++ b/sound/arm/devdma.h | |||
@@ -0,0 +1,3 @@ | |||
1 | void devdma_hw_free(struct device *dev, snd_pcm_substream_t *substream); | ||
2 | int devdma_hw_alloc(struct device *dev, snd_pcm_substream_t *substream, size_t size); | ||
3 | int devdma_mmap(struct device *dev, snd_pcm_substream_t *substream, struct vm_area_struct *vma); | ||
diff --git a/sound/core/control.c b/sound/core/control.c index f4ea6bff1dd3..227f3cf02771 100644 --- a/sound/core/control.c +++ b/sound/core/control.c | |||
@@ -215,7 +215,7 @@ snd_kcontrol_t *snd_ctl_new(snd_kcontrol_t * control, unsigned int access) | |||
215 | * | 215 | * |
216 | * Returns the pointer of the newly generated instance, or NULL on failure. | 216 | * Returns the pointer of the newly generated instance, or NULL on failure. |
217 | */ | 217 | */ |
218 | snd_kcontrol_t *snd_ctl_new1(snd_kcontrol_new_t * ncontrol, void *private_data) | 218 | snd_kcontrol_t *snd_ctl_new1(const snd_kcontrol_new_t * ncontrol, void *private_data) |
219 | { | 219 | { |
220 | snd_kcontrol_t kctl; | 220 | snd_kcontrol_t kctl; |
221 | unsigned int access; | 221 | unsigned int access; |
@@ -1102,7 +1102,7 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg | |||
1102 | } | 1102 | } |
1103 | } | 1103 | } |
1104 | up_read(&snd_ioctl_rwsem); | 1104 | up_read(&snd_ioctl_rwsem); |
1105 | snd_printd("unknown ioctl = 0x%x\n", cmd); | 1105 | snd_printdd("unknown ioctl = 0x%x\n", cmd); |
1106 | return -ENOTTY; | 1106 | return -ENOTTY; |
1107 | } | 1107 | } |
1108 | 1108 | ||
diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index 344a83fd7c2e..dbc23e35fa06 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/pci.h> | 28 | #include <linux/pci.h> |
29 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
30 | #include <linux/mm.h> | 30 | #include <linux/mm.h> |
31 | #include <asm/uaccess.h> | ||
31 | #include <linux/dma-mapping.h> | 32 | #include <linux/dma-mapping.h> |
32 | #include <linux/moduleparam.h> | 33 | #include <linux/moduleparam.h> |
33 | #include <asm/semaphore.h> | 34 | #include <asm/semaphore.h> |
@@ -46,13 +47,6 @@ MODULE_LICENSE("GPL"); | |||
46 | #define SNDRV_CARDS 8 | 47 | #define SNDRV_CARDS 8 |
47 | #endif | 48 | #endif |
48 | 49 | ||
49 | /* FIXME: so far only some PCI devices have the preallocation table */ | ||
50 | #ifdef CONFIG_PCI | ||
51 | static int enable[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1}; | ||
52 | module_param_array(enable, bool, NULL, 0444); | ||
53 | MODULE_PARM_DESC(enable, "Enable cards to allocate buffers."); | ||
54 | #endif | ||
55 | |||
56 | /* | 50 | /* |
57 | */ | 51 | */ |
58 | 52 | ||
@@ -451,9 +445,13 @@ size_t snd_dma_get_reserved_buf(struct snd_dma_buffer *dmab, unsigned int id) | |||
451 | list_for_each(p, &mem_list_head) { | 445 | list_for_each(p, &mem_list_head) { |
452 | mem = list_entry(p, struct snd_mem_list, list); | 446 | mem = list_entry(p, struct snd_mem_list, list); |
453 | if (mem->id == id && | 447 | if (mem->id == id && |
454 | ! memcmp(&mem->buffer.dev, &dmab->dev, sizeof(dmab->dev))) { | 448 | (mem->buffer.dev.dev == NULL || dmab->dev.dev == NULL || |
449 | ! memcmp(&mem->buffer.dev, &dmab->dev, sizeof(dmab->dev)))) { | ||
450 | struct device *dev = dmab->dev.dev; | ||
455 | list_del(p); | 451 | list_del(p); |
456 | *dmab = mem->buffer; | 452 | *dmab = mem->buffer; |
453 | if (dmab->dev.dev == NULL) | ||
454 | dmab->dev.dev = dev; | ||
457 | kfree(mem); | 455 | kfree(mem); |
458 | up(&list_mutex); | 456 | up(&list_mutex); |
459 | return dmab->bytes; | 457 | return dmab->bytes; |
@@ -508,91 +506,13 @@ static void free_all_reserved_pages(void) | |||
508 | } | 506 | } |
509 | 507 | ||
510 | 508 | ||
511 | |||
512 | /* | ||
513 | * allocation of buffers for pre-defined devices | ||
514 | */ | ||
515 | |||
516 | #ifdef CONFIG_PCI | ||
517 | /* FIXME: for pci only - other bus? */ | ||
518 | struct prealloc_dev { | ||
519 | unsigned short vendor; | ||
520 | unsigned short device; | ||
521 | unsigned long dma_mask; | ||
522 | unsigned int size; | ||
523 | unsigned int buffers; | ||
524 | }; | ||
525 | |||
526 | #define HAMMERFALL_BUFFER_SIZE (16*1024*4*(26+1)+0x10000) | ||
527 | |||
528 | static struct prealloc_dev prealloc_devices[] __initdata = { | ||
529 | { | ||
530 | /* hammerfall */ | ||
531 | .vendor = 0x10ee, | ||
532 | .device = 0x3fc4, | ||
533 | .dma_mask = 0xffffffff, | ||
534 | .size = HAMMERFALL_BUFFER_SIZE, | ||
535 | .buffers = 2 | ||
536 | }, | ||
537 | { | ||
538 | /* HDSP */ | ||
539 | .vendor = 0x10ee, | ||
540 | .device = 0x3fc5, | ||
541 | .dma_mask = 0xffffffff, | ||
542 | .size = HAMMERFALL_BUFFER_SIZE, | ||
543 | .buffers = 2 | ||
544 | }, | ||
545 | { }, /* terminator */ | ||
546 | }; | ||
547 | |||
548 | static void __init preallocate_cards(void) | ||
549 | { | ||
550 | struct pci_dev *pci = NULL; | ||
551 | int card; | ||
552 | |||
553 | card = 0; | ||
554 | |||
555 | while ((pci = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci)) != NULL) { | ||
556 | struct prealloc_dev *dev; | ||
557 | unsigned int i; | ||
558 | if (card >= SNDRV_CARDS) | ||
559 | break; | ||
560 | for (dev = prealloc_devices; dev->vendor; dev++) { | ||
561 | if (dev->vendor == pci->vendor && dev->device == pci->device) | ||
562 | break; | ||
563 | } | ||
564 | if (! dev->vendor) | ||
565 | continue; | ||
566 | if (! enable[card++]) { | ||
567 | printk(KERN_DEBUG "snd-page-alloc: skipping card %d, device %04x:%04x\n", card, pci->vendor, pci->device); | ||
568 | continue; | ||
569 | } | ||
570 | |||
571 | if (pci_set_dma_mask(pci, dev->dma_mask) < 0 || | ||
572 | pci_set_consistent_dma_mask(pci, dev->dma_mask) < 0) { | ||
573 | printk(KERN_ERR "snd-page-alloc: cannot set DMA mask %lx for pci %04x:%04x\n", dev->dma_mask, dev->vendor, dev->device); | ||
574 | continue; | ||
575 | } | ||
576 | for (i = 0; i < dev->buffers; i++) { | ||
577 | struct snd_dma_buffer dmab; | ||
578 | memset(&dmab, 0, sizeof(dmab)); | ||
579 | if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), | ||
580 | dev->size, &dmab) < 0) | ||
581 | printk(KERN_WARNING "snd-page-alloc: cannot allocate buffer pages (size = %d)\n", dev->size); | ||
582 | else | ||
583 | snd_dma_reserve_buf(&dmab, snd_dma_pci_buf_id(pci)); | ||
584 | } | ||
585 | } | ||
586 | } | ||
587 | #else | ||
588 | #define preallocate_cards() /* NOP */ | ||
589 | #endif | ||
590 | |||
591 | |||
592 | #ifdef CONFIG_PROC_FS | 509 | #ifdef CONFIG_PROC_FS |
593 | /* | 510 | /* |
594 | * proc file interface | 511 | * proc file interface |
595 | */ | 512 | */ |
513 | #define SND_MEM_PROC_FILE "driver/snd-page-alloc" | ||
514 | struct proc_dir_entry *snd_mem_proc; | ||
515 | |||
596 | static int snd_mem_proc_read(char *page, char **start, off_t off, | 516 | static int snd_mem_proc_read(char *page, char **start, off_t off, |
597 | int count, int *eof, void *data) | 517 | int count, int *eof, void *data) |
598 | { | 518 | { |
@@ -621,6 +541,97 @@ static int snd_mem_proc_read(char *page, char **start, off_t off, | |||
621 | up(&list_mutex); | 541 | up(&list_mutex); |
622 | return len; | 542 | return len; |
623 | } | 543 | } |
544 | |||
545 | /* FIXME: for pci only - other bus? */ | ||
546 | #ifdef CONFIG_PCI | ||
547 | #define gettoken(bufp) strsep(bufp, " \t\n") | ||
548 | |||
549 | static int snd_mem_proc_write(struct file *file, const char __user *buffer, | ||
550 | unsigned long count, void *data) | ||
551 | { | ||
552 | char buf[128]; | ||
553 | char *token, *p; | ||
554 | |||
555 | if (count > ARRAY_SIZE(buf) - 1) | ||
556 | count = ARRAY_SIZE(buf) - 1; | ||
557 | if (copy_from_user(buf, buffer, count)) | ||
558 | return -EFAULT; | ||
559 | buf[ARRAY_SIZE(buf) - 1] = '\0'; | ||
560 | |||
561 | p = buf; | ||
562 | token = gettoken(&p); | ||
563 | if (! token || *token == '#') | ||
564 | return (int)count; | ||
565 | if (strcmp(token, "add") == 0) { | ||
566 | char *endp; | ||
567 | int vendor, device, size, buffers; | ||
568 | long mask; | ||
569 | int i, alloced; | ||
570 | struct pci_dev *pci; | ||
571 | |||
572 | if ((token = gettoken(&p)) == NULL || | ||
573 | (vendor = simple_strtol(token, NULL, 0)) <= 0 || | ||
574 | (token = gettoken(&p)) == NULL || | ||
575 | (device = simple_strtol(token, NULL, 0)) <= 0 || | ||
576 | (token = gettoken(&p)) == NULL || | ||
577 | (mask = simple_strtol(token, NULL, 0)) < 0 || | ||
578 | (token = gettoken(&p)) == NULL || | ||
579 | (size = memparse(token, &endp)) < 64*1024 || | ||
580 | size > 16*1024*1024 /* too big */ || | ||
581 | (token = gettoken(&p)) == NULL || | ||
582 | (buffers = simple_strtol(token, NULL, 0)) <= 0 || | ||
583 | buffers > 4) { | ||
584 | printk(KERN_ERR "snd-page-alloc: invalid proc write format\n"); | ||
585 | return (int)count; | ||
586 | } | ||
587 | vendor &= 0xffff; | ||
588 | device &= 0xffff; | ||
589 | |||
590 | alloced = 0; | ||
591 | pci = NULL; | ||
592 | while ((pci = pci_find_device(vendor, device, pci)) != NULL) { | ||
593 | if (mask > 0 && mask < 0xffffffff) { | ||
594 | if (pci_set_dma_mask(pci, mask) < 0 || | ||
595 | pci_set_consistent_dma_mask(pci, mask) < 0) { | ||
596 | printk(KERN_ERR "snd-page-alloc: cannot set DMA mask %lx for pci %04x:%04x\n", mask, vendor, device); | ||
597 | return (int)count; | ||
598 | } | ||
599 | } | ||
600 | for (i = 0; i < buffers; i++) { | ||
601 | struct snd_dma_buffer dmab; | ||
602 | memset(&dmab, 0, sizeof(dmab)); | ||
603 | if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), | ||
604 | size, &dmab) < 0) { | ||
605 | printk(KERN_ERR "snd-page-alloc: cannot allocate buffer pages (size = %d)\n", size); | ||
606 | return (int)count; | ||
607 | } | ||
608 | snd_dma_reserve_buf(&dmab, snd_dma_pci_buf_id(pci)); | ||
609 | } | ||
610 | alloced++; | ||
611 | } | ||
612 | if (! alloced) { | ||
613 | for (i = 0; i < buffers; i++) { | ||
614 | struct snd_dma_buffer dmab; | ||
615 | memset(&dmab, 0, sizeof(dmab)); | ||
616 | /* FIXME: We can allocate only in ZONE_DMA | ||
617 | * without a device pointer! | ||
618 | */ | ||
619 | if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, NULL, | ||
620 | size, &dmab) < 0) { | ||
621 | printk(KERN_ERR "snd-page-alloc: cannot allocate buffer pages (size = %d)\n", size); | ||
622 | break; | ||
623 | } | ||
624 | snd_dma_reserve_buf(&dmab, (unsigned int)((vendor << 16) | device)); | ||
625 | } | ||
626 | } | ||
627 | } else if (strcmp(token, "erase") == 0) | ||
628 | /* FIXME: need for releasing each buffer chunk? */ | ||
629 | free_all_reserved_pages(); | ||
630 | else | ||
631 | printk(KERN_ERR "snd-page-alloc: invalid proc cmd\n"); | ||
632 | return (int)count; | ||
633 | } | ||
634 | #endif /* CONFIG_PCI */ | ||
624 | #endif /* CONFIG_PROC_FS */ | 635 | #endif /* CONFIG_PROC_FS */ |
625 | 636 | ||
626 | /* | 637 | /* |
@@ -630,15 +641,21 @@ static int snd_mem_proc_read(char *page, char **start, off_t off, | |||
630 | static int __init snd_mem_init(void) | 641 | static int __init snd_mem_init(void) |
631 | { | 642 | { |
632 | #ifdef CONFIG_PROC_FS | 643 | #ifdef CONFIG_PROC_FS |
633 | create_proc_read_entry("driver/snd-page-alloc", 0, NULL, snd_mem_proc_read, NULL); | 644 | snd_mem_proc = create_proc_entry(SND_MEM_PROC_FILE, 0644, NULL); |
645 | if (snd_mem_proc) { | ||
646 | snd_mem_proc->read_proc = snd_mem_proc_read; | ||
647 | #ifdef CONFIG_PCI | ||
648 | snd_mem_proc->write_proc = snd_mem_proc_write; | ||
649 | #endif | ||
650 | } | ||
634 | #endif | 651 | #endif |
635 | preallocate_cards(); | ||
636 | return 0; | 652 | return 0; |
637 | } | 653 | } |
638 | 654 | ||
639 | static void __exit snd_mem_exit(void) | 655 | static void __exit snd_mem_exit(void) |
640 | { | 656 | { |
641 | remove_proc_entry("driver/snd-page-alloc", NULL); | 657 | if (snd_mem_proc) |
658 | remove_proc_entry(SND_MEM_PROC_FILE, NULL); | ||
642 | free_all_reserved_pages(); | 659 | free_all_reserved_pages(); |
643 | if (snd_allocated_pages > 0) | 660 | if (snd_allocated_pages > 0) |
644 | printk(KERN_ERR "snd-malloc: Memory leak? pages not freed = %li\n", snd_allocated_pages); | 661 | printk(KERN_ERR "snd-malloc: Memory leak? pages not freed = %li\n", snd_allocated_pages); |
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 1a805020f57a..cab30977e7c0 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c | |||
@@ -125,17 +125,26 @@ int snd_pcm_plugin_append(snd_pcm_plugin_t *plugin) | |||
125 | static long snd_pcm_oss_bytes(snd_pcm_substream_t *substream, long frames) | 125 | static long snd_pcm_oss_bytes(snd_pcm_substream_t *substream, long frames) |
126 | { | 126 | { |
127 | snd_pcm_runtime_t *runtime = substream->runtime; | 127 | snd_pcm_runtime_t *runtime = substream->runtime; |
128 | snd_pcm_uframes_t buffer_size = snd_pcm_lib_buffer_bytes(substream); | 128 | long buffer_size = snd_pcm_lib_buffer_bytes(substream); |
129 | frames = frames_to_bytes(runtime, frames); | 129 | long bytes = frames_to_bytes(runtime, frames); |
130 | if (buffer_size == runtime->oss.buffer_bytes) | 130 | if (buffer_size == runtime->oss.buffer_bytes) |
131 | return frames; | 131 | return bytes; |
132 | return (runtime->oss.buffer_bytes * frames) / buffer_size; | 132 | #if BITS_PER_LONG >= 64 |
133 | return runtime->oss.buffer_bytes * bytes / buffer_size; | ||
134 | #else | ||
135 | { | ||
136 | u64 bsize = (u64)runtime->oss.buffer_bytes * (u64)bytes; | ||
137 | u32 rem; | ||
138 | div64_32(&bsize, buffer_size, &rem); | ||
139 | return (long)bsize; | ||
140 | } | ||
141 | #endif | ||
133 | } | 142 | } |
134 | 143 | ||
135 | static long snd_pcm_alsa_frames(snd_pcm_substream_t *substream, long bytes) | 144 | static long snd_pcm_alsa_frames(snd_pcm_substream_t *substream, long bytes) |
136 | { | 145 | { |
137 | snd_pcm_runtime_t *runtime = substream->runtime; | 146 | snd_pcm_runtime_t *runtime = substream->runtime; |
138 | snd_pcm_uframes_t buffer_size = snd_pcm_lib_buffer_bytes(substream); | 147 | long buffer_size = snd_pcm_lib_buffer_bytes(substream); |
139 | if (buffer_size == runtime->oss.buffer_bytes) | 148 | if (buffer_size == runtime->oss.buffer_bytes) |
140 | return bytes_to_frames(runtime, bytes); | 149 | return bytes_to_frames(runtime, bytes); |
141 | return bytes_to_frames(runtime, (buffer_size * bytes) / runtime->oss.buffer_bytes); | 150 | return bytes_to_frames(runtime, (buffer_size * bytes) / runtime->oss.buffer_bytes); |
@@ -464,7 +473,8 @@ static int snd_pcm_oss_change_params(snd_pcm_substream_t *substream) | |||
464 | sw_params->tstamp_mode = SNDRV_PCM_TSTAMP_NONE; | 473 | sw_params->tstamp_mode = SNDRV_PCM_TSTAMP_NONE; |
465 | sw_params->period_step = 1; | 474 | sw_params->period_step = 1; |
466 | sw_params->sleep_min = 0; | 475 | sw_params->sleep_min = 0; |
467 | sw_params->avail_min = 1; | 476 | sw_params->avail_min = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? |
477 | 1 : runtime->period_size; | ||
468 | sw_params->xfer_align = 1; | 478 | sw_params->xfer_align = 1; |
469 | if (atomic_read(&runtime->mmap_count) || | 479 | if (atomic_read(&runtime->mmap_count) || |
470 | (substream->oss.setup && substream->oss.setup->nosilence)) { | 480 | (substream->oss.setup && substream->oss.setup->nosilence)) { |
@@ -1527,12 +1537,15 @@ static int snd_pcm_oss_get_ptr(snd_pcm_oss_file_t *pcm_oss_file, int stream, str | |||
1527 | snd_pcm_oss_simulate_fill(substream, delay); | 1537 | snd_pcm_oss_simulate_fill(substream, delay); |
1528 | info.bytes = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr) & INT_MAX; | 1538 | info.bytes = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr) & INT_MAX; |
1529 | } else { | 1539 | } else { |
1530 | delay = snd_pcm_oss_bytes(substream, delay) + fixup; | 1540 | delay = snd_pcm_oss_bytes(substream, delay); |
1531 | info.blocks = delay / runtime->oss.period_bytes; | 1541 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { |
1532 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) | 1542 | info.blocks = (runtime->oss.buffer_bytes - delay - fixup) / runtime->oss.period_bytes; |
1533 | info.bytes = (runtime->oss.bytes - delay) & INT_MAX; | 1543 | info.bytes = (runtime->oss.bytes - delay) & INT_MAX; |
1534 | else | 1544 | } else { |
1545 | delay += fixup; | ||
1546 | info.blocks = delay / runtime->oss.period_bytes; | ||
1535 | info.bytes = (runtime->oss.bytes + delay) & INT_MAX; | 1547 | info.bytes = (runtime->oss.bytes + delay) & INT_MAX; |
1548 | } | ||
1536 | } | 1549 | } |
1537 | if (copy_to_user(_info, &info, sizeof(info))) | 1550 | if (copy_to_user(_info, &info, sizeof(info))) |
1538 | return -EFAULT; | 1551 | return -EFAULT; |
diff --git a/sound/core/oss/pcm_plugin.c b/sound/core/oss/pcm_plugin.c index 6bb31009f0b4..6430410c6c04 100644 --- a/sound/core/oss/pcm_plugin.c +++ b/sound/core/oss/pcm_plugin.c | |||
@@ -663,10 +663,7 @@ static int snd_pcm_plug_playback_channels_mask(snd_pcm_plug_t *plug, | |||
663 | bitset_t *dstmask = bs; | 663 | bitset_t *dstmask = bs; |
664 | int err; | 664 | int err; |
665 | bitset_one(dstmask, schannels); | 665 | bitset_one(dstmask, schannels); |
666 | if (plugin == NULL) { | 666 | |
667 | bitset_and(client_vmask, dstmask, schannels); | ||
668 | return 0; | ||
669 | } | ||
670 | while (1) { | 667 | while (1) { |
671 | err = plugin->src_channels_mask(plugin, dstmask, &srcmask); | 668 | err = plugin->src_channels_mask(plugin, dstmask, &srcmask); |
672 | if (err < 0) | 669 | if (err < 0) |
diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 8d94325529a8..9f4c9209b271 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c | |||
@@ -451,6 +451,7 @@ static int snd_pcm_stream_proc_init(snd_pcm_str_t *pstr) | |||
451 | entry->c.text.read = snd_pcm_xrun_debug_read; | 451 | entry->c.text.read = snd_pcm_xrun_debug_read; |
452 | entry->c.text.write_size = 64; | 452 | entry->c.text.write_size = 64; |
453 | entry->c.text.write = snd_pcm_xrun_debug_write; | 453 | entry->c.text.write = snd_pcm_xrun_debug_write; |
454 | entry->mode |= S_IWUSR; | ||
454 | entry->private_data = pstr; | 455 | entry->private_data = pstr; |
455 | if (snd_info_register(entry) < 0) { | 456 | if (snd_info_register(entry) < 0) { |
456 | snd_info_free_entry(entry); | 457 | snd_info_free_entry(entry); |
@@ -1048,7 +1049,6 @@ EXPORT_SYMBOL(snd_pcm_release_substream); | |||
1048 | EXPORT_SYMBOL(snd_pcm_format_name); | 1049 | EXPORT_SYMBOL(snd_pcm_format_name); |
1049 | /* pcm_native.c */ | 1050 | /* pcm_native.c */ |
1050 | EXPORT_SYMBOL(snd_pcm_link_rwlock); | 1051 | EXPORT_SYMBOL(snd_pcm_link_rwlock); |
1051 | EXPORT_SYMBOL(snd_pcm_start); | ||
1052 | #ifdef CONFIG_PM | 1052 | #ifdef CONFIG_PM |
1053 | EXPORT_SYMBOL(snd_pcm_suspend); | 1053 | EXPORT_SYMBOL(snd_pcm_suspend); |
1054 | EXPORT_SYMBOL(snd_pcm_suspend_all); | 1054 | EXPORT_SYMBOL(snd_pcm_suspend_all); |
@@ -1068,6 +1068,7 @@ EXPORT_SYMBOL(snd_pcm_format_little_endian); | |||
1068 | EXPORT_SYMBOL(snd_pcm_format_big_endian); | 1068 | EXPORT_SYMBOL(snd_pcm_format_big_endian); |
1069 | EXPORT_SYMBOL(snd_pcm_format_width); | 1069 | EXPORT_SYMBOL(snd_pcm_format_width); |
1070 | EXPORT_SYMBOL(snd_pcm_format_physical_width); | 1070 | EXPORT_SYMBOL(snd_pcm_format_physical_width); |
1071 | EXPORT_SYMBOL(snd_pcm_format_size); | ||
1071 | EXPORT_SYMBOL(snd_pcm_format_silence_64); | 1072 | EXPORT_SYMBOL(snd_pcm_format_silence_64); |
1072 | EXPORT_SYMBOL(snd_pcm_format_set_silence); | 1073 | EXPORT_SYMBOL(snd_pcm_format_set_silence); |
1073 | EXPORT_SYMBOL(snd_pcm_build_linear_format); | 1074 | EXPORT_SYMBOL(snd_pcm_build_linear_format); |
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 151fd99ca2c9..c5bfd0918cff 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c | |||
@@ -1143,7 +1143,8 @@ int snd_pcm_hw_constraint_pow2(snd_pcm_runtime_t *runtime, | |||
1143 | #define INT_MIN ((int)((unsigned int)INT_MAX+1)) | 1143 | #define INT_MIN ((int)((unsigned int)INT_MAX+1)) |
1144 | #endif | 1144 | #endif |
1145 | 1145 | ||
1146 | void _snd_pcm_hw_param_any(snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var) | 1146 | static void _snd_pcm_hw_param_any(snd_pcm_hw_params_t *params, |
1147 | snd_pcm_hw_param_t var) | ||
1147 | { | 1148 | { |
1148 | if (hw_is_mask(var)) { | 1149 | if (hw_is_mask(var)) { |
1149 | snd_mask_any(hw_param_mask(params, var)); | 1150 | snd_mask_any(hw_param_mask(params, var)); |
@@ -1160,6 +1161,7 @@ void _snd_pcm_hw_param_any(snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var) | |||
1160 | snd_BUG(); | 1161 | snd_BUG(); |
1161 | } | 1162 | } |
1162 | 1163 | ||
1164 | #if 0 | ||
1163 | /** | 1165 | /** |
1164 | * snd_pcm_hw_param_any | 1166 | * snd_pcm_hw_param_any |
1165 | */ | 1167 | */ |
@@ -1169,6 +1171,7 @@ int snd_pcm_hw_param_any(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, | |||
1169 | _snd_pcm_hw_param_any(params, var); | 1171 | _snd_pcm_hw_param_any(params, var); |
1170 | return snd_pcm_hw_refine(pcm, params); | 1172 | return snd_pcm_hw_refine(pcm, params); |
1171 | } | 1173 | } |
1174 | #endif /* 0 */ | ||
1172 | 1175 | ||
1173 | void _snd_pcm_hw_params_any(snd_pcm_hw_params_t *params) | 1176 | void _snd_pcm_hw_params_any(snd_pcm_hw_params_t *params) |
1174 | { | 1177 | { |
@@ -1181,6 +1184,7 @@ void _snd_pcm_hw_params_any(snd_pcm_hw_params_t *params) | |||
1181 | params->info = ~0U; | 1184 | params->info = ~0U; |
1182 | } | 1185 | } |
1183 | 1186 | ||
1187 | #if 0 | ||
1184 | /** | 1188 | /** |
1185 | * snd_pcm_hw_params_any | 1189 | * snd_pcm_hw_params_any |
1186 | * | 1190 | * |
@@ -1191,6 +1195,7 @@ int snd_pcm_hw_params_any(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) | |||
1191 | _snd_pcm_hw_params_any(params); | 1195 | _snd_pcm_hw_params_any(params); |
1192 | return snd_pcm_hw_refine(pcm, params); | 1196 | return snd_pcm_hw_refine(pcm, params); |
1193 | } | 1197 | } |
1198 | #endif /* 0 */ | ||
1194 | 1199 | ||
1195 | /** | 1200 | /** |
1196 | * snd_pcm_hw_param_value | 1201 | * snd_pcm_hw_param_value |
@@ -1198,8 +1203,8 @@ int snd_pcm_hw_params_any(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) | |||
1198 | * Return the value for field PAR if it's fixed in configuration space | 1203 | * Return the value for field PAR if it's fixed in configuration space |
1199 | * defined by PARAMS. Return -EINVAL otherwise | 1204 | * defined by PARAMS. Return -EINVAL otherwise |
1200 | */ | 1205 | */ |
1201 | int snd_pcm_hw_param_value(const snd_pcm_hw_params_t *params, | 1206 | static int snd_pcm_hw_param_value(const snd_pcm_hw_params_t *params, |
1202 | snd_pcm_hw_param_t var, int *dir) | 1207 | snd_pcm_hw_param_t var, int *dir) |
1203 | { | 1208 | { |
1204 | if (hw_is_mask(var)) { | 1209 | if (hw_is_mask(var)) { |
1205 | const snd_mask_t *mask = hw_param_mask_c(params, var); | 1210 | const snd_mask_t *mask = hw_param_mask_c(params, var); |
@@ -1296,6 +1301,7 @@ int _snd_pcm_hw_param_setinteger(snd_pcm_hw_params_t *params, | |||
1296 | return changed; | 1301 | return changed; |
1297 | } | 1302 | } |
1298 | 1303 | ||
1304 | #if 0 | ||
1299 | /** | 1305 | /** |
1300 | * snd_pcm_hw_param_setinteger | 1306 | * snd_pcm_hw_param_setinteger |
1301 | * | 1307 | * |
@@ -1317,9 +1323,10 @@ int snd_pcm_hw_param_setinteger(snd_pcm_t *pcm, | |||
1317 | } | 1323 | } |
1318 | return 0; | 1324 | return 0; |
1319 | } | 1325 | } |
1326 | #endif /* 0 */ | ||
1320 | 1327 | ||
1321 | int _snd_pcm_hw_param_first(snd_pcm_hw_params_t *params, | 1328 | static int _snd_pcm_hw_param_first(snd_pcm_hw_params_t *params, |
1322 | snd_pcm_hw_param_t var) | 1329 | snd_pcm_hw_param_t var) |
1323 | { | 1330 | { |
1324 | int changed; | 1331 | int changed; |
1325 | if (hw_is_mask(var)) | 1332 | if (hw_is_mask(var)) |
@@ -1345,9 +1352,9 @@ int _snd_pcm_hw_param_first(snd_pcm_hw_params_t *params, | |||
1345 | * values > minimum. Reduce configuration space accordingly. | 1352 | * values > minimum. Reduce configuration space accordingly. |
1346 | * Return the minimum. | 1353 | * Return the minimum. |
1347 | */ | 1354 | */ |
1348 | int snd_pcm_hw_param_first(snd_pcm_t *pcm, | 1355 | static int snd_pcm_hw_param_first(snd_pcm_t *pcm, |
1349 | snd_pcm_hw_params_t *params, | 1356 | snd_pcm_hw_params_t *params, |
1350 | snd_pcm_hw_param_t var, int *dir) | 1357 | snd_pcm_hw_param_t var, int *dir) |
1351 | { | 1358 | { |
1352 | int changed = _snd_pcm_hw_param_first(params, var); | 1359 | int changed = _snd_pcm_hw_param_first(params, var); |
1353 | if (changed < 0) | 1360 | if (changed < 0) |
@@ -1359,8 +1366,8 @@ int snd_pcm_hw_param_first(snd_pcm_t *pcm, | |||
1359 | return snd_pcm_hw_param_value(params, var, dir); | 1366 | return snd_pcm_hw_param_value(params, var, dir); |
1360 | } | 1367 | } |
1361 | 1368 | ||
1362 | int _snd_pcm_hw_param_last(snd_pcm_hw_params_t *params, | 1369 | static int _snd_pcm_hw_param_last(snd_pcm_hw_params_t *params, |
1363 | snd_pcm_hw_param_t var) | 1370 | snd_pcm_hw_param_t var) |
1364 | { | 1371 | { |
1365 | int changed; | 1372 | int changed; |
1366 | if (hw_is_mask(var)) | 1373 | if (hw_is_mask(var)) |
@@ -1386,9 +1393,9 @@ int _snd_pcm_hw_param_last(snd_pcm_hw_params_t *params, | |||
1386 | * values < maximum. Reduce configuration space accordingly. | 1393 | * values < maximum. Reduce configuration space accordingly. |
1387 | * Return the maximum. | 1394 | * Return the maximum. |
1388 | */ | 1395 | */ |
1389 | int snd_pcm_hw_param_last(snd_pcm_t *pcm, | 1396 | static int snd_pcm_hw_param_last(snd_pcm_t *pcm, |
1390 | snd_pcm_hw_params_t *params, | 1397 | snd_pcm_hw_params_t *params, |
1391 | snd_pcm_hw_param_t var, int *dir) | 1398 | snd_pcm_hw_param_t var, int *dir) |
1392 | { | 1399 | { |
1393 | int changed = _snd_pcm_hw_param_last(params, var); | 1400 | int changed = _snd_pcm_hw_param_last(params, var); |
1394 | if (changed < 0) | 1401 | if (changed < 0) |
@@ -1437,8 +1444,9 @@ int _snd_pcm_hw_param_min(snd_pcm_hw_params_t *params, | |||
1437 | * values < VAL. Reduce configuration space accordingly. | 1444 | * values < VAL. Reduce configuration space accordingly. |
1438 | * Return new minimum or -EINVAL if the configuration space is empty | 1445 | * Return new minimum or -EINVAL if the configuration space is empty |
1439 | */ | 1446 | */ |
1440 | int snd_pcm_hw_param_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, | 1447 | static int snd_pcm_hw_param_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, |
1441 | snd_pcm_hw_param_t var, unsigned int val, int *dir) | 1448 | snd_pcm_hw_param_t var, unsigned int val, |
1449 | int *dir) | ||
1442 | { | 1450 | { |
1443 | int changed = _snd_pcm_hw_param_min(params, var, val, dir ? *dir : 0); | 1451 | int changed = _snd_pcm_hw_param_min(params, var, val, dir ? *dir : 0); |
1444 | if (changed < 0) | 1452 | if (changed < 0) |
@@ -1451,8 +1459,9 @@ int snd_pcm_hw_param_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, | |||
1451 | return snd_pcm_hw_param_value_min(params, var, dir); | 1459 | return snd_pcm_hw_param_value_min(params, var, dir); |
1452 | } | 1460 | } |
1453 | 1461 | ||
1454 | int _snd_pcm_hw_param_max(snd_pcm_hw_params_t *params, | 1462 | static int _snd_pcm_hw_param_max(snd_pcm_hw_params_t *params, |
1455 | snd_pcm_hw_param_t var, unsigned int val, int dir) | 1463 | snd_pcm_hw_param_t var, unsigned int val, |
1464 | int dir) | ||
1456 | { | 1465 | { |
1457 | int changed; | 1466 | int changed; |
1458 | int open = 0; | 1467 | int open = 0; |
@@ -1490,8 +1499,9 @@ int _snd_pcm_hw_param_max(snd_pcm_hw_params_t *params, | |||
1490 | * values >= VAL + 1. Reduce configuration space accordingly. | 1499 | * values >= VAL + 1. Reduce configuration space accordingly. |
1491 | * Return new maximum or -EINVAL if the configuration space is empty | 1500 | * Return new maximum or -EINVAL if the configuration space is empty |
1492 | */ | 1501 | */ |
1493 | int snd_pcm_hw_param_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, | 1502 | static int snd_pcm_hw_param_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, |
1494 | snd_pcm_hw_param_t var, unsigned int val, int *dir) | 1503 | snd_pcm_hw_param_t var, unsigned int val, |
1504 | int *dir) | ||
1495 | { | 1505 | { |
1496 | int changed = _snd_pcm_hw_param_max(params, var, val, dir ? *dir : 0); | 1506 | int changed = _snd_pcm_hw_param_max(params, var, val, dir ? *dir : 0); |
1497 | if (changed < 0) | 1507 | if (changed < 0) |
@@ -2564,9 +2574,6 @@ snd_pcm_sframes_t snd_pcm_lib_readv(snd_pcm_substream_t *substream, | |||
2564 | EXPORT_SYMBOL(snd_interval_refine); | 2574 | EXPORT_SYMBOL(snd_interval_refine); |
2565 | EXPORT_SYMBOL(snd_interval_list); | 2575 | EXPORT_SYMBOL(snd_interval_list); |
2566 | EXPORT_SYMBOL(snd_interval_ratnum); | 2576 | EXPORT_SYMBOL(snd_interval_ratnum); |
2567 | EXPORT_SYMBOL(snd_interval_muldivk); | ||
2568 | EXPORT_SYMBOL(snd_interval_mulkdiv); | ||
2569 | EXPORT_SYMBOL(snd_interval_div); | ||
2570 | EXPORT_SYMBOL(_snd_pcm_hw_params_any); | 2577 | EXPORT_SYMBOL(_snd_pcm_hw_params_any); |
2571 | EXPORT_SYMBOL(_snd_pcm_hw_param_min); | 2578 | EXPORT_SYMBOL(_snd_pcm_hw_param_min); |
2572 | EXPORT_SYMBOL(_snd_pcm_hw_param_set); | 2579 | EXPORT_SYMBOL(_snd_pcm_hw_param_set); |
@@ -2580,7 +2587,6 @@ EXPORT_SYMBOL(snd_pcm_hw_param_last); | |||
2580 | EXPORT_SYMBOL(snd_pcm_hw_param_near); | 2587 | EXPORT_SYMBOL(snd_pcm_hw_param_near); |
2581 | EXPORT_SYMBOL(snd_pcm_hw_param_set); | 2588 | EXPORT_SYMBOL(snd_pcm_hw_param_set); |
2582 | EXPORT_SYMBOL(snd_pcm_hw_refine); | 2589 | EXPORT_SYMBOL(snd_pcm_hw_refine); |
2583 | EXPORT_SYMBOL(snd_pcm_hw_params); | ||
2584 | EXPORT_SYMBOL(snd_pcm_hw_constraints_init); | 2590 | EXPORT_SYMBOL(snd_pcm_hw_constraints_init); |
2585 | EXPORT_SYMBOL(snd_pcm_hw_constraints_complete); | 2591 | EXPORT_SYMBOL(snd_pcm_hw_constraints_complete); |
2586 | EXPORT_SYMBOL(snd_pcm_hw_constraint_list); | 2592 | EXPORT_SYMBOL(snd_pcm_hw_constraint_list); |
diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index f1d5f7a6ee0c..9a174fb96565 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c | |||
@@ -204,6 +204,7 @@ static int snd_pcm_lib_preallocate_pages1(snd_pcm_substream_t *substream, | |||
204 | entry->c.text.read = snd_pcm_lib_preallocate_proc_read; | 204 | entry->c.text.read = snd_pcm_lib_preallocate_proc_read; |
205 | entry->c.text.write_size = 64; | 205 | entry->c.text.write_size = 64; |
206 | entry->c.text.write = snd_pcm_lib_preallocate_proc_write; | 206 | entry->c.text.write = snd_pcm_lib_preallocate_proc_write; |
207 | entry->mode |= S_IWUSR; | ||
207 | entry->private_data = substream; | 208 | entry->private_data = substream; |
208 | if (snd_info_register(entry) < 0) { | 209 | if (snd_info_register(entry) < 0) { |
209 | snd_info_free_entry(entry); | 210 | snd_info_free_entry(entry); |
diff --git a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c index 422b8db14154..1453743e4da0 100644 --- a/sound/core/pcm_misc.c +++ b/sound/core/pcm_misc.c | |||
@@ -270,22 +270,6 @@ int snd_pcm_format_big_endian(snd_pcm_format_t format) | |||
270 | } | 270 | } |
271 | 271 | ||
272 | /** | 272 | /** |
273 | * snd_pcm_format_cpu_endian - Check the PCM format is CPU-endian | ||
274 | * @format: the format to check | ||
275 | * | ||
276 | * Returns 1 if the given PCM format is CPU-endian, 0 if | ||
277 | * opposite, or a negative error code if endian not specified. | ||
278 | */ | ||
279 | int snd_pcm_format_cpu_endian(snd_pcm_format_t format) | ||
280 | { | ||
281 | #ifdef SNDRV_LITTLE_ENDIAN | ||
282 | return snd_pcm_format_little_endian(format); | ||
283 | #else | ||
284 | return snd_pcm_format_big_endian(format); | ||
285 | #endif | ||
286 | } | ||
287 | |||
288 | /** | ||
289 | * snd_pcm_format_width - return the bit-width of the format | 273 | * snd_pcm_format_width - return the bit-width of the format |
290 | * @format: the format to check | 274 | * @format: the format to check |
291 | * | 275 | * |
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index cad9bbde9986..10c2c9832649 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c | |||
@@ -337,8 +337,8 @@ out: | |||
337 | return err; | 337 | return err; |
338 | } | 338 | } |
339 | 339 | ||
340 | int snd_pcm_hw_params(snd_pcm_substream_t *substream, | 340 | static int snd_pcm_hw_params(snd_pcm_substream_t *substream, |
341 | snd_pcm_hw_params_t *params) | 341 | snd_pcm_hw_params_t *params) |
342 | { | 342 | { |
343 | snd_pcm_runtime_t *runtime; | 343 | snd_pcm_runtime_t *runtime; |
344 | int err; | 344 | int err; |
@@ -1368,43 +1368,32 @@ static int snd_pcm_drain(snd_pcm_substream_t *substream) | |||
1368 | if (runtime->status->state == SNDRV_PCM_STATE_OPEN) | 1368 | if (runtime->status->state == SNDRV_PCM_STATE_OPEN) |
1369 | return -EBADFD; | 1369 | return -EBADFD; |
1370 | 1370 | ||
1371 | down_read(&snd_pcm_link_rwsem); | ||
1372 | snd_power_lock(card); | 1371 | snd_power_lock(card); |
1373 | if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { | 1372 | if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { |
1374 | result = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile); | 1373 | result = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile); |
1375 | if (result < 0) | 1374 | if (result < 0) { |
1376 | goto _unlock; | 1375 | snd_power_unlock(card); |
1376 | return result; | ||
1377 | } | ||
1377 | } | 1378 | } |
1378 | 1379 | ||
1379 | /* allocate temporary record for drain sync */ | 1380 | /* allocate temporary record for drain sync */ |
1381 | down_read(&snd_pcm_link_rwsem); | ||
1380 | if (snd_pcm_stream_linked(substream)) { | 1382 | if (snd_pcm_stream_linked(substream)) { |
1381 | drec = kmalloc(substream->group->count * sizeof(*drec), GFP_KERNEL); | 1383 | drec = kmalloc(substream->group->count * sizeof(*drec), GFP_KERNEL); |
1382 | if (! drec) { | 1384 | if (! drec) { |
1383 | result = -ENOMEM; | 1385 | up_read(&snd_pcm_link_rwsem); |
1384 | goto _unlock; | 1386 | snd_power_unlock(card); |
1387 | return -ENOMEM; | ||
1385 | } | 1388 | } |
1386 | } else | 1389 | } else |
1387 | drec = &drec_tmp; | 1390 | drec = &drec_tmp; |
1388 | 1391 | ||
1389 | snd_pcm_stream_lock_irq(substream); | 1392 | /* count only playback streams */ |
1390 | /* resume pause */ | ||
1391 | if (runtime->status->state == SNDRV_PCM_STATE_PAUSED) | ||
1392 | snd_pcm_pause(substream, 0); | ||
1393 | |||
1394 | /* pre-start/stop - all running streams are changed to DRAINING state */ | ||
1395 | result = snd_pcm_action(&snd_pcm_action_drain_init, substream, 0); | ||
1396 | if (result < 0) | ||
1397 | goto _end; | ||
1398 | |||
1399 | /* check streams with PLAYBACK & DRAINING */ | ||
1400 | num_drecs = 0; | 1393 | num_drecs = 0; |
1401 | snd_pcm_group_for_each(pos, substream) { | 1394 | snd_pcm_group_for_each(pos, substream) { |
1402 | snd_pcm_substream_t *s = snd_pcm_group_substream_entry(pos); | 1395 | snd_pcm_substream_t *s = snd_pcm_group_substream_entry(pos); |
1403 | runtime = s->runtime; | 1396 | runtime = s->runtime; |
1404 | if (runtime->status->state != SNDRV_PCM_STATE_DRAINING) { | ||
1405 | runtime->status->state = SNDRV_PCM_STATE_SETUP; | ||
1406 | continue; | ||
1407 | } | ||
1408 | if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 1397 | if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
1409 | d = &drec[num_drecs++]; | 1398 | d = &drec[num_drecs++]; |
1410 | d->substream = s; | 1399 | d->substream = s; |
@@ -1418,9 +1407,21 @@ static int snd_pcm_drain(snd_pcm_substream_t *substream) | |||
1418 | runtime->stop_threshold = runtime->buffer_size; | 1407 | runtime->stop_threshold = runtime->buffer_size; |
1419 | } | 1408 | } |
1420 | } | 1409 | } |
1421 | 1410 | up_read(&snd_pcm_link_rwsem); | |
1422 | if (! num_drecs) | 1411 | if (! num_drecs) |
1423 | goto _end; | 1412 | goto _error; |
1413 | |||
1414 | snd_pcm_stream_lock_irq(substream); | ||
1415 | /* resume pause */ | ||
1416 | if (runtime->status->state == SNDRV_PCM_STATE_PAUSED) | ||
1417 | snd_pcm_pause(substream, 0); | ||
1418 | |||
1419 | /* pre-start/stop - all running streams are changed to DRAINING state */ | ||
1420 | result = snd_pcm_action(&snd_pcm_action_drain_init, substream, 0); | ||
1421 | if (result < 0) { | ||
1422 | snd_pcm_stream_unlock_irq(substream); | ||
1423 | goto _error; | ||
1424 | } | ||
1424 | 1425 | ||
1425 | for (;;) { | 1426 | for (;;) { |
1426 | long tout; | 1427 | long tout; |
@@ -1428,6 +1429,15 @@ static int snd_pcm_drain(snd_pcm_substream_t *substream) | |||
1428 | result = -ERESTARTSYS; | 1429 | result = -ERESTARTSYS; |
1429 | break; | 1430 | break; |
1430 | } | 1431 | } |
1432 | /* all finished? */ | ||
1433 | for (i = 0; i < num_drecs; i++) { | ||
1434 | runtime = drec[i].substream->runtime; | ||
1435 | if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) | ||
1436 | break; | ||
1437 | } | ||
1438 | if (i == num_drecs) | ||
1439 | break; /* yes, all drained */ | ||
1440 | |||
1431 | set_current_state(TASK_INTERRUPTIBLE); | 1441 | set_current_state(TASK_INTERRUPTIBLE); |
1432 | snd_pcm_stream_unlock_irq(substream); | 1442 | snd_pcm_stream_unlock_irq(substream); |
1433 | snd_power_unlock(card); | 1443 | snd_power_unlock(card); |
@@ -1444,15 +1454,11 @@ static int snd_pcm_drain(snd_pcm_substream_t *substream) | |||
1444 | } | 1454 | } |
1445 | break; | 1455 | break; |
1446 | } | 1456 | } |
1447 | /* all finished? */ | ||
1448 | for (i = 0; i < num_drecs; i++) { | ||
1449 | runtime = drec[i].substream->runtime; | ||
1450 | if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) | ||
1451 | break; | ||
1452 | } | ||
1453 | if (i == num_drecs) | ||
1454 | break; | ||
1455 | } | 1457 | } |
1458 | |||
1459 | snd_pcm_stream_unlock_irq(substream); | ||
1460 | |||
1461 | _error: | ||
1456 | for (i = 0; i < num_drecs; i++) { | 1462 | for (i = 0; i < num_drecs; i++) { |
1457 | d = &drec[i]; | 1463 | d = &drec[i]; |
1458 | runtime = d->substream->runtime; | 1464 | runtime = d->substream->runtime; |
@@ -1460,13 +1466,9 @@ static int snd_pcm_drain(snd_pcm_substream_t *substream) | |||
1460 | runtime->stop_threshold = d->stop_threshold; | 1466 | runtime->stop_threshold = d->stop_threshold; |
1461 | } | 1467 | } |
1462 | 1468 | ||
1463 | _end: | ||
1464 | snd_pcm_stream_unlock_irq(substream); | ||
1465 | if (drec != &drec_tmp) | 1469 | if (drec != &drec_tmp) |
1466 | kfree(drec); | 1470 | kfree(drec); |
1467 | _unlock: | ||
1468 | snd_power_unlock(card); | 1471 | snd_power_unlock(card); |
1469 | up_read(&snd_pcm_link_rwsem); | ||
1470 | 1472 | ||
1471 | return result; | 1473 | return result; |
1472 | } | 1474 | } |
diff --git a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c index 638cc148706d..1a7736cbf3a4 100644 --- a/sound/core/seq/oss/seq_oss_synth.c +++ b/sound/core/seq/oss/seq_oss_synth.c | |||
@@ -325,14 +325,10 @@ snd_seq_oss_synth_cleanup(seq_oss_devinfo_t *dp) | |||
325 | } | 325 | } |
326 | snd_use_lock_free(&rec->use_lock); | 326 | snd_use_lock_free(&rec->use_lock); |
327 | } | 327 | } |
328 | if (info->sysex) { | 328 | kfree(info->sysex); |
329 | kfree(info->sysex); | 329 | info->sysex = NULL; |
330 | info->sysex = NULL; | 330 | kfree(info->ch); |
331 | } | 331 | info->ch = NULL; |
332 | if (info->ch) { | ||
333 | kfree(info->ch); | ||
334 | info->ch = NULL; | ||
335 | } | ||
336 | } | 332 | } |
337 | dp->synth_opened = 0; | 333 | dp->synth_opened = 0; |
338 | dp->max_synthdev = 0; | 334 | dp->max_synthdev = 0; |
@@ -418,14 +414,10 @@ snd_seq_oss_synth_reset(seq_oss_devinfo_t *dp, int dev) | |||
418 | dp->file_mode) < 0) { | 414 | dp->file_mode) < 0) { |
419 | midi_synth_dev.opened--; | 415 | midi_synth_dev.opened--; |
420 | info->opened = 0; | 416 | info->opened = 0; |
421 | if (info->sysex) { | 417 | kfree(info->sysex); |
422 | kfree(info->sysex); | 418 | info->sysex = NULL; |
423 | info->sysex = NULL; | 419 | kfree(info->ch); |
424 | } | 420 | info->ch = NULL; |
425 | if (info->ch) { | ||
426 | kfree(info->ch); | ||
427 | info->ch = NULL; | ||
428 | } | ||
429 | } | 421 | } |
430 | return; | 422 | return; |
431 | } | 423 | } |
diff --git a/sound/core/seq/seq_dummy.c b/sound/core/seq/seq_dummy.c index e88967c5b93d..ea945a5d2a0b 100644 --- a/sound/core/seq/seq_dummy.c +++ b/sound/core/seq/seq_dummy.c | |||
@@ -140,10 +140,7 @@ dummy_input(snd_seq_event_t *ev, int direct, void *private_data, int atomic, int | |||
140 | static void | 140 | static void |
141 | dummy_free(void *private_data) | 141 | dummy_free(void *private_data) |
142 | { | 142 | { |
143 | snd_seq_dummy_port_t *p; | 143 | kfree(private_data); |
144 | |||
145 | p = private_data; | ||
146 | kfree(p); | ||
147 | } | 144 | } |
148 | 145 | ||
149 | /* | 146 | /* |
diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c index 18247db45db6..57be9155eb62 100644 --- a/sound/core/seq/seq_midi.c +++ b/sound/core/seq/seq_midi.c | |||
@@ -414,6 +414,8 @@ snd_seq_midisynth_register_port(snd_seq_device_t *dev) | |||
414 | if (newclient) | 414 | if (newclient) |
415 | synths[card->number] = client; | 415 | synths[card->number] = client; |
416 | up(®ister_mutex); | 416 | up(®ister_mutex); |
417 | kfree(info); | ||
418 | kfree(port); | ||
417 | return 0; /* success */ | 419 | return 0; /* success */ |
418 | 420 | ||
419 | __nomem: | 421 | __nomem: |
diff --git a/sound/core/seq/seq_midi_event.c b/sound/core/seq/seq_midi_event.c index 21e569062bc3..df1e2bb39745 100644 --- a/sound/core/seq/seq_midi_event.c +++ b/sound/core/seq/seq_midi_event.c | |||
@@ -171,11 +171,13 @@ void snd_midi_event_reset_decode(snd_midi_event_t *dev) | |||
171 | spin_unlock_irqrestore(&dev->lock, flags); | 171 | spin_unlock_irqrestore(&dev->lock, flags); |
172 | } | 172 | } |
173 | 173 | ||
174 | #if 0 | ||
174 | void snd_midi_event_init(snd_midi_event_t *dev) | 175 | void snd_midi_event_init(snd_midi_event_t *dev) |
175 | { | 176 | { |
176 | snd_midi_event_reset_encode(dev); | 177 | snd_midi_event_reset_encode(dev); |
177 | snd_midi_event_reset_decode(dev); | 178 | snd_midi_event_reset_decode(dev); |
178 | } | 179 | } |
180 | #endif /* 0 */ | ||
179 | 181 | ||
180 | void snd_midi_event_no_status(snd_midi_event_t *dev, int on) | 182 | void snd_midi_event_no_status(snd_midi_event_t *dev, int on) |
181 | { | 183 | { |
@@ -185,6 +187,7 @@ void snd_midi_event_no_status(snd_midi_event_t *dev, int on) | |||
185 | /* | 187 | /* |
186 | * resize buffer | 188 | * resize buffer |
187 | */ | 189 | */ |
190 | #if 0 | ||
188 | int snd_midi_event_resize_buffer(snd_midi_event_t *dev, int bufsize) | 191 | int snd_midi_event_resize_buffer(snd_midi_event_t *dev, int bufsize) |
189 | { | 192 | { |
190 | unsigned char *new_buf, *old_buf; | 193 | unsigned char *new_buf, *old_buf; |
@@ -204,6 +207,7 @@ int snd_midi_event_resize_buffer(snd_midi_event_t *dev, int bufsize) | |||
204 | kfree(old_buf); | 207 | kfree(old_buf); |
205 | return 0; | 208 | return 0; |
206 | } | 209 | } |
210 | #endif /* 0 */ | ||
207 | 211 | ||
208 | /* | 212 | /* |
209 | * read bytes and encode to sequencer event if finished | 213 | * read bytes and encode to sequencer event if finished |
@@ -517,8 +521,6 @@ static int extra_decode_xrpn(snd_midi_event_t *dev, unsigned char *buf, int coun | |||
517 | 521 | ||
518 | EXPORT_SYMBOL(snd_midi_event_new); | 522 | EXPORT_SYMBOL(snd_midi_event_new); |
519 | EXPORT_SYMBOL(snd_midi_event_free); | 523 | EXPORT_SYMBOL(snd_midi_event_free); |
520 | EXPORT_SYMBOL(snd_midi_event_resize_buffer); | ||
521 | EXPORT_SYMBOL(snd_midi_event_init); | ||
522 | EXPORT_SYMBOL(snd_midi_event_reset_encode); | 524 | EXPORT_SYMBOL(snd_midi_event_reset_encode); |
523 | EXPORT_SYMBOL(snd_midi_event_reset_decode); | 525 | EXPORT_SYMBOL(snd_midi_event_reset_decode); |
524 | EXPORT_SYMBOL(snd_midi_event_no_status); | 526 | EXPORT_SYMBOL(snd_midi_event_no_status); |
diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c index 3afc7cc0c9a7..98de2e711fde 100644 --- a/sound/core/seq/seq_queue.c +++ b/sound/core/seq/seq_queue.c | |||
@@ -672,7 +672,8 @@ static void queue_broadcast_event(queue_t *q, snd_seq_event_t *ev, int atomic, i | |||
672 | * process a received queue-control event. | 672 | * process a received queue-control event. |
673 | * this function is exported for seq_sync.c. | 673 | * this function is exported for seq_sync.c. |
674 | */ | 674 | */ |
675 | void snd_seq_queue_process_event(queue_t *q, snd_seq_event_t *ev, int atomic, int hop) | 675 | static void snd_seq_queue_process_event(queue_t *q, snd_seq_event_t *ev, |
676 | int atomic, int hop) | ||
676 | { | 677 | { |
677 | switch (ev->type) { | 678 | switch (ev->type) { |
678 | case SNDRV_SEQ_EVENT_START: | 679 | case SNDRV_SEQ_EVENT_START: |
diff --git a/sound/core/seq/seq_queue.h b/sound/core/seq/seq_queue.h index b1bf5519fb3b..ea3c54216ea8 100644 --- a/sound/core/seq/seq_queue.h +++ b/sound/core/seq/seq_queue.h | |||
@@ -111,7 +111,6 @@ int snd_seq_queue_use(int queueid, int client, int use); | |||
111 | int snd_seq_queue_is_used(int queueid, int client); | 111 | int snd_seq_queue_is_used(int queueid, int client); |
112 | 112 | ||
113 | int snd_seq_control_queue(snd_seq_event_t *ev, int atomic, int hop); | 113 | int snd_seq_control_queue(snd_seq_event_t *ev, int atomic, int hop); |
114 | void snd_seq_queue_process_event(queue_t *q, snd_seq_event_t *ev, int atomic, int hop); | ||
115 | 114 | ||
116 | /* | 115 | /* |
117 | * 64bit division - for sync stuff.. | 116 | * 64bit division - for sync stuff.. |
diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c index 753f1c0863cc..a7f76fc95280 100644 --- a/sound/core/seq/seq_timer.c +++ b/sound/core/seq/seq_timer.c | |||
@@ -36,7 +36,8 @@ extern int seq_default_timer_resolution; | |||
36 | 36 | ||
37 | #define SKEW_BASE 0x10000 /* 16bit shift */ | 37 | #define SKEW_BASE 0x10000 /* 16bit shift */ |
38 | 38 | ||
39 | void snd_seq_timer_set_tick_resolution(seq_timer_tick_t *tick, int tempo, int ppq, int nticks) | 39 | static void snd_seq_timer_set_tick_resolution(seq_timer_tick_t *tick, |
40 | int tempo, int ppq, int nticks) | ||
40 | { | 41 | { |
41 | if (tempo < 1000000) | 42 | if (tempo < 1000000) |
42 | tick->resolution = (tempo * 1000) / ppq; | 43 | tick->resolution = (tempo * 1000) / ppq; |
diff --git a/sound/core/seq/seq_timer.h b/sound/core/seq/seq_timer.h index 4c0872df8931..287ed68591de 100644 --- a/sound/core/seq/seq_timer.h +++ b/sound/core/seq/seq_timer.h | |||
@@ -64,8 +64,6 @@ extern seq_timer_t *snd_seq_timer_new(void); | |||
64 | /* delete timer (destructor) */ | 64 | /* delete timer (destructor) */ |
65 | extern void snd_seq_timer_delete(seq_timer_t **tmr); | 65 | extern void snd_seq_timer_delete(seq_timer_t **tmr); |
66 | 66 | ||
67 | void snd_seq_timer_set_tick_resolution(seq_timer_tick_t *tick, int tempo, int ppq, int nticks); | ||
68 | |||
69 | /* */ | 67 | /* */ |
70 | static inline void snd_seq_timer_update_tick(seq_timer_tick_t *tick, unsigned long resolution) | 68 | static inline void snd_seq_timer_update_tick(seq_timer_tick_t *tick, unsigned long resolution) |
71 | { | 69 | { |
diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c index 6b4e630ace54..a66484b5cf0e 100644 --- a/sound/core/seq/seq_virmidi.c +++ b/sound/core/seq/seq_virmidi.c | |||
@@ -110,7 +110,7 @@ static int snd_virmidi_dev_receive_event(snd_virmidi_dev_t *rdev, snd_seq_event_ | |||
110 | * handler of a remote port which is attached to the virmidi via | 110 | * handler of a remote port which is attached to the virmidi via |
111 | * SNDRV_VIRMIDI_SEQ_ATTACH. | 111 | * SNDRV_VIRMIDI_SEQ_ATTACH. |
112 | */ | 112 | */ |
113 | /* exported */ | 113 | #if 0 |
114 | int snd_virmidi_receive(snd_rawmidi_t *rmidi, snd_seq_event_t *ev) | 114 | int snd_virmidi_receive(snd_rawmidi_t *rmidi, snd_seq_event_t *ev) |
115 | { | 115 | { |
116 | snd_virmidi_dev_t *rdev; | 116 | snd_virmidi_dev_t *rdev; |
@@ -118,6 +118,7 @@ int snd_virmidi_receive(snd_rawmidi_t *rmidi, snd_seq_event_t *ev) | |||
118 | rdev = rmidi->private_data; | 118 | rdev = rmidi->private_data; |
119 | return snd_virmidi_dev_receive_event(rdev, ev); | 119 | return snd_virmidi_dev_receive_event(rdev, ev); |
120 | } | 120 | } |
121 | #endif /* 0 */ | ||
121 | 122 | ||
122 | /* | 123 | /* |
123 | * event handler of virmidi port | 124 | * event handler of virmidi port |
@@ -384,7 +385,7 @@ static int snd_virmidi_dev_attach_seq(snd_virmidi_dev_t *rdev) | |||
384 | info->client = client; | 385 | info->client = client; |
385 | info->type = KERNEL_CLIENT; | 386 | info->type = KERNEL_CLIENT; |
386 | sprintf(info->name, "%s %d-%d", rdev->rmidi->name, rdev->card->number, rdev->device); | 387 | sprintf(info->name, "%s %d-%d", rdev->rmidi->name, rdev->card->number, rdev->device); |
387 | snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, &info); | 388 | snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, info); |
388 | 389 | ||
389 | /* create a port */ | 390 | /* create a port */ |
390 | memset(pinfo, 0, sizeof(*pinfo)); | 391 | memset(pinfo, 0, sizeof(*pinfo)); |
@@ -405,7 +406,7 @@ static int snd_virmidi_dev_attach_seq(snd_virmidi_dev_t *rdev) | |||
405 | pcallbacks.unuse = snd_virmidi_unuse; | 406 | pcallbacks.unuse = snd_virmidi_unuse; |
406 | pcallbacks.event_input = snd_virmidi_event_input; | 407 | pcallbacks.event_input = snd_virmidi_event_input; |
407 | pinfo->kernel = &pcallbacks; | 408 | pinfo->kernel = &pcallbacks; |
408 | err = snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_CREATE_PORT, &pinfo); | 409 | err = snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_CREATE_PORT, pinfo); |
409 | if (err < 0) { | 410 | if (err < 0) { |
410 | snd_seq_delete_kernel_client(client); | 411 | snd_seq_delete_kernel_client(client); |
411 | rdev->client = -1; | 412 | rdev->client = -1; |
@@ -548,4 +549,3 @@ module_init(alsa_virmidi_init) | |||
548 | module_exit(alsa_virmidi_exit) | 549 | module_exit(alsa_virmidi_exit) |
549 | 550 | ||
550 | EXPORT_SYMBOL(snd_virmidi_new); | 551 | EXPORT_SYMBOL(snd_virmidi_new); |
551 | EXPORT_SYMBOL(snd_virmidi_receive); | ||
diff --git a/sound/core/sound.c b/sound/core/sound.c index 33eaa5e5d284..0815fadeb3ec 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c | |||
@@ -431,7 +431,6 @@ EXPORT_SYMBOL(snd_card_pci_resume); | |||
431 | EXPORT_SYMBOL(snd_device_new); | 431 | EXPORT_SYMBOL(snd_device_new); |
432 | EXPORT_SYMBOL(snd_device_register); | 432 | EXPORT_SYMBOL(snd_device_register); |
433 | EXPORT_SYMBOL(snd_device_free); | 433 | EXPORT_SYMBOL(snd_device_free); |
434 | EXPORT_SYMBOL(snd_device_free_all); | ||
435 | /* isadma.c */ | 434 | /* isadma.c */ |
436 | #ifdef CONFIG_ISA | 435 | #ifdef CONFIG_ISA |
437 | EXPORT_SYMBOL(snd_dma_program); | 436 | EXPORT_SYMBOL(snd_dma_program); |
diff --git a/sound/core/timer.c b/sound/core/timer.c index fa762ca439be..b498e5482d77 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c | |||
@@ -69,6 +69,7 @@ typedef struct { | |||
69 | struct timespec tstamp; /* trigger tstamp */ | 69 | struct timespec tstamp; /* trigger tstamp */ |
70 | wait_queue_head_t qchange_sleep; | 70 | wait_queue_head_t qchange_sleep; |
71 | struct fasync_struct *fasync; | 71 | struct fasync_struct *fasync; |
72 | struct semaphore tread_sem; | ||
72 | } snd_timer_user_t; | 73 | } snd_timer_user_t; |
73 | 74 | ||
74 | /* list of timers */ | 75 | /* list of timers */ |
@@ -844,7 +845,7 @@ int snd_timer_dev_register(snd_device_t *dev) | |||
844 | return 0; | 845 | return 0; |
845 | } | 846 | } |
846 | 847 | ||
847 | int snd_timer_unregister(snd_timer_t *timer) | 848 | static int snd_timer_unregister(snd_timer_t *timer) |
848 | { | 849 | { |
849 | struct list_head *p, *n; | 850 | struct list_head *p, *n; |
850 | snd_timer_instance_t *ti; | 851 | snd_timer_instance_t *ti; |
@@ -945,11 +946,6 @@ struct snd_timer_system_private { | |||
945 | unsigned long correction; | 946 | unsigned long correction; |
946 | }; | 947 | }; |
947 | 948 | ||
948 | unsigned int snd_timer_system_resolution(void) | ||
949 | { | ||
950 | return 1000000000L / HZ; | ||
951 | } | ||
952 | |||
953 | static void snd_timer_s_function(unsigned long data) | 949 | static void snd_timer_s_function(unsigned long data) |
954 | { | 950 | { |
955 | snd_timer_t *timer = (snd_timer_t *)data; | 951 | snd_timer_t *timer = (snd_timer_t *)data; |
@@ -1208,6 +1204,7 @@ static int snd_timer_user_open(struct inode *inode, struct file *file) | |||
1208 | return -ENOMEM; | 1204 | return -ENOMEM; |
1209 | spin_lock_init(&tu->qlock); | 1205 | spin_lock_init(&tu->qlock); |
1210 | init_waitqueue_head(&tu->qchange_sleep); | 1206 | init_waitqueue_head(&tu->qchange_sleep); |
1207 | init_MUTEX(&tu->tread_sem); | ||
1211 | tu->ticks = 1; | 1208 | tu->ticks = 1; |
1212 | tu->queue_size = 128; | 1209 | tu->queue_size = 128; |
1213 | tu->queue = (snd_timer_read_t *)kmalloc(tu->queue_size * sizeof(snd_timer_read_t), GFP_KERNEL); | 1210 | tu->queue = (snd_timer_read_t *)kmalloc(tu->queue_size * sizeof(snd_timer_read_t), GFP_KERNEL); |
@@ -1454,46 +1451,51 @@ static int snd_timer_user_tselect(struct file *file, snd_timer_select_t __user * | |||
1454 | snd_timer_user_t *tu; | 1451 | snd_timer_user_t *tu; |
1455 | snd_timer_select_t tselect; | 1452 | snd_timer_select_t tselect; |
1456 | char str[32]; | 1453 | char str[32]; |
1457 | int err; | 1454 | int err = 0; |
1458 | 1455 | ||
1459 | tu = file->private_data; | 1456 | tu = file->private_data; |
1460 | if (tu->timeri) | 1457 | down(&tu->tread_sem); |
1458 | if (tu->timeri) { | ||
1461 | snd_timer_close(tu->timeri); | 1459 | snd_timer_close(tu->timeri); |
1462 | if (copy_from_user(&tselect, _tselect, sizeof(tselect))) | 1460 | tu->timeri = NULL; |
1463 | return -EFAULT; | 1461 | } |
1462 | if (copy_from_user(&tselect, _tselect, sizeof(tselect))) { | ||
1463 | err = -EFAULT; | ||
1464 | goto __err; | ||
1465 | } | ||
1464 | sprintf(str, "application %i", current->pid); | 1466 | sprintf(str, "application %i", current->pid); |
1465 | if (tselect.id.dev_class != SNDRV_TIMER_CLASS_SLAVE) | 1467 | if (tselect.id.dev_class != SNDRV_TIMER_CLASS_SLAVE) |
1466 | tselect.id.dev_sclass = SNDRV_TIMER_SCLASS_APPLICATION; | 1468 | tselect.id.dev_sclass = SNDRV_TIMER_SCLASS_APPLICATION; |
1467 | if ((err = snd_timer_open(&tu->timeri, str, &tselect.id, current->pid)) < 0) | 1469 | if ((err = snd_timer_open(&tu->timeri, str, &tselect.id, current->pid)) < 0) |
1468 | return err; | 1470 | goto __err; |
1469 | 1471 | ||
1470 | if (tu->queue) { | 1472 | kfree(tu->queue); |
1471 | kfree(tu->queue); | 1473 | tu->queue = NULL; |
1472 | tu->queue = NULL; | 1474 | kfree(tu->tqueue); |
1473 | } | 1475 | tu->tqueue = NULL; |
1474 | if (tu->tqueue) { | ||
1475 | kfree(tu->tqueue); | ||
1476 | tu->tqueue = NULL; | ||
1477 | } | ||
1478 | if (tu->tread) { | 1476 | if (tu->tread) { |
1479 | tu->tqueue = (snd_timer_tread_t *)kmalloc(tu->queue_size * sizeof(snd_timer_tread_t), GFP_KERNEL); | 1477 | tu->tqueue = (snd_timer_tread_t *)kmalloc(tu->queue_size * sizeof(snd_timer_tread_t), GFP_KERNEL); |
1480 | if (tu->tqueue == NULL) { | 1478 | if (tu->tqueue == NULL) |
1481 | snd_timer_close(tu->timeri); | 1479 | err = -ENOMEM; |
1482 | return -ENOMEM; | ||
1483 | } | ||
1484 | } else { | 1480 | } else { |
1485 | tu->queue = (snd_timer_read_t *)kmalloc(tu->queue_size * sizeof(snd_timer_read_t), GFP_KERNEL); | 1481 | tu->queue = (snd_timer_read_t *)kmalloc(tu->queue_size * sizeof(snd_timer_read_t), GFP_KERNEL); |
1486 | if (tu->queue == NULL) { | 1482 | if (tu->queue == NULL) |
1487 | snd_timer_close(tu->timeri); | 1483 | err = -ENOMEM; |
1488 | return -ENOMEM; | ||
1489 | } | ||
1490 | } | 1484 | } |
1491 | 1485 | ||
1492 | tu->timeri->flags |= SNDRV_TIMER_IFLG_FAST; | 1486 | if (err < 0) { |
1493 | tu->timeri->callback = tu->tread ? snd_timer_user_tinterrupt : snd_timer_user_interrupt; | 1487 | snd_timer_close(tu->timeri); |
1494 | tu->timeri->ccallback = snd_timer_user_ccallback; | 1488 | tu->timeri = NULL; |
1495 | tu->timeri->callback_data = (void *)tu; | 1489 | } else { |
1496 | return 0; | 1490 | tu->timeri->flags |= SNDRV_TIMER_IFLG_FAST; |
1491 | tu->timeri->callback = tu->tread ? snd_timer_user_tinterrupt : snd_timer_user_interrupt; | ||
1492 | tu->timeri->ccallback = snd_timer_user_ccallback; | ||
1493 | tu->timeri->callback_data = (void *)tu; | ||
1494 | } | ||
1495 | |||
1496 | __err: | ||
1497 | up(&tu->tread_sem); | ||
1498 | return err; | ||
1497 | } | 1499 | } |
1498 | 1500 | ||
1499 | static int snd_timer_user_info(struct file *file, snd_timer_info_t __user *_info) | 1501 | static int snd_timer_user_info(struct file *file, snd_timer_info_t __user *_info) |
@@ -1669,6 +1671,23 @@ static int snd_timer_user_continue(struct file *file) | |||
1669 | return (err = snd_timer_continue(tu->timeri)) < 0 ? err : 0; | 1671 | return (err = snd_timer_continue(tu->timeri)) < 0 ? err : 0; |
1670 | } | 1672 | } |
1671 | 1673 | ||
1674 | static int snd_timer_user_pause(struct file *file) | ||
1675 | { | ||
1676 | int err; | ||
1677 | snd_timer_user_t *tu; | ||
1678 | |||
1679 | tu = file->private_data; | ||
1680 | snd_assert(tu->timeri != NULL, return -ENXIO); | ||
1681 | return (err = snd_timer_pause(tu->timeri)) < 0 ? err : 0; | ||
1682 | } | ||
1683 | |||
1684 | enum { | ||
1685 | SNDRV_TIMER_IOCTL_START_OLD = _IO('T', 0x20), | ||
1686 | SNDRV_TIMER_IOCTL_STOP_OLD = _IO('T', 0x21), | ||
1687 | SNDRV_TIMER_IOCTL_CONTINUE_OLD = _IO('T', 0x22), | ||
1688 | SNDRV_TIMER_IOCTL_PAUSE_OLD = _IO('T', 0x23), | ||
1689 | }; | ||
1690 | |||
1672 | static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | 1691 | static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
1673 | { | 1692 | { |
1674 | snd_timer_user_t *tu; | 1693 | snd_timer_user_t *tu; |
@@ -1685,11 +1704,17 @@ static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, unsigned l | |||
1685 | { | 1704 | { |
1686 | int xarg; | 1705 | int xarg; |
1687 | 1706 | ||
1688 | if (tu->timeri) /* too late */ | 1707 | down(&tu->tread_sem); |
1708 | if (tu->timeri) { /* too late */ | ||
1709 | up(&tu->tread_sem); | ||
1689 | return -EBUSY; | 1710 | return -EBUSY; |
1690 | if (get_user(xarg, p)) | 1711 | } |
1712 | if (get_user(xarg, p)) { | ||
1713 | up(&tu->tread_sem); | ||
1691 | return -EFAULT; | 1714 | return -EFAULT; |
1715 | } | ||
1692 | tu->tread = xarg ? 1 : 0; | 1716 | tu->tread = xarg ? 1 : 0; |
1717 | up(&tu->tread_sem); | ||
1693 | return 0; | 1718 | return 0; |
1694 | } | 1719 | } |
1695 | case SNDRV_TIMER_IOCTL_GINFO: | 1720 | case SNDRV_TIMER_IOCTL_GINFO: |
@@ -1707,11 +1732,17 @@ static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, unsigned l | |||
1707 | case SNDRV_TIMER_IOCTL_STATUS: | 1732 | case SNDRV_TIMER_IOCTL_STATUS: |
1708 | return snd_timer_user_status(file, argp); | 1733 | return snd_timer_user_status(file, argp); |
1709 | case SNDRV_TIMER_IOCTL_START: | 1734 | case SNDRV_TIMER_IOCTL_START: |
1735 | case SNDRV_TIMER_IOCTL_START_OLD: | ||
1710 | return snd_timer_user_start(file); | 1736 | return snd_timer_user_start(file); |
1711 | case SNDRV_TIMER_IOCTL_STOP: | 1737 | case SNDRV_TIMER_IOCTL_STOP: |
1738 | case SNDRV_TIMER_IOCTL_STOP_OLD: | ||
1712 | return snd_timer_user_stop(file); | 1739 | return snd_timer_user_stop(file); |
1713 | case SNDRV_TIMER_IOCTL_CONTINUE: | 1740 | case SNDRV_TIMER_IOCTL_CONTINUE: |
1741 | case SNDRV_TIMER_IOCTL_CONTINUE_OLD: | ||
1714 | return snd_timer_user_continue(file); | 1742 | return snd_timer_user_continue(file); |
1743 | case SNDRV_TIMER_IOCTL_PAUSE: | ||
1744 | case SNDRV_TIMER_IOCTL_PAUSE_OLD: | ||
1745 | return snd_timer_user_pause(file); | ||
1715 | } | 1746 | } |
1716 | return -ENOTTY; | 1747 | return -ENOTTY; |
1717 | } | 1748 | } |
@@ -1898,4 +1929,3 @@ EXPORT_SYMBOL(snd_timer_global_free); | |||
1898 | EXPORT_SYMBOL(snd_timer_global_register); | 1929 | EXPORT_SYMBOL(snd_timer_global_register); |
1899 | EXPORT_SYMBOL(snd_timer_global_unregister); | 1930 | EXPORT_SYMBOL(snd_timer_global_unregister); |
1900 | EXPORT_SYMBOL(snd_timer_interrupt); | 1931 | EXPORT_SYMBOL(snd_timer_interrupt); |
1901 | EXPORT_SYMBOL(snd_timer_system_resolution); | ||
diff --git a/sound/core/timer_compat.c b/sound/core/timer_compat.c index 9fbc3957a22d..3de552dfe80f 100644 --- a/sound/core/timer_compat.c +++ b/sound/core/timer_compat.c | |||
@@ -106,8 +106,13 @@ static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, uns | |||
106 | case SNDRV_TIMER_IOCTL_SELECT: | 106 | case SNDRV_TIMER_IOCTL_SELECT: |
107 | case SNDRV_TIMER_IOCTL_PARAMS: | 107 | case SNDRV_TIMER_IOCTL_PARAMS: |
108 | case SNDRV_TIMER_IOCTL_START: | 108 | case SNDRV_TIMER_IOCTL_START: |
109 | case SNDRV_TIMER_IOCTL_START_OLD: | ||
109 | case SNDRV_TIMER_IOCTL_STOP: | 110 | case SNDRV_TIMER_IOCTL_STOP: |
111 | case SNDRV_TIMER_IOCTL_STOP_OLD: | ||
110 | case SNDRV_TIMER_IOCTL_CONTINUE: | 112 | case SNDRV_TIMER_IOCTL_CONTINUE: |
113 | case SNDRV_TIMER_IOCTL_CONTINUE_OLD: | ||
114 | case SNDRV_TIMER_IOCTL_PAUSE: | ||
115 | case SNDRV_TIMER_IOCTL_PAUSE_OLD: | ||
111 | case SNDRV_TIMER_IOCTL_NEXT_DEVICE: | 116 | case SNDRV_TIMER_IOCTL_NEXT_DEVICE: |
112 | return snd_timer_user_ioctl(file, cmd, (unsigned long)argp); | 117 | return snd_timer_user_ioctl(file, cmd, (unsigned long)argp); |
113 | case SNDRV_TIMER_IOCTL_INFO32: | 118 | case SNDRV_TIMER_IOCTL_INFO32: |
diff --git a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c index 98587176b327..af381b15fe5c 100644 --- a/sound/drivers/vx/vx_pcm.c +++ b/sound/drivers/vx/vx_pcm.c | |||
@@ -1264,14 +1264,10 @@ static void snd_vx_pcm_free(snd_pcm_t *pcm) | |||
1264 | { | 1264 | { |
1265 | vx_core_t *chip = pcm->private_data; | 1265 | vx_core_t *chip = pcm->private_data; |
1266 | chip->pcm[pcm->device] = NULL; | 1266 | chip->pcm[pcm->device] = NULL; |
1267 | if (chip->playback_pipes) { | 1267 | kfree(chip->playback_pipes); |
1268 | kfree(chip->playback_pipes); | 1268 | chip->playback_pipes = NULL; |
1269 | chip->playback_pipes = NULL; | 1269 | kfree(chip->capture_pipes); |
1270 | } | 1270 | chip->capture_pipes = NULL; |
1271 | if (chip->capture_pipes) { | ||
1272 | kfree(chip->capture_pipes); | ||
1273 | chip->capture_pipes = NULL; | ||
1274 | } | ||
1275 | } | 1271 | } |
1276 | 1272 | ||
1277 | /* | 1273 | /* |
diff --git a/sound/i2c/tea6330t.c b/sound/i2c/tea6330t.c index bb503e70b664..2da8d7f157f4 100644 --- a/sound/i2c/tea6330t.c +++ b/sound/i2c/tea6330t.c | |||
@@ -266,8 +266,7 @@ TEA6330T_TREBLE("Tone Control - Treble", 0) | |||
266 | 266 | ||
267 | static void snd_tea6330_free(snd_i2c_device_t *device) | 267 | static void snd_tea6330_free(snd_i2c_device_t *device) |
268 | { | 268 | { |
269 | tea6330t_t *tea = device->private_data; | 269 | kfree(device->private_data); |
270 | kfree(tea); | ||
271 | } | 270 | } |
272 | 271 | ||
273 | int snd_tea6330t_update_mixer(snd_card_t * card, | 272 | int snd_tea6330t_update_mixer(snd_card_t * card, |
diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index 3a3228b18726..148a856a43ad 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig | |||
@@ -179,6 +179,7 @@ config SND_INTERWAVE_STB | |||
179 | select SND_RAWMIDI | 179 | select SND_RAWMIDI |
180 | select SND_CS4231_LIB | 180 | select SND_CS4231_LIB |
181 | select SND_GUS_SYNTH | 181 | select SND_GUS_SYNTH |
182 | select ISAPNP | ||
182 | help | 183 | help |
183 | Say Y here to include support for AMD InterWave based | 184 | Say Y here to include support for AMD InterWave based |
184 | soundcards with a TEA6330T bass and treble regulator | 185 | soundcards with a TEA6330T bass and treble regulator |
diff --git a/sound/isa/ad1816a/ad1816a.c b/sound/isa/ad1816a/ad1816a.c index 9fa7a78da6c3..563296d02894 100644 --- a/sound/isa/ad1816a/ad1816a.c +++ b/sound/isa/ad1816a/ad1816a.c | |||
@@ -83,6 +83,8 @@ struct snd_card_ad1816a { | |||
83 | static struct pnp_card_device_id snd_ad1816a_pnpids[] = { | 83 | static struct pnp_card_device_id snd_ad1816a_pnpids[] = { |
84 | /* Analog Devices AD1815 */ | 84 | /* Analog Devices AD1815 */ |
85 | { .id = "ADS7150", .devs = { { .id = "ADS7150" }, { .id = "ADS7151" } } }, | 85 | { .id = "ADS7150", .devs = { { .id = "ADS7150" }, { .id = "ADS7151" } } }, |
86 | /* Analog Device AD1816? */ | ||
87 | { .id = "ADS7180", .devs = { { .id = "ADS7180" }, { .id = "ADS7181" } } }, | ||
86 | /* Analog Devices AD1816A - added by Kenneth Platz <kxp@atl.hp.com> */ | 88 | /* Analog Devices AD1816A - added by Kenneth Platz <kxp@atl.hp.com> */ |
87 | { .id = "ADS7181", .devs = { { .id = "ADS7180" }, { .id = "ADS7181" } } }, | 89 | { .id = "ADS7181", .devs = { { .id = "ADS7180" }, { .id = "ADS7181" } } }, |
88 | /* Analog Devices AD1816A - Aztech/Newcom SC-16 3D */ | 90 | /* Analog Devices AD1816A - Aztech/Newcom SC-16 3D */ |
diff --git a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c index e745a54e00a1..39f4eff44f5c 100644 --- a/sound/isa/cs423x/cs4236.c +++ b/sound/isa/cs423x/cs4236.c | |||
@@ -349,8 +349,7 @@ static int __devinit snd_card_cs4236_pnp(int dev, struct snd_card_cs4236 *acard, | |||
349 | pnp_init_resource_table(cfg); | 349 | pnp_init_resource_table(cfg); |
350 | if (mpu_port[dev] != SNDRV_AUTO_PORT) | 350 | if (mpu_port[dev] != SNDRV_AUTO_PORT) |
351 | pnp_resource_change(&cfg->port_resource[0], mpu_port[dev], 2); | 351 | pnp_resource_change(&cfg->port_resource[0], mpu_port[dev], 2); |
352 | if (mpu_irq[dev] != SNDRV_AUTO_IRQ && mpu_irq[dev] >= 0 && | 352 | if (mpu_irq[dev] != SNDRV_AUTO_IRQ && mpu_irq[dev] >= 0) |
353 | pnp_irq_valid(pdev, 0)) | ||
354 | pnp_resource_change(&cfg->irq_resource[0], mpu_irq[dev], 1); | 353 | pnp_resource_change(&cfg->irq_resource[0], mpu_irq[dev], 1); |
355 | err = pnp_manual_config_dev(pdev, cfg, 0); | 354 | err = pnp_manual_config_dev(pdev, cfg, 0); |
356 | if (err < 0) | 355 | if (err < 0) |
diff --git a/sound/isa/gus/gus_io.c b/sound/isa/gus/gus_io.c index f0570f2bf75f..337b0e2a8a36 100644 --- a/sound/isa/gus/gus_io.c +++ b/sound/isa/gus/gus_io.c | |||
@@ -244,6 +244,8 @@ unsigned short snd_gf1_i_look16(snd_gus_card_t * gus, unsigned char reg) | |||
244 | return res; | 244 | return res; |
245 | } | 245 | } |
246 | 246 | ||
247 | #if 0 | ||
248 | |||
247 | void snd_gf1_i_adlib_write(snd_gus_card_t * gus, | 249 | void snd_gf1_i_adlib_write(snd_gus_card_t * gus, |
248 | unsigned char reg, | 250 | unsigned char reg, |
249 | unsigned char data) | 251 | unsigned char data) |
@@ -265,6 +267,8 @@ void snd_gf1_i_write_addr(snd_gus_card_t * gus, unsigned char reg, | |||
265 | spin_unlock_irqrestore(&gus->reg_lock, flags); | 267 | spin_unlock_irqrestore(&gus->reg_lock, flags); |
266 | } | 268 | } |
267 | 269 | ||
270 | #endif /* 0 */ | ||
271 | |||
268 | unsigned int snd_gf1_i_read_addr(snd_gus_card_t * gus, | 272 | unsigned int snd_gf1_i_read_addr(snd_gus_card_t * gus, |
269 | unsigned char reg, short w_16bit) | 273 | unsigned char reg, short w_16bit) |
270 | { | 274 | { |
@@ -329,6 +333,8 @@ unsigned char snd_gf1_peek(snd_gus_card_t * gus, unsigned int addr) | |||
329 | return res; | 333 | return res; |
330 | } | 334 | } |
331 | 335 | ||
336 | #if 0 | ||
337 | |||
332 | void snd_gf1_pokew(snd_gus_card_t * gus, unsigned int addr, unsigned short data) | 338 | void snd_gf1_pokew(snd_gus_card_t * gus, unsigned int addr, unsigned short data) |
333 | { | 339 | { |
334 | unsigned long flags; | 340 | unsigned long flags; |
@@ -405,9 +411,7 @@ void snd_gf1_dram_setmem(snd_gus_card_t * gus, unsigned int addr, | |||
405 | spin_unlock_irqrestore(&gus->reg_lock, flags); | 411 | spin_unlock_irqrestore(&gus->reg_lock, flags); |
406 | } | 412 | } |
407 | 413 | ||
408 | /* | 414 | #endif /* 0 */ |
409 | |||
410 | */ | ||
411 | 415 | ||
412 | void snd_gf1_select_active_voices(snd_gus_card_t * gus) | 416 | void snd_gf1_select_active_voices(snd_gus_card_t * gus) |
413 | { | 417 | { |
@@ -469,6 +473,8 @@ void snd_gf1_print_voice_registers(snd_gus_card_t * gus) | |||
469 | printk(" -%i- GF1 pan = 0x%x\n", voice, snd_gf1_i_read8(gus, 0x0c)); | 473 | printk(" -%i- GF1 pan = 0x%x\n", voice, snd_gf1_i_read8(gus, 0x0c)); |
470 | } | 474 | } |
471 | 475 | ||
476 | #if 0 | ||
477 | |||
472 | void snd_gf1_print_global_registers(snd_gus_card_t * gus) | 478 | void snd_gf1_print_global_registers(snd_gus_card_t * gus) |
473 | { | 479 | { |
474 | unsigned char global_mode = 0x00; | 480 | unsigned char global_mode = 0x00; |
@@ -528,4 +534,6 @@ void snd_gf1_peek_print_block(snd_gus_card_t * gus, unsigned int addr, int count | |||
528 | } | 534 | } |
529 | } | 535 | } |
530 | 536 | ||
537 | #endif /* 0 */ | ||
538 | |||
531 | #endif | 539 | #endif |
diff --git a/sound/isa/gus/gus_main.c b/sound/isa/gus/gus_main.c index 73f81c14f768..94bbd344be5e 100644 --- a/sound/isa/gus/gus_main.c +++ b/sound/isa/gus/gus_main.c | |||
@@ -459,7 +459,6 @@ EXPORT_SYMBOL(snd_gf1_write16); | |||
459 | EXPORT_SYMBOL(snd_gf1_look16); | 459 | EXPORT_SYMBOL(snd_gf1_look16); |
460 | EXPORT_SYMBOL(snd_gf1_i_write8); | 460 | EXPORT_SYMBOL(snd_gf1_i_write8); |
461 | EXPORT_SYMBOL(snd_gf1_i_look8); | 461 | EXPORT_SYMBOL(snd_gf1_i_look8); |
462 | EXPORT_SYMBOL(snd_gf1_i_write16); | ||
463 | EXPORT_SYMBOL(snd_gf1_i_look16); | 462 | EXPORT_SYMBOL(snd_gf1_i_look16); |
464 | EXPORT_SYMBOL(snd_gf1_dram_addr); | 463 | EXPORT_SYMBOL(snd_gf1_dram_addr); |
465 | EXPORT_SYMBOL(snd_gf1_write_addr); | 464 | EXPORT_SYMBOL(snd_gf1_write_addr); |
@@ -470,8 +469,6 @@ EXPORT_SYMBOL(snd_gf1_alloc_voice); | |||
470 | EXPORT_SYMBOL(snd_gf1_free_voice); | 469 | EXPORT_SYMBOL(snd_gf1_free_voice); |
471 | EXPORT_SYMBOL(snd_gf1_ctrl_stop); | 470 | EXPORT_SYMBOL(snd_gf1_ctrl_stop); |
472 | EXPORT_SYMBOL(snd_gf1_stop_voice); | 471 | EXPORT_SYMBOL(snd_gf1_stop_voice); |
473 | EXPORT_SYMBOL(snd_gf1_start); | ||
474 | EXPORT_SYMBOL(snd_gf1_stop); | ||
475 | /* gus_mixer.c */ | 472 | /* gus_mixer.c */ |
476 | EXPORT_SYMBOL(snd_gf1_new_mixer); | 473 | EXPORT_SYMBOL(snd_gf1_new_mixer); |
477 | /* gus_pcm.c */ | 474 | /* gus_pcm.c */ |
diff --git a/sound/isa/gus/gus_mem.c b/sound/isa/gus/gus_mem.c index bfc2b91001d5..609838e8ef67 100644 --- a/sound/isa/gus/gus_mem.c +++ b/sound/isa/gus/gus_mem.c | |||
@@ -39,8 +39,8 @@ void snd_gf1_mem_lock(snd_gf1_mem_t * alloc, int xup) | |||
39 | } | 39 | } |
40 | } | 40 | } |
41 | 41 | ||
42 | snd_gf1_mem_block_t *snd_gf1_mem_xalloc(snd_gf1_mem_t * alloc, | 42 | static snd_gf1_mem_block_t *snd_gf1_mem_xalloc(snd_gf1_mem_t * alloc, |
43 | snd_gf1_mem_block_t * block) | 43 | snd_gf1_mem_block_t * block) |
44 | { | 44 | { |
45 | snd_gf1_mem_block_t *pblock, *nblock; | 45 | snd_gf1_mem_block_t *pblock, *nblock; |
46 | 46 | ||
@@ -105,8 +105,8 @@ int snd_gf1_mem_xfree(snd_gf1_mem_t * alloc, snd_gf1_mem_block_t * block) | |||
105 | return 0; | 105 | return 0; |
106 | } | 106 | } |
107 | 107 | ||
108 | snd_gf1_mem_block_t *snd_gf1_mem_look(snd_gf1_mem_t * alloc, | 108 | static snd_gf1_mem_block_t *snd_gf1_mem_look(snd_gf1_mem_t * alloc, |
109 | unsigned int address) | 109 | unsigned int address) |
110 | { | 110 | { |
111 | snd_gf1_mem_block_t *block; | 111 | snd_gf1_mem_block_t *block; |
112 | 112 | ||
@@ -118,8 +118,8 @@ snd_gf1_mem_block_t *snd_gf1_mem_look(snd_gf1_mem_t * alloc, | |||
118 | return NULL; | 118 | return NULL; |
119 | } | 119 | } |
120 | 120 | ||
121 | snd_gf1_mem_block_t *snd_gf1_mem_share(snd_gf1_mem_t * alloc, | 121 | static snd_gf1_mem_block_t *snd_gf1_mem_share(snd_gf1_mem_t * alloc, |
122 | unsigned int *share_id) | 122 | unsigned int *share_id) |
123 | { | 123 | { |
124 | snd_gf1_mem_block_t *block; | 124 | snd_gf1_mem_block_t *block; |
125 | 125 | ||
diff --git a/sound/isa/gus/gus_pcm.c b/sound/isa/gus/gus_pcm.c index 8995ad9c516d..b75066ab46fc 100644 --- a/sound/isa/gus/gus_pcm.c +++ b/sound/isa/gus/gus_pcm.c | |||
@@ -656,8 +656,7 @@ static snd_pcm_hardware_t snd_gf1_pcm_capture = | |||
656 | 656 | ||
657 | static void snd_gf1_pcm_playback_free(snd_pcm_runtime_t *runtime) | 657 | static void snd_gf1_pcm_playback_free(snd_pcm_runtime_t *runtime) |
658 | { | 658 | { |
659 | gus_pcm_private_t * pcmp = runtime->private_data; | 659 | kfree(runtime->private_data); |
660 | kfree(pcmp); | ||
661 | } | 660 | } |
662 | 661 | ||
663 | static int snd_gf1_pcm_playback_open(snd_pcm_substream_t *substream) | 662 | static int snd_gf1_pcm_playback_open(snd_pcm_substream_t *substream) |
diff --git a/sound/isa/gus/gus_reset.c b/sound/isa/gus/gus_reset.c index b4e66f6a10ae..ef687abc7070 100644 --- a/sound/isa/gus/gus_reset.c +++ b/sound/isa/gus/gus_reset.c | |||
@@ -161,7 +161,8 @@ void snd_gf1_stop_voice(snd_gus_card_t * gus, unsigned short voice) | |||
161 | #endif | 161 | #endif |
162 | } | 162 | } |
163 | 163 | ||
164 | void snd_gf1_clear_voices(snd_gus_card_t * gus, unsigned short v_min, unsigned short v_max) | 164 | static void snd_gf1_clear_voices(snd_gus_card_t * gus, unsigned short v_min, |
165 | unsigned short v_max) | ||
165 | { | 166 | { |
166 | unsigned long flags; | 167 | unsigned long flags; |
167 | unsigned int daddr; | 168 | unsigned int daddr; |
diff --git a/sound/isa/gus/gus_synth.c b/sound/isa/gus/gus_synth.c index 66552e6013a4..f51c386ee192 100644 --- a/sound/isa/gus/gus_synth.c +++ b/sound/isa/gus/gus_synth.c | |||
@@ -99,7 +99,8 @@ static void snd_gus_synth_free_private_instruments(snd_gus_port_t *p, int client | |||
99 | snd_seq_instr_list_free_cond(p->gus->gf1.ilist, &ifree, client, 0); | 99 | snd_seq_instr_list_free_cond(p->gus->gf1.ilist, &ifree, client, 0); |
100 | } | 100 | } |
101 | 101 | ||
102 | int snd_gus_synth_event_input(snd_seq_event_t *ev, int direct, void *private_data, int atomic, int hop) | 102 | static int snd_gus_synth_event_input(snd_seq_event_t *ev, int direct, |
103 | void *private_data, int atomic, int hop) | ||
103 | { | 104 | { |
104 | snd_gus_port_t * p = (snd_gus_port_t *) private_data; | 105 | snd_gus_port_t * p = (snd_gus_port_t *) private_data; |
105 | 106 | ||
diff --git a/sound/isa/gus/gus_tables.h b/sound/isa/gus/gus_tables.h index ed8e9d85ad31..4adf098d3269 100644 --- a/sound/isa/gus/gus_tables.h +++ b/sound/isa/gus/gus_tables.h | |||
@@ -23,6 +23,8 @@ | |||
23 | 23 | ||
24 | #ifdef __GUS_TABLES_ALLOC__ | 24 | #ifdef __GUS_TABLES_ALLOC__ |
25 | 25 | ||
26 | #if 0 | ||
27 | |||
26 | unsigned int snd_gf1_scale_table[SNDRV_GF1_SCALE_TABLE_SIZE] = | 28 | unsigned int snd_gf1_scale_table[SNDRV_GF1_SCALE_TABLE_SIZE] = |
27 | { | 29 | { |
28 | 8372, 8870, 9397, 9956, 10548, 11175, | 30 | 8372, 8870, 9397, 9956, 10548, 11175, |
@@ -49,6 +51,8 @@ unsigned int snd_gf1_scale_table[SNDRV_GF1_SCALE_TABLE_SIZE] = | |||
49 | 12123977, 12844906 | 51 | 12123977, 12844906 |
50 | }; | 52 | }; |
51 | 53 | ||
54 | #endif /* 0 */ | ||
55 | |||
52 | unsigned short snd_gf1_atten_table[SNDRV_GF1_ATTEN_TABLE_SIZE] = { | 56 | unsigned short snd_gf1_atten_table[SNDRV_GF1_ATTEN_TABLE_SIZE] = { |
53 | 4095 /* 0 */,1789 /* 1 */,1533 /* 2 */,1383 /* 3 */,1277 /* 4 */, | 57 | 4095 /* 0 */,1789 /* 1 */,1533 /* 2 */,1383 /* 3 */,1277 /* 4 */, |
54 | 1195 /* 5 */,1127 /* 6 */,1070 /* 7 */,1021 /* 8 */,978 /* 9 */, | 58 | 1195 /* 5 */,1127 /* 6 */,1070 /* 7 */,1021 /* 8 */,978 /* 9 */, |
diff --git a/sound/isa/gus/gus_volume.c b/sound/isa/gus/gus_volume.c index b72bcfb28617..3d36f6c8ee6a 100644 --- a/sound/isa/gus/gus_volume.c +++ b/sound/isa/gus/gus_volume.c | |||
@@ -55,6 +55,8 @@ unsigned short snd_gf1_lvol_to_gvol_raw(unsigned int vol) | |||
55 | return (e << 8) | m; | 55 | return (e << 8) | m; |
56 | } | 56 | } |
57 | 57 | ||
58 | #if 0 | ||
59 | |||
58 | unsigned int snd_gf1_gvol_to_lvol_raw(unsigned short gf1_vol) | 60 | unsigned int snd_gf1_gvol_to_lvol_raw(unsigned short gf1_vol) |
59 | { | 61 | { |
60 | unsigned int rvol; | 62 | unsigned int rvol; |
@@ -108,6 +110,8 @@ unsigned int snd_gf1_calc_ramp_rate(snd_gus_card_t * gus, | |||
108 | return (range << 6) | (increment & 0x3f); | 110 | return (range << 6) | (increment & 0x3f); |
109 | } | 111 | } |
110 | 112 | ||
113 | #endif /* 0 */ | ||
114 | |||
111 | unsigned short snd_gf1_translate_freq(snd_gus_card_t * gus, unsigned int freq16) | 115 | unsigned short snd_gf1_translate_freq(snd_gus_card_t * gus, unsigned int freq16) |
112 | { | 116 | { |
113 | freq16 >>= 3; | 117 | freq16 >>= 3; |
@@ -120,6 +124,8 @@ unsigned short snd_gf1_translate_freq(snd_gus_card_t * gus, unsigned int freq16) | |||
120 | return ((freq16 << 9) + (gus->gf1.playback_freq >> 1)) / gus->gf1.playback_freq; | 124 | return ((freq16 << 9) + (gus->gf1.playback_freq >> 1)) / gus->gf1.playback_freq; |
121 | } | 125 | } |
122 | 126 | ||
127 | #if 0 | ||
128 | |||
123 | short snd_gf1_compute_vibrato(short cents, unsigned short fc_register) | 129 | short snd_gf1_compute_vibrato(short cents, unsigned short fc_register) |
124 | { | 130 | { |
125 | static short vibrato_table[] = | 131 | static short vibrato_table[] = |
@@ -208,3 +214,5 @@ unsigned short snd_gf1_compute_freq(unsigned int freq, | |||
208 | } | 214 | } |
209 | return (unsigned short) fc; | 215 | return (unsigned short) fc; |
210 | } | 216 | } |
217 | |||
218 | #endif /* 0 */ | ||
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 428efdbd70a1..6d7a00f34d82 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig | |||
@@ -274,6 +274,19 @@ config SND_HDSP | |||
274 | To compile this driver as a module, choose M here: the module | 274 | To compile this driver as a module, choose M here: the module |
275 | will be called snd-hdsp. | 275 | will be called snd-hdsp. |
276 | 276 | ||
277 | config SND_HDSPM | ||
278 | tristate "RME Hammerfall DSP MADI" | ||
279 | depends on SND | ||
280 | select SND_HWDEP | ||
281 | select SND_RAWMIDI | ||
282 | select SND_PCM | ||
283 | help | ||
284 | Say Y here to include support for RME Hammerfall DSP MADI | ||
285 | soundcards. | ||
286 | |||
287 | To compile this driver as a module, choose M here: the module | ||
288 | will be called snd-hdspm. | ||
289 | |||
277 | config SND_TRIDENT | 290 | config SND_TRIDENT |
278 | tristate "Trident 4D-Wave DX/NX; SiS 7018" | 291 | tristate "Trident 4D-Wave DX/NX; SiS 7018" |
279 | depends on SND | 292 | depends on SND |
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 0b024ec1f709..a4b72cd2eea0 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c | |||
@@ -120,6 +120,7 @@ static const ac97_codec_id_t snd_ac97_codec_ids[] = { | |||
120 | { 0x414c4770, 0xfffffff0, "ALC203", NULL, NULL }, | 120 | { 0x414c4770, 0xfffffff0, "ALC203", NULL, NULL }, |
121 | { 0x434d4941, 0xffffffff, "CMI9738", patch_cm9738, NULL }, | 121 | { 0x434d4941, 0xffffffff, "CMI9738", patch_cm9738, NULL }, |
122 | { 0x434d4961, 0xffffffff, "CMI9739", patch_cm9739, NULL }, | 122 | { 0x434d4961, 0xffffffff, "CMI9739", patch_cm9739, NULL }, |
123 | { 0x434d4969, 0xffffffff, "CMI9780", patch_cm9780, NULL }, | ||
123 | { 0x434d4978, 0xffffffff, "CMI9761", patch_cm9761, NULL }, | 124 | { 0x434d4978, 0xffffffff, "CMI9761", patch_cm9761, NULL }, |
124 | { 0x434d4982, 0xffffffff, "CMI9761", patch_cm9761, NULL }, | 125 | { 0x434d4982, 0xffffffff, "CMI9761", patch_cm9761, NULL }, |
125 | { 0x434d4983, 0xffffffff, "CMI9761", patch_cm9761, NULL }, | 126 | { 0x434d4983, 0xffffffff, "CMI9761", patch_cm9761, NULL }, |
@@ -149,7 +150,7 @@ static const ac97_codec_id_t snd_ac97_codec_ids[] = { | |||
149 | { 0x4e534331, 0xffffffff, "LM4549", NULL, NULL }, | 150 | { 0x4e534331, 0xffffffff, "LM4549", NULL, NULL }, |
150 | { 0x4e534350, 0xffffffff, "LM4550", NULL, NULL }, | 151 | { 0x4e534350, 0xffffffff, "LM4550", NULL, NULL }, |
151 | { 0x50534304, 0xffffffff, "UCB1400", NULL, NULL }, | 152 | { 0x50534304, 0xffffffff, "UCB1400", NULL, NULL }, |
152 | { 0x53494c20, 0xffffffe0, "Si3036,8", NULL, mpatch_si3036 }, | 153 | { 0x53494c20, 0xffffffe0, "Si3036,8", mpatch_si3036, mpatch_si3036, AC97_MODEM_PATCH }, |
153 | { 0x54524102, 0xffffffff, "TR28022", NULL, NULL }, | 154 | { 0x54524102, 0xffffffff, "TR28022", NULL, NULL }, |
154 | { 0x54524106, 0xffffffff, "TR28026", NULL, NULL }, | 155 | { 0x54524106, 0xffffffff, "TR28026", NULL, NULL }, |
155 | { 0x54524108, 0xffffffff, "TR28028", patch_tritech_tr28028, NULL }, // added by xin jin [07/09/99] | 156 | { 0x54524108, 0xffffffff, "TR28028", patch_tritech_tr28028, NULL }, // added by xin jin [07/09/99] |
@@ -462,12 +463,14 @@ int snd_ac97_get_enum_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * u | |||
462 | { | 463 | { |
463 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | 464 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); |
464 | struct ac97_enum *e = (struct ac97_enum *)kcontrol->private_value; | 465 | struct ac97_enum *e = (struct ac97_enum *)kcontrol->private_value; |
465 | unsigned short val; | 466 | unsigned short val, bitmask; |
466 | 467 | ||
468 | for (bitmask = 1; bitmask < e->mask; bitmask <<= 1) | ||
469 | ; | ||
467 | val = snd_ac97_read_cache(ac97, e->reg); | 470 | val = snd_ac97_read_cache(ac97, e->reg); |
468 | ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (e->mask - 1); | 471 | ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (bitmask - 1); |
469 | if (e->shift_l != e->shift_r) | 472 | if (e->shift_l != e->shift_r) |
470 | ucontrol->value.enumerated.item[1] = (val >> e->shift_r) & (e->mask - 1); | 473 | ucontrol->value.enumerated.item[1] = (val >> e->shift_r) & (bitmask - 1); |
471 | 474 | ||
472 | return 0; | 475 | return 0; |
473 | } | 476 | } |
@@ -477,17 +480,19 @@ int snd_ac97_put_enum_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * u | |||
477 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | 480 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); |
478 | struct ac97_enum *e = (struct ac97_enum *)kcontrol->private_value; | 481 | struct ac97_enum *e = (struct ac97_enum *)kcontrol->private_value; |
479 | unsigned short val; | 482 | unsigned short val; |
480 | unsigned short mask; | 483 | unsigned short mask, bitmask; |
481 | 484 | ||
485 | for (bitmask = 1; bitmask < e->mask; bitmask <<= 1) | ||
486 | ; | ||
482 | if (ucontrol->value.enumerated.item[0] > e->mask - 1) | 487 | if (ucontrol->value.enumerated.item[0] > e->mask - 1) |
483 | return -EINVAL; | 488 | return -EINVAL; |
484 | val = ucontrol->value.enumerated.item[0] << e->shift_l; | 489 | val = ucontrol->value.enumerated.item[0] << e->shift_l; |
485 | mask = (e->mask - 1) << e->shift_l; | 490 | mask = (bitmask - 1) << e->shift_l; |
486 | if (e->shift_l != e->shift_r) { | 491 | if (e->shift_l != e->shift_r) { |
487 | if (ucontrol->value.enumerated.item[1] > e->mask - 1) | 492 | if (ucontrol->value.enumerated.item[1] > e->mask - 1) |
488 | return -EINVAL; | 493 | return -EINVAL; |
489 | val |= ucontrol->value.enumerated.item[1] << e->shift_r; | 494 | val |= ucontrol->value.enumerated.item[1] << e->shift_r; |
490 | mask |= (e->mask - 1) << e->shift_r; | 495 | mask |= (bitmask - 1) << e->shift_r; |
491 | } | 496 | } |
492 | return snd_ac97_update_bits(ac97, e->reg, mask, val); | 497 | return snd_ac97_update_bits(ac97, e->reg, mask, val); |
493 | } | 498 | } |
@@ -658,14 +663,14 @@ AC97_SINGLE("LFE Playback Switch", AC97_CENTER_LFE_MASTER, 15, 1, 1), | |||
658 | AC97_SINGLE("LFE Playback Volume", AC97_CENTER_LFE_MASTER, 8, 31, 1) | 663 | AC97_SINGLE("LFE Playback Volume", AC97_CENTER_LFE_MASTER, 8, 31, 1) |
659 | }; | 664 | }; |
660 | 665 | ||
661 | static const snd_kcontrol_new_t snd_ac97_controls_surround[2] = { | ||
662 | AC97_DOUBLE("Surround Playback Switch", AC97_SURROUND_MASTER, 15, 7, 1, 1), | ||
663 | AC97_DOUBLE("Surround Playback Volume", AC97_SURROUND_MASTER, 8, 0, 31, 1), | ||
664 | }; | ||
665 | |||
666 | static const snd_kcontrol_new_t snd_ac97_control_eapd = | 666 | static const snd_kcontrol_new_t snd_ac97_control_eapd = |
667 | AC97_SINGLE("External Amplifier", AC97_POWERDOWN, 15, 1, 1); | 667 | AC97_SINGLE("External Amplifier", AC97_POWERDOWN, 15, 1, 1); |
668 | 668 | ||
669 | static const snd_kcontrol_new_t snd_ac97_controls_modem_switches[2] = { | ||
670 | AC97_SINGLE("Off-hook Switch", AC97_GPIO_STATUS, 0, 1, 0), | ||
671 | AC97_SINGLE("Caller ID Switch", AC97_GPIO_STATUS, 2, 1, 0) | ||
672 | }; | ||
673 | |||
669 | /* change the existing EAPD control as inverted */ | 674 | /* change the existing EAPD control as inverted */ |
670 | static void set_inv_eapd(ac97_t *ac97, snd_kcontrol_t *kctl) | 675 | static void set_inv_eapd(ac97_t *ac97, snd_kcontrol_t *kctl) |
671 | { | 676 | { |
@@ -1072,9 +1077,9 @@ static void check_volume_resolution(ac97_t *ac97, int reg, unsigned char *lo_max | |||
1072 | unsigned short val; | 1077 | unsigned short val; |
1073 | snd_ac97_write(ac97, reg, 0x8080 | cbit[i] | (cbit[i] << 8)); | 1078 | snd_ac97_write(ac97, reg, 0x8080 | cbit[i] | (cbit[i] << 8)); |
1074 | val = snd_ac97_read(ac97, reg); | 1079 | val = snd_ac97_read(ac97, reg); |
1075 | if (! *lo_max && (val & cbit[i])) | 1080 | if (! *lo_max && (val & 0x7f) == cbit[i]) |
1076 | *lo_max = max[i]; | 1081 | *lo_max = max[i]; |
1077 | if (! *hi_max && (val & (cbit[i] << 8))) | 1082 | if (! *hi_max && ((val >> 8) & 0x7f) == cbit[i]) |
1078 | *hi_max = max[i]; | 1083 | *hi_max = max[i]; |
1079 | if (*lo_max && *hi_max) | 1084 | if (*lo_max && *hi_max) |
1080 | break; | 1085 | break; |
@@ -1526,13 +1531,25 @@ static int snd_ac97_mixer_build(ac97_t * ac97) | |||
1526 | 1531 | ||
1527 | static int snd_ac97_modem_build(snd_card_t * card, ac97_t * ac97) | 1532 | static int snd_ac97_modem_build(snd_card_t * card, ac97_t * ac97) |
1528 | { | 1533 | { |
1529 | /* TODO */ | 1534 | int err, idx; |
1535 | |||
1530 | //printk("AC97_GPIO_CFG = %x\n",snd_ac97_read(ac97,AC97_GPIO_CFG)); | 1536 | //printk("AC97_GPIO_CFG = %x\n",snd_ac97_read(ac97,AC97_GPIO_CFG)); |
1531 | snd_ac97_write(ac97, AC97_GPIO_CFG, 0xffff & ~(AC97_GPIO_LINE1_OH)); | 1537 | snd_ac97_write(ac97, AC97_GPIO_CFG, 0xffff & ~(AC97_GPIO_LINE1_OH)); |
1532 | snd_ac97_write(ac97, AC97_GPIO_POLARITY, 0xffff & ~(AC97_GPIO_LINE1_OH)); | 1538 | snd_ac97_write(ac97, AC97_GPIO_POLARITY, 0xffff & ~(AC97_GPIO_LINE1_OH)); |
1533 | snd_ac97_write(ac97, AC97_GPIO_STICKY, 0xffff); | 1539 | snd_ac97_write(ac97, AC97_GPIO_STICKY, 0xffff); |
1534 | snd_ac97_write(ac97, AC97_GPIO_WAKEUP, 0x0); | 1540 | snd_ac97_write(ac97, AC97_GPIO_WAKEUP, 0x0); |
1535 | snd_ac97_write(ac97, AC97_MISC_AFE, 0x0); | 1541 | snd_ac97_write(ac97, AC97_MISC_AFE, 0x0); |
1542 | |||
1543 | /* build modem switches */ | ||
1544 | for (idx = 0; idx < ARRAY_SIZE(snd_ac97_controls_modem_switches); idx++) | ||
1545 | if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_modem_switches[idx], ac97))) < 0) | ||
1546 | return err; | ||
1547 | |||
1548 | /* build chip specific controls */ | ||
1549 | if (ac97->build_ops->build_specific) | ||
1550 | if ((err = ac97->build_ops->build_specific(ac97)) < 0) | ||
1551 | return err; | ||
1552 | |||
1536 | return 0; | 1553 | return 0; |
1537 | } | 1554 | } |
1538 | 1555 | ||
@@ -1872,7 +1889,11 @@ int snd_ac97_mixer(ac97_bus_t *bus, ac97_template_t *template, ac97_t **rac97) | |||
1872 | goto __access_ok; | 1889 | goto __access_ok; |
1873 | } | 1890 | } |
1874 | 1891 | ||
1875 | snd_ac97_write(ac97, AC97_RESET, 0); /* reset to defaults */ | 1892 | /* reset to defaults */ |
1893 | if (!(ac97->scaps & AC97_SCAP_SKIP_AUDIO)) | ||
1894 | snd_ac97_write(ac97, AC97_RESET, 0); | ||
1895 | if (!(ac97->scaps & AC97_SCAP_SKIP_MODEM)) | ||
1896 | snd_ac97_write(ac97, AC97_EXTENDED_MID, 0); | ||
1876 | if (bus->ops->wait) | 1897 | if (bus->ops->wait) |
1877 | bus->ops->wait(ac97); | 1898 | bus->ops->wait(ac97); |
1878 | else { | 1899 | else { |
@@ -1964,21 +1985,21 @@ int snd_ac97_mixer(ac97_bus_t *bus, ac97_template_t *template, ac97_t **rac97) | |||
1964 | /* note: it's important to set the rate at first */ | 1985 | /* note: it's important to set the rate at first */ |
1965 | tmp = AC97_MEA_GPIO; | 1986 | tmp = AC97_MEA_GPIO; |
1966 | if (ac97->ext_mid & AC97_MEI_LINE1) { | 1987 | if (ac97->ext_mid & AC97_MEI_LINE1) { |
1967 | snd_ac97_write_cache(ac97, AC97_LINE1_RATE, 12000); | 1988 | snd_ac97_write_cache(ac97, AC97_LINE1_RATE, 8000); |
1968 | tmp |= AC97_MEA_ADC1 | AC97_MEA_DAC1; | 1989 | tmp |= AC97_MEA_ADC1 | AC97_MEA_DAC1; |
1969 | } | 1990 | } |
1970 | if (ac97->ext_mid & AC97_MEI_LINE2) { | 1991 | if (ac97->ext_mid & AC97_MEI_LINE2) { |
1971 | snd_ac97_write_cache(ac97, AC97_LINE2_RATE, 12000); | 1992 | snd_ac97_write_cache(ac97, AC97_LINE2_RATE, 8000); |
1972 | tmp |= AC97_MEA_ADC2 | AC97_MEA_DAC2; | 1993 | tmp |= AC97_MEA_ADC2 | AC97_MEA_DAC2; |
1973 | } | 1994 | } |
1974 | if (ac97->ext_mid & AC97_MEI_HANDSET) { | 1995 | if (ac97->ext_mid & AC97_MEI_HANDSET) { |
1975 | snd_ac97_write_cache(ac97, AC97_HANDSET_RATE, 12000); | 1996 | snd_ac97_write_cache(ac97, AC97_HANDSET_RATE, 8000); |
1976 | tmp |= AC97_MEA_HADC | AC97_MEA_HDAC; | 1997 | tmp |= AC97_MEA_HADC | AC97_MEA_HDAC; |
1977 | } | 1998 | } |
1978 | snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0xff00 & ~(tmp << 8)); | 1999 | snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0); |
1979 | udelay(100); | 2000 | udelay(100); |
1980 | /* nothing should be in powerdown mode */ | 2001 | /* nothing should be in powerdown mode */ |
1981 | snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0xff00 & ~(tmp << 8)); | 2002 | snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0); |
1982 | end_time = jiffies + (HZ / 10); | 2003 | end_time = jiffies + (HZ / 10); |
1983 | do { | 2004 | do { |
1984 | if ((snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS) & tmp) == tmp) | 2005 | if ((snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS) & tmp) == tmp) |
@@ -2521,11 +2542,11 @@ int snd_ac97_tune_hardware(ac97_t *ac97, struct ac97_quirk *quirk, const char *o | |||
2521 | return result; | 2542 | return result; |
2522 | } | 2543 | } |
2523 | 2544 | ||
2524 | for (; quirk->vendor; quirk++) { | 2545 | for (; quirk->subvendor; quirk++) { |
2525 | if (quirk->vendor != ac97->subsystem_vendor) | 2546 | if (quirk->subvendor != ac97->subsystem_vendor) |
2526 | continue; | 2547 | continue; |
2527 | if ((! quirk->mask && quirk->device == ac97->subsystem_device) || | 2548 | if ((! quirk->mask && quirk->subdevice == ac97->subsystem_device) || |
2528 | quirk->device == (quirk->mask & ac97->subsystem_device)) { | 2549 | quirk->subdevice == (quirk->mask & ac97->subsystem_device)) { |
2529 | if (quirk->codec_id && quirk->codec_id != ac97->id) | 2550 | if (quirk->codec_id && quirk->codec_id != ac97->id) |
2530 | continue; | 2551 | continue; |
2531 | snd_printdd("ac97 quirk for %s (%04x:%04x)\n", quirk->name, ac97->subsystem_vendor, ac97->subsystem_device); | 2552 | snd_printdd("ac97 quirk for %s (%04x:%04x)\n", quirk->name, ac97->subsystem_vendor, ac97->subsystem_device); |
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 13c34a5d8206..a15eb8522b7c 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c | |||
@@ -64,6 +64,116 @@ static int ac97_update_bits_page(ac97_t *ac97, unsigned short reg, unsigned shor | |||
64 | return ret; | 64 | return ret; |
65 | } | 65 | } |
66 | 66 | ||
67 | /* | ||
68 | * shared line-in/mic controls | ||
69 | */ | ||
70 | static int ac97_enum_text_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo, | ||
71 | const char **texts, unsigned int nums) | ||
72 | { | ||
73 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
74 | uinfo->count = 1; | ||
75 | uinfo->value.enumerated.items = nums; | ||
76 | if (uinfo->value.enumerated.item > nums - 1) | ||
77 | uinfo->value.enumerated.item = nums - 1; | ||
78 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | static int ac97_surround_jack_mode_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) | ||
83 | { | ||
84 | static const char *texts[] = { "Shared", "Independent" }; | ||
85 | return ac97_enum_text_info(kcontrol, uinfo, texts, 2); | ||
86 | } | ||
87 | |||
88 | static int ac97_surround_jack_mode_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
89 | { | ||
90 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | ||
91 | |||
92 | ucontrol->value.enumerated.item[0] = ac97->indep_surround; | ||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | static int ac97_surround_jack_mode_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
97 | { | ||
98 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | ||
99 | unsigned char indep = !!ucontrol->value.enumerated.item[0]; | ||
100 | |||
101 | if (indep != ac97->indep_surround) { | ||
102 | ac97->indep_surround = indep; | ||
103 | if (ac97->build_ops->update_jacks) | ||
104 | ac97->build_ops->update_jacks(ac97); | ||
105 | return 1; | ||
106 | } | ||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | static int ac97_channel_mode_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) | ||
111 | { | ||
112 | static const char *texts[] = { "2ch", "4ch", "6ch" }; | ||
113 | if (kcontrol->private_value) | ||
114 | return ac97_enum_text_info(kcontrol, uinfo, texts, 2); /* 4ch only */ | ||
115 | return ac97_enum_text_info(kcontrol, uinfo, texts, 3); | ||
116 | } | ||
117 | |||
118 | static int ac97_channel_mode_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
119 | { | ||
120 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | ||
121 | |||
122 | ucontrol->value.enumerated.item[0] = ac97->channel_mode; | ||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | static int ac97_channel_mode_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
127 | { | ||
128 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | ||
129 | unsigned char mode = ucontrol->value.enumerated.item[0]; | ||
130 | |||
131 | if (mode != ac97->channel_mode) { | ||
132 | ac97->channel_mode = mode; | ||
133 | if (ac97->build_ops->update_jacks) | ||
134 | ac97->build_ops->update_jacks(ac97); | ||
135 | return 1; | ||
136 | } | ||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | #define AC97_SURROUND_JACK_MODE_CTL \ | ||
141 | { \ | ||
142 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
143 | .name = "Surround Jack Mode", \ | ||
144 | .info = ac97_surround_jack_mode_info, \ | ||
145 | .get = ac97_surround_jack_mode_get, \ | ||
146 | .put = ac97_surround_jack_mode_put, \ | ||
147 | } | ||
148 | #define AC97_CHANNEL_MODE_CTL \ | ||
149 | { \ | ||
150 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
151 | .name = "Channel Mode", \ | ||
152 | .info = ac97_channel_mode_info, \ | ||
153 | .get = ac97_channel_mode_get, \ | ||
154 | .put = ac97_channel_mode_put, \ | ||
155 | } | ||
156 | #define AC97_CHANNEL_MODE_4CH_CTL \ | ||
157 | { \ | ||
158 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
159 | .name = "Channel Mode", \ | ||
160 | .info = ac97_channel_mode_info, \ | ||
161 | .get = ac97_channel_mode_get, \ | ||
162 | .put = ac97_channel_mode_put, \ | ||
163 | .private_value = 1, \ | ||
164 | } | ||
165 | |||
166 | static inline int is_shared_linein(ac97_t *ac97) | ||
167 | { | ||
168 | return ! ac97->indep_surround && ac97->channel_mode >= 1; | ||
169 | } | ||
170 | |||
171 | static inline int is_shared_micin(ac97_t *ac97) | ||
172 | { | ||
173 | return ! ac97->indep_surround && ac97->channel_mode >= 2; | ||
174 | } | ||
175 | |||
176 | |||
67 | /* The following snd_ac97_ymf753_... items added by David Shust (dshust@shustring.com) */ | 177 | /* The following snd_ac97_ymf753_... items added by David Shust (dshust@shustring.com) */ |
68 | 178 | ||
69 | /* It is possible to indicate to the Yamaha YMF753 the type of speakers being used. */ | 179 | /* It is possible to indicate to the Yamaha YMF753 the type of speakers being used. */ |
@@ -1390,6 +1500,16 @@ static int snd_ac97_ad1888_downmix_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_va | |||
1390 | AC97_AD198X_DMIX0 | AC97_AD198X_DMIX1, val); | 1500 | AC97_AD198X_DMIX0 | AC97_AD198X_DMIX1, val); |
1391 | } | 1501 | } |
1392 | 1502 | ||
1503 | static void ad1888_update_jacks(ac97_t *ac97) | ||
1504 | { | ||
1505 | /* shared Line-In */ | ||
1506 | snd_ac97_update_bits(ac97, AC97_AD_MISC, 1 << 12, | ||
1507 | is_shared_linein(ac97) ? 0 : 1 << 12); | ||
1508 | /* shared Mic */ | ||
1509 | snd_ac97_update_bits(ac97, AC97_AD_MISC, 1 << 11, | ||
1510 | is_shared_micin(ac97) ? 0 : 1 << 11); | ||
1511 | } | ||
1512 | |||
1393 | static const snd_kcontrol_new_t snd_ac97_ad1888_controls[] = { | 1513 | static const snd_kcontrol_new_t snd_ac97_ad1888_controls[] = { |
1394 | { | 1514 | { |
1395 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1515 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1406,8 +1526,8 @@ static const snd_kcontrol_new_t snd_ac97_ad1888_controls[] = { | |||
1406 | .get = snd_ac97_ad1888_downmix_get, | 1526 | .get = snd_ac97_ad1888_downmix_get, |
1407 | .put = snd_ac97_ad1888_downmix_put | 1527 | .put = snd_ac97_ad1888_downmix_put |
1408 | }, | 1528 | }, |
1409 | AC97_SINGLE("Surround Jack as Input", AC97_AD_MISC, 12, 1, 0), | 1529 | AC97_SURROUND_JACK_MODE_CTL, |
1410 | AC97_SINGLE("Center/LFE Jack as Input", AC97_AD_MISC, 11, 1, 0), | 1530 | AC97_CHANNEL_MODE_CTL, |
1411 | }; | 1531 | }; |
1412 | 1532 | ||
1413 | static int patch_ad1888_specific(ac97_t *ac97) | 1533 | static int patch_ad1888_specific(ac97_t *ac97) |
@@ -1422,8 +1542,9 @@ static struct snd_ac97_build_ops patch_ad1888_build_ops = { | |||
1422 | .build_post_spdif = patch_ad198x_post_spdif, | 1542 | .build_post_spdif = patch_ad198x_post_spdif, |
1423 | .build_specific = patch_ad1888_specific, | 1543 | .build_specific = patch_ad1888_specific, |
1424 | #ifdef CONFIG_PM | 1544 | #ifdef CONFIG_PM |
1425 | .resume = ad18xx_resume | 1545 | .resume = ad18xx_resume, |
1426 | #endif | 1546 | #endif |
1547 | .update_jacks = ad1888_update_jacks, | ||
1427 | }; | 1548 | }; |
1428 | 1549 | ||
1429 | int patch_ad1888(ac97_t * ac97) | 1550 | int patch_ad1888(ac97_t * ac97) |
@@ -1459,8 +1580,9 @@ static struct snd_ac97_build_ops patch_ad1980_build_ops = { | |||
1459 | .build_post_spdif = patch_ad198x_post_spdif, | 1580 | .build_post_spdif = patch_ad198x_post_spdif, |
1460 | .build_specific = patch_ad1980_specific, | 1581 | .build_specific = patch_ad1980_specific, |
1461 | #ifdef CONFIG_PM | 1582 | #ifdef CONFIG_PM |
1462 | .resume = ad18xx_resume | 1583 | .resume = ad18xx_resume, |
1463 | #endif | 1584 | #endif |
1585 | .update_jacks = ad1888_update_jacks, | ||
1464 | }; | 1586 | }; |
1465 | 1587 | ||
1466 | int patch_ad1980(ac97_t * ac97) | 1588 | int patch_ad1980(ac97_t * ac97) |
@@ -1471,10 +1593,21 @@ int patch_ad1980(ac97_t * ac97) | |||
1471 | } | 1593 | } |
1472 | 1594 | ||
1473 | static const snd_kcontrol_new_t snd_ac97_ad1985_controls[] = { | 1595 | static const snd_kcontrol_new_t snd_ac97_ad1985_controls[] = { |
1474 | AC97_SINGLE("Center/LFE Jack as Mic", AC97_AD_SERIAL_CFG, 9, 1, 0), | ||
1475 | AC97_SINGLE("Exchange Center/LFE", AC97_AD_SERIAL_CFG, 3, 1, 0) | 1596 | AC97_SINGLE("Exchange Center/LFE", AC97_AD_SERIAL_CFG, 3, 1, 0) |
1476 | }; | 1597 | }; |
1477 | 1598 | ||
1599 | static void ad1985_update_jacks(ac97_t *ac97) | ||
1600 | { | ||
1601 | /* shared Line-In */ | ||
1602 | snd_ac97_update_bits(ac97, AC97_AD_MISC, 1 << 12, | ||
1603 | is_shared_linein(ac97) ? 0 : 1 << 12); | ||
1604 | /* shared Mic */ | ||
1605 | snd_ac97_update_bits(ac97, AC97_AD_MISC, 1 << 11, | ||
1606 | is_shared_micin(ac97) ? 0 : 1 << 11); | ||
1607 | snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 1 << 9, | ||
1608 | is_shared_micin(ac97) ? 0 : 1 << 9); | ||
1609 | } | ||
1610 | |||
1478 | static int patch_ad1985_specific(ac97_t *ac97) | 1611 | static int patch_ad1985_specific(ac97_t *ac97) |
1479 | { | 1612 | { |
1480 | int err; | 1613 | int err; |
@@ -1488,8 +1621,9 @@ static struct snd_ac97_build_ops patch_ad1985_build_ops = { | |||
1488 | .build_post_spdif = patch_ad198x_post_spdif, | 1621 | .build_post_spdif = patch_ad198x_post_spdif, |
1489 | .build_specific = patch_ad1985_specific, | 1622 | .build_specific = patch_ad1985_specific, |
1490 | #ifdef CONFIG_PM | 1623 | #ifdef CONFIG_PM |
1491 | .resume = ad18xx_resume | 1624 | .resume = ad18xx_resume, |
1492 | #endif | 1625 | #endif |
1626 | .update_jacks = ad1985_update_jacks, | ||
1493 | }; | 1627 | }; |
1494 | 1628 | ||
1495 | int patch_ad1985(ac97_t * ac97) | 1629 | int patch_ad1985(ac97_t * ac97) |
@@ -1521,31 +1655,25 @@ int patch_ad1985(ac97_t * ac97) | |||
1521 | /* | 1655 | /* |
1522 | * realtek ALC65x/850 codecs | 1656 | * realtek ALC65x/850 codecs |
1523 | */ | 1657 | */ |
1524 | static int snd_ac97_alc650_mic_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) | 1658 | static void alc650_update_jacks(ac97_t *ac97) |
1525 | { | ||
1526 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | ||
1527 | ucontrol->value.integer.value[0] = (ac97->regs[AC97_ALC650_MULTICH] >> 10) & 1; | ||
1528 | return 0; | ||
1529 | } | ||
1530 | |||
1531 | static int snd_ac97_alc650_mic_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) | ||
1532 | { | 1659 | { |
1533 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | 1660 | int shared; |
1534 | int change, val; | 1661 | |
1535 | val = !!(snd_ac97_read(ac97, AC97_ALC650_MULTICH) & (1 << 10)); | 1662 | /* shared Line-In */ |
1536 | change = (ucontrol->value.integer.value[0] != val); | 1663 | shared = is_shared_linein(ac97); |
1537 | if (change) { | 1664 | snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 9, |
1538 | /* disable/enable vref */ | 1665 | shared ? (1 << 9) : 0); |
1539 | snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12, | 1666 | /* update shared Mic */ |
1540 | ucontrol->value.integer.value[0] ? (1 << 12) : 0); | 1667 | shared = is_shared_micin(ac97); |
1541 | /* turn on/off center-on-mic */ | 1668 | /* disable/enable vref */ |
1542 | snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 10, | 1669 | snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12, |
1543 | ucontrol->value.integer.value[0] ? (1 << 10) : 0); | 1670 | shared ? (1 << 12) : 0); |
1544 | /* GPIO0 high for mic */ | 1671 | /* turn on/off center-on-mic */ |
1545 | snd_ac97_update_bits(ac97, AC97_ALC650_GPIO_STATUS, 0x100, | 1672 | snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 10, |
1546 | ucontrol->value.integer.value[0] ? 0 : 0x100); | 1673 | shared ? (1 << 10) : 0); |
1547 | } | 1674 | /* GPIO0 high for mic */ |
1548 | return change; | 1675 | snd_ac97_update_bits(ac97, AC97_ALC650_GPIO_STATUS, 0x100, |
1676 | shared ? 0 : 0x100); | ||
1549 | } | 1677 | } |
1550 | 1678 | ||
1551 | static const snd_kcontrol_new_t snd_ac97_controls_alc650[] = { | 1679 | static const snd_kcontrol_new_t snd_ac97_controls_alc650[] = { |
@@ -1558,8 +1686,8 @@ static const snd_kcontrol_new_t snd_ac97_controls_alc650[] = { | |||
1558 | /* 6: Independent Master Volume Right */ | 1686 | /* 6: Independent Master Volume Right */ |
1559 | /* 7: Independent Master Volume Left */ | 1687 | /* 7: Independent Master Volume Left */ |
1560 | /* 8: reserved */ | 1688 | /* 8: reserved */ |
1561 | AC97_SINGLE("Line-In As Surround", AC97_ALC650_MULTICH, 9, 1, 0), | 1689 | /* 9: Line-In/Surround share */ |
1562 | /* 10: mic, see below */ | 1690 | /* 10: Mic/CLFE share */ |
1563 | /* 11-13: in IEC958 controls */ | 1691 | /* 11-13: in IEC958 controls */ |
1564 | AC97_SINGLE("Swap Surround Slot", AC97_ALC650_MULTICH, 14, 1, 0), | 1692 | AC97_SINGLE("Swap Surround Slot", AC97_ALC650_MULTICH, 14, 1, 0), |
1565 | #if 0 /* always set in patch_alc650 */ | 1693 | #if 0 /* always set in patch_alc650 */ |
@@ -1570,14 +1698,8 @@ static const snd_kcontrol_new_t snd_ac97_controls_alc650[] = { | |||
1570 | AC97_SINGLE("Center/LFE DAC Switch", AC97_ALC650_LFE_DAC_VOL, 15, 1, 1), | 1698 | AC97_SINGLE("Center/LFE DAC Switch", AC97_ALC650_LFE_DAC_VOL, 15, 1, 1), |
1571 | AC97_DOUBLE("Center/LFE DAC Volume", AC97_ALC650_LFE_DAC_VOL, 8, 0, 31, 1), | 1699 | AC97_DOUBLE("Center/LFE DAC Volume", AC97_ALC650_LFE_DAC_VOL, 8, 0, 31, 1), |
1572 | #endif | 1700 | #endif |
1573 | { | 1701 | AC97_SURROUND_JACK_MODE_CTL, |
1574 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1702 | AC97_CHANNEL_MODE_CTL, |
1575 | .name = "Mic As Center/LFE", | ||
1576 | .info = snd_ac97_info_volsw, | ||
1577 | .get = snd_ac97_alc650_mic_get, | ||
1578 | .put = snd_ac97_alc650_mic_put, | ||
1579 | .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */ | ||
1580 | }, | ||
1581 | }; | 1703 | }; |
1582 | 1704 | ||
1583 | static const snd_kcontrol_new_t snd_ac97_spdif_controls_alc650[] = { | 1705 | static const snd_kcontrol_new_t snd_ac97_spdif_controls_alc650[] = { |
@@ -1601,7 +1723,8 @@ static int patch_alc650_specific(ac97_t * ac97) | |||
1601 | } | 1723 | } |
1602 | 1724 | ||
1603 | static struct snd_ac97_build_ops patch_alc650_ops = { | 1725 | static struct snd_ac97_build_ops patch_alc650_ops = { |
1604 | .build_specific = patch_alc650_specific | 1726 | .build_specific = patch_alc650_specific, |
1727 | .update_jacks = alc650_update_jacks | ||
1605 | }; | 1728 | }; |
1606 | 1729 | ||
1607 | int patch_alc650(ac97_t * ac97) | 1730 | int patch_alc650(ac97_t * ac97) |
@@ -1659,37 +1782,27 @@ int patch_alc650(ac97_t * ac97) | |||
1659 | return 0; | 1782 | return 0; |
1660 | } | 1783 | } |
1661 | 1784 | ||
1662 | static int snd_ac97_alc655_mic_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) | 1785 | static void alc655_update_jacks(ac97_t *ac97) |
1663 | { | ||
1664 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | ||
1665 | ucontrol->value.integer.value[0] = (ac97->regs[AC97_ALC650_MULTICH] >> 10) & 1; | ||
1666 | return 0; | ||
1667 | } | ||
1668 | |||
1669 | static int snd_ac97_alc655_mic_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) | ||
1670 | { | 1786 | { |
1671 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | 1787 | int shared; |
1672 | 1788 | ||
1789 | /* shared Line-In */ | ||
1790 | shared = is_shared_linein(ac97); | ||
1791 | ac97_update_bits_page(ac97, AC97_ALC650_MULTICH, 1 << 9, | ||
1792 | shared ? (1 << 9) : 0, 0); | ||
1793 | /* update shared mic */ | ||
1794 | shared = is_shared_micin(ac97); | ||
1673 | /* misc control; vrefout disable */ | 1795 | /* misc control; vrefout disable */ |
1674 | snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12, | 1796 | snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12, |
1675 | ucontrol->value.integer.value[0] ? (1 << 12) : 0); | 1797 | shared ? (1 << 12) : 0); |
1676 | return ac97_update_bits_page(ac97, AC97_ALC650_MULTICH, 1 << 10, | 1798 | ac97_update_bits_page(ac97, AC97_ALC650_MULTICH, 1 << 10, |
1677 | ucontrol->value.integer.value[0] ? (1 << 10) : 0, | 1799 | shared ? (1 << 10) : 0, 0); |
1678 | 0); | ||
1679 | } | 1800 | } |
1680 | 1801 | ||
1681 | |||
1682 | static const snd_kcontrol_new_t snd_ac97_controls_alc655[] = { | 1802 | static const snd_kcontrol_new_t snd_ac97_controls_alc655[] = { |
1683 | AC97_PAGE_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0, 0), | 1803 | AC97_PAGE_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0, 0), |
1684 | AC97_PAGE_SINGLE("Line-In As Surround", AC97_ALC650_MULTICH, 9, 1, 0, 0), | 1804 | AC97_SURROUND_JACK_MODE_CTL, |
1685 | { | 1805 | AC97_CHANNEL_MODE_CTL, |
1686 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1687 | .name = "Mic As Center/LFE", | ||
1688 | .info = snd_ac97_info_volsw, | ||
1689 | .get = snd_ac97_alc655_mic_get, | ||
1690 | .put = snd_ac97_alc655_mic_put, | ||
1691 | .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */ | ||
1692 | }, | ||
1693 | }; | 1806 | }; |
1694 | 1807 | ||
1695 | static int alc655_iec958_route_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) | 1808 | static int alc655_iec958_route_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) |
@@ -1759,7 +1872,8 @@ static int patch_alc655_specific(ac97_t * ac97) | |||
1759 | } | 1872 | } |
1760 | 1873 | ||
1761 | static struct snd_ac97_build_ops patch_alc655_ops = { | 1874 | static struct snd_ac97_build_ops patch_alc655_ops = { |
1762 | .build_specific = patch_alc655_specific | 1875 | .build_specific = patch_alc655_specific, |
1876 | .update_jacks = alc655_update_jacks | ||
1763 | }; | 1877 | }; |
1764 | 1878 | ||
1765 | int patch_alc655(ac97_t * ac97) | 1879 | int patch_alc655(ac97_t * ac97) |
@@ -1798,63 +1912,33 @@ int patch_alc655(ac97_t * ac97) | |||
1798 | #define AC97_ALC850_JACK_SELECT 0x76 | 1912 | #define AC97_ALC850_JACK_SELECT 0x76 |
1799 | #define AC97_ALC850_MISC1 0x7a | 1913 | #define AC97_ALC850_MISC1 0x7a |
1800 | 1914 | ||
1801 | static int ac97_alc850_surround_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) | 1915 | static void alc850_update_jacks(ac97_t *ac97) |
1802 | { | ||
1803 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | ||
1804 | ucontrol->value.integer.value[0] = ((ac97->regs[AC97_ALC850_JACK_SELECT] >> 12) & 7) == 2; | ||
1805 | return 0; | ||
1806 | } | ||
1807 | |||
1808 | static int ac97_alc850_surround_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) | ||
1809 | { | 1916 | { |
1810 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | 1917 | int shared; |
1811 | 1918 | ||
1919 | /* shared Line-In */ | ||
1920 | shared = is_shared_linein(ac97); | ||
1812 | /* SURR 1kOhm (bit4), Amp (bit5) */ | 1921 | /* SURR 1kOhm (bit4), Amp (bit5) */ |
1813 | snd_ac97_update_bits(ac97, AC97_ALC850_MISC1, (1<<4)|(1<<5), | 1922 | snd_ac97_update_bits(ac97, AC97_ALC850_MISC1, (1<<4)|(1<<5), |
1814 | ucontrol->value.integer.value[0] ? (1<<5) : (1<<4)); | 1923 | shared ? (1<<5) : (1<<4)); |
1815 | /* LINE-IN = 0, SURROUND = 2 */ | 1924 | /* LINE-IN = 0, SURROUND = 2 */ |
1816 | return snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 12, | 1925 | snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 12, |
1817 | ucontrol->value.integer.value[0] ? (2<<12) : (0<<12)); | 1926 | shared ? (2<<12) : (0<<12)); |
1818 | } | 1927 | /* update shared mic */ |
1819 | 1928 | shared = is_shared_micin(ac97); | |
1820 | static int ac97_alc850_mic_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) | ||
1821 | { | ||
1822 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | ||
1823 | ucontrol->value.integer.value[0] = ((ac97->regs[AC97_ALC850_JACK_SELECT] >> 4) & 7) == 2; | ||
1824 | return 0; | ||
1825 | } | ||
1826 | |||
1827 | static int ac97_alc850_mic_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) | ||
1828 | { | ||
1829 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | ||
1830 | |||
1831 | /* Vref disable (bit12), 1kOhm (bit13) */ | 1929 | /* Vref disable (bit12), 1kOhm (bit13) */ |
1832 | snd_ac97_update_bits(ac97, AC97_ALC850_MISC1, (1<<12)|(1<<13), | 1930 | snd_ac97_update_bits(ac97, AC97_ALC850_MISC1, (1<<12)|(1<<13), |
1833 | ucontrol->value.integer.value[0] ? (1<<12) : (1<<13)); | 1931 | shared ? (1<<12) : (1<<13)); |
1834 | /* MIC-IN = 1, CENTER-LFE = 2 */ | 1932 | /* MIC-IN = 1, CENTER-LFE = 2 */ |
1835 | return snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 4, | 1933 | snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 4, |
1836 | ucontrol->value.integer.value[0] ? (2<<4) : (1<<4)); | 1934 | shared ? (2<<4) : (1<<4)); |
1837 | } | 1935 | } |
1838 | 1936 | ||
1839 | static const snd_kcontrol_new_t snd_ac97_controls_alc850[] = { | 1937 | static const snd_kcontrol_new_t snd_ac97_controls_alc850[] = { |
1840 | AC97_PAGE_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0, 0), | 1938 | AC97_PAGE_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0, 0), |
1841 | { | 1939 | AC97_SINGLE("Mic Front Input Switch", AC97_ALC850_JACK_SELECT, 15, 1, 1), |
1842 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1940 | AC97_SURROUND_JACK_MODE_CTL, |
1843 | .name = "Line-In As Surround", | 1941 | AC97_CHANNEL_MODE_CTL, |
1844 | .info = snd_ac97_info_volsw, | ||
1845 | .get = ac97_alc850_surround_get, | ||
1846 | .put = ac97_alc850_surround_put, | ||
1847 | .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */ | ||
1848 | }, | ||
1849 | { | ||
1850 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1851 | .name = "Mic As Center/LFE", | ||
1852 | .info = snd_ac97_info_volsw, | ||
1853 | .get = ac97_alc850_mic_get, | ||
1854 | .put = ac97_alc850_mic_put, | ||
1855 | .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */ | ||
1856 | }, | ||
1857 | |||
1858 | }; | 1942 | }; |
1859 | 1943 | ||
1860 | static int patch_alc850_specific(ac97_t *ac97) | 1944 | static int patch_alc850_specific(ac97_t *ac97) |
@@ -1871,7 +1955,8 @@ static int patch_alc850_specific(ac97_t *ac97) | |||
1871 | } | 1955 | } |
1872 | 1956 | ||
1873 | static struct snd_ac97_build_ops patch_alc850_ops = { | 1957 | static struct snd_ac97_build_ops patch_alc850_ops = { |
1874 | .build_specific = patch_alc850_specific | 1958 | .build_specific = patch_alc850_specific, |
1959 | .update_jacks = alc850_update_jacks | ||
1875 | }; | 1960 | }; |
1876 | 1961 | ||
1877 | int patch_alc850(ac97_t *ac97) | 1962 | int patch_alc850(ac97_t *ac97) |
@@ -1911,9 +1996,17 @@ int patch_alc850(ac97_t *ac97) | |||
1911 | /* | 1996 | /* |
1912 | * C-Media CM97xx codecs | 1997 | * C-Media CM97xx codecs |
1913 | */ | 1998 | */ |
1999 | static void cm9738_update_jacks(ac97_t *ac97) | ||
2000 | { | ||
2001 | /* shared Line-In */ | ||
2002 | snd_ac97_update_bits(ac97, AC97_CM9738_VENDOR_CTRL, 1 << 10, | ||
2003 | is_shared_linein(ac97) ? (1 << 10) : 0); | ||
2004 | } | ||
2005 | |||
1914 | static const snd_kcontrol_new_t snd_ac97_cm9738_controls[] = { | 2006 | static const snd_kcontrol_new_t snd_ac97_cm9738_controls[] = { |
1915 | AC97_SINGLE("Line-In As Surround", AC97_CM9738_VENDOR_CTRL, 10, 1, 0), | ||
1916 | AC97_SINGLE("Duplicate Front", AC97_CM9738_VENDOR_CTRL, 13, 1, 0), | 2007 | AC97_SINGLE("Duplicate Front", AC97_CM9738_VENDOR_CTRL, 13, 1, 0), |
2008 | AC97_SURROUND_JACK_MODE_CTL, | ||
2009 | AC97_CHANNEL_MODE_4CH_CTL, | ||
1917 | }; | 2010 | }; |
1918 | 2011 | ||
1919 | static int patch_cm9738_specific(ac97_t * ac97) | 2012 | static int patch_cm9738_specific(ac97_t * ac97) |
@@ -1922,7 +2015,8 @@ static int patch_cm9738_specific(ac97_t * ac97) | |||
1922 | } | 2015 | } |
1923 | 2016 | ||
1924 | static struct snd_ac97_build_ops patch_cm9738_ops = { | 2017 | static struct snd_ac97_build_ops patch_cm9738_ops = { |
1925 | .build_specific = patch_cm9738_specific | 2018 | .build_specific = patch_cm9738_specific, |
2019 | .update_jacks = cm9738_update_jacks | ||
1926 | }; | 2020 | }; |
1927 | 2021 | ||
1928 | int patch_cm9738(ac97_t * ac97) | 2022 | int patch_cm9738(ac97_t * ac97) |
@@ -1986,34 +2080,19 @@ static const snd_kcontrol_new_t snd_ac97_cm9739_controls_spdif[] = { | |||
1986 | /* BIT 8: SPD32 - 32bit SPDIF - not supported yet */ | 2080 | /* BIT 8: SPD32 - 32bit SPDIF - not supported yet */ |
1987 | }; | 2081 | }; |
1988 | 2082 | ||
1989 | static int snd_ac97_cm9739_center_mic_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) | 2083 | static void cm9739_update_jacks(ac97_t *ac97) |
1990 | { | ||
1991 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | ||
1992 | if (ac97->regs[AC97_CM9739_MULTI_CHAN] & 0x1000) | ||
1993 | ucontrol->value.integer.value[0] = 1; | ||
1994 | else | ||
1995 | ucontrol->value.integer.value[0] = 0; | ||
1996 | return 0; | ||
1997 | } | ||
1998 | |||
1999 | static int snd_ac97_cm9739_center_mic_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) | ||
2000 | { | 2084 | { |
2001 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | 2085 | /* shared Line-In */ |
2002 | return snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 0x3000, | 2086 | snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 1 << 10, |
2003 | ucontrol->value.integer.value[0] ? | 2087 | is_shared_linein(ac97) ? (1 << 10) : 0); |
2004 | 0x1000 : 0x2000); | 2088 | /* shared Mic */ |
2089 | snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 0x3000, | ||
2090 | is_shared_micin(ac97) ? 0x1000 : 0x2000); | ||
2005 | } | 2091 | } |
2006 | 2092 | ||
2007 | static const snd_kcontrol_new_t snd_ac97_cm9739_controls[] = { | 2093 | static const snd_kcontrol_new_t snd_ac97_cm9739_controls[] = { |
2008 | AC97_SINGLE("Line-In As Surround", AC97_CM9739_MULTI_CHAN, 10, 1, 0), | 2094 | AC97_SURROUND_JACK_MODE_CTL, |
2009 | { | 2095 | AC97_CHANNEL_MODE_CTL, |
2010 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2011 | .name = "Mic As Center/LFE", | ||
2012 | .info = snd_ac97_info_volsw, | ||
2013 | .get = snd_ac97_cm9739_center_mic_get, | ||
2014 | .put = snd_ac97_cm9739_center_mic_put, | ||
2015 | .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */ | ||
2016 | }, | ||
2017 | }; | 2096 | }; |
2018 | 2097 | ||
2019 | static int patch_cm9739_specific(ac97_t * ac97) | 2098 | static int patch_cm9739_specific(ac97_t * ac97) |
@@ -2028,7 +2107,8 @@ static int patch_cm9739_post_spdif(ac97_t * ac97) | |||
2028 | 2107 | ||
2029 | static struct snd_ac97_build_ops patch_cm9739_ops = { | 2108 | static struct snd_ac97_build_ops patch_cm9739_ops = { |
2030 | .build_specific = patch_cm9739_specific, | 2109 | .build_specific = patch_cm9739_specific, |
2031 | .build_post_spdif = patch_cm9739_post_spdif | 2110 | .build_post_spdif = patch_cm9739_post_spdif, |
2111 | .update_jacks = cm9739_update_jacks | ||
2032 | }; | 2112 | }; |
2033 | 2113 | ||
2034 | int patch_cm9739(ac97_t * ac97) | 2114 | int patch_cm9739(ac97_t * ac97) |
@@ -2087,71 +2167,97 @@ int patch_cm9739(ac97_t * ac97) | |||
2087 | } | 2167 | } |
2088 | 2168 | ||
2089 | #define AC97_CM9761_MULTI_CHAN 0x64 | 2169 | #define AC97_CM9761_MULTI_CHAN 0x64 |
2170 | #define AC97_CM9761_FUNC 0x66 | ||
2090 | #define AC97_CM9761_SPDIF_CTRL 0x6c | 2171 | #define AC97_CM9761_SPDIF_CTRL 0x6c |
2091 | 2172 | ||
2092 | static int snd_ac97_cm9761_linein_rear_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) | 2173 | static void cm9761_update_jacks(ac97_t *ac97) |
2093 | { | ||
2094 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | ||
2095 | if (ac97->regs[AC97_CM9739_MULTI_CHAN] & 0x0400) | ||
2096 | ucontrol->value.integer.value[0] = 1; | ||
2097 | else | ||
2098 | ucontrol->value.integer.value[0] = 0; | ||
2099 | return 0; | ||
2100 | } | ||
2101 | |||
2102 | static int snd_ac97_cm9761_linein_rear_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) | ||
2103 | { | 2174 | { |
2104 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | 2175 | unsigned short surr_vals[2][2] = { |
2105 | unsigned short vals[2][2] = { | ||
2106 | { 0x0008, 0x0400 }, /* off, on */ | 2176 | { 0x0008, 0x0400 }, /* off, on */ |
2107 | { 0x0000, 0x0408 }, /* off, on (9761-82 rev.B) */ | 2177 | { 0x0000, 0x0408 }, /* off, on (9761-82 rev.B) */ |
2108 | }; | 2178 | }; |
2109 | return snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 0x0408, | 2179 | unsigned short clfe_vals[2][2] = { |
2110 | vals[ac97->spec.dev_flags][!!ucontrol->value.integer.value[0]]); | 2180 | { 0x2000, 0x1880 }, /* off, on */ |
2181 | { 0x1000, 0x2880 }, /* off, on (9761-82 rev.B) */ | ||
2182 | }; | ||
2183 | |||
2184 | /* shared Line-In */ | ||
2185 | snd_ac97_update_bits(ac97, AC97_CM9761_MULTI_CHAN, 0x0408, | ||
2186 | surr_vals[ac97->spec.dev_flags][is_shared_linein(ac97)]); | ||
2187 | /* shared Mic */ | ||
2188 | snd_ac97_update_bits(ac97, AC97_CM9761_MULTI_CHAN, 0x3880, | ||
2189 | clfe_vals[ac97->spec.dev_flags][is_shared_micin(ac97)]); | ||
2190 | } | ||
2191 | |||
2192 | static const snd_kcontrol_new_t snd_ac97_cm9761_controls[] = { | ||
2193 | AC97_SURROUND_JACK_MODE_CTL, | ||
2194 | AC97_CHANNEL_MODE_CTL, | ||
2195 | }; | ||
2196 | |||
2197 | static int cm9761_spdif_out_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) | ||
2198 | { | ||
2199 | static char *texts[] = { "AC-Link", "ADC", "SPDIF-In" }; | ||
2200 | |||
2201 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
2202 | uinfo->count = 1; | ||
2203 | uinfo->value.enumerated.items = 3; | ||
2204 | if (uinfo->value.enumerated.item > 2) | ||
2205 | uinfo->value.enumerated.item = 2; | ||
2206 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
2207 | return 0; | ||
2111 | } | 2208 | } |
2112 | 2209 | ||
2113 | static int snd_ac97_cm9761_center_mic_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) | 2210 | static int cm9761_spdif_out_source_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) |
2114 | { | 2211 | { |
2115 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | 2212 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); |
2116 | if (ac97->regs[AC97_CM9739_MULTI_CHAN] & 0x1000) | 2213 | |
2117 | ucontrol->value.integer.value[0] = 1; | 2214 | if (ac97->regs[AC97_CM9761_FUNC] & 0x1) |
2215 | ucontrol->value.enumerated.item[0] = 2; /* SPDIF-loopback */ | ||
2216 | else if (ac97->regs[AC97_CM9761_SPDIF_CTRL] & 0x2) | ||
2217 | ucontrol->value.enumerated.item[0] = 1; /* ADC loopback */ | ||
2118 | else | 2218 | else |
2119 | ucontrol->value.integer.value[0] = 0; | 2219 | ucontrol->value.enumerated.item[0] = 0; /* AC-link */ |
2120 | if (ac97->spec.dev_flags) /* 9761-82 rev.B */ | ||
2121 | ucontrol->value.integer.value[0] = !ucontrol->value.integer.value[0]; | ||
2122 | return 0; | 2220 | return 0; |
2123 | } | 2221 | } |
2124 | 2222 | ||
2125 | static int snd_ac97_cm9761_center_mic_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) | 2223 | static int cm9761_spdif_out_source_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) |
2126 | { | 2224 | { |
2127 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | 2225 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); |
2128 | unsigned short vals[2][2] = { | 2226 | |
2129 | { 0x2000, 0x1880 }, /* off, on */ | 2227 | if (ucontrol->value.enumerated.item[0] == 2) |
2130 | { 0x1000, 0x2880 }, /* off, on (9761-82 rev.B) */ | 2228 | return snd_ac97_update_bits(ac97, AC97_CM9761_FUNC, 0x1, 0x1); |
2131 | }; | 2229 | snd_ac97_update_bits(ac97, AC97_CM9761_FUNC, 0x1, 0); |
2132 | return snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 0x3880, | 2230 | return snd_ac97_update_bits(ac97, AC97_CM9761_SPDIF_CTRL, 0x2, |
2133 | vals[ac97->spec.dev_flags][!!ucontrol->value.integer.value[0]]); | 2231 | ucontrol->value.enumerated.item[0] == 1 ? 0x2 : 0); |
2134 | } | 2232 | } |
2135 | 2233 | ||
2136 | static const snd_kcontrol_new_t snd_ac97_cm9761_controls[] = { | 2234 | static const char *cm9761_dac_clock[] = { "AC-Link", "SPDIF-In", "Both" }; |
2137 | { | 2235 | static const struct ac97_enum cm9761_dac_clock_enum = |
2138 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2236 | AC97_ENUM_SINGLE(AC97_CM9761_SPDIF_CTRL, 9, 3, cm9761_dac_clock); |
2139 | .name = "Line-In As Surround", | 2237 | |
2140 | .info = snd_ac97_info_volsw, | 2238 | static const snd_kcontrol_new_t snd_ac97_cm9761_controls_spdif[] = { |
2141 | .get = snd_ac97_cm9761_linein_rear_get, | 2239 | { /* BIT 1: SPDIFS */ |
2142 | .put = snd_ac97_cm9761_linein_rear_put, | 2240 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
2143 | .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */ | 2241 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", |
2144 | }, | 2242 | .info = cm9761_spdif_out_source_info, |
2145 | { | 2243 | .get = cm9761_spdif_out_source_get, |
2146 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2244 | .put = cm9761_spdif_out_source_put, |
2147 | .name = "Mic As Center/LFE", | ||
2148 | .info = snd_ac97_info_volsw, | ||
2149 | .get = snd_ac97_cm9761_center_mic_get, | ||
2150 | .put = snd_ac97_cm9761_center_mic_put, | ||
2151 | .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */ | ||
2152 | }, | 2245 | }, |
2246 | /* BIT 2: IG_SPIV */ | ||
2247 | AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Valid Switch", AC97_CM9761_SPDIF_CTRL, 2, 1, 0), | ||
2248 | /* BIT 3: SPI2F */ | ||
2249 | AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Monitor", AC97_CM9761_SPDIF_CTRL, 3, 1, 0), | ||
2250 | /* BIT 4: SPI2SDI */ | ||
2251 | AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), AC97_CM9761_SPDIF_CTRL, 4, 1, 0), | ||
2252 | /* BIT 9-10: DAC_CTL */ | ||
2253 | AC97_ENUM("DAC Clock Source", cm9761_dac_clock_enum), | ||
2153 | }; | 2254 | }; |
2154 | 2255 | ||
2256 | static int patch_cm9761_post_spdif(ac97_t * ac97) | ||
2257 | { | ||
2258 | return patch_build_controls(ac97, snd_ac97_cm9761_controls_spdif, ARRAY_SIZE(snd_ac97_cm9761_controls_spdif)); | ||
2259 | } | ||
2260 | |||
2155 | static int patch_cm9761_specific(ac97_t * ac97) | 2261 | static int patch_cm9761_specific(ac97_t * ac97) |
2156 | { | 2262 | { |
2157 | return patch_build_controls(ac97, snd_ac97_cm9761_controls, ARRAY_SIZE(snd_ac97_cm9761_controls)); | 2263 | return patch_build_controls(ac97, snd_ac97_cm9761_controls, ARRAY_SIZE(snd_ac97_cm9761_controls)); |
@@ -2159,7 +2265,8 @@ static int patch_cm9761_specific(ac97_t * ac97) | |||
2159 | 2265 | ||
2160 | static struct snd_ac97_build_ops patch_cm9761_ops = { | 2266 | static struct snd_ac97_build_ops patch_cm9761_ops = { |
2161 | .build_specific = patch_cm9761_specific, | 2267 | .build_specific = patch_cm9761_specific, |
2162 | .build_post_spdif = patch_cm9739_post_spdif /* hope it's identical... */ | 2268 | .build_post_spdif = patch_cm9761_post_spdif, |
2269 | .update_jacks = cm9761_update_jacks | ||
2163 | }; | 2270 | }; |
2164 | 2271 | ||
2165 | int patch_cm9761(ac97_t *ac97) | 2272 | int patch_cm9761(ac97_t *ac97) |
@@ -2193,24 +2300,25 @@ int patch_cm9761(ac97_t *ac97) | |||
2193 | /* to be sure: we overwrite the ext status bits */ | 2300 | /* to be sure: we overwrite the ext status bits */ |
2194 | snd_ac97_write_cache(ac97, AC97_EXTENDED_STATUS, 0x05c0); | 2301 | snd_ac97_write_cache(ac97, AC97_EXTENDED_STATUS, 0x05c0); |
2195 | /* Don't set 0x0200 here. This results in the silent analog output */ | 2302 | /* Don't set 0x0200 here. This results in the silent analog output */ |
2196 | snd_ac97_write_cache(ac97, AC97_CM9761_SPDIF_CTRL, 0x0009); | 2303 | snd_ac97_write_cache(ac97, AC97_CM9761_SPDIF_CTRL, 0x0001); /* enable spdif-in */ |
2197 | ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_48000; /* 48k only */ | 2304 | ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_48000; /* 48k only */ |
2198 | 2305 | ||
2199 | /* set-up multi channel */ | 2306 | /* set-up multi channel */ |
2200 | /* bit 15: pc master beep off | 2307 | /* bit 15: pc master beep off |
2201 | * bit 14: ?? | 2308 | * bit 14: pin47 = EAPD/SPDIF |
2202 | * bit 13: vref ctl [= cm9739] | 2309 | * bit 13: vref ctl [= cm9739] |
2203 | * bit 12: center/mic [= cm9739] (reverted on rev B) | 2310 | * bit 12: CLFE control (reverted on rev B) |
2204 | * bit 11: ?? (mic/center/lfe) (reverted on rev B) | 2311 | * bit 11: Mic/center share (reverted on rev B) |
2205 | * bit 10: suddound/line [= cm9739] | 2312 | * bit 10: suddound/line share |
2206 | * bit 9: mix 2 surround | 2313 | * bit 9: Analog-in mix -> surround |
2207 | * bit 8: ? | 2314 | * bit 8: Analog-in mix -> CLFE |
2208 | * bit 7: ?? (mic/center/lfe) | 2315 | * bit 7: Mic/LFE share (mic/center/lfe) |
2209 | * bit 4: ?? (front) | 2316 | * bit 5: vref select (9761A) |
2210 | * bit 3: ?? (line-in/rear share) (revereted with rev B) | 2317 | * bit 4: front control |
2211 | * bit 2: ?? (surround) | 2318 | * bit 3: surround control (revereted with rev B) |
2212 | * bit 1: front mic | 2319 | * bit 2: front mic |
2213 | * bit 0: mic boost | 2320 | * bit 1: stereo mic |
2321 | * bit 0: mic boost level (0=20dB, 1=30dB) | ||
2214 | */ | 2322 | */ |
2215 | 2323 | ||
2216 | #if 0 | 2324 | #if 0 |
@@ -2230,6 +2338,47 @@ int patch_cm9761(ac97_t *ac97) | |||
2230 | return 0; | 2338 | return 0; |
2231 | } | 2339 | } |
2232 | 2340 | ||
2341 | #define AC97_CM9780_SIDE 0x60 | ||
2342 | #define AC97_CM9780_JACK 0x62 | ||
2343 | #define AC97_CM9780_MIXER 0x64 | ||
2344 | #define AC97_CM9780_MULTI_CHAN 0x66 | ||
2345 | #define AC97_CM9780_SPDIF 0x6c | ||
2346 | |||
2347 | static const char *cm9780_ch_select[] = { "Front", "Side", "Center/LFE", "Rear" }; | ||
2348 | static const struct ac97_enum cm9780_ch_select_enum = | ||
2349 | AC97_ENUM_SINGLE(AC97_CM9780_MULTI_CHAN, 6, 4, cm9780_ch_select); | ||
2350 | static const snd_kcontrol_new_t cm9780_controls[] = { | ||
2351 | AC97_DOUBLE("Side Playback Switch", AC97_CM9780_SIDE, 15, 7, 1, 1), | ||
2352 | AC97_DOUBLE("Side Playback Volume", AC97_CM9780_SIDE, 8, 0, 31, 0), | ||
2353 | AC97_ENUM("Side Playback Route", cm9780_ch_select_enum), | ||
2354 | }; | ||
2355 | |||
2356 | static int patch_cm9780_specific(ac97_t *ac97) | ||
2357 | { | ||
2358 | return patch_build_controls(ac97, cm9780_controls, ARRAY_SIZE(cm9780_controls)); | ||
2359 | } | ||
2360 | |||
2361 | static struct snd_ac97_build_ops patch_cm9780_ops = { | ||
2362 | .build_specific = patch_cm9780_specific, | ||
2363 | .build_post_spdif = patch_cm9761_post_spdif /* identical with CM9761 */ | ||
2364 | }; | ||
2365 | |||
2366 | int patch_cm9780(ac97_t *ac97) | ||
2367 | { | ||
2368 | unsigned short val; | ||
2369 | |||
2370 | ac97->build_ops = &patch_cm9780_ops; | ||
2371 | |||
2372 | /* enable spdif */ | ||
2373 | if (ac97->ext_id & AC97_EI_SPDIF) { | ||
2374 | ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_48000; /* 48k only */ | ||
2375 | val = snd_ac97_read(ac97, AC97_CM9780_SPDIF); | ||
2376 | val |= 0x1; /* SPDI_EN */ | ||
2377 | snd_ac97_write_cache(ac97, AC97_CM9780_SPDIF, val); | ||
2378 | } | ||
2379 | |||
2380 | return 0; | ||
2381 | } | ||
2233 | 2382 | ||
2234 | /* | 2383 | /* |
2235 | * VIA VT1616 codec | 2384 | * VIA VT1616 codec |
@@ -2263,9 +2412,21 @@ int patch_vt1616(ac97_t * ac97) | |||
2263 | return 0; | 2412 | return 0; |
2264 | } | 2413 | } |
2265 | 2414 | ||
2415 | /* | ||
2416 | */ | ||
2417 | static void it2646_update_jacks(ac97_t *ac97) | ||
2418 | { | ||
2419 | /* shared Line-In */ | ||
2420 | snd_ac97_update_bits(ac97, 0x76, 1 << 9, | ||
2421 | is_shared_linein(ac97) ? (1<<9) : 0); | ||
2422 | /* shared Mic */ | ||
2423 | snd_ac97_update_bits(ac97, 0x76, 1 << 10, | ||
2424 | is_shared_micin(ac97) ? (1<<10) : 0); | ||
2425 | } | ||
2426 | |||
2266 | static const snd_kcontrol_new_t snd_ac97_controls_it2646[] = { | 2427 | static const snd_kcontrol_new_t snd_ac97_controls_it2646[] = { |
2267 | AC97_SINGLE("Line-In As Surround", 0x76, 9, 1, 0), | 2428 | AC97_SURROUND_JACK_MODE_CTL, |
2268 | AC97_SINGLE("Mic As Center/LFE", 0x76, 10, 1, 0), | 2429 | AC97_CHANNEL_MODE_CTL, |
2269 | }; | 2430 | }; |
2270 | 2431 | ||
2271 | static const snd_kcontrol_new_t snd_ac97_spdif_controls_it2646[] = { | 2432 | static const snd_kcontrol_new_t snd_ac97_spdif_controls_it2646[] = { |
@@ -2285,7 +2446,8 @@ static int patch_it2646_specific(ac97_t * ac97) | |||
2285 | } | 2446 | } |
2286 | 2447 | ||
2287 | static struct snd_ac97_build_ops patch_it2646_ops = { | 2448 | static struct snd_ac97_build_ops patch_it2646_ops = { |
2288 | .build_specific = patch_it2646_specific | 2449 | .build_specific = patch_it2646_specific, |
2450 | .update_jacks = it2646_update_jacks | ||
2289 | }; | 2451 | }; |
2290 | 2452 | ||
2291 | int patch_it2646(ac97_t * ac97) | 2453 | int patch_it2646(ac97_t * ac97) |
@@ -2297,12 +2459,29 @@ int patch_it2646(ac97_t * ac97) | |||
2297 | return 0; | 2459 | return 0; |
2298 | } | 2460 | } |
2299 | 2461 | ||
2300 | /* Si3036/8 specific registers */ | 2462 | /* |
2463 | * Si3036 codec | ||
2464 | */ | ||
2465 | |||
2301 | #define AC97_SI3036_CHIP_ID 0x5a | 2466 | #define AC97_SI3036_CHIP_ID 0x5a |
2467 | #define AC97_SI3036_LINE_CFG 0x5c | ||
2468 | |||
2469 | static const snd_kcontrol_new_t snd_ac97_controls_si3036[] = { | ||
2470 | AC97_DOUBLE("Modem Speaker Volume", 0x5c, 14, 12, 3, 1) | ||
2471 | }; | ||
2472 | |||
2473 | static int patch_si3036_specific(ac97_t * ac97) | ||
2474 | { | ||
2475 | return patch_build_controls(ac97, snd_ac97_controls_si3036, ARRAY_SIZE(snd_ac97_controls_si3036)); | ||
2476 | } | ||
2477 | |||
2478 | static struct snd_ac97_build_ops patch_si3036_ops = { | ||
2479 | .build_specific = patch_si3036_specific, | ||
2480 | }; | ||
2302 | 2481 | ||
2303 | int mpatch_si3036(ac97_t * ac97) | 2482 | int mpatch_si3036(ac97_t * ac97) |
2304 | { | 2483 | { |
2305 | //printk("mpatch_si3036: chip id = %x\n", snd_ac97_read(ac97, 0x5a)); | 2484 | ac97->build_ops = &patch_si3036_ops; |
2306 | snd_ac97_write_cache(ac97, 0x5c, 0xf210 ); | 2485 | snd_ac97_write_cache(ac97, 0x5c, 0xf210 ); |
2307 | snd_ac97_write_cache(ac97, 0x68, 0); | 2486 | snd_ac97_write_cache(ac97, 0x68, 0); |
2308 | return 0; | 2487 | return 0; |
diff --git a/sound/pci/ac97/ac97_patch.h b/sound/pci/ac97/ac97_patch.h index 6db51c96f5d0..7b7377d0f2ae 100644 --- a/sound/pci/ac97/ac97_patch.h +++ b/sound/pci/ac97/ac97_patch.h | |||
@@ -54,6 +54,7 @@ int patch_alc850(ac97_t * ac97); | |||
54 | int patch_cm9738(ac97_t * ac97); | 54 | int patch_cm9738(ac97_t * ac97); |
55 | int patch_cm9739(ac97_t * ac97); | 55 | int patch_cm9739(ac97_t * ac97); |
56 | int patch_cm9761(ac97_t * ac97); | 56 | int patch_cm9761(ac97_t * ac97); |
57 | int patch_cm9780(ac97_t * ac97); | ||
57 | int patch_vt1616(ac97_t * ac97); | 58 | int patch_vt1616(ac97_t * ac97); |
58 | int patch_it2646(ac97_t * ac97); | 59 | int patch_it2646(ac97_t * ac97); |
59 | int mpatch_si3036(ac97_t * ac97); | 60 | int mpatch_si3036(ac97_t * ac97); |
diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c index 984d5d4ba4e1..eb5c36d31a52 100644 --- a/sound/pci/ali5451/ali5451.c +++ b/sound/pci/ali5451/ali5451.c | |||
@@ -98,6 +98,8 @@ MODULE_PARM_DESC(spdif, "Support SPDIF I/O"); | |||
98 | #define ALI_LEF_CHANNEL 23 | 98 | #define ALI_LEF_CHANNEL 23 |
99 | #define ALI_SURR_LEFT_CHANNEL 26 | 99 | #define ALI_SURR_LEFT_CHANNEL 26 |
100 | #define ALI_SURR_RIGHT_CHANNEL 25 | 100 | #define ALI_SURR_RIGHT_CHANNEL 25 |
101 | #define ALI_MODEM_IN_CHANNEL 21 | ||
102 | #define ALI_MODEM_OUT_CHANNEL 20 | ||
101 | 103 | ||
102 | #define SNDRV_ALI_VOICE_TYPE_PCM 01 | 104 | #define SNDRV_ALI_VOICE_TYPE_PCM 01 |
103 | #define SNDRV_ALI_VOICE_TYPE_OTH 02 | 105 | #define SNDRV_ALI_VOICE_TYPE_OTH 02 |
@@ -122,7 +124,15 @@ MODULE_PARM_DESC(spdif, "Support SPDIF I/O"); | |||
122 | 124 | ||
123 | #define ALI_SCTRL 0x48 | 125 | #define ALI_SCTRL 0x48 |
124 | #define ALI_SPDIF_OUT_ENABLE 0x20 | 126 | #define ALI_SPDIF_OUT_ENABLE 0x20 |
127 | #define ALI_SCTRL_LINE_IN2 (1 << 9) | ||
128 | #define ALI_SCTRL_GPIO_IN2 (1 << 13) | ||
129 | #define ALI_SCTRL_LINE_OUT_EN (1 << 20) | ||
130 | #define ALI_SCTRL_GPIO_OUT_EN (1 << 23) | ||
131 | #define ALI_SCTRL_CODEC1_READY (1 << 24) | ||
132 | #define ALI_SCTRL_CODEC2_READY (1 << 25) | ||
125 | #define ALI_AC97_GPIO 0x4c | 133 | #define ALI_AC97_GPIO 0x4c |
134 | #define ALI_AC97_GPIO_ENABLE 0x8000 | ||
135 | #define ALI_AC97_GPIO_DATA_SHIFT 16 | ||
126 | #define ALI_SPDIF_CS 0x70 | 136 | #define ALI_SPDIF_CS 0x70 |
127 | #define ALI_SPDIF_CTRL 0x74 | 137 | #define ALI_SPDIF_CTRL 0x74 |
128 | #define ALI_SPDIF_IN_FUNC_ENABLE 0x02 | 138 | #define ALI_SPDIF_IN_FUNC_ENABLE 0x02 |
@@ -143,6 +153,7 @@ MODULE_PARM_DESC(spdif, "Support SPDIF I/O"); | |||
143 | #define TARGET_REACHED 0x00008000 | 153 | #define TARGET_REACHED 0x00008000 |
144 | #define MIXER_OVERFLOW 0x00000800 | 154 | #define MIXER_OVERFLOW 0x00000800 |
145 | #define MIXER_UNDERFLOW 0x00000400 | 155 | #define MIXER_UNDERFLOW 0x00000400 |
156 | #define GPIO_IRQ 0x01000000 | ||
146 | #define ALI_SBBL_SBCL 0xc0 | 157 | #define ALI_SBBL_SBCL 0xc0 |
147 | #define ALI_SBCTRL_SBE2R_SBDD 0xc4 | 158 | #define ALI_SBCTRL_SBE2R_SBDD 0xc4 |
148 | #define ALI_STIMER 0xc8 | 159 | #define ALI_STIMER 0xc8 |
@@ -162,6 +173,9 @@ MODULE_PARM_DESC(spdif, "Support SPDIF I/O"); | |||
162 | 173 | ||
163 | #define ALI_REG(codec, x) ((codec)->port + x) | 174 | #define ALI_REG(codec, x) ((codec)->port + x) |
164 | 175 | ||
176 | #define MAX_CODECS 2 | ||
177 | |||
178 | |||
165 | typedef struct snd_stru_ali ali_t; | 179 | typedef struct snd_stru_ali ali_t; |
166 | typedef struct snd_ali_stru_voice snd_ali_voice_t; | 180 | typedef struct snd_ali_stru_voice snd_ali_voice_t; |
167 | 181 | ||
@@ -245,7 +259,7 @@ struct snd_stru_ali { | |||
245 | struct pci_dev *pci_m7101; | 259 | struct pci_dev *pci_m7101; |
246 | 260 | ||
247 | snd_card_t *card; | 261 | snd_card_t *card; |
248 | snd_pcm_t *pcm; | 262 | snd_pcm_t *pcm[MAX_CODECS]; |
249 | alidev_t synth; | 263 | alidev_t synth; |
250 | snd_ali_channel_control_t chregs; | 264 | snd_ali_channel_control_t chregs; |
251 | 265 | ||
@@ -255,8 +269,10 @@ struct snd_stru_ali { | |||
255 | unsigned int spurious_irq_count; | 269 | unsigned int spurious_irq_count; |
256 | unsigned int spurious_irq_max_delta; | 270 | unsigned int spurious_irq_max_delta; |
257 | 271 | ||
272 | unsigned int num_of_codecs; | ||
273 | |||
258 | ac97_bus_t *ac97_bus; | 274 | ac97_bus_t *ac97_bus; |
259 | ac97_t *ac97; | 275 | ac97_t *ac97[MAX_CODECS]; |
260 | unsigned short ac97_ext_id; | 276 | unsigned short ac97_ext_id; |
261 | unsigned short ac97_ext_status; | 277 | unsigned short ac97_ext_status; |
262 | 278 | ||
@@ -489,7 +505,12 @@ static void snd_ali_codec_write(ac97_t *ac97, | |||
489 | ali_t *codec = ac97->private_data; | 505 | ali_t *codec = ac97->private_data; |
490 | 506 | ||
491 | snd_ali_printk("codec_write: reg=%xh data=%xh.\n", reg, val); | 507 | snd_ali_printk("codec_write: reg=%xh data=%xh.\n", reg, val); |
492 | snd_ali_codec_poke(codec, 0, reg, val); | 508 | if(reg == AC97_GPIO_STATUS) { |
509 | outl((val << ALI_AC97_GPIO_DATA_SHIFT)|ALI_AC97_GPIO_ENABLE, | ||
510 | ALI_REG(codec, ALI_AC97_GPIO)); | ||
511 | return; | ||
512 | } | ||
513 | snd_ali_codec_poke(codec, ac97->num, reg, val); | ||
493 | return ; | 514 | return ; |
494 | } | 515 | } |
495 | 516 | ||
@@ -499,7 +520,7 @@ static unsigned short snd_ali_codec_read(ac97_t *ac97, unsigned short reg) | |||
499 | ali_t *codec = ac97->private_data; | 520 | ali_t *codec = ac97->private_data; |
500 | 521 | ||
501 | snd_ali_printk("codec_read reg=%xh.\n", reg); | 522 | snd_ali_printk("codec_read reg=%xh.\n", reg); |
502 | return (snd_ali_codec_peek(codec, 0, reg)); | 523 | return (snd_ali_codec_peek(codec, ac97->num, reg)); |
503 | } | 524 | } |
504 | 525 | ||
505 | /* | 526 | /* |
@@ -1051,7 +1072,7 @@ static irqreturn_t snd_ali_card_interrupt(int irq, | |||
1051 | } | 1072 | } |
1052 | 1073 | ||
1053 | 1074 | ||
1054 | static snd_ali_voice_t *snd_ali_alloc_voice(ali_t * codec, int type, int rec) | 1075 | static snd_ali_voice_t *snd_ali_alloc_voice(ali_t * codec, int type, int rec, int channel) |
1055 | { | 1076 | { |
1056 | snd_ali_voice_t *pvoice = NULL; | 1077 | snd_ali_voice_t *pvoice = NULL; |
1057 | unsigned long flags; | 1078 | unsigned long flags; |
@@ -1061,7 +1082,8 @@ static snd_ali_voice_t *snd_ali_alloc_voice(ali_t * codec, int type, int rec) | |||
1061 | 1082 | ||
1062 | spin_lock_irqsave(&codec->voice_alloc, flags); | 1083 | spin_lock_irqsave(&codec->voice_alloc, flags); |
1063 | if (type == SNDRV_ALI_VOICE_TYPE_PCM) { | 1084 | if (type == SNDRV_ALI_VOICE_TYPE_PCM) { |
1064 | idx = snd_ali_find_free_channel(codec,rec); | 1085 | idx = channel > 0 ? snd_ali_alloc_pcm_channel(codec, channel) : |
1086 | snd_ali_find_free_channel(codec,rec); | ||
1065 | if(idx < 0) { | 1087 | if(idx < 0) { |
1066 | snd_printk("ali_alloc_voice: err.\n"); | 1088 | snd_printk("ali_alloc_voice: err.\n"); |
1067 | spin_unlock_irqrestore(&codec->voice_alloc, flags); | 1089 | spin_unlock_irqrestore(&codec->voice_alloc, flags); |
@@ -1297,7 +1319,7 @@ static int snd_ali_playback_hw_params(snd_pcm_substream_t * substream, | |||
1297 | 1319 | ||
1298 | if (params_buffer_size(hw_params)/2 != params_period_size(hw_params)) { | 1320 | if (params_buffer_size(hw_params)/2 != params_period_size(hw_params)) { |
1299 | if (evoice == NULL) { | 1321 | if (evoice == NULL) { |
1300 | evoice = snd_ali_alloc_voice(codec, SNDRV_ALI_VOICE_TYPE_PCM, 0); | 1322 | evoice = snd_ali_alloc_voice(codec, SNDRV_ALI_VOICE_TYPE_PCM, 0, -1); |
1301 | if (evoice == NULL) | 1323 | if (evoice == NULL) |
1302 | return -ENOMEM; | 1324 | return -ENOMEM; |
1303 | pvoice->extra = evoice; | 1325 | pvoice->extra = evoice; |
@@ -1328,13 +1350,13 @@ static int snd_ali_playback_hw_free(snd_pcm_substream_t * substream) | |||
1328 | return 0; | 1350 | return 0; |
1329 | } | 1351 | } |
1330 | 1352 | ||
1331 | static int snd_ali_capture_hw_params(snd_pcm_substream_t * substream, | 1353 | static int snd_ali_hw_params(snd_pcm_substream_t * substream, |
1332 | snd_pcm_hw_params_t * hw_params) | 1354 | snd_pcm_hw_params_t * hw_params) |
1333 | { | 1355 | { |
1334 | return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); | 1356 | return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); |
1335 | } | 1357 | } |
1336 | 1358 | ||
1337 | static int snd_ali_capture_hw_free(snd_pcm_substream_t * substream) | 1359 | static int snd_ali_hw_free(snd_pcm_substream_t * substream) |
1338 | { | 1360 | { |
1339 | return snd_pcm_lib_free_pages(substream); | 1361 | return snd_pcm_lib_free_pages(substream); |
1340 | } | 1362 | } |
@@ -1428,7 +1450,7 @@ static int snd_ali_playback_prepare(snd_pcm_substream_t * substream) | |||
1428 | } | 1450 | } |
1429 | 1451 | ||
1430 | 1452 | ||
1431 | static int snd_ali_capture_prepare(snd_pcm_substream_t * substream) | 1453 | static int snd_ali_prepare(snd_pcm_substream_t * substream) |
1432 | { | 1454 | { |
1433 | ali_t *codec = snd_pcm_substream_chip(substream); | 1455 | ali_t *codec = snd_pcm_substream_chip(substream); |
1434 | snd_pcm_runtime_t *runtime = substream->runtime; | 1456 | snd_pcm_runtime_t *runtime = substream->runtime; |
@@ -1446,11 +1468,13 @@ static int snd_ali_capture_prepare(snd_pcm_substream_t * substream) | |||
1446 | 1468 | ||
1447 | spin_lock_irqsave(&codec->reg_lock, flags); | 1469 | spin_lock_irqsave(&codec->reg_lock, flags); |
1448 | 1470 | ||
1449 | snd_ali_printk("capture_prepare...\n"); | 1471 | snd_ali_printk("ali_prepare...\n"); |
1450 | 1472 | ||
1451 | snd_ali_enable_special_channel(codec,pvoice->number); | 1473 | snd_ali_enable_special_channel(codec,pvoice->number); |
1452 | 1474 | ||
1453 | Delta = snd_ali_convert_rate(runtime->rate, 1); | 1475 | Delta = (pvoice->number == ALI_MODEM_IN_CHANNEL || |
1476 | pvoice->number == ALI_MODEM_OUT_CHANNEL) ? | ||
1477 | 0x1000 : snd_ali_convert_rate(runtime->rate, pvoice->mode); | ||
1454 | 1478 | ||
1455 | // Prepare capture intr channel | 1479 | // Prepare capture intr channel |
1456 | if (pvoice->number == ALI_SPDIF_IN_CHANNEL) { | 1480 | if (pvoice->number == ALI_SPDIF_IN_CHANNEL) { |
@@ -1534,7 +1558,7 @@ static snd_pcm_uframes_t snd_ali_playback_pointer(snd_pcm_substream_t *substream | |||
1534 | } | 1558 | } |
1535 | 1559 | ||
1536 | 1560 | ||
1537 | static snd_pcm_uframes_t snd_ali_capture_pointer(snd_pcm_substream_t *substream) | 1561 | static snd_pcm_uframes_t snd_ali_pointer(snd_pcm_substream_t *substream) |
1538 | { | 1562 | { |
1539 | ali_t *codec = snd_pcm_substream_chip(substream); | 1563 | ali_t *codec = snd_pcm_substream_chip(substream); |
1540 | snd_pcm_runtime_t *runtime = substream->runtime; | 1564 | snd_pcm_runtime_t *runtime = substream->runtime; |
@@ -1616,7 +1640,8 @@ static void snd_ali_pcm_free_substream(snd_pcm_runtime_t *runtime) | |||
1616 | } | 1640 | } |
1617 | } | 1641 | } |
1618 | 1642 | ||
1619 | static int snd_ali_playback_open(snd_pcm_substream_t * substream) | 1643 | static int snd_ali_open(snd_pcm_substream_t * substream, int rec, int channel, |
1644 | snd_pcm_hardware_t *phw) | ||
1620 | { | 1645 | { |
1621 | ali_t *codec = snd_pcm_substream_chip(substream); | 1646 | ali_t *codec = snd_pcm_substream_chip(substream); |
1622 | snd_pcm_runtime_t *runtime = substream->runtime; | 1647 | snd_pcm_runtime_t *runtime = substream->runtime; |
@@ -1624,7 +1649,7 @@ static int snd_ali_playback_open(snd_pcm_substream_t * substream) | |||
1624 | unsigned long flags = 0; | 1649 | unsigned long flags = 0; |
1625 | 1650 | ||
1626 | spin_lock_irqsave(&codec->reg_lock, flags); | 1651 | spin_lock_irqsave(&codec->reg_lock, flags); |
1627 | pvoice = snd_ali_alloc_voice(codec, SNDRV_ALI_VOICE_TYPE_PCM, 0); | 1652 | pvoice = snd_ali_alloc_voice(codec, SNDRV_ALI_VOICE_TYPE_PCM, rec, channel); |
1628 | if (pvoice == NULL) { | 1653 | if (pvoice == NULL) { |
1629 | spin_unlock_irqrestore(&codec->reg_lock, flags); | 1654 | spin_unlock_irqrestore(&codec->reg_lock, flags); |
1630 | return -EAGAIN; | 1655 | return -EAGAIN; |
@@ -1636,49 +1661,31 @@ static int snd_ali_playback_open(snd_pcm_substream_t * substream) | |||
1636 | runtime->private_data = pvoice; | 1661 | runtime->private_data = pvoice; |
1637 | runtime->private_free = snd_ali_pcm_free_substream; | 1662 | runtime->private_free = snd_ali_pcm_free_substream; |
1638 | 1663 | ||
1639 | runtime->hw = snd_ali_playback; | 1664 | runtime->hw = *phw; |
1640 | snd_pcm_set_sync(substream); | 1665 | snd_pcm_set_sync(substream); |
1641 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 64*1024); | 1666 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 64*1024); |
1642 | return 0; | 1667 | return 0; |
1643 | } | 1668 | } |
1644 | 1669 | ||
1670 | static int snd_ali_playback_open(snd_pcm_substream_t * substream) | ||
1671 | { | ||
1672 | return snd_ali_open(substream, 0, -1, &snd_ali_playback); | ||
1673 | } | ||
1645 | 1674 | ||
1646 | static int snd_ali_capture_open(snd_pcm_substream_t * substream) | 1675 | static int snd_ali_capture_open(snd_pcm_substream_t * substream) |
1647 | { | 1676 | { |
1648 | ali_t *codec = snd_pcm_substream_chip(substream); | 1677 | return snd_ali_open(substream, 1, -1, &snd_ali_capture); |
1649 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
1650 | snd_ali_voice_t *pvoice; | ||
1651 | unsigned long flags; | ||
1652 | |||
1653 | spin_lock_irqsave(&codec->reg_lock, flags); | ||
1654 | pvoice = snd_ali_alloc_voice(codec, SNDRV_ALI_VOICE_TYPE_PCM, 1); | ||
1655 | if (pvoice == NULL) { | ||
1656 | spin_unlock_irqrestore(&codec->reg_lock, flags); | ||
1657 | return -EAGAIN; | ||
1658 | } | ||
1659 | pvoice->codec = codec; | ||
1660 | spin_unlock_irqrestore(&codec->reg_lock, flags); | ||
1661 | |||
1662 | pvoice->substream = substream; | ||
1663 | runtime->private_data = pvoice; | ||
1664 | runtime->private_free = snd_ali_pcm_free_substream; | ||
1665 | runtime->hw = snd_ali_capture; | ||
1666 | snd_pcm_set_sync(substream); | ||
1667 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 64*1024); | ||
1668 | return 0; | ||
1669 | } | 1678 | } |
1670 | 1679 | ||
1671 | |||
1672 | static int snd_ali_playback_close(snd_pcm_substream_t * substream) | 1680 | static int snd_ali_playback_close(snd_pcm_substream_t * substream) |
1673 | { | 1681 | { |
1674 | return 0; | 1682 | return 0; |
1675 | } | 1683 | } |
1676 | 1684 | ||
1677 | static int snd_ali_capture_close(snd_pcm_substream_t * substream) | 1685 | static int snd_ali_close(snd_pcm_substream_t * substream) |
1678 | { | 1686 | { |
1679 | ali_t *codec = snd_pcm_substream_chip(substream); | 1687 | ali_t *codec = snd_pcm_substream_chip(substream); |
1680 | snd_pcm_runtime_t *runtime = substream->runtime; | 1688 | snd_ali_voice_t *pvoice = (snd_ali_voice_t *) substream->runtime->private_data; |
1681 | snd_ali_voice_t *pvoice = (snd_ali_voice_t *) runtime->private_data; | ||
1682 | 1689 | ||
1683 | snd_ali_disable_special_channel(codec,pvoice->number); | 1690 | snd_ali_disable_special_channel(codec,pvoice->number); |
1684 | 1691 | ||
@@ -1698,29 +1705,121 @@ static snd_pcm_ops_t snd_ali_playback_ops = { | |||
1698 | 1705 | ||
1699 | static snd_pcm_ops_t snd_ali_capture_ops = { | 1706 | static snd_pcm_ops_t snd_ali_capture_ops = { |
1700 | .open = snd_ali_capture_open, | 1707 | .open = snd_ali_capture_open, |
1701 | .close = snd_ali_capture_close, | 1708 | .close = snd_ali_close, |
1702 | .ioctl = snd_ali_ioctl, | 1709 | .ioctl = snd_ali_ioctl, |
1703 | .hw_params = snd_ali_capture_hw_params, | 1710 | .hw_params = snd_ali_hw_params, |
1704 | .hw_free = snd_ali_capture_hw_free, | 1711 | .hw_free = snd_ali_hw_free, |
1705 | .prepare = snd_ali_capture_prepare, | 1712 | .prepare = snd_ali_prepare, |
1713 | .trigger = snd_ali_trigger, | ||
1714 | .pointer = snd_ali_pointer, | ||
1715 | }; | ||
1716 | |||
1717 | /* | ||
1718 | * Modem PCM | ||
1719 | */ | ||
1720 | |||
1721 | static int snd_ali_modem_hw_params(snd_pcm_substream_t * substream, | ||
1722 | snd_pcm_hw_params_t * hw_params) | ||
1723 | { | ||
1724 | ali_t *chip = snd_pcm_substream_chip(substream); | ||
1725 | unsigned int modem_num = chip->num_of_codecs - 1; | ||
1726 | snd_ac97_write(chip->ac97[modem_num], AC97_LINE1_RATE, params_rate(hw_params)); | ||
1727 | snd_ac97_write(chip->ac97[modem_num], AC97_LINE1_LEVEL, 0); | ||
1728 | return snd_ali_hw_params(substream, hw_params); | ||
1729 | } | ||
1730 | |||
1731 | static snd_pcm_hardware_t snd_ali_modem = | ||
1732 | { | ||
1733 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | ||
1734 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
1735 | SNDRV_PCM_INFO_MMAP_VALID | | ||
1736 | SNDRV_PCM_INFO_RESUME | | ||
1737 | SNDRV_PCM_INFO_SYNC_START), | ||
1738 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
1739 | .rates = SNDRV_PCM_RATE_KNOT|SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000, | ||
1740 | .rate_min = 8000, | ||
1741 | .rate_max = 16000, | ||
1742 | .channels_min = 1, | ||
1743 | .channels_max = 1, | ||
1744 | .buffer_bytes_max = (256*1024), | ||
1745 | .period_bytes_min = 64, | ||
1746 | .period_bytes_max = (256*1024), | ||
1747 | .periods_min = 1, | ||
1748 | .periods_max = 1024, | ||
1749 | .fifo_size = 0, | ||
1750 | }; | ||
1751 | |||
1752 | static int snd_ali_modem_open(snd_pcm_substream_t * substream, int rec, int channel) | ||
1753 | { | ||
1754 | static unsigned int rates [] = {8000,9600,12000,16000}; | ||
1755 | static snd_pcm_hw_constraint_list_t hw_constraint_rates = { | ||
1756 | .count = ARRAY_SIZE(rates), | ||
1757 | .list = rates, | ||
1758 | .mask = 0, | ||
1759 | }; | ||
1760 | int err = snd_ali_open(substream, rec, channel, &snd_ali_modem); | ||
1761 | if (err) | ||
1762 | return err; | ||
1763 | return snd_pcm_hw_constraint_list(substream->runtime, 0, | ||
1764 | SNDRV_PCM_HW_PARAM_RATE, &hw_constraint_rates); | ||
1765 | } | ||
1766 | |||
1767 | static int snd_ali_modem_playback_open(snd_pcm_substream_t * substream) | ||
1768 | { | ||
1769 | return snd_ali_modem_open(substream, 0, ALI_MODEM_OUT_CHANNEL); | ||
1770 | } | ||
1771 | |||
1772 | static int snd_ali_modem_capture_open(snd_pcm_substream_t * substream) | ||
1773 | { | ||
1774 | return snd_ali_modem_open(substream, 1, ALI_MODEM_IN_CHANNEL); | ||
1775 | } | ||
1776 | |||
1777 | static snd_pcm_ops_t snd_ali_modem_playback_ops = { | ||
1778 | .open = snd_ali_modem_playback_open, | ||
1779 | .close = snd_ali_close, | ||
1780 | .ioctl = snd_pcm_lib_ioctl, | ||
1781 | .hw_params = snd_ali_modem_hw_params, | ||
1782 | .hw_free = snd_ali_hw_free, | ||
1783 | .prepare = snd_ali_prepare, | ||
1784 | .trigger = snd_ali_trigger, | ||
1785 | .pointer = snd_ali_pointer, | ||
1786 | }; | ||
1787 | |||
1788 | static snd_pcm_ops_t snd_ali_modem_capture_ops = { | ||
1789 | .open = snd_ali_modem_capture_open, | ||
1790 | .close = snd_ali_close, | ||
1791 | .ioctl = snd_pcm_lib_ioctl, | ||
1792 | .hw_params = snd_ali_modem_hw_params, | ||
1793 | .hw_free = snd_ali_hw_free, | ||
1794 | .prepare = snd_ali_prepare, | ||
1706 | .trigger = snd_ali_trigger, | 1795 | .trigger = snd_ali_trigger, |
1707 | .pointer = snd_ali_capture_pointer, | 1796 | .pointer = snd_ali_pointer, |
1797 | }; | ||
1798 | |||
1799 | |||
1800 | struct ali_pcm_description { | ||
1801 | char *name; | ||
1802 | unsigned int playback_num; | ||
1803 | unsigned int capture_num; | ||
1804 | snd_pcm_ops_t *playback_ops; | ||
1805 | snd_pcm_ops_t *capture_ops; | ||
1708 | }; | 1806 | }; |
1709 | 1807 | ||
1710 | 1808 | ||
1711 | static void snd_ali_pcm_free(snd_pcm_t *pcm) | 1809 | static void snd_ali_pcm_free(snd_pcm_t *pcm) |
1712 | { | 1810 | { |
1713 | ali_t *codec = pcm->private_data; | 1811 | ali_t *codec = pcm->private_data; |
1714 | codec->pcm = NULL; | 1812 | codec->pcm[pcm->device] = NULL; |
1715 | } | 1813 | } |
1716 | 1814 | ||
1717 | static int __devinit snd_ali_pcm(ali_t * codec, int device, snd_pcm_t ** rpcm) | 1815 | |
1816 | static int __devinit snd_ali_pcm(ali_t * codec, int device, struct ali_pcm_description *desc) | ||
1718 | { | 1817 | { |
1719 | snd_pcm_t *pcm; | 1818 | snd_pcm_t *pcm; |
1720 | int err; | 1819 | int err; |
1721 | 1820 | ||
1722 | if (rpcm) *rpcm = NULL; | 1821 | err = snd_pcm_new(codec->card, desc->name, device, |
1723 | err = snd_pcm_new(codec->card, "ALI 5451", device, ALI_CHANNELS, 1, &pcm); | 1822 | desc->playback_num, desc->capture_num, &pcm); |
1724 | if (err < 0) { | 1823 | if (err < 0) { |
1725 | snd_printk("snd_ali_pcm: err called snd_pcm_new.\n"); | 1824 | snd_printk("snd_ali_pcm: err called snd_pcm_new.\n"); |
1726 | return err; | 1825 | return err; |
@@ -1728,20 +1827,36 @@ static int __devinit snd_ali_pcm(ali_t * codec, int device, snd_pcm_t ** rpcm) | |||
1728 | pcm->private_data = codec; | 1827 | pcm->private_data = codec; |
1729 | pcm->private_free = snd_ali_pcm_free; | 1828 | pcm->private_free = snd_ali_pcm_free; |
1730 | pcm->info_flags = 0; | 1829 | pcm->info_flags = 0; |
1731 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ali_playback_ops); | 1830 | if (desc->playback_ops) |
1732 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ali_capture_ops); | 1831 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, desc->playback_ops); |
1832 | if (desc->capture_ops) | ||
1833 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, desc->capture_ops); | ||
1733 | 1834 | ||
1734 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, | 1835 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, |
1735 | snd_dma_pci_data(codec->pci), 64*1024, 128*1024); | 1836 | snd_dma_pci_data(codec->pci), 64*1024, 128*1024); |
1736 | 1837 | ||
1737 | pcm->info_flags = 0; | 1838 | pcm->info_flags = 0; |
1738 | pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; | 1839 | pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; |
1739 | strcpy(pcm->name, "ALI 5451"); | 1840 | strcpy(pcm->name, desc->name); |
1740 | codec->pcm = pcm; | 1841 | codec->pcm[0] = pcm; |
1741 | if (rpcm) *rpcm = pcm; | ||
1742 | return 0; | 1842 | return 0; |
1743 | } | 1843 | } |
1744 | 1844 | ||
1845 | struct ali_pcm_description ali_pcms[] = { | ||
1846 | { "ALI 5451", ALI_CHANNELS, 1, &snd_ali_playback_ops, &snd_ali_capture_ops }, | ||
1847 | { "ALI 5451 modem", 1, 1, &snd_ali_modem_playback_ops, &snd_ali_modem_capture_ops } | ||
1848 | }; | ||
1849 | |||
1850 | static int __devinit snd_ali_build_pcms(ali_t *codec) | ||
1851 | { | ||
1852 | int i, err; | ||
1853 | for(i = 0 ; i < codec->num_of_codecs && i < ARRAY_SIZE(ali_pcms) ; i++) | ||
1854 | if((err = snd_ali_pcm(codec, i, &ali_pcms[i])) < 0) | ||
1855 | return err; | ||
1856 | return 0; | ||
1857 | } | ||
1858 | |||
1859 | |||
1745 | #define ALI5451_SPDIF(xname, xindex, value) \ | 1860 | #define ALI5451_SPDIF(xname, xindex, value) \ |
1746 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\ | 1861 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\ |
1747 | .info = snd_ali5451_spdif_info, .get = snd_ali5451_spdif_get, \ | 1862 | .info = snd_ali5451_spdif_info, .get = snd_ali5451_spdif_get, \ |
@@ -1860,14 +1975,14 @@ static void snd_ali_mixer_free_ac97_bus(ac97_bus_t *bus) | |||
1860 | static void snd_ali_mixer_free_ac97(ac97_t *ac97) | 1975 | static void snd_ali_mixer_free_ac97(ac97_t *ac97) |
1861 | { | 1976 | { |
1862 | ali_t *codec = ac97->private_data; | 1977 | ali_t *codec = ac97->private_data; |
1863 | codec->ac97 = NULL; | 1978 | codec->ac97[ac97->num] = NULL; |
1864 | } | 1979 | } |
1865 | 1980 | ||
1866 | static int __devinit snd_ali_mixer(ali_t * codec) | 1981 | static int __devinit snd_ali_mixer(ali_t * codec) |
1867 | { | 1982 | { |
1868 | ac97_template_t ac97; | 1983 | ac97_template_t ac97; |
1869 | unsigned int idx; | 1984 | unsigned int idx; |
1870 | int err; | 1985 | int i, err; |
1871 | static ac97_bus_ops_t ops = { | 1986 | static ac97_bus_ops_t ops = { |
1872 | .write = snd_ali_codec_write, | 1987 | .write = snd_ali_codec_write, |
1873 | .read = snd_ali_codec_read, | 1988 | .read = snd_ali_codec_read, |
@@ -1880,10 +1995,16 @@ static int __devinit snd_ali_mixer(ali_t * codec) | |||
1880 | memset(&ac97, 0, sizeof(ac97)); | 1995 | memset(&ac97, 0, sizeof(ac97)); |
1881 | ac97.private_data = codec; | 1996 | ac97.private_data = codec; |
1882 | ac97.private_free = snd_ali_mixer_free_ac97; | 1997 | ac97.private_free = snd_ali_mixer_free_ac97; |
1883 | if ((err = snd_ac97_mixer(codec->ac97_bus, &ac97, &codec->ac97)) < 0) { | 1998 | |
1884 | snd_printk("ali mixer creating error.\n"); | 1999 | for ( i = 0 ; i < codec->num_of_codecs ; i++) { |
2000 | ac97.num = i; | ||
2001 | if ((err = snd_ac97_mixer(codec->ac97_bus, &ac97, &codec->ac97[i])) < 0) { | ||
2002 | snd_printk("ali mixer %d creating error.\n", i); | ||
2003 | if(i == 0) | ||
1885 | return err; | 2004 | return err; |
1886 | } | 2005 | } |
2006 | } | ||
2007 | |||
1887 | if (codec->spdif_support) { | 2008 | if (codec->spdif_support) { |
1888 | for(idx = 0; idx < ARRAY_SIZE(snd_ali5451_mixer_spdif); idx++) { | 2009 | for(idx = 0; idx < ARRAY_SIZE(snd_ali5451_mixer_spdif); idx++) { |
1889 | err=snd_ctl_add(codec->card, snd_ctl_new1(&snd_ali5451_mixer_spdif[idx], codec)); | 2010 | err=snd_ctl_add(codec->card, snd_ctl_new1(&snd_ali5451_mixer_spdif[idx], codec)); |
@@ -1904,8 +2025,12 @@ static int ali_suspend(snd_card_t *card, pm_message_t state) | |||
1904 | if (! im) | 2025 | if (! im) |
1905 | return 0; | 2026 | return 0; |
1906 | 2027 | ||
1907 | snd_pcm_suspend_all(chip->pcm); | 2028 | for(i = 0 ; i < chip->num_of_codecs ; i++) { |
1908 | snd_ac97_suspend(chip->ac97); | 2029 | if (chip->pcm[i]) |
2030 | snd_pcm_suspend_all(chip->pcm[i]); | ||
2031 | if(chip->ac97[i]) | ||
2032 | snd_ac97_suspend(chip->ac97[i]); | ||
2033 | } | ||
1909 | 2034 | ||
1910 | spin_lock_irq(&chip->reg_lock); | 2035 | spin_lock_irq(&chip->reg_lock); |
1911 | 2036 | ||
@@ -1969,7 +2094,9 @@ static int ali_resume(snd_card_t *card) | |||
1969 | 2094 | ||
1970 | spin_unlock_irq(&chip->reg_lock); | 2095 | spin_unlock_irq(&chip->reg_lock); |
1971 | 2096 | ||
1972 | snd_ac97_resume(chip->ac97); | 2097 | for(i = 0 ; i < chip->num_of_codecs ; i++) |
2098 | if(chip->ac97[i]) | ||
2099 | snd_ac97_resume(chip->ac97[i]); | ||
1973 | 2100 | ||
1974 | return 0; | 2101 | return 0; |
1975 | } | 2102 | } |
@@ -2036,11 +2163,37 @@ static int snd_ali_chip_init(ali_t *codec) | |||
2036 | codec->spdif_mask = 0x00000002; | 2163 | codec->spdif_mask = 0x00000002; |
2037 | } | 2164 | } |
2038 | 2165 | ||
2166 | codec->num_of_codecs = 1; | ||
2167 | |||
2168 | /* secondary codec - modem */ | ||
2169 | if (inl(ALI_REG(codec, ALI_SCTRL)) & ALI_SCTRL_CODEC2_READY) { | ||
2170 | codec->num_of_codecs++; | ||
2171 | outl(inl(ALI_REG(codec, ALI_SCTRL)) | | ||
2172 | (ALI_SCTRL_LINE_IN2|ALI_SCTRL_GPIO_IN2|ALI_SCTRL_LINE_OUT_EN), | ||
2173 | ALI_REG(codec, ALI_SCTRL)); | ||
2174 | } | ||
2175 | |||
2039 | snd_ali_printk("chip initialize succeed.\n"); | 2176 | snd_ali_printk("chip initialize succeed.\n"); |
2040 | return 0; | 2177 | return 0; |
2041 | 2178 | ||
2042 | } | 2179 | } |
2043 | 2180 | ||
2181 | /* proc for register dump */ | ||
2182 | static void snd_ali_proc_read(snd_info_entry_t *entry, snd_info_buffer_t *buf) | ||
2183 | { | ||
2184 | ali_t *codec = entry->private_data; | ||
2185 | int i; | ||
2186 | for(i = 0 ; i < 256 ; i+= 4) | ||
2187 | snd_iprintf(buf, "%02x: %08x\n", i, inl(ALI_REG(codec, i))); | ||
2188 | } | ||
2189 | |||
2190 | static void __devinit snd_ali_proc_init(ali_t *codec) | ||
2191 | { | ||
2192 | snd_info_entry_t *entry; | ||
2193 | if(!snd_card_proc_new(codec->card, "ali5451", &entry)) | ||
2194 | snd_info_set_text_ops(entry, codec, 1024, snd_ali_proc_read); | ||
2195 | } | ||
2196 | |||
2044 | static int __devinit snd_ali_resources(ali_t *codec) | 2197 | static int __devinit snd_ali_resources(ali_t *codec) |
2045 | { | 2198 | { |
2046 | int err; | 2199 | int err; |
@@ -2233,11 +2386,13 @@ static int __devinit snd_ali_probe(struct pci_dev *pci, | |||
2233 | } | 2386 | } |
2234 | 2387 | ||
2235 | snd_ali_printk("pcm building ...\n"); | 2388 | snd_ali_printk("pcm building ...\n"); |
2236 | if ((err = snd_ali_pcm(codec, 0, NULL)) < 0) { | 2389 | if ((err = snd_ali_build_pcms(codec)) < 0) { |
2237 | snd_card_free(card); | 2390 | snd_card_free(card); |
2238 | return err; | 2391 | return err; |
2239 | } | 2392 | } |
2240 | 2393 | ||
2394 | snd_ali_proc_init(codec); | ||
2395 | |||
2241 | strcpy(card->driver, "ALI5451"); | 2396 | strcpy(card->driver, "ALI5451"); |
2242 | strcpy(card->shortname, "ALI 5451"); | 2397 | strcpy(card->shortname, "ALI 5451"); |
2243 | 2398 | ||
@@ -2270,7 +2425,7 @@ static struct pci_driver driver = { | |||
2270 | 2425 | ||
2271 | static int __init alsa_card_ali_init(void) | 2426 | static int __init alsa_card_ali_init(void) |
2272 | { | 2427 | { |
2273 | return pci_module_init(&driver); | 2428 | return pci_register_driver(&driver); |
2274 | } | 2429 | } |
2275 | 2430 | ||
2276 | static void __exit alsa_card_ali_exit(void) | 2431 | static void __exit alsa_card_ali_exit(void) |
diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c index f1a5f5723ee6..ca28b229c704 100644 --- a/sound/pci/als4000.c +++ b/sound/pci/als4000.c | |||
@@ -367,7 +367,7 @@ static irqreturn_t snd_als4000_interrupt(int irq, void *dev_id, struct pt_regs * | |||
367 | if ((gcr_status & 0x40) && (chip->capture_substream)) /* capturing */ | 367 | if ((gcr_status & 0x40) && (chip->capture_substream)) /* capturing */ |
368 | snd_pcm_period_elapsed(chip->capture_substream); | 368 | snd_pcm_period_elapsed(chip->capture_substream); |
369 | if ((gcr_status & 0x10) && (chip->rmidi)) /* MPU401 interrupt */ | 369 | if ((gcr_status & 0x10) && (chip->rmidi)) /* MPU401 interrupt */ |
370 | snd_mpu401_uart_interrupt(irq, chip->rmidi, regs); | 370 | snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs); |
371 | /* release the gcr */ | 371 | /* release the gcr */ |
372 | outb(gcr_status, chip->alt_port + 0xe); | 372 | outb(gcr_status, chip->alt_port + 0xe); |
373 | 373 | ||
@@ -777,7 +777,7 @@ static struct pci_driver driver = { | |||
777 | 777 | ||
778 | static int __init alsa_card_als4000_init(void) | 778 | static int __init alsa_card_als4000_init(void) |
779 | { | 779 | { |
780 | return pci_module_init(&driver); | 780 | return pci_register_driver(&driver); |
781 | } | 781 | } |
782 | 782 | ||
783 | static void __exit alsa_card_als4000_exit(void) | 783 | static void __exit alsa_card_als4000_exit(void) |
diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index 6b04c0acc6f7..cafab4af5c57 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c | |||
@@ -1334,8 +1334,8 @@ static irqreturn_t snd_atiixp_interrupt(int irq, void *dev_id, struct pt_regs *r | |||
1334 | 1334 | ||
1335 | static struct ac97_quirk ac97_quirks[] __devinitdata = { | 1335 | static struct ac97_quirk ac97_quirks[] __devinitdata = { |
1336 | { | 1336 | { |
1337 | .vendor = 0x103c, | 1337 | .subvendor = 0x103c, |
1338 | .device = 0x006b, | 1338 | .subdevice = 0x006b, |
1339 | .name = "HP Pavilion ZV5030US", | 1339 | .name = "HP Pavilion ZV5030US", |
1340 | .type = AC97_TUNE_MUTE_LED | 1340 | .type = AC97_TUNE_MUTE_LED |
1341 | }, | 1341 | }, |
@@ -1645,7 +1645,7 @@ static struct pci_driver driver = { | |||
1645 | 1645 | ||
1646 | static int __init alsa_card_atiixp_init(void) | 1646 | static int __init alsa_card_atiixp_init(void) |
1647 | { | 1647 | { |
1648 | return pci_module_init(&driver); | 1648 | return pci_register_driver(&driver); |
1649 | } | 1649 | } |
1650 | 1650 | ||
1651 | static void __exit alsa_card_atiixp_exit(void) | 1651 | static void __exit alsa_card_atiixp_exit(void) |
diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c index fb7cecea846d..a6b4b8d589fd 100644 --- a/sound/pci/atiixp_modem.c +++ b/sound/pci/atiixp_modem.c | |||
@@ -463,6 +463,11 @@ static unsigned short snd_atiixp_ac97_read(ac97_t *ac97, unsigned short reg) | |||
463 | static void snd_atiixp_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short val) | 463 | static void snd_atiixp_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short val) |
464 | { | 464 | { |
465 | atiixp_t *chip = ac97->private_data; | 465 | atiixp_t *chip = ac97->private_data; |
466 | if (reg == AC97_GPIO_STATUS) { | ||
467 | atiixp_write(chip, MODEM_OUT_GPIO, | ||
468 | (val << ATI_REG_MODEM_OUT_GPIO_DATA_SHIFT) | ATI_REG_MODEM_OUT_GPIO_EN); | ||
469 | return; | ||
470 | } | ||
466 | snd_atiixp_codec_write(chip, ac97->num, reg, val); | 471 | snd_atiixp_codec_write(chip, ac97->num, reg, val); |
467 | } | 472 | } |
468 | 473 | ||
@@ -663,44 +668,33 @@ static int snd_atiixp_pcm_trigger(snd_pcm_substream_t *substream, int cmd) | |||
663 | { | 668 | { |
664 | atiixp_t *chip = snd_pcm_substream_chip(substream); | 669 | atiixp_t *chip = snd_pcm_substream_chip(substream); |
665 | atiixp_dma_t *dma = (atiixp_dma_t *)substream->runtime->private_data; | 670 | atiixp_dma_t *dma = (atiixp_dma_t *)substream->runtime->private_data; |
666 | unsigned int reg = 0; | 671 | int err = 0; |
667 | int i; | ||
668 | 672 | ||
669 | snd_assert(dma->ops->enable_transfer && dma->ops->flush_dma, return -EINVAL); | 673 | snd_assert(dma->ops->enable_transfer && dma->ops->flush_dma, return -EINVAL); |
670 | 674 | ||
671 | if (cmd != SNDRV_PCM_TRIGGER_START && cmd != SNDRV_PCM_TRIGGER_STOP) | ||
672 | return -EINVAL; | ||
673 | |||
674 | spin_lock(&chip->reg_lock); | 675 | spin_lock(&chip->reg_lock); |
675 | 676 | switch(cmd) { | |
676 | /* hook off/on: via GPIO_OUT */ | 677 | case SNDRV_PCM_TRIGGER_START: |
677 | for (i = 0; i < NUM_ATI_CODECS; i++) { | ||
678 | if (chip->ac97[i]) { | ||
679 | reg = snd_ac97_read(chip->ac97[i], AC97_GPIO_STATUS); | ||
680 | break; | ||
681 | } | ||
682 | } | ||
683 | if(cmd == SNDRV_PCM_TRIGGER_START) | ||
684 | reg |= AC97_GPIO_LINE1_OH; | ||
685 | else | ||
686 | reg &= ~AC97_GPIO_LINE1_OH; | ||
687 | reg = (reg << ATI_REG_MODEM_OUT_GPIO_DATA_SHIFT) | ATI_REG_MODEM_OUT_GPIO_EN ; | ||
688 | atiixp_write(chip, MODEM_OUT_GPIO, reg); | ||
689 | |||
690 | if (cmd == SNDRV_PCM_TRIGGER_START) { | ||
691 | dma->ops->enable_transfer(chip, 1); | 678 | dma->ops->enable_transfer(chip, 1); |
692 | dma->running = 1; | 679 | dma->running = 1; |
693 | } else { | 680 | break; |
681 | case SNDRV_PCM_TRIGGER_STOP: | ||
694 | dma->ops->enable_transfer(chip, 0); | 682 | dma->ops->enable_transfer(chip, 0); |
695 | dma->running = 0; | 683 | dma->running = 0; |
684 | break; | ||
685 | default: | ||
686 | err = -EINVAL; | ||
687 | break; | ||
696 | } | 688 | } |
689 | if (! err) { | ||
697 | snd_atiixp_check_bus_busy(chip); | 690 | snd_atiixp_check_bus_busy(chip); |
698 | if (cmd == SNDRV_PCM_TRIGGER_STOP) { | 691 | if (cmd == SNDRV_PCM_TRIGGER_STOP) { |
699 | dma->ops->flush_dma(chip); | 692 | dma->ops->flush_dma(chip); |
700 | snd_atiixp_check_bus_busy(chip); | 693 | snd_atiixp_check_bus_busy(chip); |
701 | } | 694 | } |
695 | } | ||
702 | spin_unlock(&chip->reg_lock); | 696 | spin_unlock(&chip->reg_lock); |
703 | return 0; | 697 | return err; |
704 | } | 698 | } |
705 | 699 | ||
706 | 700 | ||
@@ -1332,7 +1326,7 @@ static struct pci_driver driver = { | |||
1332 | 1326 | ||
1333 | static int __init alsa_card_atiixp_init(void) | 1327 | static int __init alsa_card_atiixp_init(void) |
1334 | { | 1328 | { |
1335 | return pci_module_init(&driver); | 1329 | return pci_register_driver(&driver); |
1336 | } | 1330 | } |
1337 | 1331 | ||
1338 | static void __exit alsa_card_atiixp_exit(void) | 1332 | static void __exit alsa_card_atiixp_exit(void) |
diff --git a/sound/pci/au88x0/au88x0.c b/sound/pci/au88x0/au88x0.c index 889b4a1a51a1..f6236c63aaaa 100644 --- a/sound/pci/au88x0/au88x0.c +++ b/sound/pci/au88x0/au88x0.c | |||
@@ -375,7 +375,7 @@ static struct pci_driver driver = { | |||
375 | // initialization of the module | 375 | // initialization of the module |
376 | static int __init alsa_card_vortex_init(void) | 376 | static int __init alsa_card_vortex_init(void) |
377 | { | 377 | { |
378 | return pci_module_init(&driver); | 378 | return pci_register_driver(&driver); |
379 | } | 379 | } |
380 | 380 | ||
381 | // clean up the module | 381 | // clean up the module |
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index b8ae534125c1..72bba7b2d983 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c | |||
@@ -1520,7 +1520,7 @@ static int __init alsa_card_azf3328_init(void) | |||
1520 | { | 1520 | { |
1521 | int err; | 1521 | int err; |
1522 | snd_azf3328_dbgcallenter(); | 1522 | snd_azf3328_dbgcallenter(); |
1523 | err = pci_module_init(&driver); | 1523 | err = pci_register_driver(&driver); |
1524 | snd_azf3328_dbgcallleave(); | 1524 | snd_azf3328_dbgcallleave(); |
1525 | return err; | 1525 | return err; |
1526 | } | 1526 | } |
diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c index 89a7ffe5e7d7..defdc5a459f0 100644 --- a/sound/pci/bt87x.c +++ b/sound/pci/bt87x.c | |||
@@ -918,7 +918,7 @@ static int __init alsa_card_bt87x_init(void) | |||
918 | { | 918 | { |
919 | if (load_all) | 919 | if (load_all) |
920 | driver.id_table = snd_bt87x_default_ids; | 920 | driver.id_table = snd_bt87x_default_ids; |
921 | return pci_module_init(&driver); | 921 | return pci_register_driver(&driver); |
922 | } | 922 | } |
923 | 923 | ||
924 | static void __exit alsa_card_bt87x_exit(void) | 924 | static void __exit alsa_card_bt87x_exit(void) |
diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h index deb028851056..da09cab405a9 100644 --- a/sound/pci/ca0106/ca0106.h +++ b/sound/pci/ca0106/ca0106.h | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2004 James Courtier-Dutton <James@superbug.demon.co.uk> | 2 | * Copyright (c) 2004 James Courtier-Dutton <James@superbug.demon.co.uk> |
3 | * Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit | 3 | * Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit |
4 | * Version: 0.0.20 | 4 | * Version: 0.0.21 |
5 | * | 5 | * |
6 | * FEATURES currently supported: | 6 | * FEATURES currently supported: |
7 | * See ca0106_main.c for features. | 7 | * See ca0106_main.c for features. |
@@ -45,6 +45,8 @@ | |||
45 | * Added I2C and SPI registers. Filled in interrupt enable. | 45 | * Added I2C and SPI registers. Filled in interrupt enable. |
46 | * 0.0.20 | 46 | * 0.0.20 |
47 | * Added GPIO info for SB Live 24bit. | 47 | * Added GPIO info for SB Live 24bit. |
48 | * 0.0.21 | ||
49 | * Implement support for Line-in capture on SB Live 24bit. | ||
48 | * | 50 | * |
49 | * | 51 | * |
50 | * This code was initally based on code from ALSA's emu10k1x.c which is: | 52 | * This code was initally based on code from ALSA's emu10k1x.c which is: |
@@ -152,7 +154,7 @@ | |||
152 | * bit 9 0 = Mute / 1 = Analog out. | 154 | * bit 9 0 = Mute / 1 = Analog out. |
153 | * bit 10 0 = Line-in / 1 = Mic-in. | 155 | * bit 10 0 = Line-in / 1 = Mic-in. |
154 | * bit 11 0 = ? / 1 = ? | 156 | * bit 11 0 = ? / 1 = ? |
155 | * bit 12 0 = ? / 1 = ? | 157 | * bit 12 0 = 48 Khz / 1 = 96 Khz Analog out on SB Live 24bit. |
156 | * bit 13 0 = ? / 1 = ? | 158 | * bit 13 0 = ? / 1 = ? |
157 | * bit 14 0 = Mute / 1 = Analog out | 159 | * bit 14 0 = Mute / 1 = Analog out |
158 | * bit 15 0 = ? / 1 = ? | 160 | * bit 15 0 = ? / 1 = ? |
@@ -475,9 +477,56 @@ | |||
475 | /* Causes interrupts based on timer intervals. */ | 477 | /* Causes interrupts based on timer intervals. */ |
476 | #define SPI 0x7a /* SPI: Serial Interface Register */ | 478 | #define SPI 0x7a /* SPI: Serial Interface Register */ |
477 | #define I2C_A 0x7b /* I2C Address. 32 bit */ | 479 | #define I2C_A 0x7b /* I2C Address. 32 bit */ |
478 | #define I2C_0 0x7c /* I2C Data Port 0. 32 bit */ | 480 | #define I2C_D0 0x7c /* I2C Data Port 0. 32 bit */ |
479 | #define I2C_1 0x7d /* I2C Data Port 1. 32 bit */ | 481 | #define I2C_D1 0x7d /* I2C Data Port 1. 32 bit */ |
482 | //I2C values | ||
483 | #define I2C_A_ADC_ADD_MASK 0x000000fe //The address is a 7 bit address | ||
484 | #define I2C_A_ADC_RW_MASK 0x00000001 //bit mask for R/W | ||
485 | #define I2C_A_ADC_TRANS_MASK 0x00000010 //Bit mask for I2c address DAC value | ||
486 | #define I2C_A_ADC_ABORT_MASK 0x00000020 //Bit mask for I2C transaction abort flag | ||
487 | #define I2C_A_ADC_LAST_MASK 0x00000040 //Bit mask for Last word transaction | ||
488 | #define I2C_A_ADC_BYTE_MASK 0x00000080 //Bit mask for Byte Mode | ||
480 | 489 | ||
490 | #define I2C_A_ADC_ADD 0x00000034 //This is the Device address for ADC | ||
491 | #define I2C_A_ADC_READ 0x00000001 //To perform a read operation | ||
492 | #define I2C_A_ADC_START 0x00000100 //Start I2C transaction | ||
493 | #define I2C_A_ADC_ABORT 0x00000200 //I2C transaction abort | ||
494 | #define I2C_A_ADC_LAST 0x00000400 //I2C last transaction | ||
495 | #define I2C_A_ADC_BYTE 0x00000800 //I2C one byte mode | ||
496 | |||
497 | #define I2C_D_ADC_REG_MASK 0xfe000000 //ADC address register | ||
498 | #define I2C_D_ADC_DAT_MASK 0x01ff0000 //ADC data register | ||
499 | |||
500 | #define ADC_TIMEOUT 0x00000007 //ADC Timeout Clock Disable | ||
501 | #define ADC_IFC_CTRL 0x0000000b //ADC Interface Control | ||
502 | #define ADC_MASTER 0x0000000c //ADC Master Mode Control | ||
503 | #define ADC_POWER 0x0000000d //ADC PowerDown Control | ||
504 | #define ADC_ATTEN_ADCL 0x0000000e //ADC Attenuation ADCL | ||
505 | #define ADC_ATTEN_ADCR 0x0000000f //ADC Attenuation ADCR | ||
506 | #define ADC_ALC_CTRL1 0x00000010 //ADC ALC Control 1 | ||
507 | #define ADC_ALC_CTRL2 0x00000011 //ADC ALC Control 2 | ||
508 | #define ADC_ALC_CTRL3 0x00000012 //ADC ALC Control 3 | ||
509 | #define ADC_NOISE_CTRL 0x00000013 //ADC Noise Gate Control | ||
510 | #define ADC_LIMIT_CTRL 0x00000014 //ADC Limiter Control | ||
511 | #define ADC_MUX 0x00000015 //ADC Mux offset | ||
512 | |||
513 | #if 0 | ||
514 | /* FIXME: Not tested yet. */ | ||
515 | #define ADC_GAIN_MASK 0x000000ff //Mask for ADC Gain | ||
516 | #define ADC_ZERODB 0x000000cf //Value to set ADC to 0dB | ||
517 | #define ADC_MUTE_MASK 0x000000c0 //Mask for ADC mute | ||
518 | #define ADC_MUTE 0x000000c0 //Value to mute ADC | ||
519 | #define ADC_OSR 0x00000008 //Mask for ADC oversample rate select | ||
520 | #define ADC_TIMEOUT_DISABLE 0x00000008 //Value and mask to disable Timeout clock | ||
521 | #define ADC_HPF_DISABLE 0x00000100 //Value and mask to disable High pass filter | ||
522 | #define ADC_TRANWIN_MASK 0x00000070 //Mask for Length of Transient Window | ||
523 | #endif | ||
524 | |||
525 | #define ADC_MUX_MASK 0x0000000f //Mask for ADC Mux | ||
526 | #define ADC_MUX_MIC 0x00000002 //Value to select Mic at ADC Mux | ||
527 | #define ADC_MUX_LINEIN 0x00000004 //Value to select LineIn at ADC Mux | ||
528 | #define ADC_MUX_PHONE 0x00000001 //Value to select TAD at ADC Mux (Not used) | ||
529 | #define ADC_MUX_AUX 0x00000008 //Value to select Aux at ADC Mux | ||
481 | 530 | ||
482 | #define SET_CHANNEL 0 /* Testing channel outputs 0=Front, 1=Center/LFE, 2=Unknown, 3=Rear */ | 531 | #define SET_CHANNEL 0 /* Testing channel outputs 0=Front, 1=Center/LFE, 2=Unknown, 3=Rear */ |
483 | #define PCM_FRONT_CHANNEL 0 | 532 | #define PCM_FRONT_CHANNEL 0 |
@@ -508,9 +557,18 @@ struct snd_ca0106_pcm { | |||
508 | unsigned short running; | 557 | unsigned short running; |
509 | }; | 558 | }; |
510 | 559 | ||
560 | typedef struct { | ||
561 | u32 serial; | ||
562 | char * name; | ||
563 | int ac97; | ||
564 | int gpio_type; | ||
565 | int i2c_adc; | ||
566 | } ca0106_details_t; | ||
567 | |||
511 | // definition of the chip-specific record | 568 | // definition of the chip-specific record |
512 | struct snd_ca0106 { | 569 | struct snd_ca0106 { |
513 | snd_card_t *card; | 570 | snd_card_t *card; |
571 | ca0106_details_t *details; | ||
514 | struct pci_dev *pci; | 572 | struct pci_dev *pci; |
515 | 573 | ||
516 | unsigned long port; | 574 | unsigned long port; |
@@ -531,6 +589,7 @@ struct snd_ca0106 { | |||
531 | u32 spdif_bits[4]; /* s/pdif out setup */ | 589 | u32 spdif_bits[4]; /* s/pdif out setup */ |
532 | int spdif_enable; | 590 | int spdif_enable; |
533 | int capture_source; | 591 | int capture_source; |
592 | int capture_mic_line_in; | ||
534 | 593 | ||
535 | struct snd_dma_buffer buffer; | 594 | struct snd_dma_buffer buffer; |
536 | }; | 595 | }; |
@@ -547,3 +606,6 @@ void snd_ca0106_ptr_write(ca0106_t *emu, | |||
547 | unsigned int chn, | 606 | unsigned int chn, |
548 | unsigned int data); | 607 | unsigned int data); |
549 | 608 | ||
609 | int snd_ca0106_i2c_write(ca0106_t *emu, u32 reg, u32 value); | ||
610 | |||
611 | |||
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 82533b45bc8c..95c289284267 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2004 James Courtier-Dutton <James@superbug.demon.co.uk> | 2 | * Copyright (c) 2004 James Courtier-Dutton <James@superbug.demon.co.uk> |
3 | * Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit | 3 | * Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit |
4 | * Version: 0.0.22 | 4 | * Version: 0.0.23 |
5 | * | 5 | * |
6 | * FEATURES currently supported: | 6 | * FEATURES currently supported: |
7 | * Front, Rear and Center/LFE. | 7 | * Front, Rear and Center/LFE. |
@@ -77,6 +77,8 @@ | |||
77 | * Add SPDIF capture using optional digital I/O module for SB Live 24bit. (Analog capture does not yet work.) | 77 | * Add SPDIF capture using optional digital I/O module for SB Live 24bit. (Analog capture does not yet work.) |
78 | * 0.0.22 | 78 | * 0.0.22 |
79 | * Add support for MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97. From kiksen, bug #901 | 79 | * Add support for MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97. From kiksen, bug #901 |
80 | * 0.0.23 | ||
81 | * Implement support for Line-in capture on SB Live 24bit. | ||
80 | * | 82 | * |
81 | * BUGS: | 83 | * BUGS: |
82 | * Some stability problems when unloading the snd-ca0106 kernel module. | 84 | * Some stability problems when unloading the snd-ca0106 kernel module. |
@@ -136,6 +138,7 @@ | |||
136 | #include <linux/pci.h> | 138 | #include <linux/pci.h> |
137 | #include <linux/slab.h> | 139 | #include <linux/slab.h> |
138 | #include <linux/moduleparam.h> | 140 | #include <linux/moduleparam.h> |
141 | #include <linux/dma-mapping.h> | ||
139 | #include <sound/core.h> | 142 | #include <sound/core.h> |
140 | #include <sound/initval.h> | 143 | #include <sound/initval.h> |
141 | #include <sound/pcm.h> | 144 | #include <sound/pcm.h> |
@@ -161,18 +164,32 @@ MODULE_PARM_DESC(enable, "Enable the CA0106 soundcard."); | |||
161 | 164 | ||
162 | #include "ca0106.h" | 165 | #include "ca0106.h" |
163 | 166 | ||
164 | typedef struct { | 167 | static ca0106_details_t ca0106_chip_details[] = { |
165 | u32 serial; | 168 | /* AudigyLS[SB0310] */ |
166 | char * name; | 169 | { .serial = 0x10021102, |
167 | } ca0106_names_t; | 170 | .name = "AudigyLS [SB0310]", |
168 | 171 | .ac97 = 1 } , | |
169 | static ca0106_names_t ca0106_chip_names[] = { | 172 | /* Unknown AudigyLS that also says SB0310 on it */ |
170 | { 0x10021102, "AudigyLS [SB0310]"} , | 173 | { .serial = 0x10051102, |
171 | { 0x10051102, "AudigyLS [SB0310b]"} , /* Unknown AudigyLS that also says SB0310 on it */ | 174 | .name = "AudigyLS [SB0310b]", |
172 | { 0x10061102, "Live! 7.1 24bit [SB0410]"} , /* New Sound Blaster Live! 7.1 24bit. This does not have an AC97. 53SB041000001 */ | 175 | .ac97 = 1 } , |
173 | { 0x10071102, "Live! 7.1 24bit [SB0413]"} , /* New Dell Sound Blaster Live! 7.1 24bit. This does not have an AC97. */ | 176 | /* New Sound Blaster Live! 7.1 24bit. This does not have an AC97. 53SB041000001 */ |
174 | { 0x10091462, "MSI K8N Diamond MB [SB0438]"}, /* MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97 */ | 177 | { .serial = 0x10061102, |
175 | { 0, "AudigyLS [Unknown]" } | 178 | .name = "Live! 7.1 24bit [SB0410]", |
179 | .gpio_type = 1, | ||
180 | .i2c_adc = 1 } , | ||
181 | /* New Dell Sound Blaster Live! 7.1 24bit. This does not have an AC97. */ | ||
182 | { .serial = 0x10071102, | ||
183 | .name = "Live! 7.1 24bit [SB0413]", | ||
184 | .gpio_type = 1, | ||
185 | .i2c_adc = 1 } , | ||
186 | /* MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97 */ | ||
187 | { .serial = 0x10091462, | ||
188 | .name = "MSI K8N Diamond MB [SB0438]", | ||
189 | .gpio_type = 1, | ||
190 | .i2c_adc = 1 } , | ||
191 | { .serial = 0, | ||
192 | .name = "AudigyLS [Unknown]" } | ||
176 | }; | 193 | }; |
177 | 194 | ||
178 | /* hardware definition */ | 195 | /* hardware definition */ |
@@ -200,10 +217,10 @@ static snd_pcm_hardware_t snd_ca0106_capture_hw = { | |||
200 | SNDRV_PCM_INFO_INTERLEAVED | | 217 | SNDRV_PCM_INFO_INTERLEAVED | |
201 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | 218 | SNDRV_PCM_INFO_BLOCK_TRANSFER | |
202 | SNDRV_PCM_INFO_MMAP_VALID), | 219 | SNDRV_PCM_INFO_MMAP_VALID), |
203 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | 220 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, |
204 | .rates = SNDRV_PCM_RATE_48000, | 221 | .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000, |
205 | .rate_min = 48000, | 222 | .rate_min = 44100, |
206 | .rate_max = 48000, | 223 | .rate_max = 192000, |
207 | .channels_min = 2, | 224 | .channels_min = 2, |
208 | .channels_max = 2, | 225 | .channels_max = 2, |
209 | .buffer_bytes_max = ((65536 - 64) * 8), | 226 | .buffer_bytes_max = ((65536 - 64) * 8), |
@@ -246,6 +263,62 @@ void snd_ca0106_ptr_write(ca0106_t *emu, | |||
246 | spin_unlock_irqrestore(&emu->emu_lock, flags); | 263 | spin_unlock_irqrestore(&emu->emu_lock, flags); |
247 | } | 264 | } |
248 | 265 | ||
266 | int snd_ca0106_i2c_write(ca0106_t *emu, | ||
267 | u32 reg, | ||
268 | u32 value) | ||
269 | { | ||
270 | u32 tmp; | ||
271 | int timeout=0; | ||
272 | int status; | ||
273 | int retry; | ||
274 | if ((reg > 0x7f) || (value > 0x1ff)) | ||
275 | { | ||
276 | snd_printk("i2c_write: invalid values.\n"); | ||
277 | return -EINVAL; | ||
278 | } | ||
279 | |||
280 | tmp = reg << 25 | value << 16; | ||
281 | /* Not sure what this I2C channel controls. */ | ||
282 | /* snd_ca0106_ptr_write(emu, I2C_D0, 0, tmp); */ | ||
283 | |||
284 | /* This controls the I2C connected to the WM8775 ADC Codec */ | ||
285 | snd_ca0106_ptr_write(emu, I2C_D1, 0, tmp); | ||
286 | |||
287 | for(retry=0;retry<10;retry++) | ||
288 | { | ||
289 | /* Send the data to i2c */ | ||
290 | tmp = snd_ca0106_ptr_read(emu, I2C_A, 0); | ||
291 | tmp = tmp & ~(I2C_A_ADC_READ|I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD_MASK); | ||
292 | tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD); | ||
293 | snd_ca0106_ptr_write(emu, I2C_A, 0, tmp); | ||
294 | |||
295 | /* Wait till the transaction ends */ | ||
296 | while(1) | ||
297 | { | ||
298 | status = snd_ca0106_ptr_read(emu, I2C_A, 0); | ||
299 | //snd_printk("I2C:status=0x%x\n", status); | ||
300 | timeout++; | ||
301 | if((status & I2C_A_ADC_START)==0) | ||
302 | break; | ||
303 | |||
304 | if(timeout>1000) | ||
305 | break; | ||
306 | } | ||
307 | //Read back and see if the transaction is successful | ||
308 | if((status & I2C_A_ADC_ABORT)==0) | ||
309 | break; | ||
310 | } | ||
311 | |||
312 | if(retry==10) | ||
313 | { | ||
314 | snd_printk("Writing to ADC failed!\n"); | ||
315 | return -EINVAL; | ||
316 | } | ||
317 | |||
318 | return 0; | ||
319 | } | ||
320 | |||
321 | |||
249 | static void snd_ca0106_intr_enable(ca0106_t *emu, unsigned int intrenb) | 322 | static void snd_ca0106_intr_enable(ca0106_t *emu, unsigned int intrenb) |
250 | { | 323 | { |
251 | unsigned long flags; | 324 | unsigned long flags; |
@@ -259,11 +332,7 @@ static void snd_ca0106_intr_enable(ca0106_t *emu, unsigned int intrenb) | |||
259 | 332 | ||
260 | static void snd_ca0106_pcm_free_substream(snd_pcm_runtime_t *runtime) | 333 | static void snd_ca0106_pcm_free_substream(snd_pcm_runtime_t *runtime) |
261 | { | 334 | { |
262 | ca0106_pcm_t *epcm = runtime->private_data; | 335 | kfree(runtime->private_data); |
263 | |||
264 | if (epcm) { | ||
265 | kfree(epcm); | ||
266 | } | ||
267 | } | 336 | } |
268 | 337 | ||
269 | /* open_playback callback */ | 338 | /* open_playback callback */ |
@@ -538,6 +607,61 @@ static int snd_ca0106_pcm_prepare_capture(snd_pcm_substream_t *substream) | |||
538 | snd_pcm_runtime_t *runtime = substream->runtime; | 607 | snd_pcm_runtime_t *runtime = substream->runtime; |
539 | ca0106_pcm_t *epcm = runtime->private_data; | 608 | ca0106_pcm_t *epcm = runtime->private_data; |
540 | int channel = epcm->channel_id; | 609 | int channel = epcm->channel_id; |
610 | u32 hcfg_mask = HCFG_CAPTURE_S32_LE; | ||
611 | u32 hcfg_set = 0x00000000; | ||
612 | u32 hcfg; | ||
613 | u32 over_sampling=0x2; | ||
614 | u32 reg71_mask = 0x0000c000 ; /* Global. Set ADC rate. */ | ||
615 | u32 reg71_set = 0; | ||
616 | u32 reg71; | ||
617 | |||
618 | //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)); | ||
619 | //snd_printk("dma_addr=%x, dma_area=%p, table_base=%p\n",runtime->dma_addr, runtime->dma_area, table_base); | ||
620 | //snd_printk("dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n",emu->buffer.addr, emu->buffer.area, emu->buffer.bytes); | ||
621 | /* reg71 controls ADC rate. */ | ||
622 | switch (runtime->rate) { | ||
623 | case 44100: | ||
624 | reg71_set = 0x00004000; | ||
625 | break; | ||
626 | case 48000: | ||
627 | reg71_set = 0; | ||
628 | break; | ||
629 | case 96000: | ||
630 | reg71_set = 0x00008000; | ||
631 | over_sampling=0xa; | ||
632 | break; | ||
633 | case 192000: | ||
634 | reg71_set = 0x0000c000; | ||
635 | over_sampling=0xa; | ||
636 | break; | ||
637 | default: | ||
638 | reg71_set = 0; | ||
639 | break; | ||
640 | } | ||
641 | /* Format is a global setting */ | ||
642 | /* FIXME: Only let the first channel accessed set this. */ | ||
643 | switch (runtime->format) { | ||
644 | case SNDRV_PCM_FORMAT_S16_LE: | ||
645 | hcfg_set = 0; | ||
646 | break; | ||
647 | case SNDRV_PCM_FORMAT_S32_LE: | ||
648 | hcfg_set = HCFG_CAPTURE_S32_LE; | ||
649 | break; | ||
650 | default: | ||
651 | hcfg_set = 0; | ||
652 | break; | ||
653 | } | ||
654 | hcfg = inl(emu->port + HCFG) ; | ||
655 | hcfg = (hcfg & ~hcfg_mask) | hcfg_set; | ||
656 | outl(hcfg, emu->port + HCFG); | ||
657 | reg71 = snd_ca0106_ptr_read(emu, 0x71, 0); | ||
658 | reg71 = (reg71 & ~reg71_mask) | reg71_set; | ||
659 | snd_ca0106_ptr_write(emu, 0x71, 0, reg71); | ||
660 | if (emu->details->i2c_adc == 1) { /* The SB0410 and SB0413 use I2C to control ADC. */ | ||
661 | snd_ca0106_i2c_write(emu, ADC_MASTER, over_sampling); /* Adjust the over sampler to better suit the capture rate. */ | ||
662 | } | ||
663 | |||
664 | |||
541 | //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)); | 665 | //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)); |
542 | snd_ca0106_ptr_write(emu, 0x13, channel, 0); | 666 | snd_ca0106_ptr_write(emu, 0x13, channel, 0); |
543 | snd_ca0106_ptr_write(emu, CAPTURE_DMA_ADDR, channel, runtime->dma_addr); | 667 | snd_ca0106_ptr_write(emu, CAPTURE_DMA_ADDR, channel, runtime->dma_addr); |
@@ -810,6 +934,7 @@ static int snd_ca0106_ac97(ca0106_t *chip) | |||
810 | 934 | ||
811 | memset(&ac97, 0, sizeof(ac97)); | 935 | memset(&ac97, 0, sizeof(ac97)); |
812 | ac97.private_data = chip; | 936 | ac97.private_data = chip; |
937 | ac97.scaps = AC97_SCAP_NO_SPDIF; | ||
813 | return snd_ac97_mixer(pbus, &ac97, &chip->ac97); | 938 | return snd_ac97_mixer(pbus, &ac97, &chip->ac97); |
814 | } | 939 | } |
815 | 940 | ||
@@ -993,6 +1118,7 @@ static int __devinit snd_ca0106_create(snd_card_t *card, | |||
993 | ca0106_t **rchip) | 1118 | ca0106_t **rchip) |
994 | { | 1119 | { |
995 | ca0106_t *chip; | 1120 | ca0106_t *chip; |
1121 | ca0106_details_t *c; | ||
996 | int err; | 1122 | int err; |
997 | int ch; | 1123 | int ch; |
998 | static snd_device_ops_t ops = { | 1124 | static snd_device_ops_t ops = { |
@@ -1003,8 +1129,8 @@ static int __devinit snd_ca0106_create(snd_card_t *card, | |||
1003 | 1129 | ||
1004 | if ((err = pci_enable_device(pci)) < 0) | 1130 | if ((err = pci_enable_device(pci)) < 0) |
1005 | return err; | 1131 | return err; |
1006 | if (pci_set_dma_mask(pci, 0xffffffffUL) < 0 || | 1132 | if (pci_set_dma_mask(pci, DMA_32BIT_MASK) < 0 || |
1007 | pci_set_consistent_dma_mask(pci, 0xffffffffUL) < 0) { | 1133 | pci_set_consistent_dma_mask(pci, DMA_32BIT_MASK) < 0) { |
1008 | printk(KERN_ERR "error to set 32bit mask DMA\n"); | 1134 | printk(KERN_ERR "error to set 32bit mask DMA\n"); |
1009 | pci_disable_device(pci); | 1135 | pci_disable_device(pci); |
1010 | return -ENXIO; | 1136 | return -ENXIO; |
@@ -1054,6 +1180,15 @@ static int __devinit snd_ca0106_create(snd_card_t *card, | |||
1054 | printk(KERN_INFO "Model %04x Rev %08x Serial %08x\n", chip->model, | 1180 | printk(KERN_INFO "Model %04x Rev %08x Serial %08x\n", chip->model, |
1055 | chip->revision, chip->serial); | 1181 | chip->revision, chip->serial); |
1056 | #endif | 1182 | #endif |
1183 | strcpy(card->driver, "CA0106"); | ||
1184 | strcpy(card->shortname, "CA0106"); | ||
1185 | |||
1186 | for (c=ca0106_chip_details; c->serial; c++) { | ||
1187 | if (c->serial == chip->serial) break; | ||
1188 | } | ||
1189 | chip->details = c; | ||
1190 | sprintf(card->longname, "%s at 0x%lx irq %i", | ||
1191 | c->name, chip->port, chip->irq); | ||
1057 | 1192 | ||
1058 | outl(0, chip->port + INTE); | 1193 | outl(0, chip->port + INTE); |
1059 | 1194 | ||
@@ -1113,7 +1248,7 @@ static int __devinit snd_ca0106_create(snd_card_t *card, | |||
1113 | //snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0xf0f003f); /* OSS drivers set this. */ | 1248 | //snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0xf0f003f); /* OSS drivers set this. */ |
1114 | /* Analog or Digital output */ | 1249 | /* Analog or Digital output */ |
1115 | snd_ca0106_ptr_write(chip, SPDIF_SELECT1, 0, 0xf); | 1250 | snd_ca0106_ptr_write(chip, SPDIF_SELECT1, 0, 0xf); |
1116 | snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0x000b0000); /* 0x0b000000 for digital, 0x000b0000 for analog, from win2000 drivers */ | 1251 | snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0x000f0000); /* 0x0b000000 for digital, 0x000b0000 for analog, from win2000 drivers. Use 0x000f0000 for surround71 */ |
1117 | chip->spdif_enable = 0; /* Set digital SPDIF output off */ | 1252 | chip->spdif_enable = 0; /* Set digital SPDIF output off */ |
1118 | chip->capture_source = 3; /* Set CAPTURE_SOURCE */ | 1253 | chip->capture_source = 3; /* Set CAPTURE_SOURCE */ |
1119 | //snd_ca0106_ptr_write(chip, 0x45, 0, 0); /* Analogue out */ | 1254 | //snd_ca0106_ptr_write(chip, 0x45, 0, 0); /* Analogue out */ |
@@ -1138,13 +1273,11 @@ static int __devinit snd_ca0106_create(snd_card_t *card, | |||
1138 | snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4); /* Select MIC, Line in, TAD in, AUX in */ | 1273 | snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4); /* Select MIC, Line in, TAD in, AUX in */ |
1139 | chip->capture_source = 3; /* Set CAPTURE_SOURCE */ | 1274 | chip->capture_source = 3; /* Set CAPTURE_SOURCE */ |
1140 | 1275 | ||
1141 | if ((chip->serial == 0x10061102) || | 1276 | if (chip->details->gpio_type == 1) { /* The SB0410 and SB0413 use GPIO differently. */ |
1142 | (chip->serial == 0x10071102) || | ||
1143 | (chip->serial == 0x10091462)) { /* The SB0410 and SB0413 use GPIO differently. */ | ||
1144 | /* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */ | 1277 | /* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */ |
1145 | outl(0x0, chip->port+GPIO); | 1278 | outl(0x0, chip->port+GPIO); |
1146 | //outl(0x00f0e000, chip->port+GPIO); /* Analog */ | 1279 | //outl(0x00f0e000, chip->port+GPIO); /* Analog */ |
1147 | outl(0x005f4300, chip->port+GPIO); /* Analog */ | 1280 | outl(0x005f5301, chip->port+GPIO); /* Analog */ |
1148 | } else { | 1281 | } else { |
1149 | outl(0x0, chip->port+GPIO); | 1282 | outl(0x0, chip->port+GPIO); |
1150 | outl(0x005f03a3, chip->port+GPIO); /* Analog */ | 1283 | outl(0x005f03a3, chip->port+GPIO); /* Analog */ |
@@ -1157,6 +1290,10 @@ static int __devinit snd_ca0106_create(snd_card_t *card, | |||
1157 | //outl(0x00000009, chip->port+HCFG); | 1290 | //outl(0x00000009, chip->port+HCFG); |
1158 | outl(HCFG_AC97 | HCFG_AUDIOENABLE, chip->port+HCFG); /* AC97 2.0, Enable outputs. */ | 1291 | outl(HCFG_AC97 | HCFG_AUDIOENABLE, chip->port+HCFG); /* AC97 2.0, Enable outputs. */ |
1159 | 1292 | ||
1293 | if (chip->details->i2c_adc == 1) { /* The SB0410 and SB0413 use I2C to control ADC. */ | ||
1294 | snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); /* Enable Line-in capture. MIC in currently untested. */ | ||
1295 | } | ||
1296 | |||
1160 | if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, | 1297 | if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, |
1161 | chip, &ops)) < 0) { | 1298 | chip, &ops)) < 0) { |
1162 | snd_ca0106_free(chip); | 1299 | snd_ca0106_free(chip); |
@@ -1172,7 +1309,6 @@ static int __devinit snd_ca0106_probe(struct pci_dev *pci, | |||
1172 | static int dev; | 1309 | static int dev; |
1173 | snd_card_t *card; | 1310 | snd_card_t *card; |
1174 | ca0106_t *chip; | 1311 | ca0106_t *chip; |
1175 | ca0106_names_t *c; | ||
1176 | int err; | 1312 | int err; |
1177 | 1313 | ||
1178 | if (dev >= SNDRV_CARDS) | 1314 | if (dev >= SNDRV_CARDS) |
@@ -1207,9 +1343,7 @@ static int __devinit snd_ca0106_probe(struct pci_dev *pci, | |||
1207 | snd_card_free(card); | 1343 | snd_card_free(card); |
1208 | return err; | 1344 | return err; |
1209 | } | 1345 | } |
1210 | if ((chip->serial != 0x10061102) && | 1346 | if (chip->details->ac97 == 1) { /* The SB0410 and SB0413 do not have an AC97 chip. */ |
1211 | (chip->serial != 0x10071102) && | ||
1212 | (chip->serial != 0x10091462) ) { /* The SB0410 and SB0413 do not have an ac97 chip. */ | ||
1213 | if ((err = snd_ca0106_ac97(chip)) < 0) { | 1347 | if ((err = snd_ca0106_ac97(chip)) < 0) { |
1214 | snd_card_free(card); | 1348 | snd_card_free(card); |
1215 | return err; | 1349 | return err; |
@@ -1222,15 +1356,6 @@ static int __devinit snd_ca0106_probe(struct pci_dev *pci, | |||
1222 | 1356 | ||
1223 | snd_ca0106_proc_init(chip); | 1357 | snd_ca0106_proc_init(chip); |
1224 | 1358 | ||
1225 | strcpy(card->driver, "CA0106"); | ||
1226 | strcpy(card->shortname, "CA0106"); | ||
1227 | |||
1228 | for (c=ca0106_chip_names; c->serial; c++) { | ||
1229 | if (c->serial == chip->serial) break; | ||
1230 | } | ||
1231 | sprintf(card->longname, "%s at 0x%lx irq %i", | ||
1232 | c->name, chip->port, chip->irq); | ||
1233 | |||
1234 | if ((err = snd_card_register(card)) < 0) { | 1359 | if ((err = snd_card_register(card)) < 0) { |
1235 | snd_card_free(card); | 1360 | snd_card_free(card); |
1236 | return err; | 1361 | return err; |
@@ -1267,7 +1392,7 @@ static int __init alsa_card_ca0106_init(void) | |||
1267 | { | 1392 | { |
1268 | int err; | 1393 | int err; |
1269 | 1394 | ||
1270 | if ((err = pci_module_init(&driver)) > 0) | 1395 | if ((err = pci_register_driver(&driver)) > 0) |
1271 | return err; | 1396 | return err; |
1272 | 1397 | ||
1273 | return 0; | 1398 | return 0; |
diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index 97bed1b0899d..0e5e9ce0ff28 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2004 James Courtier-Dutton <James@superbug.demon.co.uk> | 2 | * Copyright (c) 2004 James Courtier-Dutton <James@superbug.demon.co.uk> |
3 | * Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit | 3 | * Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit |
4 | * Version: 0.0.16 | 4 | * Version: 0.0.17 |
5 | * | 5 | * |
6 | * FEATURES currently supported: | 6 | * FEATURES currently supported: |
7 | * See ca0106_main.c for features. | 7 | * See ca0106_main.c for features. |
@@ -37,6 +37,8 @@ | |||
37 | * Separated ca0106.c into separate functional .c files. | 37 | * Separated ca0106.c into separate functional .c files. |
38 | * 0.0.16 | 38 | * 0.0.16 |
39 | * Modified Copyright message. | 39 | * Modified Copyright message. |
40 | * 0.0.17 | ||
41 | * Implement Mic and Line in Capture. | ||
40 | * | 42 | * |
41 | * This code was initally based on code from ALSA's emu10k1x.c which is: | 43 | * This code was initally based on code from ALSA's emu10k1x.c which is: |
42 | * Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com> | 44 | * Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com> |
@@ -113,7 +115,7 @@ static int snd_ca0106_shared_spdif_put(snd_kcontrol_t * kcontrol, | |||
113 | } else { | 115 | } else { |
114 | /* Analog */ | 116 | /* Analog */ |
115 | snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf); | 117 | snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf); |
116 | snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x000b0000); | 118 | snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x000f0000); |
117 | snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, | 119 | snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, |
118 | snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) | 0x1000); | 120 | snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) | 0x1000); |
119 | mask = inl(emu->port + GPIO) | 0x101; | 121 | mask = inl(emu->port + GPIO) | 0x101; |
@@ -183,6 +185,65 @@ static snd_kcontrol_new_t snd_ca0106_capture_source __devinitdata = | |||
183 | .put = snd_ca0106_capture_source_put | 185 | .put = snd_ca0106_capture_source_put |
184 | }; | 186 | }; |
185 | 187 | ||
188 | static int snd_ca0106_capture_mic_line_in_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) | ||
189 | { | ||
190 | static char *texts[2] = { "Line in", "Mic in" }; | ||
191 | |||
192 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
193 | uinfo->count = 1; | ||
194 | uinfo->value.enumerated.items = 2; | ||
195 | if (uinfo->value.enumerated.item > 1) | ||
196 | uinfo->value.enumerated.item = 1; | ||
197 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | static int snd_ca0106_capture_mic_line_in_get(snd_kcontrol_t * kcontrol, | ||
202 | snd_ctl_elem_value_t * ucontrol) | ||
203 | { | ||
204 | ca0106_t *emu = snd_kcontrol_chip(kcontrol); | ||
205 | |||
206 | ucontrol->value.enumerated.item[0] = emu->capture_mic_line_in; | ||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | static int snd_ca0106_capture_mic_line_in_put(snd_kcontrol_t * kcontrol, | ||
211 | snd_ctl_elem_value_t * ucontrol) | ||
212 | { | ||
213 | ca0106_t *emu = snd_kcontrol_chip(kcontrol); | ||
214 | unsigned int val; | ||
215 | int change = 0; | ||
216 | u32 tmp; | ||
217 | |||
218 | val = ucontrol->value.enumerated.item[0] ; | ||
219 | change = (emu->capture_mic_line_in != val); | ||
220 | if (change) { | ||
221 | emu->capture_mic_line_in = val; | ||
222 | if (val) { | ||
223 | snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_PHONE); /* Mute input */ | ||
224 | tmp = inl(emu->port+GPIO) & ~0x400; | ||
225 | tmp = tmp | 0x400; | ||
226 | outl(tmp, emu->port+GPIO); | ||
227 | snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_MIC); | ||
228 | } else { | ||
229 | snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_PHONE); /* Mute input */ | ||
230 | tmp = inl(emu->port+GPIO) & ~0x400; | ||
231 | outl(tmp, emu->port+GPIO); | ||
232 | snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_LINEIN); | ||
233 | } | ||
234 | } | ||
235 | return change; | ||
236 | } | ||
237 | |||
238 | static snd_kcontrol_new_t snd_ca0106_capture_mic_line_in __devinitdata = | ||
239 | { | ||
240 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
241 | .name = "Mic/Line in Capture", | ||
242 | .info = snd_ca0106_capture_mic_line_in_info, | ||
243 | .get = snd_ca0106_capture_mic_line_in_get, | ||
244 | .put = snd_ca0106_capture_mic_line_in_put | ||
245 | }; | ||
246 | |||
186 | static int snd_ca0106_spdif_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) | 247 | static int snd_ca0106_spdif_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) |
187 | { | 248 | { |
188 | uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; | 249 | uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; |
@@ -437,7 +498,7 @@ static snd_kcontrol_new_t snd_ca0106_volume_control_analog_center_lfe = | |||
437 | static snd_kcontrol_new_t snd_ca0106_volume_control_analog_unknown = | 498 | static snd_kcontrol_new_t snd_ca0106_volume_control_analog_unknown = |
438 | { | 499 | { |
439 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 500 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
440 | .name = "Analog Unknown Volume", | 501 | .name = "Analog Side Volume", |
441 | .info = snd_ca0106_volume_info, | 502 | .info = snd_ca0106_volume_info, |
442 | .get = snd_ca0106_volume_get_analog_unknown, | 503 | .get = snd_ca0106_volume_get_analog_unknown, |
443 | .put = snd_ca0106_volume_put_analog_unknown | 504 | .put = snd_ca0106_volume_put_analog_unknown |
@@ -620,10 +681,11 @@ int __devinit snd_ca0106_mixer(ca0106_t *emu) | |||
620 | return -ENOMEM; | 681 | return -ENOMEM; |
621 | if ((err = snd_ctl_add(card, kctl))) | 682 | if ((err = snd_ctl_add(card, kctl))) |
622 | return err; | 683 | return err; |
623 | if ((kctl = ctl_find(card, SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT))) != NULL) { | 684 | if (emu->details->i2c_adc == 1) { |
624 | /* already defined by ac97, remove it */ | 685 | if ((kctl = snd_ctl_new1(&snd_ca0106_capture_mic_line_in, emu)) == NULL) |
625 | /* FIXME: or do we need both controls? */ | 686 | return -ENOMEM; |
626 | remove_ctl(card, SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT)); | 687 | if ((err = snd_ctl_add(card, kctl))) |
688 | return err; | ||
627 | } | 689 | } |
628 | if ((kctl = snd_ctl_new1(&snd_ca0106_spdif_control, emu)) == NULL) | 690 | if ((kctl = snd_ctl_new1(&snd_ca0106_spdif_control, emu)) == NULL) |
629 | return -ENOMEM; | 691 | return -ENOMEM; |
diff --git a/sound/pci/ca0106/ca0106_proc.c b/sound/pci/ca0106/ca0106_proc.c index afb711421e47..1c9cc821d1b9 100644 --- a/sound/pci/ca0106/ca0106_proc.c +++ b/sound/pci/ca0106/ca0106_proc.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2004 James Courtier-Dutton <James@superbug.demon.co.uk> | 2 | * Copyright (c) 2004 James Courtier-Dutton <James@superbug.demon.co.uk> |
3 | * Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit | 3 | * Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit |
4 | * Version: 0.0.17 | 4 | * Version: 0.0.18 |
5 | * | 5 | * |
6 | * FEATURES currently supported: | 6 | * FEATURES currently supported: |
7 | * See ca0106_main.c for features. | 7 | * See ca0106_main.c for features. |
@@ -39,7 +39,9 @@ | |||
39 | * Modified Copyright message. | 39 | * Modified Copyright message. |
40 | * 0.0.17 | 40 | * 0.0.17 |
41 | * Add iec958 file in proc file system to show status of SPDIF in. | 41 | * Add iec958 file in proc file system to show status of SPDIF in. |
42 | * | 42 | * 0.0.18 |
43 | * Implement support for Line-in capture on SB Live 24bit. | ||
44 | * | ||
43 | * This code was initally based on code from ALSA's emu10k1x.c which is: | 45 | * This code was initally based on code from ALSA's emu10k1x.c which is: |
44 | * Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com> | 46 | * Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com> |
45 | * | 47 | * |
@@ -95,7 +97,7 @@ static struct snd_ca0106_category_str snd_ca0106_con_category[] = { | |||
95 | }; | 97 | }; |
96 | 98 | ||
97 | 99 | ||
98 | void snd_ca0106_proc_dump_iec958( snd_info_buffer_t *buffer, u32 value) | 100 | static void snd_ca0106_proc_dump_iec958( snd_info_buffer_t *buffer, u32 value) |
99 | { | 101 | { |
100 | int i; | 102 | int i; |
101 | u32 status[4]; | 103 | u32 status[4]; |
@@ -407,6 +409,20 @@ static void snd_ca0106_proc_reg_write(snd_info_entry_t *entry, | |||
407 | } | 409 | } |
408 | } | 410 | } |
409 | 411 | ||
412 | static void snd_ca0106_proc_i2c_write(snd_info_entry_t *entry, | ||
413 | snd_info_buffer_t * buffer) | ||
414 | { | ||
415 | ca0106_t *emu = entry->private_data; | ||
416 | char line[64]; | ||
417 | unsigned int reg, val; | ||
418 | while (!snd_info_get_line(buffer, line, sizeof(line))) { | ||
419 | if (sscanf(line, "%x %x", ®, &val) != 2) | ||
420 | continue; | ||
421 | if ((reg <= 0x7f) || (val <= 0x1ff)) { | ||
422 | snd_ca0106_i2c_write(emu, reg, val); | ||
423 | } | ||
424 | } | ||
425 | } | ||
410 | 426 | ||
411 | int __devinit snd_ca0106_proc_init(ca0106_t * emu) | 427 | int __devinit snd_ca0106_proc_init(ca0106_t * emu) |
412 | { | 428 | { |
@@ -418,6 +434,7 @@ int __devinit snd_ca0106_proc_init(ca0106_t * emu) | |||
418 | snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_reg_read32); | 434 | snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_reg_read32); |
419 | entry->c.text.write_size = 64; | 435 | entry->c.text.write_size = 64; |
420 | entry->c.text.write = snd_ca0106_proc_reg_write32; | 436 | entry->c.text.write = snd_ca0106_proc_reg_write32; |
437 | entry->mode |= S_IWUSR; | ||
421 | } | 438 | } |
422 | if(! snd_card_proc_new(emu->card, "ca0106_reg16", &entry)) | 439 | if(! snd_card_proc_new(emu->card, "ca0106_reg16", &entry)) |
423 | snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_reg_read16); | 440 | snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_reg_read16); |
@@ -427,6 +444,14 @@ int __devinit snd_ca0106_proc_init(ca0106_t * emu) | |||
427 | snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_reg_read1); | 444 | snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_reg_read1); |
428 | entry->c.text.write_size = 64; | 445 | entry->c.text.write_size = 64; |
429 | entry->c.text.write = snd_ca0106_proc_reg_write; | 446 | entry->c.text.write = snd_ca0106_proc_reg_write; |
447 | entry->mode |= S_IWUSR; | ||
448 | // entry->private_data = emu; | ||
449 | } | ||
450 | if(! snd_card_proc_new(emu->card, "ca0106_i2c", &entry)) { | ||
451 | snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_i2c_write); | ||
452 | entry->c.text.write_size = 64; | ||
453 | entry->c.text.write = snd_ca0106_proc_i2c_write; | ||
454 | entry->mode |= S_IWUSR; | ||
430 | // entry->private_data = emu; | 455 | // entry->private_data = emu; |
431 | } | 456 | } |
432 | if(! snd_card_proc_new(emu->card, "ca0106_regs2", &entry)) | 457 | if(! snd_card_proc_new(emu->card, "ca0106_regs2", &entry)) |
diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index 113208fbde1b..b4503385ea69 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c | |||
@@ -519,40 +519,50 @@ inline static unsigned char snd_cmipci_read_b(cmipci_t *cm, unsigned int cmd) | |||
519 | } | 519 | } |
520 | 520 | ||
521 | /* bit operations for dword register */ | 521 | /* bit operations for dword register */ |
522 | static void snd_cmipci_set_bit(cmipci_t *cm, unsigned int cmd, unsigned int flag) | 522 | static int snd_cmipci_set_bit(cmipci_t *cm, unsigned int cmd, unsigned int flag) |
523 | { | 523 | { |
524 | unsigned int val; | 524 | unsigned int val, oval; |
525 | val = inl(cm->iobase + cmd); | 525 | val = oval = inl(cm->iobase + cmd); |
526 | val |= flag; | 526 | val |= flag; |
527 | if (val == oval) | ||
528 | return 0; | ||
527 | outl(val, cm->iobase + cmd); | 529 | outl(val, cm->iobase + cmd); |
530 | return 1; | ||
528 | } | 531 | } |
529 | 532 | ||
530 | static void snd_cmipci_clear_bit(cmipci_t *cm, unsigned int cmd, unsigned int flag) | 533 | static int snd_cmipci_clear_bit(cmipci_t *cm, unsigned int cmd, unsigned int flag) |
531 | { | 534 | { |
532 | unsigned int val; | 535 | unsigned int val, oval; |
533 | val = inl(cm->iobase + cmd); | 536 | val = oval = inl(cm->iobase + cmd); |
534 | val &= ~flag; | 537 | val &= ~flag; |
538 | if (val == oval) | ||
539 | return 0; | ||
535 | outl(val, cm->iobase + cmd); | 540 | outl(val, cm->iobase + cmd); |
541 | return 1; | ||
536 | } | 542 | } |
537 | 543 | ||
538 | #if 0 // not used | ||
539 | /* bit operations for byte register */ | 544 | /* bit operations for byte register */ |
540 | static void snd_cmipci_set_bit_b(cmipci_t *cm, unsigned int cmd, unsigned char flag) | 545 | static int snd_cmipci_set_bit_b(cmipci_t *cm, unsigned int cmd, unsigned char flag) |
541 | { | 546 | { |
542 | unsigned char val; | 547 | unsigned char val, oval; |
543 | val = inb(cm->iobase + cmd); | 548 | val = oval = inb(cm->iobase + cmd); |
544 | val |= flag; | 549 | val |= flag; |
550 | if (val == oval) | ||
551 | return 0; | ||
545 | outb(val, cm->iobase + cmd); | 552 | outb(val, cm->iobase + cmd); |
553 | return 1; | ||
546 | } | 554 | } |
547 | 555 | ||
548 | static void snd_cmipci_clear_bit_b(cmipci_t *cm, unsigned int cmd, unsigned char flag) | 556 | static int snd_cmipci_clear_bit_b(cmipci_t *cm, unsigned int cmd, unsigned char flag) |
549 | { | 557 | { |
550 | unsigned char val; | 558 | unsigned char val, oval; |
551 | val = inb(cm->iobase + cmd); | 559 | val = oval = inb(cm->iobase + cmd); |
552 | val &= ~flag; | 560 | val &= ~flag; |
561 | if (val == oval) | ||
562 | return 0; | ||
553 | outb(val, cm->iobase + cmd); | 563 | outb(val, cm->iobase + cmd); |
564 | return 1; | ||
554 | } | 565 | } |
555 | #endif | ||
556 | 566 | ||
557 | 567 | ||
558 | /* | 568 | /* |
@@ -2250,8 +2260,8 @@ DEFINE_SWITCH_ARG(exchange_dac, CM_REG_MISC_CTRL, CM_XCHGDAC, 0, 0, 0); /* rever | |||
2250 | DEFINE_SWITCH_ARG(exchange_dac, CM_REG_MISC_CTRL, CM_XCHGDAC, CM_XCHGDAC, 0, 0); | 2260 | DEFINE_SWITCH_ARG(exchange_dac, CM_REG_MISC_CTRL, CM_XCHGDAC, CM_XCHGDAC, 0, 0); |
2251 | #endif | 2261 | #endif |
2252 | DEFINE_BIT_SWITCH_ARG(fourch, CM_REG_MISC_CTRL, CM_N4SPK3D, 0, 0); | 2262 | DEFINE_BIT_SWITCH_ARG(fourch, CM_REG_MISC_CTRL, CM_N4SPK3D, 0, 0); |
2253 | DEFINE_BIT_SWITCH_ARG(line_rear, CM_REG_MIXER1, CM_SPK4, 1, 0); | 2263 | // DEFINE_BIT_SWITCH_ARG(line_rear, CM_REG_MIXER1, CM_SPK4, 1, 0); |
2254 | DEFINE_BIT_SWITCH_ARG(line_bass, CM_REG_LEGACY_CTRL, CM_LINE_AS_BASS, 0, 0); | 2264 | // DEFINE_BIT_SWITCH_ARG(line_bass, CM_REG_LEGACY_CTRL, CM_LINE_AS_BASS, 0, 0); |
2255 | // DEFINE_BIT_SWITCH_ARG(joystick, CM_REG_FUNCTRL1, CM_JYSTK_EN, 0, 0); /* now module option */ | 2265 | // DEFINE_BIT_SWITCH_ARG(joystick, CM_REG_FUNCTRL1, CM_JYSTK_EN, 0, 0); /* now module option */ |
2256 | DEFINE_SWITCH_ARG(modem, CM_REG_MISC_CTRL, CM_FLINKON|CM_FLINKOFF, CM_FLINKON, 0, 0); | 2266 | DEFINE_SWITCH_ARG(modem, CM_REG_MISC_CTRL, CM_FLINKON|CM_FLINKOFF, CM_FLINKON, 0, 0); |
2257 | 2267 | ||
@@ -2300,10 +2310,114 @@ static int snd_cmipci_spdout_enable_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_v | |||
2300 | } | 2310 | } |
2301 | 2311 | ||
2302 | 2312 | ||
2313 | static int snd_cmipci_line_in_mode_info(snd_kcontrol_t *kcontrol, | ||
2314 | snd_ctl_elem_info_t *uinfo) | ||
2315 | { | ||
2316 | cmipci_t *cm = snd_kcontrol_chip(kcontrol); | ||
2317 | static char *texts[3] = { "Line-In", "Rear Output", "Bass Output" }; | ||
2318 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
2319 | uinfo->count = 1; | ||
2320 | uinfo->value.enumerated.items = cm->chip_version >= 39 ? 3 : 2; | ||
2321 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) | ||
2322 | uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; | ||
2323 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
2324 | return 0; | ||
2325 | } | ||
2326 | |||
2327 | static inline unsigned int get_line_in_mode(cmipci_t *cm) | ||
2328 | { | ||
2329 | unsigned int val; | ||
2330 | if (cm->chip_version >= 39) { | ||
2331 | val = snd_cmipci_read(cm, CM_REG_LEGACY_CTRL); | ||
2332 | if (val & CM_LINE_AS_BASS) | ||
2333 | return 2; | ||
2334 | } | ||
2335 | val = snd_cmipci_read_b(cm, CM_REG_MIXER1); | ||
2336 | if (val & CM_SPK4) | ||
2337 | return 1; | ||
2338 | return 0; | ||
2339 | } | ||
2340 | |||
2341 | static int snd_cmipci_line_in_mode_get(snd_kcontrol_t *kcontrol, | ||
2342 | snd_ctl_elem_value_t *ucontrol) | ||
2343 | { | ||
2344 | cmipci_t *cm = snd_kcontrol_chip(kcontrol); | ||
2345 | |||
2346 | spin_lock_irq(&cm->reg_lock); | ||
2347 | ucontrol->value.enumerated.item[0] = get_line_in_mode(cm); | ||
2348 | spin_unlock_irq(&cm->reg_lock); | ||
2349 | return 0; | ||
2350 | } | ||
2351 | |||
2352 | static int snd_cmipci_line_in_mode_put(snd_kcontrol_t *kcontrol, | ||
2353 | snd_ctl_elem_value_t *ucontrol) | ||
2354 | { | ||
2355 | cmipci_t *cm = snd_kcontrol_chip(kcontrol); | ||
2356 | int change; | ||
2357 | |||
2358 | spin_lock_irq(&cm->reg_lock); | ||
2359 | if (ucontrol->value.enumerated.item[0] == 2) | ||
2360 | change = snd_cmipci_set_bit(cm, CM_REG_LEGACY_CTRL, CM_LINE_AS_BASS); | ||
2361 | else | ||
2362 | change = snd_cmipci_clear_bit(cm, CM_REG_LEGACY_CTRL, CM_LINE_AS_BASS); | ||
2363 | if (ucontrol->value.enumerated.item[0] == 1) | ||
2364 | change |= snd_cmipci_set_bit_b(cm, CM_REG_MIXER1, CM_SPK4); | ||
2365 | else | ||
2366 | change |= snd_cmipci_clear_bit_b(cm, CM_REG_MIXER1, CM_SPK4); | ||
2367 | spin_unlock_irq(&cm->reg_lock); | ||
2368 | return change; | ||
2369 | } | ||
2370 | |||
2371 | static int snd_cmipci_mic_in_mode_info(snd_kcontrol_t *kcontrol, | ||
2372 | snd_ctl_elem_info_t *uinfo) | ||
2373 | { | ||
2374 | static char *texts[2] = { "Mic-In", "Center/LFE Output" }; | ||
2375 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
2376 | uinfo->count = 1; | ||
2377 | uinfo->value.enumerated.items = 2; | ||
2378 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) | ||
2379 | uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; | ||
2380 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
2381 | return 0; | ||
2382 | } | ||
2383 | |||
2384 | static int snd_cmipci_mic_in_mode_get(snd_kcontrol_t *kcontrol, | ||
2385 | snd_ctl_elem_value_t *ucontrol) | ||
2386 | { | ||
2387 | cmipci_t *cm = snd_kcontrol_chip(kcontrol); | ||
2388 | /* same bit as spdi_phase */ | ||
2389 | spin_lock_irq(&cm->reg_lock); | ||
2390 | ucontrol->value.enumerated.item[0] = | ||
2391 | (snd_cmipci_read_b(cm, CM_REG_MISC) & CM_SPDIF_INVERSE) ? 1 : 0; | ||
2392 | spin_unlock_irq(&cm->reg_lock); | ||
2393 | return 0; | ||
2394 | } | ||
2395 | |||
2396 | static int snd_cmipci_mic_in_mode_put(snd_kcontrol_t *kcontrol, | ||
2397 | snd_ctl_elem_value_t *ucontrol) | ||
2398 | { | ||
2399 | cmipci_t *cm = snd_kcontrol_chip(kcontrol); | ||
2400 | int change; | ||
2401 | |||
2402 | spin_lock_irq(&cm->reg_lock); | ||
2403 | if (ucontrol->value.enumerated.item[0]) | ||
2404 | change = snd_cmipci_set_bit_b(cm, CM_REG_MISC, CM_SPDIF_INVERSE); | ||
2405 | else | ||
2406 | change = snd_cmipci_clear_bit_b(cm, CM_REG_MISC, CM_SPDIF_INVERSE); | ||
2407 | spin_unlock_irq(&cm->reg_lock); | ||
2408 | return change; | ||
2409 | } | ||
2410 | |||
2303 | /* both for CM8338/8738 */ | 2411 | /* both for CM8338/8738 */ |
2304 | static snd_kcontrol_new_t snd_cmipci_mixer_switches[] __devinitdata = { | 2412 | static snd_kcontrol_new_t snd_cmipci_mixer_switches[] __devinitdata = { |
2305 | DEFINE_MIXER_SWITCH("Four Channel Mode", fourch), | 2413 | DEFINE_MIXER_SWITCH("Four Channel Mode", fourch), |
2306 | DEFINE_MIXER_SWITCH("Line-In As Rear", line_rear), | 2414 | { |
2415 | .name = "Line-In Mode", | ||
2416 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2417 | .info = snd_cmipci_line_in_mode_info, | ||
2418 | .get = snd_cmipci_line_in_mode_get, | ||
2419 | .put = snd_cmipci_line_in_mode_put, | ||
2420 | }, | ||
2307 | }; | 2421 | }; |
2308 | 2422 | ||
2309 | /* for non-multichannel chips */ | 2423 | /* for non-multichannel chips */ |
@@ -2341,10 +2455,15 @@ static snd_kcontrol_new_t snd_cmipci_old_mixer_switches[] __devinitdata = { | |||
2341 | 2455 | ||
2342 | /* only for model 039 or later */ | 2456 | /* only for model 039 or later */ |
2343 | static snd_kcontrol_new_t snd_cmipci_extra_mixer_switches[] __devinitdata = { | 2457 | static snd_kcontrol_new_t snd_cmipci_extra_mixer_switches[] __devinitdata = { |
2344 | DEFINE_MIXER_SWITCH("Line-In As Bass", line_bass), | ||
2345 | DEFINE_MIXER_SWITCH("IEC958 In Select", spdif_in_sel2), | 2458 | DEFINE_MIXER_SWITCH("IEC958 In Select", spdif_in_sel2), |
2346 | DEFINE_MIXER_SWITCH("IEC958 In Phase Inverse", spdi_phase2), | 2459 | DEFINE_MIXER_SWITCH("IEC958 In Phase Inverse", spdi_phase2), |
2347 | DEFINE_MIXER_SWITCH("Mic As Center/LFE", spdi_phase), /* same bit as spdi_phase */ | 2460 | { |
2461 | .name = "Mic-In Mode", | ||
2462 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2463 | .info = snd_cmipci_mic_in_mode_info, | ||
2464 | .get = snd_cmipci_mic_in_mode_get, | ||
2465 | .put = snd_cmipci_mic_in_mode_put, | ||
2466 | } | ||
2348 | }; | 2467 | }; |
2349 | 2468 | ||
2350 | /* card control switches */ | 2469 | /* card control switches */ |
@@ -2944,7 +3063,7 @@ static struct pci_driver driver = { | |||
2944 | 3063 | ||
2945 | static int __init alsa_card_cmipci_init(void) | 3064 | static int __init alsa_card_cmipci_init(void) |
2946 | { | 3065 | { |
2947 | return pci_module_init(&driver); | 3066 | return pci_register_driver(&driver); |
2948 | } | 3067 | } |
2949 | 3068 | ||
2950 | static void __exit alsa_card_cmipci_exit(void) | 3069 | static void __exit alsa_card_cmipci_exit(void) |
diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index d7e06b3caf97..b6e1854e9389 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c | |||
@@ -206,7 +206,10 @@ MODULE_PARM_DESC(dual_codec, "Secondary Codec ID (0 = disabled)."); | |||
206 | 206 | ||
207 | #define BA0_PMCS 0x0344 /* Power Management Control/Status */ | 207 | #define BA0_PMCS 0x0344 /* Power Management Control/Status */ |
208 | #define BA0_CWPR 0x03e0 /* Configuration Write Protect */ | 208 | #define BA0_CWPR 0x03e0 /* Configuration Write Protect */ |
209 | |||
209 | #define BA0_EPPMC 0x03e4 /* Extended PCI Power Management Control */ | 210 | #define BA0_EPPMC 0x03e4 /* Extended PCI Power Management Control */ |
211 | #define BA0_EPPMC_FPDN (1<<14) /* Full Power DowN */ | ||
212 | |||
210 | #define BA0_GPIOR 0x03e8 /* GPIO Pin Interface Register */ | 213 | #define BA0_GPIOR 0x03e8 /* GPIO Pin Interface Register */ |
211 | 214 | ||
212 | #define BA0_SPMC 0x03ec /* Serial Port Power Management Control (& ASDIN2 enable) */ | 215 | #define BA0_SPMC 0x03ec /* Serial Port Power Management Control (& ASDIN2 enable) */ |
@@ -1461,6 +1464,11 @@ static int snd_cs4281_chip_init(cs4281_t *chip) | |||
1461 | int timeout; | 1464 | int timeout; |
1462 | int retry_count = 2; | 1465 | int retry_count = 2; |
1463 | 1466 | ||
1467 | /* Having EPPMC.FPDN=1 prevent proper chip initialisation */ | ||
1468 | tmp = snd_cs4281_peekBA0(chip, BA0_EPPMC); | ||
1469 | if (tmp & BA0_EPPMC_FPDN) | ||
1470 | snd_cs4281_pokeBA0(chip, BA0_EPPMC, tmp & ~BA0_EPPMC_FPDN); | ||
1471 | |||
1464 | __retry: | 1472 | __retry: |
1465 | tmp = snd_cs4281_peekBA0(chip, BA0_CFLR); | 1473 | tmp = snd_cs4281_peekBA0(chip, BA0_CFLR); |
1466 | if (tmp != BA0_CFLR_DEFAULT) { | 1474 | if (tmp != BA0_CFLR_DEFAULT) { |
@@ -2124,7 +2132,7 @@ static struct pci_driver driver = { | |||
2124 | 2132 | ||
2125 | static int __init alsa_card_cs4281_init(void) | 2133 | static int __init alsa_card_cs4281_init(void) |
2126 | { | 2134 | { |
2127 | return pci_module_init(&driver); | 2135 | return pci_register_driver(&driver); |
2128 | } | 2136 | } |
2129 | 2137 | ||
2130 | static void __exit alsa_card_cs4281_exit(void) | 2138 | static void __exit alsa_card_cs4281_exit(void) |
diff --git a/sound/pci/cs46xx/cs46xx.c b/sound/pci/cs46xx/cs46xx.c index 25d6466a867c..db212ecd792a 100644 --- a/sound/pci/cs46xx/cs46xx.c +++ b/sound/pci/cs46xx/cs46xx.c | |||
@@ -171,7 +171,7 @@ static struct pci_driver driver = { | |||
171 | 171 | ||
172 | static int __init alsa_card_cs46xx_init(void) | 172 | static int __init alsa_card_cs46xx_init(void) |
173 | { | 173 | { |
174 | return pci_module_init(&driver); | 174 | return pci_register_driver(&driver); |
175 | } | 175 | } |
176 | 176 | ||
177 | static void __exit alsa_card_cs46xx_exit(void) | 177 | static void __exit alsa_card_cs46xx_exit(void) |
diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index 5f2ffb7efa06..fd4c50c88bc9 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c | |||
@@ -1295,8 +1295,7 @@ static snd_pcm_hw_constraint_list_t hw_constraints_period_sizes = { | |||
1295 | 1295 | ||
1296 | static void snd_cs46xx_pcm_free_substream(snd_pcm_runtime_t *runtime) | 1296 | static void snd_cs46xx_pcm_free_substream(snd_pcm_runtime_t *runtime) |
1297 | { | 1297 | { |
1298 | cs46xx_pcm_t * cpcm = runtime->private_data; | 1298 | kfree(runtime->private_data); |
1299 | kfree(cpcm); | ||
1300 | } | 1299 | } |
1301 | 1300 | ||
1302 | static int _cs46xx_playback_open_channel (snd_pcm_substream_t * substream,int pcm_channel_id) | 1301 | static int _cs46xx_playback_open_channel (snd_pcm_substream_t * substream,int pcm_channel_id) |
diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c index 6446afe19d80..2085a998eaeb 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c | |||
@@ -228,7 +228,7 @@ static struct pci_driver driver = { | |||
228 | 228 | ||
229 | static int __init alsa_card_emu10k1_init(void) | 229 | static int __init alsa_card_emu10k1_init(void) |
230 | { | 230 | { |
231 | return pci_module_init(&driver); | 231 | return pci_register_driver(&driver); |
232 | } | 232 | } |
233 | 233 | ||
234 | static void __exit alsa_card_emu10k1_exit(void) | 234 | static void __exit alsa_card_emu10k1_exit(void) |
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index c3c96f9f2c7f..a341e758acde 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c | |||
@@ -170,7 +170,7 @@ static int __devinit snd_emu10k1_init(emu10k1_t * emu, int enable_ir) | |||
170 | SPCS_GENERATIONSTATUS | 0x00001200 | | 170 | SPCS_GENERATIONSTATUS | 0x00001200 | |
171 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); | 171 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); |
172 | 172 | ||
173 | if (emu->audigy && emu->revision == 4) { /* audigy2 */ | 173 | if (emu->card_capabilities->ca0151_chip) { /* audigy2 */ |
174 | /* Hacks for Alice3 to work independent of haP16V driver */ | 174 | /* Hacks for Alice3 to work independent of haP16V driver */ |
175 | u32 tmp; | 175 | u32 tmp; |
176 | 176 | ||
@@ -189,7 +189,7 @@ static int __devinit snd_emu10k1_init(emu10k1_t * emu, int enable_ir) | |||
189 | /* Enabled Phased (8-channel) P16V playback */ | 189 | /* Enabled Phased (8-channel) P16V playback */ |
190 | outl(0x0201, emu->port + HCFG2); | 190 | outl(0x0201, emu->port + HCFG2); |
191 | /* Set playback routing. */ | 191 | /* Set playback routing. */ |
192 | snd_emu10k1_ptr_write(emu, CAPTURE_P16V_SOURCE, 0, 78e4); | 192 | snd_emu10k1_ptr20_write(emu, CAPTURE_P16V_SOURCE, 0, 0x78e4); |
193 | } | 193 | } |
194 | if (emu->audigy && (emu->serial == 0x10011102) ) { /* audigy2 Value */ | 194 | if (emu->audigy && (emu->serial == 0x10011102) ) { /* audigy2 Value */ |
195 | /* Hacks for Alice3 to work independent of haP16V driver */ | 195 | /* Hacks for Alice3 to work independent of haP16V driver */ |
@@ -600,7 +600,7 @@ static int snd_emu10k1_free(emu10k1_t *emu) | |||
600 | if (emu->port) | 600 | if (emu->port) |
601 | pci_release_regions(emu->pci); | 601 | pci_release_regions(emu->pci); |
602 | pci_disable_device(emu->pci); | 602 | pci_disable_device(emu->pci); |
603 | if (emu->audigy && emu->revision == 4) /* P16V */ | 603 | if (emu->card_capabilities->ca0151_chip) /* P16V */ |
604 | snd_p16v_free(emu); | 604 | snd_p16v_free(emu); |
605 | kfree(emu); | 605 | kfree(emu); |
606 | return 0; | 606 | return 0; |
@@ -612,21 +612,24 @@ static int snd_emu10k1_dev_free(snd_device_t *device) | |||
612 | return snd_emu10k1_free(emu); | 612 | return snd_emu10k1_free(emu); |
613 | } | 613 | } |
614 | 614 | ||
615 | /* vendor, device, subsystem, emu10k1_chip, emu10k2_chip, ca0102_chip, ca0108_chip, ca0151_chip, spk71, spdif_bug, ac97_chip, ecard, driver, name */ | ||
616 | |||
617 | static emu_chip_details_t emu_chip_details[] = { | 615 | static emu_chip_details_t emu_chip_details[] = { |
618 | /* Audigy 2 Value AC3 out does not work yet. Need to find out how to turn off interpolators.*/ | 616 | /* Audigy 2 Value AC3 out does not work yet. Need to find out how to turn off interpolators.*/ |
619 | {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x10011102, | 617 | {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x10011102, |
620 | .driver = "Audigy2", .name = "Audigy 2 Value [SB0400]", | 618 | .driver = "Audigy2", .name = "Audigy 2 Value [SB0400]", |
619 | .id = "Audigy2", | ||
621 | .emu10k2_chip = 1, | 620 | .emu10k2_chip = 1, |
622 | .ca0108_chip = 1, | 621 | .ca0108_chip = 1, |
623 | .spk71 = 1} , | 622 | .spk71 = 1, |
623 | .ac97_chip = 1} , | ||
624 | {.vendor = 0x1102, .device = 0x0008, | 624 | {.vendor = 0x1102, .device = 0x0008, |
625 | .driver = "Audigy2", .name = "Audigy 2 Value [Unknown]", | 625 | .driver = "Audigy2", .name = "Audigy 2 Value [Unknown]", |
626 | .id = "Audigy2", | ||
626 | .emu10k2_chip = 1, | 627 | .emu10k2_chip = 1, |
627 | .ca0108_chip = 1} , | 628 | .ca0108_chip = 1, |
629 | .ac97_chip = 1} , | ||
628 | {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20071102, | 630 | {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20071102, |
629 | .driver = "Audigy2", .name = "Audigy 4 PRO [SB0380]", | 631 | .driver = "Audigy2", .name = "Audigy 4 PRO [SB0380]", |
632 | .id = "Audigy2", | ||
630 | .emu10k2_chip = 1, | 633 | .emu10k2_chip = 1, |
631 | .ca0102_chip = 1, | 634 | .ca0102_chip = 1, |
632 | .ca0151_chip = 1, | 635 | .ca0151_chip = 1, |
@@ -635,6 +638,7 @@ static emu_chip_details_t emu_chip_details[] = { | |||
635 | .ac97_chip = 1} , | 638 | .ac97_chip = 1} , |
636 | {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20021102, | 639 | {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20021102, |
637 | .driver = "Audigy2", .name = "Audigy 2 ZS [SB0350]", | 640 | .driver = "Audigy2", .name = "Audigy 2 ZS [SB0350]", |
641 | .id = "Audigy2", | ||
638 | .emu10k2_chip = 1, | 642 | .emu10k2_chip = 1, |
639 | .ca0102_chip = 1, | 643 | .ca0102_chip = 1, |
640 | .ca0151_chip = 1, | 644 | .ca0151_chip = 1, |
@@ -643,6 +647,7 @@ static emu_chip_details_t emu_chip_details[] = { | |||
643 | .ac97_chip = 1} , | 647 | .ac97_chip = 1} , |
644 | {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20011102, | 648 | {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20011102, |
645 | .driver = "Audigy2", .name = "Audigy 2 ZS [2001]", | 649 | .driver = "Audigy2", .name = "Audigy 2 ZS [2001]", |
650 | .id = "Audigy2", | ||
646 | .emu10k2_chip = 1, | 651 | .emu10k2_chip = 1, |
647 | .ca0102_chip = 1, | 652 | .ca0102_chip = 1, |
648 | .ca0151_chip = 1, | 653 | .ca0151_chip = 1, |
@@ -651,6 +656,7 @@ static emu_chip_details_t emu_chip_details[] = { | |||
651 | .ac97_chip = 1} , | 656 | .ac97_chip = 1} , |
652 | {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10071102, | 657 | {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10071102, |
653 | .driver = "Audigy2", .name = "Audigy 2 [SB0240]", | 658 | .driver = "Audigy2", .name = "Audigy 2 [SB0240]", |
659 | .id = "Audigy2", | ||
654 | .emu10k2_chip = 1, | 660 | .emu10k2_chip = 1, |
655 | .ca0102_chip = 1, | 661 | .ca0102_chip = 1, |
656 | .ca0151_chip = 1, | 662 | .ca0151_chip = 1, |
@@ -659,35 +665,165 @@ static emu_chip_details_t emu_chip_details[] = { | |||
659 | .ac97_chip = 1} , | 665 | .ac97_chip = 1} , |
660 | {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10051102, | 666 | {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10051102, |
661 | .driver = "Audigy2", .name = "Audigy 2 EX [1005]", | 667 | .driver = "Audigy2", .name = "Audigy 2 EX [1005]", |
668 | .id = "Audigy2", | ||
662 | .emu10k2_chip = 1, | 669 | .emu10k2_chip = 1, |
663 | .ca0102_chip = 1, | 670 | .ca0102_chip = 1, |
664 | .ca0151_chip = 1, | 671 | .ca0151_chip = 1, |
665 | .spdif_bug = 1} , | 672 | .spdif_bug = 1} , |
666 | {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10021102, | 673 | {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10021102, |
667 | .driver = "Audigy2", .name = "Audigy 2 Platinum [SB0240P]", | 674 | .driver = "Audigy2", .name = "Audigy 2 Platinum [SB0240P]", |
675 | .id = "Audigy2", | ||
668 | .emu10k2_chip = 1, | 676 | .emu10k2_chip = 1, |
669 | .ca0102_chip = 1, | 677 | .ca0102_chip = 1, |
670 | .ca0151_chip = 1, | 678 | .ca0151_chip = 1, |
671 | .spk71 = 1, | 679 | .spk71 = 1, |
672 | .spdif_bug = 1, | 680 | .spdif_bug = 1, |
673 | .ac97_chip = 1} , | 681 | .ac97_chip = 1} , |
682 | {.vendor = 0x1102, .device = 0x0004, .revision = 0x04, | ||
683 | .driver = "Audigy2", .name = "Audigy 2 [Unknown]", | ||
684 | .id = "Audigy2", | ||
685 | .emu10k2_chip = 1, | ||
686 | .ca0102_chip = 1, | ||
687 | .ca0151_chip = 1, | ||
688 | .spdif_bug = 1, | ||
689 | .ac97_chip = 1} , | ||
690 | {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10020052, | ||
691 | .driver = "Audigy", .name = "Audigy 1 ES [SB0160]", | ||
692 | .id = "Audigy", | ||
693 | .emu10k2_chip = 1, | ||
694 | .ca0102_chip = 1, | ||
695 | .spdif_bug = 1, | ||
696 | .ac97_chip = 1} , | ||
697 | {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x00531102, | ||
698 | .driver = "Audigy", .name = "Audigy 1 [SB0090]", | ||
699 | .id = "Audigy", | ||
700 | .emu10k2_chip = 1, | ||
701 | .ca0102_chip = 1, | ||
702 | .ac97_chip = 1} , | ||
703 | {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x00511102, | ||
704 | .driver = "Audigy", .name = "Audigy 1 [SB0090]", | ||
705 | .id = "Audigy", | ||
706 | .emu10k2_chip = 1, | ||
707 | .ca0102_chip = 1, | ||
708 | .ac97_chip = 1} , | ||
674 | {.vendor = 0x1102, .device = 0x0004, | 709 | {.vendor = 0x1102, .device = 0x0004, |
675 | .driver = "Audigy", .name = "Audigy 1 or 2 [Unknown]", | 710 | .driver = "Audigy", .name = "Audigy 1 [Unknown]", |
711 | .id = "Audigy", | ||
676 | .emu10k2_chip = 1, | 712 | .emu10k2_chip = 1, |
677 | .ca0102_chip = 1, | 713 | .ca0102_chip = 1, |
678 | .spdif_bug = 1} , | 714 | .ac97_chip = 1} , |
679 | {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x40011102, | 715 | {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x40011102, |
680 | .driver = "EMU10K1", .name = "E-mu APS [4001]", | 716 | .driver = "EMU10K1", .name = "E-mu APS [4001]", |
717 | .id = "APS", | ||
681 | .emu10k1_chip = 1, | 718 | .emu10k1_chip = 1, |
682 | .ecard = 1} , | 719 | .ecard = 1} , |
720 | {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80611102, | ||
721 | .driver = "EMU10K1", .name = "SBLive! Player 5.1 [SB0060]", | ||
722 | .id = "Live", | ||
723 | .emu10k1_chip = 1, | ||
724 | .ac97_chip = 1, | ||
725 | .sblive51 = 1} , | ||
683 | {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80641102, | 726 | {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80641102, |
684 | .driver = "EMU10K1", .name = "SB Live 5.1", | 727 | .driver = "EMU10K1", .name = "SB Live 5.1", |
728 | .id = "Live", | ||
729 | .emu10k1_chip = 1, | ||
730 | .ac97_chip = 1, | ||
731 | .sblive51 = 1} , | ||
732 | {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80401102, | ||
733 | .driver = "EMU10K1", .name = "SBLive! Platinum [CT4760P]", | ||
734 | .id = "Live", | ||
685 | .emu10k1_chip = 1, | 735 | .emu10k1_chip = 1, |
686 | .ac97_chip = 1} , | 736 | .ac97_chip = 1} , |
737 | {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x00211102, | ||
738 | .driver = "EMU10K1", .name = "SBLive! [CT4620]", | ||
739 | .id = "Live", | ||
740 | .emu10k1_chip = 1, | ||
741 | .ac97_chip = 1, | ||
742 | .sblive51 = 1} , | ||
743 | {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x00201102, | ||
744 | .driver = "EMU10K1", .name = "SBLive! Value [CT4670]", | ||
745 | .id = "Live", | ||
746 | .emu10k1_chip = 1, | ||
747 | .ac97_chip = 1, | ||
748 | .sblive51 = 1} , | ||
749 | {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80221102, | ||
750 | .driver = "EMU10K1", .name = "SBLive! Value [CT4780]", | ||
751 | .id = "Live", | ||
752 | .emu10k1_chip = 1, | ||
753 | .ac97_chip = 1, | ||
754 | .sblive51 = 1} , | ||
755 | {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80231102, | ||
756 | .driver = "EMU10K1", .name = "SB PCI512 [CT4790]", | ||
757 | .id = "Live", | ||
758 | .emu10k1_chip = 1, | ||
759 | .ac97_chip = 1, | ||
760 | .sblive51 = 1} , | ||
761 | {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80261102, | ||
762 | .driver = "EMU10K1", .name = "SBLive! Value [CT4830]", | ||
763 | .id = "Live", | ||
764 | .emu10k1_chip = 1, | ||
765 | .ac97_chip = 1, | ||
766 | .sblive51 = 1} , | ||
767 | {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80311102, | ||
768 | .driver = "EMU10K1", .name = "SBLive! Value [CT4831]", | ||
769 | .id = "Live", | ||
770 | .emu10k1_chip = 1, | ||
771 | .ac97_chip = 1, | ||
772 | .sblive51 = 1} , | ||
773 | {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80271102, | ||
774 | .driver = "EMU10K1", .name = "SBLive! Value [CT4832]", | ||
775 | .id = "Live", | ||
776 | .emu10k1_chip = 1, | ||
777 | .ac97_chip = 1, | ||
778 | .sblive51 = 1} , | ||
779 | {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80511102, | ||
780 | .driver = "EMU10K1", .name = "SBLive! Value [CT4850]", | ||
781 | .id = "Live", | ||
782 | .emu10k1_chip = 1, | ||
783 | .ac97_chip = 1, | ||
784 | .sblive51 = 1} , | ||
785 | {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80281102, | ||
786 | .driver = "EMU10K1", .name = "SBLive! Value [CT4870]", | ||
787 | .id = "Live", | ||
788 | .emu10k1_chip = 1, | ||
789 | .ac97_chip = 1, | ||
790 | .sblive51 = 1} , | ||
791 | {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80321102, | ||
792 | .driver = "EMU10K1", .name = "SBLive! Value [CT4871]", | ||
793 | .id = "Live", | ||
794 | .emu10k1_chip = 1, | ||
795 | .ac97_chip = 1, | ||
796 | .sblive51 = 1} , | ||
797 | {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80611102, | ||
798 | .driver = "EMU10K1", .name = "SBLive! Value [SB0060]", | ||
799 | .id = "Live", | ||
800 | .emu10k1_chip = 1, | ||
801 | .ac97_chip = 1, | ||
802 | .sblive51 = 1} , | ||
803 | {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80691102, | ||
804 | .driver = "EMU10K1", .name = "SBLive! Value [SB0101]", | ||
805 | .id = "Live", | ||
806 | .emu10k1_chip = 1, | ||
807 | .ac97_chip = 1, | ||
808 | .sblive51 = 1} , | ||
809 | {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x806A1102, | ||
810 | .driver = "EMU10K1", .name = "SBLive! Value [SB0103]", | ||
811 | .id = "Live", | ||
812 | .emu10k1_chip = 1, | ||
813 | .ac97_chip = 1, | ||
814 | .sblive51 = 1} , | ||
815 | {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x806B1102, | ||
816 | .driver = "EMU10K1", .name = "SBLive! [SB0105]", | ||
817 | .id = "Live", | ||
818 | .emu10k1_chip = 1, | ||
819 | .ac97_chip = 1, | ||
820 | .sblive51 = 1} , | ||
687 | {.vendor = 0x1102, .device = 0x0002, | 821 | {.vendor = 0x1102, .device = 0x0002, |
688 | .driver = "EMU10K1", .name = "SB Live [Unknown]", | 822 | .driver = "EMU10K1", .name = "SB Live [Unknown]", |
823 | .id = "Live", | ||
689 | .emu10k1_chip = 1, | 824 | .emu10k1_chip = 1, |
690 | .ac97_chip = 1} , | 825 | .ac97_chip = 1, |
826 | .sblive51 = 1} , | ||
691 | { } /* terminator */ | 827 | { } /* terminator */ |
692 | }; | 828 | }; |
693 | 829 | ||
@@ -738,13 +874,15 @@ int __devinit snd_emu10k1_create(snd_card_t * card, | |||
738 | emu->revision = revision; | 874 | emu->revision = revision; |
739 | pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &emu->serial); | 875 | pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &emu->serial); |
740 | pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &emu->model); | 876 | pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &emu->model); |
741 | emu->card_type = EMU10K1_CARD_CREATIVE; | ||
742 | 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); | 877 | 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); |
743 | 878 | ||
744 | for (c = emu_chip_details; c->vendor; c++) { | 879 | for (c = emu_chip_details; c->vendor; c++) { |
745 | if (c->vendor == pci->vendor && c->device == pci->device) { | 880 | if (c->vendor == pci->vendor && c->device == pci->device) { |
746 | if (c->subsystem == emu->serial) break; | 881 | if (c->subsystem && c->subsystem != emu->serial) |
747 | if (c->subsystem == 0) break; | 882 | continue; |
883 | if (c->revision && c->revision != emu->revision) | ||
884 | continue; | ||
885 | break; | ||
748 | } | 886 | } |
749 | } | 887 | } |
750 | if (c->vendor == 0) { | 888 | if (c->vendor == 0) { |
@@ -759,6 +897,23 @@ int __devinit snd_emu10k1_create(snd_card_t * card, | |||
759 | else | 897 | else |
760 | snd_printdd("Sound card name=%s, vendor=0x%x, device=0x%x, subsystem=0x%x\n", c->name, pci->vendor, pci->device, emu->serial); | 898 | snd_printdd("Sound card name=%s, vendor=0x%x, device=0x%x, subsystem=0x%x\n", c->name, pci->vendor, pci->device, emu->serial); |
761 | 899 | ||
900 | if (!*card->id && c->id) { | ||
901 | int i, n = 0; | ||
902 | strlcpy(card->id, c->id, sizeof(card->id)); | ||
903 | for (;;) { | ||
904 | for (i = 0; i < snd_ecards_limit; i++) { | ||
905 | if (snd_cards[i] && !strcmp(snd_cards[i]->id, card->id)) | ||
906 | break; | ||
907 | } | ||
908 | if (i >= snd_ecards_limit) | ||
909 | break; | ||
910 | n++; | ||
911 | if (n >= SNDRV_CARDS) | ||
912 | break; | ||
913 | snprintf(card->id, sizeof(card->id), "%s_%d", c->id, n); | ||
914 | } | ||
915 | } | ||
916 | |||
762 | is_audigy = emu->audigy = c->emu10k2_chip; | 917 | is_audigy = emu->audigy = c->emu10k2_chip; |
763 | 918 | ||
764 | /* set the DMA transfer mask */ | 919 | /* set the DMA transfer mask */ |
@@ -816,15 +971,6 @@ int __devinit snd_emu10k1_create(snd_card_t * card, | |||
816 | 971 | ||
817 | pci_set_master(pci); | 972 | pci_set_master(pci); |
818 | 973 | ||
819 | if (c->ecard) { | ||
820 | emu->card_type = EMU10K1_CARD_EMUAPS; | ||
821 | emu->APS = 1; | ||
822 | } | ||
823 | if (! c->ac97_chip) | ||
824 | emu->no_ac97 = 1; | ||
825 | |||
826 | emu->spk71 = c->spk71; | ||
827 | |||
828 | emu->fx8010.fxbus_mask = 0x303f; | 974 | emu->fx8010.fxbus_mask = 0x303f; |
829 | if (extin_mask == 0) | 975 | if (extin_mask == 0) |
830 | extin_mask = 0x3fcf; | 976 | extin_mask = 0x3fcf; |
@@ -833,7 +979,7 @@ int __devinit snd_emu10k1_create(snd_card_t * card, | |||
833 | emu->fx8010.extin_mask = extin_mask; | 979 | emu->fx8010.extin_mask = extin_mask; |
834 | emu->fx8010.extout_mask = extout_mask; | 980 | emu->fx8010.extout_mask = extout_mask; |
835 | 981 | ||
836 | if (emu->APS) { | 982 | if (emu->card_capabilities->ecard) { |
837 | if ((err = snd_emu10k1_ecard_init(emu)) < 0) { | 983 | if ((err = snd_emu10k1_ecard_init(emu)) < 0) { |
838 | snd_emu10k1_free(emu); | 984 | snd_emu10k1_free(emu); |
839 | return err; | 985 | return err; |
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index 27dfd8ddddf4..e90c5ddd1d17 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c | |||
@@ -361,10 +361,7 @@ static void snd_emu10k1x_gpio_write(emu10k1x_t *emu, unsigned int value) | |||
361 | 361 | ||
362 | static void snd_emu10k1x_pcm_free_substream(snd_pcm_runtime_t *runtime) | 362 | static void snd_emu10k1x_pcm_free_substream(snd_pcm_runtime_t *runtime) |
363 | { | 363 | { |
364 | emu10k1x_pcm_t *epcm = runtime->private_data; | 364 | kfree(runtime->private_data); |
365 | |||
366 | if (epcm) | ||
367 | kfree(epcm); | ||
368 | } | 365 | } |
369 | 366 | ||
370 | static void snd_emu10k1x_pcm_interrupt(emu10k1x_t *emu, emu10k1x_voice_t *voice) | 367 | static void snd_emu10k1x_pcm_interrupt(emu10k1x_t *emu, emu10k1x_voice_t *voice) |
@@ -1075,6 +1072,7 @@ static int __devinit snd_emu10k1x_proc_init(emu10k1x_t * emu) | |||
1075 | snd_info_set_text_ops(entry, emu, 1024, snd_emu10k1x_proc_reg_read); | 1072 | snd_info_set_text_ops(entry, emu, 1024, snd_emu10k1x_proc_reg_read); |
1076 | entry->c.text.write_size = 64; | 1073 | entry->c.text.write_size = 64; |
1077 | entry->c.text.write = snd_emu10k1x_proc_reg_write; | 1074 | entry->c.text.write = snd_emu10k1x_proc_reg_write; |
1075 | entry->mode |= S_IWUSR; | ||
1078 | entry->private_data = emu; | 1076 | entry->private_data = emu; |
1079 | } | 1077 | } |
1080 | 1078 | ||
@@ -1627,7 +1625,7 @@ static int __init alsa_card_emu10k1x_init(void) | |||
1627 | { | 1625 | { |
1628 | int err; | 1626 | int err; |
1629 | 1627 | ||
1630 | if ((err = pci_module_init(&driver)) > 0) | 1628 | if ((err = pci_register_driver(&driver)) > 0) |
1631 | return err; | 1629 | return err; |
1632 | 1630 | ||
1633 | return 0; | 1631 | return 0; |
diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c index b9fa2e887fee..0529fb281125 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c | |||
@@ -1077,7 +1077,7 @@ static int __devinit _snd_emu10k1_audigy_init_efx(emu10k1_t *emu) | |||
1077 | gpr += 2; | 1077 | gpr += 2; |
1078 | 1078 | ||
1079 | /* PCM Side Playback (independent from stereo mix) */ | 1079 | /* PCM Side Playback (independent from stereo mix) */ |
1080 | if (emu->spk71) { | 1080 | if (emu->card_capabilities->spk71) { |
1081 | A_OP(icode, &ptr, iMAC0, A_GPR(playback+6), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_SIDE)); | 1081 | A_OP(icode, &ptr, iMAC0, A_GPR(playback+6), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_SIDE)); |
1082 | A_OP(icode, &ptr, iMAC0, A_GPR(playback+7), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_SIDE)); | 1082 | A_OP(icode, &ptr, iMAC0, A_GPR(playback+7), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_SIDE)); |
1083 | snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Side Playback Volume", gpr, 100); | 1083 | snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Side Playback Volume", gpr, 100); |
@@ -1145,14 +1145,14 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) | |||
1145 | A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_SPDIF_CD_L); | 1145 | A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_SPDIF_CD_L); |
1146 | A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_SPDIF_CD_R); | 1146 | A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_SPDIF_CD_R); |
1147 | snd_emu10k1_init_stereo_control(&controls[nctl++], | 1147 | snd_emu10k1_init_stereo_control(&controls[nctl++], |
1148 | emu->no_ac97 ? "CD Playback Volume" : "Audigy CD Playback Volume", | 1148 | emu->card_capabilities->ac97_chip ? "Audigy CD Playback Volume" : "CD Playback Volume", |
1149 | gpr, 0); | 1149 | gpr, 0); |
1150 | gpr += 2; | 1150 | gpr += 2; |
1151 | /* Audigy CD Capture Volume */ | 1151 | /* Audigy CD Capture Volume */ |
1152 | A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_SPDIF_CD_L); | 1152 | A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_SPDIF_CD_L); |
1153 | A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_SPDIF_CD_R); | 1153 | A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_SPDIF_CD_R); |
1154 | snd_emu10k1_init_stereo_control(&controls[nctl++], | 1154 | snd_emu10k1_init_stereo_control(&controls[nctl++], |
1155 | emu->no_ac97 ? "CD Capture Volume" : "Audigy CD Capture Volume", | 1155 | emu->card_capabilities->ac97_chip ? "Audigy CD Capture Volume" : "CD Capture Volume", |
1156 | gpr, 0); | 1156 | gpr, 0); |
1157 | gpr += 2; | 1157 | gpr += 2; |
1158 | 1158 | ||
@@ -1171,14 +1171,14 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) | |||
1171 | A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_LINE2_L); | 1171 | A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_LINE2_L); |
1172 | A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_LINE2_R); | 1172 | A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_LINE2_R); |
1173 | snd_emu10k1_init_stereo_control(&controls[nctl++], | 1173 | snd_emu10k1_init_stereo_control(&controls[nctl++], |
1174 | emu->no_ac97 ? "Line Playback Volume" : "Line2 Playback Volume", | 1174 | emu->card_capabilities->ac97_chip ? "Line2 Playback Volume" : "Line Playback Volume", |
1175 | gpr, 0); | 1175 | gpr, 0); |
1176 | gpr += 2; | 1176 | gpr += 2; |
1177 | /* Line2 Capture Volume */ | 1177 | /* Line2 Capture Volume */ |
1178 | A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_LINE2_L); | 1178 | A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_LINE2_L); |
1179 | A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_LINE2_R); | 1179 | A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_LINE2_R); |
1180 | snd_emu10k1_init_stereo_control(&controls[nctl++], | 1180 | snd_emu10k1_init_stereo_control(&controls[nctl++], |
1181 | emu->no_ac97 ? "Line Capture Volume" : "Line2 Capture Volume", | 1181 | emu->card_capabilities->ac97_chip ? "Line2 Capture Volume" : "Line Capture Volume", |
1182 | gpr, 0); | 1182 | gpr, 0); |
1183 | gpr += 2; | 1183 | gpr += 2; |
1184 | 1184 | ||
@@ -1197,14 +1197,14 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) | |||
1197 | A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AUX2_L); | 1197 | A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AUX2_L); |
1198 | A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AUX2_R); | 1198 | A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AUX2_R); |
1199 | snd_emu10k1_init_stereo_control(&controls[nctl++], | 1199 | snd_emu10k1_init_stereo_control(&controls[nctl++], |
1200 | emu->no_ac97 ? "Aux Playback Volume" : "Aux2 Playback Volume", | 1200 | emu->card_capabilities->ac97_chip ? "Aux2 Playback Volume" : "Aux Playback Volume", |
1201 | gpr, 0); | 1201 | gpr, 0); |
1202 | gpr += 2; | 1202 | gpr += 2; |
1203 | /* Aux2 Capture Volume */ | 1203 | /* Aux2 Capture Volume */ |
1204 | A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_AUX2_L); | 1204 | A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_AUX2_L); |
1205 | A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_AUX2_R); | 1205 | A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_AUX2_R); |
1206 | snd_emu10k1_init_stereo_control(&controls[nctl++], | 1206 | snd_emu10k1_init_stereo_control(&controls[nctl++], |
1207 | emu->no_ac97 ? "Aux Capture Volume" : "Aux2 Capture Volume", | 1207 | emu->card_capabilities->ac97_chip ? "Aux2 Capture Volume" : "Aux Capture Volume", |
1208 | gpr, 0); | 1208 | gpr, 0); |
1209 | gpr += 2; | 1209 | gpr += 2; |
1210 | 1210 | ||
@@ -1232,7 +1232,7 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) | |||
1232 | snd_emu10k1_init_mono_control(&controls[nctl++], "LFE Playback Volume", gpr, 0); | 1232 | snd_emu10k1_init_mono_control(&controls[nctl++], "LFE Playback Volume", gpr, 0); |
1233 | gpr++; | 1233 | gpr++; |
1234 | 1234 | ||
1235 | if (emu->spk71) { | 1235 | if (emu->card_capabilities->spk71) { |
1236 | /* Stereo Mix Side Playback */ | 1236 | /* Stereo Mix Side Playback */ |
1237 | A_OP(icode, &ptr, iMAC0, A_GPR(playback+6), A_GPR(playback+6), A_GPR(gpr), A_GPR(stereo_mix)); | 1237 | A_OP(icode, &ptr, iMAC0, A_GPR(playback+6), A_GPR(playback+6), A_GPR(gpr), A_GPR(stereo_mix)); |
1238 | A_OP(icode, &ptr, iMAC0, A_GPR(playback+7), A_GPR(playback+7), A_GPR(gpr+1), A_GPR(stereo_mix+1)); | 1238 | A_OP(icode, &ptr, iMAC0, A_GPR(playback+7), A_GPR(playback+7), A_GPR(gpr+1), A_GPR(stereo_mix+1)); |
@@ -1266,7 +1266,7 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) | |||
1266 | 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 */ | 1266 | 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 */ |
1267 | A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), A_GPR(playback + 4), A_C_00000000, A_C_00000000); /* center */ | 1267 | A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), A_GPR(playback + 4), A_C_00000000, A_C_00000000); /* center */ |
1268 | A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), A_GPR(playback + 5), A_C_00000000, A_C_00000000); /* LFE */ | 1268 | A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), A_GPR(playback + 5), A_C_00000000, A_C_00000000); /* LFE */ |
1269 | if (emu->spk71) { | 1269 | if (emu->card_capabilities->spk71) { |
1270 | 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 */ | 1270 | 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 */ |
1271 | 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 */ | 1271 | 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 */ |
1272 | } | 1272 | } |
@@ -1359,7 +1359,7 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) | |||
1359 | A_PUT_STEREO_OUTPUT(A_EXTOUT_AREAR_L, A_EXTOUT_AREAR_R, playback+2 + SND_EMU10K1_PLAYBACK_CHANNELS); | 1359 | A_PUT_STEREO_OUTPUT(A_EXTOUT_AREAR_L, A_EXTOUT_AREAR_R, playback+2 + SND_EMU10K1_PLAYBACK_CHANNELS); |
1360 | A_PUT_OUTPUT(A_EXTOUT_ACENTER, playback+4 + SND_EMU10K1_PLAYBACK_CHANNELS); | 1360 | A_PUT_OUTPUT(A_EXTOUT_ACENTER, playback+4 + SND_EMU10K1_PLAYBACK_CHANNELS); |
1361 | A_PUT_OUTPUT(A_EXTOUT_ALFE, playback+5 + SND_EMU10K1_PLAYBACK_CHANNELS); | 1361 | A_PUT_OUTPUT(A_EXTOUT_ALFE, playback+5 + SND_EMU10K1_PLAYBACK_CHANNELS); |
1362 | if (emu->spk71) | 1362 | if (emu->card_capabilities->spk71) |
1363 | A_PUT_STEREO_OUTPUT(A_EXTOUT_ASIDE_L, A_EXTOUT_ASIDE_R, playback+6 + SND_EMU10K1_PLAYBACK_CHANNELS); | 1363 | A_PUT_STEREO_OUTPUT(A_EXTOUT_ASIDE_L, A_EXTOUT_ASIDE_R, playback+6 + SND_EMU10K1_PLAYBACK_CHANNELS); |
1364 | 1364 | ||
1365 | /* headphone */ | 1365 | /* headphone */ |
@@ -1982,22 +1982,27 @@ static int __devinit _snd_emu10k1_init_efx(emu10k1_t *emu) | |||
1982 | OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_MIC_CAP), GPR(capture + 2), C_00000000, C_00000000); | 1982 | OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_MIC_CAP), GPR(capture + 2), C_00000000, C_00000000); |
1983 | 1983 | ||
1984 | /* EFX capture - capture the 16 EXTINS */ | 1984 | /* EFX capture - capture the 16 EXTINS */ |
1985 | OP(icode, &ptr, iACC3, FXBUS2(14), C_00000000, C_00000000, EXTIN(0)); | 1985 | if (emu->card_capabilities->sblive51) { |
1986 | OP(icode, &ptr, iACC3, FXBUS2(15), C_00000000, C_00000000, EXTIN(1)); | 1986 | /* On the Live! 5.1, FXBUS2(1) and FXBUS(2) are shared with EXTOUT_ACENTER |
1987 | OP(icode, &ptr, iACC3, FXBUS2(0), C_00000000, C_00000000, EXTIN(2)); | 1987 | * and EXTOUT_ALFE, so we can't connect inputs to them for multitrack recording. |
1988 | OP(icode, &ptr, iACC3, FXBUS2(3), C_00000000, C_00000000, EXTIN(3)); | 1988 | * |
1989 | /* Dont connect anything to FXBUS2 1 and 2. These are shared with | 1989 | * Since only 14 of the 16 EXTINs are used, this is not a big problem. |
1990 | * Center/LFE on the SBLive 5.1. The kX driver only changes the | 1990 | * We route AC97L and R to FX capture 14 and 15, SPDIF CD in to FX capture |
1991 | * routing when it detects an SBLive 5.1. | 1991 | * 0 and 3, then the rest of the EXTINs to the corresponding FX capture |
1992 | * | 1992 | * channel. Multitrack recorders will still see the center/lfe output signal |
1993 | * Since only 14 of the 16 EXTINs are used, this is not a big problem. | 1993 | * on the second and third channels. |
1994 | * We route AC97L and R to FX capture 14 and 15, SPDIF CD in to FX capture | 1994 | */ |
1995 | * 0 and 3, then the rest of the EXTINs to the corresponding FX capture | 1995 | OP(icode, &ptr, iACC3, FXBUS2(14), C_00000000, C_00000000, EXTIN(0)); |
1996 | * channel. | 1996 | OP(icode, &ptr, iACC3, FXBUS2(15), C_00000000, C_00000000, EXTIN(1)); |
1997 | */ | 1997 | OP(icode, &ptr, iACC3, FXBUS2(0), C_00000000, C_00000000, EXTIN(2)); |
1998 | for (z = 4; z < 14; z++) { | 1998 | OP(icode, &ptr, iACC3, FXBUS2(3), C_00000000, C_00000000, EXTIN(3)); |
1999 | OP(icode, &ptr, iACC3, FXBUS2(z), C_00000000, C_00000000, EXTIN(z)); | 1999 | for (z = 4; z < 14; z++) |
2000 | OP(icode, &ptr, iACC3, FXBUS2(z), C_00000000, C_00000000, EXTIN(z)); | ||
2001 | } else { | ||
2002 | for (z = 0; z < 16; z++) | ||
2003 | OP(icode, &ptr, iACC3, FXBUS2(z), C_00000000, C_00000000, EXTIN(z)); | ||
2000 | } | 2004 | } |
2005 | |||
2001 | 2006 | ||
2002 | if (gpr > tmp) { | 2007 | if (gpr > tmp) { |
2003 | snd_BUG(); | 2008 | snd_BUG(); |
@@ -2128,7 +2133,6 @@ static int snd_emu10k1_fx8010_info(emu10k1_t *emu, emu10k1_fx8010_info_t *info) | |||
2128 | int res; | 2133 | int res; |
2129 | 2134 | ||
2130 | memset(info, 0, sizeof(info)); | 2135 | memset(info, 0, sizeof(info)); |
2131 | info->card = emu->card_type; | ||
2132 | info->internal_tram_size = emu->fx8010.itram_size; | 2136 | info->internal_tram_size = emu->fx8010.itram_size; |
2133 | info->external_tram_size = emu->fx8010.etram_pages.bytes / 2; | 2137 | info->external_tram_size = emu->fx8010.etram_pages.bytes / 2; |
2134 | fxbus = fxbuses; | 2138 | fxbus = fxbuses; |
diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index 044663d31aa7..6be82c5fe138 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c | |||
@@ -68,6 +68,7 @@ static int snd_emu10k1_spdif_get_mask(snd_kcontrol_t * kcontrol, | |||
68 | return 0; | 68 | return 0; |
69 | } | 69 | } |
70 | 70 | ||
71 | #if 0 | ||
71 | static int snd_audigy_spdif_output_rate_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) | 72 | static int snd_audigy_spdif_output_rate_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) |
72 | { | 73 | { |
73 | static char *texts[] = {"44100", "48000", "96000"}; | 74 | static char *texts[] = {"44100", "48000", "96000"}; |
@@ -152,6 +153,7 @@ static snd_kcontrol_new_t snd_audigy_spdif_output_rate = | |||
152 | .get = snd_audigy_spdif_output_rate_get, | 153 | .get = snd_audigy_spdif_output_rate_get, |
153 | .put = snd_audigy_spdif_output_rate_put | 154 | .put = snd_audigy_spdif_output_rate_put |
154 | }; | 155 | }; |
156 | #endif | ||
155 | 157 | ||
156 | static int snd_emu10k1_spdif_put(snd_kcontrol_t * kcontrol, | 158 | static int snd_emu10k1_spdif_put(snd_kcontrol_t * kcontrol, |
157 | snd_ctl_elem_value_t * ucontrol) | 159 | snd_ctl_elem_value_t * ucontrol) |
@@ -791,7 +793,7 @@ int __devinit snd_emu10k1_mixer(emu10k1_t *emu) | |||
791 | NULL | 793 | NULL |
792 | }; | 794 | }; |
793 | 795 | ||
794 | if (!emu->no_ac97) { | 796 | if (emu->card_capabilities->ac97_chip) { |
795 | ac97_bus_t *pbus; | 797 | ac97_bus_t *pbus; |
796 | ac97_template_t ac97; | 798 | ac97_template_t ac97; |
797 | static ac97_bus_ops_t ops = { | 799 | static ac97_bus_ops_t ops = { |
@@ -833,7 +835,7 @@ int __devinit snd_emu10k1_mixer(emu10k1_t *emu) | |||
833 | for (; *c; c++) | 835 | for (; *c; c++) |
834 | remove_ctl(card, *c); | 836 | remove_ctl(card, *c); |
835 | } else { | 837 | } else { |
836 | if (emu->APS) | 838 | if (emu->card_capabilities->ecard) |
837 | strcpy(emu->card->mixername, "EMU APS"); | 839 | strcpy(emu->card->mixername, "EMU APS"); |
838 | else if (emu->audigy) | 840 | else if (emu->audigy) |
839 | strcpy(emu->card->mixername, "SB Audigy"); | 841 | strcpy(emu->card->mixername, "SB Audigy"); |
@@ -918,7 +920,7 @@ int __devinit snd_emu10k1_mixer(emu10k1_t *emu) | |||
918 | mix->attn[0] = 0xffff; | 920 | mix->attn[0] = 0xffff; |
919 | } | 921 | } |
920 | 922 | ||
921 | if (! emu->APS) { /* FIXME: APS has these controls? */ | 923 | if (! emu->card_capabilities->ecard) { /* FIXME: APS has these controls? */ |
922 | /* sb live! and audigy */ | 924 | /* sb live! and audigy */ |
923 | if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu)) == NULL) | 925 | if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu)) == NULL) |
924 | return -ENOMEM; | 926 | return -ENOMEM; |
@@ -935,18 +937,20 @@ int __devinit snd_emu10k1_mixer(emu10k1_t *emu) | |||
935 | return -ENOMEM; | 937 | return -ENOMEM; |
936 | if ((err = snd_ctl_add(card, kctl))) | 938 | if ((err = snd_ctl_add(card, kctl))) |
937 | return err; | 939 | return err; |
940 | #if 0 | ||
938 | if ((kctl = snd_ctl_new1(&snd_audigy_spdif_output_rate, emu)) == NULL) | 941 | if ((kctl = snd_ctl_new1(&snd_audigy_spdif_output_rate, emu)) == NULL) |
939 | return -ENOMEM; | 942 | return -ENOMEM; |
940 | if ((err = snd_ctl_add(card, kctl))) | 943 | if ((err = snd_ctl_add(card, kctl))) |
941 | return err; | 944 | return err; |
942 | } else if (! emu->APS) { | 945 | #endif |
946 | } else if (! emu->card_capabilities->ecard) { | ||
943 | /* sb live! */ | 947 | /* sb live! */ |
944 | if ((kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu)) == NULL) | 948 | if ((kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu)) == NULL) |
945 | return -ENOMEM; | 949 | return -ENOMEM; |
946 | if ((err = snd_ctl_add(card, kctl))) | 950 | if ((err = snd_ctl_add(card, kctl))) |
947 | return err; | 951 | return err; |
948 | } | 952 | } |
949 | if (emu->audigy && emu->revision == 4) { /* P16V */ | 953 | if (emu->card_capabilities->ca0151_chip) { /* P16V */ |
950 | if ((err = snd_p16v_mixer(emu))) | 954 | if ((err = snd_p16v_mixer(emu))) |
951 | return err; | 955 | return err; |
952 | } | 956 | } |
diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index d1c2a02c486b..520b99af5f55 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c | |||
@@ -262,7 +262,7 @@ static unsigned int emu10k1_select_interprom(unsigned int pitch_target) | |||
262 | * | 262 | * |
263 | * returns: cache invalidate size in samples | 263 | * returns: cache invalidate size in samples |
264 | */ | 264 | */ |
265 | static int inline emu10k1_ccis(int stereo, int w_16) | 265 | static inline int emu10k1_ccis(int stereo, int w_16) |
266 | { | 266 | { |
267 | if (w_16) { | 267 | if (w_16) { |
268 | return stereo ? 24 : 26; | 268 | return stereo ? 24 : 26; |
@@ -991,9 +991,7 @@ static void snd_emu10k1_pcm_efx_mixer_notify(emu10k1_t *emu, int idx, int activa | |||
991 | 991 | ||
992 | static void snd_emu10k1_pcm_free_substream(snd_pcm_runtime_t *runtime) | 992 | static void snd_emu10k1_pcm_free_substream(snd_pcm_runtime_t *runtime) |
993 | { | 993 | { |
994 | emu10k1_pcm_t *epcm = runtime->private_data; | 994 | kfree(runtime->private_data); |
995 | |||
996 | kfree(epcm); | ||
997 | } | 995 | } |
998 | 996 | ||
999 | static int snd_emu10k1_efx_playback_close(snd_pcm_substream_t * substream) | 997 | static int snd_emu10k1_efx_playback_close(snd_pcm_substream_t * substream) |
diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c index d990d5eb45a8..cc22707c91fa 100644 --- a/sound/pci/emu10k1/emuproc.c +++ b/sound/pci/emu10k1/emuproc.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/init.h> | 30 | #include <linux/init.h> |
31 | #include <sound/core.h> | 31 | #include <sound/core.h> |
32 | #include <sound/emu10k1.h> | 32 | #include <sound/emu10k1.h> |
33 | #include "p16v.h" | ||
33 | 34 | ||
34 | static void snd_emu10k1_proc_spdif_status(emu10k1_t * emu, | 35 | static void snd_emu10k1_proc_spdif_status(emu10k1_t * emu, |
35 | snd_info_buffer_t * buffer, | 36 | snd_info_buffer_t * buffer, |
@@ -44,28 +45,34 @@ static void snd_emu10k1_proc_spdif_status(emu10k1_t * emu, | |||
44 | unsigned int status, rate = 0; | 45 | unsigned int status, rate = 0; |
45 | 46 | ||
46 | status = snd_emu10k1_ptr_read(emu, status_reg, 0); | 47 | status = snd_emu10k1_ptr_read(emu, status_reg, 0); |
47 | if (rate_reg > 0) | ||
48 | rate = snd_emu10k1_ptr_read(emu, rate_reg, 0); | ||
49 | 48 | ||
50 | snd_iprintf(buffer, "\n%s\n", title); | 49 | snd_iprintf(buffer, "\n%s\n", title); |
51 | 50 | ||
52 | snd_iprintf(buffer, "Professional Mode : %s\n", (status & SPCS_PROFESSIONAL) ? "yes" : "no"); | 51 | if (status != 0xffffffff) { |
53 | snd_iprintf(buffer, "Not Audio Data : %s\n", (status & SPCS_NOTAUDIODATA) ? "yes" : "no"); | 52 | snd_iprintf(buffer, "Professional Mode : %s\n", (status & SPCS_PROFESSIONAL) ? "yes" : "no"); |
54 | snd_iprintf(buffer, "Copyright : %s\n", (status & SPCS_COPYRIGHT) ? "yes" : "no"); | 53 | snd_iprintf(buffer, "Not Audio Data : %s\n", (status & SPCS_NOTAUDIODATA) ? "yes" : "no"); |
55 | snd_iprintf(buffer, "Emphasis : %s\n", emphasis[(status & SPCS_EMPHASISMASK) >> 3]); | 54 | snd_iprintf(buffer, "Copyright : %s\n", (status & SPCS_COPYRIGHT) ? "yes" : "no"); |
56 | snd_iprintf(buffer, "Mode : %i\n", (status & SPCS_MODEMASK) >> 6); | 55 | snd_iprintf(buffer, "Emphasis : %s\n", emphasis[(status & SPCS_EMPHASISMASK) >> 3]); |
57 | snd_iprintf(buffer, "Category Code : 0x%x\n", (status & SPCS_CATEGORYCODEMASK) >> 8); | 56 | snd_iprintf(buffer, "Mode : %i\n", (status & SPCS_MODEMASK) >> 6); |
58 | snd_iprintf(buffer, "Generation Status : %s\n", status & SPCS_GENERATIONSTATUS ? "original" : "copy"); | 57 | snd_iprintf(buffer, "Category Code : 0x%x\n", (status & SPCS_CATEGORYCODEMASK) >> 8); |
59 | snd_iprintf(buffer, "Source Mask : %i\n", (status & SPCS_SOURCENUMMASK) >> 16); | 58 | snd_iprintf(buffer, "Generation Status : %s\n", status & SPCS_GENERATIONSTATUS ? "original" : "copy"); |
60 | snd_iprintf(buffer, "Channel Number : %s\n", channel[(status & SPCS_CHANNELNUMMASK) >> 20]); | 59 | snd_iprintf(buffer, "Source Mask : %i\n", (status & SPCS_SOURCENUMMASK) >> 16); |
61 | snd_iprintf(buffer, "Sample Rate : %iHz\n", samplerate[(status & SPCS_SAMPLERATEMASK) >> 24]); | 60 | snd_iprintf(buffer, "Channel Number : %s\n", channel[(status & SPCS_CHANNELNUMMASK) >> 20]); |
62 | snd_iprintf(buffer, "Clock Accuracy : %s\n", clkaccy[(status & SPCS_CLKACCYMASK) >> 28]); | 61 | snd_iprintf(buffer, "Sample Rate : %iHz\n", samplerate[(status & SPCS_SAMPLERATEMASK) >> 24]); |
63 | 62 | snd_iprintf(buffer, "Clock Accuracy : %s\n", clkaccy[(status & SPCS_CLKACCYMASK) >> 28]); | |
64 | if (rate_reg > 0) { | 63 | |
65 | snd_iprintf(buffer, "S/PDIF Locked : %s\n", rate & SRCS_SPDIFLOCKED ? "on" : "off"); | 64 | if (rate_reg > 0) { |
66 | snd_iprintf(buffer, "Rate Locked : %s\n", rate & SRCS_RATELOCKED ? "on" : "off"); | 65 | rate = snd_emu10k1_ptr_read(emu, rate_reg, 0); |
67 | snd_iprintf(buffer, "Estimated Sample Rate : 0x%x\n", rate & SRCS_ESTSAMPLERATE); | 66 | snd_iprintf(buffer, "S/PDIF Valid : %s\n", rate & SRCS_SPDIFVALID ? "on" : "off"); |
67 | snd_iprintf(buffer, "S/PDIF Locked : %s\n", rate & SRCS_SPDIFLOCKED ? "on" : "off"); | ||
68 | snd_iprintf(buffer, "Rate Locked : %s\n", rate & SRCS_RATELOCKED ? "on" : "off"); | ||
69 | /* From ((Rate * 48000 ) / 262144); */ | ||
70 | snd_iprintf(buffer, "Estimated Sample Rate : %d\n", ((rate & 0xFFFFF ) * 375) >> 11); | ||
71 | } | ||
72 | } else { | ||
73 | snd_iprintf(buffer, "No signal detected.\n"); | ||
68 | } | 74 | } |
75 | |||
69 | } | 76 | } |
70 | 77 | ||
71 | static void snd_emu10k1_proc_read(snd_info_entry_t *entry, | 78 | static void snd_emu10k1_proc_read(snd_info_entry_t *entry, |
@@ -182,7 +189,7 @@ static void snd_emu10k1_proc_read(snd_info_entry_t *entry, | |||
182 | 189 | ||
183 | snd_iprintf(buffer, "EMU10K1\n\n"); | 190 | snd_iprintf(buffer, "EMU10K1\n\n"); |
184 | snd_iprintf(buffer, "Card : %s\n", | 191 | snd_iprintf(buffer, "Card : %s\n", |
185 | emu->audigy ? "Audigy" : (emu->APS ? "EMU APS" : "Creative")); | 192 | emu->audigy ? "Audigy" : (emu->card_capabilities->ecard ? "EMU APS" : "Creative")); |
186 | snd_iprintf(buffer, "Internal TRAM (words) : 0x%x\n", emu->fx8010.itram_size); | 193 | snd_iprintf(buffer, "Internal TRAM (words) : 0x%x\n", emu->fx8010.itram_size); |
187 | snd_iprintf(buffer, "External TRAM (words) : 0x%x\n", (int)emu->fx8010.etram_pages.bytes / 2); | 194 | snd_iprintf(buffer, "External TRAM (words) : 0x%x\n", (int)emu->fx8010.etram_pages.bytes / 2); |
188 | snd_iprintf(buffer, "\n"); | 195 | snd_iprintf(buffer, "\n"); |
@@ -223,15 +230,35 @@ static void snd_emu10k1_proc_read(snd_info_entry_t *entry, | |||
223 | snd_iprintf(buffer, "\nAll FX Outputs :\n"); | 230 | snd_iprintf(buffer, "\nAll FX Outputs :\n"); |
224 | for (idx = 0; idx < (emu->audigy ? 64 : 32); idx++) | 231 | for (idx = 0; idx < (emu->audigy ? 64 : 32); idx++) |
225 | snd_iprintf(buffer, " Output %02i [%s]\n", idx, outputs[idx]); | 232 | snd_iprintf(buffer, " Output %02i [%s]\n", idx, outputs[idx]); |
226 | snd_emu10k1_proc_spdif_status(emu, buffer, "S/PDIF Output 0", SPCS0, -1); | 233 | } |
227 | snd_emu10k1_proc_spdif_status(emu, buffer, "S/PDIF Output 1", SPCS1, -1); | 234 | |
228 | snd_emu10k1_proc_spdif_status(emu, buffer, "S/PDIF Output 2/3", SPCS2, -1); | 235 | static void snd_emu10k1_proc_spdif_read(snd_info_entry_t *entry, |
229 | snd_emu10k1_proc_spdif_status(emu, buffer, "CD-ROM S/PDIF", CDCS, CDSRCS); | 236 | snd_info_buffer_t * buffer) |
230 | snd_emu10k1_proc_spdif_status(emu, buffer, "General purpose S/PDIF", GPSCS, GPSRCS); | 237 | { |
238 | emu10k1_t *emu = entry->private_data; | ||
239 | snd_emu10k1_proc_spdif_status(emu, buffer, "CD-ROM S/PDIF In", CDCS, CDSRCS); | ||
240 | snd_emu10k1_proc_spdif_status(emu, buffer, "Optical or Coax S/PDIF In", GPSCS, GPSRCS); | ||
241 | #if 0 | ||
231 | val = snd_emu10k1_ptr_read(emu, ZVSRCS, 0); | 242 | val = snd_emu10k1_ptr_read(emu, ZVSRCS, 0); |
232 | snd_iprintf(buffer, "\nZoomed Video\n"); | 243 | snd_iprintf(buffer, "\nZoomed Video\n"); |
233 | snd_iprintf(buffer, "Rate Locked : %s\n", val & SRCS_RATELOCKED ? "on" : "off"); | 244 | snd_iprintf(buffer, "Rate Locked : %s\n", val & SRCS_RATELOCKED ? "on" : "off"); |
234 | snd_iprintf(buffer, "Estimated Sample Rate : 0x%x\n", val & SRCS_ESTSAMPLERATE); | 245 | snd_iprintf(buffer, "Estimated Sample Rate : 0x%x\n", val & SRCS_ESTSAMPLERATE); |
246 | #endif | ||
247 | } | ||
248 | |||
249 | static void snd_emu10k1_proc_rates_read(snd_info_entry_t *entry, | ||
250 | snd_info_buffer_t * buffer) | ||
251 | { | ||
252 | static int samplerate[8] = { 44100, 48000, 96000, 192000, 4, 5, 6, 7 }; | ||
253 | emu10k1_t *emu = entry->private_data; | ||
254 | unsigned int val, tmp, n; | ||
255 | val = snd_emu10k1_ptr20_read(emu, CAPTURE_RATE_STATUS, 0); | ||
256 | tmp = (val >> 16) & 0x8; | ||
257 | for (n=0;n<4;n++) { | ||
258 | tmp = val >> (16 + (n*4)); | ||
259 | if (tmp & 0x8) snd_iprintf(buffer, "Channel %d: Rate=%d\n", n, samplerate[tmp & 0x7]); | ||
260 | else snd_iprintf(buffer, "Channel %d: No input\n", n); | ||
261 | } | ||
235 | } | 262 | } |
236 | 263 | ||
237 | static void snd_emu10k1_proc_acode_read(snd_info_entry_t *entry, | 264 | static void snd_emu10k1_proc_acode_read(snd_info_entry_t *entry, |
@@ -500,32 +527,46 @@ int __devinit snd_emu10k1_proc_init(emu10k1_t * emu) | |||
500 | snd_info_set_text_ops(entry, emu, 1024, snd_emu_proc_io_reg_read); | 527 | snd_info_set_text_ops(entry, emu, 1024, snd_emu_proc_io_reg_read); |
501 | entry->c.text.write_size = 64; | 528 | entry->c.text.write_size = 64; |
502 | entry->c.text.write = snd_emu_proc_io_reg_write; | 529 | entry->c.text.write = snd_emu_proc_io_reg_write; |
530 | entry->mode |= S_IWUSR; | ||
503 | } | 531 | } |
504 | if (! snd_card_proc_new(emu->card, "ptr_regs00a", &entry)) { | 532 | if (! snd_card_proc_new(emu->card, "ptr_regs00a", &entry)) { |
505 | snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read00a); | 533 | snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read00a); |
506 | entry->c.text.write_size = 64; | 534 | entry->c.text.write_size = 64; |
507 | entry->c.text.write = snd_emu_proc_ptr_reg_write00; | 535 | entry->c.text.write = snd_emu_proc_ptr_reg_write00; |
536 | entry->mode |= S_IWUSR; | ||
508 | } | 537 | } |
509 | if (! snd_card_proc_new(emu->card, "ptr_regs00b", &entry)) { | 538 | if (! snd_card_proc_new(emu->card, "ptr_regs00b", &entry)) { |
510 | snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read00b); | 539 | snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read00b); |
511 | entry->c.text.write_size = 64; | 540 | entry->c.text.write_size = 64; |
512 | entry->c.text.write = snd_emu_proc_ptr_reg_write00; | 541 | entry->c.text.write = snd_emu_proc_ptr_reg_write00; |
542 | entry->mode |= S_IWUSR; | ||
513 | } | 543 | } |
514 | if (! snd_card_proc_new(emu->card, "ptr_regs20a", &entry)) { | 544 | if (! snd_card_proc_new(emu->card, "ptr_regs20a", &entry)) { |
515 | snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read20a); | 545 | snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read20a); |
516 | entry->c.text.write_size = 64; | 546 | entry->c.text.write_size = 64; |
517 | entry->c.text.write = snd_emu_proc_ptr_reg_write20; | 547 | entry->c.text.write = snd_emu_proc_ptr_reg_write20; |
548 | entry->mode |= S_IWUSR; | ||
518 | } | 549 | } |
519 | if (! snd_card_proc_new(emu->card, "ptr_regs20b", &entry)) { | 550 | if (! snd_card_proc_new(emu->card, "ptr_regs20b", &entry)) { |
520 | snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read20b); | 551 | snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read20b); |
521 | entry->c.text.write_size = 64; | 552 | entry->c.text.write_size = 64; |
522 | entry->c.text.write = snd_emu_proc_ptr_reg_write20; | 553 | entry->c.text.write = snd_emu_proc_ptr_reg_write20; |
554 | entry->mode |= S_IWUSR; | ||
523 | } | 555 | } |
524 | #endif | 556 | #endif |
525 | 557 | ||
526 | if (! snd_card_proc_new(emu->card, "emu10k1", &entry)) | 558 | if (! snd_card_proc_new(emu->card, "emu10k1", &entry)) |
527 | snd_info_set_text_ops(entry, emu, 2048, snd_emu10k1_proc_read); | 559 | snd_info_set_text_ops(entry, emu, 2048, snd_emu10k1_proc_read); |
528 | 560 | ||
561 | if (emu->card_capabilities->emu10k2_chip) { | ||
562 | if (! snd_card_proc_new(emu->card, "spdif-in", &entry)) | ||
563 | snd_info_set_text_ops(entry, emu, 2048, snd_emu10k1_proc_spdif_read); | ||
564 | } | ||
565 | if (emu->card_capabilities->ca0151_chip) { | ||
566 | if (! snd_card_proc_new(emu->card, "capture-rates", &entry)) | ||
567 | snd_info_set_text_ops(entry, emu, 2048, snd_emu10k1_proc_rates_read); | ||
568 | } | ||
569 | |||
529 | if (! snd_card_proc_new(emu->card, "voices", &entry)) | 570 | if (! snd_card_proc_new(emu->card, "voices", &entry)) |
530 | snd_info_set_text_ops(entry, emu, 2048, snd_emu10k1_proc_voices_read); | 571 | snd_info_set_text_ops(entry, emu, 2048, snd_emu10k1_proc_voices_read); |
531 | 572 | ||
diff --git a/sound/pci/emu10k1/irq.c b/sound/pci/emu10k1/irq.c index b81a7cafff39..cd8460d56752 100644 --- a/sound/pci/emu10k1/irq.c +++ b/sound/pci/emu10k1/irq.c | |||
@@ -37,7 +37,7 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
37 | int handled = 0; | 37 | int handled = 0; |
38 | 38 | ||
39 | while ((status = inl(emu->port + IPR)) != 0) { | 39 | while ((status = inl(emu->port + IPR)) != 0) { |
40 | // printk("irq - status = 0x%x\n", status); | 40 | //printk("emu10k1 irq - status = 0x%x\n", status); |
41 | orig_status = status; | 41 | orig_status = status; |
42 | handled = 1; | 42 | handled = 1; |
43 | if (status & IPR_PCIERROR) { | 43 | if (status & IPR_PCIERROR) { |
@@ -147,9 +147,36 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
147 | snd_emu10k1_intr_disable(emu, INTE_FXDSPENABLE); | 147 | snd_emu10k1_intr_disable(emu, INTE_FXDSPENABLE); |
148 | status &= ~IPR_FXDSP; | 148 | status &= ~IPR_FXDSP; |
149 | } | 149 | } |
150 | if (status & IPR_P16V) { | ||
151 | while ((status2 = inl(emu->port + IPR2)) != 0) { | ||
152 | u32 mask = INTE2_PLAYBACK_CH_0_LOOP; /* Full Loop */ | ||
153 | emu10k1_voice_t *pvoice = &(emu->p16v_voices[0]); | ||
154 | emu10k1_voice_t *cvoice = &(emu->p16v_capture_voice); | ||
155 | |||
156 | //printk(KERN_INFO "status2=0x%x\n", status2); | ||
157 | orig_status2 = status2; | ||
158 | if(status2 & mask) { | ||
159 | if(pvoice->use) { | ||
160 | snd_pcm_period_elapsed(pvoice->epcm->substream); | ||
161 | } else { | ||
162 | snd_printk(KERN_ERR "p16v: status: 0x%08x, mask=0x%08x, pvoice=%p, use=%d\n", status2, mask, pvoice, pvoice->use); | ||
163 | } | ||
164 | } | ||
165 | if(status2 & 0x110000) { | ||
166 | //printk(KERN_INFO "capture int found\n"); | ||
167 | if(cvoice->use) { | ||
168 | //printk(KERN_INFO "capture period_elapsed\n"); | ||
169 | snd_pcm_period_elapsed(cvoice->epcm->substream); | ||
170 | } | ||
171 | } | ||
172 | outl(orig_status2, emu->port + IPR2); /* ack all */ | ||
173 | } | ||
174 | status &= ~IPR_P16V; | ||
175 | } | ||
176 | |||
150 | if (status) { | 177 | if (status) { |
151 | unsigned int bits; | 178 | unsigned int bits; |
152 | //snd_printk(KERN_ERR "emu10k1: unhandled interrupt: 0x%08x\n", status); | 179 | snd_printk(KERN_ERR "emu10k1: unhandled interrupt: 0x%08x\n", status); |
153 | //make sure any interrupts we don't handle are disabled: | 180 | //make sure any interrupts we don't handle are disabled: |
154 | bits = INTE_FXDSPENABLE | | 181 | bits = INTE_FXDSPENABLE | |
155 | INTE_PCIERRORENABLE | | 182 | INTE_PCIERRORENABLE | |
@@ -170,20 +197,5 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
170 | } | 197 | } |
171 | outl(orig_status, emu->port + IPR); /* ack all */ | 198 | outl(orig_status, emu->port + IPR); /* ack all */ |
172 | } | 199 | } |
173 | if (emu->audigy && emu->revision == 4) { /* P16V */ | ||
174 | while ((status2 = inl(emu->port + IPR2)) != 0) { | ||
175 | u32 mask = INTE2_PLAYBACK_CH_0_LOOP; /* Full Loop */ | ||
176 | emu10k1_voice_t *pvoice = &(emu->p16v_voices[0]); | ||
177 | orig_status2 = status2; | ||
178 | if(status2 & mask) { | ||
179 | if(pvoice->use) { | ||
180 | snd_pcm_period_elapsed(pvoice->epcm->substream); | ||
181 | } else { | ||
182 | snd_printk(KERN_ERR "p16v: status: 0x%08x, mask=0x%08x, pvoice=%p, use=%d\n", status2, mask, pvoice, pvoice->use); | ||
183 | } | ||
184 | } | ||
185 | outl(orig_status2, emu->port + IPR2); /* ack all */ | ||
186 | } | ||
187 | } | ||
188 | return IRQ_RETVAL(handled); | 200 | return IRQ_RETVAL(handled); |
189 | } | 201 | } |
diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index d03cb2fefc9e..98f980189892 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) by James Courtier-Dutton <James@superbug.demon.co.uk> | 2 | * Copyright (c) by James Courtier-Dutton <James@superbug.demon.co.uk> |
3 | * Driver p16v chips | 3 | * Driver p16v chips |
4 | * Version: 0.22 | 4 | * Version: 0.25 |
5 | * | 5 | * |
6 | * FEATURES currently supported: | 6 | * FEATURES currently supported: |
7 | * Output fixed at S32_LE, 2 channel to hw:0,0 | 7 | * Output fixed at S32_LE, 2 channel to hw:0,0 |
@@ -41,7 +41,15 @@ | |||
41 | * Integrated with snd-emu10k1 driver. | 41 | * Integrated with snd-emu10k1 driver. |
42 | * 0.22 | 42 | * 0.22 |
43 | * Removed #if 0 ... #endif | 43 | * Removed #if 0 ... #endif |
44 | * | 44 | * 0.23 |
45 | * Implement different capture rates. | ||
46 | * 0.24 | ||
47 | * Implement different capture source channels. | ||
48 | * e.g. When HD Capture source is set to SPDIF, | ||
49 | * setting HD Capture channel to 0 captures from CDROM digital input. | ||
50 | * setting HD Capture channel to 1 captures from SPDIF in. | ||
51 | * 0.25 | ||
52 | * Include capture buffer sizes. | ||
45 | * | 53 | * |
46 | * BUGS: | 54 | * BUGS: |
47 | * Some stability problems when unloading the snd-p16v kernel module. | 55 | * Some stability problems when unloading the snd-p16v kernel module. |
@@ -119,22 +127,41 @@ static snd_pcm_hardware_t snd_p16v_playback_hw = { | |||
119 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | 127 | SNDRV_PCM_INFO_BLOCK_TRANSFER | |
120 | SNDRV_PCM_INFO_MMAP_VALID), | 128 | SNDRV_PCM_INFO_MMAP_VALID), |
121 | .formats = SNDRV_PCM_FMTBIT_S32_LE, /* Only supports 24-bit samples padded to 32 bits. */ | 129 | .formats = SNDRV_PCM_FMTBIT_S32_LE, /* Only supports 24-bit samples padded to 32 bits. */ |
122 | .rates = SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_48000 , | 130 | .rates = SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_44100, |
123 | .rate_min = 48000, | 131 | .rate_min = 44100, |
124 | .rate_max = 192000, | 132 | .rate_max = 192000, |
125 | .channels_min = 8, | 133 | .channels_min = 8, |
126 | .channels_max = 8, | 134 | .channels_max = 8, |
127 | .buffer_bytes_max = (32*1024), | 135 | .buffer_bytes_max = ((65536 - 64) * 8), |
128 | .period_bytes_min = 64, | 136 | .period_bytes_min = 64, |
129 | .period_bytes_max = (16*1024), | 137 | .period_bytes_max = (65536 - 64), |
130 | .periods_min = 2, | 138 | .periods_min = 2, |
131 | .periods_max = 8, | 139 | .periods_max = 8, |
132 | .fifo_size = 0, | 140 | .fifo_size = 0, |
133 | }; | 141 | }; |
134 | 142 | ||
143 | static snd_pcm_hardware_t snd_p16v_capture_hw = { | ||
144 | .info = (SNDRV_PCM_INFO_MMAP | | ||
145 | SNDRV_PCM_INFO_INTERLEAVED | | ||
146 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
147 | SNDRV_PCM_INFO_MMAP_VALID), | ||
148 | .formats = SNDRV_PCM_FMTBIT_S32_LE, | ||
149 | .rates = SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_44100, | ||
150 | .rate_min = 44100, | ||
151 | .rate_max = 192000, | ||
152 | .channels_min = 2, | ||
153 | .channels_max = 2, | ||
154 | .buffer_bytes_max = (65536 - 64), | ||
155 | .period_bytes_min = 64, | ||
156 | .period_bytes_max = (65536 - 128) >> 1, /* size has to be N*64 bytes */ | ||
157 | .periods_min = 2, | ||
158 | .periods_max = 2, | ||
159 | .fifo_size = 0, | ||
160 | }; | ||
161 | |||
135 | static void snd_p16v_pcm_free_substream(snd_pcm_runtime_t *runtime) | 162 | static void snd_p16v_pcm_free_substream(snd_pcm_runtime_t *runtime) |
136 | { | 163 | { |
137 | snd_pcm_t *epcm = runtime->private_data; | 164 | emu10k1_pcm_t *epcm = runtime->private_data; |
138 | 165 | ||
139 | if (epcm) { | 166 | if (epcm) { |
140 | //snd_printk("epcm free: %p\n", epcm); | 167 | //snd_printk("epcm free: %p\n", epcm); |
@@ -178,15 +205,63 @@ static int snd_p16v_pcm_open_playback_channel(snd_pcm_substream_t *substream, in | |||
178 | 205 | ||
179 | return 0; | 206 | return 0; |
180 | } | 207 | } |
208 | /* open_capture callback */ | ||
209 | static int snd_p16v_pcm_open_capture_channel(snd_pcm_substream_t *substream, int channel_id) | ||
210 | { | ||
211 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | ||
212 | emu10k1_voice_t *channel = &(emu->p16v_capture_voice); | ||
213 | emu10k1_pcm_t *epcm; | ||
214 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
215 | int err; | ||
216 | |||
217 | epcm = kcalloc(1, sizeof(*epcm), GFP_KERNEL); | ||
218 | //snd_printk("epcm kcalloc: %p\n", epcm); | ||
219 | |||
220 | if (epcm == NULL) | ||
221 | return -ENOMEM; | ||
222 | epcm->emu = emu; | ||
223 | epcm->substream = substream; | ||
224 | //snd_printk("epcm device=%d, channel_id=%d\n", substream->pcm->device, channel_id); | ||
225 | |||
226 | runtime->private_data = epcm; | ||
227 | runtime->private_free = snd_p16v_pcm_free_substream; | ||
228 | |||
229 | runtime->hw = snd_p16v_capture_hw; | ||
230 | |||
231 | channel->emu = emu; | ||
232 | channel->number = channel_id; | ||
233 | |||
234 | channel->use=1; | ||
235 | //snd_printk("p16v: open channel_id=%d, channel=%p, use=0x%x\n", channel_id, channel, channel->use); | ||
236 | //printk("open:channel_id=%d, chip=%p, channel=%p\n",channel_id, chip, channel); | ||
237 | //channel->interrupt = snd_p16v_pcm_channel_interrupt; | ||
238 | channel->epcm=epcm; | ||
239 | if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) | ||
240 | return err; | ||
241 | |||
242 | return 0; | ||
243 | } | ||
244 | |||
181 | 245 | ||
182 | /* close callback */ | 246 | /* close callback */ |
183 | static int snd_p16v_pcm_close_playback(snd_pcm_substream_t *substream) | 247 | static int snd_p16v_pcm_close_playback(snd_pcm_substream_t *substream) |
184 | { | 248 | { |
185 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | 249 | emu10k1_t *emu = snd_pcm_substream_chip(substream); |
186 | //snd_pcm_runtime_t *runtime = substream->runtime; | 250 | //snd_pcm_runtime_t *runtime = substream->runtime; |
187 | //emu10k1_pcm_t *epcm = runtime->private_data; | 251 | //emu10k1_pcm_t *epcm = runtime->private_data; |
188 | emu->p16v_voices[substream->pcm->device - emu->p16v_device_offset].use=0; | 252 | emu->p16v_voices[substream->pcm->device - emu->p16v_device_offset].use=0; |
189 | /* FIXME: maybe zero others */ | 253 | /* FIXME: maybe zero others */ |
254 | return 0; | ||
255 | } | ||
256 | |||
257 | /* close callback */ | ||
258 | static int snd_p16v_pcm_close_capture(snd_pcm_substream_t *substream) | ||
259 | { | ||
260 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | ||
261 | //snd_pcm_runtime_t *runtime = substream->runtime; | ||
262 | //emu10k1_pcm_t *epcm = runtime->private_data; | ||
263 | emu->p16v_capture_voice.use=0; | ||
264 | /* FIXME: maybe zero others */ | ||
190 | return 0; | 265 | return 0; |
191 | } | 266 | } |
192 | 267 | ||
@@ -195,36 +270,55 @@ static int snd_p16v_pcm_open_playback_front(snd_pcm_substream_t *substream) | |||
195 | return snd_p16v_pcm_open_playback_channel(substream, PCM_FRONT_CHANNEL); | 270 | return snd_p16v_pcm_open_playback_channel(substream, PCM_FRONT_CHANNEL); |
196 | } | 271 | } |
197 | 272 | ||
273 | static int snd_p16v_pcm_open_capture(snd_pcm_substream_t *substream) | ||
274 | { | ||
275 | // Only using channel 0 for now, but the card has 2 channels. | ||
276 | return snd_p16v_pcm_open_capture_channel(substream, 0); | ||
277 | } | ||
278 | |||
198 | /* hw_params callback */ | 279 | /* hw_params callback */ |
199 | static int snd_p16v_pcm_hw_params_playback(snd_pcm_substream_t *substream, | 280 | static int snd_p16v_pcm_hw_params_playback(snd_pcm_substream_t *substream, |
200 | snd_pcm_hw_params_t * hw_params) | 281 | snd_pcm_hw_params_t * hw_params) |
201 | { | 282 | { |
202 | int result; | 283 | int result; |
203 | //snd_printk("hw_params alloc: substream=%p\n", substream); | ||
204 | result = snd_pcm_lib_malloc_pages(substream, | 284 | result = snd_pcm_lib_malloc_pages(substream, |
205 | params_buffer_bytes(hw_params)); | 285 | params_buffer_bytes(hw_params)); |
206 | //snd_printk("hw_params alloc: result=%d\n", result); | ||
207 | //dump_stack(); | ||
208 | return result; | 286 | return result; |
209 | } | 287 | } |
210 | 288 | ||
289 | /* hw_params callback */ | ||
290 | static int snd_p16v_pcm_hw_params_capture(snd_pcm_substream_t *substream, | ||
291 | snd_pcm_hw_params_t * hw_params) | ||
292 | { | ||
293 | int result; | ||
294 | result = snd_pcm_lib_malloc_pages(substream, | ||
295 | params_buffer_bytes(hw_params)); | ||
296 | return result; | ||
297 | } | ||
298 | |||
299 | |||
211 | /* hw_free callback */ | 300 | /* hw_free callback */ |
212 | static int snd_p16v_pcm_hw_free_playback(snd_pcm_substream_t *substream) | 301 | static int snd_p16v_pcm_hw_free_playback(snd_pcm_substream_t *substream) |
213 | { | 302 | { |
214 | int result; | 303 | int result; |
215 | //snd_printk("hw_params free: substream=%p\n", substream); | ||
216 | result = snd_pcm_lib_free_pages(substream); | 304 | result = snd_pcm_lib_free_pages(substream); |
217 | //snd_printk("hw_params free: result=%d\n", result); | ||
218 | //dump_stack(); | ||
219 | return result; | 305 | return result; |
220 | } | 306 | } |
221 | 307 | ||
308 | /* hw_free callback */ | ||
309 | static int snd_p16v_pcm_hw_free_capture(snd_pcm_substream_t *substream) | ||
310 | { | ||
311 | int result; | ||
312 | result = snd_pcm_lib_free_pages(substream); | ||
313 | return result; | ||
314 | } | ||
315 | |||
316 | |||
222 | /* prepare playback callback */ | 317 | /* prepare playback callback */ |
223 | static int snd_p16v_pcm_prepare_playback(snd_pcm_substream_t *substream) | 318 | static int snd_p16v_pcm_prepare_playback(snd_pcm_substream_t *substream) |
224 | { | 319 | { |
225 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | 320 | emu10k1_t *emu = snd_pcm_substream_chip(substream); |
226 | snd_pcm_runtime_t *runtime = substream->runtime; | 321 | snd_pcm_runtime_t *runtime = substream->runtime; |
227 | //emu10k1_pcm_t *epcm = runtime->private_data; | ||
228 | int channel = substream->pcm->device - emu->p16v_device_offset; | 322 | int channel = substream->pcm->device - emu->p16v_device_offset; |
229 | u32 *table_base = (u32 *)(emu->p16v_buffer.area+(8*16*channel)); | 323 | u32 *table_base = (u32 *)(emu->p16v_buffer.area+(8*16*channel)); |
230 | u32 period_size_bytes = frames_to_bytes(runtime, runtime->period_size); | 324 | u32 period_size_bytes = frames_to_bytes(runtime, runtime->period_size); |
@@ -237,23 +331,21 @@ static int snd_p16v_pcm_prepare_playback(snd_pcm_substream_t *substream) | |||
237 | tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, channel); | 331 | tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, channel); |
238 | switch (runtime->rate) { | 332 | switch (runtime->rate) { |
239 | case 44100: | 333 | case 44100: |
240 | snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe000) | 0x8000); /* FIXME: This will change the capture rate as well! */ | 334 | snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe0e0) | 0x8080); |
241 | break; | ||
242 | case 48000: | ||
243 | snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe000) | 0x0000); /* FIXME: This will change the capture rate as well! */ | ||
244 | break; | 335 | break; |
245 | case 96000: | 336 | case 96000: |
246 | snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe000) | 0x4000); /* FIXME: This will change the capture rate as well! */ | 337 | snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe0e0) | 0x4040); |
247 | break; | 338 | break; |
248 | case 192000: | 339 | case 192000: |
249 | snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe000) | 0x2000); /* FIXME: This will change the capture rate as well! */ | 340 | snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe0e0) | 0x2020); |
250 | break; | 341 | break; |
342 | case 48000: | ||
251 | default: | 343 | default: |
252 | snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, 0x0000); /* FIXME: This will change the capture rate as well! */ | 344 | snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe0e0) | 0x0000); |
253 | break; | 345 | break; |
254 | } | 346 | } |
255 | /* FIXME: Check emu->buffer.size before actually writing to it. */ | 347 | /* FIXME: Check emu->buffer.size before actually writing to it. */ |
256 | for(i=0; i < runtime->periods; i++) { | 348 | for(i=0; i < runtime->periods; i++) { |
257 | table_base[i*2]=runtime->dma_addr+(i*period_size_bytes); | 349 | table_base[i*2]=runtime->dma_addr+(i*period_size_bytes); |
258 | table_base[(i*2)+1]=period_size_bytes<<16; | 350 | table_base[(i*2)+1]=period_size_bytes<<16; |
259 | } | 351 | } |
@@ -262,7 +354,8 @@ static int snd_p16v_pcm_prepare_playback(snd_pcm_substream_t *substream) | |||
262 | snd_emu10k1_ptr20_write(emu, PLAYBACK_LIST_SIZE, channel, (runtime->periods - 1) << 19); | 354 | snd_emu10k1_ptr20_write(emu, PLAYBACK_LIST_SIZE, channel, (runtime->periods - 1) << 19); |
263 | snd_emu10k1_ptr20_write(emu, PLAYBACK_LIST_PTR, channel, 0); | 355 | snd_emu10k1_ptr20_write(emu, PLAYBACK_LIST_PTR, channel, 0); |
264 | snd_emu10k1_ptr20_write(emu, PLAYBACK_DMA_ADDR, channel, runtime->dma_addr); | 356 | snd_emu10k1_ptr20_write(emu, PLAYBACK_DMA_ADDR, channel, runtime->dma_addr); |
265 | snd_emu10k1_ptr20_write(emu, PLAYBACK_PERIOD_SIZE, channel, frames_to_bytes(runtime, runtime->period_size)<<16); // buffer size in bytes | 357 | //snd_emu10k1_ptr20_write(emu, PLAYBACK_PERIOD_SIZE, channel, frames_to_bytes(runtime, runtime->period_size)<<16); // buffer size in bytes |
358 | snd_emu10k1_ptr20_write(emu, PLAYBACK_PERIOD_SIZE, channel, 0); // buffer size in bytes | ||
266 | snd_emu10k1_ptr20_write(emu, PLAYBACK_POINTER, channel, 0); | 359 | snd_emu10k1_ptr20_write(emu, PLAYBACK_POINTER, channel, 0); |
267 | snd_emu10k1_ptr20_write(emu, 0x07, channel, 0x0); | 360 | snd_emu10k1_ptr20_write(emu, 0x07, channel, 0x0); |
268 | snd_emu10k1_ptr20_write(emu, 0x08, channel, 0); | 361 | snd_emu10k1_ptr20_write(emu, 0x08, channel, 0); |
@@ -270,6 +363,41 @@ static int snd_p16v_pcm_prepare_playback(snd_pcm_substream_t *substream) | |||
270 | return 0; | 363 | return 0; |
271 | } | 364 | } |
272 | 365 | ||
366 | /* prepare capture callback */ | ||
367 | static int snd_p16v_pcm_prepare_capture(snd_pcm_substream_t *substream) | ||
368 | { | ||
369 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | ||
370 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
371 | int channel = substream->pcm->device - emu->p16v_device_offset; | ||
372 | u32 tmp; | ||
373 | //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)); | ||
374 | tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, channel); | ||
375 | switch (runtime->rate) { | ||
376 | case 44100: | ||
377 | snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0x0e00) | 0x0800); | ||
378 | break; | ||
379 | case 96000: | ||
380 | snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0x0e00) | 0x0400); | ||
381 | break; | ||
382 | case 192000: | ||
383 | snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0x0e00) | 0x0200); | ||
384 | break; | ||
385 | case 48000: | ||
386 | default: | ||
387 | snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0x0e00) | 0x0000); | ||
388 | break; | ||
389 | } | ||
390 | /* FIXME: Check emu->buffer.size before actually writing to it. */ | ||
391 | snd_emu10k1_ptr20_write(emu, 0x13, channel, 0); | ||
392 | snd_emu10k1_ptr20_write(emu, CAPTURE_DMA_ADDR, channel, runtime->dma_addr); | ||
393 | snd_emu10k1_ptr20_write(emu, CAPTURE_BUFFER_SIZE, channel, frames_to_bytes(runtime, runtime->buffer_size)<<16); // buffer size in bytes | ||
394 | snd_emu10k1_ptr20_write(emu, CAPTURE_POINTER, channel, 0); | ||
395 | //snd_emu10k1_ptr20_write(emu, CAPTURE_SOURCE, 0x0, 0x333300e4); /* Select MIC or Line in */ | ||
396 | //snd_emu10k1_ptr20_write(emu, EXTENDED_INT_MASK, 0, snd_emu10k1_ptr20_read(emu, EXTENDED_INT_MASK, 0) | (0x110000<<channel)); | ||
397 | |||
398 | return 0; | ||
399 | } | ||
400 | |||
273 | static void snd_p16v_intr_enable(emu10k1_t *emu, unsigned int intrenb) | 401 | static void snd_p16v_intr_enable(emu10k1_t *emu, unsigned int intrenb) |
274 | { | 402 | { |
275 | unsigned long flags; | 403 | unsigned long flags; |
@@ -345,6 +473,36 @@ static int snd_p16v_pcm_trigger_playback(snd_pcm_substream_t *substream, | |||
345 | return result; | 473 | return result; |
346 | } | 474 | } |
347 | 475 | ||
476 | /* trigger_capture callback */ | ||
477 | static int snd_p16v_pcm_trigger_capture(snd_pcm_substream_t *substream, | ||
478 | int cmd) | ||
479 | { | ||
480 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | ||
481 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
482 | emu10k1_pcm_t *epcm = runtime->private_data; | ||
483 | int channel = 0; | ||
484 | int result = 0; | ||
485 | u32 inte = INTE2_CAPTURE_CH_0_LOOP | INTE2_CAPTURE_CH_0_HALF_LOOP; | ||
486 | |||
487 | switch (cmd) { | ||
488 | case SNDRV_PCM_TRIGGER_START: | ||
489 | snd_p16v_intr_enable(emu, inte); | ||
490 | snd_emu10k1_ptr20_write(emu, BASIC_INTERRUPT, 0, snd_emu10k1_ptr20_read(emu, BASIC_INTERRUPT, 0)|(0x100<<channel)); | ||
491 | epcm->running = 1; | ||
492 | break; | ||
493 | case SNDRV_PCM_TRIGGER_STOP: | ||
494 | snd_emu10k1_ptr20_write(emu, BASIC_INTERRUPT, 0, snd_emu10k1_ptr20_read(emu, BASIC_INTERRUPT, 0) & ~(0x100<<channel)); | ||
495 | snd_p16v_intr_disable(emu, inte); | ||
496 | //snd_emu10k1_ptr20_write(emu, EXTENDED_INT_MASK, 0, snd_emu10k1_ptr20_read(emu, EXTENDED_INT_MASK, 0) & ~(0x110000<<channel)); | ||
497 | epcm->running = 0; | ||
498 | break; | ||
499 | default: | ||
500 | result = -EINVAL; | ||
501 | break; | ||
502 | } | ||
503 | return result; | ||
504 | } | ||
505 | |||
348 | /* pointer_playback callback */ | 506 | /* pointer_playback callback */ |
349 | static snd_pcm_uframes_t | 507 | static snd_pcm_uframes_t |
350 | snd_p16v_pcm_pointer_playback(snd_pcm_substream_t *substream) | 508 | snd_p16v_pcm_pointer_playback(snd_pcm_substream_t *substream) |
@@ -370,6 +528,31 @@ snd_p16v_pcm_pointer_playback(snd_pcm_substream_t *substream) | |||
370 | return ptr; | 528 | return ptr; |
371 | } | 529 | } |
372 | 530 | ||
531 | /* pointer_capture callback */ | ||
532 | static snd_pcm_uframes_t | ||
533 | snd_p16v_pcm_pointer_capture(snd_pcm_substream_t *substream) | ||
534 | { | ||
535 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | ||
536 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
537 | emu10k1_pcm_t *epcm = runtime->private_data; | ||
538 | snd_pcm_uframes_t ptr, ptr1, ptr2 = 0; | ||
539 | int channel = 0; | ||
540 | |||
541 | if (!epcm->running) | ||
542 | return 0; | ||
543 | |||
544 | ptr1 = snd_emu10k1_ptr20_read(emu, CAPTURE_POINTER, channel); | ||
545 | ptr2 = bytes_to_frames(runtime, ptr1); | ||
546 | ptr=ptr2; | ||
547 | if (ptr >= runtime->buffer_size) { | ||
548 | ptr -= runtime->buffer_size; | ||
549 | printk("buffer capture limited!\n"); | ||
550 | } | ||
551 | //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); | ||
552 | |||
553 | return ptr; | ||
554 | } | ||
555 | |||
373 | /* operators */ | 556 | /* operators */ |
374 | static snd_pcm_ops_t snd_p16v_playback_front_ops = { | 557 | static snd_pcm_ops_t snd_p16v_playback_front_ops = { |
375 | .open = snd_p16v_pcm_open_playback_front, | 558 | .open = snd_p16v_pcm_open_playback_front, |
@@ -382,6 +565,18 @@ static snd_pcm_ops_t snd_p16v_playback_front_ops = { | |||
382 | .pointer = snd_p16v_pcm_pointer_playback, | 565 | .pointer = snd_p16v_pcm_pointer_playback, |
383 | }; | 566 | }; |
384 | 567 | ||
568 | static snd_pcm_ops_t snd_p16v_capture_ops = { | ||
569 | .open = snd_p16v_pcm_open_capture, | ||
570 | .close = snd_p16v_pcm_close_capture, | ||
571 | .ioctl = snd_pcm_lib_ioctl, | ||
572 | .hw_params = snd_p16v_pcm_hw_params_capture, | ||
573 | .hw_free = snd_p16v_pcm_hw_free_capture, | ||
574 | .prepare = snd_p16v_pcm_prepare_capture, | ||
575 | .trigger = snd_p16v_pcm_trigger_capture, | ||
576 | .pointer = snd_p16v_pcm_pointer_capture, | ||
577 | }; | ||
578 | |||
579 | |||
385 | int snd_p16v_free(emu10k1_t *chip) | 580 | int snd_p16v_free(emu10k1_t *chip) |
386 | { | 581 | { |
387 | // release the data | 582 | // release the data |
@@ -405,20 +600,22 @@ int snd_p16v_pcm(emu10k1_t *emu, int device, snd_pcm_t **rpcm) | |||
405 | snd_pcm_t *pcm; | 600 | snd_pcm_t *pcm; |
406 | snd_pcm_substream_t *substream; | 601 | snd_pcm_substream_t *substream; |
407 | int err; | 602 | int err; |
408 | int capture=0; | 603 | int capture=1; |
409 | 604 | ||
410 | //snd_printk("snd_p16v_pcm called. device=%d\n", device); | 605 | //snd_printk("snd_p16v_pcm called. device=%d\n", device); |
411 | emu->p16v_device_offset = device; | 606 | emu->p16v_device_offset = device; |
412 | if (rpcm) | 607 | if (rpcm) |
413 | *rpcm = NULL; | 608 | *rpcm = NULL; |
414 | //if (device == 0) capture=1; | 609 | |
415 | if ((err = snd_pcm_new(emu->card, "p16v", device, 1, capture, &pcm)) < 0) | 610 | if ((err = snd_pcm_new(emu->card, "p16v", device, 1, capture, &pcm)) < 0) |
416 | return err; | 611 | return err; |
417 | 612 | ||
418 | pcm->private_data = emu; | 613 | pcm->private_data = emu; |
419 | pcm->private_free = snd_p16v_pcm_free; | 614 | pcm->private_free = snd_p16v_pcm_free; |
420 | 615 | // Single playback 8 channel device. | |
616 | // Single capture 2 channel device. | ||
421 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_p16v_playback_front_ops); | 617 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_p16v_playback_front_ops); |
618 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_p16v_capture_ops); | ||
422 | 619 | ||
423 | pcm->info_flags = 0; | 620 | pcm->info_flags = 0; |
424 | pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; | 621 | pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; |
@@ -431,7 +628,7 @@ int snd_p16v_pcm(emu10k1_t *emu, int device, snd_pcm_t **rpcm) | |||
431 | if ((err = snd_pcm_lib_preallocate_pages(substream, | 628 | if ((err = snd_pcm_lib_preallocate_pages(substream, |
432 | SNDRV_DMA_TYPE_DEV, | 629 | SNDRV_DMA_TYPE_DEV, |
433 | snd_dma_pci_data(emu->pci), | 630 | snd_dma_pci_data(emu->pci), |
434 | 64*1024, 64*1024)) < 0) /* FIXME: 32*1024 for sound buffer, between 32and64 for Periods table. */ | 631 | ((65536 - 64) * 8), ((65536 - 64) * 8))) < 0) |
435 | return err; | 632 | return err; |
436 | //snd_printk("preallocate playback substream: err=%d\n", err); | 633 | //snd_printk("preallocate playback substream: err=%d\n", err); |
437 | } | 634 | } |
@@ -442,7 +639,7 @@ int snd_p16v_pcm(emu10k1_t *emu, int device, snd_pcm_t **rpcm) | |||
442 | if ((err = snd_pcm_lib_preallocate_pages(substream, | 639 | if ((err = snd_pcm_lib_preallocate_pages(substream, |
443 | SNDRV_DMA_TYPE_DEV, | 640 | SNDRV_DMA_TYPE_DEV, |
444 | snd_dma_pci_data(emu->pci), | 641 | snd_dma_pci_data(emu->pci), |
445 | 64*1024, 64*1024)) < 0) | 642 | 65536 - 64, 65536 - 64)) < 0) |
446 | return err; | 643 | return err; |
447 | //snd_printk("preallocate capture substream: err=%d\n", err); | 644 | //snd_printk("preallocate capture substream: err=%d\n", err); |
448 | } | 645 | } |
@@ -694,6 +891,106 @@ static snd_kcontrol_new_t snd_p16v_volume_control_spdif_rear = | |||
694 | .put = snd_p16v_volume_put_spdif_rear | 891 | .put = snd_p16v_volume_put_spdif_rear |
695 | }; | 892 | }; |
696 | 893 | ||
894 | static int snd_p16v_capture_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) | ||
895 | { | ||
896 | static char *texts[8] = { "SPDIF", "I2S", "SRC48", "SRCMulti_SPDIF", "SRCMulti_I2S", "CDIF", "FX", "AC97" }; | ||
897 | |||
898 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
899 | uinfo->count = 1; | ||
900 | uinfo->value.enumerated.items = 8; | ||
901 | if (uinfo->value.enumerated.item > 7) | ||
902 | uinfo->value.enumerated.item = 7; | ||
903 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
904 | return 0; | ||
905 | } | ||
906 | |||
907 | static int snd_p16v_capture_source_get(snd_kcontrol_t * kcontrol, | ||
908 | snd_ctl_elem_value_t * ucontrol) | ||
909 | { | ||
910 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol); | ||
911 | |||
912 | ucontrol->value.enumerated.item[0] = emu->p16v_capture_source; | ||
913 | return 0; | ||
914 | } | ||
915 | |||
916 | static int snd_p16v_capture_source_put(snd_kcontrol_t * kcontrol, | ||
917 | snd_ctl_elem_value_t * ucontrol) | ||
918 | { | ||
919 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol); | ||
920 | unsigned int val; | ||
921 | int change = 0; | ||
922 | u32 mask; | ||
923 | u32 source; | ||
924 | |||
925 | val = ucontrol->value.enumerated.item[0] ; | ||
926 | change = (emu->p16v_capture_source != val); | ||
927 | if (change) { | ||
928 | emu->p16v_capture_source = val; | ||
929 | source = (val << 28) | (val << 24) | (val << 20) | (val << 16); | ||
930 | mask = snd_emu10k1_ptr20_read(emu, BASIC_INTERRUPT, 0) & 0xffff; | ||
931 | snd_emu10k1_ptr20_write(emu, BASIC_INTERRUPT, 0, source | mask); | ||
932 | } | ||
933 | return change; | ||
934 | } | ||
935 | |||
936 | static snd_kcontrol_new_t snd_p16v_capture_source __devinitdata = | ||
937 | { | ||
938 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
939 | .name = "HD Capture source", | ||
940 | .info = snd_p16v_capture_source_info, | ||
941 | .get = snd_p16v_capture_source_get, | ||
942 | .put = snd_p16v_capture_source_put | ||
943 | }; | ||
944 | |||
945 | static int snd_p16v_capture_channel_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) | ||
946 | { | ||
947 | static char *texts[4] = { "0", "1", "2", "3", }; | ||
948 | |||
949 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
950 | uinfo->count = 1; | ||
951 | uinfo->value.enumerated.items = 4; | ||
952 | if (uinfo->value.enumerated.item > 3) | ||
953 | uinfo->value.enumerated.item = 3; | ||
954 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
955 | return 0; | ||
956 | } | ||
957 | |||
958 | static int snd_p16v_capture_channel_get(snd_kcontrol_t * kcontrol, | ||
959 | snd_ctl_elem_value_t * ucontrol) | ||
960 | { | ||
961 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol); | ||
962 | |||
963 | ucontrol->value.enumerated.item[0] = emu->p16v_capture_channel; | ||
964 | return 0; | ||
965 | } | ||
966 | |||
967 | static int snd_p16v_capture_channel_put(snd_kcontrol_t * kcontrol, | ||
968 | snd_ctl_elem_value_t * ucontrol) | ||
969 | { | ||
970 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol); | ||
971 | unsigned int val; | ||
972 | int change = 0; | ||
973 | u32 tmp; | ||
974 | |||
975 | val = ucontrol->value.enumerated.item[0] ; | ||
976 | change = (emu->p16v_capture_channel != val); | ||
977 | if (change) { | ||
978 | emu->p16v_capture_channel = val; | ||
979 | tmp = snd_emu10k1_ptr20_read(emu, CAPTURE_P16V_SOURCE, 0) & 0xfffc; | ||
980 | snd_emu10k1_ptr20_write(emu, CAPTURE_P16V_SOURCE, 0, tmp | val); | ||
981 | } | ||
982 | return change; | ||
983 | } | ||
984 | |||
985 | static snd_kcontrol_new_t snd_p16v_capture_channel __devinitdata = | ||
986 | { | ||
987 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
988 | .name = "HD Capture channel", | ||
989 | .info = snd_p16v_capture_channel_info, | ||
990 | .get = snd_p16v_capture_channel_get, | ||
991 | .put = snd_p16v_capture_channel_put | ||
992 | }; | ||
993 | |||
697 | int snd_p16v_mixer(emu10k1_t *emu) | 994 | int snd_p16v_mixer(emu10k1_t *emu) |
698 | { | 995 | { |
699 | int err; | 996 | int err; |
@@ -731,6 +1028,14 @@ int snd_p16v_mixer(emu10k1_t *emu) | |||
731 | return -ENOMEM; | 1028 | return -ENOMEM; |
732 | if ((err = snd_ctl_add(card, kctl))) | 1029 | if ((err = snd_ctl_add(card, kctl))) |
733 | return err; | 1030 | return err; |
1031 | if ((kctl = snd_ctl_new1(&snd_p16v_capture_source, emu)) == NULL) | ||
1032 | return -ENOMEM; | ||
1033 | if ((err = snd_ctl_add(card, kctl))) | ||
1034 | return err; | ||
1035 | if ((kctl = snd_ctl_new1(&snd_p16v_capture_channel, emu)) == NULL) | ||
1036 | return -ENOMEM; | ||
1037 | if ((err = snd_ctl_add(card, kctl))) | ||
1038 | return err; | ||
734 | return 0; | 1039 | return 0; |
735 | } | 1040 | } |
736 | 1041 | ||
diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index f910399db5c3..4e63498a58b2 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c | |||
@@ -2401,7 +2401,7 @@ static struct pci_driver driver = { | |||
2401 | 2401 | ||
2402 | static int __init alsa_card_ens137x_init(void) | 2402 | static int __init alsa_card_ens137x_init(void) |
2403 | { | 2403 | { |
2404 | return pci_module_init(&driver); | 2404 | return pci_register_driver(&driver); |
2405 | } | 2405 | } |
2406 | 2406 | ||
2407 | static void __exit alsa_card_ens137x_exit(void) | 2407 | static void __exit alsa_card_ens137x_exit(void) |
diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c index b4ca8adf393c..b492777bc30f 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c | |||
@@ -1761,7 +1761,7 @@ static struct pci_driver driver = { | |||
1761 | 1761 | ||
1762 | static int __init alsa_card_es1938_init(void) | 1762 | static int __init alsa_card_es1938_init(void) |
1763 | { | 1763 | { |
1764 | return pci_module_init(&driver); | 1764 | return pci_register_driver(&driver); |
1765 | } | 1765 | } |
1766 | 1766 | ||
1767 | static void __exit alsa_card_es1938_exit(void) | 1767 | static void __exit alsa_card_es1938_exit(void) |
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index faf63ff19c42..ea889b311390 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c | |||
@@ -2559,6 +2559,7 @@ static struct ess_device_list pm_whitelist[] __devinitdata = { | |||
2559 | { TYPE_MAESTRO2E, 0x103c }, | 2559 | { TYPE_MAESTRO2E, 0x103c }, |
2560 | { TYPE_MAESTRO2E, 0x1179 }, | 2560 | { TYPE_MAESTRO2E, 0x1179 }, |
2561 | { TYPE_MAESTRO2E, 0x14c0 }, /* HP omnibook 4150 */ | 2561 | { TYPE_MAESTRO2E, 0x14c0 }, /* HP omnibook 4150 */ |
2562 | { TYPE_MAESTRO2E, 0x1558 }, | ||
2562 | }; | 2563 | }; |
2563 | 2564 | ||
2564 | static struct ess_device_list mpu_blacklist[] __devinitdata = { | 2565 | static struct ess_device_list mpu_blacklist[] __devinitdata = { |
@@ -2795,7 +2796,7 @@ static struct pci_driver driver = { | |||
2795 | 2796 | ||
2796 | static int __init alsa_card_es1968_init(void) | 2797 | static int __init alsa_card_es1968_init(void) |
2797 | { | 2798 | { |
2798 | return pci_module_init(&driver); | 2799 | return pci_register_driver(&driver); |
2799 | } | 2800 | } |
2800 | 2801 | ||
2801 | static void __exit alsa_card_es1968_exit(void) | 2802 | static void __exit alsa_card_es1968_exit(void) |
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index 08e7c5a296d5..ff10e637a95e 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c | |||
@@ -195,6 +195,7 @@ struct _snd_fm801 { | |||
195 | 195 | ||
196 | static struct pci_device_id snd_fm801_ids[] = { | 196 | static struct pci_device_id snd_fm801_ids[] = { |
197 | { 0x1319, 0x0801, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0, }, /* FM801 */ | 197 | { 0x1319, 0x0801, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0, }, /* FM801 */ |
198 | { 0x5213, 0x0510, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0, }, /* Gallant Odyssey Sound 4 */ | ||
198 | { 0, } | 199 | { 0, } |
199 | }; | 200 | }; |
200 | 201 | ||
@@ -1468,7 +1469,7 @@ static struct pci_driver driver = { | |||
1468 | 1469 | ||
1469 | static int __init alsa_card_fm801_init(void) | 1470 | static int __init alsa_card_fm801_init(void) |
1470 | { | 1471 | { |
1471 | return pci_module_init(&driver); | 1472 | return pci_register_driver(&driver); |
1472 | } | 1473 | } |
1473 | 1474 | ||
1474 | static void __exit alsa_card_fm801_exit(void) | 1475 | static void __exit alsa_card_fm801_exit(void) |
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index 570a59d33b41..bd8cb33c4fb4 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile | |||
@@ -1,5 +1,5 @@ | |||
1 | snd-hda-intel-objs := hda_intel.o | 1 | snd-hda-intel-objs := hda_intel.o |
2 | snd-hda-codec-objs := hda_codec.o hda_generic.o patch_realtek.o patch_cmedia.o patch_analog.o | 2 | snd-hda-codec-objs := hda_codec.o hda_generic.o patch_realtek.o patch_cmedia.o patch_analog.o patch_sigmatel.o |
3 | ifdef CONFIG_PROC_FS | 3 | ifdef CONFIG_PROC_FS |
4 | snd-hda-codec-objs += hda_proc.o | 4 | snd-hda-codec-objs += hda_proc.o |
5 | endif | 5 | endif |
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 9ed117ac0c09..e2cf02387289 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
@@ -49,8 +49,10 @@ struct hda_vendor_id { | |||
49 | /* codec vendor labels */ | 49 | /* codec vendor labels */ |
50 | static struct hda_vendor_id hda_vendor_ids[] = { | 50 | static struct hda_vendor_id hda_vendor_ids[] = { |
51 | { 0x10ec, "Realtek" }, | 51 | { 0x10ec, "Realtek" }, |
52 | { 0x11d4, "Analog Devices" }, | ||
52 | { 0x13f6, "C-Media" }, | 53 | { 0x13f6, "C-Media" }, |
53 | { 0x434d, "C-Media" }, | 54 | { 0x434d, "C-Media" }, |
55 | { 0x8384, "SigmaTel" }, | ||
54 | {} /* terminator */ | 56 | {} /* terminator */ |
55 | }; | 57 | }; |
56 | 58 | ||
@@ -508,7 +510,7 @@ int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, | |||
508 | /* FIXME: support for multiple AFGs? */ | 510 | /* FIXME: support for multiple AFGs? */ |
509 | codec->afg = look_for_afg_node(codec); | 511 | codec->afg = look_for_afg_node(codec); |
510 | if (! codec->afg) { | 512 | if (! codec->afg) { |
511 | snd_printk(KERN_ERR "hda_codec: no AFG node found\n"); | 513 | snd_printdd("hda_codec: no AFG node found\n"); |
512 | snd_hda_codec_free(codec); | 514 | snd_hda_codec_free(codec); |
513 | return -ENODEV; | 515 | return -ENODEV; |
514 | } | 516 | } |
@@ -548,6 +550,9 @@ int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, | |||
548 | void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, u32 stream_tag, | 550 | void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, u32 stream_tag, |
549 | int channel_id, int format) | 551 | int channel_id, int format) |
550 | { | 552 | { |
553 | if (! nid) | ||
554 | return; | ||
555 | |||
551 | snd_printdd("hda_codec_setup_stream: NID=0x%x, stream=0x%x, channel=%d, format=0x%x\n", | 556 | snd_printdd("hda_codec_setup_stream: NID=0x%x, stream=0x%x, channel=%d, format=0x%x\n", |
552 | nid, stream_tag, channel_id, format); | 557 | nid, stream_tag, channel_id, format); |
553 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID, | 558 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID, |
@@ -561,9 +566,10 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, u32 stre | |||
561 | * amp access functions | 566 | * amp access functions |
562 | */ | 567 | */ |
563 | 568 | ||
564 | #define HDA_HASH_KEY(nid,dir,idx) (u32)((nid) + (idx) * 32 + (dir) * 64) | 569 | /* FIXME: more better hash key? */ |
570 | #define HDA_HASH_KEY(nid,dir,idx) (u32)((nid) + ((idx) << 16) + ((dir) << 24)) | ||
565 | #define INFO_AMP_CAPS (1<<0) | 571 | #define INFO_AMP_CAPS (1<<0) |
566 | #define INFO_AMP_VOL (1<<1) | 572 | #define INFO_AMP_VOL(ch) (1 << (1 + (ch))) |
567 | 573 | ||
568 | /* initialize the hash table */ | 574 | /* initialize the hash table */ |
569 | static void init_amp_hash(struct hda_codec *codec) | 575 | static void init_amp_hash(struct hda_codec *codec) |
@@ -622,28 +628,29 @@ static u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction) | |||
622 | 628 | ||
623 | /* | 629 | /* |
624 | * read the current volume to info | 630 | * read the current volume to info |
625 | * if the cache exists, read from the cache. | 631 | * if the cache exists, read the cache value. |
626 | */ | 632 | */ |
627 | static void get_vol_mute(struct hda_codec *codec, struct hda_amp_info *info, | 633 | static unsigned int get_vol_mute(struct hda_codec *codec, struct hda_amp_info *info, |
628 | hda_nid_t nid, int ch, int direction, int index) | 634 | hda_nid_t nid, int ch, int direction, int index) |
629 | { | 635 | { |
630 | u32 val, parm; | 636 | u32 val, parm; |
631 | 637 | ||
632 | if (info->status & (INFO_AMP_VOL << ch)) | 638 | if (info->status & INFO_AMP_VOL(ch)) |
633 | return; | 639 | return info->vol[ch]; |
634 | 640 | ||
635 | parm = ch ? AC_AMP_GET_RIGHT : AC_AMP_GET_LEFT; | 641 | parm = ch ? AC_AMP_GET_RIGHT : AC_AMP_GET_LEFT; |
636 | parm |= direction == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT; | 642 | parm |= direction == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT; |
637 | parm |= index; | 643 | parm |= index; |
638 | val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, parm); | 644 | val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, parm); |
639 | info->vol[ch] = val & 0xff; | 645 | info->vol[ch] = val & 0xff; |
640 | info->status |= INFO_AMP_VOL << ch; | 646 | info->status |= INFO_AMP_VOL(ch); |
647 | return info->vol[ch]; | ||
641 | } | 648 | } |
642 | 649 | ||
643 | /* | 650 | /* |
644 | * write the current volume in info to the h/w | 651 | * write the current volume in info to the h/w and update the cache |
645 | */ | 652 | */ |
646 | static void put_vol_mute(struct hda_codec *codec, | 653 | static void put_vol_mute(struct hda_codec *codec, struct hda_amp_info *info, |
647 | hda_nid_t nid, int ch, int direction, int index, int val) | 654 | hda_nid_t nid, int ch, int direction, int index, int val) |
648 | { | 655 | { |
649 | u32 parm; | 656 | u32 parm; |
@@ -653,30 +660,34 @@ static void put_vol_mute(struct hda_codec *codec, | |||
653 | parm |= index << AC_AMP_SET_INDEX_SHIFT; | 660 | parm |= index << AC_AMP_SET_INDEX_SHIFT; |
654 | parm |= val; | 661 | parm |= val; |
655 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, parm); | 662 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, parm); |
663 | info->vol[ch] = val; | ||
656 | } | 664 | } |
657 | 665 | ||
658 | /* | 666 | /* |
659 | * read/write AMP value. The volume is between 0 to 0x7f, 0x80 = mute bit. | 667 | * read AMP value. The volume is between 0 to 0x7f, 0x80 = mute bit. |
660 | */ | 668 | */ |
661 | int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int index) | 669 | static int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int index) |
662 | { | 670 | { |
663 | struct hda_amp_info *info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, index)); | 671 | struct hda_amp_info *info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, index)); |
664 | if (! info) | 672 | if (! info) |
665 | return 0; | 673 | return 0; |
666 | get_vol_mute(codec, info, nid, ch, direction, index); | 674 | return get_vol_mute(codec, info, nid, ch, direction, index); |
667 | return info->vol[ch]; | ||
668 | } | 675 | } |
669 | 676 | ||
670 | int snd_hda_codec_amp_write(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int idx, int val) | 677 | /* |
678 | * update the AMP value, mask = bit mask to set, val = the value | ||
679 | */ | ||
680 | 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) | ||
671 | { | 681 | { |
672 | struct hda_amp_info *info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, idx)); | 682 | struct hda_amp_info *info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, idx)); |
683 | |||
673 | if (! info) | 684 | if (! info) |
674 | return 0; | 685 | return 0; |
675 | get_vol_mute(codec, info, nid, ch, direction, idx); | 686 | val &= mask; |
687 | val |= get_vol_mute(codec, info, nid, ch, direction, idx) & ~mask; | ||
676 | if (info->vol[ch] == val && ! codec->in_resume) | 688 | if (info->vol[ch] == val && ! codec->in_resume) |
677 | return 0; | 689 | return 0; |
678 | put_vol_mute(codec, nid, ch, direction, idx, val); | 690 | put_vol_mute(codec, info, nid, ch, direction, idx, val); |
679 | info->vol[ch] = val; | ||
680 | return 1; | 691 | return 1; |
681 | } | 692 | } |
682 | 693 | ||
@@ -735,21 +746,15 @@ int snd_hda_mixer_amp_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t | |||
735 | int chs = get_amp_channels(kcontrol); | 746 | int chs = get_amp_channels(kcontrol); |
736 | int dir = get_amp_direction(kcontrol); | 747 | int dir = get_amp_direction(kcontrol); |
737 | int idx = get_amp_index(kcontrol); | 748 | int idx = get_amp_index(kcontrol); |
738 | int val; | ||
739 | long *valp = ucontrol->value.integer.value; | 749 | long *valp = ucontrol->value.integer.value; |
740 | int change = 0; | 750 | int change = 0; |
741 | 751 | ||
742 | if (chs & 1) { | 752 | if (chs & 1) |
743 | val = *valp & 0x7f; | 753 | change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx, |
744 | val |= snd_hda_codec_amp_read(codec, nid, 0, dir, idx) & 0x80; | 754 | 0x7f, *valp); |
745 | change = snd_hda_codec_amp_write(codec, nid, 0, dir, idx, val); | 755 | if (chs & 2) |
746 | valp++; | 756 | change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx, |
747 | } | 757 | 0x7f, valp[1]); |
748 | if (chs & 2) { | ||
749 | val = *valp & 0x7f; | ||
750 | val |= snd_hda_codec_amp_read(codec, nid, 1, dir, idx) & 0x80; | ||
751 | change |= snd_hda_codec_amp_write(codec, nid, 1, dir, idx, val); | ||
752 | } | ||
753 | return change; | 758 | return change; |
754 | } | 759 | } |
755 | 760 | ||
@@ -788,21 +793,15 @@ int snd_hda_mixer_amp_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t | |||
788 | int chs = get_amp_channels(kcontrol); | 793 | int chs = get_amp_channels(kcontrol); |
789 | int dir = get_amp_direction(kcontrol); | 794 | int dir = get_amp_direction(kcontrol); |
790 | int idx = get_amp_index(kcontrol); | 795 | int idx = get_amp_index(kcontrol); |
791 | int val; | ||
792 | long *valp = ucontrol->value.integer.value; | 796 | long *valp = ucontrol->value.integer.value; |
793 | int change = 0; | 797 | int change = 0; |
794 | 798 | ||
795 | if (chs & 1) { | 799 | if (chs & 1) |
796 | val = snd_hda_codec_amp_read(codec, nid, 0, dir, idx) & 0x7f; | 800 | change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx, |
797 | val |= *valp ? 0 : 0x80; | 801 | 0x80, *valp ? 0 : 0x80); |
798 | change = snd_hda_codec_amp_write(codec, nid, 0, dir, idx, val); | 802 | if (chs & 2) |
799 | valp++; | 803 | change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx, |
800 | } | 804 | 0x80, valp[1] ? 0 : 0x80); |
801 | if (chs & 2) { | ||
802 | val = snd_hda_codec_amp_read(codec, nid, 1, dir, idx) & 0x7f; | ||
803 | val |= *valp ? 0 : 0x80; | ||
804 | change = snd_hda_codec_amp_write(codec, nid, 1, dir, idx, val); | ||
805 | } | ||
806 | return change; | 805 | return change; |
807 | } | 806 | } |
808 | 807 | ||
@@ -1448,10 +1447,6 @@ static int set_pcm_default_values(struct hda_codec *codec, struct hda_pcm_stream | |||
1448 | snd_assert(info->nid, return -EINVAL); | 1447 | snd_assert(info->nid, return -EINVAL); |
1449 | info->ops.prepare = hda_pcm_default_prepare; | 1448 | info->ops.prepare = hda_pcm_default_prepare; |
1450 | } | 1449 | } |
1451 | if (info->ops.prepare == NULL) { | ||
1452 | snd_assert(info->nid, return -EINVAL); | ||
1453 | info->ops.prepare = hda_pcm_default_prepare; | ||
1454 | } | ||
1455 | if (info->ops.cleanup == NULL) { | 1450 | if (info->ops.cleanup == NULL) { |
1456 | snd_assert(info->nid, return -EINVAL); | 1451 | snd_assert(info->nid, return -EINVAL); |
1457 | info->ops.cleanup = hda_pcm_default_cleanup; | 1452 | info->ops.cleanup = hda_pcm_default_cleanup; |
@@ -1525,12 +1520,12 @@ int snd_hda_build_pcms(struct hda_bus *bus) | |||
1525 | * | 1520 | * |
1526 | * If no entries are matching, the function returns a negative value. | 1521 | * If no entries are matching, the function returns a negative value. |
1527 | */ | 1522 | */ |
1528 | int snd_hda_check_board_config(struct hda_codec *codec, struct hda_board_config *tbl) | 1523 | int snd_hda_check_board_config(struct hda_codec *codec, const struct hda_board_config *tbl) |
1529 | { | 1524 | { |
1530 | struct hda_board_config *c; | 1525 | const struct hda_board_config *c; |
1531 | 1526 | ||
1532 | if (codec->bus->modelname) { | 1527 | if (codec->bus->modelname) { |
1533 | for (c = tbl; c->modelname || c->pci_vendor; c++) { | 1528 | for (c = tbl; c->modelname || c->pci_subvendor; c++) { |
1534 | if (c->modelname && | 1529 | if (c->modelname && |
1535 | ! strcmp(codec->bus->modelname, c->modelname)) { | 1530 | ! strcmp(codec->bus->modelname, c->modelname)) { |
1536 | snd_printd(KERN_INFO "hda_codec: model '%s' is selected\n", c->modelname); | 1531 | snd_printd(KERN_INFO "hda_codec: model '%s' is selected\n", c->modelname); |
@@ -1543,9 +1538,10 @@ int snd_hda_check_board_config(struct hda_codec *codec, struct hda_board_config | |||
1543 | u16 subsystem_vendor, subsystem_device; | 1538 | u16 subsystem_vendor, subsystem_device; |
1544 | pci_read_config_word(codec->bus->pci, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor); | 1539 | pci_read_config_word(codec->bus->pci, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor); |
1545 | pci_read_config_word(codec->bus->pci, PCI_SUBSYSTEM_ID, &subsystem_device); | 1540 | pci_read_config_word(codec->bus->pci, PCI_SUBSYSTEM_ID, &subsystem_device); |
1546 | for (c = tbl; c->modelname || c->pci_vendor; c++) { | 1541 | for (c = tbl; c->modelname || c->pci_subvendor; c++) { |
1547 | if (c->pci_vendor == subsystem_vendor && | 1542 | if (c->pci_subvendor == subsystem_vendor && |
1548 | c->pci_device == subsystem_device) | 1543 | (! c->pci_subdevice /* all match */|| |
1544 | (c->pci_subdevice == subsystem_device))) | ||
1549 | return c->config; | 1545 | return c->config; |
1550 | } | 1546 | } |
1551 | } | 1547 | } |
@@ -1687,11 +1683,12 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, struct hda_multi_o | |||
1687 | snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag, 0, format); | 1683 | snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag, 0, format); |
1688 | /* surrounds */ | 1684 | /* surrounds */ |
1689 | for (i = 1; i < mout->num_dacs; i++) { | 1685 | for (i = 1; i < mout->num_dacs; i++) { |
1690 | if (i == HDA_REAR && chs == 2) /* copy front to rear */ | 1686 | if (chs >= (i + 1) * 2) /* independent out */ |
1691 | snd_hda_codec_setup_stream(codec, nids[i], stream_tag, 0, format); | ||
1692 | else if (chs >= (i + 1) * 2) /* independent out */ | ||
1693 | snd_hda_codec_setup_stream(codec, nids[i], stream_tag, i * 2, | 1687 | snd_hda_codec_setup_stream(codec, nids[i], stream_tag, i * 2, |
1694 | format); | 1688 | format); |
1689 | else /* copy front */ | ||
1690 | snd_hda_codec_setup_stream(codec, nids[i], stream_tag, 0, | ||
1691 | format); | ||
1695 | } | 1692 | } |
1696 | return 0; | 1693 | return 0; |
1697 | } | 1694 | } |
@@ -1717,6 +1714,105 @@ int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, struct hda_multi_o | |||
1717 | return 0; | 1714 | return 0; |
1718 | } | 1715 | } |
1719 | 1716 | ||
1717 | /* | ||
1718 | * Helper for automatic ping configuration | ||
1719 | */ | ||
1720 | /* parse all pin widgets and store the useful pin nids to cfg */ | ||
1721 | int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *cfg) | ||
1722 | { | ||
1723 | hda_nid_t nid, nid_start; | ||
1724 | int i, j, nodes; | ||
1725 | short seq, sequences[4], assoc_line_out; | ||
1726 | |||
1727 | memset(cfg, 0, sizeof(*cfg)); | ||
1728 | |||
1729 | memset(sequences, 0, sizeof(sequences)); | ||
1730 | assoc_line_out = 0; | ||
1731 | |||
1732 | nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid_start); | ||
1733 | for (nid = nid_start; nid < nodes + nid_start; nid++) { | ||
1734 | unsigned int wid_caps = snd_hda_param_read(codec, nid, | ||
1735 | AC_PAR_AUDIO_WIDGET_CAP); | ||
1736 | unsigned int wid_type = (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; | ||
1737 | unsigned int def_conf; | ||
1738 | short assoc, loc; | ||
1739 | |||
1740 | /* read all default configuration for pin complex */ | ||
1741 | if (wid_type != AC_WID_PIN) | ||
1742 | continue; | ||
1743 | def_conf = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); | ||
1744 | if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) | ||
1745 | continue; | ||
1746 | loc = get_defcfg_location(def_conf); | ||
1747 | switch (get_defcfg_device(def_conf)) { | ||
1748 | case AC_JACK_LINE_OUT: | ||
1749 | case AC_JACK_SPEAKER: | ||
1750 | seq = get_defcfg_sequence(def_conf); | ||
1751 | assoc = get_defcfg_association(def_conf); | ||
1752 | if (! assoc) | ||
1753 | continue; | ||
1754 | if (! assoc_line_out) | ||
1755 | assoc_line_out = assoc; | ||
1756 | else if (assoc_line_out != assoc) | ||
1757 | continue; | ||
1758 | if (cfg->line_outs >= ARRAY_SIZE(cfg->line_out_pins)) | ||
1759 | continue; | ||
1760 | cfg->line_out_pins[cfg->line_outs] = nid; | ||
1761 | sequences[cfg->line_outs] = seq; | ||
1762 | cfg->line_outs++; | ||
1763 | break; | ||
1764 | case AC_JACK_HP_OUT: | ||
1765 | cfg->hp_pin = nid; | ||
1766 | break; | ||
1767 | case AC_JACK_MIC_IN: | ||
1768 | if (loc == AC_JACK_LOC_FRONT) | ||
1769 | cfg->input_pins[AUTO_PIN_FRONT_MIC] = nid; | ||
1770 | else | ||
1771 | cfg->input_pins[AUTO_PIN_MIC] = nid; | ||
1772 | break; | ||
1773 | case AC_JACK_LINE_IN: | ||
1774 | if (loc == AC_JACK_LOC_FRONT) | ||
1775 | cfg->input_pins[AUTO_PIN_FRONT_LINE] = nid; | ||
1776 | else | ||
1777 | cfg->input_pins[AUTO_PIN_LINE] = nid; | ||
1778 | break; | ||
1779 | case AC_JACK_CD: | ||
1780 | cfg->input_pins[AUTO_PIN_CD] = nid; | ||
1781 | break; | ||
1782 | case AC_JACK_AUX: | ||
1783 | cfg->input_pins[AUTO_PIN_AUX] = nid; | ||
1784 | break; | ||
1785 | case AC_JACK_SPDIF_OUT: | ||
1786 | cfg->dig_out_pin = nid; | ||
1787 | break; | ||
1788 | case AC_JACK_SPDIF_IN: | ||
1789 | cfg->dig_in_pin = nid; | ||
1790 | break; | ||
1791 | } | ||
1792 | } | ||
1793 | |||
1794 | /* sort by sequence */ | ||
1795 | for (i = 0; i < cfg->line_outs; i++) | ||
1796 | for (j = i + 1; j < cfg->line_outs; j++) | ||
1797 | if (sequences[i] > sequences[j]) { | ||
1798 | seq = sequences[i]; | ||
1799 | sequences[i] = sequences[j]; | ||
1800 | sequences[j] = seq; | ||
1801 | nid = cfg->line_out_pins[i]; | ||
1802 | cfg->line_out_pins[i] = cfg->line_out_pins[j]; | ||
1803 | cfg->line_out_pins[j] = nid; | ||
1804 | } | ||
1805 | |||
1806 | /* Swap surround and CLFE: the association order is front/CLFE/surr/back */ | ||
1807 | if (cfg->line_outs >= 3) { | ||
1808 | nid = cfg->line_out_pins[1]; | ||
1809 | cfg->line_out_pins[1] = cfg->line_out_pins[2]; | ||
1810 | cfg->line_out_pins[2] = nid; | ||
1811 | } | ||
1812 | |||
1813 | return 0; | ||
1814 | } | ||
1815 | |||
1720 | #ifdef CONFIG_PM | 1816 | #ifdef CONFIG_PM |
1721 | /* | 1817 | /* |
1722 | * power management | 1818 | * power management |
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index c9e9dc9c7c98..59991560d492 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h | |||
@@ -75,6 +75,9 @@ enum { | |||
75 | #define AC_VERB_GET_DIGI_CONVERT 0x0f0d | 75 | #define AC_VERB_GET_DIGI_CONVERT 0x0f0d |
76 | #define AC_VERB_GET_VOLUME_KNOB_CONTROL 0x0f0f | 76 | #define AC_VERB_GET_VOLUME_KNOB_CONTROL 0x0f0f |
77 | /* f10-f1a: GPIO */ | 77 | /* f10-f1a: GPIO */ |
78 | #define AC_VERB_GET_GPIO_DATA 0x0f15 | ||
79 | #define AC_VERB_GET_GPIO_MASK 0x0f16 | ||
80 | #define AC_VERB_GET_GPIO_DIRECTION 0x0f17 | ||
78 | #define AC_VERB_GET_CONFIG_DEFAULT 0x0f1c | 81 | #define AC_VERB_GET_CONFIG_DEFAULT 0x0f1c |
79 | 82 | ||
80 | /* | 83 | /* |
@@ -97,6 +100,9 @@ enum { | |||
97 | #define AC_VERB_SET_DIGI_CONVERT_1 0x70d | 100 | #define AC_VERB_SET_DIGI_CONVERT_1 0x70d |
98 | #define AC_VERB_SET_DIGI_CONVERT_2 0x70e | 101 | #define AC_VERB_SET_DIGI_CONVERT_2 0x70e |
99 | #define AC_VERB_SET_VOLUME_KNOB_CONTROL 0x70f | 102 | #define AC_VERB_SET_VOLUME_KNOB_CONTROL 0x70f |
103 | #define AC_VERB_SET_GPIO_DATA 0x715 | ||
104 | #define AC_VERB_SET_GPIO_MASK 0x716 | ||
105 | #define AC_VERB_SET_GPIO_DIRECTION 0x717 | ||
100 | #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 0x71c | 106 | #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 0x71c |
101 | #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_1 0x71d | 107 | #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_1 0x71d |
102 | #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_2 0x71e | 108 | #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_2 0x71e |
@@ -176,16 +182,15 @@ enum { | |||
176 | #define AC_PINCAP_OUT (1<<4) /* output capable */ | 182 | #define AC_PINCAP_OUT (1<<4) /* output capable */ |
177 | #define AC_PINCAP_IN (1<<5) /* input capable */ | 183 | #define AC_PINCAP_IN (1<<5) /* input capable */ |
178 | #define AC_PINCAP_BALANCE (1<<6) /* balanced I/O capable */ | 184 | #define AC_PINCAP_BALANCE (1<<6) /* balanced I/O capable */ |
179 | #define AC_PINCAP_VREF (7<<8) | 185 | #define AC_PINCAP_VREF (0x37<<8) |
180 | #define AC_PINCAP_VREF_SHIFT 8 | 186 | #define AC_PINCAP_VREF_SHIFT 8 |
181 | #define AC_PINCAP_EAPD (1<<16) /* EAPD capable */ | 187 | #define AC_PINCAP_EAPD (1<<16) /* EAPD capable */ |
182 | /* Vref status (used in pin cap and pin ctl) */ | 188 | /* Vref status (used in pin cap) */ |
183 | #define AC_PIN_VREF_HIZ (1<<0) /* Hi-Z */ | 189 | #define AC_PINCAP_VREF_HIZ (1<<0) /* Hi-Z */ |
184 | #define AC_PIN_VREF_50 (1<<1) /* 50% */ | 190 | #define AC_PINCAP_VREF_50 (1<<1) /* 50% */ |
185 | #define AC_PIN_VREF_GRD (1<<2) /* ground */ | 191 | #define AC_PINCAP_VREF_GRD (1<<2) /* ground */ |
186 | #define AC_PIN_VREF_80 (1<<4) /* 80% */ | 192 | #define AC_PINCAP_VREF_80 (1<<4) /* 80% */ |
187 | #define AC_PIN_VREF_100 (1<<5) /* 100% */ | 193 | #define AC_PINCAP_VREF_100 (1<<5) /* 100% */ |
188 | |||
189 | 194 | ||
190 | /* Amplifier capabilities */ | 195 | /* Amplifier capabilities */ |
191 | #define AC_AMPCAP_OFFSET (0x7f<<0) /* 0dB offset */ | 196 | #define AC_AMPCAP_OFFSET (0x7f<<0) /* 0dB offset */ |
@@ -248,6 +253,11 @@ enum { | |||
248 | 253 | ||
249 | /* Pin widget control - 8bit */ | 254 | /* Pin widget control - 8bit */ |
250 | #define AC_PINCTL_VREFEN (0x7<<0) | 255 | #define AC_PINCTL_VREFEN (0x7<<0) |
256 | #define AC_PINCTL_VREF_HIZ 0 /* Hi-Z */ | ||
257 | #define AC_PINCTL_VREF_50 1 /* 50% */ | ||
258 | #define AC_PINCTL_VREF_GRD 2 /* ground */ | ||
259 | #define AC_PINCTL_VREF_80 4 /* 80% */ | ||
260 | #define AC_PINCTL_VREF_100 5 /* 100% */ | ||
251 | #define AC_PINCTL_IN_EN (1<<5) | 261 | #define AC_PINCTL_IN_EN (1<<5) |
252 | #define AC_PINCTL_OUT_EN (1<<6) | 262 | #define AC_PINCTL_OUT_EN (1<<6) |
253 | #define AC_PINCTL_HP_EN (1<<7) | 263 | #define AC_PINCTL_HP_EN (1<<7) |
@@ -255,7 +265,9 @@ enum { | |||
255 | /* configuration default - 32bit */ | 265 | /* configuration default - 32bit */ |
256 | #define AC_DEFCFG_SEQUENCE (0xf<<0) | 266 | #define AC_DEFCFG_SEQUENCE (0xf<<0) |
257 | #define AC_DEFCFG_DEF_ASSOC (0xf<<4) | 267 | #define AC_DEFCFG_DEF_ASSOC (0xf<<4) |
268 | #define AC_DEFCFG_ASSOC_SHIFT 4 | ||
258 | #define AC_DEFCFG_MISC (0xf<<8) | 269 | #define AC_DEFCFG_MISC (0xf<<8) |
270 | #define AC_DEFCFG_MISC_SHIFT 8 | ||
259 | #define AC_DEFCFG_COLOR (0xf<<12) | 271 | #define AC_DEFCFG_COLOR (0xf<<12) |
260 | #define AC_DEFCFG_COLOR_SHIFT 12 | 272 | #define AC_DEFCFG_COLOR_SHIFT 12 |
261 | #define AC_DEFCFG_CONN_TYPE (0xf<<16) | 273 | #define AC_DEFCFG_CONN_TYPE (0xf<<16) |
@@ -413,7 +425,7 @@ struct hda_bus { | |||
413 | 425 | ||
414 | /* codec linked list */ | 426 | /* codec linked list */ |
415 | struct list_head codec_list; | 427 | struct list_head codec_list; |
416 | struct hda_codec *caddr_tbl[HDA_MAX_CODEC_ADDRESS]; /* caddr -> codec */ | 428 | struct hda_codec *caddr_tbl[HDA_MAX_CODEC_ADDRESS + 1]; /* caddr -> codec */ |
417 | 429 | ||
418 | struct semaphore cmd_mutex; | 430 | struct semaphore cmd_mutex; |
419 | 431 | ||
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 69f7b6c4cf83..2d046abb5911 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c | |||
@@ -44,7 +44,7 @@ struct hda_gnode { | |||
44 | struct list_head list; | 44 | struct list_head list; |
45 | }; | 45 | }; |
46 | 46 | ||
47 | /* pathc-specific record */ | 47 | /* patch-specific record */ |
48 | struct hda_gspec { | 48 | struct hda_gspec { |
49 | struct hda_gnode *dac_node; /* DAC node */ | 49 | struct hda_gnode *dac_node; /* DAC node */ |
50 | struct hda_gnode *out_pin_node; /* Output pin (Line-Out) node */ | 50 | struct hda_gnode *out_pin_node; /* Output pin (Line-Out) node */ |
@@ -68,8 +68,8 @@ struct hda_gspec { | |||
68 | /* | 68 | /* |
69 | * retrieve the default device type from the default config value | 69 | * retrieve the default device type from the default config value |
70 | */ | 70 | */ |
71 | #define get_defcfg_type(node) (((node)->def_cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT) | 71 | #define defcfg_type(node) (((node)->def_cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT) |
72 | #define get_defcfg_location(node) (((node)->def_cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT) | 72 | #define defcfg_location(node) (((node)->def_cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT) |
73 | 73 | ||
74 | /* | 74 | /* |
75 | * destructor | 75 | * destructor |
@@ -323,7 +323,7 @@ static struct hda_gnode *parse_output_jack(struct hda_codec *codec, | |||
323 | if (! (node->pin_caps & AC_PINCAP_OUT)) | 323 | if (! (node->pin_caps & AC_PINCAP_OUT)) |
324 | continue; | 324 | continue; |
325 | if (jack_type >= 0) { | 325 | if (jack_type >= 0) { |
326 | if (jack_type != get_defcfg_type(node)) | 326 | if (jack_type != defcfg_type(node)) |
327 | continue; | 327 | continue; |
328 | if (node->wid_caps & AC_WCAP_DIGITAL) | 328 | if (node->wid_caps & AC_WCAP_DIGITAL) |
329 | continue; /* skip SPDIF */ | 329 | continue; /* skip SPDIF */ |
@@ -418,15 +418,15 @@ static int capture_source_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *uc | |||
418 | */ | 418 | */ |
419 | static const char *get_input_type(struct hda_gnode *node, unsigned int *pinctl) | 419 | static const char *get_input_type(struct hda_gnode *node, unsigned int *pinctl) |
420 | { | 420 | { |
421 | unsigned int location = get_defcfg_location(node); | 421 | unsigned int location = defcfg_location(node); |
422 | switch (get_defcfg_type(node)) { | 422 | switch (defcfg_type(node)) { |
423 | case AC_JACK_LINE_IN: | 423 | case AC_JACK_LINE_IN: |
424 | if ((location & 0x0f) == AC_JACK_LOC_FRONT) | 424 | if ((location & 0x0f) == AC_JACK_LOC_FRONT) |
425 | return "Front Line"; | 425 | return "Front Line"; |
426 | return "Line"; | 426 | return "Line"; |
427 | case AC_JACK_CD: | 427 | case AC_JACK_CD: |
428 | if (pinctl) | 428 | if (pinctl) |
429 | *pinctl |= AC_PIN_VREF_GRD; | 429 | *pinctl |= AC_PINCTL_VREF_GRD; |
430 | return "CD"; | 430 | return "CD"; |
431 | case AC_JACK_AUX: | 431 | case AC_JACK_AUX: |
432 | if ((location & 0x0f) == AC_JACK_LOC_FRONT) | 432 | if ((location & 0x0f) == AC_JACK_LOC_FRONT) |
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 959953ca320a..5e0cca36ed57 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c | |||
@@ -51,6 +51,7 @@ static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | |||
51 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; | 51 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; |
52 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | 52 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; |
53 | static char *model[SNDRV_CARDS]; | 53 | static char *model[SNDRV_CARDS]; |
54 | static int position_fix[SNDRV_CARDS]; | ||
54 | 55 | ||
55 | module_param_array(index, int, NULL, 0444); | 56 | module_param_array(index, int, NULL, 0444); |
56 | MODULE_PARM_DESC(index, "Index value for Intel HD audio interface."); | 57 | MODULE_PARM_DESC(index, "Index value for Intel HD audio interface."); |
@@ -60,12 +61,17 @@ module_param_array(enable, bool, NULL, 0444); | |||
60 | MODULE_PARM_DESC(enable, "Enable Intel HD audio interface."); | 61 | MODULE_PARM_DESC(enable, "Enable Intel HD audio interface."); |
61 | module_param_array(model, charp, NULL, 0444); | 62 | module_param_array(model, charp, NULL, 0444); |
62 | MODULE_PARM_DESC(model, "Use the given board model."); | 63 | MODULE_PARM_DESC(model, "Use the given board model."); |
64 | module_param_array(position_fix, int, NULL, 0444); | ||
65 | MODULE_PARM_DESC(position_fix, "Fix DMA pointer (0 = FIFO size, 1 = none, 2 = POSBUF)."); | ||
63 | 66 | ||
64 | MODULE_LICENSE("GPL"); | 67 | MODULE_LICENSE("GPL"); |
65 | MODULE_SUPPORTED_DEVICE("{{Intel, ICH6}," | 68 | MODULE_SUPPORTED_DEVICE("{{Intel, ICH6}," |
66 | "{Intel, ICH6M}," | 69 | "{Intel, ICH6M}," |
67 | "{Intel, ICH7}," | 70 | "{Intel, ICH7}," |
68 | "{Intel, ESB2}}"); | 71 | "{Intel, ESB2}," |
72 | "{ATI, SB450}," | ||
73 | "{VIA, VT8251}," | ||
74 | "{VIA, VT8237A}}"); | ||
69 | MODULE_DESCRIPTION("Intel HDA driver"); | 75 | MODULE_DESCRIPTION("Intel HDA driver"); |
70 | 76 | ||
71 | #define SFX "hda-intel: " | 77 | #define SFX "hda-intel: " |
@@ -150,7 +156,7 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; | |||
150 | 156 | ||
151 | /* STATESTS int mask: SD2,SD1,SD0 */ | 157 | /* STATESTS int mask: SD2,SD1,SD0 */ |
152 | #define STATESTS_INT_MASK 0x07 | 158 | #define STATESTS_INT_MASK 0x07 |
153 | #define AZX_MAX_CODECS 3 | 159 | #define AZX_MAX_CODECS 4 |
154 | 160 | ||
155 | /* SD_CTL bits */ | 161 | /* SD_CTL bits */ |
156 | #define SD_CTL_STREAM_RESET 0x01 /* stream reset bit */ | 162 | #define SD_CTL_STREAM_RESET 0x01 /* stream reset bit */ |
@@ -183,6 +189,18 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; | |||
183 | #define ICH6_MAX_CORB_ENTRIES 256 | 189 | #define ICH6_MAX_CORB_ENTRIES 256 |
184 | #define ICH6_MAX_RIRB_ENTRIES 256 | 190 | #define ICH6_MAX_RIRB_ENTRIES 256 |
185 | 191 | ||
192 | /* position fix mode */ | ||
193 | enum { | ||
194 | POS_FIX_FIFO, | ||
195 | POS_FIX_NONE, | ||
196 | POS_FIX_POSBUF | ||
197 | }; | ||
198 | |||
199 | /* Defines for ATI HD Audio support in SB450 south bridge */ | ||
200 | #define ATI_SB450_HDAUDIO_PCI_DEVICE_ID 0x437b | ||
201 | #define ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR 0x42 | ||
202 | #define ATI_SB450_HDAUDIO_ENABLE_SNOOP 0x02 | ||
203 | |||
186 | 204 | ||
187 | /* | 205 | /* |
188 | * Use CORB/RIRB for communication from/to codecs. | 206 | * Use CORB/RIRB for communication from/to codecs. |
@@ -191,12 +209,6 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; | |||
191 | #define USE_CORB_RIRB | 209 | #define USE_CORB_RIRB |
192 | 210 | ||
193 | /* | 211 | /* |
194 | * Define this if use the position buffer instead of reading SD_LPIB | ||
195 | * It's not used as default since SD_LPIB seems to give more accurate position | ||
196 | */ | ||
197 | /* #define USE_POSBUF */ | ||
198 | |||
199 | /* | ||
200 | */ | 212 | */ |
201 | 213 | ||
202 | typedef struct snd_azx azx_t; | 214 | typedef struct snd_azx azx_t; |
@@ -271,6 +283,10 @@ struct snd_azx { | |||
271 | struct snd_dma_buffer bdl; | 283 | struct snd_dma_buffer bdl; |
272 | struct snd_dma_buffer rb; | 284 | struct snd_dma_buffer rb; |
273 | struct snd_dma_buffer posbuf; | 285 | struct snd_dma_buffer posbuf; |
286 | |||
287 | /* flags */ | ||
288 | int position_fix; | ||
289 | unsigned int initialized: 1; | ||
274 | }; | 290 | }; |
275 | 291 | ||
276 | /* | 292 | /* |
@@ -638,7 +654,7 @@ static void azx_stream_stop(azx_t *chip, azx_dev_t *azx_dev) | |||
638 | */ | 654 | */ |
639 | static void azx_init_chip(azx_t *chip) | 655 | static void azx_init_chip(azx_t *chip) |
640 | { | 656 | { |
641 | unsigned char tcsel_reg; | 657 | unsigned char tcsel_reg, ati_misc_cntl2; |
642 | 658 | ||
643 | /* Clear bits 0-2 of PCI register TCSEL (at offset 0x44) | 659 | /* Clear bits 0-2 of PCI register TCSEL (at offset 0x44) |
644 | * TCSEL == Traffic Class Select Register, which sets PCI express QOS | 660 | * TCSEL == Traffic Class Select Register, which sets PCI express QOS |
@@ -657,11 +673,20 @@ static void azx_init_chip(azx_t *chip) | |||
657 | /* initialize the codec command I/O */ | 673 | /* initialize the codec command I/O */ |
658 | azx_init_cmd_io(chip); | 674 | azx_init_cmd_io(chip); |
659 | 675 | ||
660 | #ifdef USE_POSBUF | 676 | if (chip->position_fix == POS_FIX_POSBUF) { |
661 | /* program the position buffer */ | 677 | /* program the position buffer */ |
662 | azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr); | 678 | azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr); |
663 | azx_writel(chip, DPUBASE, upper_32bit(chip->posbuf.addr)); | 679 | azx_writel(chip, DPUBASE, upper_32bit(chip->posbuf.addr)); |
664 | #endif | 680 | } |
681 | |||
682 | /* For ATI SB450 azalia HD audio, we need to enable snoop */ | ||
683 | if (chip->pci->vendor == PCI_VENDOR_ID_ATI && | ||
684 | chip->pci->device == ATI_SB450_HDAUDIO_PCI_DEVICE_ID) { | ||
685 | pci_read_config_byte(chip->pci, ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, | ||
686 | &ati_misc_cntl2); | ||
687 | pci_write_config_byte(chip->pci, ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, | ||
688 | (ati_misc_cntl2 & 0xf8) | ATI_SB450_HDAUDIO_ENABLE_SNOOP); | ||
689 | } | ||
665 | } | 690 | } |
666 | 691 | ||
667 | 692 | ||
@@ -791,11 +816,12 @@ static int azx_setup_controller(azx_t *chip, azx_dev_t *azx_dev) | |||
791 | /* upper BDL address */ | 816 | /* upper BDL address */ |
792 | azx_sd_writel(azx_dev, SD_BDLPU, upper_32bit(azx_dev->bdl_addr)); | 817 | azx_sd_writel(azx_dev, SD_BDLPU, upper_32bit(azx_dev->bdl_addr)); |
793 | 818 | ||
794 | #ifdef USE_POSBUF | 819 | if (chip->position_fix == POS_FIX_POSBUF) { |
795 | /* enable the position buffer */ | 820 | /* enable the position buffer */ |
796 | if (! (azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE)) | 821 | if (! (azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE)) |
797 | azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE); | 822 | azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE); |
798 | #endif | 823 | } |
824 | |||
799 | /* set the interrupt enable bits in the descriptor control register */ | 825 | /* set the interrupt enable bits in the descriptor control register */ |
800 | azx_sd_writel(azx_dev, SD_CTL, azx_sd_readl(azx_dev, SD_CTL) | SD_INT_MASK); | 826 | azx_sd_writel(azx_dev, SD_CTL, azx_sd_readl(azx_dev, SD_CTL) | SD_INT_MASK); |
801 | 827 | ||
@@ -1036,16 +1062,20 @@ static int azx_pcm_trigger(snd_pcm_substream_t *substream, int cmd) | |||
1036 | 1062 | ||
1037 | static snd_pcm_uframes_t azx_pcm_pointer(snd_pcm_substream_t *substream) | 1063 | static snd_pcm_uframes_t azx_pcm_pointer(snd_pcm_substream_t *substream) |
1038 | { | 1064 | { |
1065 | struct azx_pcm *apcm = snd_pcm_substream_chip(substream); | ||
1066 | azx_t *chip = apcm->chip; | ||
1039 | azx_dev_t *azx_dev = get_azx_dev(substream); | 1067 | azx_dev_t *azx_dev = get_azx_dev(substream); |
1040 | unsigned int pos; | 1068 | unsigned int pos; |
1041 | 1069 | ||
1042 | #ifdef USE_POSBUF | 1070 | if (chip->position_fix == POS_FIX_POSBUF) { |
1043 | /* use the position buffer */ | 1071 | /* use the position buffer */ |
1044 | pos = *azx_dev->posbuf; | 1072 | pos = *azx_dev->posbuf; |
1045 | #else | 1073 | } else { |
1046 | /* read LPIB */ | 1074 | /* read LPIB */ |
1047 | pos = azx_sd_readl(azx_dev, SD_LPIB) + azx_dev->fifo_size; | 1075 | pos = azx_sd_readl(azx_dev, SD_LPIB); |
1048 | #endif | 1076 | if (chip->position_fix == POS_FIX_FIFO) |
1077 | pos += azx_dev->fifo_size; | ||
1078 | } | ||
1049 | if (pos >= azx_dev->bufsize) | 1079 | if (pos >= azx_dev->bufsize) |
1050 | pos = 0; | 1080 | pos = 0; |
1051 | return bytes_to_frames(substream->runtime, pos); | 1081 | return bytes_to_frames(substream->runtime, pos); |
@@ -1155,9 +1185,8 @@ static int __devinit azx_init_stream(azx_t *chip) | |||
1155 | azx_dev_t *azx_dev = &chip->azx_dev[i]; | 1185 | azx_dev_t *azx_dev = &chip->azx_dev[i]; |
1156 | azx_dev->bdl = (u32 *)(chip->bdl.area + off); | 1186 | azx_dev->bdl = (u32 *)(chip->bdl.area + off); |
1157 | azx_dev->bdl_addr = chip->bdl.addr + off; | 1187 | azx_dev->bdl_addr = chip->bdl.addr + off; |
1158 | #ifdef USE_POSBUF | 1188 | if (chip->position_fix == POS_FIX_POSBUF) |
1159 | azx_dev->posbuf = (volatile u32 *)(chip->posbuf.area + i * 8); | 1189 | azx_dev->posbuf = (volatile u32 *)(chip->posbuf.area + i * 8); |
1160 | #endif | ||
1161 | /* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */ | 1190 | /* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */ |
1162 | azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80); | 1191 | azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80); |
1163 | /* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */ | 1192 | /* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */ |
@@ -1207,7 +1236,7 @@ static int azx_resume(snd_card_t *card) | |||
1207 | */ | 1236 | */ |
1208 | static int azx_free(azx_t *chip) | 1237 | static int azx_free(azx_t *chip) |
1209 | { | 1238 | { |
1210 | if (chip->remap_addr) { | 1239 | if (chip->initialized) { |
1211 | int i; | 1240 | int i; |
1212 | 1241 | ||
1213 | for (i = 0; i < MAX_ICH6_DEV; i++) | 1242 | for (i = 0; i < MAX_ICH6_DEV; i++) |
@@ -1237,10 +1266,8 @@ static int azx_free(azx_t *chip) | |||
1237 | snd_dma_free_pages(&chip->bdl); | 1266 | snd_dma_free_pages(&chip->bdl); |
1238 | if (chip->rb.area) | 1267 | if (chip->rb.area) |
1239 | snd_dma_free_pages(&chip->rb); | 1268 | snd_dma_free_pages(&chip->rb); |
1240 | #ifdef USE_POSBUF | ||
1241 | if (chip->posbuf.area) | 1269 | if (chip->posbuf.area) |
1242 | snd_dma_free_pages(&chip->posbuf); | 1270 | snd_dma_free_pages(&chip->posbuf); |
1243 | #endif | ||
1244 | pci_release_regions(chip->pci); | 1271 | pci_release_regions(chip->pci); |
1245 | pci_disable_device(chip->pci); | 1272 | pci_disable_device(chip->pci); |
1246 | kfree(chip); | 1273 | kfree(chip); |
@@ -1256,7 +1283,8 @@ static int azx_dev_free(snd_device_t *device) | |||
1256 | /* | 1283 | /* |
1257 | * constructor | 1284 | * constructor |
1258 | */ | 1285 | */ |
1259 | static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci, azx_t **rchip) | 1286 | static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci, |
1287 | int posfix, azx_t **rchip) | ||
1260 | { | 1288 | { |
1261 | azx_t *chip; | 1289 | azx_t *chip; |
1262 | int err = 0; | 1290 | int err = 0; |
@@ -1283,6 +1311,8 @@ static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci, azx_t **r | |||
1283 | chip->pci = pci; | 1311 | chip->pci = pci; |
1284 | chip->irq = -1; | 1312 | chip->irq = -1; |
1285 | 1313 | ||
1314 | chip->position_fix = posfix; | ||
1315 | |||
1286 | if ((err = pci_request_regions(pci, "ICH HD audio")) < 0) { | 1316 | if ((err = pci_request_regions(pci, "ICH HD audio")) < 0) { |
1287 | kfree(chip); | 1317 | kfree(chip); |
1288 | pci_disable_device(pci); | 1318 | pci_disable_device(pci); |
@@ -1314,14 +1344,14 @@ static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci, azx_t **r | |||
1314 | snd_printk(KERN_ERR SFX "cannot allocate BDL\n"); | 1344 | snd_printk(KERN_ERR SFX "cannot allocate BDL\n"); |
1315 | goto errout; | 1345 | goto errout; |
1316 | } | 1346 | } |
1317 | #ifdef USE_POSBUF | 1347 | if (chip->position_fix == POS_FIX_POSBUF) { |
1318 | /* allocate memory for the position buffer */ | 1348 | /* allocate memory for the position buffer */ |
1319 | if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), | 1349 | if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), |
1320 | MAX_ICH6_DEV * 8, &chip->posbuf)) < 0) { | 1350 | MAX_ICH6_DEV * 8, &chip->posbuf)) < 0) { |
1321 | snd_printk(KERN_ERR SFX "cannot allocate posbuf\n"); | 1351 | snd_printk(KERN_ERR SFX "cannot allocate posbuf\n"); |
1322 | goto errout; | 1352 | goto errout; |
1353 | } | ||
1323 | } | 1354 | } |
1324 | #endif | ||
1325 | /* allocate CORB/RIRB */ | 1355 | /* allocate CORB/RIRB */ |
1326 | if ((err = azx_alloc_cmd_io(chip)) < 0) | 1356 | if ((err = azx_alloc_cmd_io(chip)) < 0) |
1327 | goto errout; | 1357 | goto errout; |
@@ -1332,6 +1362,8 @@ static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci, azx_t **r | |||
1332 | /* initialize chip */ | 1362 | /* initialize chip */ |
1333 | azx_init_chip(chip); | 1363 | azx_init_chip(chip); |
1334 | 1364 | ||
1365 | chip->initialized = 1; | ||
1366 | |||
1335 | /* codec detection */ | 1367 | /* codec detection */ |
1336 | if (! chip->codec_mask) { | 1368 | if (! chip->codec_mask) { |
1337 | snd_printk(KERN_ERR SFX "no codecs found!\n"); | 1369 | snd_printk(KERN_ERR SFX "no codecs found!\n"); |
@@ -1372,7 +1404,7 @@ static int __devinit azx_probe(struct pci_dev *pci, const struct pci_device_id * | |||
1372 | return -ENOMEM; | 1404 | return -ENOMEM; |
1373 | } | 1405 | } |
1374 | 1406 | ||
1375 | if ((err = azx_create(card, pci, &chip)) < 0) { | 1407 | if ((err = azx_create(card, pci, position_fix[dev], &chip)) < 0) { |
1376 | snd_card_free(card); | 1408 | snd_card_free(card); |
1377 | return err; | 1409 | return err; |
1378 | } | 1410 | } |
@@ -1424,6 +1456,9 @@ static struct pci_device_id azx_ids[] = { | |||
1424 | { 0x8086, 0x2668, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ICH6 */ | 1456 | { 0x8086, 0x2668, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ICH6 */ |
1425 | { 0x8086, 0x27d8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ICH7 */ | 1457 | { 0x8086, 0x27d8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ICH7 */ |
1426 | { 0x8086, 0x269a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ESB2 */ | 1458 | { 0x8086, 0x269a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ESB2 */ |
1459 | { 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ATI SB450 */ | ||
1460 | { 0x1106, 0x3288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* VIA VT8251/VT8237A */ | ||
1461 | { 0x10b9, 0x5461, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ALI 5461? */ | ||
1427 | { 0, } | 1462 | { 0, } |
1428 | }; | 1463 | }; |
1429 | MODULE_DEVICE_TABLE(pci, azx_ids); | 1464 | MODULE_DEVICE_TABLE(pci, azx_ids); |
@@ -1439,7 +1474,7 @@ static struct pci_driver driver = { | |||
1439 | 1474 | ||
1440 | static int __init alsa_card_azx_init(void) | 1475 | static int __init alsa_card_azx_init(void) |
1441 | { | 1476 | { |
1442 | return pci_module_init(&driver); | 1477 | return pci_register_driver(&driver); |
1443 | } | 1478 | } |
1444 | 1479 | ||
1445 | static void __exit alsa_card_azx_exit(void) | 1480 | static void __exit alsa_card_azx_exit(void) |
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 7c7b849875a0..810cfd2d9bba 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h | |||
@@ -126,11 +126,11 @@ static inline int snd_hda_codec_proc_new(struct hda_codec *codec) { return 0; } | |||
126 | struct hda_board_config { | 126 | struct hda_board_config { |
127 | const char *modelname; | 127 | const char *modelname; |
128 | int config; | 128 | int config; |
129 | unsigned short pci_vendor; | 129 | unsigned short pci_subvendor; |
130 | unsigned short pci_device; | 130 | unsigned short pci_subdevice; |
131 | }; | 131 | }; |
132 | 132 | ||
133 | int snd_hda_check_board_config(struct hda_codec *codec, struct hda_board_config *tbl); | 133 | int snd_hda_check_board_config(struct hda_codec *codec, const struct hda_board_config *tbl); |
134 | int snd_hda_add_new_ctls(struct hda_codec *codec, snd_kcontrol_new_t *knew); | 134 | int snd_hda_add_new_ctls(struct hda_codec *codec, snd_kcontrol_new_t *knew); |
135 | 135 | ||
136 | /* | 136 | /* |
@@ -158,4 +158,35 @@ struct hda_bus_unsolicited { | |||
158 | struct work_struct work; | 158 | struct work_struct work; |
159 | }; | 159 | }; |
160 | 160 | ||
161 | /* | ||
162 | * Helper for automatic ping configuration | ||
163 | */ | ||
164 | |||
165 | enum { | ||
166 | AUTO_PIN_MIC, | ||
167 | AUTO_PIN_FRONT_MIC, | ||
168 | AUTO_PIN_LINE, | ||
169 | AUTO_PIN_FRONT_LINE, | ||
170 | AUTO_PIN_CD, | ||
171 | AUTO_PIN_AUX, | ||
172 | AUTO_PIN_LAST | ||
173 | }; | ||
174 | |||
175 | struct auto_pin_cfg { | ||
176 | int line_outs; | ||
177 | hda_nid_t line_out_pins[4]; /* sorted in the order of Front/Surr/CLFE/Side */ | ||
178 | hda_nid_t hp_pin; | ||
179 | hda_nid_t input_pins[AUTO_PIN_LAST]; | ||
180 | hda_nid_t dig_out_pin; | ||
181 | hda_nid_t dig_in_pin; | ||
182 | }; | ||
183 | |||
184 | #define get_defcfg_connect(cfg) ((cfg & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT) | ||
185 | #define get_defcfg_association(cfg) ((cfg & AC_DEFCFG_DEF_ASSOC) >> AC_DEFCFG_ASSOC_SHIFT) | ||
186 | #define get_defcfg_location(cfg) ((cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT) | ||
187 | #define get_defcfg_sequence(cfg) (cfg & AC_DEFCFG_SEQUENCE) | ||
188 | #define get_defcfg_device(cfg) ((cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT) | ||
189 | |||
190 | int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *cfg); | ||
191 | |||
161 | #endif /* __SOUND_HDA_LOCAL_H */ | 192 | #endif /* __SOUND_HDA_LOCAL_H */ |
diff --git a/sound/pci/hda/hda_patch.h b/sound/pci/hda/hda_patch.h index cf6abce42bc9..a5de684b6944 100644 --- a/sound/pci/hda/hda_patch.h +++ b/sound/pci/hda/hda_patch.h | |||
@@ -8,10 +8,13 @@ extern struct hda_codec_preset snd_hda_preset_realtek[]; | |||
8 | extern struct hda_codec_preset snd_hda_preset_cmedia[]; | 8 | extern struct hda_codec_preset snd_hda_preset_cmedia[]; |
9 | /* Analog Devices codecs */ | 9 | /* Analog Devices codecs */ |
10 | extern struct hda_codec_preset snd_hda_preset_analog[]; | 10 | extern struct hda_codec_preset snd_hda_preset_analog[]; |
11 | /* SigmaTel codecs */ | ||
12 | extern struct hda_codec_preset snd_hda_preset_sigmatel[]; | ||
11 | 13 | ||
12 | static const struct hda_codec_preset *hda_preset_tables[] = { | 14 | static const struct hda_codec_preset *hda_preset_tables[] = { |
13 | snd_hda_preset_realtek, | 15 | snd_hda_preset_realtek, |
14 | snd_hda_preset_cmedia, | 16 | snd_hda_preset_cmedia, |
15 | snd_hda_preset_analog, | 17 | snd_hda_preset_analog, |
18 | snd_hda_preset_sigmatel, | ||
16 | NULL | 19 | NULL |
17 | }; | 20 | }; |
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 4d5db7faad8d..de1217bd8e68 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c | |||
@@ -68,21 +68,27 @@ static void print_amp_caps(snd_info_buffer_t *buffer, | |||
68 | 68 | ||
69 | static void print_amp_vals(snd_info_buffer_t *buffer, | 69 | static void print_amp_vals(snd_info_buffer_t *buffer, |
70 | struct hda_codec *codec, hda_nid_t nid, | 70 | struct hda_codec *codec, hda_nid_t nid, |
71 | int dir, int stereo) | 71 | int dir, int stereo, int indices) |
72 | { | 72 | { |
73 | unsigned int val; | 73 | unsigned int val; |
74 | if (stereo) { | 74 | int i; |
75 | |||
76 | if (dir == HDA_OUTPUT) | ||
77 | dir = AC_AMP_GET_OUTPUT; | ||
78 | else | ||
79 | dir = AC_AMP_GET_INPUT; | ||
80 | for (i = 0; i < indices; i++) { | ||
81 | snd_iprintf(buffer, " ["); | ||
82 | if (stereo) { | ||
83 | val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, | ||
84 | AC_AMP_GET_LEFT | dir | i); | ||
85 | snd_iprintf(buffer, "0x%02x ", val); | ||
86 | } | ||
75 | val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, | 87 | val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, |
76 | AC_AMP_GET_LEFT | | 88 | AC_AMP_GET_RIGHT | dir | i); |
77 | (dir == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : | 89 | snd_iprintf(buffer, "0x%02x]", val); |
78 | AC_AMP_GET_INPUT)); | ||
79 | snd_iprintf(buffer, "0x%02x ", val); | ||
80 | } | 90 | } |
81 | val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, | 91 | snd_iprintf(buffer, "\n"); |
82 | AC_AMP_GET_RIGHT | | ||
83 | (dir == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : | ||
84 | AC_AMP_GET_INPUT)); | ||
85 | snd_iprintf(buffer, "0x%02x\n", val); | ||
86 | } | 92 | } |
87 | 93 | ||
88 | static void print_pcm_caps(snd_info_buffer_t *buffer, | 94 | static void print_pcm_caps(snd_info_buffer_t *buffer, |
@@ -157,6 +163,7 @@ static const char *get_jack_color(u32 cfg) | |||
157 | static void print_pin_caps(snd_info_buffer_t *buffer, | 163 | static void print_pin_caps(snd_info_buffer_t *buffer, |
158 | struct hda_codec *codec, hda_nid_t nid) | 164 | struct hda_codec *codec, hda_nid_t nid) |
159 | { | 165 | { |
166 | static char *jack_conns[4] = { "Jack", "N/A", "Fixed", "Both" }; | ||
160 | static char *jack_types[16] = { | 167 | static char *jack_types[16] = { |
161 | "Line Out", "Speaker", "HP Out", "CD", | 168 | "Line Out", "Speaker", "HP Out", "CD", |
162 | "SPDIF Out", "Digital Out", "Modem Line", "Modem Hand", | 169 | "SPDIF Out", "Digital Out", "Modem Line", "Modem Hand", |
@@ -176,7 +183,8 @@ static void print_pin_caps(snd_info_buffer_t *buffer, | |||
176 | snd_iprintf(buffer, " HP"); | 183 | snd_iprintf(buffer, " HP"); |
177 | snd_iprintf(buffer, "\n"); | 184 | snd_iprintf(buffer, "\n"); |
178 | caps = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); | 185 | caps = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); |
179 | snd_iprintf(buffer, " Pin Default 0x%08x: %s at %s %s\n", caps, | 186 | snd_iprintf(buffer, " Pin Default 0x%08x: [%s] %s at %s %s\n", caps, |
187 | jack_conns[(caps & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT], | ||
180 | jack_types[(caps & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT], | 188 | jack_types[(caps & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT], |
181 | jack_locations[(caps >> (AC_DEFCFG_LOCATION_SHIFT + 4)) & 3], | 189 | jack_locations[(caps >> (AC_DEFCFG_LOCATION_SHIFT + 4)) & 3], |
182 | get_jack_location(caps)); | 190 | get_jack_location(caps)); |
@@ -215,6 +223,9 @@ static void print_codec_info(snd_info_entry_t *entry, snd_info_buffer_t *buffer) | |||
215 | unsigned int wid_caps = snd_hda_param_read(codec, nid, | 223 | unsigned int wid_caps = snd_hda_param_read(codec, nid, |
216 | AC_PAR_AUDIO_WIDGET_CAP); | 224 | AC_PAR_AUDIO_WIDGET_CAP); |
217 | unsigned int wid_type = (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; | 225 | unsigned int wid_type = (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; |
226 | int conn_len = 0; | ||
227 | hda_nid_t conn[HDA_MAX_CONNECTIONS]; | ||
228 | |||
218 | snd_iprintf(buffer, "Node 0x%02x [%s] wcaps 0x%x:", nid, | 229 | snd_iprintf(buffer, "Node 0x%02x [%s] wcaps 0x%x:", nid, |
219 | get_wid_type_name(wid_type), wid_caps); | 230 | get_wid_type_name(wid_type), wid_caps); |
220 | if (wid_caps & AC_WCAP_STEREO) | 231 | if (wid_caps & AC_WCAP_STEREO) |
@@ -229,19 +240,23 @@ static void print_codec_info(snd_info_entry_t *entry, snd_info_buffer_t *buffer) | |||
229 | snd_iprintf(buffer, " Amp-Out"); | 240 | snd_iprintf(buffer, " Amp-Out"); |
230 | snd_iprintf(buffer, "\n"); | 241 | snd_iprintf(buffer, "\n"); |
231 | 242 | ||
243 | if (wid_caps & AC_WCAP_CONN_LIST) | ||
244 | conn_len = snd_hda_get_connections(codec, nid, conn, | ||
245 | HDA_MAX_CONNECTIONS); | ||
246 | |||
232 | if (wid_caps & AC_WCAP_IN_AMP) { | 247 | if (wid_caps & AC_WCAP_IN_AMP) { |
233 | snd_iprintf(buffer, " Amp-In caps: "); | 248 | snd_iprintf(buffer, " Amp-In caps: "); |
234 | print_amp_caps(buffer, codec, nid, HDA_INPUT); | 249 | print_amp_caps(buffer, codec, nid, HDA_INPUT); |
235 | snd_iprintf(buffer, " Amp-In vals: "); | 250 | snd_iprintf(buffer, " Amp-In vals: "); |
236 | print_amp_vals(buffer, codec, nid, HDA_INPUT, | 251 | print_amp_vals(buffer, codec, nid, HDA_INPUT, |
237 | wid_caps & AC_WCAP_STEREO); | 252 | wid_caps & AC_WCAP_STEREO, conn_len); |
238 | } | 253 | } |
239 | if (wid_caps & AC_WCAP_OUT_AMP) { | 254 | if (wid_caps & AC_WCAP_OUT_AMP) { |
240 | snd_iprintf(buffer, " Amp-Out caps: "); | 255 | snd_iprintf(buffer, " Amp-Out caps: "); |
241 | print_amp_caps(buffer, codec, nid, HDA_OUTPUT); | 256 | print_amp_caps(buffer, codec, nid, HDA_OUTPUT); |
242 | snd_iprintf(buffer, " Amp-Out vals: "); | 257 | snd_iprintf(buffer, " Amp-Out vals: "); |
243 | print_amp_vals(buffer, codec, nid, HDA_OUTPUT, | 258 | print_amp_vals(buffer, codec, nid, HDA_OUTPUT, |
244 | wid_caps & AC_WCAP_STEREO); | 259 | wid_caps & AC_WCAP_STEREO, 1); |
245 | } | 260 | } |
246 | 261 | ||
247 | if (wid_type == AC_WID_PIN) { | 262 | if (wid_type == AC_WID_PIN) { |
@@ -265,14 +280,17 @@ static void print_codec_info(snd_info_entry_t *entry, snd_info_buffer_t *buffer) | |||
265 | } | 280 | } |
266 | 281 | ||
267 | if (wid_caps & AC_WCAP_CONN_LIST) { | 282 | if (wid_caps & AC_WCAP_CONN_LIST) { |
268 | hda_nid_t conn[HDA_MAX_CONNECTIONS]; | 283 | int c, curr = -1; |
269 | int c, conn_len; | 284 | if (conn_len > 1 && wid_type != AC_WID_AUD_MIX) |
270 | conn_len = snd_hda_get_connections(codec, nid, conn, | 285 | curr = snd_hda_codec_read(codec, nid, 0, |
271 | HDA_MAX_CONNECTIONS); | 286 | AC_VERB_GET_CONNECT_SEL, 0); |
272 | snd_iprintf(buffer, " Connection: %d\n", conn_len); | 287 | snd_iprintf(buffer, " Connection: %d\n", conn_len); |
273 | snd_iprintf(buffer, " "); | 288 | snd_iprintf(buffer, " "); |
274 | for (c = 0; c < conn_len; c++) | 289 | for (c = 0; c < conn_len; c++) { |
275 | snd_iprintf(buffer, " 0x%02x", conn[c]); | 290 | snd_iprintf(buffer, " 0x%02x", conn[c]); |
291 | if (c == curr) | ||
292 | snd_iprintf(buffer, "*"); | ||
293 | } | ||
276 | snd_iprintf(buffer, "\n"); | 294 | snd_iprintf(buffer, "\n"); |
277 | } | 295 | } |
278 | } | 296 | } |
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 75d23849f71a..2fd05bb84136 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * HD audio interface patch for AD1986A | 2 | * HD audio interface patch for AD1981HD, AD1983, AD1986A |
3 | * | 3 | * |
4 | * Copyright (c) 2005 Takashi Iwai <tiwai@suse.de> | 4 | * Copyright (c) 2005 Takashi Iwai <tiwai@suse.de> |
5 | * | 5 | * |
@@ -27,13 +27,239 @@ | |||
27 | #include "hda_codec.h" | 27 | #include "hda_codec.h" |
28 | #include "hda_local.h" | 28 | #include "hda_local.h" |
29 | 29 | ||
30 | struct ad1986a_spec { | 30 | struct ad198x_spec { |
31 | struct semaphore amp_mutex; /* PCM volume/mute control mutex */ | 31 | struct semaphore amp_mutex; /* PCM volume/mute control mutex */ |
32 | struct hda_multi_out multiout; /* playback */ | 32 | struct hda_multi_out multiout; /* playback */ |
33 | hda_nid_t adc_nid; | ||
34 | const struct hda_input_mux *input_mux; | ||
33 | unsigned int cur_mux; /* capture source */ | 35 | unsigned int cur_mux; /* capture source */ |
36 | unsigned int spdif_route; | ||
37 | snd_kcontrol_new_t *mixers; | ||
38 | const struct hda_verb *init_verbs; | ||
34 | struct hda_pcm pcm_rec[2]; /* PCM information */ | 39 | struct hda_pcm pcm_rec[2]; /* PCM information */ |
35 | }; | 40 | }; |
36 | 41 | ||
42 | /* | ||
43 | * input MUX handling (common part) | ||
44 | */ | ||
45 | static int ad198x_mux_enum_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) | ||
46 | { | ||
47 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
48 | struct ad198x_spec *spec = codec->spec; | ||
49 | |||
50 | return snd_hda_input_mux_info(spec->input_mux, uinfo); | ||
51 | } | ||
52 | |||
53 | static int ad198x_mux_enum_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
54 | { | ||
55 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
56 | struct ad198x_spec *spec = codec->spec; | ||
57 | |||
58 | ucontrol->value.enumerated.item[0] = spec->cur_mux; | ||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | static int ad198x_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
63 | { | ||
64 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
65 | struct ad198x_spec *spec = codec->spec; | ||
66 | |||
67 | return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, | ||
68 | spec->adc_nid, &spec->cur_mux); | ||
69 | } | ||
70 | |||
71 | /* | ||
72 | * initialization (common callbacks) | ||
73 | */ | ||
74 | static int ad198x_init(struct hda_codec *codec) | ||
75 | { | ||
76 | struct ad198x_spec *spec = codec->spec; | ||
77 | snd_hda_sequence_write(codec, spec->init_verbs); | ||
78 | return 0; | ||
79 | } | ||
80 | |||
81 | static int ad198x_build_controls(struct hda_codec *codec) | ||
82 | { | ||
83 | struct ad198x_spec *spec = codec->spec; | ||
84 | int err; | ||
85 | |||
86 | err = snd_hda_add_new_ctls(codec, spec->mixers); | ||
87 | if (err < 0) | ||
88 | return err; | ||
89 | if (spec->multiout.dig_out_nid) | ||
90 | err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); | ||
91 | if (err < 0) | ||
92 | return err; | ||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | /* | ||
97 | * Analog playback callbacks | ||
98 | */ | ||
99 | static int ad198x_playback_pcm_open(struct hda_pcm_stream *hinfo, | ||
100 | struct hda_codec *codec, | ||
101 | snd_pcm_substream_t *substream) | ||
102 | { | ||
103 | struct ad198x_spec *spec = codec->spec; | ||
104 | return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream); | ||
105 | } | ||
106 | |||
107 | static int ad198x_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | ||
108 | struct hda_codec *codec, | ||
109 | unsigned int stream_tag, | ||
110 | unsigned int format, | ||
111 | snd_pcm_substream_t *substream) | ||
112 | { | ||
113 | struct ad198x_spec *spec = codec->spec; | ||
114 | return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, | ||
115 | format, substream); | ||
116 | } | ||
117 | |||
118 | static int ad198x_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, | ||
119 | struct hda_codec *codec, | ||
120 | snd_pcm_substream_t *substream) | ||
121 | { | ||
122 | struct ad198x_spec *spec = codec->spec; | ||
123 | return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); | ||
124 | } | ||
125 | |||
126 | /* | ||
127 | * Digital out | ||
128 | */ | ||
129 | static int ad198x_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, | ||
130 | struct hda_codec *codec, | ||
131 | snd_pcm_substream_t *substream) | ||
132 | { | ||
133 | struct ad198x_spec *spec = codec->spec; | ||
134 | return snd_hda_multi_out_dig_open(codec, &spec->multiout); | ||
135 | } | ||
136 | |||
137 | static int ad198x_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, | ||
138 | struct hda_codec *codec, | ||
139 | snd_pcm_substream_t *substream) | ||
140 | { | ||
141 | struct ad198x_spec *spec = codec->spec; | ||
142 | return snd_hda_multi_out_dig_close(codec, &spec->multiout); | ||
143 | } | ||
144 | |||
145 | /* | ||
146 | * Analog capture | ||
147 | */ | ||
148 | static int ad198x_capture_pcm_prepare(struct hda_pcm_stream *hinfo, | ||
149 | struct hda_codec *codec, | ||
150 | unsigned int stream_tag, | ||
151 | unsigned int format, | ||
152 | snd_pcm_substream_t *substream) | ||
153 | { | ||
154 | struct ad198x_spec *spec = codec->spec; | ||
155 | snd_hda_codec_setup_stream(codec, spec->adc_nid, stream_tag, 0, format); | ||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | static int ad198x_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, | ||
160 | struct hda_codec *codec, | ||
161 | snd_pcm_substream_t *substream) | ||
162 | { | ||
163 | struct ad198x_spec *spec = codec->spec; | ||
164 | snd_hda_codec_setup_stream(codec, spec->adc_nid, 0, 0, 0); | ||
165 | return 0; | ||
166 | } | ||
167 | |||
168 | |||
169 | /* | ||
170 | */ | ||
171 | static struct hda_pcm_stream ad198x_pcm_analog_playback = { | ||
172 | .substreams = 1, | ||
173 | .channels_min = 2, | ||
174 | .channels_max = 6, | ||
175 | .nid = 0, /* fill later */ | ||
176 | .ops = { | ||
177 | .open = ad198x_playback_pcm_open, | ||
178 | .prepare = ad198x_playback_pcm_prepare, | ||
179 | .cleanup = ad198x_playback_pcm_cleanup | ||
180 | }, | ||
181 | }; | ||
182 | |||
183 | static struct hda_pcm_stream ad198x_pcm_analog_capture = { | ||
184 | .substreams = 2, | ||
185 | .channels_min = 2, | ||
186 | .channels_max = 2, | ||
187 | .nid = 0, /* fill later */ | ||
188 | .ops = { | ||
189 | .prepare = ad198x_capture_pcm_prepare, | ||
190 | .cleanup = ad198x_capture_pcm_cleanup | ||
191 | }, | ||
192 | }; | ||
193 | |||
194 | static struct hda_pcm_stream ad198x_pcm_digital_playback = { | ||
195 | .substreams = 1, | ||
196 | .channels_min = 2, | ||
197 | .channels_max = 2, | ||
198 | .nid = 0, /* fill later */ | ||
199 | .ops = { | ||
200 | .open = ad198x_dig_playback_pcm_open, | ||
201 | .close = ad198x_dig_playback_pcm_close | ||
202 | }, | ||
203 | }; | ||
204 | |||
205 | static int ad198x_build_pcms(struct hda_codec *codec) | ||
206 | { | ||
207 | struct ad198x_spec *spec = codec->spec; | ||
208 | struct hda_pcm *info = spec->pcm_rec; | ||
209 | |||
210 | codec->num_pcms = 1; | ||
211 | codec->pcm_info = info; | ||
212 | |||
213 | info->name = "AD198x Analog"; | ||
214 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_analog_playback; | ||
215 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->multiout.max_channels; | ||
216 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; | ||
217 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_analog_capture; | ||
218 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nid; | ||
219 | |||
220 | if (spec->multiout.dig_out_nid) { | ||
221 | info++; | ||
222 | codec->num_pcms++; | ||
223 | info->name = "AD198x Digital"; | ||
224 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_digital_playback; | ||
225 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; | ||
226 | } | ||
227 | |||
228 | return 0; | ||
229 | } | ||
230 | |||
231 | static void ad198x_free(struct hda_codec *codec) | ||
232 | { | ||
233 | kfree(codec->spec); | ||
234 | } | ||
235 | |||
236 | #ifdef CONFIG_PM | ||
237 | static int ad198x_resume(struct hda_codec *codec) | ||
238 | { | ||
239 | struct ad198x_spec *spec = codec->spec; | ||
240 | |||
241 | ad198x_init(codec); | ||
242 | snd_hda_resume_ctls(codec, spec->mixers); | ||
243 | snd_hda_resume_spdif_out(codec); | ||
244 | return 0; | ||
245 | } | ||
246 | #endif | ||
247 | |||
248 | static struct hda_codec_ops ad198x_patch_ops = { | ||
249 | .build_controls = ad198x_build_controls, | ||
250 | .build_pcms = ad198x_build_pcms, | ||
251 | .init = ad198x_init, | ||
252 | .free = ad198x_free, | ||
253 | #ifdef CONFIG_PM | ||
254 | .resume = ad198x_resume, | ||
255 | #endif | ||
256 | }; | ||
257 | |||
258 | |||
259 | /* | ||
260 | * AD1986A specific | ||
261 | */ | ||
262 | |||
37 | #define AD1986A_SPDIF_OUT 0x02 | 263 | #define AD1986A_SPDIF_OUT 0x02 |
38 | #define AD1986A_FRONT_DAC 0x03 | 264 | #define AD1986A_FRONT_DAC 0x03 |
39 | #define AD1986A_SURR_DAC 0x04 | 265 | #define AD1986A_SURR_DAC 0x04 |
@@ -68,7 +294,7 @@ static struct hda_input_mux ad1986a_capture_source = { | |||
68 | static int ad1986a_pcm_amp_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | 294 | static int ad1986a_pcm_amp_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) |
69 | { | 295 | { |
70 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 296 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
71 | struct ad1986a_spec *ad = codec->spec; | 297 | struct ad198x_spec *ad = codec->spec; |
72 | 298 | ||
73 | down(&ad->amp_mutex); | 299 | down(&ad->amp_mutex); |
74 | snd_hda_mixer_amp_volume_get(kcontrol, ucontrol); | 300 | snd_hda_mixer_amp_volume_get(kcontrol, ucontrol); |
@@ -79,7 +305,7 @@ static int ad1986a_pcm_amp_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_ | |||
79 | static int ad1986a_pcm_amp_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | 305 | static int ad1986a_pcm_amp_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) |
80 | { | 306 | { |
81 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 307 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
82 | struct ad1986a_spec *ad = codec->spec; | 308 | struct ad198x_spec *ad = codec->spec; |
83 | int i, change = 0; | 309 | int i, change = 0; |
84 | 310 | ||
85 | down(&ad->amp_mutex); | 311 | down(&ad->amp_mutex); |
@@ -92,12 +318,12 @@ static int ad1986a_pcm_amp_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_ | |||
92 | return change; | 318 | return change; |
93 | } | 319 | } |
94 | 320 | ||
95 | #define ad1986a_pcm_amp_sw_info snd_hda_mixer_amp_volume_info | 321 | #define ad1986a_pcm_amp_sw_info snd_hda_mixer_amp_switch_info |
96 | 322 | ||
97 | static int ad1986a_pcm_amp_sw_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | 323 | static int ad1986a_pcm_amp_sw_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) |
98 | { | 324 | { |
99 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 325 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
100 | struct ad1986a_spec *ad = codec->spec; | 326 | struct ad198x_spec *ad = codec->spec; |
101 | 327 | ||
102 | down(&ad->amp_mutex); | 328 | down(&ad->amp_mutex); |
103 | snd_hda_mixer_amp_switch_get(kcontrol, ucontrol); | 329 | snd_hda_mixer_amp_switch_get(kcontrol, ucontrol); |
@@ -108,7 +334,7 @@ static int ad1986a_pcm_amp_sw_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t | |||
108 | static int ad1986a_pcm_amp_sw_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | 334 | static int ad1986a_pcm_amp_sw_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) |
109 | { | 335 | { |
110 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 336 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
111 | struct ad1986a_spec *ad = codec->spec; | 337 | struct ad198x_spec *ad = codec->spec; |
112 | int i, change = 0; | 338 | int i, change = 0; |
113 | 339 | ||
114 | down(&ad->amp_mutex); | 340 | down(&ad->amp_mutex); |
@@ -122,32 +348,6 @@ static int ad1986a_pcm_amp_sw_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t | |||
122 | } | 348 | } |
123 | 349 | ||
124 | /* | 350 | /* |
125 | * input MUX handling | ||
126 | */ | ||
127 | static int ad1986a_mux_enum_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) | ||
128 | { | ||
129 | return snd_hda_input_mux_info(&ad1986a_capture_source, uinfo); | ||
130 | } | ||
131 | |||
132 | static int ad1986a_mux_enum_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
133 | { | ||
134 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
135 | struct ad1986a_spec *spec = codec->spec; | ||
136 | |||
137 | ucontrol->value.enumerated.item[0] = spec->cur_mux; | ||
138 | return 0; | ||
139 | } | ||
140 | |||
141 | static int ad1986a_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
142 | { | ||
143 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
144 | struct ad1986a_spec *spec = codec->spec; | ||
145 | |||
146 | return snd_hda_input_mux_put(codec, &ad1986a_capture_source, ucontrol, | ||
147 | AD1986A_ADC, &spec->cur_mux); | ||
148 | } | ||
149 | |||
150 | /* | ||
151 | * mixers | 351 | * mixers |
152 | */ | 352 | */ |
153 | static snd_kcontrol_new_t ad1986a_mixers[] = { | 353 | static snd_kcontrol_new_t ad1986a_mixers[] = { |
@@ -194,9 +394,9 @@ static snd_kcontrol_new_t ad1986a_mixers[] = { | |||
194 | { | 394 | { |
195 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 395 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
196 | .name = "Capture Source", | 396 | .name = "Capture Source", |
197 | .info = ad1986a_mux_enum_info, | 397 | .info = ad198x_mux_enum_info, |
198 | .get = ad1986a_mux_enum_get, | 398 | .get = ad198x_mux_enum_get, |
199 | .put = ad1986a_mux_enum_put, | 399 | .put = ad198x_mux_enum_put, |
200 | }, | 400 | }, |
201 | HDA_CODEC_MUTE("Stereo Downmix Switch", 0x09, 0x0, HDA_OUTPUT), | 401 | HDA_CODEC_MUTE("Stereo Downmix Switch", 0x09, 0x0, HDA_OUTPUT), |
202 | { } /* end */ | 402 | { } /* end */ |
@@ -241,183 +441,328 @@ static struct hda_verb ad1986a_init_verbs[] = { | |||
241 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | 441 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, |
242 | {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | 442 | {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, |
243 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | 443 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, |
444 | /* HP Pin */ | ||
445 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | ||
446 | /* Front, Surround, CLFE Pins */ | ||
447 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
448 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
449 | {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
450 | /* Mono Pin */ | ||
451 | {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
452 | /* Mic Pin */ | ||
453 | {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | ||
454 | /* Line, Aux, CD, Beep-In Pin */ | ||
455 | {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
456 | {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
457 | {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
458 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
459 | {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
244 | { } /* end */ | 460 | { } /* end */ |
245 | }; | 461 | }; |
246 | 462 | ||
247 | 463 | ||
248 | static int ad1986a_init(struct hda_codec *codec) | 464 | static int patch_ad1986a(struct hda_codec *codec) |
249 | { | 465 | { |
250 | snd_hda_sequence_write(codec, ad1986a_init_verbs); | 466 | struct ad198x_spec *spec; |
251 | return 0; | ||
252 | } | ||
253 | 467 | ||
254 | static int ad1986a_build_controls(struct hda_codec *codec) | 468 | spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); |
255 | { | 469 | if (spec == NULL) |
256 | int err; | 470 | return -ENOMEM; |
471 | |||
472 | init_MUTEX(&spec->amp_mutex); | ||
473 | codec->spec = spec; | ||
474 | |||
475 | spec->multiout.max_channels = 6; | ||
476 | spec->multiout.num_dacs = ARRAY_SIZE(ad1986a_dac_nids); | ||
477 | spec->multiout.dac_nids = ad1986a_dac_nids; | ||
478 | spec->multiout.dig_out_nid = AD1986A_SPDIF_OUT; | ||
479 | spec->adc_nid = AD1986A_ADC; | ||
480 | spec->input_mux = &ad1986a_capture_source; | ||
481 | spec->mixers = ad1986a_mixers; | ||
482 | spec->init_verbs = ad1986a_init_verbs; | ||
483 | |||
484 | codec->patch_ops = ad198x_patch_ops; | ||
257 | 485 | ||
258 | err = snd_hda_add_new_ctls(codec, ad1986a_mixers); | ||
259 | if (err < 0) | ||
260 | return err; | ||
261 | err = snd_hda_create_spdif_out_ctls(codec, AD1986A_SPDIF_OUT); | ||
262 | if (err < 0) | ||
263 | return err; | ||
264 | return 0; | 486 | return 0; |
265 | } | 487 | } |
266 | 488 | ||
267 | /* | 489 | /* |
268 | * Analog playback callbacks | 490 | * AD1983 specific |
269 | */ | 491 | */ |
270 | static int ad1986a_playback_pcm_open(struct hda_pcm_stream *hinfo, | ||
271 | struct hda_codec *codec, | ||
272 | snd_pcm_substream_t *substream) | ||
273 | { | ||
274 | struct ad1986a_spec *spec = codec->spec; | ||
275 | return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream); | ||
276 | } | ||
277 | 492 | ||
278 | static int ad1986a_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | 493 | #define AD1983_SPDIF_OUT 0x02 |
279 | struct hda_codec *codec, | 494 | #define AD1983_DAC 0x03 |
280 | unsigned int stream_tag, | 495 | #define AD1983_ADC 0x04 |
281 | unsigned int format, | ||
282 | snd_pcm_substream_t *substream) | ||
283 | { | ||
284 | struct ad1986a_spec *spec = codec->spec; | ||
285 | return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, | ||
286 | format, substream); | ||
287 | } | ||
288 | 496 | ||
289 | static int ad1986a_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, | 497 | static hda_nid_t ad1983_dac_nids[1] = { AD1983_DAC }; |
290 | struct hda_codec *codec, | 498 | |
291 | snd_pcm_substream_t *substream) | 499 | static struct hda_input_mux ad1983_capture_source = { |
292 | { | 500 | .num_items = 4, |
293 | struct ad1986a_spec *spec = codec->spec; | 501 | .items = { |
294 | return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); | 502 | { "Mic", 0x0 }, |
295 | } | 503 | { "Line", 0x1 }, |
504 | { "Mix", 0x2 }, | ||
505 | { "Mix Mono", 0x3 }, | ||
506 | }, | ||
507 | }; | ||
296 | 508 | ||
297 | /* | 509 | /* |
298 | * Digital out | 510 | * SPDIF playback route |
299 | */ | 511 | */ |
300 | static int ad1986a_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, | 512 | static int ad1983_spdif_route_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) |
301 | struct hda_codec *codec, | ||
302 | snd_pcm_substream_t *substream) | ||
303 | { | 513 | { |
304 | struct ad1986a_spec *spec = codec->spec; | 514 | static char *texts[] = { "PCM", "ADC" }; |
305 | return snd_hda_multi_out_dig_open(codec, &spec->multiout); | 515 | |
516 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
517 | uinfo->count = 1; | ||
518 | uinfo->value.enumerated.items = 2; | ||
519 | if (uinfo->value.enumerated.item > 1) | ||
520 | uinfo->value.enumerated.item = 1; | ||
521 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
522 | return 0; | ||
306 | } | 523 | } |
307 | 524 | ||
308 | static int ad1986a_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, | 525 | static int ad1983_spdif_route_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) |
309 | struct hda_codec *codec, | ||
310 | snd_pcm_substream_t *substream) | ||
311 | { | 526 | { |
312 | struct ad1986a_spec *spec = codec->spec; | 527 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
313 | return snd_hda_multi_out_dig_close(codec, &spec->multiout); | 528 | struct ad198x_spec *spec = codec->spec; |
314 | } | ||
315 | 529 | ||
316 | /* | 530 | ucontrol->value.enumerated.item[0] = spec->spdif_route; |
317 | * Analog capture | ||
318 | */ | ||
319 | static int ad1986a_capture_pcm_prepare(struct hda_pcm_stream *hinfo, | ||
320 | struct hda_codec *codec, | ||
321 | unsigned int stream_tag, | ||
322 | unsigned int format, | ||
323 | snd_pcm_substream_t *substream) | ||
324 | { | ||
325 | snd_hda_codec_setup_stream(codec, AD1986A_ADC, stream_tag, 0, format); | ||
326 | return 0; | 531 | return 0; |
327 | } | 532 | } |
328 | 533 | ||
329 | static int ad1986a_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, | 534 | static int ad1983_spdif_route_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) |
330 | struct hda_codec *codec, | ||
331 | snd_pcm_substream_t *substream) | ||
332 | { | 535 | { |
333 | snd_hda_codec_setup_stream(codec, AD1986A_ADC, 0, 0, 0); | 536 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
537 | struct ad198x_spec *spec = codec->spec; | ||
538 | |||
539 | if (spec->spdif_route != ucontrol->value.enumerated.item[0]) { | ||
540 | spec->spdif_route = ucontrol->value.enumerated.item[0]; | ||
541 | snd_hda_codec_write(codec, spec->multiout.dig_out_nid, 0, | ||
542 | AC_VERB_SET_CONNECT_SEL, spec->spdif_route); | ||
543 | return 1; | ||
544 | } | ||
334 | return 0; | 545 | return 0; |
335 | } | 546 | } |
336 | 547 | ||
337 | 548 | static snd_kcontrol_new_t ad1983_mixers[] = { | |
338 | /* | 549 | HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT), |
339 | */ | 550 | HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT), |
340 | static struct hda_pcm_stream ad1986a_pcm_analog_playback = { | 551 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT), |
341 | .substreams = 1, | 552 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT), |
342 | .channels_min = 2, | 553 | HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT), |
343 | .channels_max = 6, | 554 | HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT), |
344 | .nid = AD1986A_FRONT_DAC, /* NID to query formats and rates */ | 555 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT), |
345 | .ops = { | 556 | HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT), |
346 | .open = ad1986a_playback_pcm_open, | 557 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT), |
347 | .prepare = ad1986a_playback_pcm_prepare, | 558 | HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT), |
348 | .cleanup = ad1986a_playback_pcm_cleanup | 559 | HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT), |
560 | HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT), | ||
561 | HDA_CODEC_VOLUME_MONO("PC Speaker Playback Volume", 0x10, 1, 0x0, HDA_OUTPUT), | ||
562 | HDA_CODEC_MUTE_MONO("PC Speaker Playback Switch", 0x10, 1, 0x0, HDA_OUTPUT), | ||
563 | HDA_CODEC_VOLUME("Mic Boost", 0x0c, 0x0, HDA_OUTPUT), | ||
564 | HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), | ||
565 | HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT), | ||
566 | { | ||
567 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
568 | .name = "Capture Source", | ||
569 | .info = ad198x_mux_enum_info, | ||
570 | .get = ad198x_mux_enum_get, | ||
571 | .put = ad198x_mux_enum_put, | ||
349 | }, | 572 | }, |
350 | }; | 573 | { |
351 | 574 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
352 | static struct hda_pcm_stream ad1986a_pcm_analog_capture = { | 575 | .name = "IEC958 Playback Route", |
353 | .substreams = 2, | 576 | .info = ad1983_spdif_route_info, |
354 | .channels_min = 2, | 577 | .get = ad1983_spdif_route_get, |
355 | .channels_max = 2, | 578 | .put = ad1983_spdif_route_put, |
356 | .nid = AD1986A_ADC, /* NID to query formats and rates */ | ||
357 | .ops = { | ||
358 | .prepare = ad1986a_capture_pcm_prepare, | ||
359 | .cleanup = ad1986a_capture_pcm_cleanup | ||
360 | }, | 579 | }, |
580 | { } /* end */ | ||
361 | }; | 581 | }; |
362 | 582 | ||
363 | static struct hda_pcm_stream ad1986a_pcm_digital_playback = { | 583 | static struct hda_verb ad1983_init_verbs[] = { |
364 | .substreams = 1, | 584 | /* Front, HP, Mono; mute as default */ |
365 | .channels_min = 2, | 585 | {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, |
366 | .channels_max = 2, | 586 | {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, |
367 | .nid = AD1986A_SPDIF_OUT, | 587 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, |
368 | .ops = { | 588 | /* Beep, PCM, Mic, Line-In: mute */ |
369 | .open = ad1986a_dig_playback_pcm_open, | 589 | {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, |
370 | .close = ad1986a_dig_playback_pcm_close | 590 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, |
371 | }, | 591 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, |
592 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
593 | /* Front, HP selectors; from Mix */ | ||
594 | {0x05, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
595 | {0x06, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
596 | /* Mono selector; from Mix */ | ||
597 | {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03}, | ||
598 | /* Mic selector; Mic */ | ||
599 | {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
600 | /* Line-in selector: Line-in */ | ||
601 | {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
602 | /* Mic boost: 0dB */ | ||
603 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
604 | /* Record selector: mic */ | ||
605 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
606 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
607 | /* SPDIF route: PCM */ | ||
608 | {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
609 | /* Front Pin */ | ||
610 | {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
611 | /* HP Pin */ | ||
612 | {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | ||
613 | /* Mono Pin */ | ||
614 | {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
615 | /* Mic Pin */ | ||
616 | {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | ||
617 | /* Line Pin */ | ||
618 | {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
619 | { } /* end */ | ||
372 | }; | 620 | }; |
373 | 621 | ||
374 | static int ad1986a_build_pcms(struct hda_codec *codec) | 622 | static int patch_ad1983(struct hda_codec *codec) |
375 | { | 623 | { |
376 | struct ad1986a_spec *spec = codec->spec; | 624 | struct ad198x_spec *spec; |
377 | struct hda_pcm *info = spec->pcm_rec; | ||
378 | 625 | ||
379 | codec->num_pcms = 2; | 626 | spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); |
380 | codec->pcm_info = info; | 627 | if (spec == NULL) |
628 | return -ENOMEM; | ||
381 | 629 | ||
382 | info->name = "AD1986A Analog"; | 630 | init_MUTEX(&spec->amp_mutex); |
383 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad1986a_pcm_analog_playback; | 631 | codec->spec = spec; |
384 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad1986a_pcm_analog_capture; | 632 | |
385 | info++; | 633 | spec->multiout.max_channels = 2; |
634 | spec->multiout.num_dacs = ARRAY_SIZE(ad1983_dac_nids); | ||
635 | spec->multiout.dac_nids = ad1983_dac_nids; | ||
636 | spec->multiout.dig_out_nid = AD1983_SPDIF_OUT; | ||
637 | spec->adc_nid = AD1983_ADC; | ||
638 | spec->input_mux = &ad1983_capture_source; | ||
639 | spec->mixers = ad1983_mixers; | ||
640 | spec->init_verbs = ad1983_init_verbs; | ||
641 | spec->spdif_route = 0; | ||
386 | 642 | ||
387 | info->name = "AD1986A Digital"; | 643 | codec->patch_ops = ad198x_patch_ops; |
388 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad1986a_pcm_digital_playback; | ||
389 | 644 | ||
390 | return 0; | 645 | return 0; |
391 | } | 646 | } |
392 | 647 | ||
393 | static void ad1986a_free(struct hda_codec *codec) | ||
394 | { | ||
395 | kfree(codec->spec); | ||
396 | } | ||
397 | 648 | ||
398 | #ifdef CONFIG_PM | 649 | /* |
399 | static int ad1986a_resume(struct hda_codec *codec) | 650 | * AD1981 HD specific |
400 | { | 651 | */ |
401 | ad1986a_init(codec); | ||
402 | snd_hda_resume_ctls(codec, ad1986a_mixers); | ||
403 | snd_hda_resume_spdif_out(codec); | ||
404 | return 0; | ||
405 | } | ||
406 | #endif | ||
407 | 652 | ||
408 | static struct hda_codec_ops ad1986a_patch_ops = { | 653 | #define AD1981_SPDIF_OUT 0x02 |
409 | .build_controls = ad1986a_build_controls, | 654 | #define AD1981_DAC 0x03 |
410 | .build_pcms = ad1986a_build_pcms, | 655 | #define AD1981_ADC 0x04 |
411 | .init = ad1986a_init, | 656 | |
412 | .free = ad1986a_free, | 657 | static hda_nid_t ad1981_dac_nids[1] = { AD1981_DAC }; |
413 | #ifdef CONFIG_PM | 658 | |
414 | .resume = ad1986a_resume, | 659 | /* 0x0c, 0x09, 0x0e, 0x0f, 0x19, 0x05, 0x18, 0x17 */ |
415 | #endif | 660 | static struct hda_input_mux ad1981_capture_source = { |
661 | .num_items = 7, | ||
662 | .items = { | ||
663 | { "Front Mic", 0x0 }, | ||
664 | { "Line", 0x1 }, | ||
665 | { "Mix", 0x2 }, | ||
666 | { "Mix Mono", 0x3 }, | ||
667 | { "CD", 0x4 }, | ||
668 | { "Mic", 0x6 }, | ||
669 | { "Aux", 0x7 }, | ||
670 | }, | ||
416 | }; | 671 | }; |
417 | 672 | ||
418 | static int patch_ad1986a(struct hda_codec *codec) | 673 | static snd_kcontrol_new_t ad1981_mixers[] = { |
674 | HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT), | ||
675 | HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT), | ||
676 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT), | ||
677 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT), | ||
678 | HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT), | ||
679 | HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT), | ||
680 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT), | ||
681 | HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT), | ||
682 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT), | ||
683 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
684 | HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT), | ||
685 | HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT), | ||
686 | HDA_CODEC_VOLUME("Aux Playback Volume", 0x1b, 0x0, HDA_OUTPUT), | ||
687 | HDA_CODEC_MUTE("Aux Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | ||
688 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT), | ||
689 | HDA_CODEC_MUTE("Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT), | ||
690 | HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT), | ||
691 | HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT), | ||
692 | HDA_CODEC_VOLUME_MONO("PC Speaker Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT), | ||
693 | HDA_CODEC_MUTE_MONO("PC Speaker Playback Switch", 0x0d, 1, 0x0, HDA_OUTPUT), | ||
694 | HDA_CODEC_VOLUME("Front Mic Boost", 0x08, 0x0, HDA_INPUT), | ||
695 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x0, HDA_INPUT), | ||
696 | HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), | ||
697 | HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT), | ||
698 | { | ||
699 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
700 | .name = "Capture Source", | ||
701 | .info = ad198x_mux_enum_info, | ||
702 | .get = ad198x_mux_enum_get, | ||
703 | .put = ad198x_mux_enum_put, | ||
704 | }, | ||
705 | /* identical with AD1983 */ | ||
706 | { | ||
707 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
708 | .name = "IEC958 Playback Route", | ||
709 | .info = ad1983_spdif_route_info, | ||
710 | .get = ad1983_spdif_route_get, | ||
711 | .put = ad1983_spdif_route_put, | ||
712 | }, | ||
713 | { } /* end */ | ||
714 | }; | ||
715 | |||
716 | static struct hda_verb ad1981_init_verbs[] = { | ||
717 | /* Front, HP, Mono; mute as default */ | ||
718 | {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
719 | {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
720 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
721 | /* Beep, PCM, Front Mic, Line, Rear Mic, Aux, CD-In: mute */ | ||
722 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
723 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
724 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
725 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
726 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
727 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
728 | {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
729 | /* Front, HP selectors; from Mix */ | ||
730 | {0x05, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
731 | {0x06, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
732 | /* Mono selector; from Mix */ | ||
733 | {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03}, | ||
734 | /* Mic Mixer; select Front Mic */ | ||
735 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
736 | {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
737 | /* Mic boost: 0dB */ | ||
738 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
739 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
740 | /* Record selector: Front mic */ | ||
741 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
742 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
743 | /* SPDIF route: PCM */ | ||
744 | {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
745 | /* Front Pin */ | ||
746 | {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
747 | /* HP Pin */ | ||
748 | {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | ||
749 | /* Mono Pin */ | ||
750 | {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
751 | /* Front & Rear Mic Pins */ | ||
752 | {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | ||
753 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | ||
754 | /* Line Pin */ | ||
755 | {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
756 | /* Digital Beep */ | ||
757 | {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
758 | /* Line-Out as Input: disabled */ | ||
759 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
760 | { } /* end */ | ||
761 | }; | ||
762 | |||
763 | static int patch_ad1981(struct hda_codec *codec) | ||
419 | { | 764 | { |
420 | struct ad1986a_spec *spec; | 765 | struct ad198x_spec *spec; |
421 | 766 | ||
422 | spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); | 767 | spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); |
423 | if (spec == NULL) | 768 | if (spec == NULL) |
@@ -426,20 +771,28 @@ static int patch_ad1986a(struct hda_codec *codec) | |||
426 | init_MUTEX(&spec->amp_mutex); | 771 | init_MUTEX(&spec->amp_mutex); |
427 | codec->spec = spec; | 772 | codec->spec = spec; |
428 | 773 | ||
429 | spec->multiout.max_channels = 6; | 774 | spec->multiout.max_channels = 2; |
430 | spec->multiout.num_dacs = ARRAY_SIZE(ad1986a_dac_nids); | 775 | spec->multiout.num_dacs = ARRAY_SIZE(ad1981_dac_nids); |
431 | spec->multiout.dac_nids = ad1986a_dac_nids; | 776 | spec->multiout.dac_nids = ad1981_dac_nids; |
432 | spec->multiout.dig_out_nid = AD1986A_SPDIF_OUT; | 777 | spec->multiout.dig_out_nid = AD1981_SPDIF_OUT; |
778 | spec->adc_nid = AD1981_ADC; | ||
779 | spec->input_mux = &ad1981_capture_source; | ||
780 | spec->mixers = ad1981_mixers; | ||
781 | spec->init_verbs = ad1981_init_verbs; | ||
782 | spec->spdif_route = 0; | ||
433 | 783 | ||
434 | codec->patch_ops = ad1986a_patch_ops; | 784 | codec->patch_ops = ad198x_patch_ops; |
435 | 785 | ||
436 | return 0; | 786 | return 0; |
437 | } | 787 | } |
438 | 788 | ||
789 | |||
439 | /* | 790 | /* |
440 | * patch entries | 791 | * patch entries |
441 | */ | 792 | */ |
442 | struct hda_codec_preset snd_hda_preset_analog[] = { | 793 | struct hda_codec_preset snd_hda_preset_analog[] = { |
794 | { .id = 0x11d41981, .name = "AD1981", .patch = patch_ad1981 }, | ||
795 | { .id = 0x11d41983, .name = "AD1983", .patch = patch_ad1983 }, | ||
443 | { .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a }, | 796 | { .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a }, |
444 | {} /* terminator */ | 797 | {} /* terminator */ |
445 | }; | 798 | }; |
diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index b7cc8e4bffb7..2d6e3e3d0a38 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <sound/core.h> | 29 | #include <sound/core.h> |
30 | #include "hda_codec.h" | 30 | #include "hda_codec.h" |
31 | #include "hda_local.h" | 31 | #include "hda_local.h" |
32 | #define NUM_PINS 11 | ||
32 | 33 | ||
33 | 34 | ||
34 | /* board config type */ | 35 | /* board config type */ |
@@ -38,6 +39,7 @@ enum { | |||
38 | CMI_FULL, /* back 6-jack + front-panel 2-jack */ | 39 | CMI_FULL, /* back 6-jack + front-panel 2-jack */ |
39 | CMI_FULL_DIG, /* back 6-jack + front-panel 2-jack + digital I/O */ | 40 | CMI_FULL_DIG, /* back 6-jack + front-panel 2-jack + digital I/O */ |
40 | CMI_ALLOUT, /* back 5-jack + front-panel 2-jack + digital out */ | 41 | CMI_ALLOUT, /* back 5-jack + front-panel 2-jack + digital out */ |
42 | CMI_AUTO, /* let driver guess it */ | ||
41 | }; | 43 | }; |
42 | 44 | ||
43 | struct cmi_spec { | 45 | struct cmi_spec { |
@@ -48,6 +50,8 @@ struct cmi_spec { | |||
48 | 50 | ||
49 | /* playback */ | 51 | /* playback */ |
50 | struct hda_multi_out multiout; | 52 | struct hda_multi_out multiout; |
53 | hda_nid_t dac_nids[4]; /* NID for each DAC */ | ||
54 | int num_dacs; | ||
51 | 55 | ||
52 | /* capture */ | 56 | /* capture */ |
53 | hda_nid_t *adc_nids; | 57 | hda_nid_t *adc_nids; |
@@ -63,8 +67,30 @@ struct cmi_spec { | |||
63 | const struct cmi_channel_mode *channel_modes; | 67 | const struct cmi_channel_mode *channel_modes; |
64 | 68 | ||
65 | struct hda_pcm pcm_rec[2]; /* PCM information */ | 69 | struct hda_pcm pcm_rec[2]; /* PCM information */ |
70 | |||
71 | /* pin deafault configuration */ | ||
72 | hda_nid_t pin_nid[NUM_PINS]; | ||
73 | unsigned int def_conf[NUM_PINS]; | ||
74 | unsigned int pin_def_confs; | ||
75 | |||
76 | /* multichannel pins */ | ||
77 | hda_nid_t multich_pin[4]; /* max 8-channel */ | ||
78 | struct hda_verb multi_init[9]; /* 2 verbs for each pin + terminator */ | ||
66 | }; | 79 | }; |
67 | 80 | ||
81 | /* amp values */ | ||
82 | #define AMP_IN_MUTE(idx) (0x7080 | ((idx)<<8)) | ||
83 | #define AMP_IN_UNMUTE(idx) (0x7000 | ((idx)<<8)) | ||
84 | #define AMP_OUT_MUTE 0xb080 | ||
85 | #define AMP_OUT_UNMUTE 0xb000 | ||
86 | #define AMP_OUT_ZERO 0xb000 | ||
87 | /* pinctl values */ | ||
88 | #define PIN_IN 0x20 | ||
89 | #define PIN_VREF80 0x24 | ||
90 | #define PIN_VREF50 0x21 | ||
91 | #define PIN_OUT 0x40 | ||
92 | #define PIN_HP 0xc0 | ||
93 | |||
68 | /* | 94 | /* |
69 | * input MUX | 95 | * input MUX |
70 | */ | 96 | */ |
@@ -102,9 +128,9 @@ static int cmi_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucon | |||
102 | /* 3-stack / 2 channel */ | 128 | /* 3-stack / 2 channel */ |
103 | static struct hda_verb cmi9880_ch2_init[] = { | 129 | static struct hda_verb cmi9880_ch2_init[] = { |
104 | /* set line-in PIN for input */ | 130 | /* set line-in PIN for input */ |
105 | { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | 131 | { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, |
106 | /* set mic PIN for input, also enable vref */ | 132 | /* set mic PIN for input, also enable vref */ |
107 | { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | 133 | { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, |
108 | /* route front PCM (DAC1) to HP */ | 134 | /* route front PCM (DAC1) to HP */ |
109 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, | 135 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, |
110 | {} | 136 | {} |
@@ -113,9 +139,9 @@ static struct hda_verb cmi9880_ch2_init[] = { | |||
113 | /* 3-stack / 6 channel */ | 139 | /* 3-stack / 6 channel */ |
114 | static struct hda_verb cmi9880_ch6_init[] = { | 140 | static struct hda_verb cmi9880_ch6_init[] = { |
115 | /* set line-in PIN for output */ | 141 | /* set line-in PIN for output */ |
116 | { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | 142 | { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, |
117 | /* set mic PIN for output */ | 143 | /* set mic PIN for output */ |
118 | { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | 144 | { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, |
119 | /* route front PCM (DAC1) to HP */ | 145 | /* route front PCM (DAC1) to HP */ |
120 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, | 146 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, |
121 | {} | 147 | {} |
@@ -124,9 +150,9 @@ static struct hda_verb cmi9880_ch6_init[] = { | |||
124 | /* 3-stack+front / 8 channel */ | 150 | /* 3-stack+front / 8 channel */ |
125 | static struct hda_verb cmi9880_ch8_init[] = { | 151 | static struct hda_verb cmi9880_ch8_init[] = { |
126 | /* set line-in PIN for output */ | 152 | /* set line-in PIN for output */ |
127 | { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | 153 | { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, |
128 | /* set mic PIN for output */ | 154 | /* set mic PIN for output */ |
129 | { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | 155 | { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, |
130 | /* route rear-surround PCM (DAC4) to HP */ | 156 | /* route rear-surround PCM (DAC4) to HP */ |
131 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x03 }, | 157 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x03 }, |
132 | {} | 158 | {} |
@@ -269,25 +295,27 @@ static hda_nid_t cmi9880_adc_nids[2] = { | |||
269 | */ | 295 | */ |
270 | static struct hda_verb cmi9880_basic_init[] = { | 296 | static struct hda_verb cmi9880_basic_init[] = { |
271 | /* port-D for line out (rear panel) */ | 297 | /* port-D for line out (rear panel) */ |
272 | { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | 298 | { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, |
273 | /* port-E for HP out (front panel) */ | 299 | /* port-E for HP out (front panel) */ |
274 | { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | 300 | { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, |
275 | /* route front PCM to HP */ | 301 | /* route front PCM to HP */ |
276 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, | 302 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, |
277 | /* port-A for surround (rear panel) */ | 303 | /* port-A for surround (rear panel) */ |
278 | { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | 304 | { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, |
279 | /* port-G for CLFE (rear panel) */ | 305 | /* port-G for CLFE (rear panel) */ |
280 | { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | 306 | { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, |
307 | { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x02 }, | ||
281 | /* port-H for side (rear panel) */ | 308 | /* port-H for side (rear panel) */ |
282 | { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | 309 | { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, |
310 | { 0x20, AC_VERB_SET_CONNECT_SEL, 0x01 }, | ||
283 | /* port-C for line-in (rear panel) */ | 311 | /* port-C for line-in (rear panel) */ |
284 | { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | 312 | { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, |
285 | /* port-B for mic-in (rear panel) with vref */ | 313 | /* port-B for mic-in (rear panel) with vref */ |
286 | { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | 314 | { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, |
287 | /* port-F for mic-in (front panel) with vref */ | 315 | /* port-F for mic-in (front panel) with vref */ |
288 | { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | 316 | { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, |
289 | /* CD-in */ | 317 | /* CD-in */ |
290 | { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | 318 | { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, |
291 | /* route front mic to ADC1/2 */ | 319 | /* route front mic to ADC1/2 */ |
292 | { 0x08, AC_VERB_SET_CONNECT_SEL, 0x05 }, | 320 | { 0x08, AC_VERB_SET_CONNECT_SEL, 0x05 }, |
293 | { 0x09, AC_VERB_SET_CONNECT_SEL, 0x05 }, | 321 | { 0x09, AC_VERB_SET_CONNECT_SEL, 0x05 }, |
@@ -296,23 +324,27 @@ static struct hda_verb cmi9880_basic_init[] = { | |||
296 | 324 | ||
297 | static struct hda_verb cmi9880_allout_init[] = { | 325 | static struct hda_verb cmi9880_allout_init[] = { |
298 | /* port-D for line out (rear panel) */ | 326 | /* port-D for line out (rear panel) */ |
299 | { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | 327 | { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, |
300 | /* port-E for HP out (front panel) */ | 328 | /* port-E for HP out (front panel) */ |
301 | { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | 329 | { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, |
302 | /* route front PCM to HP */ | 330 | /* route front PCM to HP */ |
303 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, | 331 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, |
304 | /* port-A for side (rear panel) */ | 332 | /* port-A for side (rear panel) */ |
305 | { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | 333 | { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, |
306 | /* port-G for CLFE (rear panel) */ | 334 | /* port-G for CLFE (rear panel) */ |
307 | { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | 335 | { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, |
336 | { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x02 }, | ||
337 | /* port-H for side (rear panel) */ | ||
338 | { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, | ||
339 | { 0x20, AC_VERB_SET_CONNECT_SEL, 0x01 }, | ||
308 | /* port-C for surround (rear panel) */ | 340 | /* port-C for surround (rear panel) */ |
309 | { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | 341 | { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, |
310 | /* port-B for mic-in (rear panel) with vref */ | 342 | /* port-B for mic-in (rear panel) with vref */ |
311 | { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | 343 | { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, |
312 | /* port-F for mic-in (front panel) with vref */ | 344 | /* port-F for mic-in (front panel) with vref */ |
313 | { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | 345 | { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, |
314 | /* CD-in */ | 346 | /* CD-in */ |
315 | { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | 347 | { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, |
316 | /* route front mic to ADC1/2 */ | 348 | /* route front mic to ADC1/2 */ |
317 | { 0x08, AC_VERB_SET_CONNECT_SEL, 0x05 }, | 349 | { 0x08, AC_VERB_SET_CONNECT_SEL, 0x05 }, |
318 | { 0x09, AC_VERB_SET_CONNECT_SEL, 0x05 }, | 350 | { 0x09, AC_VERB_SET_CONNECT_SEL, 0x05 }, |
@@ -347,6 +379,81 @@ static int cmi9880_build_controls(struct hda_codec *codec) | |||
347 | return 0; | 379 | return 0; |
348 | } | 380 | } |
349 | 381 | ||
382 | /* fill in the multi_dac_nids table, which will decide | ||
383 | which audio widget to use for each channel */ | ||
384 | static int cmi9880_fill_multi_dac_nids(struct hda_codec *codec, const struct auto_pin_cfg *cfg) | ||
385 | { | ||
386 | struct cmi_spec *spec = codec->spec; | ||
387 | hda_nid_t nid; | ||
388 | int assigned[4]; | ||
389 | int i, j; | ||
390 | |||
391 | /* clear the table, only one c-media dac assumed here */ | ||
392 | memset(spec->dac_nids, 0, sizeof(spec->dac_nids)); | ||
393 | memset(assigned, 0, sizeof(assigned)); | ||
394 | /* check the pins we found */ | ||
395 | for (i = 0; i < cfg->line_outs; i++) { | ||
396 | nid = cfg->line_out_pins[i]; | ||
397 | /* nid 0x0b~0x0e is hardwired to audio widget 0x3~0x6 */ | ||
398 | if (nid >= 0x0b && nid <= 0x0e) { | ||
399 | spec->dac_nids[i] = (nid - 0x0b) + 0x03; | ||
400 | assigned[nid - 0x0b] = 1; | ||
401 | } | ||
402 | } | ||
403 | /* left pin can be connect to any audio widget */ | ||
404 | for (i = 0; i < cfg->line_outs; i++) { | ||
405 | nid = cfg->line_out_pins[i]; | ||
406 | if (nid <= 0x0e) | ||
407 | continue; | ||
408 | /* search for an empty channel */ | ||
409 | for (j = 0; j < cfg->line_outs; j++) { | ||
410 | if (! assigned[j]) { | ||
411 | spec->dac_nids[i] = i + 0x03; | ||
412 | assigned[j] = 1; | ||
413 | break; | ||
414 | } | ||
415 | } | ||
416 | } | ||
417 | spec->num_dacs = cfg->line_outs; | ||
418 | return 0; | ||
419 | } | ||
420 | |||
421 | /* create multi_init table, which is used for multichannel initialization */ | ||
422 | static int cmi9880_fill_multi_init(struct hda_codec *codec, const struct auto_pin_cfg *cfg) | ||
423 | { | ||
424 | struct cmi_spec *spec = codec->spec; | ||
425 | hda_nid_t nid; | ||
426 | int i, j, k, len; | ||
427 | |||
428 | /* clear the table, only one c-media dac assumed here */ | ||
429 | memset(spec->multi_init, 0, sizeof(spec->multi_init)); | ||
430 | for (j = 0, i = 0; i < cfg->line_outs; i++) { | ||
431 | hda_nid_t conn[4]; | ||
432 | nid = cfg->line_out_pins[i]; | ||
433 | /* set as output */ | ||
434 | spec->multi_init[j].nid = nid; | ||
435 | spec->multi_init[j].verb = AC_VERB_SET_PIN_WIDGET_CONTROL; | ||
436 | spec->multi_init[j].param = PIN_OUT; | ||
437 | j++; | ||
438 | if (nid > 0x0e) { | ||
439 | /* set connection */ | ||
440 | spec->multi_init[j].nid = nid; | ||
441 | spec->multi_init[j].verb = AC_VERB_SET_CONNECT_SEL; | ||
442 | spec->multi_init[j].param = 0; | ||
443 | /* find the index in connect list */ | ||
444 | len = snd_hda_get_connections(codec, nid, conn, 4); | ||
445 | for (k = 0; k < len; k++) | ||
446 | if (conn[k] == spec->dac_nids[i]) { | ||
447 | spec->multi_init[j].param = j; | ||
448 | break; | ||
449 | } | ||
450 | j++; | ||
451 | break; | ||
452 | } | ||
453 | } | ||
454 | return 0; | ||
455 | } | ||
456 | |||
350 | static int cmi9880_init(struct hda_codec *codec) | 457 | static int cmi9880_init(struct hda_codec *codec) |
351 | { | 458 | { |
352 | struct cmi_spec *spec = codec->spec; | 459 | struct cmi_spec *spec = codec->spec; |
@@ -354,6 +461,8 @@ static int cmi9880_init(struct hda_codec *codec) | |||
354 | snd_hda_sequence_write(codec, cmi9880_allout_init); | 461 | snd_hda_sequence_write(codec, cmi9880_allout_init); |
355 | else | 462 | else |
356 | snd_hda_sequence_write(codec, cmi9880_basic_init); | 463 | snd_hda_sequence_write(codec, cmi9880_basic_init); |
464 | if (spec->board_config == CMI_AUTO) | ||
465 | snd_hda_sequence_write(codec, spec->multi_init); | ||
357 | return 0; | 466 | return 0; |
358 | } | 467 | } |
359 | 468 | ||
@@ -540,6 +649,7 @@ static struct hda_board_config cmi9880_cfg_tbl[] = { | |||
540 | { .modelname = "full", .config = CMI_FULL }, | 649 | { .modelname = "full", .config = CMI_FULL }, |
541 | { .modelname = "full_dig", .config = CMI_FULL_DIG }, | 650 | { .modelname = "full_dig", .config = CMI_FULL_DIG }, |
542 | { .modelname = "allout", .config = CMI_ALLOUT }, | 651 | { .modelname = "allout", .config = CMI_ALLOUT }, |
652 | { .modelname = "auto", .config = CMI_AUTO }, | ||
543 | {} /* terminator */ | 653 | {} /* terminator */ |
544 | }; | 654 | }; |
545 | 655 | ||
@@ -564,10 +674,14 @@ static int patch_cmi9880(struct hda_codec *codec) | |||
564 | codec->spec = spec; | 674 | codec->spec = spec; |
565 | spec->board_config = snd_hda_check_board_config(codec, cmi9880_cfg_tbl); | 675 | spec->board_config = snd_hda_check_board_config(codec, cmi9880_cfg_tbl); |
566 | if (spec->board_config < 0) { | 676 | if (spec->board_config < 0) { |
567 | snd_printd(KERN_INFO "hda_codec: Unknown model for CMI9880\n"); | 677 | snd_printdd(KERN_INFO "hda_codec: Unknown model for CMI9880\n"); |
568 | spec->board_config = CMI_FULL_DIG; /* try everything */ | 678 | spec->board_config = CMI_AUTO; /* try everything */ |
569 | } | 679 | } |
570 | 680 | ||
681 | /* copy default DAC NIDs */ | ||
682 | memcpy(spec->dac_nids, cmi9880_dac_nids, sizeof(spec->dac_nids)); | ||
683 | spec->num_dacs = 4; | ||
684 | |||
571 | switch (spec->board_config) { | 685 | switch (spec->board_config) { |
572 | case CMI_MINIMAL: | 686 | case CMI_MINIMAL: |
573 | case CMI_MIN_FP: | 687 | case CMI_MIN_FP: |
@@ -599,10 +713,58 @@ static int patch_cmi9880(struct hda_codec *codec) | |||
599 | spec->input_mux = &cmi9880_no_line_mux; | 713 | spec->input_mux = &cmi9880_no_line_mux; |
600 | spec->multiout.dig_out_nid = CMI_DIG_OUT_NID; | 714 | spec->multiout.dig_out_nid = CMI_DIG_OUT_NID; |
601 | break; | 715 | break; |
716 | case CMI_AUTO: | ||
717 | { | ||
718 | unsigned int port_e, port_f, port_g, port_h; | ||
719 | unsigned int port_spdifi, port_spdifo; | ||
720 | struct auto_pin_cfg cfg; | ||
721 | |||
722 | /* collect pin default configuration */ | ||
723 | port_e = snd_hda_codec_read(codec, 0x0f, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); | ||
724 | port_f = snd_hda_codec_read(codec, 0x10, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); | ||
725 | spec->front_panel = 1; | ||
726 | if (get_defcfg_connect(port_e) == AC_JACK_PORT_NONE || | ||
727 | get_defcfg_connect(port_f) == AC_JACK_PORT_NONE) { | ||
728 | port_g = snd_hda_codec_read(codec, 0x1f, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); | ||
729 | port_h = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); | ||
730 | spec->surr_switch = 1; | ||
731 | /* no front panel */ | ||
732 | if (get_defcfg_connect(port_g) == AC_JACK_PORT_NONE || | ||
733 | get_defcfg_connect(port_h) == AC_JACK_PORT_NONE) { | ||
734 | /* no optional rear panel */ | ||
735 | spec->board_config = CMI_MINIMAL; | ||
736 | spec->front_panel = 0; | ||
737 | spec->num_ch_modes = 2; | ||
738 | } else { | ||
739 | spec->board_config = CMI_MIN_FP; | ||
740 | spec->num_ch_modes = 3; | ||
741 | } | ||
742 | spec->channel_modes = cmi9880_channel_modes; | ||
743 | spec->input_mux = &cmi9880_basic_mux; | ||
744 | spec->multiout.max_channels = cmi9880_channel_modes[0].channels; | ||
745 | } else { | ||
746 | spec->input_mux = &cmi9880_basic_mux; | ||
747 | port_spdifi = snd_hda_codec_read(codec, 0x13, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); | ||
748 | port_spdifo = snd_hda_codec_read(codec, 0x12, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); | ||
749 | if (get_defcfg_connect(port_spdifo) != AC_JACK_PORT_NONE) | ||
750 | spec->multiout.dig_out_nid = CMI_DIG_OUT_NID; | ||
751 | if (get_defcfg_connect(port_spdifi) != AC_JACK_PORT_NONE) | ||
752 | spec->dig_in_nid = CMI_DIG_IN_NID; | ||
753 | spec->multiout.max_channels = 8; | ||
754 | } | ||
755 | snd_hda_parse_pin_def_config(codec, &cfg); | ||
756 | if (cfg.line_outs) { | ||
757 | spec->multiout.max_channels = cfg.line_outs * 2; | ||
758 | cmi9880_fill_multi_dac_nids(codec, &cfg); | ||
759 | cmi9880_fill_multi_init(codec, &cfg); | ||
760 | } else | ||
761 | snd_printd("patch_cmedia: cannot detect association in defcfg\n"); | ||
762 | break; | ||
763 | } | ||
602 | } | 764 | } |
603 | 765 | ||
604 | spec->multiout.num_dacs = 4; | 766 | spec->multiout.num_dacs = spec->num_dacs; |
605 | spec->multiout.dac_nids = cmi9880_dac_nids; | 767 | spec->multiout.dac_nids = spec->dac_nids; |
606 | 768 | ||
607 | spec->adc_nids = cmi9880_adc_nids; | 769 | spec->adc_nids = cmi9880_adc_nids; |
608 | 770 | ||
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 17c5062423ae..9edd558d6bd3 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -33,38 +33,73 @@ | |||
33 | 33 | ||
34 | /* ALC880 board config type */ | 34 | /* ALC880 board config type */ |
35 | enum { | 35 | enum { |
36 | ALC880_MINIMAL, | ||
37 | ALC880_3ST, | 36 | ALC880_3ST, |
38 | ALC880_3ST_DIG, | 37 | ALC880_3ST_DIG, |
39 | ALC880_5ST, | 38 | ALC880_5ST, |
40 | ALC880_5ST_DIG, | 39 | ALC880_5ST_DIG, |
41 | ALC880_W810, | 40 | ALC880_W810, |
41 | ALC880_Z71V, | ||
42 | ALC880_AUTO, | ||
43 | ALC880_6ST_DIG, | ||
44 | ALC880_F1734, | ||
45 | ALC880_ASUS, | ||
46 | ALC880_ASUS_DIG, | ||
47 | ALC880_ASUS_W1V, | ||
48 | ALC880_UNIWILL_DIG, | ||
49 | #ifdef CONFIG_SND_DEBUG | ||
50 | ALC880_TEST, | ||
51 | #endif | ||
52 | ALC880_MODEL_LAST /* last tag */ | ||
53 | }; | ||
54 | |||
55 | /* ALC260 models */ | ||
56 | enum { | ||
57 | ALC260_BASIC, | ||
58 | ALC260_HP, | ||
59 | ALC260_MODEL_LAST /* last tag */ | ||
42 | }; | 60 | }; |
43 | 61 | ||
62 | /* amp values */ | ||
63 | #define AMP_IN_MUTE(idx) (0x7080 | ((idx)<<8)) | ||
64 | #define AMP_IN_UNMUTE(idx) (0x7000 | ((idx)<<8)) | ||
65 | #define AMP_OUT_MUTE 0xb080 | ||
66 | #define AMP_OUT_UNMUTE 0xb000 | ||
67 | #define AMP_OUT_ZERO 0xb000 | ||
68 | /* pinctl values */ | ||
69 | #define PIN_IN 0x20 | ||
70 | #define PIN_VREF80 0x24 | ||
71 | #define PIN_VREF50 0x21 | ||
72 | #define PIN_OUT 0x40 | ||
73 | #define PIN_HP 0xc0 | ||
74 | |||
44 | struct alc_spec { | 75 | struct alc_spec { |
45 | /* codec parameterization */ | 76 | /* codec parameterization */ |
46 | unsigned int front_panel: 1; | 77 | snd_kcontrol_new_t *mixers[3]; /* mixer arrays */ |
47 | |||
48 | snd_kcontrol_new_t* mixers[2]; | ||
49 | unsigned int num_mixers; | 78 | unsigned int num_mixers; |
50 | 79 | ||
51 | struct hda_verb *init_verbs; | 80 | const struct hda_verb *init_verbs[3]; /* initialization verbs |
81 | * don't forget NULL termination! | ||
82 | */ | ||
83 | unsigned int num_init_verbs; | ||
52 | 84 | ||
53 | char* stream_name_analog; | 85 | char *stream_name_analog; /* analog PCM stream */ |
54 | struct hda_pcm_stream *stream_analog_playback; | 86 | struct hda_pcm_stream *stream_analog_playback; |
55 | struct hda_pcm_stream *stream_analog_capture; | 87 | struct hda_pcm_stream *stream_analog_capture; |
56 | 88 | ||
57 | char* stream_name_digital; | 89 | char *stream_name_digital; /* digital PCM stream */ |
58 | struct hda_pcm_stream *stream_digital_playback; | 90 | struct hda_pcm_stream *stream_digital_playback; |
59 | struct hda_pcm_stream *stream_digital_capture; | 91 | struct hda_pcm_stream *stream_digital_capture; |
60 | 92 | ||
61 | /* playback */ | 93 | /* playback */ |
62 | struct hda_multi_out multiout; | 94 | struct hda_multi_out multiout; /* playback set-up |
95 | * max_channels, dacs must be set | ||
96 | * dig_out_nid and hp_nid are optional | ||
97 | */ | ||
63 | 98 | ||
64 | /* capture */ | 99 | /* capture */ |
65 | unsigned int num_adc_nids; | 100 | unsigned int num_adc_nids; |
66 | hda_nid_t *adc_nids; | 101 | hda_nid_t *adc_nids; |
67 | hda_nid_t dig_in_nid; | 102 | hda_nid_t dig_in_nid; /* digital-in NID; optional */ |
68 | 103 | ||
69 | /* capture source */ | 104 | /* capture source */ |
70 | const struct hda_input_mux *input_mux; | 105 | const struct hda_input_mux *input_mux; |
@@ -75,61 +110,17 @@ struct alc_spec { | |||
75 | int num_channel_mode; | 110 | int num_channel_mode; |
76 | 111 | ||
77 | /* PCM information */ | 112 | /* PCM information */ |
78 | struct hda_pcm pcm_rec[2]; | 113 | struct hda_pcm pcm_rec[2]; /* used in alc_build_pcms() */ |
79 | }; | ||
80 | |||
81 | /* DAC/ADC assignment */ | ||
82 | |||
83 | static hda_nid_t alc880_dac_nids[4] = { | ||
84 | /* front, rear, clfe, rear_surr */ | ||
85 | 0x02, 0x05, 0x04, 0x03 | ||
86 | }; | ||
87 | |||
88 | static hda_nid_t alc880_w810_dac_nids[3] = { | ||
89 | /* front, rear/surround, clfe */ | ||
90 | 0x02, 0x03, 0x04 | ||
91 | }; | ||
92 | |||
93 | static hda_nid_t alc880_adc_nids[3] = { | ||
94 | /* ADC0-2 */ | ||
95 | 0x07, 0x08, 0x09, | ||
96 | }; | ||
97 | |||
98 | #define ALC880_DIGOUT_NID 0x06 | ||
99 | #define ALC880_DIGIN_NID 0x0a | ||
100 | 114 | ||
101 | static hda_nid_t alc260_dac_nids[1] = { | 115 | struct semaphore bind_mutex; /* for bound controls */ |
102 | /* front */ | ||
103 | 0x02, | ||
104 | }; | ||
105 | 116 | ||
106 | static hda_nid_t alc260_adc_nids[2] = { | 117 | /* dynamic controls, init_verbs and input_mux */ |
107 | /* ADC0-1 */ | 118 | struct auto_pin_cfg autocfg; |
108 | 0x04, 0x05, | 119 | unsigned int num_kctl_alloc, num_kctl_used; |
120 | snd_kcontrol_new_t *kctl_alloc; | ||
121 | struct hda_input_mux private_imux; | ||
109 | }; | 122 | }; |
110 | 123 | ||
111 | #define ALC260_DIGOUT_NID 0x03 | ||
112 | #define ALC260_DIGIN_NID 0x06 | ||
113 | |||
114 | static struct hda_input_mux alc880_capture_source = { | ||
115 | .num_items = 4, | ||
116 | .items = { | ||
117 | { "Mic", 0x0 }, | ||
118 | { "Front Mic", 0x3 }, | ||
119 | { "Line", 0x2 }, | ||
120 | { "CD", 0x4 }, | ||
121 | }, | ||
122 | }; | ||
123 | |||
124 | static struct hda_input_mux alc260_capture_source = { | ||
125 | .num_items = 4, | ||
126 | .items = { | ||
127 | { "Mic", 0x0 }, | ||
128 | { "Front Mic", 0x1 }, | ||
129 | { "Line", 0x2 }, | ||
130 | { "CD", 0x4 }, | ||
131 | }, | ||
132 | }; | ||
133 | 124 | ||
134 | /* | 125 | /* |
135 | * input MUX handling | 126 | * input MUX handling |
@@ -160,6 +151,7 @@ static int alc_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucon | |||
160 | spec->adc_nids[adc_idx], &spec->cur_mux[adc_idx]); | 151 | spec->adc_nids[adc_idx], &spec->cur_mux[adc_idx]); |
161 | } | 152 | } |
162 | 153 | ||
154 | |||
163 | /* | 155 | /* |
164 | * channel mode setting | 156 | * channel mode setting |
165 | */ | 157 | */ |
@@ -168,135 +160,18 @@ struct alc_channel_mode { | |||
168 | const struct hda_verb *sequence; | 160 | const struct hda_verb *sequence; |
169 | }; | 161 | }; |
170 | 162 | ||
171 | |||
172 | /* | ||
173 | * channel source setting (2/6 channel selection for 3-stack) | ||
174 | */ | ||
175 | |||
176 | /* | ||
177 | * set the path ways for 2 channel output | ||
178 | * need to set the codec line out and mic 1 pin widgets to inputs | ||
179 | */ | ||
180 | static struct hda_verb alc880_threestack_ch2_init[] = { | ||
181 | /* set pin widget 1Ah (line in) for input */ | ||
182 | { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
183 | /* set pin widget 18h (mic1) for input, for mic also enable the vref */ | ||
184 | { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | ||
185 | /* mute the output for Line In PW */ | ||
186 | { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 }, | ||
187 | /* mute for Mic1 PW */ | ||
188 | { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 }, | ||
189 | { } /* end */ | ||
190 | }; | ||
191 | |||
192 | /* | ||
193 | * 6ch mode | ||
194 | * need to set the codec line out and mic 1 pin widgets to outputs | ||
195 | */ | ||
196 | static struct hda_verb alc880_threestack_ch6_init[] = { | ||
197 | /* set pin widget 1Ah (line in) for output */ | ||
198 | { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
199 | /* set pin widget 18h (mic1) for output */ | ||
200 | { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
201 | /* unmute the output for Line In PW */ | ||
202 | { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000 }, | ||
203 | /* unmute for Mic1 PW */ | ||
204 | { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000 }, | ||
205 | /* for rear channel output using Line In 1 | ||
206 | * set select widget connection (nid = 0x12) - to summer node | ||
207 | * for rear NID = 0x0f...offset 3 in connection list | ||
208 | */ | ||
209 | { 0x12, AC_VERB_SET_CONNECT_SEL, 0x3 }, | ||
210 | /* for Mic1 - retask for center/lfe */ | ||
211 | /* set select widget connection (nid = 0x10) - to summer node for | ||
212 | * front CLFE NID = 0x0e...offset 2 in connection list | ||
213 | */ | ||
214 | { 0x10, AC_VERB_SET_CONNECT_SEL, 0x2 }, | ||
215 | { } /* end */ | ||
216 | }; | ||
217 | |||
218 | static struct alc_channel_mode alc880_threestack_modes[2] = { | ||
219 | { 2, alc880_threestack_ch2_init }, | ||
220 | { 6, alc880_threestack_ch6_init }, | ||
221 | }; | ||
222 | |||
223 | |||
224 | /* | ||
225 | * channel source setting (6/8 channel selection for 5-stack) | ||
226 | */ | ||
227 | |||
228 | /* set the path ways for 6 channel output | ||
229 | * need to set the codec line out and mic 1 pin widgets to inputs | ||
230 | */ | ||
231 | static struct hda_verb alc880_fivestack_ch6_init[] = { | ||
232 | /* set pin widget 1Ah (line in) for input */ | ||
233 | { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
234 | /* mute the output for Line In PW */ | ||
235 | { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 }, | ||
236 | { } /* end */ | ||
237 | }; | ||
238 | |||
239 | /* need to set the codec line out and mic 1 pin widgets to outputs */ | ||
240 | static struct hda_verb alc880_fivestack_ch8_init[] = { | ||
241 | /* set pin widget 1Ah (line in) for output */ | ||
242 | { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
243 | /* unmute the output for Line In PW */ | ||
244 | { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000 }, | ||
245 | /* output for surround channel output using Line In 1 */ | ||
246 | /* set select widget connection (nid = 0x12) - to summer node | ||
247 | * for surr_rear NID = 0x0d...offset 1 in connection list | ||
248 | */ | ||
249 | { 0x12, AC_VERB_SET_CONNECT_SEL, 0x1 }, | ||
250 | { } /* end */ | ||
251 | }; | ||
252 | |||
253 | static struct alc_channel_mode alc880_fivestack_modes[2] = { | ||
254 | { 6, alc880_fivestack_ch6_init }, | ||
255 | { 8, alc880_fivestack_ch8_init }, | ||
256 | }; | ||
257 | |||
258 | /* | ||
259 | * channel source setting for W810 system | ||
260 | * | ||
261 | * W810 has rear IO for: | ||
262 | * Front (DAC 02) | ||
263 | * Surround (DAC 03) | ||
264 | * Center/LFE (DAC 04) | ||
265 | * Digital out (06) | ||
266 | * | ||
267 | * The system also has a pair of internal speakers, and a headphone jack. | ||
268 | * These are both connected to Line2 on the codec, hence to DAC 02. | ||
269 | * | ||
270 | * There is a variable resistor to control the speaker or headphone | ||
271 | * volume. This is a hardware-only device without a software API. | ||
272 | * | ||
273 | * Plugging headphones in will disable the internal speakers. This is | ||
274 | * implemented in hardware, not via the driver using jack sense. In | ||
275 | * a similar fashion, plugging into the rear socket marked "front" will | ||
276 | * disable both the speakers and headphones. | ||
277 | * | ||
278 | * For input, there's a microphone jack, and an "audio in" jack. | ||
279 | * These may not do anything useful with this driver yet, because I | ||
280 | * haven't setup any initialization verbs for these yet... | ||
281 | */ | ||
282 | |||
283 | static struct alc_channel_mode alc880_w810_modes[1] = { | ||
284 | { 6, NULL } | ||
285 | }; | ||
286 | |||
287 | /* | ||
288 | */ | ||
289 | static int alc880_ch_mode_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) | 163 | static int alc880_ch_mode_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) |
290 | { | 164 | { |
291 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 165 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
292 | struct alc_spec *spec = codec->spec; | 166 | struct alc_spec *spec = codec->spec; |
167 | int items = kcontrol->private_value ? (int)kcontrol->private_value : 2; | ||
293 | 168 | ||
294 | snd_assert(spec->channel_mode, return -ENXIO); | 169 | snd_assert(spec->channel_mode, return -ENXIO); |
295 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 170 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; |
296 | uinfo->count = 1; | 171 | uinfo->count = 1; |
297 | uinfo->value.enumerated.items = 2; | 172 | uinfo->value.enumerated.items = items; |
298 | if (uinfo->value.enumerated.item >= 2) | 173 | if (uinfo->value.enumerated.item >= items) |
299 | uinfo->value.enumerated.item = 1; | 174 | uinfo->value.enumerated.item = items - 1; |
300 | sprintf(uinfo->value.enumerated.name, "%dch", | 175 | sprintf(uinfo->value.enumerated.name, "%dch", |
301 | spec->channel_mode[uinfo->value.enumerated.item].channels); | 176 | spec->channel_mode[uinfo->value.enumerated.item].channels); |
302 | return 0; | 177 | return 0; |
@@ -306,10 +181,16 @@ static int alc880_ch_mode_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *uc | |||
306 | { | 181 | { |
307 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 182 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
308 | struct alc_spec *spec = codec->spec; | 183 | struct alc_spec *spec = codec->spec; |
184 | int items = kcontrol->private_value ? (int)kcontrol->private_value : 2; | ||
185 | int i; | ||
309 | 186 | ||
310 | snd_assert(spec->channel_mode, return -ENXIO); | 187 | snd_assert(spec->channel_mode, return -ENXIO); |
311 | ucontrol->value.enumerated.item[0] = | 188 | for (i = 0; i < items; i++) { |
312 | (spec->multiout.max_channels == spec->channel_mode[0].channels) ? 0 : 1; | 189 | if (spec->multiout.max_channels == spec->channel_mode[i].channels) { |
190 | ucontrol->value.enumerated.item[0] = i; | ||
191 | break; | ||
192 | } | ||
193 | } | ||
313 | return 0; | 194 | return 0; |
314 | } | 195 | } |
315 | 196 | ||
@@ -335,21 +216,149 @@ static int alc880_ch_mode_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *uc | |||
335 | 216 | ||
336 | 217 | ||
337 | /* | 218 | /* |
219 | * bound volume controls | ||
220 | * | ||
221 | * bind multiple volumes (# indices, from 0) | ||
222 | */ | ||
223 | |||
224 | #define AMP_VAL_IDX_SHIFT 19 | ||
225 | #define AMP_VAL_IDX_MASK (0x0f<<19) | ||
226 | |||
227 | static int alc_bind_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) | ||
228 | { | ||
229 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
230 | struct alc_spec *spec = codec->spec; | ||
231 | unsigned long pval; | ||
232 | |||
233 | down(&spec->bind_mutex); | ||
234 | pval = kcontrol->private_value; | ||
235 | kcontrol->private_value = pval & ~AMP_VAL_IDX_MASK; /* index 0 */ | ||
236 | snd_hda_mixer_amp_switch_info(kcontrol, uinfo); | ||
237 | kcontrol->private_value = pval; | ||
238 | up(&spec->bind_mutex); | ||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | static int alc_bind_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
243 | { | ||
244 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
245 | struct alc_spec *spec = codec->spec; | ||
246 | unsigned long pval; | ||
247 | |||
248 | down(&spec->bind_mutex); | ||
249 | pval = kcontrol->private_value; | ||
250 | kcontrol->private_value = pval & ~AMP_VAL_IDX_MASK; /* index 0 */ | ||
251 | snd_hda_mixer_amp_switch_get(kcontrol, ucontrol); | ||
252 | kcontrol->private_value = pval; | ||
253 | up(&spec->bind_mutex); | ||
254 | return 0; | ||
255 | } | ||
256 | |||
257 | static int alc_bind_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
258 | { | ||
259 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
260 | struct alc_spec *spec = codec->spec; | ||
261 | unsigned long pval; | ||
262 | int i, indices, change = 0; | ||
263 | |||
264 | down(&spec->bind_mutex); | ||
265 | pval = kcontrol->private_value; | ||
266 | indices = (pval & AMP_VAL_IDX_MASK) >> AMP_VAL_IDX_SHIFT; | ||
267 | for (i = 0; i < indices; i++) { | ||
268 | kcontrol->private_value = (pval & ~AMP_VAL_IDX_MASK) | (i << AMP_VAL_IDX_SHIFT); | ||
269 | change |= snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); | ||
270 | } | ||
271 | kcontrol->private_value = pval; | ||
272 | up(&spec->bind_mutex); | ||
273 | return change; | ||
274 | } | ||
275 | |||
276 | #define ALC_BIND_MUTE_MONO(xname, nid, channel, indices, direction) \ | ||
277 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ | ||
278 | .info = alc_bind_switch_info, \ | ||
279 | .get = alc_bind_switch_get, \ | ||
280 | .put = alc_bind_switch_put, \ | ||
281 | .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, indices, direction) } | ||
282 | |||
283 | #define ALC_BIND_MUTE(xname,nid,indices,dir) ALC_BIND_MUTE_MONO(xname,nid,3,indices,dir) | ||
284 | |||
285 | |||
286 | /* | ||
287 | * ALC880 3-stack model | ||
288 | * | ||
289 | * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e) | ||
290 | * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18, F-Mic = 0x1b | ||
291 | * HP = 0x19 | ||
338 | */ | 292 | */ |
339 | 293 | ||
340 | /* 3-stack mode | 294 | static hda_nid_t alc880_dac_nids[4] = { |
341 | * Pin assignment: Front=0x14, Line-In/Rear=0x1a, Mic/CLFE=0x18, F-Mic=0x1b | 295 | /* front, rear, clfe, rear_surr */ |
342 | * HP=0x19 | 296 | 0x02, 0x05, 0x04, 0x03 |
297 | }; | ||
298 | |||
299 | static hda_nid_t alc880_adc_nids[3] = { | ||
300 | /* ADC0-2 */ | ||
301 | 0x07, 0x08, 0x09, | ||
302 | }; | ||
303 | |||
304 | /* The datasheet says the node 0x07 is connected from inputs, | ||
305 | * but it shows zero connection in the real implementation on some devices. | ||
343 | */ | 306 | */ |
344 | static snd_kcontrol_new_t alc880_base_mixer[] = { | 307 | static hda_nid_t alc880_adc_nids_alt[2] = { |
308 | /* ADC1-2 */ | ||
309 | 0x08, 0x09, | ||
310 | }; | ||
311 | |||
312 | #define ALC880_DIGOUT_NID 0x06 | ||
313 | #define ALC880_DIGIN_NID 0x0a | ||
314 | |||
315 | static struct hda_input_mux alc880_capture_source = { | ||
316 | .num_items = 4, | ||
317 | .items = { | ||
318 | { "Mic", 0x0 }, | ||
319 | { "Front Mic", 0x3 }, | ||
320 | { "Line", 0x2 }, | ||
321 | { "CD", 0x4 }, | ||
322 | }, | ||
323 | }; | ||
324 | |||
325 | /* channel source setting (2/6 channel selection for 3-stack) */ | ||
326 | /* 2ch mode */ | ||
327 | static struct hda_verb alc880_threestack_ch2_init[] = { | ||
328 | /* set line-in to input, mute it */ | ||
329 | { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, | ||
330 | { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, | ||
331 | /* set mic-in to input vref 80%, mute it */ | ||
332 | { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, | ||
333 | { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, | ||
334 | { } /* end */ | ||
335 | }; | ||
336 | |||
337 | /* 6ch mode */ | ||
338 | static struct hda_verb alc880_threestack_ch6_init[] = { | ||
339 | /* set line-in to output, unmute it */ | ||
340 | { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
341 | { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, | ||
342 | /* set mic-in to output, unmute it */ | ||
343 | { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
344 | { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, | ||
345 | { } /* end */ | ||
346 | }; | ||
347 | |||
348 | static struct alc_channel_mode alc880_threestack_modes[2] = { | ||
349 | { 2, alc880_threestack_ch2_init }, | ||
350 | { 6, alc880_threestack_ch6_init }, | ||
351 | }; | ||
352 | |||
353 | static snd_kcontrol_new_t alc880_three_stack_mixer[] = { | ||
345 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | 354 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), |
346 | HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), | 355 | ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), |
347 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT), | 356 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT), |
348 | HDA_CODEC_MUTE("Surround Playback Switch", 0x1a, 0x0, HDA_OUTPUT), | 357 | ALC_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT), |
349 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), | 358 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), |
350 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), | 359 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), |
351 | HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x18, 1, 0x0, HDA_OUTPUT), | 360 | ALC_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), |
352 | HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x18, 2, 0x0, HDA_OUTPUT), | 361 | ALC_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), |
353 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), | 362 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), |
354 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), | 363 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), |
355 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), | 364 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), |
@@ -360,12 +369,25 @@ static snd_kcontrol_new_t alc880_base_mixer[] = { | |||
360 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT), | 369 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT), |
361 | HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), | 370 | HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), |
362 | HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), | 371 | HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), |
363 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), | ||
364 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT), | 372 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT), |
373 | { | ||
374 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
375 | .name = "Channel Mode", | ||
376 | .info = alc880_ch_mode_info, | ||
377 | .get = alc880_ch_mode_get, | ||
378 | .put = alc880_ch_mode_put, | ||
379 | }, | ||
380 | { } /* end */ | ||
381 | }; | ||
382 | |||
383 | /* capture mixer elements */ | ||
384 | static snd_kcontrol_new_t alc880_capture_mixer[] = { | ||
365 | HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), | 385 | HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), |
366 | HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), | 386 | HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), |
367 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), | 387 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), |
368 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), | 388 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), |
389 | HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT), | ||
390 | HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT), | ||
369 | { | 391 | { |
370 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 392 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
371 | /* The multiple "Capture Source" controls confuse alsamixer | 393 | /* The multiple "Capture Source" controls confuse alsamixer |
@@ -374,65 +396,125 @@ static snd_kcontrol_new_t alc880_base_mixer[] = { | |||
374 | */ | 396 | */ |
375 | /* .name = "Capture Source", */ | 397 | /* .name = "Capture Source", */ |
376 | .name = "Input Source", | 398 | .name = "Input Source", |
377 | .count = 2, | 399 | .count = 3, |
378 | .info = alc_mux_enum_info, | 400 | .info = alc_mux_enum_info, |
379 | .get = alc_mux_enum_get, | 401 | .get = alc_mux_enum_get, |
380 | .put = alc_mux_enum_put, | 402 | .put = alc_mux_enum_put, |
381 | }, | 403 | }, |
404 | { } /* end */ | ||
405 | }; | ||
406 | |||
407 | /* capture mixer elements (in case NID 0x07 not available) */ | ||
408 | static snd_kcontrol_new_t alc880_capture_alt_mixer[] = { | ||
409 | HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), | ||
410 | HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), | ||
411 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), | ||
412 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), | ||
382 | { | 413 | { |
383 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 414 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
384 | .name = "Channel Mode", | 415 | /* The multiple "Capture Source" controls confuse alsamixer |
385 | .info = alc880_ch_mode_info, | 416 | * So call somewhat different.. |
386 | .get = alc880_ch_mode_get, | 417 | * FIXME: the controls appear in the "playback" view! |
387 | .put = alc880_ch_mode_put, | 418 | */ |
419 | /* .name = "Capture Source", */ | ||
420 | .name = "Input Source", | ||
421 | .count = 2, | ||
422 | .info = alc_mux_enum_info, | ||
423 | .get = alc_mux_enum_get, | ||
424 | .put = alc_mux_enum_put, | ||
388 | }, | 425 | }, |
389 | { } /* end */ | 426 | { } /* end */ |
390 | }; | 427 | }; |
391 | 428 | ||
392 | /* 5-stack mode | 429 | |
393 | * Pin assignment: Front=0x14, Rear=0x17, CLFE=0x16 | 430 | |
394 | * Line-In/Side=0x1a, Mic=0x18, F-Mic=0x1b, HP=0x19 | 431 | /* |
432 | * ALC880 5-stack model | ||
433 | * | ||
434 | * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d), Side = 0x02 (0xd) | ||
435 | * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16 | ||
436 | * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19 | ||
395 | */ | 437 | */ |
438 | |||
439 | /* additional mixers to alc880_three_stack_mixer */ | ||
396 | static snd_kcontrol_new_t alc880_five_stack_mixer[] = { | 440 | static snd_kcontrol_new_t alc880_five_stack_mixer[] = { |
441 | HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT), | ||
442 | ALC_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT), | ||
443 | { } /* end */ | ||
444 | }; | ||
445 | |||
446 | /* channel source setting (6/8 channel selection for 5-stack) */ | ||
447 | /* 6ch mode */ | ||
448 | static struct hda_verb alc880_fivestack_ch6_init[] = { | ||
449 | /* set line-in to input, mute it */ | ||
450 | { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, | ||
451 | { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, | ||
452 | { } /* end */ | ||
453 | }; | ||
454 | |||
455 | /* 8ch mode */ | ||
456 | static struct hda_verb alc880_fivestack_ch8_init[] = { | ||
457 | /* set line-in to output, unmute it */ | ||
458 | { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
459 | { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, | ||
460 | { } /* end */ | ||
461 | }; | ||
462 | |||
463 | static struct alc_channel_mode alc880_fivestack_modes[2] = { | ||
464 | { 6, alc880_fivestack_ch6_init }, | ||
465 | { 8, alc880_fivestack_ch8_init }, | ||
466 | }; | ||
467 | |||
468 | |||
469 | /* | ||
470 | * ALC880 6-stack model | ||
471 | * | ||
472 | * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e), Side = 0x05 (0x0f) | ||
473 | * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17, | ||
474 | * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b | ||
475 | */ | ||
476 | |||
477 | static hda_nid_t alc880_6st_dac_nids[4] = { | ||
478 | /* front, rear, clfe, rear_surr */ | ||
479 | 0x02, 0x03, 0x04, 0x05 | ||
480 | }; | ||
481 | |||
482 | static struct hda_input_mux alc880_6stack_capture_source = { | ||
483 | .num_items = 4, | ||
484 | .items = { | ||
485 | { "Mic", 0x0 }, | ||
486 | { "Front Mic", 0x1 }, | ||
487 | { "Line", 0x2 }, | ||
488 | { "CD", 0x4 }, | ||
489 | }, | ||
490 | }; | ||
491 | |||
492 | /* fixed 8-channels */ | ||
493 | static struct alc_channel_mode alc880_sixstack_modes[1] = { | ||
494 | { 8, NULL }, | ||
495 | }; | ||
496 | |||
497 | static snd_kcontrol_new_t alc880_six_stack_mixer[] = { | ||
397 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | 498 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), |
398 | HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), | 499 | ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), |
399 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT), | 500 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), |
400 | HDA_CODEC_MUTE("Surround Playback Switch", 0x17, 0x0, HDA_OUTPUT), | 501 | ALC_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), |
401 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), | 502 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), |
402 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), | 503 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), |
403 | HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x16, 1, 0x0, HDA_OUTPUT), | 504 | ALC_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), |
404 | HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), | 505 | ALC_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), |
405 | HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT), | 506 | HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), |
406 | HDA_CODEC_MUTE("Side Playback Switch", 0x1a, 0x0, HDA_OUTPUT), | 507 | ALC_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), |
407 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), | 508 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), |
408 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), | 509 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), |
409 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), | 510 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), |
410 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), | 511 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), |
411 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | 512 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), |
412 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | 513 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), |
413 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT), | 514 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), |
414 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT), | 515 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), |
415 | HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), | 516 | HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), |
416 | HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), | 517 | HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), |
417 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), | ||
418 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT), | ||
419 | HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), | ||
420 | HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), | ||
421 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), | ||
422 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), | ||
423 | { | ||
424 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
425 | /* The multiple "Capture Source" controls confuse alsamixer | ||
426 | * So call somewhat different.. | ||
427 | * FIXME: the controls appear in the "playback" view! | ||
428 | */ | ||
429 | /* .name = "Capture Source", */ | ||
430 | .name = "Input Source", | ||
431 | .count = 2, | ||
432 | .info = alc_mux_enum_info, | ||
433 | .get = alc_mux_enum_get, | ||
434 | .put = alc_mux_enum_put, | ||
435 | }, | ||
436 | { | 518 | { |
437 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 519 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
438 | .name = "Channel Mode", | 520 | .name = "Channel Mode", |
@@ -443,39 +525,169 @@ static snd_kcontrol_new_t alc880_five_stack_mixer[] = { | |||
443 | { } /* end */ | 525 | { } /* end */ |
444 | }; | 526 | }; |
445 | 527 | ||
528 | |||
529 | /* | ||
530 | * ALC880 W810 model | ||
531 | * | ||
532 | * W810 has rear IO for: | ||
533 | * Front (DAC 02) | ||
534 | * Surround (DAC 03) | ||
535 | * Center/LFE (DAC 04) | ||
536 | * Digital out (06) | ||
537 | * | ||
538 | * The system also has a pair of internal speakers, and a headphone jack. | ||
539 | * These are both connected to Line2 on the codec, hence to DAC 02. | ||
540 | * | ||
541 | * There is a variable resistor to control the speaker or headphone | ||
542 | * volume. This is a hardware-only device without a software API. | ||
543 | * | ||
544 | * Plugging headphones in will disable the internal speakers. This is | ||
545 | * implemented in hardware, not via the driver using jack sense. In | ||
546 | * a similar fashion, plugging into the rear socket marked "front" will | ||
547 | * disable both the speakers and headphones. | ||
548 | * | ||
549 | * For input, there's a microphone jack, and an "audio in" jack. | ||
550 | * These may not do anything useful with this driver yet, because I | ||
551 | * haven't setup any initialization verbs for these yet... | ||
552 | */ | ||
553 | |||
554 | static hda_nid_t alc880_w810_dac_nids[3] = { | ||
555 | /* front, rear/surround, clfe */ | ||
556 | 0x02, 0x03, 0x04 | ||
557 | }; | ||
558 | |||
559 | /* fixed 6 channels */ | ||
560 | static struct alc_channel_mode alc880_w810_modes[1] = { | ||
561 | { 6, NULL } | ||
562 | }; | ||
563 | |||
564 | /* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */ | ||
446 | static snd_kcontrol_new_t alc880_w810_base_mixer[] = { | 565 | static snd_kcontrol_new_t alc880_w810_base_mixer[] = { |
447 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | 566 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), |
448 | HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), | 567 | ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), |
449 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), | 568 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), |
450 | HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT), | 569 | ALC_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), |
451 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), | 570 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), |
452 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), | 571 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), |
453 | HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x16, 1, 0x0, HDA_OUTPUT), | 572 | ALC_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), |
454 | HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), | 573 | ALC_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), |
455 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | 574 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), |
456 | HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), | 575 | { } /* end */ |
457 | HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), | 576 | }; |
458 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), | 577 | |
459 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), | 578 | |
460 | HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT), | 579 | /* |
461 | HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT), | 580 | * Z710V model |
581 | * | ||
582 | * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d) | ||
583 | * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?), Line = 0x1a | ||
584 | */ | ||
585 | |||
586 | static hda_nid_t alc880_z71v_dac_nids[1] = { | ||
587 | 0x02 | ||
588 | }; | ||
589 | #define ALC880_Z71V_HP_DAC 0x03 | ||
590 | |||
591 | /* fixed 2 channels */ | ||
592 | static struct alc_channel_mode alc880_2_jack_modes[1] = { | ||
593 | { 2, NULL } | ||
594 | }; | ||
595 | |||
596 | static snd_kcontrol_new_t alc880_z71v_mixer[] = { | ||
597 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
598 | ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), | ||
599 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), | ||
600 | ALC_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT), | ||
601 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), | ||
602 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), | ||
603 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | ||
604 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | ||
605 | { } /* end */ | ||
606 | }; | ||
607 | |||
608 | |||
609 | /* FIXME! */ | ||
610 | /* | ||
611 | * ALC880 F1734 model | ||
612 | * | ||
613 | * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d) | ||
614 | * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18 | ||
615 | */ | ||
616 | |||
617 | static hda_nid_t alc880_f1734_dac_nids[1] = { | ||
618 | 0x03 | ||
619 | }; | ||
620 | #define ALC880_F1734_HP_DAC 0x02 | ||
621 | |||
622 | static snd_kcontrol_new_t alc880_f1734_mixer[] = { | ||
623 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
624 | ALC_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), | ||
625 | HDA_CODEC_VOLUME("Internal Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), | ||
626 | ALC_BIND_MUTE("Internal Speaker Playback Switch", 0x0d, 2, HDA_INPUT), | ||
627 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), | ||
628 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), | ||
629 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | ||
630 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | ||
631 | { } /* end */ | ||
632 | }; | ||
633 | |||
634 | |||
635 | /* FIXME! */ | ||
636 | /* | ||
637 | * ALC880 ASUS model | ||
638 | * | ||
639 | * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e) | ||
640 | * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16, | ||
641 | * Mic = 0x18, Line = 0x1a | ||
642 | */ | ||
643 | |||
644 | #define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */ | ||
645 | #define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */ | ||
646 | |||
647 | static snd_kcontrol_new_t alc880_asus_mixer[] = { | ||
648 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
649 | ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), | ||
650 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), | ||
651 | ALC_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), | ||
652 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), | ||
653 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), | ||
654 | ALC_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), | ||
655 | ALC_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), | ||
656 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), | ||
657 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), | ||
658 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), | ||
659 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), | ||
660 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | ||
661 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | ||
462 | { | 662 | { |
463 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 663 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
464 | /* The multiple "Capture Source" controls confuse alsamixer | 664 | .name = "Channel Mode", |
465 | * So call somewhat different.. | 665 | .info = alc880_ch_mode_info, |
466 | * FIXME: the controls appear in the "playback" view! | 666 | .get = alc880_ch_mode_get, |
467 | */ | 667 | .put = alc880_ch_mode_put, |
468 | /* .name = "Capture Source", */ | ||
469 | .name = "Input Source", | ||
470 | .count = 3, | ||
471 | .info = alc_mux_enum_info, | ||
472 | .get = alc_mux_enum_get, | ||
473 | .put = alc_mux_enum_put, | ||
474 | }, | 668 | }, |
475 | { } /* end */ | 669 | { } /* end */ |
476 | }; | 670 | }; |
477 | 671 | ||
672 | /* FIXME! */ | ||
478 | /* | 673 | /* |
674 | * ALC880 ASUS W1V model | ||
675 | * | ||
676 | * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e) | ||
677 | * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16, | ||
678 | * Mic = 0x18, Line = 0x1a, Line2 = 0x1b | ||
679 | */ | ||
680 | |||
681 | /* additional mixers to alc880_asus_mixer */ | ||
682 | static snd_kcontrol_new_t alc880_asus_w1v_mixer[] = { | ||
683 | HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT), | ||
684 | HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT), | ||
685 | { } /* end */ | ||
686 | }; | ||
687 | |||
688 | |||
689 | /* | ||
690 | * build control elements | ||
479 | */ | 691 | */ |
480 | static int alc_build_controls(struct hda_codec *codec) | 692 | static int alc_build_controls(struct hda_codec *codec) |
481 | { | 693 | { |
@@ -502,227 +714,297 @@ static int alc_build_controls(struct hda_codec *codec) | |||
502 | return 0; | 714 | return 0; |
503 | } | 715 | } |
504 | 716 | ||
717 | |||
505 | /* | 718 | /* |
506 | * initialize the codec volumes, etc | 719 | * initialize the codec volumes, etc |
507 | */ | 720 | */ |
508 | 721 | ||
509 | static struct hda_verb alc880_init_verbs_three_stack[] = { | 722 | /* |
510 | /* Line In pin widget for input */ | 723 | * generic initialization of ADC, input mixers and output mixers |
511 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, | 724 | */ |
512 | /* CD pin widget for input */ | 725 | static struct hda_verb alc880_volume_init_verbs[] = { |
513 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, | 726 | /* |
514 | /* Mic1 (rear panel) pin widget for input and vref at 80% */ | 727 | * Unmute ADC0-2 and set the default input to mic-in |
515 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, | 728 | */ |
516 | /* Mic2 (front panel) pin widget for input and vref at 80% */ | 729 | {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, |
517 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, | 730 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
518 | /* unmute amp left and right */ | 731 | {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, |
519 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, | 732 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
520 | /* set connection select to line in (default select for this ADC) */ | 733 | {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, |
521 | {0x07, AC_VERB_SET_CONNECT_SEL, 0x02}, | 734 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
522 | /* unmute front mixer amp left (volume = 0) */ | 735 | |
523 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | 736 | /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback |
524 | /* mute pin widget amp left and right (no gain on this amp) */ | 737 | * mixer widget |
525 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, | ||
526 | /* unmute rear mixer amp left and right (volume = 0) */ | ||
527 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
528 | /* mute pin widget amp left and right (no gain on this amp) */ | ||
529 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, | ||
530 | /* unmute rear mixer amp left and right (volume = 0) */ | ||
531 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
532 | /* mute pin widget amp left and right (no gain on this amp) */ | ||
533 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, | ||
534 | |||
535 | /* using rear surround as the path for headphone output */ | ||
536 | /* unmute rear surround mixer amp left and right (volume = 0) */ | ||
537 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
538 | /* PASD 3 stack boards use the Mic 2 as the headphone output */ | ||
539 | /* need to program the selector associated with the Mic 2 pin widget to | ||
540 | * surround path (index 0x01) for headphone output */ | ||
541 | {0x11, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
542 | /* mute pin widget amp left and right (no gain on this amp) */ | ||
543 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, | ||
544 | /* need to retask the Mic 2 pin widget to output */ | ||
545 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
546 | |||
547 | /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) for mixer widget(nid=0x0B) | ||
548 | * to support the input path of analog loopback | ||
549 | * Note: PASD motherboards uses the Line In 2 as the input for front panel | 738 | * Note: PASD motherboards uses the Line In 2 as the input for front panel |
550 | * mic (mic 2) | 739 | * mic (mic 2) |
551 | */ | 740 | */ |
552 | /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03 */ | 741 | /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ |
553 | /* unmute CD */ | 742 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
554 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, | 743 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, |
555 | /* unmute Line In */ | 744 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, |
556 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, | 745 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, |
557 | /* unmute Mic 1 */ | 746 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, |
558 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | 747 | |
559 | /* unmute Line In 2 (for PASD boards Mic 2) */ | 748 | /* |
560 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, | 749 | * Set up output mixers (0x0c - 0x0f) |
561 | |||
562 | /* Unmute input amps for the line out paths to support the output path of | ||
563 | * analog loopback | ||
564 | * the mixers on the output path has 2 inputs, one from the DAC and one | ||
565 | * from the mixer | ||
566 | */ | 750 | */ |
567 | /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ | 751 | /* set vol=0 to output mixers */ |
568 | /* Unmute Front out path */ | 752 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, |
569 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | 753 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, |
570 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | 754 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, |
571 | /* Unmute Surround (used as HP) out path */ | 755 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, |
572 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | 756 | /* set up input amps for analog loopback */ |
573 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | 757 | /* Amp Indices: DAC = 0, mixer = 1 */ |
574 | /* Unmute C/LFE out path */ | 758 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, |
575 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | 759 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, |
576 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))}, /* mute */ | 760 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, |
577 | /* Unmute rear Surround out path */ | 761 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, |
578 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | 762 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, |
579 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | 763 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, |
764 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
765 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
580 | 766 | ||
581 | { } | 767 | { } |
582 | }; | 768 | }; |
583 | 769 | ||
584 | static struct hda_verb alc880_init_verbs_five_stack[] = { | 770 | /* |
585 | /* Line In pin widget for input */ | 771 | * 3-stack pin configuration: |
586 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, | 772 | * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b |
587 | /* CD pin widget for input */ | 773 | */ |
588 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, | 774 | static struct hda_verb alc880_pin_3stack_init_verbs[] = { |
589 | /* Mic1 (rear panel) pin widget for input and vref at 80% */ | 775 | /* |
590 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, | 776 | * preset connection lists of input pins |
591 | /* Mic2 (front panel) pin widget for input and vref at 80% */ | 777 | * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround |
592 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, | ||
593 | /* unmute amp left and right */ | ||
594 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, | ||
595 | /* set connection select to line in (default select for this ADC) */ | ||
596 | {0x07, AC_VERB_SET_CONNECT_SEL, 0x02}, | ||
597 | /* unmute front mixer amp left and right (volume = 0) */ | ||
598 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
599 | /* mute pin widget amp left and right (no gain on this amp) */ | ||
600 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, | ||
601 | /* five rear and clfe */ | ||
602 | /* unmute rear mixer amp left and right (volume = 0) */ | ||
603 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
604 | /* mute pin widget amp left and right (no gain on this amp) */ | ||
605 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, | ||
606 | /* unmute clfe mixer amp left and right (volume = 0) */ | ||
607 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
608 | /* mute pin widget amp left and right (no gain on this amp) */ | ||
609 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, | ||
610 | |||
611 | /* using rear surround as the path for headphone output */ | ||
612 | /* unmute rear surround mixer amp left and right (volume = 0) */ | ||
613 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
614 | /* PASD 3 stack boards use the Mic 2 as the headphone output */ | ||
615 | /* need to program the selector associated with the Mic 2 pin widget to | ||
616 | * surround path (index 0x01) for headphone output | ||
617 | */ | ||
618 | {0x11, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
619 | /* mute pin widget amp left and right (no gain on this amp) */ | ||
620 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, | ||
621 | /* need to retask the Mic 2 pin widget to output */ | ||
622 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
623 | |||
624 | /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) for mixer | ||
625 | * widget(nid=0x0B) to support the input path of analog loopback | ||
626 | */ | 778 | */ |
627 | /* Note: PASD motherboards uses the Line In 2 as the input for front panel mic (mic 2) */ | 779 | {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */ |
628 | /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03*/ | 780 | {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ |
629 | /* unmute CD */ | 781 | {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */ |
630 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, | 782 | |
631 | /* unmute Line In */ | 783 | /* |
632 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, | 784 | * Set pin mode and muting |
633 | /* unmute Mic 1 */ | ||
634 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
635 | /* unmute Line In 2 (for PASD boards Mic 2) */ | ||
636 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, | ||
637 | |||
638 | /* Unmute input amps for the line out paths to support the output path of | ||
639 | * analog loopback | ||
640 | * the mixers on the output path has 2 inputs, one from the DAC and | ||
641 | * one from the mixer | ||
642 | */ | 785 | */ |
643 | /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ | 786 | /* set front pin widgets 0x14 for output */ |
644 | /* Unmute Front out path */ | 787 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, |
645 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | 788 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, |
646 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | 789 | /* Mic1 (rear panel) pin widget for input and vref at 80% */ |
647 | /* Unmute Surround (used as HP) out path */ | 790 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, |
648 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | 791 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, |
649 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | 792 | /* Mic2 (as headphone out) for HP output */ |
650 | /* Unmute C/LFE out path */ | 793 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, |
651 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | 794 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, |
652 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))}, /* mute */ | 795 | /* Line In pin widget for input */ |
653 | /* Unmute rear Surround out path */ | 796 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, |
654 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | 797 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, |
655 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | 798 | /* Line2 (as front mic) pin widget for input and vref at 80% */ |
799 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
800 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
801 | /* CD pin widget for input */ | ||
802 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
656 | 803 | ||
657 | { } | 804 | { } |
658 | }; | 805 | }; |
659 | 806 | ||
660 | static struct hda_verb alc880_w810_init_verbs[] = { | 807 | /* |
661 | /* front channel selector/amp: input 0: DAC: unmuted, (no volume selection) */ | 808 | * 5-stack pin configuration: |
662 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, | 809 | * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19, |
663 | 810 | * line-in/side = 0x1a, f-mic = 0x1b | |
664 | /* front channel selector/amp: input 1: capture mix: muted, (no volume selection) */ | 811 | */ |
665 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7180}, | 812 | static struct hda_verb alc880_pin_5stack_init_verbs[] = { |
666 | 813 | /* | |
667 | /* front channel selector/amp: output 0: unmuted, max volume */ | 814 | * preset connection lists of input pins |
668 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | 815 | * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround |
669 | 816 | */ | |
670 | /* front out pin: muted, (no volume selection) */ | 817 | {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ |
671 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | 818 | {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */ |
672 | |||
673 | /* front out pin: NOT headphone enable, out enable, vref disabled */ | ||
674 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
675 | 819 | ||
820 | /* | ||
821 | * Set pin mode and muting | ||
822 | */ | ||
823 | /* set pin widgets 0x14-0x17 for output */ | ||
824 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
825 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
826 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
827 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
828 | /* unmute pins for output (no gain on this amp) */ | ||
829 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
830 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
831 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
832 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
676 | 833 | ||
677 | /* surround channel selector/amp: input 0: DAC: unmuted, (no volume selection) */ | 834 | /* Mic1 (rear panel) pin widget for input and vref at 80% */ |
678 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, | 835 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, |
836 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
837 | /* Mic2 (as headphone out) for HP output */ | ||
838 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
839 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
840 | /* Line In pin widget for input */ | ||
841 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
842 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
843 | /* Line2 (as front mic) pin widget for input and vref at 80% */ | ||
844 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
845 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
846 | /* CD pin widget for input */ | ||
847 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
679 | 848 | ||
680 | /* surround channel selector/amp: input 1: capture mix: muted, (no volume selection) */ | 849 | { } |
681 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7180}, | 850 | }; |
682 | 851 | ||
683 | /* surround channel selector/amp: output 0: unmuted, max volume */ | 852 | /* |
684 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | 853 | * W810 pin configuration: |
854 | * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b | ||
855 | */ | ||
856 | static struct hda_verb alc880_pin_w810_init_verbs[] = { | ||
857 | /* hphone/speaker input selector: front DAC */ | ||
858 | {0x13, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
685 | 859 | ||
686 | /* surround out pin: muted, (no volume selection) */ | 860 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, |
687 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | 861 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, |
862 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
863 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
864 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
865 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
688 | 866 | ||
689 | /* surround out pin: NOT headphone enable, out enable, vref disabled */ | 867 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, |
690 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | 868 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, |
691 | 869 | ||
870 | { } | ||
871 | }; | ||
692 | 872 | ||
693 | /* c/lfe channel selector/amp: input 0: DAC: unmuted, (no volume selection) */ | 873 | /* |
694 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, | 874 | * Z71V pin configuration: |
875 | * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?) | ||
876 | */ | ||
877 | static struct hda_verb alc880_pin_z71v_init_verbs[] = { | ||
878 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
879 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
880 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
881 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
695 | 882 | ||
696 | /* c/lfe channel selector/amp: input 1: capture mix: muted, (no volume selection) */ | 883 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, |
697 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0x7180}, | 884 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, |
885 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
886 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
698 | 887 | ||
699 | /* c/lfe channel selector/amp: output 0: unmuted, max volume */ | 888 | { } |
700 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | 889 | }; |
701 | 890 | ||
702 | /* c/lfe out pin: muted, (no volume selection) */ | 891 | /* |
703 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | 892 | * 6-stack pin configuration: |
893 | * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18, f-mic = 0x19, | ||
894 | * line = 0x1a, HP = 0x1b | ||
895 | */ | ||
896 | static struct hda_verb alc880_pin_6stack_init_verbs[] = { | ||
897 | {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ | ||
898 | |||
899 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
900 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
901 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
902 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
903 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
904 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
905 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
906 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
907 | |||
908 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
909 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
910 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
911 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
912 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
913 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
914 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
915 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
916 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
917 | |||
918 | { } | ||
919 | }; | ||
704 | 920 | ||
705 | /* c/lfe out pin: NOT headphone enable, out enable, vref disabled */ | 921 | /* FIXME! */ |
706 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | 922 | /* |
923 | * F1734 pin configuration: | ||
924 | * HP = 0x14, speaker-out = 0x15, mic = 0x18 | ||
925 | */ | ||
926 | static struct hda_verb alc880_pin_f1734_init_verbs[] = { | ||
927 | {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, | ||
928 | {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
929 | {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
930 | {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
931 | |||
932 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
933 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
934 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
935 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
936 | |||
937 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
938 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
939 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
940 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
941 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
942 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
943 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
944 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
945 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
707 | 946 | ||
947 | { } | ||
948 | }; | ||
708 | 949 | ||
709 | /* hphone/speaker input selector: front DAC */ | 950 | /* FIXME! */ |
710 | {0x13, AC_VERB_SET_CONNECT_SEL, 0x0}, | 951 | /* |
952 | * ASUS pin configuration: | ||
953 | * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a | ||
954 | */ | ||
955 | static struct hda_verb alc880_pin_asus_init_verbs[] = { | ||
956 | {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, | ||
957 | {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
958 | {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
959 | {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
960 | |||
961 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
962 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
963 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
964 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
965 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
966 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
967 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
968 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
969 | |||
970 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
971 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
972 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
973 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
974 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
975 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
976 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
977 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
978 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
979 | |||
980 | { } | ||
981 | }; | ||
711 | 982 | ||
712 | /* hphone/speaker out pin: muted, (no volume selection) */ | 983 | /* Enable GPIO mask and set output */ |
713 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | 984 | static struct hda_verb alc880_gpio1_init_verbs[] = { |
985 | {0x01, AC_VERB_SET_GPIO_MASK, 0x01}, | ||
986 | {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01}, | ||
987 | {0x01, AC_VERB_SET_GPIO_DATA, 0x01}, | ||
988 | }; | ||
714 | 989 | ||
715 | /* hphone/speaker out pin: NOT headphone enable, out enable, vref disabled */ | 990 | /* Enable GPIO mask and set output */ |
716 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | 991 | static struct hda_verb alc880_gpio2_init_verbs[] = { |
992 | {0x01, AC_VERB_SET_GPIO_MASK, 0x02}, | ||
993 | {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02}, | ||
994 | {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, | ||
995 | }; | ||
717 | 996 | ||
718 | 997 | ||
719 | { } | 998 | /* |
720 | }; | 999 | */ |
721 | 1000 | ||
722 | static int alc_init(struct hda_codec *codec) | 1001 | static int alc_init(struct hda_codec *codec) |
723 | { | 1002 | { |
724 | struct alc_spec *spec = codec->spec; | 1003 | struct alc_spec *spec = codec->spec; |
725 | snd_hda_sequence_write(codec, spec->init_verbs); | 1004 | unsigned int i; |
1005 | |||
1006 | for (i = 0; i < spec->num_init_verbs; i++) | ||
1007 | snd_hda_sequence_write(codec, spec->init_verbs[i]); | ||
726 | return 0; | 1008 | return 0; |
727 | } | 1009 | } |
728 | 1010 | ||
@@ -736,9 +1018,8 @@ static int alc_resume(struct hda_codec *codec) | |||
736 | int i; | 1018 | int i; |
737 | 1019 | ||
738 | alc_init(codec); | 1020 | alc_init(codec); |
739 | for (i = 0; i < spec->num_mixers; i++) { | 1021 | for (i = 0; i < spec->num_mixers; i++) |
740 | snd_hda_resume_ctls(codec, spec->mixers[i]); | 1022 | snd_hda_resume_ctls(codec, spec->mixers[i]); |
741 | } | ||
742 | if (spec->multiout.dig_out_nid) | 1023 | if (spec->multiout.dig_out_nid) |
743 | snd_hda_resume_spdif_out(codec); | 1024 | snd_hda_resume_spdif_out(codec); |
744 | if (spec->dig_in_nid) | 1025 | if (spec->dig_in_nid) |
@@ -830,7 +1111,7 @@ static struct hda_pcm_stream alc880_pcm_analog_playback = { | |||
830 | .substreams = 1, | 1111 | .substreams = 1, |
831 | .channels_min = 2, | 1112 | .channels_min = 2, |
832 | .channels_max = 8, | 1113 | .channels_max = 8, |
833 | .nid = 0x02, /* NID to query formats and rates */ | 1114 | /* NID is set in alc_build_pcms */ |
834 | .ops = { | 1115 | .ops = { |
835 | .open = alc880_playback_pcm_open, | 1116 | .open = alc880_playback_pcm_open, |
836 | .prepare = alc880_playback_pcm_prepare, | 1117 | .prepare = alc880_playback_pcm_prepare, |
@@ -842,7 +1123,7 @@ static struct hda_pcm_stream alc880_pcm_analog_capture = { | |||
842 | .substreams = 2, | 1123 | .substreams = 2, |
843 | .channels_min = 2, | 1124 | .channels_min = 2, |
844 | .channels_max = 2, | 1125 | .channels_max = 2, |
845 | .nid = 0x07, /* NID to query formats and rates */ | 1126 | /* NID is set in alc_build_pcms */ |
846 | .ops = { | 1127 | .ops = { |
847 | .prepare = alc880_capture_pcm_prepare, | 1128 | .prepare = alc880_capture_pcm_prepare, |
848 | .cleanup = alc880_capture_pcm_cleanup | 1129 | .cleanup = alc880_capture_pcm_cleanup |
@@ -878,7 +1159,9 @@ static int alc_build_pcms(struct hda_codec *codec) | |||
878 | 1159 | ||
879 | info->name = spec->stream_name_analog; | 1160 | info->name = spec->stream_name_analog; |
880 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback); | 1161 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback); |
1162 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; | ||
881 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture); | 1163 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture); |
1164 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; | ||
882 | 1165 | ||
883 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0; | 1166 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0; |
884 | for (i = 0; i < spec->num_channel_mode; i++) { | 1167 | for (i = 0; i < spec->num_channel_mode; i++) { |
@@ -906,7 +1189,18 @@ static int alc_build_pcms(struct hda_codec *codec) | |||
906 | 1189 | ||
907 | static void alc_free(struct hda_codec *codec) | 1190 | static void alc_free(struct hda_codec *codec) |
908 | { | 1191 | { |
909 | kfree(codec->spec); | 1192 | struct alc_spec *spec = codec->spec; |
1193 | unsigned int i; | ||
1194 | |||
1195 | if (! spec) | ||
1196 | return; | ||
1197 | |||
1198 | if (spec->kctl_alloc) { | ||
1199 | for (i = 0; i < spec->num_kctl_used; i++) | ||
1200 | kfree(spec->kctl_alloc[i].name); | ||
1201 | kfree(spec->kctl_alloc); | ||
1202 | } | ||
1203 | kfree(spec); | ||
910 | } | 1204 | } |
911 | 1205 | ||
912 | /* | 1206 | /* |
@@ -921,153 +1215,915 @@ static struct hda_codec_ops alc_patch_ops = { | |||
921 | #endif | 1215 | #endif |
922 | }; | 1216 | }; |
923 | 1217 | ||
1218 | |||
1219 | /* | ||
1220 | * Test configuration for debugging | ||
1221 | * | ||
1222 | * Almost all inputs/outputs are enabled. I/O pins can be configured via | ||
1223 | * enum controls. | ||
1224 | */ | ||
1225 | #ifdef CONFIG_SND_DEBUG | ||
1226 | static hda_nid_t alc880_test_dac_nids[4] = { | ||
1227 | 0x02, 0x03, 0x04, 0x05 | ||
1228 | }; | ||
1229 | |||
1230 | static struct hda_input_mux alc880_test_capture_source = { | ||
1231 | .num_items = 5, | ||
1232 | .items = { | ||
1233 | { "In-1", 0x0 }, | ||
1234 | { "In-2", 0x1 }, | ||
1235 | { "In-3", 0x2 }, | ||
1236 | { "In-4", 0x3 }, | ||
1237 | { "CD", 0x4 }, | ||
1238 | }, | ||
1239 | }; | ||
1240 | |||
1241 | static struct alc_channel_mode alc880_test_modes[4] = { | ||
1242 | { 2, NULL }, | ||
1243 | { 4, NULL }, | ||
1244 | { 6, NULL }, | ||
1245 | { 8, NULL }, | ||
1246 | }; | ||
1247 | |||
1248 | static int alc_test_pin_ctl_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) | ||
1249 | { | ||
1250 | static char *texts[] = { | ||
1251 | "N/A", "Line Out", "HP Out", | ||
1252 | "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%" | ||
1253 | }; | ||
1254 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
1255 | uinfo->count = 1; | ||
1256 | uinfo->value.enumerated.items = 8; | ||
1257 | if (uinfo->value.enumerated.item >= 8) | ||
1258 | uinfo->value.enumerated.item = 7; | ||
1259 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
1260 | return 0; | ||
1261 | } | ||
1262 | |||
1263 | static int alc_test_pin_ctl_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
1264 | { | ||
1265 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1266 | hda_nid_t nid = (hda_nid_t)kcontrol->private_value; | ||
1267 | unsigned int pin_ctl, item = 0; | ||
1268 | |||
1269 | pin_ctl = snd_hda_codec_read(codec, nid, 0, | ||
1270 | AC_VERB_GET_PIN_WIDGET_CONTROL, 0); | ||
1271 | if (pin_ctl & AC_PINCTL_OUT_EN) { | ||
1272 | if (pin_ctl & AC_PINCTL_HP_EN) | ||
1273 | item = 2; | ||
1274 | else | ||
1275 | item = 1; | ||
1276 | } else if (pin_ctl & AC_PINCTL_IN_EN) { | ||
1277 | switch (pin_ctl & AC_PINCTL_VREFEN) { | ||
1278 | case AC_PINCTL_VREF_HIZ: item = 3; break; | ||
1279 | case AC_PINCTL_VREF_50: item = 4; break; | ||
1280 | case AC_PINCTL_VREF_GRD: item = 5; break; | ||
1281 | case AC_PINCTL_VREF_80: item = 6; break; | ||
1282 | case AC_PINCTL_VREF_100: item = 7; break; | ||
1283 | } | ||
1284 | } | ||
1285 | ucontrol->value.enumerated.item[0] = item; | ||
1286 | return 0; | ||
1287 | } | ||
1288 | |||
1289 | static int alc_test_pin_ctl_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
1290 | { | ||
1291 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1292 | hda_nid_t nid = (hda_nid_t)kcontrol->private_value; | ||
1293 | static unsigned int ctls[] = { | ||
1294 | 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN, | ||
1295 | AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ, | ||
1296 | AC_PINCTL_IN_EN | AC_PINCTL_VREF_50, | ||
1297 | AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD, | ||
1298 | AC_PINCTL_IN_EN | AC_PINCTL_VREF_80, | ||
1299 | AC_PINCTL_IN_EN | AC_PINCTL_VREF_100, | ||
1300 | }; | ||
1301 | unsigned int old_ctl, new_ctl; | ||
1302 | |||
1303 | old_ctl = snd_hda_codec_read(codec, nid, 0, | ||
1304 | AC_VERB_GET_PIN_WIDGET_CONTROL, 0); | ||
1305 | new_ctl = ctls[ucontrol->value.enumerated.item[0]]; | ||
1306 | if (old_ctl != new_ctl) { | ||
1307 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, new_ctl); | ||
1308 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, | ||
1309 | ucontrol->value.enumerated.item[0] >= 3 ? 0xb080 : 0xb000); | ||
1310 | return 1; | ||
1311 | } | ||
1312 | return 0; | ||
1313 | } | ||
1314 | |||
1315 | static int alc_test_pin_src_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) | ||
1316 | { | ||
1317 | static char *texts[] = { | ||
1318 | "Front", "Surround", "CLFE", "Side" | ||
1319 | }; | ||
1320 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
1321 | uinfo->count = 1; | ||
1322 | uinfo->value.enumerated.items = 4; | ||
1323 | if (uinfo->value.enumerated.item >= 4) | ||
1324 | uinfo->value.enumerated.item = 3; | ||
1325 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
1326 | return 0; | ||
1327 | } | ||
1328 | |||
1329 | static int alc_test_pin_src_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
1330 | { | ||
1331 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1332 | hda_nid_t nid = (hda_nid_t)kcontrol->private_value; | ||
1333 | unsigned int sel; | ||
1334 | |||
1335 | sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0); | ||
1336 | ucontrol->value.enumerated.item[0] = sel & 3; | ||
1337 | return 0; | ||
1338 | } | ||
1339 | |||
1340 | static int alc_test_pin_src_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
1341 | { | ||
1342 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1343 | hda_nid_t nid = (hda_nid_t)kcontrol->private_value; | ||
1344 | unsigned int sel; | ||
1345 | |||
1346 | sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3; | ||
1347 | if (ucontrol->value.enumerated.item[0] != sel) { | ||
1348 | sel = ucontrol->value.enumerated.item[0] & 3; | ||
1349 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, sel); | ||
1350 | return 1; | ||
1351 | } | ||
1352 | return 0; | ||
1353 | } | ||
1354 | |||
1355 | #define PIN_CTL_TEST(xname,nid) { \ | ||
1356 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
1357 | .name = xname, \ | ||
1358 | .info = alc_test_pin_ctl_info, \ | ||
1359 | .get = alc_test_pin_ctl_get, \ | ||
1360 | .put = alc_test_pin_ctl_put, \ | ||
1361 | .private_value = nid \ | ||
1362 | } | ||
1363 | |||
1364 | #define PIN_SRC_TEST(xname,nid) { \ | ||
1365 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
1366 | .name = xname, \ | ||
1367 | .info = alc_test_pin_src_info, \ | ||
1368 | .get = alc_test_pin_src_get, \ | ||
1369 | .put = alc_test_pin_src_put, \ | ||
1370 | .private_value = nid \ | ||
1371 | } | ||
1372 | |||
1373 | static snd_kcontrol_new_t alc880_test_mixer[] = { | ||
1374 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
1375 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), | ||
1376 | HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT), | ||
1377 | HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), | ||
1378 | ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), | ||
1379 | ALC_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), | ||
1380 | ALC_BIND_MUTE("CLFE Playback Volume", 0x0e, 2, HDA_INPUT), | ||
1381 | ALC_BIND_MUTE("Side Playback Volume", 0x0f, 2, HDA_INPUT), | ||
1382 | PIN_CTL_TEST("Front Pin Mode", 0x14), | ||
1383 | PIN_CTL_TEST("Surround Pin Mode", 0x15), | ||
1384 | PIN_CTL_TEST("CLFE Pin Mode", 0x16), | ||
1385 | PIN_CTL_TEST("Side Pin Mode", 0x17), | ||
1386 | PIN_CTL_TEST("In-1 Pin Mode", 0x18), | ||
1387 | PIN_CTL_TEST("In-2 Pin Mode", 0x19), | ||
1388 | PIN_CTL_TEST("In-3 Pin Mode", 0x1a), | ||
1389 | PIN_CTL_TEST("In-4 Pin Mode", 0x1b), | ||
1390 | PIN_SRC_TEST("In-1 Pin Source", 0x18), | ||
1391 | PIN_SRC_TEST("In-2 Pin Source", 0x19), | ||
1392 | PIN_SRC_TEST("In-3 Pin Source", 0x1a), | ||
1393 | PIN_SRC_TEST("In-4 Pin Source", 0x1b), | ||
1394 | HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT), | ||
1395 | HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT), | ||
1396 | HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT), | ||
1397 | HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT), | ||
1398 | HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT), | ||
1399 | HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT), | ||
1400 | HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT), | ||
1401 | HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT), | ||
1402 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT), | ||
1403 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT), | ||
1404 | HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), | ||
1405 | HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), | ||
1406 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), | ||
1407 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), | ||
1408 | { | ||
1409 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1410 | .name = "Input Source", | ||
1411 | .count = 2, | ||
1412 | .info = alc_mux_enum_info, | ||
1413 | .get = alc_mux_enum_get, | ||
1414 | .put = alc_mux_enum_put, | ||
1415 | }, | ||
1416 | { | ||
1417 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1418 | .name = "Channel Mode", | ||
1419 | .info = alc880_ch_mode_info, | ||
1420 | .get = alc880_ch_mode_get, | ||
1421 | .put = alc880_ch_mode_put, | ||
1422 | }, | ||
1423 | { } /* end */ | ||
1424 | }; | ||
1425 | |||
1426 | static struct hda_verb alc880_test_init_verbs[] = { | ||
1427 | /* Unmute inputs of 0x0c - 0x0f */ | ||
1428 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
1429 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
1430 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
1431 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
1432 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
1433 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
1434 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
1435 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
1436 | /* Vol output for 0x0c-0x0f */ | ||
1437 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
1438 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
1439 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
1440 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
1441 | /* Set output pins 0x14-0x17 */ | ||
1442 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
1443 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
1444 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
1445 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
1446 | /* Unmute output pins 0x14-0x17 */ | ||
1447 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
1448 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
1449 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
1450 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
1451 | /* Set input pins 0x18-0x1c */ | ||
1452 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
1453 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
1454 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
1455 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
1456 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
1457 | /* Mute input pins 0x18-0x1b */ | ||
1458 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
1459 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
1460 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
1461 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
1462 | /* ADC set up */ | ||
1463 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
1464 | {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
1465 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
1466 | {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
1467 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
1468 | {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
1469 | /* Analog input/passthru */ | ||
1470 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
1471 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
1472 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
1473 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
1474 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
1475 | { } | ||
1476 | }; | ||
1477 | #endif | ||
1478 | |||
924 | /* | 1479 | /* |
925 | */ | 1480 | */ |
926 | 1481 | ||
927 | static struct hda_board_config alc880_cfg_tbl[] = { | 1482 | static struct hda_board_config alc880_cfg_tbl[] = { |
928 | /* Back 3 jack, front 2 jack */ | 1483 | /* Back 3 jack, front 2 jack */ |
929 | { .modelname = "3stack", .config = ALC880_3ST }, | 1484 | { .modelname = "3stack", .config = ALC880_3ST }, |
930 | { .pci_vendor = 0x8086, .pci_device = 0xe200, .config = ALC880_3ST }, | 1485 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe200, .config = ALC880_3ST }, |
931 | { .pci_vendor = 0x8086, .pci_device = 0xe201, .config = ALC880_3ST }, | 1486 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe201, .config = ALC880_3ST }, |
932 | { .pci_vendor = 0x8086, .pci_device = 0xe202, .config = ALC880_3ST }, | 1487 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe202, .config = ALC880_3ST }, |
933 | { .pci_vendor = 0x8086, .pci_device = 0xe203, .config = ALC880_3ST }, | 1488 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe203, .config = ALC880_3ST }, |
934 | { .pci_vendor = 0x8086, .pci_device = 0xe204, .config = ALC880_3ST }, | 1489 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe204, .config = ALC880_3ST }, |
935 | { .pci_vendor = 0x8086, .pci_device = 0xe205, .config = ALC880_3ST }, | 1490 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe205, .config = ALC880_3ST }, |
936 | { .pci_vendor = 0x8086, .pci_device = 0xe206, .config = ALC880_3ST }, | 1491 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe206, .config = ALC880_3ST }, |
937 | { .pci_vendor = 0x8086, .pci_device = 0xe207, .config = ALC880_3ST }, | 1492 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe207, .config = ALC880_3ST }, |
938 | { .pci_vendor = 0x8086, .pci_device = 0xe208, .config = ALC880_3ST }, | 1493 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe208, .config = ALC880_3ST }, |
939 | { .pci_vendor = 0x8086, .pci_device = 0xe209, .config = ALC880_3ST }, | 1494 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe209, .config = ALC880_3ST }, |
940 | { .pci_vendor = 0x8086, .pci_device = 0xe20a, .config = ALC880_3ST }, | 1495 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20a, .config = ALC880_3ST }, |
941 | { .pci_vendor = 0x8086, .pci_device = 0xe20b, .config = ALC880_3ST }, | 1496 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20b, .config = ALC880_3ST }, |
942 | { .pci_vendor = 0x8086, .pci_device = 0xe20c, .config = ALC880_3ST }, | 1497 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20c, .config = ALC880_3ST }, |
943 | { .pci_vendor = 0x8086, .pci_device = 0xe20d, .config = ALC880_3ST }, | 1498 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20d, .config = ALC880_3ST }, |
944 | { .pci_vendor = 0x8086, .pci_device = 0xe20e, .config = ALC880_3ST }, | 1499 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20e, .config = ALC880_3ST }, |
945 | { .pci_vendor = 0x8086, .pci_device = 0xe20f, .config = ALC880_3ST }, | 1500 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20f, .config = ALC880_3ST }, |
946 | { .pci_vendor = 0x8086, .pci_device = 0xe210, .config = ALC880_3ST }, | 1501 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe210, .config = ALC880_3ST }, |
947 | { .pci_vendor = 0x8086, .pci_device = 0xe211, .config = ALC880_3ST }, | 1502 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe211, .config = ALC880_3ST }, |
948 | { .pci_vendor = 0x8086, .pci_device = 0xe214, .config = ALC880_3ST }, | 1503 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe214, .config = ALC880_3ST }, |
949 | { .pci_vendor = 0x8086, .pci_device = 0xe302, .config = ALC880_3ST }, | 1504 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe302, .config = ALC880_3ST }, |
950 | { .pci_vendor = 0x8086, .pci_device = 0xe303, .config = ALC880_3ST }, | 1505 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe303, .config = ALC880_3ST }, |
951 | { .pci_vendor = 0x8086, .pci_device = 0xe304, .config = ALC880_3ST }, | 1506 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe304, .config = ALC880_3ST }, |
952 | { .pci_vendor = 0x8086, .pci_device = 0xe306, .config = ALC880_3ST }, | 1507 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe306, .config = ALC880_3ST }, |
953 | { .pci_vendor = 0x8086, .pci_device = 0xe307, .config = ALC880_3ST }, | 1508 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe307, .config = ALC880_3ST }, |
954 | { .pci_vendor = 0x8086, .pci_device = 0xe404, .config = ALC880_3ST }, | 1509 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe404, .config = ALC880_3ST }, |
955 | { .pci_vendor = 0x8086, .pci_device = 0xa101, .config = ALC880_3ST }, | 1510 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xa101, .config = ALC880_3ST }, |
956 | { .pci_vendor = 0x107b, .pci_device = 0x3031, .config = ALC880_3ST }, | 1511 | { .pci_subvendor = 0x107b, .pci_subdevice = 0x3031, .config = ALC880_3ST }, |
957 | { .pci_vendor = 0x107b, .pci_device = 0x4036, .config = ALC880_3ST }, | 1512 | { .pci_subvendor = 0x107b, .pci_subdevice = 0x4036, .config = ALC880_3ST }, |
958 | { .pci_vendor = 0x107b, .pci_device = 0x4037, .config = ALC880_3ST }, | 1513 | { .pci_subvendor = 0x107b, .pci_subdevice = 0x4037, .config = ALC880_3ST }, |
959 | { .pci_vendor = 0x107b, .pci_device = 0x4038, .config = ALC880_3ST }, | 1514 | { .pci_subvendor = 0x107b, .pci_subdevice = 0x4038, .config = ALC880_3ST }, |
960 | { .pci_vendor = 0x107b, .pci_device = 0x4040, .config = ALC880_3ST }, | 1515 | { .pci_subvendor = 0x107b, .pci_subdevice = 0x4040, .config = ALC880_3ST }, |
961 | { .pci_vendor = 0x107b, .pci_device = 0x4041, .config = ALC880_3ST }, | 1516 | { .pci_subvendor = 0x107b, .pci_subdevice = 0x4041, .config = ALC880_3ST }, |
962 | 1517 | ||
963 | /* Back 3 jack, front 2 jack (Internal add Aux-In) */ | 1518 | /* Back 3 jack, front 2 jack (Internal add Aux-In) */ |
964 | { .pci_vendor = 0x1025, .pci_device = 0xe310, .config = ALC880_3ST }, | 1519 | { .pci_subvendor = 0x1025, .pci_subdevice = 0xe310, .config = ALC880_3ST }, |
1520 | { .pci_subvendor = 0x104d, .pci_subdevice = 0x81d6, .config = ALC880_3ST }, | ||
965 | 1521 | ||
966 | /* Back 3 jack plus 1 SPDIF out jack, front 2 jack */ | 1522 | /* Back 3 jack plus 1 SPDIF out jack, front 2 jack */ |
967 | { .modelname = "3stack-digout", .config = ALC880_3ST_DIG }, | 1523 | { .modelname = "3stack-digout", .config = ALC880_3ST_DIG }, |
968 | { .pci_vendor = 0x8086, .pci_device = 0xe308, .config = ALC880_3ST_DIG }, | 1524 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe308, .config = ALC880_3ST_DIG }, |
969 | 1525 | ||
970 | /* Back 3 jack plus 1 SPDIF out jack, front 2 jack (Internal add Aux-In)*/ | 1526 | /* Back 3 jack plus 1 SPDIF out jack, front 2 jack (Internal add Aux-In)*/ |
971 | { .pci_vendor = 0x8086, .pci_device = 0xe305, .config = ALC880_3ST_DIG }, | 1527 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe305, .config = ALC880_3ST_DIG }, |
972 | { .pci_vendor = 0x8086, .pci_device = 0xd402, .config = ALC880_3ST_DIG }, | 1528 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xd402, .config = ALC880_3ST_DIG }, |
973 | { .pci_vendor = 0x1025, .pci_device = 0xe309, .config = ALC880_3ST_DIG }, | 1529 | { .pci_subvendor = 0x1025, .pci_subdevice = 0xe309, .config = ALC880_3ST_DIG }, |
974 | 1530 | ||
975 | /* Back 5 jack, front 2 jack */ | 1531 | /* Back 5 jack, front 2 jack */ |
976 | { .modelname = "5stack", .config = ALC880_5ST }, | 1532 | { .modelname = "5stack", .config = ALC880_5ST }, |
977 | { .pci_vendor = 0x107b, .pci_device = 0x3033, .config = ALC880_5ST }, | 1533 | { .pci_subvendor = 0x107b, .pci_subdevice = 0x3033, .config = ALC880_5ST }, |
978 | { .pci_vendor = 0x107b, .pci_device = 0x4039, .config = ALC880_5ST }, | 1534 | { .pci_subvendor = 0x107b, .pci_subdevice = 0x4039, .config = ALC880_5ST }, |
979 | { .pci_vendor = 0x107b, .pci_device = 0x3032, .config = ALC880_5ST }, | 1535 | { .pci_subvendor = 0x107b, .pci_subdevice = 0x3032, .config = ALC880_5ST }, |
980 | { .pci_vendor = 0x103c, .pci_device = 0x2a09, .config = ALC880_5ST }, | 1536 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x2a09, .config = ALC880_5ST }, |
1537 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x814e, .config = ALC880_5ST }, | ||
981 | 1538 | ||
982 | /* Back 5 jack plus 1 SPDIF out jack, front 2 jack */ | 1539 | /* Back 5 jack plus 1 SPDIF out jack, front 2 jack */ |
983 | { .modelname = "5stack-digout", .config = ALC880_5ST_DIG }, | 1540 | { .modelname = "5stack-digout", .config = ALC880_5ST_DIG }, |
984 | { .pci_vendor = 0x8086, .pci_device = 0xe224, .config = ALC880_5ST_DIG }, | 1541 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe224, .config = ALC880_5ST_DIG }, |
985 | { .pci_vendor = 0x8086, .pci_device = 0xe400, .config = ALC880_5ST_DIG }, | 1542 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe400, .config = ALC880_5ST_DIG }, |
986 | { .pci_vendor = 0x8086, .pci_device = 0xe401, .config = ALC880_5ST_DIG }, | 1543 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe401, .config = ALC880_5ST_DIG }, |
987 | { .pci_vendor = 0x8086, .pci_device = 0xe402, .config = ALC880_5ST_DIG }, | 1544 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe402, .config = ALC880_5ST_DIG }, |
988 | { .pci_vendor = 0x8086, .pci_device = 0xd400, .config = ALC880_5ST_DIG }, | 1545 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xd400, .config = ALC880_5ST_DIG }, |
989 | { .pci_vendor = 0x8086, .pci_device = 0xd401, .config = ALC880_5ST_DIG }, | 1546 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xd401, .config = ALC880_5ST_DIG }, |
990 | { .pci_vendor = 0x8086, .pci_device = 0xa100, .config = ALC880_5ST_DIG }, | 1547 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xa100, .config = ALC880_5ST_DIG }, |
991 | { .pci_vendor = 0x1565, .pci_device = 0x8202, .config = ALC880_5ST_DIG }, | 1548 | { .pci_subvendor = 0x1565, .pci_subdevice = 0x8202, .config = ALC880_5ST_DIG }, |
1549 | { .pci_subvendor = 0x1019, .pci_subdevice = 0xa880, .config = ALC880_5ST_DIG }, | ||
1550 | { .pci_subvendor = 0x1019, .pci_subdevice = 0xa884, .config = ALC880_5ST_DIG }, | ||
1551 | { .pci_subvendor = 0x1695, .pci_subdevice = 0x400d, .config = ALC880_5ST_DIG }, | ||
1552 | { .pci_subvendor = 0x0000, .pci_subdevice = 0x8086, .config = ALC880_5ST_DIG }, | ||
992 | 1553 | ||
993 | { .modelname = "w810", .config = ALC880_W810 }, | 1554 | { .modelname = "w810", .config = ALC880_W810 }, |
994 | { .pci_vendor = 0x161f, .pci_device = 0x203d, .config = ALC880_W810 }, | 1555 | { .pci_subvendor = 0x161f, .pci_subdevice = 0x203d, .config = ALC880_W810 }, |
1556 | |||
1557 | { .modelname = "z71v", .config = ALC880_Z71V }, | ||
1558 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1964, .config = ALC880_Z71V }, | ||
1559 | |||
1560 | { .modelname = "6statack-digout", .config = ALC880_6ST_DIG }, | ||
1561 | { .pci_subvendor = 0x2668, .pci_subdevice = 0x8086, .config = ALC880_6ST_DIG }, | ||
1562 | { .pci_subvendor = 0x8086, .pci_subdevice = 0x2668, .config = ALC880_6ST_DIG }, | ||
1563 | { .pci_subvendor = 0x1462, .pci_subdevice = 0x1150, .config = ALC880_6ST_DIG }, | ||
1564 | { .pci_subvendor = 0xe803, .pci_subdevice = 0x1019, .config = ALC880_6ST_DIG }, | ||
1565 | |||
1566 | { .modelname = "asus", .config = ALC880_ASUS }, | ||
1567 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1964, .config = ALC880_ASUS_DIG }, | ||
1568 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1973, .config = ALC880_ASUS_DIG }, | ||
1569 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x19b3, .config = ALC880_ASUS_DIG }, | ||
1570 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1113, .config = ALC880_ASUS_DIG }, | ||
1571 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1993, .config = ALC880_ASUS }, | ||
1572 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x10c3, .config = ALC880_ASUS_DIG }, | ||
1573 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1133, .config = ALC880_ASUS }, | ||
1574 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1123, .config = ALC880_ASUS_DIG }, | ||
1575 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1143, .config = ALC880_ASUS }, | ||
1576 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x10b3, .config = ALC880_ASUS_W1V }, | ||
1577 | |||
1578 | { .modelname = "uniwill", .config = ALC880_UNIWILL_DIG }, | ||
1579 | { .pci_subvendor = 0x1584, .pci_subdevice = 0x9050, .config = ALC880_UNIWILL_DIG }, | ||
1580 | |||
1581 | { .modelname = "F1734", .config = ALC880_F1734 }, | ||
1582 | { .pci_subvendor = 0x1734, .pci_subdevice = 0x107c, .config = ALC880_F1734 }, | ||
1583 | |||
1584 | #ifdef CONFIG_SND_DEBUG | ||
1585 | { .modelname = "test", .config = ALC880_TEST }, | ||
1586 | #endif | ||
995 | 1587 | ||
996 | {} | 1588 | {} |
997 | }; | 1589 | }; |
998 | 1590 | ||
1591 | /* | ||
1592 | * configuration template - to be copied to the spec instance | ||
1593 | */ | ||
1594 | struct alc_config_preset { | ||
1595 | snd_kcontrol_new_t *mixers[4]; | ||
1596 | const struct hda_verb *init_verbs[4]; | ||
1597 | unsigned int num_dacs; | ||
1598 | hda_nid_t *dac_nids; | ||
1599 | hda_nid_t dig_out_nid; /* optional */ | ||
1600 | hda_nid_t hp_nid; /* optional */ | ||
1601 | unsigned int num_adc_nids; | ||
1602 | hda_nid_t *adc_nids; | ||
1603 | unsigned int num_channel_mode; | ||
1604 | const struct alc_channel_mode *channel_mode; | ||
1605 | const struct hda_input_mux *input_mux; | ||
1606 | }; | ||
1607 | |||
1608 | static struct alc_config_preset alc880_presets[] = { | ||
1609 | [ALC880_3ST] = { | ||
1610 | .mixers = { alc880_three_stack_mixer }, | ||
1611 | .init_verbs = { alc880_volume_init_verbs, alc880_pin_3stack_init_verbs }, | ||
1612 | .num_dacs = ARRAY_SIZE(alc880_dac_nids), | ||
1613 | .dac_nids = alc880_dac_nids, | ||
1614 | .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), | ||
1615 | .channel_mode = alc880_threestack_modes, | ||
1616 | .input_mux = &alc880_capture_source, | ||
1617 | }, | ||
1618 | [ALC880_3ST_DIG] = { | ||
1619 | .mixers = { alc880_three_stack_mixer }, | ||
1620 | .init_verbs = { alc880_volume_init_verbs, alc880_pin_3stack_init_verbs }, | ||
1621 | .num_dacs = ARRAY_SIZE(alc880_dac_nids), | ||
1622 | .dac_nids = alc880_dac_nids, | ||
1623 | .dig_out_nid = ALC880_DIGOUT_NID, | ||
1624 | .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), | ||
1625 | .channel_mode = alc880_threestack_modes, | ||
1626 | .input_mux = &alc880_capture_source, | ||
1627 | }, | ||
1628 | [ALC880_5ST] = { | ||
1629 | .mixers = { alc880_three_stack_mixer, alc880_five_stack_mixer}, | ||
1630 | .init_verbs = { alc880_volume_init_verbs, alc880_pin_5stack_init_verbs }, | ||
1631 | .num_dacs = ARRAY_SIZE(alc880_dac_nids), | ||
1632 | .dac_nids = alc880_dac_nids, | ||
1633 | .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes), | ||
1634 | .channel_mode = alc880_fivestack_modes, | ||
1635 | .input_mux = &alc880_capture_source, | ||
1636 | }, | ||
1637 | [ALC880_5ST_DIG] = { | ||
1638 | .mixers = { alc880_three_stack_mixer, alc880_five_stack_mixer }, | ||
1639 | .init_verbs = { alc880_volume_init_verbs, alc880_pin_5stack_init_verbs }, | ||
1640 | .num_dacs = ARRAY_SIZE(alc880_dac_nids), | ||
1641 | .dac_nids = alc880_dac_nids, | ||
1642 | .dig_out_nid = ALC880_DIGOUT_NID, | ||
1643 | .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes), | ||
1644 | .channel_mode = alc880_fivestack_modes, | ||
1645 | .input_mux = &alc880_capture_source, | ||
1646 | }, | ||
1647 | [ALC880_6ST_DIG] = { | ||
1648 | .mixers = { alc880_six_stack_mixer }, | ||
1649 | .init_verbs = { alc880_volume_init_verbs, alc880_pin_6stack_init_verbs }, | ||
1650 | .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids), | ||
1651 | .dac_nids = alc880_6st_dac_nids, | ||
1652 | .dig_out_nid = ALC880_DIGOUT_NID, | ||
1653 | .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes), | ||
1654 | .channel_mode = alc880_sixstack_modes, | ||
1655 | .input_mux = &alc880_6stack_capture_source, | ||
1656 | }, | ||
1657 | [ALC880_W810] = { | ||
1658 | .mixers = { alc880_w810_base_mixer }, | ||
1659 | .init_verbs = { alc880_volume_init_verbs, alc880_pin_w810_init_verbs }, | ||
1660 | .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids), | ||
1661 | .dac_nids = alc880_w810_dac_nids, | ||
1662 | .dig_out_nid = ALC880_DIGOUT_NID, | ||
1663 | .num_channel_mode = ARRAY_SIZE(alc880_w810_modes), | ||
1664 | .channel_mode = alc880_w810_modes, | ||
1665 | .input_mux = &alc880_capture_source, | ||
1666 | }, | ||
1667 | [ALC880_Z71V] = { | ||
1668 | .mixers = { alc880_z71v_mixer }, | ||
1669 | .init_verbs = { alc880_volume_init_verbs, alc880_pin_z71v_init_verbs, | ||
1670 | alc880_gpio2_init_verbs }, | ||
1671 | .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids), | ||
1672 | .dac_nids = alc880_z71v_dac_nids, | ||
1673 | .dig_out_nid = ALC880_DIGOUT_NID, | ||
1674 | .hp_nid = 0x03, | ||
1675 | .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), | ||
1676 | .channel_mode = alc880_2_jack_modes, | ||
1677 | .input_mux = &alc880_capture_source, | ||
1678 | }, | ||
1679 | [ALC880_F1734] = { | ||
1680 | .mixers = { alc880_f1734_mixer }, | ||
1681 | .init_verbs = { alc880_volume_init_verbs, alc880_pin_f1734_init_verbs }, | ||
1682 | .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids), | ||
1683 | .dac_nids = alc880_f1734_dac_nids, | ||
1684 | .hp_nid = 0x02, | ||
1685 | .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), | ||
1686 | .channel_mode = alc880_2_jack_modes, | ||
1687 | .input_mux = &alc880_capture_source, | ||
1688 | }, | ||
1689 | [ALC880_ASUS] = { | ||
1690 | .mixers = { alc880_asus_mixer }, | ||
1691 | .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs, | ||
1692 | alc880_gpio1_init_verbs }, | ||
1693 | .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), | ||
1694 | .dac_nids = alc880_asus_dac_nids, | ||
1695 | .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), | ||
1696 | .channel_mode = alc880_asus_modes, | ||
1697 | .input_mux = &alc880_capture_source, | ||
1698 | }, | ||
1699 | [ALC880_ASUS_DIG] = { | ||
1700 | .mixers = { alc880_asus_mixer }, | ||
1701 | .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs, | ||
1702 | alc880_gpio1_init_verbs }, | ||
1703 | .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), | ||
1704 | .dac_nids = alc880_asus_dac_nids, | ||
1705 | .dig_out_nid = ALC880_DIGOUT_NID, | ||
1706 | .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), | ||
1707 | .channel_mode = alc880_asus_modes, | ||
1708 | .input_mux = &alc880_capture_source, | ||
1709 | }, | ||
1710 | [ALC880_ASUS_W1V] = { | ||
1711 | .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer }, | ||
1712 | .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs, | ||
1713 | alc880_gpio1_init_verbs }, | ||
1714 | .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), | ||
1715 | .dac_nids = alc880_asus_dac_nids, | ||
1716 | .dig_out_nid = ALC880_DIGOUT_NID, | ||
1717 | .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), | ||
1718 | .channel_mode = alc880_asus_modes, | ||
1719 | .input_mux = &alc880_capture_source, | ||
1720 | }, | ||
1721 | [ALC880_UNIWILL_DIG] = { | ||
1722 | .mixers = { alc880_asus_mixer }, | ||
1723 | .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs }, | ||
1724 | .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), | ||
1725 | .dac_nids = alc880_asus_dac_nids, | ||
1726 | .dig_out_nid = ALC880_DIGOUT_NID, | ||
1727 | .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), | ||
1728 | .channel_mode = alc880_asus_modes, | ||
1729 | .input_mux = &alc880_capture_source, | ||
1730 | }, | ||
1731 | #ifdef CONFIG_SND_DEBUG | ||
1732 | [ALC880_TEST] = { | ||
1733 | .mixers = { alc880_test_mixer }, | ||
1734 | .init_verbs = { alc880_test_init_verbs }, | ||
1735 | .num_dacs = ARRAY_SIZE(alc880_test_dac_nids), | ||
1736 | .dac_nids = alc880_test_dac_nids, | ||
1737 | .dig_out_nid = ALC880_DIGOUT_NID, | ||
1738 | .num_channel_mode = ARRAY_SIZE(alc880_test_modes), | ||
1739 | .channel_mode = alc880_test_modes, | ||
1740 | .input_mux = &alc880_test_capture_source, | ||
1741 | }, | ||
1742 | #endif | ||
1743 | }; | ||
1744 | |||
1745 | /* | ||
1746 | * Automatic parse of I/O pins from the BIOS configuration | ||
1747 | */ | ||
1748 | |||
1749 | #define NUM_CONTROL_ALLOC 32 | ||
1750 | #define NUM_VERB_ALLOC 32 | ||
1751 | |||
1752 | enum { | ||
1753 | ALC_CTL_WIDGET_VOL, | ||
1754 | ALC_CTL_WIDGET_MUTE, | ||
1755 | ALC_CTL_BIND_MUTE, | ||
1756 | }; | ||
1757 | static snd_kcontrol_new_t alc880_control_templates[] = { | ||
1758 | HDA_CODEC_VOLUME(NULL, 0, 0, 0), | ||
1759 | HDA_CODEC_MUTE(NULL, 0, 0, 0), | ||
1760 | ALC_BIND_MUTE(NULL, 0, 0, 0), | ||
1761 | }; | ||
1762 | |||
1763 | /* add dynamic controls */ | ||
1764 | static int add_control(struct alc_spec *spec, int type, const char *name, unsigned long val) | ||
1765 | { | ||
1766 | snd_kcontrol_new_t *knew; | ||
1767 | |||
1768 | if (spec->num_kctl_used >= spec->num_kctl_alloc) { | ||
1769 | int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC; | ||
1770 | |||
1771 | knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */ | ||
1772 | if (! knew) | ||
1773 | return -ENOMEM; | ||
1774 | if (spec->kctl_alloc) { | ||
1775 | memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc); | ||
1776 | kfree(spec->kctl_alloc); | ||
1777 | } | ||
1778 | spec->kctl_alloc = knew; | ||
1779 | spec->num_kctl_alloc = num; | ||
1780 | } | ||
1781 | |||
1782 | knew = &spec->kctl_alloc[spec->num_kctl_used]; | ||
1783 | *knew = alc880_control_templates[type]; | ||
1784 | knew->name = snd_kmalloc_strdup(name, GFP_KERNEL); | ||
1785 | if (! knew->name) | ||
1786 | return -ENOMEM; | ||
1787 | knew->private_value = val; | ||
1788 | spec->num_kctl_used++; | ||
1789 | return 0; | ||
1790 | } | ||
1791 | |||
1792 | #define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17) | ||
1793 | #define alc880_fixed_pin_idx(nid) ((nid) - 0x14) | ||
1794 | #define alc880_is_multi_pin(nid) ((nid) >= 0x18) | ||
1795 | #define alc880_multi_pin_idx(nid) ((nid) - 0x18) | ||
1796 | #define alc880_is_input_pin(nid) ((nid) >= 0x18) | ||
1797 | #define alc880_input_pin_idx(nid) ((nid) - 0x18) | ||
1798 | #define alc880_idx_to_dac(nid) ((nid) + 0x02) | ||
1799 | #define alc880_dac_to_idx(nid) ((nid) - 0x02) | ||
1800 | #define alc880_idx_to_mixer(nid) ((nid) + 0x0c) | ||
1801 | #define alc880_idx_to_selector(nid) ((nid) + 0x10) | ||
1802 | #define ALC880_PIN_CD_NID 0x1c | ||
1803 | |||
1804 | /* fill in the dac_nids table from the parsed pin configuration */ | ||
1805 | static int alc880_auto_fill_dac_nids(struct alc_spec *spec, const struct auto_pin_cfg *cfg) | ||
1806 | { | ||
1807 | hda_nid_t nid; | ||
1808 | int assigned[4]; | ||
1809 | int i, j; | ||
1810 | |||
1811 | memset(assigned, 0, sizeof(assigned)); | ||
1812 | |||
1813 | /* check the pins hardwired to audio widget */ | ||
1814 | for (i = 0; i < cfg->line_outs; i++) { | ||
1815 | nid = cfg->line_out_pins[i]; | ||
1816 | if (alc880_is_fixed_pin(nid)) { | ||
1817 | int idx = alc880_fixed_pin_idx(nid); | ||
1818 | spec->multiout.dac_nids[i] = alc880_dac_to_idx(idx); | ||
1819 | assigned[idx] = 1; | ||
1820 | } | ||
1821 | } | ||
1822 | /* left pins can be connect to any audio widget */ | ||
1823 | for (i = 0; i < cfg->line_outs; i++) { | ||
1824 | nid = cfg->line_out_pins[i]; | ||
1825 | if (alc880_is_fixed_pin(nid)) | ||
1826 | continue; | ||
1827 | /* search for an empty channel */ | ||
1828 | for (j = 0; j < cfg->line_outs; j++) { | ||
1829 | if (! assigned[j]) { | ||
1830 | spec->multiout.dac_nids[i] = alc880_idx_to_dac(j); | ||
1831 | assigned[j] = 1; | ||
1832 | break; | ||
1833 | } | ||
1834 | } | ||
1835 | } | ||
1836 | spec->multiout.num_dacs = cfg->line_outs; | ||
1837 | return 0; | ||
1838 | } | ||
1839 | |||
1840 | /* add playback controls from the parsed DAC table */ | ||
1841 | static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg) | ||
1842 | { | ||
1843 | char name[32]; | ||
1844 | static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" }; | ||
1845 | hda_nid_t nid; | ||
1846 | int i, err; | ||
1847 | |||
1848 | for (i = 0; i < cfg->line_outs; i++) { | ||
1849 | if (! spec->multiout.dac_nids[i]) | ||
1850 | continue; | ||
1851 | nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i])); | ||
1852 | if (i == 2) { | ||
1853 | /* Center/LFE */ | ||
1854 | if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Center Playback Volume", | ||
1855 | HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT))) < 0) | ||
1856 | return err; | ||
1857 | if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "LFE Playback Volume", | ||
1858 | HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0) | ||
1859 | return err; | ||
1860 | if ((err = add_control(spec, ALC_CTL_BIND_MUTE, "Center Playback Switch", | ||
1861 | HDA_COMPOSE_AMP_VAL(nid, 1, 2, HDA_INPUT))) < 0) | ||
1862 | return err; | ||
1863 | if ((err = add_control(spec, ALC_CTL_BIND_MUTE, "LFE Playback Switch", | ||
1864 | HDA_COMPOSE_AMP_VAL(nid, 2, 2, HDA_INPUT))) < 0) | ||
1865 | return err; | ||
1866 | } else { | ||
1867 | sprintf(name, "%s Playback Volume", chname[i]); | ||
1868 | if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, name, | ||
1869 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) | ||
1870 | return err; | ||
1871 | sprintf(name, "%s Playback Switch", chname[i]); | ||
1872 | if ((err = add_control(spec, ALC_CTL_BIND_MUTE, name, | ||
1873 | HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT))) < 0) | ||
1874 | return err; | ||
1875 | } | ||
1876 | } | ||
1877 | |||
1878 | return 0; | ||
1879 | } | ||
1880 | |||
1881 | /* add playback controls for HP output */ | ||
1882 | static int alc880_auto_create_hp_ctls(struct alc_spec *spec, hda_nid_t pin) | ||
1883 | { | ||
1884 | hda_nid_t nid; | ||
1885 | int err; | ||
1886 | |||
1887 | if (! pin) | ||
1888 | return 0; | ||
1889 | |||
1890 | if (alc880_is_fixed_pin(pin)) { | ||
1891 | nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin)); | ||
1892 | if (! spec->multiout.dac_nids[0]) { | ||
1893 | /* use this as the primary output */ | ||
1894 | spec->multiout.dac_nids[0] = nid; | ||
1895 | if (! spec->multiout.num_dacs) | ||
1896 | spec->multiout.num_dacs = 1; | ||
1897 | } else | ||
1898 | /* specify the DAC as the extra HP output */ | ||
1899 | spec->multiout.hp_nid = nid; | ||
1900 | /* control HP volume/switch on the output mixer amp */ | ||
1901 | nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin)); | ||
1902 | if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Headphone Playback Volume", | ||
1903 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) | ||
1904 | return err; | ||
1905 | if ((err = add_control(spec, ALC_CTL_BIND_MUTE, "Headphone Playback Switch", | ||
1906 | HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT))) < 0) | ||
1907 | return err; | ||
1908 | } else if (alc880_is_multi_pin(pin)) { | ||
1909 | /* set manual connection */ | ||
1910 | if (! spec->multiout.dac_nids[0]) { | ||
1911 | /* use this as the primary output */ | ||
1912 | spec->multiout.dac_nids[0] = alc880_idx_to_dac(alc880_multi_pin_idx(pin)); | ||
1913 | if (! spec->multiout.num_dacs) | ||
1914 | spec->multiout.num_dacs = 1; | ||
1915 | } | ||
1916 | /* we have only a switch on HP-out PIN */ | ||
1917 | if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, "Headphone Playback Switch", | ||
1918 | HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT))) < 0) | ||
1919 | return err; | ||
1920 | } | ||
1921 | return 0; | ||
1922 | } | ||
1923 | |||
1924 | /* create input playback/capture controls for the given pin */ | ||
1925 | static int new_analog_input(struct alc_spec *spec, hda_nid_t pin, const char *ctlname) | ||
1926 | { | ||
1927 | char name[32]; | ||
1928 | int err, idx; | ||
1929 | |||
1930 | sprintf(name, "%s Playback Volume", ctlname); | ||
1931 | idx = alc880_input_pin_idx(pin); | ||
1932 | if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, name, | ||
1933 | HDA_COMPOSE_AMP_VAL(0x0b, 3, idx, HDA_INPUT))) < 0) | ||
1934 | return err; | ||
1935 | sprintf(name, "%s Playback Switch", ctlname); | ||
1936 | if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, | ||
1937 | HDA_COMPOSE_AMP_VAL(0x0b, 3, idx, HDA_INPUT))) < 0) | ||
1938 | return err; | ||
1939 | return 0; | ||
1940 | } | ||
1941 | |||
1942 | /* create playback/capture controls for input pins */ | ||
1943 | static int alc880_auto_create_analog_input_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg) | ||
1944 | { | ||
1945 | static char *labels[AUTO_PIN_LAST] = { | ||
1946 | "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux" | ||
1947 | }; | ||
1948 | struct hda_input_mux *imux = &spec->private_imux; | ||
1949 | int i, err; | ||
1950 | |||
1951 | for (i = 0; i < AUTO_PIN_LAST; i++) { | ||
1952 | if (alc880_is_input_pin(cfg->input_pins[i])) { | ||
1953 | err = new_analog_input(spec, cfg->input_pins[i], labels[i]); | ||
1954 | if (err < 0) | ||
1955 | return err; | ||
1956 | imux->items[imux->num_items].label = labels[i]; | ||
1957 | imux->items[imux->num_items].index = alc880_input_pin_idx(cfg->input_pins[i]); | ||
1958 | imux->num_items++; | ||
1959 | } | ||
1960 | } | ||
1961 | return 0; | ||
1962 | } | ||
1963 | |||
1964 | static void alc880_auto_set_output_and_unmute(struct hda_codec *codec, hda_nid_t nid, int pin_type, | ||
1965 | int dac_idx) | ||
1966 | { | ||
1967 | /* set as output */ | ||
1968 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type); | ||
1969 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); | ||
1970 | /* need the manual connection? */ | ||
1971 | if (alc880_is_multi_pin(nid)) { | ||
1972 | struct alc_spec *spec = codec->spec; | ||
1973 | int idx = alc880_multi_pin_idx(nid); | ||
1974 | snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0, | ||
1975 | AC_VERB_SET_CONNECT_SEL, | ||
1976 | alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx])); | ||
1977 | } | ||
1978 | } | ||
1979 | |||
1980 | static void alc880_auto_init_multi_out(struct hda_codec *codec) | ||
1981 | { | ||
1982 | struct alc_spec *spec = codec->spec; | ||
1983 | int i; | ||
1984 | |||
1985 | for (i = 0; i < spec->autocfg.line_outs; i++) { | ||
1986 | hda_nid_t nid = spec->autocfg.line_out_pins[i]; | ||
1987 | alc880_auto_set_output_and_unmute(codec, nid, PIN_OUT, i); | ||
1988 | } | ||
1989 | } | ||
1990 | |||
1991 | static void alc880_auto_init_hp_out(struct hda_codec *codec) | ||
1992 | { | ||
1993 | struct alc_spec *spec = codec->spec; | ||
1994 | hda_nid_t pin; | ||
1995 | |||
1996 | pin = spec->autocfg.hp_pin; | ||
1997 | if (pin) /* connect to front */ | ||
1998 | alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); | ||
1999 | } | ||
2000 | |||
2001 | static void alc880_auto_init_analog_input(struct hda_codec *codec) | ||
2002 | { | ||
2003 | struct alc_spec *spec = codec->spec; | ||
2004 | int i; | ||
2005 | |||
2006 | for (i = 0; i < AUTO_PIN_LAST; i++) { | ||
2007 | hda_nid_t nid = spec->autocfg.input_pins[i]; | ||
2008 | if (alc880_is_input_pin(nid)) { | ||
2009 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
2010 | i <= AUTO_PIN_FRONT_MIC ? PIN_VREF80 : PIN_IN); | ||
2011 | if (nid != ALC880_PIN_CD_NID) | ||
2012 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, | ||
2013 | AMP_OUT_MUTE); | ||
2014 | } | ||
2015 | } | ||
2016 | } | ||
2017 | |||
2018 | /* parse the BIOS configuration and set up the alc_spec */ | ||
2019 | /* return 1 if successful, 0 if the proper config is not found, or a negative error code */ | ||
2020 | static int alc880_parse_auto_config(struct hda_codec *codec) | ||
2021 | { | ||
2022 | struct alc_spec *spec = codec->spec; | ||
2023 | int err; | ||
2024 | |||
2025 | if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg)) < 0) | ||
2026 | return err; | ||
2027 | if ((err = alc880_auto_fill_dac_nids(spec, &spec->autocfg)) < 0) | ||
2028 | return err; | ||
2029 | if (! spec->autocfg.line_outs && ! spec->autocfg.hp_pin) | ||
2030 | return 0; /* can't find valid BIOS pin config */ | ||
2031 | if ((err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 || | ||
2032 | (err = alc880_auto_create_hp_ctls(spec, spec->autocfg.hp_pin)) < 0 || | ||
2033 | (err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0) | ||
2034 | return err; | ||
2035 | |||
2036 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; | ||
2037 | |||
2038 | if (spec->autocfg.dig_out_pin) | ||
2039 | spec->multiout.dig_out_nid = ALC880_DIGOUT_NID; | ||
2040 | if (spec->autocfg.dig_in_pin) | ||
2041 | spec->dig_in_nid = ALC880_DIGIN_NID; | ||
2042 | |||
2043 | if (spec->kctl_alloc) | ||
2044 | spec->mixers[spec->num_mixers++] = spec->kctl_alloc; | ||
2045 | |||
2046 | spec->init_verbs[spec->num_init_verbs++] = alc880_volume_init_verbs; | ||
2047 | |||
2048 | spec->input_mux = &spec->private_imux; | ||
2049 | |||
2050 | return 1; | ||
2051 | } | ||
2052 | |||
2053 | /* init callback for auto-configuration model -- overriding the default init */ | ||
2054 | static int alc880_auto_init(struct hda_codec *codec) | ||
2055 | { | ||
2056 | alc_init(codec); | ||
2057 | alc880_auto_init_multi_out(codec); | ||
2058 | alc880_auto_init_hp_out(codec); | ||
2059 | alc880_auto_init_analog_input(codec); | ||
2060 | return 0; | ||
2061 | } | ||
2062 | |||
2063 | /* | ||
2064 | * OK, here we have finally the patch for ALC880 | ||
2065 | */ | ||
2066 | |||
999 | static int patch_alc880(struct hda_codec *codec) | 2067 | static int patch_alc880(struct hda_codec *codec) |
1000 | { | 2068 | { |
1001 | struct alc_spec *spec; | 2069 | struct alc_spec *spec; |
1002 | int board_config; | 2070 | int board_config; |
2071 | int i, err; | ||
1003 | 2072 | ||
1004 | spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); | 2073 | spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); |
1005 | if (spec == NULL) | 2074 | if (spec == NULL) |
1006 | return -ENOMEM; | 2075 | return -ENOMEM; |
1007 | 2076 | ||
2077 | init_MUTEX(&spec->bind_mutex); | ||
1008 | codec->spec = spec; | 2078 | codec->spec = spec; |
1009 | 2079 | ||
1010 | board_config = snd_hda_check_board_config(codec, alc880_cfg_tbl); | 2080 | board_config = snd_hda_check_board_config(codec, alc880_cfg_tbl); |
1011 | if (board_config < 0) { | 2081 | if (board_config < 0 || board_config >= ALC880_MODEL_LAST) { |
1012 | snd_printd(KERN_INFO "hda_codec: Unknown model for ALC880\n"); | 2082 | printk(KERN_INFO "hda_codec: Unknown model for ALC880, trying auto-probe from BIOS...\n"); |
1013 | board_config = ALC880_MINIMAL; | 2083 | board_config = ALC880_AUTO; |
1014 | } | 2084 | } |
1015 | 2085 | ||
1016 | switch (board_config) { | 2086 | if (board_config == ALC880_AUTO) { |
1017 | case ALC880_W810: | 2087 | /* automatic parse from the BIOS config */ |
1018 | spec->mixers[spec->num_mixers] = alc880_w810_base_mixer; | 2088 | err = alc880_parse_auto_config(codec); |
1019 | spec->num_mixers++; | 2089 | if (err < 0) { |
1020 | break; | 2090 | alc_free(codec); |
1021 | case ALC880_5ST: | 2091 | return err; |
1022 | case ALC880_5ST_DIG: | 2092 | } else if (! err) { |
1023 | spec->mixers[spec->num_mixers] = alc880_five_stack_mixer; | 2093 | printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS. Using 3-stack mode...\n"); |
1024 | spec->num_mixers++; | 2094 | board_config = ALC880_3ST; |
1025 | break; | 2095 | } |
1026 | default: | ||
1027 | spec->mixers[spec->num_mixers] = alc880_base_mixer; | ||
1028 | spec->num_mixers++; | ||
1029 | break; | ||
1030 | } | 2096 | } |
1031 | 2097 | ||
1032 | switch (board_config) { | 2098 | if (board_config != ALC880_AUTO) { |
1033 | case ALC880_3ST_DIG: | 2099 | /* set up from the preset table */ |
1034 | case ALC880_5ST_DIG: | 2100 | const struct alc_config_preset *preset; |
1035 | case ALC880_W810: | ||
1036 | spec->multiout.dig_out_nid = ALC880_DIGOUT_NID; | ||
1037 | break; | ||
1038 | default: | ||
1039 | break; | ||
1040 | } | ||
1041 | 2101 | ||
1042 | switch (board_config) { | 2102 | preset = &alc880_presets[board_config]; |
1043 | case ALC880_3ST: | ||
1044 | case ALC880_3ST_DIG: | ||
1045 | case ALC880_5ST: | ||
1046 | case ALC880_5ST_DIG: | ||
1047 | case ALC880_W810: | ||
1048 | spec->front_panel = 1; | ||
1049 | break; | ||
1050 | default: | ||
1051 | break; | ||
1052 | } | ||
1053 | 2103 | ||
1054 | switch (board_config) { | 2104 | for (i = 0; preset->mixers[i]; i++) { |
1055 | case ALC880_5ST: | 2105 | snd_assert(spec->num_mixers < ARRAY_SIZE(spec->mixers), break); |
1056 | case ALC880_5ST_DIG: | 2106 | spec->mixers[spec->num_mixers++] = preset->mixers[i]; |
1057 | spec->init_verbs = alc880_init_verbs_five_stack; | 2107 | } |
1058 | spec->channel_mode = alc880_fivestack_modes; | 2108 | for (i = 0; preset->init_verbs[i]; i++) { |
1059 | spec->num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes); | 2109 | snd_assert(spec->num_init_verbs < ARRAY_SIZE(spec->init_verbs), break); |
1060 | break; | 2110 | spec->init_verbs[spec->num_init_verbs++] = preset->init_verbs[i]; |
1061 | case ALC880_W810: | 2111 | } |
1062 | spec->init_verbs = alc880_w810_init_verbs; | 2112 | |
1063 | spec->channel_mode = alc880_w810_modes; | 2113 | spec->channel_mode = preset->channel_mode; |
1064 | spec->num_channel_mode = ARRAY_SIZE(alc880_w810_modes); | 2114 | spec->num_channel_mode = preset->num_channel_mode; |
1065 | break; | 2115 | |
1066 | default: | 2116 | spec->multiout.max_channels = spec->channel_mode[0].channels; |
1067 | spec->init_verbs = alc880_init_verbs_three_stack; | 2117 | |
1068 | spec->channel_mode = alc880_threestack_modes; | 2118 | spec->multiout.num_dacs = preset->num_dacs; |
1069 | spec->num_channel_mode = ARRAY_SIZE(alc880_threestack_modes); | 2119 | spec->multiout.dac_nids = preset->dac_nids; |
1070 | break; | 2120 | spec->multiout.dig_out_nid = preset->dig_out_nid; |
2121 | spec->multiout.hp_nid = preset->hp_nid; | ||
2122 | |||
2123 | spec->input_mux = preset->input_mux; | ||
2124 | |||
2125 | spec->num_adc_nids = preset->num_adc_nids; | ||
2126 | spec->adc_nids = preset->adc_nids; | ||
1071 | } | 2127 | } |
1072 | 2128 | ||
1073 | spec->stream_name_analog = "ALC880 Analog"; | 2129 | spec->stream_name_analog = "ALC880 Analog"; |
@@ -1078,34 +2134,64 @@ static int patch_alc880(struct hda_codec *codec) | |||
1078 | spec->stream_digital_playback = &alc880_pcm_digital_playback; | 2134 | spec->stream_digital_playback = &alc880_pcm_digital_playback; |
1079 | spec->stream_digital_capture = &alc880_pcm_digital_capture; | 2135 | spec->stream_digital_capture = &alc880_pcm_digital_capture; |
1080 | 2136 | ||
1081 | spec->multiout.max_channels = spec->channel_mode[0].channels; | 2137 | if (! spec->adc_nids && spec->input_mux) { |
1082 | 2138 | /* check whether NID 0x07 is valid */ | |
1083 | switch (board_config) { | 2139 | unsigned int wcap = snd_hda_param_read(codec, alc880_adc_nids[0], |
1084 | case ALC880_W810: | 2140 | AC_PAR_AUDIO_WIDGET_CAP); |
1085 | spec->multiout.num_dacs = ARRAY_SIZE(alc880_w810_dac_nids); | 2141 | wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; /* get type */ |
1086 | spec->multiout.dac_nids = alc880_w810_dac_nids; | 2142 | if (wcap != AC_WID_AUD_IN) { |
1087 | // No dedicated headphone socket - it's shared with built-in speakers. | 2143 | spec->adc_nids = alc880_adc_nids_alt; |
1088 | break; | 2144 | spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt); |
1089 | default: | 2145 | spec->mixers[spec->num_mixers] = alc880_capture_alt_mixer; |
1090 | spec->multiout.num_dacs = ARRAY_SIZE(alc880_dac_nids); | 2146 | spec->num_mixers++; |
1091 | spec->multiout.dac_nids = alc880_dac_nids; | 2147 | } else { |
1092 | spec->multiout.hp_nid = 0x03; /* rear-surround NID */ | 2148 | spec->adc_nids = alc880_adc_nids; |
1093 | break; | 2149 | spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids); |
2150 | spec->mixers[spec->num_mixers] = alc880_capture_mixer; | ||
2151 | spec->num_mixers++; | ||
2152 | } | ||
1094 | } | 2153 | } |
1095 | 2154 | ||
1096 | spec->input_mux = &alc880_capture_source; | ||
1097 | spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids); | ||
1098 | spec->adc_nids = alc880_adc_nids; | ||
1099 | |||
1100 | codec->patch_ops = alc_patch_ops; | 2155 | codec->patch_ops = alc_patch_ops; |
2156 | if (board_config == ALC880_AUTO) | ||
2157 | codec->patch_ops.init = alc880_auto_init; | ||
1101 | 2158 | ||
1102 | return 0; | 2159 | return 0; |
1103 | } | 2160 | } |
1104 | 2161 | ||
2162 | |||
1105 | /* | 2163 | /* |
1106 | * ALC260 support | 2164 | * ALC260 support |
1107 | */ | 2165 | */ |
1108 | 2166 | ||
2167 | static hda_nid_t alc260_dac_nids[1] = { | ||
2168 | /* front */ | ||
2169 | 0x02, | ||
2170 | }; | ||
2171 | |||
2172 | static hda_nid_t alc260_adc_nids[1] = { | ||
2173 | /* ADC0 */ | ||
2174 | 0x04, | ||
2175 | }; | ||
2176 | |||
2177 | static hda_nid_t alc260_hp_adc_nids[1] = { | ||
2178 | /* ADC1 */ | ||
2179 | 0x05, | ||
2180 | }; | ||
2181 | |||
2182 | #define ALC260_DIGOUT_NID 0x03 | ||
2183 | #define ALC260_DIGIN_NID 0x06 | ||
2184 | |||
2185 | static struct hda_input_mux alc260_capture_source = { | ||
2186 | .num_items = 4, | ||
2187 | .items = { | ||
2188 | { "Mic", 0x0 }, | ||
2189 | { "Front Mic", 0x1 }, | ||
2190 | { "Line", 0x2 }, | ||
2191 | { "CD", 0x4 }, | ||
2192 | }, | ||
2193 | }; | ||
2194 | |||
1109 | /* | 2195 | /* |
1110 | * This is just place-holder, so there's something for alc_build_pcms to look | 2196 | * This is just place-holder, so there's something for alc_build_pcms to look |
1111 | * at when it calculates the maximum number of channels. ALC260 has no mixer | 2197 | * at when it calculates the maximum number of channels. ALC260 has no mixer |
@@ -1116,11 +2202,9 @@ static struct alc_channel_mode alc260_modes[1] = { | |||
1116 | { 2, NULL }, | 2202 | { 2, NULL }, |
1117 | }; | 2203 | }; |
1118 | 2204 | ||
1119 | snd_kcontrol_new_t alc260_base_mixer[] = { | 2205 | static snd_kcontrol_new_t alc260_base_mixer[] = { |
1120 | HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT), | 2206 | HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT), |
1121 | /* use LINE2 for the output */ | 2207 | ALC_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT), |
1122 | /* HDA_CODEC_MUTE("Front Playback Switch", 0x0f, 0x0, HDA_OUTPUT), */ | ||
1123 | HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT), | ||
1124 | HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), | 2208 | HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), |
1125 | HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), | 2209 | HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), |
1126 | HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), | 2210 | HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), |
@@ -1132,9 +2216,9 @@ snd_kcontrol_new_t alc260_base_mixer[] = { | |||
1132 | HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x07, 0x05, HDA_INPUT), | 2216 | HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x07, 0x05, HDA_INPUT), |
1133 | HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x07, 0x05, HDA_INPUT), | 2217 | HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x07, 0x05, HDA_INPUT), |
1134 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT), | 2218 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT), |
1135 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT), | 2219 | ALC_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT), |
1136 | HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), | 2220 | HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), |
1137 | HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT), | 2221 | ALC_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_OUTPUT), |
1138 | HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT), | 2222 | HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT), |
1139 | HDA_CODEC_MUTE("Capture Switch", 0x04, 0x0, HDA_INPUT), | 2223 | HDA_CODEC_MUTE("Capture Switch", 0x04, 0x0, HDA_INPUT), |
1140 | { | 2224 | { |
@@ -1147,60 +2231,91 @@ snd_kcontrol_new_t alc260_base_mixer[] = { | |||
1147 | { } /* end */ | 2231 | { } /* end */ |
1148 | }; | 2232 | }; |
1149 | 2233 | ||
2234 | static snd_kcontrol_new_t alc260_hp_mixer[] = { | ||
2235 | HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT), | ||
2236 | ALC_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT), | ||
2237 | HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), | ||
2238 | HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), | ||
2239 | HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), | ||
2240 | HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT), | ||
2241 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), | ||
2242 | HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT), | ||
2243 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT), | ||
2244 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT), | ||
2245 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT), | ||
2246 | ALC_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT), | ||
2247 | HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), | ||
2248 | ALC_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_OUTPUT), | ||
2249 | HDA_CODEC_VOLUME("Capture Volume", 0x05, 0x0, HDA_INPUT), | ||
2250 | HDA_CODEC_MUTE("Capture Switch", 0x05, 0x0, HDA_INPUT), | ||
2251 | { | ||
2252 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2253 | .name = "Capture Source", | ||
2254 | .info = alc_mux_enum_info, | ||
2255 | .get = alc_mux_enum_get, | ||
2256 | .put = alc_mux_enum_put, | ||
2257 | }, | ||
2258 | { } /* end */ | ||
2259 | }; | ||
2260 | |||
1150 | static struct hda_verb alc260_init_verbs[] = { | 2261 | static struct hda_verb alc260_init_verbs[] = { |
1151 | /* Line In pin widget for input */ | 2262 | /* Line In pin widget for input */ |
1152 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, | 2263 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, |
1153 | /* CD pin widget for input */ | 2264 | /* CD pin widget for input */ |
1154 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, | 2265 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, |
1155 | /* Mic1 (rear panel) pin widget for input and vref at 80% */ | 2266 | /* Mic1 (rear panel) pin widget for input and vref at 80% */ |
1156 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, | 2267 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, |
1157 | /* Mic2 (front panel) pin widget for input and vref at 80% */ | 2268 | /* Mic2 (front panel) pin widget for input and vref at 80% */ |
1158 | {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, | 2269 | {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, |
1159 | /* LINE-2 is used for line-out in rear */ | 2270 | /* LINE-2 is used for line-out in rear */ |
1160 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | 2271 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, |
1161 | /* select line-out */ | 2272 | /* select line-out */ |
1162 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, | 2273 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, |
1163 | /* LINE-OUT pin */ | 2274 | /* LINE-OUT pin */ |
1164 | {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | 2275 | {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, |
1165 | /* enable HP */ | 2276 | /* enable HP */ |
1166 | {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | 2277 | {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, |
1167 | /* enable Mono */ | 2278 | /* enable Mono */ |
1168 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | 2279 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, |
1169 | /* unmute amp left and right */ | 2280 | /* mute capture amp left and right */ |
1170 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, | 2281 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
1171 | /* set connection select to line in (default select for this ADC) */ | 2282 | /* set connection select to line in (default select for this ADC) */ |
1172 | {0x04, AC_VERB_SET_CONNECT_SEL, 0x02}, | 2283 | {0x04, AC_VERB_SET_CONNECT_SEL, 0x02}, |
1173 | /* unmute Line-Out mixer amp left and right (volume = 0) */ | 2284 | /* mute capture amp left and right */ |
1174 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | 2285 | {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
1175 | /* mute pin widget amp left and right (no gain on this amp) */ | 2286 | /* set connection select to line in (default select for this ADC) */ |
1176 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | 2287 | {0x05, AC_VERB_SET_CONNECT_SEL, 0x02}, |
1177 | /* unmute HP mixer amp left and right (volume = 0) */ | 2288 | /* set vol=0 Line-Out mixer amp left and right */ |
1178 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | 2289 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, |
1179 | /* mute pin widget amp left and right (no gain on this amp) */ | 2290 | /* unmute pin widget amp left and right (no gain on this amp) */ |
1180 | {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | 2291 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, |
1181 | /* unmute Mono mixer amp left and right (volume = 0) */ | 2292 | /* set vol=0 HP mixer amp left and right */ |
1182 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | 2293 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, |
1183 | /* mute pin widget amp left and right (no gain on this amp) */ | 2294 | /* unmute pin widget amp left and right (no gain on this amp) */ |
1184 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | 2295 | {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, |
1185 | /* mute LINE-2 out */ | 2296 | /* set vol=0 Mono mixer amp left and right */ |
1186 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | 2297 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, |
2298 | /* unmute pin widget amp left and right (no gain on this amp) */ | ||
2299 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2300 | /* unmute LINE-2 out pin */ | ||
2301 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
1187 | /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03 */ | 2302 | /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03 */ |
1188 | /* unmute CD */ | 2303 | /* mute CD */ |
1189 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, | 2304 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, |
1190 | /* unmute Line In */ | 2305 | /* mute Line In */ |
1191 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, | 2306 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, |
1192 | /* unmute Mic */ | 2307 | /* mute Mic */ |
1193 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | 2308 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
1194 | /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ | 2309 | /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ |
1195 | /* Unmute Front out path */ | 2310 | /* mute Front out path */ |
1196 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | 2311 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, |
1197 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | 2312 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, |
1198 | /* Unmute Headphone out path */ | 2313 | /* mute Headphone out path */ |
1199 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | 2314 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, |
1200 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | 2315 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, |
1201 | /* Unmute Mono out path */ | 2316 | /* mute Mono out path */ |
1202 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | 2317 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, |
1203 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | 2318 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, |
1204 | { } | 2319 | { } |
1205 | }; | 2320 | }; |
1206 | 2321 | ||
@@ -1208,30 +2323,52 @@ static struct hda_pcm_stream alc260_pcm_analog_playback = { | |||
1208 | .substreams = 1, | 2323 | .substreams = 1, |
1209 | .channels_min = 2, | 2324 | .channels_min = 2, |
1210 | .channels_max = 2, | 2325 | .channels_max = 2, |
1211 | .nid = 0x2, | ||
1212 | }; | 2326 | }; |
1213 | 2327 | ||
1214 | static struct hda_pcm_stream alc260_pcm_analog_capture = { | 2328 | static struct hda_pcm_stream alc260_pcm_analog_capture = { |
1215 | .substreams = 1, | 2329 | .substreams = 1, |
1216 | .channels_min = 2, | 2330 | .channels_min = 2, |
1217 | .channels_max = 2, | 2331 | .channels_max = 2, |
1218 | .nid = 0x4, | 2332 | }; |
2333 | |||
2334 | static struct hda_board_config alc260_cfg_tbl[] = { | ||
2335 | { .modelname = "hp", .config = ALC260_HP }, | ||
2336 | { .pci_subvendor = 0x103c, .config = ALC260_HP }, | ||
2337 | {} | ||
1219 | }; | 2338 | }; |
1220 | 2339 | ||
1221 | static int patch_alc260(struct hda_codec *codec) | 2340 | static int patch_alc260(struct hda_codec *codec) |
1222 | { | 2341 | { |
1223 | struct alc_spec *spec; | 2342 | struct alc_spec *spec; |
2343 | int board_config; | ||
1224 | 2344 | ||
1225 | spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); | 2345 | spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); |
1226 | if (spec == NULL) | 2346 | if (spec == NULL) |
1227 | return -ENOMEM; | 2347 | return -ENOMEM; |
1228 | 2348 | ||
2349 | init_MUTEX(&spec->bind_mutex); | ||
1229 | codec->spec = spec; | 2350 | codec->spec = spec; |
1230 | 2351 | ||
1231 | spec->mixers[spec->num_mixers] = alc260_base_mixer; | 2352 | board_config = snd_hda_check_board_config(codec, alc260_cfg_tbl); |
1232 | spec->num_mixers++; | 2353 | if (board_config < 0 || board_config >= ALC260_MODEL_LAST) { |
2354 | snd_printd(KERN_INFO "hda_codec: Unknown model for ALC260\n"); | ||
2355 | board_config = ALC260_BASIC; | ||
2356 | } | ||
2357 | |||
2358 | switch (board_config) { | ||
2359 | case ALC260_HP: | ||
2360 | spec->mixers[spec->num_mixers] = alc260_hp_mixer; | ||
2361 | spec->num_mixers++; | ||
2362 | break; | ||
2363 | default: | ||
2364 | spec->mixers[spec->num_mixers] = alc260_base_mixer; | ||
2365 | spec->num_mixers++; | ||
2366 | break; | ||
2367 | } | ||
2368 | |||
2369 | spec->init_verbs[0] = alc260_init_verbs; | ||
2370 | spec->num_init_verbs = 1; | ||
1233 | 2371 | ||
1234 | spec->init_verbs = alc260_init_verbs; | ||
1235 | spec->channel_mode = alc260_modes; | 2372 | spec->channel_mode = alc260_modes; |
1236 | spec->num_channel_mode = ARRAY_SIZE(alc260_modes); | 2373 | spec->num_channel_mode = ARRAY_SIZE(alc260_modes); |
1237 | 2374 | ||
@@ -1244,14 +2381,23 @@ static int patch_alc260(struct hda_codec *codec) | |||
1244 | spec->multiout.dac_nids = alc260_dac_nids; | 2381 | spec->multiout.dac_nids = alc260_dac_nids; |
1245 | 2382 | ||
1246 | spec->input_mux = &alc260_capture_source; | 2383 | spec->input_mux = &alc260_capture_source; |
1247 | spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids); | 2384 | switch (board_config) { |
1248 | spec->adc_nids = alc260_adc_nids; | 2385 | case ALC260_HP: |
2386 | spec->num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids); | ||
2387 | spec->adc_nids = alc260_hp_adc_nids; | ||
2388 | break; | ||
2389 | default: | ||
2390 | spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids); | ||
2391 | spec->adc_nids = alc260_adc_nids; | ||
2392 | break; | ||
2393 | } | ||
1249 | 2394 | ||
1250 | codec->patch_ops = alc_patch_ops; | 2395 | codec->patch_ops = alc_patch_ops; |
1251 | 2396 | ||
1252 | return 0; | 2397 | return 0; |
1253 | } | 2398 | } |
1254 | 2399 | ||
2400 | |||
1255 | /* | 2401 | /* |
1256 | * ALC882 support | 2402 | * ALC882 support |
1257 | * | 2403 | * |
@@ -1324,15 +2470,15 @@ static int alc882_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *u | |||
1324 | */ | 2470 | */ |
1325 | static snd_kcontrol_new_t alc882_base_mixer[] = { | 2471 | static snd_kcontrol_new_t alc882_base_mixer[] = { |
1326 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | 2472 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), |
1327 | HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), | 2473 | ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), |
1328 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), | 2474 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), |
1329 | HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT), | 2475 | ALC_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), |
1330 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), | 2476 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), |
1331 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), | 2477 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), |
1332 | HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x16, 1, 0x0, HDA_OUTPUT), | 2478 | ALC_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), |
1333 | HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), | 2479 | ALC_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_OUTPUT), |
1334 | HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), | 2480 | HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), |
1335 | HDA_CODEC_MUTE("Side Playback Switch", 0x17, 0x0, HDA_OUTPUT), | 2481 | ALC_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), |
1336 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | 2482 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), |
1337 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), | 2483 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), |
1338 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), | 2484 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), |
@@ -1364,89 +2510,80 @@ static snd_kcontrol_new_t alc882_base_mixer[] = { | |||
1364 | 2510 | ||
1365 | static struct hda_verb alc882_init_verbs[] = { | 2511 | static struct hda_verb alc882_init_verbs[] = { |
1366 | /* Front mixer: unmute input/output amp left and right (volume = 0) */ | 2512 | /* Front mixer: unmute input/output amp left and right (volume = 0) */ |
1367 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | 2513 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, |
1368 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | 2514 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, |
2515 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
1369 | /* Rear mixer */ | 2516 | /* Rear mixer */ |
1370 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | 2517 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, |
1371 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | 2518 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, |
2519 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
1372 | /* CLFE mixer */ | 2520 | /* CLFE mixer */ |
1373 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | 2521 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, |
1374 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | 2522 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, |
2523 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
1375 | /* Side mixer */ | 2524 | /* Side mixer */ |
1376 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | 2525 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, |
1377 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | 2526 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, |
1378 | 2527 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | |
1379 | /* Front Pin: to output mode */ | 2528 | |
1380 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | 2529 | /* Front Pin: output 0 (0x0c) */ |
1381 | /* Front Pin: mute amp left and right (no volume) */ | 2530 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, |
1382 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, | 2531 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, |
1383 | /* select Front mixer (0x0c, index 0) */ | ||
1384 | {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, | 2532 | {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, |
1385 | /* Rear Pin */ | 2533 | /* Rear Pin: output 1 (0x0d) */ |
1386 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | 2534 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, |
1387 | /* Rear Pin: mute amp left and right (no volume) */ | 2535 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, |
1388 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, | ||
1389 | /* select Rear mixer (0x0d, index 1) */ | ||
1390 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, | 2536 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, |
1391 | /* CLFE Pin */ | 2537 | /* CLFE Pin: output 2 (0x0e) */ |
1392 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | 2538 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, |
1393 | /* CLFE Pin: mute amp left and right (no volume) */ | 2539 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, |
1394 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, | ||
1395 | /* select CLFE mixer (0x0e, index 2) */ | ||
1396 | {0x16, AC_VERB_SET_CONNECT_SEL, 0x02}, | 2540 | {0x16, AC_VERB_SET_CONNECT_SEL, 0x02}, |
1397 | /* Side Pin */ | 2541 | /* Side Pin: output 3 (0x0f) */ |
1398 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | 2542 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, |
1399 | /* Side Pin: mute amp left and right (no volume) */ | 2543 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, |
1400 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, | ||
1401 | /* select Side mixer (0x0f, index 3) */ | ||
1402 | {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, | 2544 | {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, |
1403 | /* Headphone Pin */ | 2545 | /* Mic (rear) pin: input vref at 80% */ |
1404 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | 2546 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, |
1405 | /* Headphone Pin: mute amp left and right (no volume) */ | 2547 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, |
1406 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, | 2548 | /* Front Mic pin: input vref at 80% */ |
1407 | /* select Front mixer (0x0c, index 0) */ | 2549 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, |
2550 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
2551 | /* Line In pin: input */ | ||
2552 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
2553 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
2554 | /* Line-2 In: Headphone output (output 0 - 0x0c) */ | ||
2555 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
2556 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
1408 | {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, | 2557 | {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, |
1409 | /* Mic (rear) pin widget for input and vref at 80% */ | ||
1410 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, | ||
1411 | /* Front Mic pin widget for input and vref at 80% */ | ||
1412 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, | ||
1413 | /* Line In pin widget for input */ | ||
1414 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, | ||
1415 | /* CD pin widget for input */ | 2558 | /* CD pin widget for input */ |
1416 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, | 2559 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, |
1417 | 2560 | ||
1418 | /* FIXME: use matrix-type input source selection */ | 2561 | /* FIXME: use matrix-type input source selection */ |
1419 | /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ | 2562 | /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ |
1420 | /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ | 2563 | /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ |
1421 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | 2564 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
1422 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, | 2565 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, |
1423 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, | 2566 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, |
1424 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, | 2567 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, |
1425 | /* Input mixer2 */ | 2568 | /* Input mixer2 */ |
1426 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | 2569 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
1427 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, | 2570 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, |
1428 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, | 2571 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, |
1429 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, | 2572 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, |
1430 | /* Input mixer3 */ | 2573 | /* Input mixer3 */ |
1431 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | 2574 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
1432 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, | 2575 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, |
1433 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, | 2576 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, |
1434 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, | 2577 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, |
1435 | /* ADC1: unmute amp left and right */ | 2578 | /* ADC1: mute amp left and right */ |
1436 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, | 2579 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, |
1437 | /* ADC2: unmute amp left and right */ | 2580 | {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, |
1438 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, | 2581 | /* ADC2: mute amp left and right */ |
1439 | /* ADC3: unmute amp left and right */ | 2582 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, |
1440 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, | 2583 | {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, |
1441 | 2584 | /* ADC3: mute amp left and right */ | |
1442 | /* Unmute front loopback */ | 2585 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, |
1443 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | 2586 | {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, |
1444 | /* Unmute rear loopback */ | ||
1445 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | ||
1446 | /* Mute CLFE loopback */ | ||
1447 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))}, | ||
1448 | /* Unmute side loopback */ | ||
1449 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | ||
1450 | 2587 | ||
1451 | { } | 2588 | { } |
1452 | }; | 2589 | }; |
@@ -1459,6 +2596,7 @@ static int patch_alc882(struct hda_codec *codec) | |||
1459 | if (spec == NULL) | 2596 | if (spec == NULL) |
1460 | return -ENOMEM; | 2597 | return -ENOMEM; |
1461 | 2598 | ||
2599 | init_MUTEX(&spec->bind_mutex); | ||
1462 | codec->spec = spec; | 2600 | codec->spec = spec; |
1463 | 2601 | ||
1464 | spec->mixers[spec->num_mixers] = alc882_base_mixer; | 2602 | spec->mixers[spec->num_mixers] = alc882_base_mixer; |
@@ -1466,8 +2604,9 @@ static int patch_alc882(struct hda_codec *codec) | |||
1466 | 2604 | ||
1467 | spec->multiout.dig_out_nid = ALC880_DIGOUT_NID; | 2605 | spec->multiout.dig_out_nid = ALC880_DIGOUT_NID; |
1468 | spec->dig_in_nid = ALC880_DIGIN_NID; | 2606 | spec->dig_in_nid = ALC880_DIGIN_NID; |
1469 | spec->front_panel = 1; | 2607 | spec->init_verbs[0] = alc882_init_verbs; |
1470 | spec->init_verbs = alc882_init_verbs; | 2608 | spec->num_init_verbs = 1; |
2609 | |||
1471 | spec->channel_mode = alc882_ch_modes; | 2610 | spec->channel_mode = alc882_ch_modes; |
1472 | spec->num_channel_mode = ARRAY_SIZE(alc882_ch_modes); | 2611 | spec->num_channel_mode = ARRAY_SIZE(alc882_ch_modes); |
1473 | 2612 | ||
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c new file mode 100644 index 000000000000..013be2ea513a --- /dev/null +++ b/sound/pci/hda/patch_sigmatel.c | |||
@@ -0,0 +1,666 @@ | |||
1 | /* | ||
2 | * Universal Interface for Intel High Definition Audio Codec | ||
3 | * | ||
4 | * HD audio interface patch for SigmaTel STAC92xx | ||
5 | * | ||
6 | * Copyright (c) 2005 Embedded Alley Solutions, Inc. | ||
7 | * <matt@embeddedalley.com> | ||
8 | * | ||
9 | * Based on patch_cmedia.c and patch_realtek.c | ||
10 | * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de> | ||
11 | * | ||
12 | * This driver is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This driver is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
25 | */ | ||
26 | |||
27 | #include <sound/driver.h> | ||
28 | #include <linux/init.h> | ||
29 | #include <linux/delay.h> | ||
30 | #include <linux/slab.h> | ||
31 | #include <linux/pci.h> | ||
32 | #include <sound/core.h> | ||
33 | #include "hda_codec.h" | ||
34 | #include "hda_local.h" | ||
35 | |||
36 | #undef STAC_TEST | ||
37 | |||
38 | struct sigmatel_spec { | ||
39 | /* playback */ | ||
40 | struct hda_multi_out multiout; | ||
41 | hda_nid_t playback_nid; | ||
42 | |||
43 | /* capture */ | ||
44 | hda_nid_t *adc_nids; | ||
45 | unsigned int num_adcs; | ||
46 | hda_nid_t *mux_nids; | ||
47 | unsigned int num_muxes; | ||
48 | hda_nid_t capture_nid; | ||
49 | hda_nid_t dig_in_nid; | ||
50 | |||
51 | /* power management*/ | ||
52 | hda_nid_t *pstate_nids; | ||
53 | unsigned int num_pstates; | ||
54 | |||
55 | /* pin widgets */ | ||
56 | hda_nid_t *pin_nids; | ||
57 | unsigned int num_pins; | ||
58 | #ifdef STAC_TEST | ||
59 | unsigned int *pin_configs; | ||
60 | #endif | ||
61 | |||
62 | /* codec specific stuff */ | ||
63 | struct hda_verb *init; | ||
64 | snd_kcontrol_new_t *mixer; | ||
65 | |||
66 | /* capture source */ | ||
67 | struct hda_input_mux input_mux; | ||
68 | char input_labels[HDA_MAX_NUM_INPUTS][16]; | ||
69 | unsigned int cur_mux[2]; | ||
70 | |||
71 | /* channel mode */ | ||
72 | unsigned int num_ch_modes; | ||
73 | unsigned int cur_ch_mode; | ||
74 | const struct sigmatel_channel_mode *channel_modes; | ||
75 | |||
76 | struct hda_pcm pcm_rec[1]; /* PCM information */ | ||
77 | }; | ||
78 | |||
79 | static hda_nid_t stac9200_adc_nids[1] = { | ||
80 | 0x03, | ||
81 | }; | ||
82 | |||
83 | static hda_nid_t stac9200_mux_nids[1] = { | ||
84 | 0x0c, | ||
85 | }; | ||
86 | |||
87 | static hda_nid_t stac9200_dac_nids[1] = { | ||
88 | 0x02, | ||
89 | }; | ||
90 | |||
91 | static hda_nid_t stac9200_pstate_nids[3] = { | ||
92 | 0x01, 0x02, 0x03, | ||
93 | }; | ||
94 | |||
95 | static hda_nid_t stac9200_pin_nids[8] = { | ||
96 | 0x08, 0x09, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, | ||
97 | }; | ||
98 | |||
99 | static hda_nid_t stac922x_adc_nids[2] = { | ||
100 | 0x06, 0x07, | ||
101 | }; | ||
102 | |||
103 | static hda_nid_t stac922x_mux_nids[2] = { | ||
104 | 0x12, 0x13, | ||
105 | }; | ||
106 | |||
107 | static hda_nid_t stac922x_dac_nids[4] = { | ||
108 | 0x02, 0x03, 0x04, 0x05, | ||
109 | }; | ||
110 | |||
111 | static hda_nid_t stac922x_pstate_nids[8] = { | ||
112 | 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x11, | ||
113 | }; | ||
114 | |||
115 | static hda_nid_t stac922x_pin_nids[10] = { | ||
116 | 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, | ||
117 | 0x0f, 0x10, 0x11, 0x15, 0x1b, | ||
118 | }; | ||
119 | |||
120 | static int stac92xx_mux_enum_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) | ||
121 | { | ||
122 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
123 | struct sigmatel_spec *spec = codec->spec; | ||
124 | return snd_hda_input_mux_info(&spec->input_mux, uinfo); | ||
125 | } | ||
126 | |||
127 | static int stac92xx_mux_enum_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
128 | { | ||
129 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
130 | struct sigmatel_spec *spec = codec->spec; | ||
131 | unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
132 | |||
133 | ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; | ||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | static int stac92xx_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
138 | { | ||
139 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
140 | struct sigmatel_spec *spec = codec->spec; | ||
141 | unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
142 | |||
143 | return snd_hda_input_mux_put(codec, &spec->input_mux, ucontrol, | ||
144 | spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]); | ||
145 | } | ||
146 | |||
147 | static struct hda_verb stac9200_ch2_init[] = { | ||
148 | /* set dac0mux for dac converter */ | ||
149 | { 0x07, 0x701, 0x00}, | ||
150 | {} | ||
151 | }; | ||
152 | |||
153 | static struct hda_verb stac922x_ch2_init[] = { | ||
154 | /* set master volume and direct control */ | ||
155 | { 0x16, 0x70f, 0xff}, | ||
156 | {} | ||
157 | }; | ||
158 | |||
159 | struct sigmatel_channel_mode { | ||
160 | unsigned int channels; | ||
161 | const struct hda_verb *sequence; | ||
162 | }; | ||
163 | |||
164 | static snd_kcontrol_new_t stac9200_mixer[] = { | ||
165 | HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT), | ||
166 | HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT), | ||
167 | { | ||
168 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
169 | .name = "Input Source", | ||
170 | .count = 1, | ||
171 | .info = stac92xx_mux_enum_info, | ||
172 | .get = stac92xx_mux_enum_get, | ||
173 | .put = stac92xx_mux_enum_put, | ||
174 | }, | ||
175 | HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT), | ||
176 | HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT), | ||
177 | HDA_CODEC_VOLUME("Input Mux Volume", 0x0c, 0, HDA_OUTPUT), | ||
178 | { } /* end */ | ||
179 | }; | ||
180 | |||
181 | static snd_kcontrol_new_t stac922x_mixer[] = { | ||
182 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x2, 0x0, HDA_OUTPUT), | ||
183 | HDA_CODEC_MUTE("PCM Playback Switch", 0x2, 0x0, HDA_OUTPUT), | ||
184 | { | ||
185 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
186 | .name = "Input Source", | ||
187 | .count = 1, | ||
188 | .info = stac92xx_mux_enum_info, | ||
189 | .get = stac92xx_mux_enum_get, | ||
190 | .put = stac92xx_mux_enum_put, | ||
191 | }, | ||
192 | HDA_CODEC_VOLUME("Capture Volume", 0x17, 0x0, HDA_INPUT), | ||
193 | HDA_CODEC_MUTE("Capture Switch", 0x17, 0x0, HDA_INPUT), | ||
194 | HDA_CODEC_VOLUME("Mux Capture Volume", 0x12, 0x0, HDA_OUTPUT), | ||
195 | { } /* end */ | ||
196 | }; | ||
197 | |||
198 | static int stac92xx_build_controls(struct hda_codec *codec) | ||
199 | { | ||
200 | struct sigmatel_spec *spec = codec->spec; | ||
201 | int err; | ||
202 | |||
203 | err = snd_hda_add_new_ctls(codec, spec->mixer); | ||
204 | if (err < 0) | ||
205 | return err; | ||
206 | if (spec->multiout.dig_out_nid) { | ||
207 | err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); | ||
208 | if (err < 0) | ||
209 | return err; | ||
210 | } | ||
211 | if (spec->dig_in_nid) { | ||
212 | err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); | ||
213 | if (err < 0) | ||
214 | return err; | ||
215 | } | ||
216 | return 0; | ||
217 | } | ||
218 | |||
219 | #ifdef STAC_TEST | ||
220 | static unsigned int stac9200_pin_configs[8] = { | ||
221 | 0x01c47010, 0x01447010, 0x0221401f, 0x01114010, | ||
222 | 0x02a19020, 0x01a19021, 0x90100140, 0x01813122, | ||
223 | }; | ||
224 | |||
225 | static unsigned int stac922x_pin_configs[14] = { | ||
226 | 0x40000100, 0x40000100, 0x40000100, 0x01114010, | ||
227 | 0x01813122, 0x40000100, 0x01447010, 0x01c47010, | ||
228 | 0x40000100, 0x40000100, | ||
229 | }; | ||
230 | |||
231 | static void stac92xx_set_config_regs(struct hda_codec *codec) | ||
232 | { | ||
233 | int i; | ||
234 | struct sigmatel_spec *spec = codec->spec; | ||
235 | unsigned int pin_cfg; | ||
236 | |||
237 | for (i=0; i < spec->num_pins; i++) { | ||
238 | snd_hda_codec_write(codec, spec->pin_nids[i], 0, | ||
239 | AC_VERB_SET_CONFIG_DEFAULT_BYTES_0, | ||
240 | spec->pin_configs[i] & 0x000000ff); | ||
241 | snd_hda_codec_write(codec, spec->pin_nids[i], 0, | ||
242 | AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, | ||
243 | (spec->pin_configs[i] & 0x0000ff00) >> 8); | ||
244 | snd_hda_codec_write(codec, spec->pin_nids[i], 0, | ||
245 | AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, | ||
246 | (spec->pin_configs[i] & 0x00ff0000) >> 16); | ||
247 | snd_hda_codec_write(codec, spec->pin_nids[i], 0, | ||
248 | AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, | ||
249 | spec->pin_configs[i] >> 24); | ||
250 | pin_cfg = snd_hda_codec_read(codec, spec->pin_nids[i], 0, | ||
251 | AC_VERB_GET_CONFIG_DEFAULT, | ||
252 | 0x00); | ||
253 | printk("pin nid %2.2x pin config %8.8x\n", spec->pin_nids[i], pin_cfg); | ||
254 | } | ||
255 | } | ||
256 | #endif | ||
257 | |||
258 | static int stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid, unsigned int value) | ||
259 | { | ||
260 | unsigned int pin_ctl; | ||
261 | |||
262 | pin_ctl = snd_hda_codec_read(codec, nid, 0, | ||
263 | AC_VERB_GET_PIN_WIDGET_CONTROL, | ||
264 | 0x00); | ||
265 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
266 | pin_ctl | value); | ||
267 | |||
268 | return 0; | ||
269 | } | ||
270 | |||
271 | static int stac92xx_set_vref(struct hda_codec *codec, hda_nid_t nid) | ||
272 | { | ||
273 | unsigned int vref_caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP) >> AC_PINCAP_VREF_SHIFT; | ||
274 | unsigned int vref_ctl = AC_PINCTL_VREF_HIZ; | ||
275 | |||
276 | if (vref_caps & AC_PINCAP_VREF_100) | ||
277 | vref_ctl = AC_PINCTL_VREF_100; | ||
278 | else if (vref_caps & AC_PINCAP_VREF_80) | ||
279 | vref_ctl = AC_PINCTL_VREF_80; | ||
280 | else if (vref_caps & AC_PINCAP_VREF_50) | ||
281 | vref_ctl = AC_PINCTL_VREF_50; | ||
282 | else if (vref_caps & AC_PINCAP_VREF_GRD) | ||
283 | vref_ctl = AC_PINCTL_VREF_GRD; | ||
284 | |||
285 | stac92xx_set_pinctl(codec, nid, vref_ctl); | ||
286 | |||
287 | return 0; | ||
288 | } | ||
289 | |||
290 | /* | ||
291 | * retrieve the default device type from the default config value | ||
292 | */ | ||
293 | #define get_defcfg_type(cfg) ((cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT) | ||
294 | #define get_defcfg_location(cfg) ((cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT) | ||
295 | |||
296 | static int stac92xx_config_pin(struct hda_codec *codec, hda_nid_t nid, unsigned int pin_cfg) | ||
297 | { | ||
298 | struct sigmatel_spec *spec = codec->spec; | ||
299 | u32 location = get_defcfg_location(pin_cfg); | ||
300 | char *label; | ||
301 | const char *type = NULL; | ||
302 | int ainput = 0; | ||
303 | |||
304 | switch(get_defcfg_type(pin_cfg)) { | ||
305 | case AC_JACK_HP_OUT: | ||
306 | /* Enable HP amp */ | ||
307 | stac92xx_set_pinctl(codec, nid, AC_PINCTL_HP_EN); | ||
308 | /* Fall through */ | ||
309 | case AC_JACK_SPDIF_OUT: | ||
310 | case AC_JACK_LINE_OUT: | ||
311 | case AC_JACK_SPEAKER: | ||
312 | /* Enable output */ | ||
313 | stac92xx_set_pinctl(codec, nid, AC_PINCTL_OUT_EN); | ||
314 | break; | ||
315 | case AC_JACK_SPDIF_IN: | ||
316 | stac92xx_set_pinctl(codec, nid, AC_PINCTL_IN_EN); | ||
317 | break; | ||
318 | case AC_JACK_MIC_IN: | ||
319 | if ((location & 0x0f) == AC_JACK_LOC_FRONT) | ||
320 | type = "Front Mic"; | ||
321 | else | ||
322 | type = "Mic"; | ||
323 | ainput = 1; | ||
324 | /* Set vref */ | ||
325 | stac92xx_set_vref(codec, nid); | ||
326 | stac92xx_set_pinctl(codec, nid, AC_PINCTL_IN_EN); | ||
327 | break; | ||
328 | case AC_JACK_CD: | ||
329 | type = "CD"; | ||
330 | ainput = 1; | ||
331 | stac92xx_set_pinctl(codec, nid, AC_PINCTL_IN_EN); | ||
332 | break; | ||
333 | case AC_JACK_LINE_IN: | ||
334 | if ((location & 0x0f) == AC_JACK_LOC_FRONT) | ||
335 | type = "Front Line"; | ||
336 | else | ||
337 | type = "Line"; | ||
338 | ainput = 1; | ||
339 | stac92xx_set_pinctl(codec, nid, AC_PINCTL_IN_EN); | ||
340 | break; | ||
341 | case AC_JACK_AUX: | ||
342 | if ((location & 0x0f) == AC_JACK_LOC_FRONT) | ||
343 | type = "Front Aux"; | ||
344 | else | ||
345 | type = "Aux"; | ||
346 | ainput = 1; | ||
347 | stac92xx_set_pinctl(codec, nid, AC_PINCTL_IN_EN); | ||
348 | break; | ||
349 | } | ||
350 | |||
351 | if (ainput) { | ||
352 | hda_nid_t con_lst[HDA_MAX_NUM_INPUTS]; | ||
353 | int i, j, num_cons, index = -1; | ||
354 | if (!type) | ||
355 | type = "Input"; | ||
356 | label = spec->input_labels[spec->input_mux.num_items]; | ||
357 | strcpy(label, type); | ||
358 | spec->input_mux.items[spec->input_mux.num_items].label = label; | ||
359 | for (i=0; i<spec->num_muxes; i++) { | ||
360 | num_cons = snd_hda_get_connections(codec, spec->mux_nids[i], con_lst, HDA_MAX_NUM_INPUTS); | ||
361 | for (j=0; j<num_cons; j++) | ||
362 | if (con_lst[j] == nid) { | ||
363 | index = j; | ||
364 | break; | ||
365 | } | ||
366 | if (index >= 0) | ||
367 | break; | ||
368 | } | ||
369 | spec->input_mux.items[spec->input_mux.num_items].index = index; | ||
370 | spec->input_mux.num_items++; | ||
371 | } | ||
372 | |||
373 | return 0; | ||
374 | } | ||
375 | |||
376 | static int stac92xx_config_pins(struct hda_codec *codec) | ||
377 | { | ||
378 | struct sigmatel_spec *spec = codec->spec; | ||
379 | int i; | ||
380 | unsigned int pin_cfg; | ||
381 | |||
382 | for (i=0; i < spec->num_pins; i++) { | ||
383 | /* Default to disabled */ | ||
384 | snd_hda_codec_write(codec, spec->pin_nids[i], 0, | ||
385 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
386 | 0x00); | ||
387 | |||
388 | pin_cfg = snd_hda_codec_read(codec, spec->pin_nids[i], 0, | ||
389 | AC_VERB_GET_CONFIG_DEFAULT, | ||
390 | 0x00); | ||
391 | if (((pin_cfg & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT) == AC_JACK_PORT_NONE) | ||
392 | continue; /* Move on */ | ||
393 | |||
394 | stac92xx_config_pin(codec, spec->pin_nids[i], pin_cfg); | ||
395 | } | ||
396 | |||
397 | return 0; | ||
398 | } | ||
399 | |||
400 | static int stac92xx_init(struct hda_codec *codec) | ||
401 | { | ||
402 | struct sigmatel_spec *spec = codec->spec; | ||
403 | int i; | ||
404 | |||
405 | for (i=0; i < spec->num_pstates; i++) | ||
406 | snd_hda_codec_write(codec, spec->pstate_nids[i], 0, | ||
407 | AC_VERB_SET_POWER_STATE, 0x00); | ||
408 | |||
409 | mdelay(100); | ||
410 | |||
411 | snd_hda_sequence_write(codec, spec->init); | ||
412 | |||
413 | #ifdef STAC_TEST | ||
414 | stac92xx_set_config_regs(codec); | ||
415 | #endif | ||
416 | |||
417 | stac92xx_config_pins(codec); | ||
418 | |||
419 | return 0; | ||
420 | } | ||
421 | |||
422 | /* | ||
423 | * Analog playback callbacks | ||
424 | */ | ||
425 | static int stac92xx_playback_pcm_open(struct hda_pcm_stream *hinfo, | ||
426 | struct hda_codec *codec, | ||
427 | snd_pcm_substream_t *substream) | ||
428 | { | ||
429 | struct sigmatel_spec *spec = codec->spec; | ||
430 | return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream); | ||
431 | } | ||
432 | |||
433 | static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | ||
434 | struct hda_codec *codec, | ||
435 | unsigned int stream_tag, | ||
436 | unsigned int format, | ||
437 | snd_pcm_substream_t *substream) | ||
438 | { | ||
439 | struct sigmatel_spec *spec = codec->spec; | ||
440 | return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, | ||
441 | format, substream); | ||
442 | } | ||
443 | |||
444 | static int stac92xx_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, | ||
445 | struct hda_codec *codec, | ||
446 | snd_pcm_substream_t *substream) | ||
447 | { | ||
448 | struct sigmatel_spec *spec = codec->spec; | ||
449 | return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); | ||
450 | } | ||
451 | |||
452 | /* | ||
453 | * Digital playback callbacks | ||
454 | */ | ||
455 | static int stac92xx_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, | ||
456 | struct hda_codec *codec, | ||
457 | snd_pcm_substream_t *substream) | ||
458 | { | ||
459 | struct sigmatel_spec *spec = codec->spec; | ||
460 | return snd_hda_multi_out_dig_open(codec, &spec->multiout); | ||
461 | } | ||
462 | |||
463 | static int stac92xx_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, | ||
464 | struct hda_codec *codec, | ||
465 | snd_pcm_substream_t *substream) | ||
466 | { | ||
467 | struct sigmatel_spec *spec = codec->spec; | ||
468 | return snd_hda_multi_out_dig_close(codec, &spec->multiout); | ||
469 | } | ||
470 | |||
471 | |||
472 | /* | ||
473 | * Analog capture callbacks | ||
474 | */ | ||
475 | static int stac92xx_capture_pcm_prepare(struct hda_pcm_stream *hinfo, | ||
476 | struct hda_codec *codec, | ||
477 | unsigned int stream_tag, | ||
478 | unsigned int format, | ||
479 | snd_pcm_substream_t *substream) | ||
480 | { | ||
481 | struct sigmatel_spec *spec = codec->spec; | ||
482 | |||
483 | snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], | ||
484 | stream_tag, 0, format); | ||
485 | return 0; | ||
486 | } | ||
487 | |||
488 | static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, | ||
489 | struct hda_codec *codec, | ||
490 | snd_pcm_substream_t *substream) | ||
491 | { | ||
492 | struct sigmatel_spec *spec = codec->spec; | ||
493 | |||
494 | snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 0, 0, 0); | ||
495 | return 0; | ||
496 | } | ||
497 | |||
498 | static struct hda_pcm_stream stac92xx_pcm_digital_playback = { | ||
499 | .substreams = 1, | ||
500 | .channels_min = 2, | ||
501 | .channels_max = 2, | ||
502 | /* NID is set in stac92xx_build_pcms */ | ||
503 | .ops = { | ||
504 | .open = stac92xx_dig_playback_pcm_open, | ||
505 | .close = stac92xx_dig_playback_pcm_close | ||
506 | }, | ||
507 | }; | ||
508 | |||
509 | static struct hda_pcm_stream stac92xx_pcm_digital_capture = { | ||
510 | .substreams = 1, | ||
511 | .channels_min = 2, | ||
512 | .channels_max = 2, | ||
513 | /* NID is set in stac92xx_build_pcms */ | ||
514 | }; | ||
515 | |||
516 | static struct hda_pcm_stream stac92xx_pcm_analog_playback = { | ||
517 | .substreams = 1, | ||
518 | .channels_min = 2, | ||
519 | .channels_max = 2, | ||
520 | .nid = 0x02, /* NID to query formats and rates */ | ||
521 | .ops = { | ||
522 | .open = stac92xx_playback_pcm_open, | ||
523 | .prepare = stac92xx_playback_pcm_prepare, | ||
524 | .cleanup = stac92xx_playback_pcm_cleanup | ||
525 | }, | ||
526 | }; | ||
527 | |||
528 | static struct hda_pcm_stream stac92xx_pcm_analog_capture = { | ||
529 | .substreams = 2, | ||
530 | .channels_min = 2, | ||
531 | .channels_max = 2, | ||
532 | .nid = 0x06, /* NID to query formats and rates */ | ||
533 | .ops = { | ||
534 | .prepare = stac92xx_capture_pcm_prepare, | ||
535 | .cleanup = stac92xx_capture_pcm_cleanup | ||
536 | }, | ||
537 | }; | ||
538 | |||
539 | static int stac92xx_build_pcms(struct hda_codec *codec) | ||
540 | { | ||
541 | struct sigmatel_spec *spec = codec->spec; | ||
542 | struct hda_pcm *info = spec->pcm_rec; | ||
543 | |||
544 | codec->num_pcms = 1; | ||
545 | codec->pcm_info = info; | ||
546 | |||
547 | info->name = "STAC92xx"; | ||
548 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback; | ||
549 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->playback_nid; | ||
550 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture; | ||
551 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->capture_nid; | ||
552 | |||
553 | if (spec->multiout.dig_out_nid || spec->dig_in_nid) { | ||
554 | codec->num_pcms++; | ||
555 | info++; | ||
556 | info->name = "STAC92xx Digital"; | ||
557 | if (spec->multiout.dig_out_nid) { | ||
558 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_digital_playback; | ||
559 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; | ||
560 | } | ||
561 | if (spec->dig_in_nid) { | ||
562 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_digital_capture; | ||
563 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; | ||
564 | } | ||
565 | } | ||
566 | |||
567 | return 0; | ||
568 | } | ||
569 | |||
570 | static void stac92xx_free(struct hda_codec *codec) | ||
571 | { | ||
572 | kfree(codec->spec); | ||
573 | } | ||
574 | |||
575 | static struct hda_codec_ops stac92xx_patch_ops = { | ||
576 | .build_controls = stac92xx_build_controls, | ||
577 | .build_pcms = stac92xx_build_pcms, | ||
578 | .init = stac92xx_init, | ||
579 | .free = stac92xx_free, | ||
580 | }; | ||
581 | |||
582 | static int patch_stac9200(struct hda_codec *codec) | ||
583 | { | ||
584 | struct sigmatel_spec *spec; | ||
585 | |||
586 | spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); | ||
587 | if (spec == NULL) | ||
588 | return -ENOMEM; | ||
589 | |||
590 | codec->spec = spec; | ||
591 | |||
592 | spec->multiout.max_channels = 2; | ||
593 | spec->multiout.num_dacs = 1; | ||
594 | spec->multiout.dac_nids = stac9200_dac_nids; | ||
595 | spec->multiout.dig_out_nid = 0x05; | ||
596 | spec->dig_in_nid = 0x04; | ||
597 | spec->adc_nids = stac9200_adc_nids; | ||
598 | spec->mux_nids = stac9200_mux_nids; | ||
599 | spec->num_muxes = 1; | ||
600 | spec->input_mux.num_items = 0; | ||
601 | spec->pstate_nids = stac9200_pstate_nids; | ||
602 | spec->num_pstates = 3; | ||
603 | spec->pin_nids = stac9200_pin_nids; | ||
604 | #ifdef STAC_TEST | ||
605 | spec->pin_configs = stac9200_pin_configs; | ||
606 | #endif | ||
607 | spec->num_pins = 8; | ||
608 | spec->init = stac9200_ch2_init; | ||
609 | spec->mixer = stac9200_mixer; | ||
610 | spec->playback_nid = 0x02; | ||
611 | spec->capture_nid = 0x03; | ||
612 | |||
613 | codec->patch_ops = stac92xx_patch_ops; | ||
614 | |||
615 | return 0; | ||
616 | } | ||
617 | |||
618 | static int patch_stac922x(struct hda_codec *codec) | ||
619 | { | ||
620 | struct sigmatel_spec *spec; | ||
621 | |||
622 | spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); | ||
623 | if (spec == NULL) | ||
624 | return -ENOMEM; | ||
625 | |||
626 | codec->spec = spec; | ||
627 | |||
628 | spec->multiout.max_channels = 2; | ||
629 | spec->multiout.num_dacs = 4; | ||
630 | spec->multiout.dac_nids = stac922x_dac_nids; | ||
631 | spec->multiout.dig_out_nid = 0x08; | ||
632 | spec->dig_in_nid = 0x09; | ||
633 | spec->adc_nids = stac922x_adc_nids; | ||
634 | spec->mux_nids = stac922x_mux_nids; | ||
635 | spec->num_muxes = 2; | ||
636 | spec->input_mux.num_items = 0; | ||
637 | spec->pstate_nids = stac922x_pstate_nids; | ||
638 | spec->num_pstates = 8; | ||
639 | spec->pin_nids = stac922x_pin_nids; | ||
640 | #ifdef STAC_TEST | ||
641 | spec->pin_configs = stac922x_pin_configs; | ||
642 | #endif | ||
643 | spec->num_pins = 10; | ||
644 | spec->init = stac922x_ch2_init; | ||
645 | spec->mixer = stac922x_mixer; | ||
646 | spec->playback_nid = 0x02; | ||
647 | spec->capture_nid = 0x06; | ||
648 | |||
649 | codec->patch_ops = stac92xx_patch_ops; | ||
650 | |||
651 | return 0; | ||
652 | } | ||
653 | |||
654 | /* | ||
655 | * patch entries | ||
656 | */ | ||
657 | struct hda_codec_preset snd_hda_preset_sigmatel[] = { | ||
658 | { .id = 0x83847690, .name = "STAC9200", .patch = patch_stac9200 }, | ||
659 | { .id = 0x83847882, .name = "STAC9220 A1", .patch = patch_stac922x }, | ||
660 | { .id = 0x83847680, .name = "STAC9221 A1", .patch = patch_stac922x }, | ||
661 | { .id = 0x83847880, .name = "STAC9220 A2", .patch = patch_stac922x }, | ||
662 | { .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = patch_stac922x }, | ||
663 | { .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x }, | ||
664 | { .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x }, | ||
665 | {} /* terminator */ | ||
666 | }; | ||
diff --git a/sound/pci/ice1712/amp.c b/sound/pci/ice1712/amp.c index 779951725e1e..289b0b5711e4 100644 --- a/sound/pci/ice1712/amp.c +++ b/sound/pci/ice1712/amp.c | |||
@@ -30,16 +30,39 @@ | |||
30 | #include <sound/core.h> | 30 | #include <sound/core.h> |
31 | 31 | ||
32 | #include "ice1712.h" | 32 | #include "ice1712.h" |
33 | #include "envy24ht.h" | ||
33 | #include "amp.h" | 34 | #include "amp.h" |
34 | 35 | ||
36 | static void wm_put(ice1712_t *ice, int reg, unsigned short val) | ||
37 | { | ||
38 | unsigned short cval; | ||
39 | cval = (reg << 9) | val; | ||
40 | snd_vt1724_write_i2c(ice, WM_DEV, cval >> 8, cval & 0xff); | ||
41 | } | ||
35 | 42 | ||
36 | static int __devinit snd_vt1724_amp_init(ice1712_t *ice) | 43 | static int __devinit snd_vt1724_amp_init(ice1712_t *ice) |
37 | { | 44 | { |
45 | static unsigned short wm_inits[] = { | ||
46 | WM_ATTEN_L, 0x0000, /* 0 db */ | ||
47 | WM_ATTEN_R, 0x0000, /* 0 db */ | ||
48 | WM_DAC_CTRL, 0x0008, /* 24bit I2S */ | ||
49 | WM_INT_CTRL, 0x0001, /* 24bit I2S */ | ||
50 | }; | ||
51 | |||
52 | unsigned int i; | ||
53 | |||
38 | /* only use basic functionality for now */ | 54 | /* only use basic functionality for now */ |
39 | 55 | ||
40 | ice->num_total_dacs = 2; /* only PSDOUT0 is connected */ | 56 | ice->num_total_dacs = 2; /* only PSDOUT0 is connected */ |
41 | ice->num_total_adcs = 2; | 57 | ice->num_total_adcs = 2; |
42 | 58 | ||
59 | /* Chaintech AV-710 has another codecs, which need initialization */ | ||
60 | /* initialize WM8728 codec */ | ||
61 | if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AV710) { | ||
62 | for (i = 0; i < ARRAY_SIZE(wm_inits); i += 2) | ||
63 | wm_put(ice, wm_inits[i], wm_inits[i+1]); | ||
64 | } | ||
65 | |||
43 | return 0; | 66 | return 0; |
44 | } | 67 | } |
45 | 68 | ||
@@ -54,6 +77,13 @@ static int __devinit snd_vt1724_amp_add_controls(ice1712_t *ice) | |||
54 | /* entry point */ | 77 | /* entry point */ |
55 | struct snd_ice1712_card_info snd_vt1724_amp_cards[] __devinitdata = { | 78 | struct snd_ice1712_card_info snd_vt1724_amp_cards[] __devinitdata = { |
56 | { | 79 | { |
80 | .subvendor = VT1724_SUBDEVICE_AV710, | ||
81 | .name = "Chaintech AV-710", | ||
82 | .model = "av710", | ||
83 | .chip_init = snd_vt1724_amp_init, | ||
84 | .build_controls = snd_vt1724_amp_add_controls, | ||
85 | }, | ||
86 | { | ||
57 | .subvendor = VT1724_SUBDEVICE_AUDIO2000, | 87 | .subvendor = VT1724_SUBDEVICE_AUDIO2000, |
58 | .name = "AMP Ltd AUDIO2000", | 88 | .name = "AMP Ltd AUDIO2000", |
59 | .model = "amp2000", | 89 | .model = "amp2000", |
diff --git a/sound/pci/ice1712/amp.h b/sound/pci/ice1712/amp.h index d58d43383e83..a0fc89b48122 100644 --- a/sound/pci/ice1712/amp.h +++ b/sound/pci/ice1712/amp.h | |||
@@ -24,9 +24,23 @@ | |||
24 | * | 24 | * |
25 | */ | 25 | */ |
26 | 26 | ||
27 | #define AMP_AUDIO2000_DEVICE_DESC "{AMP Ltd,AUDIO2000}," | 27 | #define AMP_AUDIO2000_DEVICE_DESC "{AMP Ltd,AUDIO2000},"\ |
28 | "{Chaintech,AV-710}," | ||
28 | 29 | ||
30 | #if 0 | ||
29 | #define VT1724_SUBDEVICE_AUDIO2000 0x12142417 /* Advanced Micro Peripherals Ltd AUDIO2000 */ | 31 | #define VT1724_SUBDEVICE_AUDIO2000 0x12142417 /* Advanced Micro Peripherals Ltd AUDIO2000 */ |
32 | #else | ||
33 | #define VT1724_SUBDEVICE_AUDIO2000 0x00030003 /* a dummy ID for AMP Audio2000 */ | ||
34 | #endif | ||
35 | #define VT1724_SUBDEVICE_AV710 0x12142417 /* AV710 - the same ID with Audio2000! */ | ||
36 | |||
37 | /* WM8728 on I2C for AV710 */ | ||
38 | #define WM_DEV 0x36 | ||
39 | |||
40 | #define WM_ATTEN_L 0x00 | ||
41 | #define WM_ATTEN_R 0x01 | ||
42 | #define WM_DAC_CTRL 0x02 | ||
43 | #define WM_INT_CTRL 0x03 | ||
30 | 44 | ||
31 | extern struct snd_ice1712_card_info snd_vt1724_amp_cards[]; | 45 | extern struct snd_ice1712_card_info snd_vt1724_amp_cards[]; |
32 | 46 | ||
diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index 79fba6be3503..a2545a5b26c4 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c | |||
@@ -2748,7 +2748,7 @@ static struct pci_driver driver = { | |||
2748 | 2748 | ||
2749 | static int __init alsa_card_ice1712_init(void) | 2749 | static int __init alsa_card_ice1712_init(void) |
2750 | { | 2750 | { |
2751 | return pci_module_init(&driver); | 2751 | return pci_register_driver(&driver); |
2752 | } | 2752 | } |
2753 | 2753 | ||
2754 | static void __exit alsa_card_ice1712_exit(void) | 2754 | static void __exit alsa_card_ice1712_exit(void) |
diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h index 8bb1c58c26a0..5ad4728daa7b 100644 --- a/sound/pci/ice1712/ice1712.h +++ b/sound/pci/ice1712/ice1712.h | |||
@@ -373,6 +373,11 @@ struct _snd_ice1712 { | |||
373 | unsigned short master[2]; | 373 | unsigned short master[2]; |
374 | unsigned short vol[8]; | 374 | unsigned short vol[8]; |
375 | } aureon; | 375 | } aureon; |
376 | /* AC97 register cache for Phase28 */ | ||
377 | struct phase28_spec { | ||
378 | unsigned short master[2]; | ||
379 | unsigned short vol[8]; | ||
380 | } phase28; | ||
376 | /* Hoontech-specific setting */ | 381 | /* Hoontech-specific setting */ |
377 | struct hoontech_spec { | 382 | struct hoontech_spec { |
378 | unsigned char boxbits[4]; | 383 | unsigned char boxbits[4]; |
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 95500f06f0c6..79b5f12e06fc 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c | |||
@@ -2328,7 +2328,7 @@ static struct pci_driver driver = { | |||
2328 | 2328 | ||
2329 | static int __init alsa_card_ice1724_init(void) | 2329 | static int __init alsa_card_ice1724_init(void) |
2330 | { | 2330 | { |
2331 | return pci_module_init(&driver); | 2331 | return pci_register_driver(&driver); |
2332 | } | 2332 | } |
2333 | 2333 | ||
2334 | static void __exit alsa_card_ice1724_exit(void) | 2334 | static void __exit alsa_card_ice1724_exit(void) |
diff --git a/sound/pci/ice1712/phase.c b/sound/pci/ice1712/phase.c index d1f90832443c..5bf734b04fa0 100644 --- a/sound/pci/ice1712/phase.c +++ b/sound/pci/ice1712/phase.c | |||
@@ -45,6 +45,47 @@ | |||
45 | #include "envy24ht.h" | 45 | #include "envy24ht.h" |
46 | #include "phase.h" | 46 | #include "phase.h" |
47 | 47 | ||
48 | /* WM8770 registers */ | ||
49 | #define WM_DAC_ATTEN 0x00 /* DAC1-8 analog attenuation */ | ||
50 | #define WM_DAC_MASTER_ATTEN 0x08 /* DAC master analog attenuation */ | ||
51 | #define WM_DAC_DIG_ATTEN 0x09 /* DAC1-8 digital attenuation */ | ||
52 | #define WM_DAC_DIG_MASTER_ATTEN 0x11 /* DAC master digital attenuation */ | ||
53 | #define WM_PHASE_SWAP 0x12 /* DAC phase */ | ||
54 | #define WM_DAC_CTRL1 0x13 /* DAC control bits */ | ||
55 | #define WM_MUTE 0x14 /* mute controls */ | ||
56 | #define WM_DAC_CTRL2 0x15 /* de-emphasis and zefo-flag */ | ||
57 | #define WM_INT_CTRL 0x16 /* interface control */ | ||
58 | #define WM_MASTER 0x17 /* master clock and mode */ | ||
59 | #define WM_POWERDOWN 0x18 /* power-down controls */ | ||
60 | #define WM_ADC_GAIN 0x19 /* ADC gain L(19)/R(1a) */ | ||
61 | #define WM_ADC_MUX 0x1b /* input MUX */ | ||
62 | #define WM_OUT_MUX1 0x1c /* output MUX */ | ||
63 | #define WM_OUT_MUX2 0x1e /* output MUX */ | ||
64 | #define WM_RESET 0x1f /* software reset */ | ||
65 | |||
66 | |||
67 | /* | ||
68 | * Logarithmic volume values for WM8770 | ||
69 | * Computed as 20 * Log10(255 / x) | ||
70 | */ | ||
71 | static unsigned char wm_vol[256] = { | ||
72 | 127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24, 24, 23, | ||
73 | 23, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17, | ||
74 | 17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13, | ||
75 | 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, | ||
76 | 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, | ||
77 | 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, | ||
78 | 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, | ||
79 | 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, | ||
80 | 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, | ||
81 | 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, | ||
82 | 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, | ||
83 | 0, 0 | ||
84 | }; | ||
85 | |||
86 | #define WM_VOL_MAX (sizeof(wm_vol) - 1) | ||
87 | #define WM_VOL_MUTE 0x8000 | ||
88 | |||
48 | static akm4xxx_t akm_phase22 __devinitdata = { | 89 | static akm4xxx_t akm_phase22 __devinitdata = { |
49 | .type = SND_AK4524, | 90 | .type = SND_AK4524, |
50 | .num_dacs = 2, | 91 | .num_dacs = 2, |
@@ -124,6 +165,684 @@ static unsigned char phase22_eeprom[] __devinitdata = { | |||
124 | 0x00, /* GPIO_STATE2 */ | 165 | 0x00, /* GPIO_STATE2 */ |
125 | }; | 166 | }; |
126 | 167 | ||
168 | static unsigned char phase28_eeprom[] __devinitdata = { | ||
169 | 0x0b, /* SYSCONF: clock 512, spdif-in/ADC, 4DACs */ | ||
170 | 0x80, /* ACLINK: I2S */ | ||
171 | 0xfc, /* I2S: vol, 96k, 24bit, 192k */ | ||
172 | 0xc3, /* SPDIF: out-en, out-int, spdif-in */ | ||
173 | 0xff, /* GPIO_DIR */ | ||
174 | 0xff, /* GPIO_DIR1 */ | ||
175 | 0x5f, /* GPIO_DIR2 */ | ||
176 | 0x00, /* GPIO_MASK */ | ||
177 | 0x00, /* GPIO_MASK1 */ | ||
178 | 0x00, /* GPIO_MASK2 */ | ||
179 | 0x00, /* GPIO_STATE */ | ||
180 | 0x00, /* GPIO_STATE1 */ | ||
181 | 0x00, /* GPIO_STATE2 */ | ||
182 | }; | ||
183 | |||
184 | /* | ||
185 | * write data in the SPI mode | ||
186 | */ | ||
187 | static void phase28_spi_write(ice1712_t *ice, unsigned int cs, unsigned int data, int bits) | ||
188 | { | ||
189 | unsigned int tmp; | ||
190 | int i; | ||
191 | |||
192 | tmp = snd_ice1712_gpio_read(ice); | ||
193 | |||
194 | snd_ice1712_gpio_set_mask(ice, ~(PHASE28_WM_RW|PHASE28_SPI_MOSI|PHASE28_SPI_CLK| | ||
195 | PHASE28_WM_CS)); | ||
196 | tmp |= PHASE28_WM_RW; | ||
197 | tmp &= ~cs; | ||
198 | snd_ice1712_gpio_write(ice, tmp); | ||
199 | udelay(1); | ||
200 | |||
201 | for (i = bits - 1; i >= 0; i--) { | ||
202 | tmp &= ~PHASE28_SPI_CLK; | ||
203 | snd_ice1712_gpio_write(ice, tmp); | ||
204 | udelay(1); | ||
205 | if (data & (1 << i)) | ||
206 | tmp |= PHASE28_SPI_MOSI; | ||
207 | else | ||
208 | tmp &= ~PHASE28_SPI_MOSI; | ||
209 | snd_ice1712_gpio_write(ice, tmp); | ||
210 | udelay(1); | ||
211 | tmp |= PHASE28_SPI_CLK; | ||
212 | snd_ice1712_gpio_write(ice, tmp); | ||
213 | udelay(1); | ||
214 | } | ||
215 | |||
216 | tmp &= ~PHASE28_SPI_CLK; | ||
217 | tmp |= cs; | ||
218 | snd_ice1712_gpio_write(ice, tmp); | ||
219 | udelay(1); | ||
220 | tmp |= PHASE28_SPI_CLK; | ||
221 | snd_ice1712_gpio_write(ice, tmp); | ||
222 | udelay(1); | ||
223 | } | ||
224 | |||
225 | /* | ||
226 | * get the current register value of WM codec | ||
227 | */ | ||
228 | static unsigned short wm_get(ice1712_t *ice, int reg) | ||
229 | { | ||
230 | reg <<= 1; | ||
231 | return ((unsigned short)ice->akm[0].images[reg] << 8) | | ||
232 | ice->akm[0].images[reg + 1]; | ||
233 | } | ||
234 | |||
235 | /* | ||
236 | * set the register value of WM codec | ||
237 | */ | ||
238 | static void wm_put_nocache(ice1712_t *ice, int reg, unsigned short val) | ||
239 | { | ||
240 | phase28_spi_write(ice, PHASE28_WM_CS, (reg << 9) | (val & 0x1ff), 16); | ||
241 | } | ||
242 | |||
243 | /* | ||
244 | * set the register value of WM codec and remember it | ||
245 | */ | ||
246 | static void wm_put(ice1712_t *ice, int reg, unsigned short val) | ||
247 | { | ||
248 | wm_put_nocache(ice, reg, val); | ||
249 | reg <<= 1; | ||
250 | ice->akm[0].images[reg] = val >> 8; | ||
251 | ice->akm[0].images[reg + 1] = val; | ||
252 | } | ||
253 | |||
254 | static void wm_set_vol(ice1712_t *ice, unsigned int index, unsigned short vol, unsigned short master) | ||
255 | { | ||
256 | unsigned char nvol; | ||
257 | |||
258 | if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE)) | ||
259 | nvol = 0; | ||
260 | else | ||
261 | nvol = 127 - wm_vol[(((vol & ~WM_VOL_MUTE) * (master & ~WM_VOL_MUTE)) / 127) & WM_VOL_MAX]; | ||
262 | |||
263 | wm_put(ice, index, nvol); | ||
264 | wm_put_nocache(ice, index, 0x180 | nvol); | ||
265 | } | ||
266 | |||
267 | /* | ||
268 | * DAC mute control | ||
269 | */ | ||
270 | #define wm_pcm_mute_info phase28_mono_bool_info | ||
271 | |||
272 | static int wm_pcm_mute_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
273 | { | ||
274 | ice1712_t *ice = snd_kcontrol_chip(kcontrol); | ||
275 | |||
276 | down(&ice->gpio_mutex); | ||
277 | ucontrol->value.integer.value[0] = (wm_get(ice, WM_MUTE) & 0x10) ? 0 : 1; | ||
278 | up(&ice->gpio_mutex); | ||
279 | return 0; | ||
280 | } | ||
281 | |||
282 | static int wm_pcm_mute_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) | ||
283 | { | ||
284 | ice1712_t *ice = snd_kcontrol_chip(kcontrol); | ||
285 | unsigned short nval, oval; | ||
286 | int change; | ||
287 | |||
288 | snd_ice1712_save_gpio_status(ice); | ||
289 | oval = wm_get(ice, WM_MUTE); | ||
290 | nval = (oval & ~0x10) | (ucontrol->value.integer.value[0] ? 0 : 0x10); | ||
291 | if ((change = (nval != oval))) | ||
292 | wm_put(ice, WM_MUTE, nval); | ||
293 | snd_ice1712_restore_gpio_status(ice); | ||
294 | |||
295 | return change; | ||
296 | } | ||
297 | |||
298 | /* | ||
299 | * Master volume attenuation mixer control | ||
300 | */ | ||
301 | static int wm_master_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) | ||
302 | { | ||
303 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
304 | uinfo->count = 2; | ||
305 | uinfo->value.integer.min = 0; | ||
306 | uinfo->value.integer.max = WM_VOL_MAX; | ||
307 | return 0; | ||
308 | } | ||
309 | |||
310 | static int wm_master_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
311 | { | ||
312 | ice1712_t *ice = snd_kcontrol_chip(kcontrol); | ||
313 | int i; | ||
314 | for (i=0; i<2; i++) | ||
315 | ucontrol->value.integer.value[i] = ice->spec.phase28.master[i] & ~WM_VOL_MUTE; | ||
316 | return 0; | ||
317 | } | ||
318 | |||
319 | static int wm_master_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
320 | { | ||
321 | ice1712_t *ice = snd_kcontrol_chip(kcontrol); | ||
322 | int ch, change = 0; | ||
323 | |||
324 | snd_ice1712_save_gpio_status(ice); | ||
325 | for (ch = 0; ch < 2; ch++) { | ||
326 | if (ucontrol->value.integer.value[ch] != ice->spec.phase28.master[ch]) { | ||
327 | int dac; | ||
328 | ice->spec.phase28.master[ch] &= WM_VOL_MUTE; | ||
329 | ice->spec.phase28.master[ch] |= ucontrol->value.integer.value[ch]; | ||
330 | for (dac = 0; dac < ice->num_total_dacs; dac += 2) | ||
331 | wm_set_vol(ice, WM_DAC_ATTEN + dac + ch, | ||
332 | ice->spec.phase28.vol[dac + ch], | ||
333 | ice->spec.phase28.master[ch]); | ||
334 | change = 1; | ||
335 | } | ||
336 | } | ||
337 | snd_ice1712_restore_gpio_status(ice); | ||
338 | return change; | ||
339 | } | ||
340 | |||
341 | static int __devinit phase28_init(ice1712_t *ice) | ||
342 | { | ||
343 | static unsigned short wm_inits_phase28[] = { | ||
344 | /* These come first to reduce init pop noise */ | ||
345 | 0x1b, 0x044, /* ADC Mux (AC'97 source) */ | ||
346 | 0x1c, 0x00B, /* Out Mux1 (VOUT1 = DAC+AUX, VOUT2 = DAC) */ | ||
347 | 0x1d, 0x009, /* Out Mux2 (VOUT2 = DAC, VOUT3 = DAC) */ | ||
348 | |||
349 | 0x18, 0x000, /* All power-up */ | ||
350 | |||
351 | 0x16, 0x122, /* I2S, normal polarity, 24bit */ | ||
352 | 0x17, 0x022, /* 256fs, slave mode */ | ||
353 | 0x00, 0, /* DAC1 analog mute */ | ||
354 | 0x01, 0, /* DAC2 analog mute */ | ||
355 | 0x02, 0, /* DAC3 analog mute */ | ||
356 | 0x03, 0, /* DAC4 analog mute */ | ||
357 | 0x04, 0, /* DAC5 analog mute */ | ||
358 | 0x05, 0, /* DAC6 analog mute */ | ||
359 | 0x06, 0, /* DAC7 analog mute */ | ||
360 | 0x07, 0, /* DAC8 analog mute */ | ||
361 | 0x08, 0x100, /* master analog mute */ | ||
362 | 0x09, 0xff, /* DAC1 digital full */ | ||
363 | 0x0a, 0xff, /* DAC2 digital full */ | ||
364 | 0x0b, 0xff, /* DAC3 digital full */ | ||
365 | 0x0c, 0xff, /* DAC4 digital full */ | ||
366 | 0x0d, 0xff, /* DAC5 digital full */ | ||
367 | 0x0e, 0xff, /* DAC6 digital full */ | ||
368 | 0x0f, 0xff, /* DAC7 digital full */ | ||
369 | 0x10, 0xff, /* DAC8 digital full */ | ||
370 | 0x11, 0x1ff, /* master digital full */ | ||
371 | 0x12, 0x000, /* phase normal */ | ||
372 | 0x13, 0x090, /* unmute DAC L/R */ | ||
373 | 0x14, 0x000, /* all unmute */ | ||
374 | 0x15, 0x000, /* no deemphasis, no ZFLG */ | ||
375 | 0x19, 0x000, /* -12dB ADC/L */ | ||
376 | 0x1a, 0x000, /* -12dB ADC/R */ | ||
377 | (unsigned short)-1 | ||
378 | }; | ||
379 | |||
380 | unsigned int tmp; | ||
381 | akm4xxx_t *ak; | ||
382 | unsigned short *p; | ||
383 | int i; | ||
384 | |||
385 | ice->num_total_dacs = 8; | ||
386 | ice->num_total_adcs = 2; | ||
387 | |||
388 | // Initialize analog chips | ||
389 | ak = ice->akm = kcalloc(1, sizeof(akm4xxx_t), GFP_KERNEL); | ||
390 | if (!ak) | ||
391 | return -ENOMEM; | ||
392 | ice->akm_codecs = 1; | ||
393 | |||
394 | snd_ice1712_gpio_set_dir(ice, 0x5fffff); /* fix this for the time being */ | ||
395 | |||
396 | /* reset the wm codec as the SPI mode */ | ||
397 | snd_ice1712_save_gpio_status(ice); | ||
398 | snd_ice1712_gpio_set_mask(ice, ~(PHASE28_WM_RESET|PHASE28_WM_CS|PHASE28_HP_SEL)); | ||
399 | |||
400 | tmp = snd_ice1712_gpio_read(ice); | ||
401 | tmp &= ~PHASE28_WM_RESET; | ||
402 | snd_ice1712_gpio_write(ice, tmp); | ||
403 | udelay(1); | ||
404 | tmp |= PHASE28_WM_CS; | ||
405 | snd_ice1712_gpio_write(ice, tmp); | ||
406 | udelay(1); | ||
407 | tmp |= PHASE28_WM_RESET; | ||
408 | snd_ice1712_gpio_write(ice, tmp); | ||
409 | udelay(1); | ||
410 | |||
411 | p = wm_inits_phase28; | ||
412 | for (; *p != (unsigned short)-1; p += 2) | ||
413 | wm_put(ice, p[0], p[1]); | ||
414 | |||
415 | snd_ice1712_restore_gpio_status(ice); | ||
416 | |||
417 | ice->spec.phase28.master[0] = WM_VOL_MUTE; | ||
418 | ice->spec.phase28.master[1] = WM_VOL_MUTE; | ||
419 | for (i = 0; i < ice->num_total_dacs; i++) { | ||
420 | ice->spec.phase28.vol[i] = WM_VOL_MUTE; | ||
421 | wm_set_vol(ice, i, ice->spec.phase28.vol[i], ice->spec.phase28.master[i % 2]); | ||
422 | } | ||
423 | |||
424 | return 0; | ||
425 | } | ||
426 | |||
427 | /* | ||
428 | * DAC volume attenuation mixer control | ||
429 | */ | ||
430 | static int wm_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) | ||
431 | { | ||
432 | int voices = kcontrol->private_value >> 8; | ||
433 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
434 | uinfo->count = voices; | ||
435 | uinfo->value.integer.min = 0; /* mute (-101dB) */ | ||
436 | uinfo->value.integer.max = 0x7F; /* 0dB */ | ||
437 | return 0; | ||
438 | } | ||
439 | |||
440 | static int wm_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
441 | { | ||
442 | ice1712_t *ice = snd_kcontrol_chip(kcontrol); | ||
443 | int i, ofs, voices; | ||
444 | |||
445 | voices = kcontrol->private_value >> 8; | ||
446 | ofs = kcontrol->private_value & 0xff; | ||
447 | for (i = 0; i < voices; i++) | ||
448 | ucontrol->value.integer.value[i] = ice->spec.phase28.vol[ofs+i] & ~WM_VOL_MUTE; | ||
449 | return 0; | ||
450 | } | ||
451 | |||
452 | static int wm_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
453 | { | ||
454 | ice1712_t *ice = snd_kcontrol_chip(kcontrol); | ||
455 | int i, idx, ofs, voices; | ||
456 | int change = 0; | ||
457 | |||
458 | voices = kcontrol->private_value >> 8; | ||
459 | ofs = kcontrol->private_value & 0xff; | ||
460 | snd_ice1712_save_gpio_status(ice); | ||
461 | for (i = 0; i < voices; i++) { | ||
462 | idx = WM_DAC_ATTEN + ofs + i; | ||
463 | if (ucontrol->value.integer.value[i] != ice->spec.phase28.vol[ofs+i]) { | ||
464 | ice->spec.phase28.vol[ofs+i] &= WM_VOL_MUTE; | ||
465 | ice->spec.phase28.vol[ofs+i] |= ucontrol->value.integer.value[i]; | ||
466 | wm_set_vol(ice, idx, ice->spec.phase28.vol[ofs+i], | ||
467 | ice->spec.phase28.master[i]); | ||
468 | change = 1; | ||
469 | } | ||
470 | } | ||
471 | snd_ice1712_restore_gpio_status(ice); | ||
472 | return change; | ||
473 | } | ||
474 | |||
475 | /* | ||
476 | * WM8770 mute control | ||
477 | */ | ||
478 | static int wm_mute_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) { | ||
479 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
480 | uinfo->count = kcontrol->private_value >> 8; | ||
481 | uinfo->value.integer.min = 0; | ||
482 | uinfo->value.integer.max = 1; | ||
483 | return 0; | ||
484 | } | ||
485 | |||
486 | static int wm_mute_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
487 | { | ||
488 | ice1712_t *ice = snd_kcontrol_chip(kcontrol); | ||
489 | int voices, ofs, i; | ||
490 | |||
491 | voices = kcontrol->private_value >> 8; | ||
492 | ofs = kcontrol->private_value & 0xFF; | ||
493 | |||
494 | for (i = 0; i < voices; i++) | ||
495 | ucontrol->value.integer.value[i] = (ice->spec.phase28.vol[ofs+i] & WM_VOL_MUTE) ? 0 : 1; | ||
496 | return 0; | ||
497 | } | ||
498 | |||
499 | static int wm_mute_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) | ||
500 | { | ||
501 | ice1712_t *ice = snd_kcontrol_chip(kcontrol); | ||
502 | int change = 0, voices, ofs, i; | ||
503 | |||
504 | voices = kcontrol->private_value >> 8; | ||
505 | ofs = kcontrol->private_value & 0xFF; | ||
506 | |||
507 | snd_ice1712_save_gpio_status(ice); | ||
508 | for (i = 0; i < voices; i++) { | ||
509 | int val = (ice->spec.phase28.vol[ofs + i] & WM_VOL_MUTE) ? 0 : 1; | ||
510 | if (ucontrol->value.integer.value[i] != val) { | ||
511 | ice->spec.phase28.vol[ofs + i] &= ~WM_VOL_MUTE; | ||
512 | ice->spec.phase28.vol[ofs + i] |= | ||
513 | ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE; | ||
514 | wm_set_vol(ice, ofs + i, ice->spec.phase28.vol[ofs + i], | ||
515 | ice->spec.phase28.master[i]); | ||
516 | change = 1; | ||
517 | } | ||
518 | } | ||
519 | snd_ice1712_restore_gpio_status(ice); | ||
520 | |||
521 | return change; | ||
522 | } | ||
523 | |||
524 | /* | ||
525 | * WM8770 master mute control | ||
526 | */ | ||
527 | static int wm_master_mute_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) { | ||
528 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
529 | uinfo->count = 2; | ||
530 | uinfo->value.integer.min = 0; | ||
531 | uinfo->value.integer.max = 1; | ||
532 | return 0; | ||
533 | } | ||
534 | |||
535 | static int wm_master_mute_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
536 | { | ||
537 | ice1712_t *ice = snd_kcontrol_chip(kcontrol); | ||
538 | |||
539 | ucontrol->value.integer.value[0] = (ice->spec.phase28.master[0] & WM_VOL_MUTE) ? 0 : 1; | ||
540 | ucontrol->value.integer.value[1] = (ice->spec.phase28.master[1] & WM_VOL_MUTE) ? 0 : 1; | ||
541 | return 0; | ||
542 | } | ||
543 | |||
544 | static int wm_master_mute_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) | ||
545 | { | ||
546 | ice1712_t *ice = snd_kcontrol_chip(kcontrol); | ||
547 | int change = 0, i; | ||
548 | |||
549 | snd_ice1712_save_gpio_status(ice); | ||
550 | for (i = 0; i < 2; i++) { | ||
551 | int val = (ice->spec.phase28.master[i] & WM_VOL_MUTE) ? 0 : 1; | ||
552 | if (ucontrol->value.integer.value[i] != val) { | ||
553 | int dac; | ||
554 | ice->spec.phase28.master[i] &= ~WM_VOL_MUTE; | ||
555 | ice->spec.phase28.master[i] |= | ||
556 | ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE; | ||
557 | for (dac = 0; dac < ice->num_total_dacs; dac += 2) | ||
558 | wm_set_vol(ice, WM_DAC_ATTEN + dac + i, | ||
559 | ice->spec.phase28.vol[dac + i], | ||
560 | ice->spec.phase28.master[i]); | ||
561 | change = 1; | ||
562 | } | ||
563 | } | ||
564 | snd_ice1712_restore_gpio_status(ice); | ||
565 | |||
566 | return change; | ||
567 | } | ||
568 | |||
569 | /* digital master volume */ | ||
570 | #define PCM_0dB 0xff | ||
571 | #define PCM_RES 128 /* -64dB */ | ||
572 | #define PCM_MIN (PCM_0dB - PCM_RES) | ||
573 | static int wm_pcm_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) | ||
574 | { | ||
575 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
576 | uinfo->count = 1; | ||
577 | uinfo->value.integer.min = 0; /* mute (-64dB) */ | ||
578 | uinfo->value.integer.max = PCM_RES; /* 0dB */ | ||
579 | return 0; | ||
580 | } | ||
581 | |||
582 | static int wm_pcm_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
583 | { | ||
584 | ice1712_t *ice = snd_kcontrol_chip(kcontrol); | ||
585 | unsigned short val; | ||
586 | |||
587 | down(&ice->gpio_mutex); | ||
588 | val = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff; | ||
589 | val = val > PCM_MIN ? (val - PCM_MIN) : 0; | ||
590 | ucontrol->value.integer.value[0] = val; | ||
591 | up(&ice->gpio_mutex); | ||
592 | return 0; | ||
593 | } | ||
594 | |||
595 | static int wm_pcm_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
596 | { | ||
597 | ice1712_t *ice = snd_kcontrol_chip(kcontrol); | ||
598 | unsigned short ovol, nvol; | ||
599 | int change = 0; | ||
600 | |||
601 | snd_ice1712_save_gpio_status(ice); | ||
602 | nvol = ucontrol->value.integer.value[0]; | ||
603 | nvol = (nvol ? (nvol + PCM_MIN) : 0) & 0xff; | ||
604 | ovol = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff; | ||
605 | if (ovol != nvol) { | ||
606 | wm_put(ice, WM_DAC_DIG_MASTER_ATTEN, nvol); /* prelatch */ | ||
607 | wm_put_nocache(ice, WM_DAC_DIG_MASTER_ATTEN, nvol | 0x100); /* update */ | ||
608 | change = 1; | ||
609 | } | ||
610 | snd_ice1712_restore_gpio_status(ice); | ||
611 | return change; | ||
612 | } | ||
613 | |||
614 | /* | ||
615 | */ | ||
616 | static int phase28_mono_bool_info(snd_kcontrol_t *k, snd_ctl_elem_info_t *uinfo) | ||
617 | { | ||
618 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
619 | uinfo->count = 1; | ||
620 | uinfo->value.integer.min = 0; | ||
621 | uinfo->value.integer.max = 1; | ||
622 | return 0; | ||
623 | } | ||
624 | |||
625 | /* | ||
626 | * Deemphasis | ||
627 | */ | ||
628 | #define phase28_deemp_info phase28_mono_bool_info | ||
629 | |||
630 | static int phase28_deemp_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
631 | { | ||
632 | ice1712_t *ice = snd_kcontrol_chip(kcontrol); | ||
633 | ucontrol->value.integer.value[0] = (wm_get(ice, WM_DAC_CTRL2) & 0xf) == 0xf; | ||
634 | return 0; | ||
635 | } | ||
636 | |||
637 | static int phase28_deemp_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
638 | { | ||
639 | ice1712_t *ice = snd_kcontrol_chip(kcontrol); | ||
640 | int temp, temp2; | ||
641 | temp2 = temp = wm_get(ice, WM_DAC_CTRL2); | ||
642 | if (ucontrol->value.integer.value[0]) | ||
643 | temp |= 0xf; | ||
644 | else | ||
645 | temp &= ~0xf; | ||
646 | if (temp != temp2) { | ||
647 | wm_put(ice, WM_DAC_CTRL2, temp); | ||
648 | return 1; | ||
649 | } | ||
650 | return 0; | ||
651 | } | ||
652 | |||
653 | /* | ||
654 | * ADC Oversampling | ||
655 | */ | ||
656 | static int phase28_oversampling_info(snd_kcontrol_t *k, snd_ctl_elem_info_t *uinfo) | ||
657 | { | ||
658 | static char *texts[2] = { "128x", "64x" }; | ||
659 | |||
660 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
661 | uinfo->count = 1; | ||
662 | uinfo->value.enumerated.items = 2; | ||
663 | |||
664 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) | ||
665 | uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; | ||
666 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
667 | |||
668 | return 0; | ||
669 | } | ||
670 | |||
671 | static int phase28_oversampling_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
672 | { | ||
673 | ice1712_t *ice = snd_kcontrol_chip(kcontrol); | ||
674 | ucontrol->value.enumerated.item[0] = (wm_get(ice, WM_MASTER) & 0x8) == 0x8; | ||
675 | return 0; | ||
676 | } | ||
677 | |||
678 | static int phase28_oversampling_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
679 | { | ||
680 | int temp, temp2; | ||
681 | ice1712_t *ice = snd_kcontrol_chip(kcontrol); | ||
682 | |||
683 | temp2 = temp = wm_get(ice, WM_MASTER); | ||
684 | |||
685 | if (ucontrol->value.enumerated.item[0]) | ||
686 | temp |= 0x8; | ||
687 | else | ||
688 | temp &= ~0x8; | ||
689 | |||
690 | if (temp != temp2) { | ||
691 | wm_put(ice, WM_MASTER, temp); | ||
692 | return 1; | ||
693 | } | ||
694 | return 0; | ||
695 | } | ||
696 | |||
697 | static snd_kcontrol_new_t phase28_dac_controls[] __devinitdata = { | ||
698 | { | ||
699 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
700 | .name = "Master Playback Switch", | ||
701 | .info = wm_master_mute_info, | ||
702 | .get = wm_master_mute_get, | ||
703 | .put = wm_master_mute_put | ||
704 | }, | ||
705 | { | ||
706 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
707 | .name = "Master Playback Volume", | ||
708 | .info = wm_master_vol_info, | ||
709 | .get = wm_master_vol_get, | ||
710 | .put = wm_master_vol_put | ||
711 | }, | ||
712 | { | ||
713 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
714 | .name = "Front Playback Switch", | ||
715 | .info = wm_mute_info, | ||
716 | .get = wm_mute_get, | ||
717 | .put = wm_mute_put, | ||
718 | .private_value = (2 << 8) | 0 | ||
719 | }, | ||
720 | { | ||
721 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
722 | .name = "Front Playback Volume", | ||
723 | .info = wm_vol_info, | ||
724 | .get = wm_vol_get, | ||
725 | .put = wm_vol_put, | ||
726 | .private_value = (2 << 8) | 0 | ||
727 | }, | ||
728 | { | ||
729 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
730 | .name = "Rear Playback Switch", | ||
731 | .info = wm_mute_info, | ||
732 | .get = wm_mute_get, | ||
733 | .put = wm_mute_put, | ||
734 | .private_value = (2 << 8) | 2 | ||
735 | }, | ||
736 | { | ||
737 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
738 | .name = "Rear Playback Volume", | ||
739 | .info = wm_vol_info, | ||
740 | .get = wm_vol_get, | ||
741 | .put = wm_vol_put, | ||
742 | .private_value = (2 << 8) | 2 | ||
743 | }, | ||
744 | { | ||
745 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
746 | .name = "Center Playback Switch", | ||
747 | .info = wm_mute_info, | ||
748 | .get = wm_mute_get, | ||
749 | .put = wm_mute_put, | ||
750 | .private_value = (1 << 8) | 4 | ||
751 | }, | ||
752 | { | ||
753 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
754 | .name = "Center Playback Volume", | ||
755 | .info = wm_vol_info, | ||
756 | .get = wm_vol_get, | ||
757 | .put = wm_vol_put, | ||
758 | .private_value = (1 << 8) | 4 | ||
759 | }, | ||
760 | { | ||
761 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
762 | .name = "LFE Playback Switch", | ||
763 | .info = wm_mute_info, | ||
764 | .get = wm_mute_get, | ||
765 | .put = wm_mute_put, | ||
766 | .private_value = (1 << 8) | 5 | ||
767 | }, | ||
768 | { | ||
769 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
770 | .name = "LFE Playback Volume", | ||
771 | .info = wm_vol_info, | ||
772 | .get = wm_vol_get, | ||
773 | .put = wm_vol_put, | ||
774 | .private_value = (1 << 8) | 5 | ||
775 | }, | ||
776 | { | ||
777 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
778 | .name = "Side Playback Switch", | ||
779 | .info = wm_mute_info, | ||
780 | .get = wm_mute_get, | ||
781 | .put = wm_mute_put, | ||
782 | .private_value = (2 << 8) | 6 | ||
783 | }, | ||
784 | { | ||
785 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
786 | .name = "Side Playback Volume", | ||
787 | .info = wm_vol_info, | ||
788 | .get = wm_vol_get, | ||
789 | .put = wm_vol_put, | ||
790 | .private_value = (2 << 8) | 6 | ||
791 | } | ||
792 | }; | ||
793 | |||
794 | static snd_kcontrol_new_t wm_controls[] __devinitdata = { | ||
795 | { | ||
796 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
797 | .name = "PCM Playback Switch", | ||
798 | .info = wm_pcm_mute_info, | ||
799 | .get = wm_pcm_mute_get, | ||
800 | .put = wm_pcm_mute_put | ||
801 | }, | ||
802 | { | ||
803 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
804 | .name = "PCM Playback Volume", | ||
805 | .info = wm_pcm_vol_info, | ||
806 | .get = wm_pcm_vol_get, | ||
807 | .put = wm_pcm_vol_put | ||
808 | }, | ||
809 | { | ||
810 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
811 | .name = "DAC Deemphasis Switch", | ||
812 | .info = phase28_deemp_info, | ||
813 | .get = phase28_deemp_get, | ||
814 | .put = phase28_deemp_put | ||
815 | }, | ||
816 | { | ||
817 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
818 | .name = "ADC Oversampling", | ||
819 | .info = phase28_oversampling_info, | ||
820 | .get = phase28_oversampling_get, | ||
821 | .put = phase28_oversampling_put | ||
822 | } | ||
823 | }; | ||
824 | |||
825 | static int __devinit phase28_add_controls(ice1712_t *ice) | ||
826 | { | ||
827 | unsigned int i, counts; | ||
828 | int err; | ||
829 | |||
830 | counts = ARRAY_SIZE(phase28_dac_controls); | ||
831 | for (i = 0; i < counts; i++) { | ||
832 | err = snd_ctl_add(ice->card, snd_ctl_new1(&phase28_dac_controls[i], ice)); | ||
833 | if (err < 0) | ||
834 | return err; | ||
835 | } | ||
836 | |||
837 | for (i = 0; i < ARRAY_SIZE(wm_controls); i++) { | ||
838 | err = snd_ctl_add(ice->card, snd_ctl_new1(&wm_controls[i], ice)); | ||
839 | if (err < 0) | ||
840 | return err; | ||
841 | } | ||
842 | |||
843 | return 0; | ||
844 | } | ||
845 | |||
127 | struct snd_ice1712_card_info snd_vt1724_phase_cards[] __devinitdata = { | 846 | struct snd_ice1712_card_info snd_vt1724_phase_cards[] __devinitdata = { |
128 | { | 847 | { |
129 | .subvendor = VT1724_SUBDEVICE_PHASE22, | 848 | .subvendor = VT1724_SUBDEVICE_PHASE22, |
@@ -134,5 +853,14 @@ struct snd_ice1712_card_info snd_vt1724_phase_cards[] __devinitdata = { | |||
134 | .eeprom_size = sizeof(phase22_eeprom), | 853 | .eeprom_size = sizeof(phase22_eeprom), |
135 | .eeprom_data = phase22_eeprom, | 854 | .eeprom_data = phase22_eeprom, |
136 | }, | 855 | }, |
856 | { | ||
857 | .subvendor = VT1724_SUBDEVICE_PHASE28, | ||
858 | .name = "Terratec PHASE 28", | ||
859 | .model = "phase28", | ||
860 | .chip_init = phase28_init, | ||
861 | .build_controls = phase28_add_controls, | ||
862 | .eeprom_size = sizeof(phase28_eeprom), | ||
863 | .eeprom_data = phase28_eeprom, | ||
864 | }, | ||
137 | { } /* terminator */ | 865 | { } /* terminator */ |
138 | }; | 866 | }; |
diff --git a/sound/pci/ice1712/phase.h b/sound/pci/ice1712/phase.h index 6230cf16989f..13e841b55488 100644 --- a/sound/pci/ice1712/phase.h +++ b/sound/pci/ice1712/phase.h | |||
@@ -24,11 +24,28 @@ | |||
24 | * | 24 | * |
25 | */ | 25 | */ |
26 | 26 | ||
27 | #define PHASE_DEVICE_DESC "{Terratec,Phase 22}," | 27 | #define PHASE_DEVICE_DESC "{Terratec,Phase 22},"\ |
28 | "{Terratec,Phase 28}," | ||
28 | 29 | ||
29 | #define VT1724_SUBDEVICE_PHASE22 0x3b155011 | 30 | #define VT1724_SUBDEVICE_PHASE22 0x3b155011 |
31 | #define VT1724_SUBDEVICE_PHASE28 0x3b154911 | ||
30 | 32 | ||
31 | /* entry point */ | 33 | /* entry point */ |
32 | extern struct snd_ice1712_card_info snd_vt1724_phase_cards[]; | 34 | extern struct snd_ice1712_card_info snd_vt1724_phase_cards[]; |
33 | 35 | ||
36 | /* PHASE28 GPIO bits */ | ||
37 | #define PHASE28_SPI_MISO (1 << 21) | ||
38 | #define PHASE28_WM_RESET (1 << 20) | ||
39 | #define PHASE28_SPI_CLK (1 << 19) | ||
40 | #define PHASE28_SPI_MOSI (1 << 18) | ||
41 | #define PHASE28_WM_RW (1 << 17) | ||
42 | #define PHASE28_AC97_RESET (1 << 16) | ||
43 | #define PHASE28_DIGITAL_SEL1 (1 << 15) | ||
44 | #define PHASE28_HP_SEL (1 << 14) | ||
45 | #define PHASE28_WM_CS (1 << 12) | ||
46 | #define PHASE28_AC97_COMMIT (1 << 11) | ||
47 | #define PHASE28_AC97_ADDR (1 << 10) | ||
48 | #define PHASE28_AC97_DATA_LOW (1 << 9) | ||
49 | #define PHASE28_AC97_DATA_HIGH (1 << 8) | ||
50 | #define PHASE28_AC97_DATA_MASK 0xFF | ||
34 | #endif /* __SOUND_PHASE */ | 51 | #endif /* __SOUND_PHASE */ |
diff --git a/sound/pci/ice1712/vt1720_mobo.c b/sound/pci/ice1712/vt1720_mobo.c index 3bd92627231c..ab61e383024f 100644 --- a/sound/pci/ice1712/vt1720_mobo.c +++ b/sound/pci/ice1712/vt1720_mobo.c | |||
@@ -110,6 +110,15 @@ struct snd_ice1712_card_info snd_vt1720_mobo_cards[] __devinitdata = { | |||
110 | .eeprom_size = sizeof(k8x800_eeprom), | 110 | .eeprom_size = sizeof(k8x800_eeprom), |
111 | .eeprom_data = k8x800_eeprom, | 111 | .eeprom_data = k8x800_eeprom, |
112 | }, | 112 | }, |
113 | { | ||
114 | .subvendor = VT1720_SUBDEVICE_SN25P, | ||
115 | .name = "Shuttle SN25P", | ||
116 | /* identical with k8x800 */ | ||
117 | .chip_init = k8x800_init, | ||
118 | .build_controls = k8x800_add_controls, | ||
119 | .eeprom_size = sizeof(k8x800_eeprom), | ||
120 | .eeprom_data = k8x800_eeprom, | ||
121 | }, | ||
113 | { } /* terminator */ | 122 | { } /* terminator */ |
114 | }; | 123 | }; |
115 | 124 | ||
diff --git a/sound/pci/ice1712/vt1720_mobo.h b/sound/pci/ice1712/vt1720_mobo.h index f949eb804cae..0b1b0ee1bea7 100644 --- a/sound/pci/ice1712/vt1720_mobo.h +++ b/sound/pci/ice1712/vt1720_mobo.h | |||
@@ -27,12 +27,14 @@ | |||
27 | #define VT1720_MOBO_DEVICE_DESC "{Albatron,K8X800 Pro II},"\ | 27 | #define VT1720_MOBO_DEVICE_DESC "{Albatron,K8X800 Pro II},"\ |
28 | "{Chaintech,ZNF3-150},"\ | 28 | "{Chaintech,ZNF3-150},"\ |
29 | "{Chaintech,ZNF3-250},"\ | 29 | "{Chaintech,ZNF3-250},"\ |
30 | "{Chaintech,9CJS}," | 30 | "{Chaintech,9CJS},"\ |
31 | "{Shuttle,SN25P}," | ||
31 | 32 | ||
32 | #define VT1720_SUBDEVICE_K8X800 0xf217052c | 33 | #define VT1720_SUBDEVICE_K8X800 0xf217052c |
33 | #define VT1720_SUBDEVICE_ZNF3_150 0x0f2741f6 | 34 | #define VT1720_SUBDEVICE_ZNF3_150 0x0f2741f6 |
34 | #define VT1720_SUBDEVICE_ZNF3_250 0x0f2745f6 | 35 | #define VT1720_SUBDEVICE_ZNF3_250 0x0f2745f6 |
35 | #define VT1720_SUBDEVICE_9CJS 0x0f272327 | 36 | #define VT1720_SUBDEVICE_9CJS 0x0f272327 |
37 | #define VT1720_SUBDEVICE_SN25P 0x97123650 | ||
36 | 38 | ||
37 | extern struct snd_ice1712_card_info snd_vt1720_mobo_cards[]; | 39 | extern struct snd_ice1712_card_info snd_vt1720_mobo_cards[]; |
38 | 40 | ||
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 8b33b12fa5dc..cc16f95f9cef 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c | |||
@@ -1725,229 +1725,235 @@ static struct ac97_pcm ac97_pcm_defs[] __devinitdata = { | |||
1725 | 1725 | ||
1726 | static struct ac97_quirk ac97_quirks[] __devinitdata = { | 1726 | static struct ac97_quirk ac97_quirks[] __devinitdata = { |
1727 | { | 1727 | { |
1728 | .vendor = 0x0e11, | 1728 | .subvendor = 0x0e11, |
1729 | .device = 0x008a, | 1729 | .subdevice = 0x008a, |
1730 | .name = "Compaq Evo W4000", /* AD1885 */ | 1730 | .name = "Compaq Evo W4000", /* AD1885 */ |
1731 | .type = AC97_TUNE_HP_ONLY | 1731 | .type = AC97_TUNE_HP_ONLY |
1732 | }, | 1732 | }, |
1733 | { | 1733 | { |
1734 | .vendor = 0x0e11, | 1734 | .subvendor = 0x0e11, |
1735 | .device = 0x00b8, | 1735 | .subdevice = 0x00b8, |
1736 | .name = "Compaq Evo D510C", | 1736 | .name = "Compaq Evo D510C", |
1737 | .type = AC97_TUNE_HP_ONLY | 1737 | .type = AC97_TUNE_HP_ONLY |
1738 | }, | 1738 | }, |
1739 | { | 1739 | { |
1740 | .vendor = 0x0e11, | 1740 | .subvendor = 0x0e11, |
1741 | .device = 0x0860, | 1741 | .subdevice = 0x0860, |
1742 | .name = "HP/Compaq nx7010", | 1742 | .name = "HP/Compaq nx7010", |
1743 | .type = AC97_TUNE_MUTE_LED | 1743 | .type = AC97_TUNE_MUTE_LED |
1744 | }, | 1744 | }, |
1745 | { | 1745 | { |
1746 | .vendor = 0x1014, | 1746 | .subvendor = 0x1014, |
1747 | .device = 0x1f00, | 1747 | .subdevice = 0x1f00, |
1748 | .name = "MS-9128", | 1748 | .name = "MS-9128", |
1749 | .type = AC97_TUNE_ALC_JACK | 1749 | .type = AC97_TUNE_ALC_JACK |
1750 | }, | 1750 | }, |
1751 | { | 1751 | { |
1752 | .vendor = 0x1028, | 1752 | .subvendor = 0x1028, |
1753 | .device = 0x00d8, | 1753 | .subdevice = 0x00d8, |
1754 | .name = "Dell Precision 530", /* AD1885 */ | 1754 | .name = "Dell Precision 530", /* AD1885 */ |
1755 | .type = AC97_TUNE_HP_ONLY | 1755 | .type = AC97_TUNE_HP_ONLY |
1756 | }, | 1756 | }, |
1757 | { | 1757 | { |
1758 | .vendor = 0x1028, | 1758 | .subvendor = 0x1028, |
1759 | .device = 0x010d, | 1759 | .subdevice = 0x010d, |
1760 | .name = "Dell", /* which model? AD1885 */ | 1760 | .name = "Dell", /* which model? AD1885 */ |
1761 | .type = AC97_TUNE_HP_ONLY | 1761 | .type = AC97_TUNE_HP_ONLY |
1762 | }, | 1762 | }, |
1763 | { | 1763 | { |
1764 | .vendor = 0x1028, | 1764 | .subvendor = 0x1028, |
1765 | .device = 0x0126, | 1765 | .subdevice = 0x0126, |
1766 | .name = "Dell Optiplex GX260", /* AD1981A */ | 1766 | .name = "Dell Optiplex GX260", /* AD1981A */ |
1767 | .type = AC97_TUNE_HP_ONLY | 1767 | .type = AC97_TUNE_HP_ONLY |
1768 | }, | 1768 | }, |
1769 | { | 1769 | { |
1770 | .vendor = 0x1028, | 1770 | .subvendor = 0x1028, |
1771 | .device = 0x012c, | 1771 | .subdevice = 0x012c, |
1772 | .name = "Dell Precision 650", /* AD1981A */ | 1772 | .name = "Dell Precision 650", /* AD1981A */ |
1773 | .type = AC97_TUNE_HP_ONLY | 1773 | .type = AC97_TUNE_HP_ONLY |
1774 | }, | 1774 | }, |
1775 | { | 1775 | { |
1776 | .vendor = 0x1028, | 1776 | .subvendor = 0x1028, |
1777 | .device = 0x012d, | 1777 | .subdevice = 0x012d, |
1778 | .name = "Dell Precision 450", /* AD1981B*/ | 1778 | .name = "Dell Precision 450", /* AD1981B*/ |
1779 | .type = AC97_TUNE_HP_ONLY | 1779 | .type = AC97_TUNE_HP_ONLY |
1780 | }, | 1780 | }, |
1781 | { | 1781 | { |
1782 | .vendor = 0x1028, | 1782 | .subvendor = 0x1028, |
1783 | .device = 0x0147, | 1783 | .subdevice = 0x0147, |
1784 | .name = "Dell", /* which model? AD1981B*/ | 1784 | .name = "Dell", /* which model? AD1981B*/ |
1785 | .type = AC97_TUNE_HP_ONLY | 1785 | .type = AC97_TUNE_HP_ONLY |
1786 | }, | 1786 | }, |
1787 | { | 1787 | { |
1788 | .vendor = 0x1028, | 1788 | .subvendor = 0x1028, |
1789 | .device = 0x0163, | 1789 | .subdevice = 0x0163, |
1790 | .name = "Dell Unknown", /* STAC9750/51 */ | 1790 | .name = "Dell Unknown", /* STAC9750/51 */ |
1791 | .type = AC97_TUNE_HP_ONLY | 1791 | .type = AC97_TUNE_HP_ONLY |
1792 | }, | 1792 | }, |
1793 | { | 1793 | { |
1794 | .vendor = 0x103c, | 1794 | .subvendor = 0x103c, |
1795 | .device = 0x006d, | 1795 | .subdevice = 0x006d, |
1796 | .name = "HP zv5000", | 1796 | .name = "HP zv5000", |
1797 | .type = AC97_TUNE_MUTE_LED /*AD1981B*/ | 1797 | .type = AC97_TUNE_MUTE_LED /*AD1981B*/ |
1798 | }, | 1798 | }, |
1799 | { /* FIXME: which codec? */ | 1799 | { /* FIXME: which codec? */ |
1800 | .vendor = 0x103c, | 1800 | .subvendor = 0x103c, |
1801 | .device = 0x00c3, | 1801 | .subdevice = 0x00c3, |
1802 | .name = "HP xw6000", | 1802 | .name = "HP xw6000", |
1803 | .type = AC97_TUNE_HP_ONLY | 1803 | .type = AC97_TUNE_HP_ONLY |
1804 | }, | 1804 | }, |
1805 | { | 1805 | { |
1806 | .vendor = 0x103c, | 1806 | .subvendor = 0x103c, |
1807 | .device = 0x088c, | 1807 | .subdevice = 0x088c, |
1808 | .name = "HP nc8000", | 1808 | .name = "HP nc8000", |
1809 | .type = AC97_TUNE_MUTE_LED | 1809 | .type = AC97_TUNE_MUTE_LED |
1810 | }, | 1810 | }, |
1811 | { | 1811 | { |
1812 | .vendor = 0x103c, | 1812 | .subvendor = 0x103c, |
1813 | .device = 0x0890, | 1813 | .subdevice = 0x0890, |
1814 | .name = "HP nc6000", | 1814 | .name = "HP nc6000", |
1815 | .type = AC97_TUNE_MUTE_LED | 1815 | .type = AC97_TUNE_MUTE_LED |
1816 | }, | 1816 | }, |
1817 | { | 1817 | { |
1818 | .vendor = 0x103c, | 1818 | .subvendor = 0x103c, |
1819 | .device = 0x129d, | 1819 | .subdevice = 0x129d, |
1820 | .name = "HP xw8000", | 1820 | .name = "HP xw8000", |
1821 | .type = AC97_TUNE_HP_ONLY | 1821 | .type = AC97_TUNE_HP_ONLY |
1822 | }, | 1822 | }, |
1823 | { | 1823 | { |
1824 | .vendor = 0x103c, | 1824 | .subvendor = 0x103c, |
1825 | .device = 0x12f1, | 1825 | .subdevice = 0x12f1, |
1826 | .name = "HP xw8200", /* AD1981B*/ | 1826 | .name = "HP xw8200", /* AD1981B*/ |
1827 | .type = AC97_TUNE_HP_ONLY | 1827 | .type = AC97_TUNE_HP_ONLY |
1828 | }, | 1828 | }, |
1829 | { | 1829 | { |
1830 | .vendor = 0x103c, | 1830 | .subvendor = 0x103c, |
1831 | .device = 0x12f2, | 1831 | .subdevice = 0x12f2, |
1832 | .name = "HP xw6200", | 1832 | .name = "HP xw6200", |
1833 | .type = AC97_TUNE_HP_ONLY | 1833 | .type = AC97_TUNE_HP_ONLY |
1834 | }, | 1834 | }, |
1835 | { | 1835 | { |
1836 | .vendor = 0x103c, | 1836 | .subvendor = 0x103c, |
1837 | .device = 0x3008, | 1837 | .subdevice = 0x3008, |
1838 | .name = "HP xw4200", /* AD1981B*/ | 1838 | .name = "HP xw4200", /* AD1981B*/ |
1839 | .type = AC97_TUNE_HP_ONLY | 1839 | .type = AC97_TUNE_HP_ONLY |
1840 | }, | 1840 | }, |
1841 | { | 1841 | { |
1842 | .vendor = 0x104d, | 1842 | .subvendor = 0x104d, |
1843 | .device = 0x8197, | 1843 | .subdevice = 0x8197, |
1844 | .name = "Sony S1XP", | 1844 | .name = "Sony S1XP", |
1845 | .type = AC97_TUNE_INV_EAPD | 1845 | .type = AC97_TUNE_INV_EAPD |
1846 | }, | 1846 | }, |
1847 | { | 1847 | { |
1848 | .vendor = 0x1043, | 1848 | .subvendor = 0x1043, |
1849 | .device = 0x80f3, | 1849 | .subdevice = 0x80f3, |
1850 | .name = "ASUS ICH5/AD1985", | 1850 | .name = "ASUS ICH5/AD1985", |
1851 | .type = AC97_TUNE_AD_SHARING | 1851 | .type = AC97_TUNE_AD_SHARING |
1852 | }, | 1852 | }, |
1853 | { | 1853 | { |
1854 | .vendor = 0x10cf, | 1854 | .subvendor = 0x10cf, |
1855 | .device = 0x11c3, | 1855 | .subdevice = 0x11c3, |
1856 | .name = "Fujitsu-Siemens E4010", | 1856 | .name = "Fujitsu-Siemens E4010", |
1857 | .type = AC97_TUNE_HP_ONLY | 1857 | .type = AC97_TUNE_HP_ONLY |
1858 | }, | 1858 | }, |
1859 | { | 1859 | { |
1860 | .vendor = 0x10cf, | 1860 | .subvendor = 0x10cf, |
1861 | .device = 0x1253, | 1861 | .subdevice = 0x1225, |
1862 | .name = "Fujitsu-Siemens T3010", | ||
1863 | .type = AC97_TUNE_HP_ONLY | ||
1864 | }, | ||
1865 | { | ||
1866 | .subvendor = 0x10cf, | ||
1867 | .subdevice = 0x1253, | ||
1862 | .name = "Fujitsu S6210", /* STAC9750/51 */ | 1868 | .name = "Fujitsu S6210", /* STAC9750/51 */ |
1863 | .type = AC97_TUNE_HP_ONLY | 1869 | .type = AC97_TUNE_HP_ONLY |
1864 | }, | 1870 | }, |
1865 | { | 1871 | { |
1866 | .vendor = 0x10f1, | 1872 | .subvendor = 0x10f1, |
1867 | .device = 0x2665, | 1873 | .subdevice = 0x2665, |
1868 | .name = "Fujitsu-Siemens Celsius", /* AD1981? */ | 1874 | .name = "Fujitsu-Siemens Celsius", /* AD1981? */ |
1869 | .type = AC97_TUNE_HP_ONLY | 1875 | .type = AC97_TUNE_HP_ONLY |
1870 | }, | 1876 | }, |
1871 | { | 1877 | { |
1872 | .vendor = 0x10f1, | 1878 | .subvendor = 0x10f1, |
1873 | .device = 0x2885, | 1879 | .subdevice = 0x2885, |
1874 | .name = "AMD64 Mobo", /* ALC650 */ | 1880 | .name = "AMD64 Mobo", /* ALC650 */ |
1875 | .type = AC97_TUNE_HP_ONLY | 1881 | .type = AC97_TUNE_HP_ONLY |
1876 | }, | 1882 | }, |
1877 | { | 1883 | { |
1878 | .vendor = 0x110a, | 1884 | .subvendor = 0x110a, |
1879 | .device = 0x0056, | 1885 | .subdevice = 0x0056, |
1880 | .name = "Fujitsu-Siemens Scenic", /* AD1981? */ | 1886 | .name = "Fujitsu-Siemens Scenic", /* AD1981? */ |
1881 | .type = AC97_TUNE_HP_ONLY | 1887 | .type = AC97_TUNE_HP_ONLY |
1882 | }, | 1888 | }, |
1883 | { | 1889 | { |
1884 | .vendor = 0x11d4, | 1890 | .subvendor = 0x11d4, |
1885 | .device = 0x5375, | 1891 | .subdevice = 0x5375, |
1886 | .name = "ADI AD1985 (discrete)", | 1892 | .name = "ADI AD1985 (discrete)", |
1887 | .type = AC97_TUNE_HP_ONLY | 1893 | .type = AC97_TUNE_HP_ONLY |
1888 | }, | 1894 | }, |
1889 | { | 1895 | { |
1890 | .vendor = 0x1462, | 1896 | .subvendor = 0x1462, |
1891 | .device = 0x5470, | 1897 | .subdevice = 0x5470, |
1892 | .name = "MSI P4 ATX 645 Ultra", | 1898 | .name = "MSI P4 ATX 645 Ultra", |
1893 | .type = AC97_TUNE_HP_ONLY | 1899 | .type = AC97_TUNE_HP_ONLY |
1894 | }, | 1900 | }, |
1895 | { | 1901 | { |
1896 | .vendor = 0x1734, | 1902 | .subvendor = 0x1734, |
1897 | .device = 0x0088, | 1903 | .subdevice = 0x0088, |
1898 | .name = "Fujitsu-Siemens D1522", /* AD1981 */ | 1904 | .name = "Fujitsu-Siemens D1522", /* AD1981 */ |
1899 | .type = AC97_TUNE_HP_ONLY | 1905 | .type = AC97_TUNE_HP_ONLY |
1900 | }, | 1906 | }, |
1901 | { | 1907 | { |
1902 | .vendor = 0x8086, | 1908 | .subvendor = 0x8086, |
1903 | .device = 0x2000, | 1909 | .subdevice = 0x2000, |
1904 | .mask = 0xfff0, | 1910 | .mask = 0xfff0, |
1905 | .name = "Intel ICH5/AD1985", | 1911 | .name = "Intel ICH5/AD1985", |
1906 | .type = AC97_TUNE_AD_SHARING | 1912 | .type = AC97_TUNE_AD_SHARING |
1907 | }, | 1913 | }, |
1908 | { | 1914 | { |
1909 | .vendor = 0x8086, | 1915 | .subvendor = 0x8086, |
1910 | .device = 0x4000, | 1916 | .subdevice = 0x4000, |
1911 | .mask = 0xfff0, | 1917 | .mask = 0xfff0, |
1912 | .name = "Intel ICH5/AD1985", | 1918 | .name = "Intel ICH5/AD1985", |
1913 | .type = AC97_TUNE_AD_SHARING | 1919 | .type = AC97_TUNE_AD_SHARING |
1914 | }, | 1920 | }, |
1915 | { | 1921 | { |
1916 | .vendor = 0x8086, | 1922 | .subvendor = 0x8086, |
1917 | .device = 0x4856, | 1923 | .subdevice = 0x4856, |
1918 | .name = "Intel D845WN (82801BA)", | 1924 | .name = "Intel D845WN (82801BA)", |
1919 | .type = AC97_TUNE_SWAP_HP | 1925 | .type = AC97_TUNE_SWAP_HP |
1920 | }, | 1926 | }, |
1921 | { | 1927 | { |
1922 | .vendor = 0x8086, | 1928 | .subvendor = 0x8086, |
1923 | .device = 0x4d44, | 1929 | .subdevice = 0x4d44, |
1924 | .name = "Intel D850EMV2", /* AD1885 */ | 1930 | .name = "Intel D850EMV2", /* AD1885 */ |
1925 | .type = AC97_TUNE_HP_ONLY | 1931 | .type = AC97_TUNE_HP_ONLY |
1926 | }, | 1932 | }, |
1927 | { | 1933 | { |
1928 | .vendor = 0x8086, | 1934 | .subvendor = 0x8086, |
1929 | .device = 0x4d56, | 1935 | .subdevice = 0x4d56, |
1930 | .name = "Intel ICH/AD1885", | 1936 | .name = "Intel ICH/AD1885", |
1931 | .type = AC97_TUNE_HP_ONLY | 1937 | .type = AC97_TUNE_HP_ONLY |
1932 | }, | 1938 | }, |
1933 | { | 1939 | { |
1934 | .vendor = 0x8086, | 1940 | .subvendor = 0x8086, |
1935 | .device = 0x6000, | 1941 | .subdevice = 0x6000, |
1936 | .mask = 0xfff0, | 1942 | .mask = 0xfff0, |
1937 | .name = "Intel ICH5/AD1985", | 1943 | .name = "Intel ICH5/AD1985", |
1938 | .type = AC97_TUNE_AD_SHARING | 1944 | .type = AC97_TUNE_AD_SHARING |
1939 | }, | 1945 | }, |
1940 | { | 1946 | { |
1941 | .vendor = 0x8086, | 1947 | .subvendor = 0x8086, |
1942 | .device = 0xe000, | 1948 | .subdevice = 0xe000, |
1943 | .mask = 0xfff0, | 1949 | .mask = 0xfff0, |
1944 | .name = "Intel ICH5/AD1985", | 1950 | .name = "Intel ICH5/AD1985", |
1945 | .type = AC97_TUNE_AD_SHARING | 1951 | .type = AC97_TUNE_AD_SHARING |
1946 | }, | 1952 | }, |
1947 | #if 0 /* FIXME: this seems wrong on most boards */ | 1953 | #if 0 /* FIXME: this seems wrong on most boards */ |
1948 | { | 1954 | { |
1949 | .vendor = 0x8086, | 1955 | .subvendor = 0x8086, |
1950 | .device = 0xa000, | 1956 | .subdevice = 0xa000, |
1951 | .mask = 0xfff0, | 1957 | .mask = 0xfff0, |
1952 | .name = "Intel ICH5/AD1985", | 1958 | .name = "Intel ICH5/AD1985", |
1953 | .type = AC97_TUNE_HP_ONLY | 1959 | .type = AC97_TUNE_HP_ONLY |
@@ -2849,7 +2855,7 @@ static struct pci_driver driver = { | |||
2849 | 2855 | ||
2850 | static int __init alsa_card_intel8x0_init(void) | 2856 | static int __init alsa_card_intel8x0_init(void) |
2851 | { | 2857 | { |
2852 | return pci_module_init(&driver); | 2858 | return pci_register_driver(&driver); |
2853 | } | 2859 | } |
2854 | 2860 | ||
2855 | static void __exit alsa_card_intel8x0_exit(void) | 2861 | static void __exit alsa_card_intel8x0_exit(void) |
diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index 67da096d659b..bb758c77d211 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c | |||
@@ -35,7 +35,6 @@ | |||
35 | #include <sound/pcm.h> | 35 | #include <sound/pcm.h> |
36 | #include <sound/ac97_codec.h> | 36 | #include <sound/ac97_codec.h> |
37 | #include <sound/info.h> | 37 | #include <sound/info.h> |
38 | #include <sound/control.h> | ||
39 | #include <sound/initval.h> | 38 | #include <sound/initval.h> |
40 | 39 | ||
41 | MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); | 40 | MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); |
@@ -292,60 +291,9 @@ static struct pci_device_id snd_intel8x0m_ids[] = { | |||
292 | #endif | 291 | #endif |
293 | { 0, } | 292 | { 0, } |
294 | }; | 293 | }; |
295 | static int snd_intel8x0m_switch_default_get(snd_kcontrol_t *kcontrol, | ||
296 | snd_ctl_elem_value_t *ucontrol); | ||
297 | static int snd_intel8x0m_switch_default_put(snd_kcontrol_t *kcontrol, | ||
298 | snd_ctl_elem_value_t *ucontrol); | ||
299 | static int snd_intel8x0m_switch_default_info(snd_kcontrol_t *kcontrol, | ||
300 | snd_ctl_elem_info_t *uinfo); | ||
301 | |||
302 | #define PRIVATE_VALUE_INITIALIZER(r,m) (((r) & 0xffff) << 16 | ((m) & 0xffff)) | ||
303 | #define PRIVATE_VALUE_MASK(control) ((control)->private_value & 0xffff) | ||
304 | #define PRIVATE_VALUE_REG(control) (((control)->private_value >> 16) & 0xffff) | ||
305 | |||
306 | static snd_kcontrol_new_t snd_intel8x0m_mixer_switches[] __devinitdata = { | ||
307 | { .name = "Off-hook Switch", | ||
308 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
309 | .info = snd_intel8x0m_switch_default_info, | ||
310 | .get = snd_intel8x0m_switch_default_get, | ||
311 | .put = snd_intel8x0m_switch_default_put, | ||
312 | .private_value = PRIVATE_VALUE_INITIALIZER(AC97_GPIO_STATUS,AC97_GPIO_LINE1_OH) | ||
313 | } | ||
314 | }; | ||
315 | 294 | ||
316 | MODULE_DEVICE_TABLE(pci, snd_intel8x0m_ids); | 295 | MODULE_DEVICE_TABLE(pci, snd_intel8x0m_ids); |
317 | 296 | ||
318 | static int snd_intel8x0m_switch_default_info(snd_kcontrol_t *kcontrol, | ||
319 | snd_ctl_elem_info_t *uinfo) | ||
320 | { | ||
321 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
322 | uinfo->count = 1; | ||
323 | uinfo->value.integer.min = 0; | ||
324 | uinfo->value.integer.max = 1; | ||
325 | return 0; | ||
326 | } | ||
327 | |||
328 | static int snd_intel8x0m_switch_default_get(snd_kcontrol_t *kcontrol, | ||
329 | snd_ctl_elem_value_t *ucontrol) | ||
330 | { | ||
331 | unsigned short mask = PRIVATE_VALUE_MASK(kcontrol); | ||
332 | unsigned short reg = PRIVATE_VALUE_REG(kcontrol); | ||
333 | intel8x0_t *chip = snd_kcontrol_chip(kcontrol); | ||
334 | unsigned int status; | ||
335 | status = snd_ac97_read(chip->ac97, reg) & mask ? 1 : 0; | ||
336 | ucontrol->value.integer.value[0] = status; | ||
337 | return 0; | ||
338 | } | ||
339 | static int snd_intel8x0m_switch_default_put(snd_kcontrol_t *kcontrol, | ||
340 | snd_ctl_elem_value_t *ucontrol) | ||
341 | { | ||
342 | unsigned short mask = PRIVATE_VALUE_MASK(kcontrol); | ||
343 | unsigned short reg = PRIVATE_VALUE_REG(kcontrol); | ||
344 | intel8x0_t *chip = snd_kcontrol_chip(kcontrol); | ||
345 | unsigned short new_status = ucontrol->value.integer.value[0] ? mask : ~mask; | ||
346 | return snd_ac97_update_bits(chip->ac97, reg, | ||
347 | mask, new_status); | ||
348 | } | ||
349 | /* | 297 | /* |
350 | * Lowlevel I/O - busmaster | 298 | * Lowlevel I/O - busmaster |
351 | */ | 299 | */ |
@@ -500,6 +448,8 @@ static unsigned short snd_intel8x0_codec_read(ac97_t *ac97, | |||
500 | res = 0xffff; | 448 | res = 0xffff; |
501 | } | 449 | } |
502 | } | 450 | } |
451 | if (reg == AC97_GPIO_STATUS) | ||
452 | iagetword(chip, 0); /* clear semaphore */ | ||
503 | return res; | 453 | return res; |
504 | } | 454 | } |
505 | 455 | ||
@@ -698,21 +648,6 @@ static snd_pcm_uframes_t snd_intel8x0_pcm_pointer(snd_pcm_substream_t * substrea | |||
698 | return bytes_to_frames(substream->runtime, ptr); | 648 | return bytes_to_frames(substream->runtime, ptr); |
699 | } | 649 | } |
700 | 650 | ||
701 | static int snd_intel8x0m_pcm_trigger(snd_pcm_substream_t *substream, int cmd) | ||
702 | { | ||
703 | /* hook off/on on start/stop */ | ||
704 | /* Moved this to mixer control */ | ||
705 | switch (cmd) { | ||
706 | case SNDRV_PCM_TRIGGER_START: | ||
707 | break; | ||
708 | case SNDRV_PCM_TRIGGER_STOP: | ||
709 | break; | ||
710 | default: | ||
711 | return -EINVAL; | ||
712 | } | ||
713 | return snd_intel8x0_pcm_trigger(substream,cmd); | ||
714 | } | ||
715 | |||
716 | static int snd_intel8x0m_pcm_prepare(snd_pcm_substream_t * substream) | 651 | static int snd_intel8x0m_pcm_prepare(snd_pcm_substream_t * substream) |
717 | { | 652 | { |
718 | intel8x0_t *chip = snd_pcm_substream_chip(substream); | 653 | intel8x0_t *chip = snd_pcm_substream_chip(substream); |
@@ -808,7 +743,7 @@ static snd_pcm_ops_t snd_intel8x0m_playback_ops = { | |||
808 | .hw_params = snd_intel8x0_hw_params, | 743 | .hw_params = snd_intel8x0_hw_params, |
809 | .hw_free = snd_intel8x0_hw_free, | 744 | .hw_free = snd_intel8x0_hw_free, |
810 | .prepare = snd_intel8x0m_pcm_prepare, | 745 | .prepare = snd_intel8x0m_pcm_prepare, |
811 | .trigger = snd_intel8x0m_pcm_trigger, | 746 | .trigger = snd_intel8x0_pcm_trigger, |
812 | .pointer = snd_intel8x0_pcm_pointer, | 747 | .pointer = snd_intel8x0_pcm_pointer, |
813 | }; | 748 | }; |
814 | 749 | ||
@@ -819,7 +754,7 @@ static snd_pcm_ops_t snd_intel8x0m_capture_ops = { | |||
819 | .hw_params = snd_intel8x0_hw_params, | 754 | .hw_params = snd_intel8x0_hw_params, |
820 | .hw_free = snd_intel8x0_hw_free, | 755 | .hw_free = snd_intel8x0_hw_free, |
821 | .prepare = snd_intel8x0m_pcm_prepare, | 756 | .prepare = snd_intel8x0m_pcm_prepare, |
822 | .trigger = snd_intel8x0m_pcm_trigger, | 757 | .trigger = snd_intel8x0_pcm_trigger, |
823 | .pointer = snd_intel8x0_pcm_pointer, | 758 | .pointer = snd_intel8x0_pcm_pointer, |
824 | }; | 759 | }; |
825 | 760 | ||
@@ -947,7 +882,6 @@ static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock) | |||
947 | ac97_t *x97; | 882 | ac97_t *x97; |
948 | int err; | 883 | int err; |
949 | unsigned int glob_sta = 0; | 884 | unsigned int glob_sta = 0; |
950 | unsigned int idx; | ||
951 | static ac97_bus_ops_t ops = { | 885 | static ac97_bus_ops_t ops = { |
952 | .write = snd_intel8x0_codec_write, | 886 | .write = snd_intel8x0_codec_write, |
953 | .read = snd_intel8x0_codec_read, | 887 | .read = snd_intel8x0_codec_read, |
@@ -983,10 +917,6 @@ static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock) | |||
983 | chip->ichd[ICHD_MDMIN].ac97 = x97; | 917 | chip->ichd[ICHD_MDMIN].ac97 = x97; |
984 | chip->ichd[ICHD_MDMOUT].ac97 = x97; | 918 | chip->ichd[ICHD_MDMOUT].ac97 = x97; |
985 | } | 919 | } |
986 | for (idx = 0; idx < ARRAY_SIZE(snd_intel8x0m_mixer_switches); idx++) { | ||
987 | if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_intel8x0m_mixer_switches[idx], chip))) < 0) | ||
988 | goto __err; | ||
989 | } | ||
990 | 920 | ||
991 | chip->in_ac97_init = 0; | 921 | chip->in_ac97_init = 0; |
992 | return 0; | 922 | return 0; |
@@ -1450,7 +1380,7 @@ static struct pci_driver driver = { | |||
1450 | 1380 | ||
1451 | static int __init alsa_card_intel8x0m_init(void) | 1381 | static int __init alsa_card_intel8x0m_init(void) |
1452 | { | 1382 | { |
1453 | return pci_module_init(&driver); | 1383 | return pci_register_driver(&driver); |
1454 | } | 1384 | } |
1455 | 1385 | ||
1456 | static void __exit alsa_card_intel8x0m_exit(void) | 1386 | static void __exit alsa_card_intel8x0m_exit(void) |
diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c index bb1de2008176..79d8eda54f0d 100644 --- a/sound/pci/korg1212/korg1212.c +++ b/sound/pci/korg1212/korg1212.c | |||
@@ -2541,7 +2541,7 @@ static struct pci_driver driver = { | |||
2541 | 2541 | ||
2542 | static int __init alsa_card_korg1212_init(void) | 2542 | static int __init alsa_card_korg1212_init(void) |
2543 | { | 2543 | { |
2544 | return pci_module_init(&driver); | 2544 | return pci_register_driver(&driver); |
2545 | } | 2545 | } |
2546 | 2546 | ||
2547 | static void __exit alsa_card_korg1212_exit(void) | 2547 | static void __exit alsa_card_korg1212_exit(void) |
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index 2cf33083d7cc..096f15132853 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c | |||
@@ -779,6 +779,12 @@ struct m3_quirk { | |||
779 | (e.g. for IrDA on Dell Inspirons) */ | 779 | (e.g. for IrDA on Dell Inspirons) */ |
780 | }; | 780 | }; |
781 | 781 | ||
782 | struct m3_hv_quirk { | ||
783 | u16 vendor, device, subsystem_vendor, subsystem_device; | ||
784 | u32 config; /* ALLEGRO_CONFIG hardware volume bits */ | ||
785 | int is_omnibook; /* Do HP OmniBook GPIO magic? */ | ||
786 | }; | ||
787 | |||
782 | struct m3_list { | 788 | struct m3_list { |
783 | int curlen; | 789 | int curlen; |
784 | int mem_addr; | 790 | int mem_addr; |
@@ -828,6 +834,7 @@ struct snd_m3 { | |||
828 | 834 | ||
829 | struct pci_dev *pci; | 835 | struct pci_dev *pci; |
830 | struct m3_quirk *quirk; | 836 | struct m3_quirk *quirk; |
837 | struct m3_hv_quirk *hv_quirk; | ||
831 | 838 | ||
832 | int dacs_active; | 839 | int dacs_active; |
833 | int timer_users; | 840 | int timer_users; |
@@ -851,6 +858,11 @@ struct snd_m3 { | |||
851 | m3_dma_t *substreams; | 858 | m3_dma_t *substreams; |
852 | 859 | ||
853 | spinlock_t reg_lock; | 860 | spinlock_t reg_lock; |
861 | spinlock_t ac97_lock; | ||
862 | |||
863 | snd_kcontrol_t *master_switch; | ||
864 | snd_kcontrol_t *master_volume; | ||
865 | struct tasklet_struct hwvol_tq; | ||
854 | 866 | ||
855 | #ifdef CONFIG_PM | 867 | #ifdef CONFIG_PM |
856 | u16 *suspend_mem; | 868 | u16 *suspend_mem; |
@@ -968,6 +980,71 @@ static struct m3_quirk m3_quirk_list[] = { | |||
968 | { NULL } | 980 | { NULL } |
969 | }; | 981 | }; |
970 | 982 | ||
983 | /* These values came from the Windows driver. */ | ||
984 | static struct m3_hv_quirk m3_hv_quirk_list[] = { | ||
985 | /* Allegro chips */ | ||
986 | { 0x125D, 0x1988, 0x0E11, 0x002E, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | ||
987 | { 0x125D, 0x1988, 0x0E11, 0x0094, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | ||
988 | { 0x125D, 0x1988, 0x0E11, 0xB112, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | ||
989 | { 0x125D, 0x1988, 0x0E11, 0xB114, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | ||
990 | { 0x125D, 0x1988, 0x103C, 0x0012, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | ||
991 | { 0x125D, 0x1988, 0x103C, 0x0018, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | ||
992 | { 0x125D, 0x1988, 0x103C, 0x001C, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | ||
993 | { 0x125D, 0x1988, 0x103C, 0x001D, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | ||
994 | { 0x125D, 0x1988, 0x103C, 0x001E, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | ||
995 | { 0x125D, 0x1988, 0x107B, 0x3350, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | ||
996 | { 0x125D, 0x1988, 0x10F7, 0x8338, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | ||
997 | { 0x125D, 0x1988, 0x10F7, 0x833C, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | ||
998 | { 0x125D, 0x1988, 0x10F7, 0x833D, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | ||
999 | { 0x125D, 0x1988, 0x10F7, 0x833E, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | ||
1000 | { 0x125D, 0x1988, 0x10F7, 0x833F, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | ||
1001 | { 0x125D, 0x1988, 0x13BD, 0x1018, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | ||
1002 | { 0x125D, 0x1988, 0x13BD, 0x1019, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | ||
1003 | { 0x125D, 0x1988, 0x13BD, 0x101A, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | ||
1004 | { 0x125D, 0x1988, 0x14FF, 0x0F03, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | ||
1005 | { 0x125D, 0x1988, 0x14FF, 0x0F04, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | ||
1006 | { 0x125D, 0x1988, 0x14FF, 0x0F05, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | ||
1007 | { 0x125D, 0x1988, 0x156D, 0xB400, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | ||
1008 | { 0x125D, 0x1988, 0x156D, 0xB795, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | ||
1009 | { 0x125D, 0x1988, 0x156D, 0xB797, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | ||
1010 | { 0x125D, 0x1988, 0x156D, 0xC700, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, | ||
1011 | { 0x125D, 0x1988, 0x1033, 0x80F1, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, | ||
1012 | { 0x125D, 0x1988, 0x103C, 0x001A, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, /* HP OmniBook 6100 */ | ||
1013 | { 0x125D, 0x1988, 0x107B, 0x340A, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, | ||
1014 | { 0x125D, 0x1988, 0x107B, 0x3450, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, | ||
1015 | { 0x125D, 0x1988, 0x109F, 0x3134, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, | ||
1016 | { 0x125D, 0x1988, 0x109F, 0x3161, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, | ||
1017 | { 0x125D, 0x1988, 0x144D, 0x3280, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, | ||
1018 | { 0x125D, 0x1988, 0x144D, 0x3281, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, | ||
1019 | { 0x125D, 0x1988, 0x144D, 0xC002, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, | ||
1020 | { 0x125D, 0x1988, 0x144D, 0xC003, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, | ||
1021 | { 0x125D, 0x1988, 0x1509, 0x1740, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, | ||
1022 | { 0x125D, 0x1988, 0x1610, 0x0010, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, | ||
1023 | { 0x125D, 0x1988, 0x1042, 0x1042, HV_CTRL_ENABLE, 0 }, | ||
1024 | { 0x125D, 0x1988, 0x107B, 0x9500, HV_CTRL_ENABLE, 0 }, | ||
1025 | { 0x125D, 0x1988, 0x14FF, 0x0F06, HV_CTRL_ENABLE, 0 }, | ||
1026 | { 0x125D, 0x1988, 0x1558, 0x8586, HV_CTRL_ENABLE, 0 }, | ||
1027 | { 0x125D, 0x1988, 0x161F, 0x2011, HV_CTRL_ENABLE, 0 }, | ||
1028 | /* Maestro3 chips */ | ||
1029 | { 0x125D, 0x1998, 0x103C, 0x000E, HV_CTRL_ENABLE, 0 }, | ||
1030 | { 0x125D, 0x1998, 0x103C, 0x0010, HV_CTRL_ENABLE, 1 }, /* HP OmniBook 6000 */ | ||
1031 | { 0x125D, 0x1998, 0x103C, 0x0011, HV_CTRL_ENABLE, 1 }, /* HP OmniBook 500 */ | ||
1032 | { 0x125D, 0x1998, 0x103C, 0x001B, HV_CTRL_ENABLE, 0 }, | ||
1033 | { 0x125D, 0x1998, 0x104D, 0x80A6, HV_CTRL_ENABLE, 0 }, | ||
1034 | { 0x125D, 0x1998, 0x104D, 0x80AA, HV_CTRL_ENABLE, 0 }, | ||
1035 | { 0x125D, 0x1998, 0x107B, 0x5300, HV_CTRL_ENABLE, 0 }, | ||
1036 | { 0x125D, 0x1998, 0x110A, 0x1998, HV_CTRL_ENABLE, 0 }, | ||
1037 | { 0x125D, 0x1998, 0x13BD, 0x1015, HV_CTRL_ENABLE, 0 }, | ||
1038 | { 0x125D, 0x1998, 0x13BD, 0x101C, HV_CTRL_ENABLE, 0 }, | ||
1039 | { 0x125D, 0x1998, 0x13BD, 0x1802, HV_CTRL_ENABLE, 0 }, | ||
1040 | { 0x125D, 0x1998, 0x1599, 0x0715, HV_CTRL_ENABLE, 0 }, | ||
1041 | { 0x125D, 0x1998, 0x5643, 0x5643, HV_CTRL_ENABLE, 0 }, | ||
1042 | { 0x125D, 0x199A, 0x144D, 0x3260, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 }, | ||
1043 | { 0x125D, 0x199A, 0x144D, 0x3261, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 }, | ||
1044 | { 0x125D, 0x199A, 0x144D, 0xC000, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 }, | ||
1045 | { 0x125D, 0x199A, 0x144D, 0xC001, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 }, | ||
1046 | { 0 } | ||
1047 | }; | ||
971 | 1048 | ||
972 | /* | 1049 | /* |
973 | * lowlevel functions | 1050 | * lowlevel functions |
@@ -1565,6 +1642,68 @@ static void snd_m3_update_ptr(m3_t *chip, m3_dma_t *s) | |||
1565 | } | 1642 | } |
1566 | } | 1643 | } |
1567 | 1644 | ||
1645 | static void snd_m3_update_hw_volume(unsigned long private_data) | ||
1646 | { | ||
1647 | m3_t *chip = (m3_t *) private_data; | ||
1648 | int x, val; | ||
1649 | unsigned long flags; | ||
1650 | |||
1651 | /* Figure out which volume control button was pushed, | ||
1652 | based on differences from the default register | ||
1653 | values. */ | ||
1654 | x = inb(chip->iobase + SHADOW_MIX_REG_VOICE) & 0xee; | ||
1655 | |||
1656 | /* Reset the volume control registers. */ | ||
1657 | outb(0x88, chip->iobase + SHADOW_MIX_REG_VOICE); | ||
1658 | outb(0x88, chip->iobase + HW_VOL_COUNTER_VOICE); | ||
1659 | outb(0x88, chip->iobase + SHADOW_MIX_REG_MASTER); | ||
1660 | outb(0x88, chip->iobase + HW_VOL_COUNTER_MASTER); | ||
1661 | |||
1662 | if (!chip->master_switch || !chip->master_volume) | ||
1663 | return; | ||
1664 | |||
1665 | /* FIXME: we can't call snd_ac97_* functions since here is in tasklet. */ | ||
1666 | spin_lock_irqsave(&chip->ac97_lock, flags); | ||
1667 | |||
1668 | val = chip->ac97->regs[AC97_MASTER_VOL]; | ||
1669 | switch (x) { | ||
1670 | case 0x88: | ||
1671 | /* mute */ | ||
1672 | val ^= 0x8000; | ||
1673 | chip->ac97->regs[AC97_MASTER_VOL] = val; | ||
1674 | outw(val, chip->iobase + CODEC_DATA); | ||
1675 | outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND); | ||
1676 | snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
1677 | &chip->master_switch->id); | ||
1678 | break; | ||
1679 | case 0xaa: | ||
1680 | /* volume up */ | ||
1681 | if ((val & 0x7f) > 0) | ||
1682 | val--; | ||
1683 | if ((val & 0x7f00) > 0) | ||
1684 | val -= 0x0100; | ||
1685 | chip->ac97->regs[AC97_MASTER_VOL] = val; | ||
1686 | outw(val, chip->iobase + CODEC_DATA); | ||
1687 | outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND); | ||
1688 | snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
1689 | &chip->master_volume->id); | ||
1690 | break; | ||
1691 | case 0x66: | ||
1692 | /* volume down */ | ||
1693 | if ((val & 0x7f) < 0x1f) | ||
1694 | val++; | ||
1695 | if ((val & 0x7f00) < 0x1f00) | ||
1696 | val += 0x0100; | ||
1697 | chip->ac97->regs[AC97_MASTER_VOL] = val; | ||
1698 | outw(val, chip->iobase + CODEC_DATA); | ||
1699 | outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND); | ||
1700 | snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
1701 | &chip->master_volume->id); | ||
1702 | break; | ||
1703 | } | ||
1704 | spin_unlock_irqrestore(&chip->ac97_lock, flags); | ||
1705 | } | ||
1706 | |||
1568 | static irqreturn_t | 1707 | static irqreturn_t |
1569 | snd_m3_interrupt(int irq, void *dev_id, struct pt_regs *regs) | 1708 | snd_m3_interrupt(int irq, void *dev_id, struct pt_regs *regs) |
1570 | { | 1709 | { |
@@ -1576,7 +1715,10 @@ snd_m3_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
1576 | 1715 | ||
1577 | if (status == 0xff) | 1716 | if (status == 0xff) |
1578 | return IRQ_NONE; | 1717 | return IRQ_NONE; |
1579 | 1718 | ||
1719 | if (status & HV_INT_PENDING) | ||
1720 | tasklet_hi_schedule(&chip->hwvol_tq); | ||
1721 | |||
1580 | /* | 1722 | /* |
1581 | * ack an assp int if its running | 1723 | * ack an assp int if its running |
1582 | * and has an int pending | 1724 | * and has an int pending |
@@ -1605,7 +1747,7 @@ snd_m3_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
1605 | #endif | 1747 | #endif |
1606 | 1748 | ||
1607 | /* ack ints */ | 1749 | /* ack ints */ |
1608 | snd_m3_outw(chip, HOST_INT_STATUS, status); | 1750 | outb(status, chip->iobase + HOST_INT_STATUS); |
1609 | 1751 | ||
1610 | return IRQ_HANDLED; | 1752 | return IRQ_HANDLED; |
1611 | } | 1753 | } |
@@ -1842,24 +1984,32 @@ static unsigned short | |||
1842 | snd_m3_ac97_read(ac97_t *ac97, unsigned short reg) | 1984 | snd_m3_ac97_read(ac97_t *ac97, unsigned short reg) |
1843 | { | 1985 | { |
1844 | m3_t *chip = ac97->private_data; | 1986 | m3_t *chip = ac97->private_data; |
1987 | unsigned long flags; | ||
1988 | unsigned short data; | ||
1845 | 1989 | ||
1846 | if (snd_m3_ac97_wait(chip)) | 1990 | if (snd_m3_ac97_wait(chip)) |
1847 | return 0xffff; | 1991 | return 0xffff; |
1992 | spin_lock_irqsave(&chip->ac97_lock, flags); | ||
1848 | snd_m3_outb(chip, 0x80 | (reg & 0x7f), CODEC_COMMAND); | 1993 | snd_m3_outb(chip, 0x80 | (reg & 0x7f), CODEC_COMMAND); |
1849 | if (snd_m3_ac97_wait(chip)) | 1994 | if (snd_m3_ac97_wait(chip)) |
1850 | return 0xffff; | 1995 | return 0xffff; |
1851 | return snd_m3_inw(chip, CODEC_DATA); | 1996 | data = snd_m3_inw(chip, CODEC_DATA); |
1997 | spin_unlock_irqrestore(&chip->ac97_lock, flags); | ||
1998 | return data; | ||
1852 | } | 1999 | } |
1853 | 2000 | ||
1854 | static void | 2001 | static void |
1855 | snd_m3_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short val) | 2002 | snd_m3_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short val) |
1856 | { | 2003 | { |
1857 | m3_t *chip = ac97->private_data; | 2004 | m3_t *chip = ac97->private_data; |
2005 | unsigned long flags; | ||
1858 | 2006 | ||
1859 | if (snd_m3_ac97_wait(chip)) | 2007 | if (snd_m3_ac97_wait(chip)) |
1860 | return; | 2008 | return; |
2009 | spin_lock_irqsave(&chip->ac97_lock, flags); | ||
1861 | snd_m3_outw(chip, val, CODEC_DATA); | 2010 | snd_m3_outw(chip, val, CODEC_DATA); |
1862 | snd_m3_outb(chip, reg & 0x7f, CODEC_COMMAND); | 2011 | snd_m3_outb(chip, reg & 0x7f, CODEC_COMMAND); |
2012 | spin_unlock_irqrestore(&chip->ac97_lock, flags); | ||
1863 | } | 2013 | } |
1864 | 2014 | ||
1865 | 2015 | ||
@@ -1968,6 +2118,7 @@ static int __devinit snd_m3_mixer(m3_t *chip) | |||
1968 | { | 2118 | { |
1969 | ac97_bus_t *pbus; | 2119 | ac97_bus_t *pbus; |
1970 | ac97_template_t ac97; | 2120 | ac97_template_t ac97; |
2121 | snd_ctl_elem_id_t id; | ||
1971 | int err; | 2122 | int err; |
1972 | static ac97_bus_ops_t ops = { | 2123 | static ac97_bus_ops_t ops = { |
1973 | .write = snd_m3_ac97_write, | 2124 | .write = snd_m3_ac97_write, |
@@ -1988,6 +2139,15 @@ static int __devinit snd_m3_mixer(m3_t *chip) | |||
1988 | schedule_timeout(HZ / 10); | 2139 | schedule_timeout(HZ / 10); |
1989 | snd_ac97_write(chip->ac97, AC97_PCM, 0); | 2140 | snd_ac97_write(chip->ac97, AC97_PCM, 0); |
1990 | 2141 | ||
2142 | memset(&id, 0, sizeof(id)); | ||
2143 | id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
2144 | strcpy(id.name, "Master Playback Switch"); | ||
2145 | chip->master_switch = snd_ctl_find_id(chip->card, &id); | ||
2146 | memset(&id, 0, sizeof(id)); | ||
2147 | id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
2148 | strcpy(id.name, "Master Playback Volume"); | ||
2149 | chip->master_volume = snd_ctl_find_id(chip->card, &id); | ||
2150 | |||
1991 | return 0; | 2151 | return 0; |
1992 | } | 2152 | } |
1993 | 2153 | ||
@@ -2293,6 +2453,7 @@ static int | |||
2293 | snd_m3_chip_init(m3_t *chip) | 2453 | snd_m3_chip_init(m3_t *chip) |
2294 | { | 2454 | { |
2295 | struct pci_dev *pcidev = chip->pci; | 2455 | struct pci_dev *pcidev = chip->pci; |
2456 | unsigned long io = chip->iobase; | ||
2296 | u32 n; | 2457 | u32 n; |
2297 | u16 w; | 2458 | u16 w; |
2298 | u8 t; /* makes as much sense as 'n', no? */ | 2459 | u8 t; /* makes as much sense as 'n', no? */ |
@@ -2303,8 +2464,27 @@ snd_m3_chip_init(m3_t *chip) | |||
2303 | DISABLE_LEGACY); | 2464 | DISABLE_LEGACY); |
2304 | pci_write_config_word(pcidev, PCI_LEGACY_AUDIO_CTRL, w); | 2465 | pci_write_config_word(pcidev, PCI_LEGACY_AUDIO_CTRL, w); |
2305 | 2466 | ||
2467 | if (chip->hv_quirk && chip->hv_quirk->is_omnibook) { | ||
2468 | /* | ||
2469 | * Volume buttons on some HP OmniBook laptops don't work | ||
2470 | * correctly. This makes them work for the most part. | ||
2471 | * | ||
2472 | * Volume up and down buttons on the laptop side work. | ||
2473 | * Fn+cursor_up (volme up) works. | ||
2474 | * Fn+cursor_down (volume down) doesn't work. | ||
2475 | * Fn+F7 (mute) works acts as volume up. | ||
2476 | */ | ||
2477 | outw(~(GPI_VOL_DOWN|GPI_VOL_UP), io + GPIO_MASK); | ||
2478 | outw(inw(io + GPIO_DIRECTION) & ~(GPI_VOL_DOWN|GPI_VOL_UP), io + GPIO_DIRECTION); | ||
2479 | outw((GPI_VOL_DOWN|GPI_VOL_UP), io + GPIO_DATA); | ||
2480 | outw(0xffff, io + GPIO_MASK); | ||
2481 | } | ||
2306 | pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n); | 2482 | pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n); |
2307 | n &= REDUCED_DEBOUNCE; | 2483 | n &= ~(HV_CTRL_ENABLE | REDUCED_DEBOUNCE | HV_BUTTON_FROM_GD); |
2484 | if (chip->hv_quirk) | ||
2485 | n |= chip->hv_quirk->config; | ||
2486 | /* For some reason we must always use reduced debounce. */ | ||
2487 | n |= REDUCED_DEBOUNCE; | ||
2308 | n |= PM_CTRL_ENABLE | CLK_DIV_BY_49 | USE_PCI_TIMING; | 2488 | n |= PM_CTRL_ENABLE | CLK_DIV_BY_49 | USE_PCI_TIMING; |
2309 | pci_write_config_dword(pcidev, PCI_ALLEGRO_CONFIG, n); | 2489 | pci_write_config_dword(pcidev, PCI_ALLEGRO_CONFIG, n); |
2310 | 2490 | ||
@@ -2332,6 +2512,12 @@ snd_m3_chip_init(m3_t *chip) | |||
2332 | 2512 | ||
2333 | outb(RUN_ASSP, chip->iobase + ASSP_CONTROL_B); | 2513 | outb(RUN_ASSP, chip->iobase + ASSP_CONTROL_B); |
2334 | 2514 | ||
2515 | outb(0x00, io + HARDWARE_VOL_CTRL); | ||
2516 | outb(0x88, io + SHADOW_MIX_REG_VOICE); | ||
2517 | outb(0x88, io + HW_VOL_COUNTER_VOICE); | ||
2518 | outb(0x88, io + SHADOW_MIX_REG_MASTER); | ||
2519 | outb(0x88, io + HW_VOL_COUNTER_MASTER); | ||
2520 | |||
2335 | return 0; | 2521 | return 0; |
2336 | } | 2522 | } |
2337 | 2523 | ||
@@ -2341,7 +2527,7 @@ snd_m3_enable_ints(m3_t *chip) | |||
2341 | unsigned long io = chip->iobase; | 2527 | unsigned long io = chip->iobase; |
2342 | 2528 | ||
2343 | /* TODO: MPU401 not supported yet */ | 2529 | /* TODO: MPU401 not supported yet */ |
2344 | outw(ASSP_INT_ENABLE /*| MPU401_INT_ENABLE*/, io + HOST_INT_CTRL); | 2530 | outw(ASSP_INT_ENABLE | HV_INT_ENABLE /*| MPU401_INT_ENABLE*/, io + HOST_INT_CTRL); |
2345 | outb(inb(io + ASSP_CONTROL_C) | ASSP_HOST_INT_ENABLE, | 2531 | outb(inb(io + ASSP_CONTROL_C) | ASSP_HOST_INT_ENABLE, |
2346 | io + ASSP_CONTROL_C); | 2532 | io + ASSP_CONTROL_C); |
2347 | } | 2533 | } |
@@ -2367,7 +2553,7 @@ static int snd_m3_free(m3_t *chip) | |||
2367 | kfree(chip->substreams); | 2553 | kfree(chip->substreams); |
2368 | } | 2554 | } |
2369 | if (chip->iobase) { | 2555 | if (chip->iobase) { |
2370 | snd_m3_outw(chip, HOST_INT_CTRL, 0); /* disable ints */ | 2556 | outw(0, chip->iobase + HOST_INT_CTRL); /* disable ints */ |
2371 | } | 2557 | } |
2372 | 2558 | ||
2373 | #ifdef CONFIG_PM | 2559 | #ifdef CONFIG_PM |
@@ -2486,7 +2672,7 @@ snd_m3_create(snd_card_t *card, struct pci_dev *pci, | |||
2486 | m3_t *chip; | 2672 | m3_t *chip; |
2487 | int i, err; | 2673 | int i, err; |
2488 | struct m3_quirk *quirk; | 2674 | struct m3_quirk *quirk; |
2489 | u16 subsystem_vendor, subsystem_device; | 2675 | struct m3_hv_quirk *hv_quirk; |
2490 | static snd_device_ops_t ops = { | 2676 | static snd_device_ops_t ops = { |
2491 | .dev_free = snd_m3_dev_free, | 2677 | .dev_free = snd_m3_dev_free, |
2492 | }; | 2678 | }; |
@@ -2524,18 +2710,25 @@ snd_m3_create(snd_card_t *card, struct pci_dev *pci, | |||
2524 | chip->pci = pci; | 2710 | chip->pci = pci; |
2525 | chip->irq = -1; | 2711 | chip->irq = -1; |
2526 | 2712 | ||
2527 | pci_read_config_word(pci, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor); | ||
2528 | pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &subsystem_device); | ||
2529 | |||
2530 | for (quirk = m3_quirk_list; quirk->vendor; quirk++) { | 2713 | for (quirk = m3_quirk_list; quirk->vendor; quirk++) { |
2531 | if (subsystem_vendor == quirk->vendor && | 2714 | if (pci->subsystem_vendor == quirk->vendor && |
2532 | subsystem_device == quirk->device) { | 2715 | pci->subsystem_device == quirk->device) { |
2533 | printk(KERN_INFO "maestro3: enabled hack for '%s'\n", quirk->name); | 2716 | printk(KERN_INFO "maestro3: enabled hack for '%s'\n", quirk->name); |
2534 | chip->quirk = quirk; | 2717 | chip->quirk = quirk; |
2535 | break; | 2718 | break; |
2536 | } | 2719 | } |
2537 | } | 2720 | } |
2538 | 2721 | ||
2722 | for (hv_quirk = m3_hv_quirk_list; hv_quirk->vendor; hv_quirk++) { | ||
2723 | if (pci->vendor == hv_quirk->vendor && | ||
2724 | pci->device == hv_quirk->device && | ||
2725 | pci->subsystem_vendor == hv_quirk->subsystem_vendor && | ||
2726 | pci->subsystem_device == hv_quirk->subsystem_device) { | ||
2727 | chip->hv_quirk = hv_quirk; | ||
2728 | break; | ||
2729 | } | ||
2730 | } | ||
2731 | |||
2539 | chip->external_amp = enable_amp; | 2732 | chip->external_amp = enable_amp; |
2540 | if (amp_gpio >= 0 && amp_gpio <= 0x0f) | 2733 | if (amp_gpio >= 0 && amp_gpio <= 0x0f) |
2541 | chip->amp_gpio = amp_gpio; | 2734 | chip->amp_gpio = amp_gpio; |
@@ -2593,6 +2786,9 @@ snd_m3_create(snd_card_t *card, struct pci_dev *pci, | |||
2593 | return err; | 2786 | return err; |
2594 | } | 2787 | } |
2595 | 2788 | ||
2789 | spin_lock_init(&chip->ac97_lock); | ||
2790 | tasklet_init(&chip->hwvol_tq, snd_m3_update_hw_volume, (unsigned long)chip); | ||
2791 | |||
2596 | if ((err = snd_m3_mixer(chip)) < 0) | 2792 | if ((err = snd_m3_mixer(chip)) < 0) |
2597 | return err; | 2793 | return err; |
2598 | 2794 | ||
@@ -2702,7 +2898,7 @@ static struct pci_driver driver = { | |||
2702 | 2898 | ||
2703 | static int __init alsa_card_m3_init(void) | 2899 | static int __init alsa_card_m3_init(void) |
2704 | { | 2900 | { |
2705 | return pci_module_init(&driver); | 2901 | return pci_register_driver(&driver); |
2706 | } | 2902 | } |
2707 | 2903 | ||
2708 | static void __exit alsa_card_m3_exit(void) | 2904 | static void __exit alsa_card_m3_exit(void) |
diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c index 65bb0f47af2c..082c0d0f73d2 100644 --- a/sound/pci/mixart/mixart.c +++ b/sound/pci/mixart/mixart.c | |||
@@ -1431,7 +1431,7 @@ static struct pci_driver driver = { | |||
1431 | 1431 | ||
1432 | static int __init alsa_card_mixart_init(void) | 1432 | static int __init alsa_card_mixart_init(void) |
1433 | { | 1433 | { |
1434 | return pci_module_init(&driver); | 1434 | return pci_register_driver(&driver); |
1435 | } | 1435 | } |
1436 | 1436 | ||
1437 | static void __exit alsa_card_mixart_exit(void) | 1437 | static void __exit alsa_card_mixart_exit(void) |
diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c index 356fbeac6f9e..8a52091f8552 100644 --- a/sound/pci/nm256/nm256.c +++ b/sound/pci/nm256/nm256.c | |||
@@ -1645,7 +1645,7 @@ static struct pci_driver driver = { | |||
1645 | 1645 | ||
1646 | static int __init alsa_card_nm256_init(void) | 1646 | static int __init alsa_card_nm256_init(void) |
1647 | { | 1647 | { |
1648 | return pci_module_init(&driver); | 1648 | return pci_register_driver(&driver); |
1649 | } | 1649 | } |
1650 | 1650 | ||
1651 | static void __exit alsa_card_nm256_exit(void) | 1651 | static void __exit alsa_card_nm256_exit(void) |
diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c index b96acd5a57db..b7b554df6705 100644 --- a/sound/pci/rme32.c +++ b/sound/pci/rme32.c | |||
@@ -2031,7 +2031,7 @@ static struct pci_driver driver = { | |||
2031 | 2031 | ||
2032 | static int __init alsa_card_rme32_init(void) | 2032 | static int __init alsa_card_rme32_init(void) |
2033 | { | 2033 | { |
2034 | return pci_module_init(&driver); | 2034 | return pci_register_driver(&driver); |
2035 | } | 2035 | } |
2036 | 2036 | ||
2037 | static void __exit alsa_card_rme32_exit(void) | 2037 | static void __exit alsa_card_rme32_exit(void) |
diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c index 8e2666841d21..10c4f45a913c 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c | |||
@@ -2437,7 +2437,7 @@ static struct pci_driver driver = { | |||
2437 | 2437 | ||
2438 | static int __init alsa_card_rme96_init(void) | 2438 | static int __init alsa_card_rme96_init(void) |
2439 | { | 2439 | { |
2440 | return pci_module_init(&driver); | 2440 | return pci_register_driver(&driver); |
2441 | } | 2441 | } |
2442 | 2442 | ||
2443 | static void __exit alsa_card_rme96_exit(void) | 2443 | static void __exit alsa_card_rme96_exit(void) |
diff --git a/sound/pci/rme9652/Makefile b/sound/pci/rme9652/Makefile index 917374c9cd40..d2c294e136f9 100644 --- a/sound/pci/rme9652/Makefile +++ b/sound/pci/rme9652/Makefile | |||
@@ -5,7 +5,9 @@ | |||
5 | 5 | ||
6 | snd-rme9652-objs := rme9652.o | 6 | snd-rme9652-objs := rme9652.o |
7 | snd-hdsp-objs := hdsp.o | 7 | snd-hdsp-objs := hdsp.o |
8 | snd-hdspm-objs := hdspm.o | ||
8 | 9 | ||
9 | # Toplevel Module Dependency | 10 | # Toplevel Module Dependency |
10 | obj-$(CONFIG_SND_RME9652) += snd-rme9652.o | 11 | obj-$(CONFIG_SND_RME9652) += snd-rme9652.o |
11 | obj-$(CONFIG_SND_HDSP) += snd-hdsp.o | 12 | obj-$(CONFIG_SND_HDSP) += snd-hdsp.o |
13 | obj-$(CONFIG_SND_HDSPM) +=snd-hdspm.o | ||
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 12efbf0fab54..a673cc438b91 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c | |||
@@ -559,18 +559,22 @@ static int snd_hammerfall_get_buffer(struct pci_dev *pci, struct snd_dma_buffer | |||
559 | { | 559 | { |
560 | dmab->dev.type = SNDRV_DMA_TYPE_DEV; | 560 | dmab->dev.type = SNDRV_DMA_TYPE_DEV; |
561 | dmab->dev.dev = snd_dma_pci_data(pci); | 561 | dmab->dev.dev = snd_dma_pci_data(pci); |
562 | if (! snd_dma_get_reserved_buf(dmab, snd_dma_pci_buf_id(pci))) { | 562 | if (snd_dma_get_reserved_buf(dmab, snd_dma_pci_buf_id(pci))) { |
563 | if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), | 563 | if (dmab->bytes >= size) |
564 | size, dmab) < 0) | 564 | return 0; |
565 | return -ENOMEM; | ||
566 | } | 565 | } |
566 | if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), | ||
567 | size, dmab) < 0) | ||
568 | return -ENOMEM; | ||
567 | return 0; | 569 | return 0; |
568 | } | 570 | } |
569 | 571 | ||
570 | static void snd_hammerfall_free_buffer(struct snd_dma_buffer *dmab, struct pci_dev *pci) | 572 | static void snd_hammerfall_free_buffer(struct snd_dma_buffer *dmab, struct pci_dev *pci) |
571 | { | 573 | { |
572 | if (dmab->area) | 574 | if (dmab->area) { |
575 | dmab->dev.dev = NULL; /* make it anonymous */ | ||
573 | snd_dma_reserve_buf(dmab, snd_dma_pci_buf_id(pci)); | 576 | snd_dma_reserve_buf(dmab, snd_dma_pci_buf_id(pci)); |
577 | } | ||
574 | } | 578 | } |
575 | 579 | ||
576 | 580 | ||
@@ -4912,19 +4916,9 @@ static int __devinit hdsp_request_fw_loader(hdsp_t *hdsp) | |||
4912 | release_firmware(fw); | 4916 | release_firmware(fw); |
4913 | return -EINVAL; | 4917 | return -EINVAL; |
4914 | } | 4918 | } |
4915 | #ifdef SNDRV_BIG_ENDIAN | 4919 | |
4916 | { | ||
4917 | int i; | ||
4918 | u32 *src = (u32*)fw->data; | ||
4919 | for (i = 0; i < ARRAY_SIZE(hdsp->firmware_cache); i++, src++) | ||
4920 | hdsp->firmware_cache[i] = ((*src & 0x000000ff) << 16) | | ||
4921 | ((*src & 0x0000ff00) << 8) | | ||
4922 | ((*src & 0x00ff0000) >> 8) | | ||
4923 | ((*src & 0xff000000) >> 16); | ||
4924 | } | ||
4925 | #else | ||
4926 | memcpy(hdsp->firmware_cache, fw->data, sizeof(hdsp->firmware_cache)); | 4920 | memcpy(hdsp->firmware_cache, fw->data, sizeof(hdsp->firmware_cache)); |
4927 | #endif | 4921 | |
4928 | release_firmware(fw); | 4922 | release_firmware(fw); |
4929 | 4923 | ||
4930 | hdsp->state |= HDSP_FirmwareCached; | 4924 | hdsp->state |= HDSP_FirmwareCached; |
@@ -5194,7 +5188,7 @@ static struct pci_driver driver = { | |||
5194 | 5188 | ||
5195 | static int __init alsa_card_hdsp_init(void) | 5189 | static int __init alsa_card_hdsp_init(void) |
5196 | { | 5190 | { |
5197 | return pci_module_init(&driver); | 5191 | return pci_register_driver(&driver); |
5198 | } | 5192 | } |
5199 | 5193 | ||
5200 | static void __exit alsa_card_hdsp_exit(void) | 5194 | static void __exit alsa_card_hdsp_exit(void) |
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c new file mode 100644 index 000000000000..9e86d0eb41ce --- /dev/null +++ b/sound/pci/rme9652/hdspm.c | |||
@@ -0,0 +1,3671 @@ | |||
1 | /* -*- linux-c -*- | ||
2 | * | ||
3 | * ALSA driver for RME Hammerfall DSP MADI audio interface(s) | ||
4 | * | ||
5 | * Copyright (c) 2003 Winfried Ritsch (IEM) | ||
6 | * code based on hdsp.c Paul Davis | ||
7 | * Marcus Andersson | ||
8 | * Thomas Charbonnel | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
23 | * | ||
24 | */ | ||
25 | #include <sound/driver.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/delay.h> | ||
28 | #include <linux/interrupt.h> | ||
29 | #include <linux/moduleparam.h> | ||
30 | #include <linux/slab.h> | ||
31 | #include <linux/pci.h> | ||
32 | #include <asm/io.h> | ||
33 | |||
34 | #include <sound/core.h> | ||
35 | #include <sound/control.h> | ||
36 | #include <sound/pcm.h> | ||
37 | #include <sound/info.h> | ||
38 | #include <sound/asoundef.h> | ||
39 | #include <sound/rawmidi.h> | ||
40 | #include <sound/hwdep.h> | ||
41 | #include <sound/initval.h> | ||
42 | |||
43 | #include <sound/hdspm.h> | ||
44 | |||
45 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ | ||
46 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ | ||
47 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;/* Enable this card */ | ||
48 | |||
49 | /* Disable precise pointer at start */ | ||
50 | static int precise_ptr[SNDRV_CARDS]; | ||
51 | |||
52 | /* Send all playback to line outs */ | ||
53 | static int line_outs_monitor[SNDRV_CARDS]; | ||
54 | |||
55 | /* Enable Analog Outs on Channel 63/64 by default */ | ||
56 | static int enable_monitor[SNDRV_CARDS]; | ||
57 | |||
58 | module_param_array(index, int, NULL, 0444); | ||
59 | MODULE_PARM_DESC(index, "Index value for RME HDSPM interface."); | ||
60 | |||
61 | module_param_array(id, charp, NULL, 0444); | ||
62 | MODULE_PARM_DESC(id, "ID string for RME HDSPM interface."); | ||
63 | |||
64 | module_param_array(enable, bool, NULL, 0444); | ||
65 | MODULE_PARM_DESC(enable, "Enable/disable specific HDSPM soundcards."); | ||
66 | |||
67 | module_param_array(precise_ptr, bool, NULL, 0444); | ||
68 | MODULE_PARM_DESC(precise_ptr, "Enable precise pointer, or disable."); | ||
69 | |||
70 | module_param_array(line_outs_monitor, bool, NULL, 0444); | ||
71 | MODULE_PARM_DESC(line_outs_monitor, | ||
72 | "Send playback streams to analog outs by default."); | ||
73 | |||
74 | module_param_array(enable_monitor, bool, NULL, 0444); | ||
75 | MODULE_PARM_DESC(enable_monitor, | ||
76 | "Enable Analog Out on Channel 63/64 by default."); | ||
77 | |||
78 | MODULE_AUTHOR | ||
79 | ("Winfried Ritsch <ritsch_AT_iem.at>, Paul Davis <paul@linuxaudiosystems.com>, " | ||
80 | "Marcus Andersson, Thomas Charbonnel <thomas@undata.org>"); | ||
81 | MODULE_DESCRIPTION("RME HDSPM"); | ||
82 | MODULE_LICENSE("GPL"); | ||
83 | MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); | ||
84 | |||
85 | /* --- Write registers. --- | ||
86 | These are defined as byte-offsets from the iobase value. */ | ||
87 | |||
88 | #define HDSPM_controlRegister 64 | ||
89 | #define HDSPM_interruptConfirmation 96 | ||
90 | #define HDSPM_control2Reg 256 /* not in specs ???????? */ | ||
91 | #define HDSPM_midiDataOut0 352 /* just believe in old code */ | ||
92 | #define HDSPM_midiDataOut1 356 | ||
93 | |||
94 | /* DMA enable for 64 channels, only Bit 0 is relevant */ | ||
95 | #define HDSPM_outputEnableBase 512 /* 512-767 input DMA */ | ||
96 | #define HDSPM_inputEnableBase 768 /* 768-1023 output DMA */ | ||
97 | |||
98 | /* 16 page addresses for each of the 64 channels DMA buffer in and out | ||
99 | (each 64k=16*4k) Buffer must be 4k aligned (which is default i386 ????) */ | ||
100 | #define HDSPM_pageAddressBufferOut 8192 | ||
101 | #define HDSPM_pageAddressBufferIn (HDSPM_pageAddressBufferOut+64*16*4) | ||
102 | |||
103 | #define HDSPM_MADI_mixerBase 32768 /* 32768-65535 for 2x64x64 Fader */ | ||
104 | |||
105 | #define HDSPM_MATRIX_MIXER_SIZE 8192 /* = 2*64*64 * 4 Byte => 32kB */ | ||
106 | |||
107 | /* --- Read registers. --- | ||
108 | These are defined as byte-offsets from the iobase value */ | ||
109 | #define HDSPM_statusRegister 0 | ||
110 | #define HDSPM_statusRegister2 96 | ||
111 | |||
112 | #define HDSPM_midiDataIn0 360 | ||
113 | #define HDSPM_midiDataIn1 364 | ||
114 | |||
115 | /* status is data bytes in MIDI-FIFO (0-128) */ | ||
116 | #define HDSPM_midiStatusOut0 384 | ||
117 | #define HDSPM_midiStatusOut1 388 | ||
118 | #define HDSPM_midiStatusIn0 392 | ||
119 | #define HDSPM_midiStatusIn1 396 | ||
120 | |||
121 | |||
122 | /* the meters are regular i/o-mapped registers, but offset | ||
123 | considerably from the rest. the peak registers are reset | ||
124 | when read; the least-significant 4 bits are full-scale counters; | ||
125 | the actual peak value is in the most-significant 24 bits. | ||
126 | */ | ||
127 | #define HDSPM_MADI_peakrmsbase 4096 /* 4096-8191 2x64x32Bit Meters */ | ||
128 | |||
129 | /* --- Control Register bits --------- */ | ||
130 | #define HDSPM_Start (1<<0) /* start engine */ | ||
131 | |||
132 | #define HDSPM_Latency0 (1<<1) /* buffer size = 2^n */ | ||
133 | #define HDSPM_Latency1 (1<<2) /* where n is defined */ | ||
134 | #define HDSPM_Latency2 (1<<3) /* by Latency{2,1,0} */ | ||
135 | |||
136 | #define HDSPM_ClockModeMaster (1<<4) /* 1=Master, 0=Slave/Autosync */ | ||
137 | |||
138 | #define HDSPM_AudioInterruptEnable (1<<5) /* what do you think ? */ | ||
139 | |||
140 | #define HDSPM_Frequency0 (1<<6) /* 0=44.1kHz/88.2kHz 1=48kHz/96kHz */ | ||
141 | #define HDSPM_Frequency1 (1<<7) /* 0=32kHz/64kHz */ | ||
142 | #define HDSPM_DoubleSpeed (1<<8) /* 0=normal speed, 1=double speed */ | ||
143 | #define HDSPM_QuadSpeed (1<<31) /* quad speed bit, not implemented now */ | ||
144 | |||
145 | #define HDSPM_TX_64ch (1<<10) /* Output 64channel MODE=1, | ||
146 | 56channelMODE=0 */ | ||
147 | |||
148 | #define HDSPM_AutoInp (1<<11) /* Auto Input (takeover) == Safe Mode, | ||
149 | 0=off, 1=on */ | ||
150 | |||
151 | #define HDSPM_InputSelect0 (1<<14) /* Input select 0= optical, 1=coax */ | ||
152 | #define HDSPM_InputSelect1 (1<<15) /* should be 0 */ | ||
153 | |||
154 | #define HDSPM_SyncRef0 (1<<16) /* 0=WOrd, 1=MADI */ | ||
155 | #define HDSPM_SyncRef1 (1<<17) /* should be 0 */ | ||
156 | |||
157 | #define HDSPM_clr_tms (1<<19) /* clear track marker, do not use | ||
158 | AES additional bits in | ||
159 | lower 5 Audiodatabits ??? */ | ||
160 | |||
161 | #define HDSPM_Midi0InterruptEnable (1<<22) | ||
162 | #define HDSPM_Midi1InterruptEnable (1<<23) | ||
163 | |||
164 | #define HDSPM_LineOut (1<<24) /* Analog Out on channel 63/64 on=1, mute=0 */ | ||
165 | |||
166 | |||
167 | /* --- bit helper defines */ | ||
168 | #define HDSPM_LatencyMask (HDSPM_Latency0|HDSPM_Latency1|HDSPM_Latency2) | ||
169 | #define HDSPM_FrequencyMask (HDSPM_Frequency0|HDSPM_Frequency1) | ||
170 | #define HDSPM_InputMask (HDSPM_InputSelect0|HDSPM_InputSelect1) | ||
171 | #define HDSPM_InputOptical 0 | ||
172 | #define HDSPM_InputCoaxial (HDSPM_InputSelect0) | ||
173 | #define HDSPM_SyncRefMask (HDSPM_SyncRef0|HDSPM_SyncRef1) | ||
174 | #define HDSPM_SyncRef_Word 0 | ||
175 | #define HDSPM_SyncRef_MADI (HDSPM_SyncRef0) | ||
176 | |||
177 | #define HDSPM_SYNC_FROM_WORD 0 /* Preferred sync reference */ | ||
178 | #define HDSPM_SYNC_FROM_MADI 1 /* choices - used by "pref_sync_ref" */ | ||
179 | |||
180 | #define HDSPM_Frequency32KHz HDSPM_Frequency0 | ||
181 | #define HDSPM_Frequency44_1KHz HDSPM_Frequency1 | ||
182 | #define HDSPM_Frequency48KHz (HDSPM_Frequency1|HDSPM_Frequency0) | ||
183 | #define HDSPM_Frequency64KHz (HDSPM_DoubleSpeed|HDSPM_Frequency0) | ||
184 | #define HDSPM_Frequency88_2KHz (HDSPM_DoubleSpeed|HDSPM_Frequency1) | ||
185 | #define HDSPM_Frequency96KHz (HDSPM_DoubleSpeed|HDSPM_Frequency1|HDSPM_Frequency0) | ||
186 | |||
187 | /* --- for internal discrimination */ | ||
188 | #define HDSPM_CLOCK_SOURCE_AUTOSYNC 0 /* Sample Clock Sources */ | ||
189 | #define HDSPM_CLOCK_SOURCE_INTERNAL_32KHZ 1 | ||
190 | #define HDSPM_CLOCK_SOURCE_INTERNAL_44_1KHZ 2 | ||
191 | #define HDSPM_CLOCK_SOURCE_INTERNAL_48KHZ 3 | ||
192 | #define HDSPM_CLOCK_SOURCE_INTERNAL_64KHZ 4 | ||
193 | #define HDSPM_CLOCK_SOURCE_INTERNAL_88_2KHZ 5 | ||
194 | #define HDSPM_CLOCK_SOURCE_INTERNAL_96KHZ 6 | ||
195 | #define HDSPM_CLOCK_SOURCE_INTERNAL_128KHZ 7 | ||
196 | #define HDSPM_CLOCK_SOURCE_INTERNAL_176_4KHZ 8 | ||
197 | #define HDSPM_CLOCK_SOURCE_INTERNAL_192KHZ 9 | ||
198 | |||
199 | /* Synccheck Status */ | ||
200 | #define HDSPM_SYNC_CHECK_NO_LOCK 0 | ||
201 | #define HDSPM_SYNC_CHECK_LOCK 1 | ||
202 | #define HDSPM_SYNC_CHECK_SYNC 2 | ||
203 | |||
204 | /* AutoSync References - used by "autosync_ref" control switch */ | ||
205 | #define HDSPM_AUTOSYNC_FROM_WORD 0 | ||
206 | #define HDSPM_AUTOSYNC_FROM_MADI 1 | ||
207 | #define HDSPM_AUTOSYNC_FROM_NONE 2 | ||
208 | |||
209 | /* Possible sources of MADI input */ | ||
210 | #define HDSPM_OPTICAL 0 /* optical */ | ||
211 | #define HDSPM_COAXIAL 1 /* BNC */ | ||
212 | |||
213 | #define hdspm_encode_latency(x) (((x)<<1) & HDSPM_LatencyMask) | ||
214 | #define hdspm_decode_latency(x) (((x) & HDSPM_LatencyMask)>>1) | ||
215 | |||
216 | #define hdspm_encode_in(x) (((x)&0x3)<<14) | ||
217 | #define hdspm_decode_in(x) (((x)>>14)&0x3) | ||
218 | |||
219 | /* --- control2 register bits --- */ | ||
220 | #define HDSPM_TMS (1<<0) | ||
221 | #define HDSPM_TCK (1<<1) | ||
222 | #define HDSPM_TDI (1<<2) | ||
223 | #define HDSPM_JTAG (1<<3) | ||
224 | #define HDSPM_PWDN (1<<4) | ||
225 | #define HDSPM_PROGRAM (1<<5) | ||
226 | #define HDSPM_CONFIG_MODE_0 (1<<6) | ||
227 | #define HDSPM_CONFIG_MODE_1 (1<<7) | ||
228 | /*#define HDSPM_VERSION_BIT (1<<8) not defined any more*/ | ||
229 | #define HDSPM_BIGENDIAN_MODE (1<<9) | ||
230 | #define HDSPM_RD_MULTIPLE (1<<10) | ||
231 | |||
232 | /* --- Status Register bits --- */ | ||
233 | #define HDSPM_audioIRQPending (1<<0) /* IRQ is high and pending */ | ||
234 | #define HDSPM_RX_64ch (1<<1) /* Input 64chan. MODE=1, 56chn. MODE=0 */ | ||
235 | #define HDSPM_AB_int (1<<2) /* InputChannel Opt=0, Coax=1 (like inp0) */ | ||
236 | #define HDSPM_madiLock (1<<3) /* MADI Locked =1, no=0 */ | ||
237 | |||
238 | #define HDSPM_BufferPositionMask 0x000FFC0 /* Bit 6..15 : h/w buffer pointer */ | ||
239 | /* since 64byte accurate last 6 bits | ||
240 | are not used */ | ||
241 | |||
242 | #define HDSPM_madiSync (1<<18) /* MADI is in sync */ | ||
243 | #define HDSPM_DoubleSpeedStatus (1<<19) /* (input) card in double speed */ | ||
244 | |||
245 | #define HDSPM_madiFreq0 (1<<22) /* system freq 0=error */ | ||
246 | #define HDSPM_madiFreq1 (1<<23) /* 1=32, 2=44.1 3=48 */ | ||
247 | #define HDSPM_madiFreq2 (1<<24) /* 4=64, 5=88.2 6=96 */ | ||
248 | #define HDSPM_madiFreq3 (1<<25) /* 7=128, 8=176.4 9=192 */ | ||
249 | |||
250 | #define HDSPM_BufferID (1<<26) /* (Double)Buffer ID toggles with Interrupt */ | ||
251 | #define HDSPM_midi0IRQPending (1<<30) /* MIDI IRQ is pending */ | ||
252 | #define HDSPM_midi1IRQPending (1<<31) /* and aktiv */ | ||
253 | |||
254 | /* --- status bit helpers */ | ||
255 | #define HDSPM_madiFreqMask (HDSPM_madiFreq0|HDSPM_madiFreq1|HDSPM_madiFreq2|HDSPM_madiFreq3) | ||
256 | #define HDSPM_madiFreq32 (HDSPM_madiFreq0) | ||
257 | #define HDSPM_madiFreq44_1 (HDSPM_madiFreq1) | ||
258 | #define HDSPM_madiFreq48 (HDSPM_madiFreq0|HDSPM_madiFreq1) | ||
259 | #define HDSPM_madiFreq64 (HDSPM_madiFreq2) | ||
260 | #define HDSPM_madiFreq88_2 (HDSPM_madiFreq0|HDSPM_madiFreq2) | ||
261 | #define HDSPM_madiFreq96 (HDSPM_madiFreq1|HDSPM_madiFreq2) | ||
262 | #define HDSPM_madiFreq128 (HDSPM_madiFreq0|HDSPM_madiFreq1|HDSPM_madiFreq2) | ||
263 | #define HDSPM_madiFreq176_4 (HDSPM_madiFreq3) | ||
264 | #define HDSPM_madiFreq192 (HDSPM_madiFreq3|HDSPM_madiFreq0) | ||
265 | |||
266 | /* Status2 Register bits */ | ||
267 | |||
268 | #define HDSPM_version0 (1<<0) /* not realy defined but I guess */ | ||
269 | #define HDSPM_version1 (1<<1) /* in former cards it was ??? */ | ||
270 | #define HDSPM_version2 (1<<2) | ||
271 | |||
272 | #define HDSPM_wcLock (1<<3) /* Wordclock is detected and locked */ | ||
273 | #define HDSPM_wcSync (1<<4) /* Wordclock is in sync with systemclock */ | ||
274 | |||
275 | #define HDSPM_wc_freq0 (1<<5) /* input freq detected via autosync */ | ||
276 | #define HDSPM_wc_freq1 (1<<6) /* 001=32, 010==44.1, 011=48, */ | ||
277 | #define HDSPM_wc_freq2 (1<<7) /* 100=64, 101=88.2, 110=96, */ | ||
278 | /* missing Bit for 111=128, 1000=176.4, 1001=192 */ | ||
279 | |||
280 | #define HDSPM_SelSyncRef0 (1<<8) /* Sync Source in slave mode */ | ||
281 | #define HDSPM_SelSyncRef1 (1<<9) /* 000=word, 001=MADI, */ | ||
282 | #define HDSPM_SelSyncRef2 (1<<10) /* 111=no valid signal */ | ||
283 | |||
284 | #define HDSPM_wc_valid (HDSPM_wcLock|HDSPM_wcSync) | ||
285 | |||
286 | #define HDSPM_wcFreqMask (HDSPM_wc_freq0|HDSPM_wc_freq1|HDSPM_wc_freq2) | ||
287 | #define HDSPM_wcFreq32 (HDSPM_wc_freq0) | ||
288 | #define HDSPM_wcFreq44_1 (HDSPM_wc_freq1) | ||
289 | #define HDSPM_wcFreq48 (HDSPM_wc_freq0|HDSPM_wc_freq1) | ||
290 | #define HDSPM_wcFreq64 (HDSPM_wc_freq2) | ||
291 | #define HDSPM_wcFreq88_2 (HDSPM_wc_freq0|HDSPM_wc_freq2) | ||
292 | #define HDSPM_wcFreq96 (HDSPM_wc_freq1|HDSPM_wc_freq2) | ||
293 | |||
294 | |||
295 | #define HDSPM_SelSyncRefMask (HDSPM_SelSyncRef0|HDSPM_SelSyncRef1|HDSPM_SelSyncRef2) | ||
296 | #define HDSPM_SelSyncRef_WORD 0 | ||
297 | #define HDSPM_SelSyncRef_MADI (HDSPM_SelSyncRef0) | ||
298 | #define HDSPM_SelSyncRef_NVALID (HDSPM_SelSyncRef0|HDSPM_SelSyncRef1|HDSPM_SelSyncRef2) | ||
299 | |||
300 | /* Mixer Values */ | ||
301 | #define UNITY_GAIN 32768 /* = 65536/2 */ | ||
302 | #define MINUS_INFINITY_GAIN 0 | ||
303 | |||
304 | /* PCI info */ | ||
305 | #ifndef PCI_VENDOR_ID_XILINX | ||
306 | #define PCI_VENDOR_ID_XILINX 0x10ee | ||
307 | #endif | ||
308 | #ifndef PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP | ||
309 | #define PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP 0x3fc5 | ||
310 | #endif | ||
311 | #ifndef PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP_MADI | ||
312 | #define PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP_MADI 0x3fc6 | ||
313 | #endif | ||
314 | |||
315 | |||
316 | /* Number of channels for different Speed Modes */ | ||
317 | #define MADI_SS_CHANNELS 64 | ||
318 | #define MADI_DS_CHANNELS 32 | ||
319 | #define MADI_QS_CHANNELS 16 | ||
320 | |||
321 | /* the size of a substream (1 mono data stream) */ | ||
322 | #define HDSPM_CHANNEL_BUFFER_SAMPLES (16*1024) | ||
323 | #define HDSPM_CHANNEL_BUFFER_BYTES (4*HDSPM_CHANNEL_BUFFER_SAMPLES) | ||
324 | |||
325 | /* the size of the area we need to allocate for DMA transfers. the | ||
326 | size is the same regardless of the number of channels, and | ||
327 | also the latency to use. | ||
328 | for one direction !!! | ||
329 | */ | ||
330 | #define HDSPM_DMA_AREA_BYTES (HDSPM_MAX_CHANNELS * HDSPM_CHANNEL_BUFFER_BYTES) | ||
331 | #define HDSPM_DMA_AREA_KILOBYTES (HDSPM_DMA_AREA_BYTES/1024) | ||
332 | |||
333 | typedef struct _hdspm hdspm_t; | ||
334 | typedef struct _hdspm_midi hdspm_midi_t; | ||
335 | |||
336 | struct _hdspm_midi { | ||
337 | hdspm_t *hdspm; | ||
338 | int id; | ||
339 | snd_rawmidi_t *rmidi; | ||
340 | snd_rawmidi_substream_t *input; | ||
341 | snd_rawmidi_substream_t *output; | ||
342 | char istimer; /* timer in use */ | ||
343 | struct timer_list timer; | ||
344 | spinlock_t lock; | ||
345 | int pending; | ||
346 | }; | ||
347 | |||
348 | struct _hdspm { | ||
349 | spinlock_t lock; | ||
350 | snd_pcm_substream_t *capture_substream; /* only one playback */ | ||
351 | snd_pcm_substream_t *playback_substream; /* and/or capture stream */ | ||
352 | |||
353 | char *card_name; /* for procinfo */ | ||
354 | unsigned short firmware_rev; /* dont know if relevant */ | ||
355 | |||
356 | int precise_ptr; /* use precise pointers, to be tested */ | ||
357 | int monitor_outs; /* set up monitoring outs init flag */ | ||
358 | |||
359 | u32 control_register; /* cached value */ | ||
360 | u32 control2_register; /* cached value */ | ||
361 | |||
362 | hdspm_midi_t midi[2]; | ||
363 | struct tasklet_struct midi_tasklet; | ||
364 | |||
365 | size_t period_bytes; | ||
366 | unsigned char ss_channels; /* channels of card in single speed */ | ||
367 | unsigned char ds_channels; /* Double Speed */ | ||
368 | unsigned char qs_channels; /* Quad Speed */ | ||
369 | |||
370 | unsigned char *playback_buffer; /* suitably aligned address */ | ||
371 | unsigned char *capture_buffer; /* suitably aligned address */ | ||
372 | |||
373 | pid_t capture_pid; /* process id which uses capture */ | ||
374 | pid_t playback_pid; /* process id which uses capture */ | ||
375 | int running; /* running status */ | ||
376 | |||
377 | int last_external_sample_rate; /* samplerate mystic ... */ | ||
378 | int last_internal_sample_rate; | ||
379 | int system_sample_rate; | ||
380 | |||
381 | char *channel_map; /* channel map for DS and Quadspeed */ | ||
382 | |||
383 | int dev; /* Hardware vars... */ | ||
384 | int irq; | ||
385 | unsigned long port; | ||
386 | void __iomem *iobase; | ||
387 | |||
388 | int irq_count; /* for debug */ | ||
389 | |||
390 | snd_card_t *card; /* one card */ | ||
391 | snd_pcm_t *pcm; /* has one pcm */ | ||
392 | snd_hwdep_t *hwdep; /* and a hwdep for additional ioctl */ | ||
393 | struct pci_dev *pci; /* and an pci info */ | ||
394 | |||
395 | /* Mixer vars */ | ||
396 | snd_kcontrol_t *playback_mixer_ctls[HDSPM_MAX_CHANNELS]; /* fast alsa mixer */ | ||
397 | snd_kcontrol_t *input_mixer_ctls[HDSPM_MAX_CHANNELS]; /* but input to much, so not used */ | ||
398 | hdspm_mixer_t *mixer; /* full mixer accessable over mixer ioctl or hwdep-device */ | ||
399 | |||
400 | }; | ||
401 | |||
402 | /* These tables map the ALSA channels 1..N to the channels that we | ||
403 | need to use in order to find the relevant channel buffer. RME | ||
404 | refer to this kind of mapping as between "the ADAT channel and | ||
405 | the DMA channel." We index it using the logical audio channel, | ||
406 | and the value is the DMA channel (i.e. channel buffer number) | ||
407 | where the data for that channel can be read/written from/to. | ||
408 | */ | ||
409 | |||
410 | static char channel_map_madi_ss[HDSPM_MAX_CHANNELS] = { | ||
411 | 0, 1, 2, 3, 4, 5, 6, 7, | ||
412 | 8, 9, 10, 11, 12, 13, 14, 15, | ||
413 | 16, 17, 18, 19, 20, 21, 22, 23, | ||
414 | 24, 25, 26, 27, 28, 29, 30, 31, | ||
415 | 32, 33, 34, 35, 36, 37, 38, 39, | ||
416 | 40, 41, 42, 43, 44, 45, 46, 47, | ||
417 | 48, 49, 50, 51, 52, 53, 54, 55, | ||
418 | 56, 57, 58, 59, 60, 61, 62, 63 | ||
419 | }; | ||
420 | |||
421 | static char channel_map_madi_ds[HDSPM_MAX_CHANNELS] = { | ||
422 | 0, 2, 4, 6, 8, 10, 12, 14, | ||
423 | 16, 18, 20, 22, 24, 26, 28, 30, | ||
424 | 32, 34, 36, 38, 40, 42, 44, 46, | ||
425 | 48, 50, 52, 54, 56, 58, 60, 62, | ||
426 | -1, -1, -1, -1, -1, -1, -1, -1, | ||
427 | -1, -1, -1, -1, -1, -1, -1, -1, | ||
428 | -1, -1, -1, -1, -1, -1, -1, -1, | ||
429 | -1, -1, -1, -1, -1, -1, -1, -1 | ||
430 | }; | ||
431 | |||
432 | static char channel_map_madi_qs[HDSPM_MAX_CHANNELS] = { | ||
433 | 0, 4, 8, 12, 16, 20, 24, 28, | ||
434 | 32, 36, 40, 44, 48, 52, 56, 60 | ||
435 | -1, -1, -1, -1, -1, -1, -1, -1, | ||
436 | -1, -1, -1, -1, -1, -1, -1, -1, | ||
437 | -1, -1, -1, -1, -1, -1, -1, -1, | ||
438 | -1, -1, -1, -1, -1, -1, -1, -1, | ||
439 | -1, -1, -1, -1, -1, -1, -1, -1, | ||
440 | -1, -1, -1, -1, -1, -1, -1, -1 | ||
441 | }; | ||
442 | |||
443 | |||
444 | static struct pci_device_id snd_hdspm_ids[] = { | ||
445 | { | ||
446 | .vendor = PCI_VENDOR_ID_XILINX, | ||
447 | .device = PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP_MADI, | ||
448 | .subvendor = PCI_ANY_ID, | ||
449 | .subdevice = PCI_ANY_ID, | ||
450 | .class = 0, | ||
451 | .class_mask = 0, | ||
452 | .driver_data = 0}, | ||
453 | {0,} | ||
454 | }; | ||
455 | |||
456 | MODULE_DEVICE_TABLE(pci, snd_hdspm_ids); | ||
457 | |||
458 | /* prototypes */ | ||
459 | static int __devinit snd_hdspm_create_alsa_devices(snd_card_t * card, | ||
460 | hdspm_t * hdspm); | ||
461 | static int __devinit snd_hdspm_create_pcm(snd_card_t * card, | ||
462 | hdspm_t * hdspm); | ||
463 | |||
464 | static inline void snd_hdspm_initialize_midi_flush(hdspm_t * hdspm); | ||
465 | static int hdspm_update_simple_mixer_controls(hdspm_t * hdspm); | ||
466 | static int hdspm_autosync_ref(hdspm_t * hdspm); | ||
467 | static int snd_hdspm_set_defaults(hdspm_t * hdspm); | ||
468 | static void hdspm_set_sgbuf(hdspm_t * hdspm, struct snd_sg_buf *sgbuf, | ||
469 | unsigned int reg, int channels); | ||
470 | |||
471 | /* Write/read to/from HDSPM with Adresses in Bytes | ||
472 | not words but only 32Bit writes are allowed */ | ||
473 | |||
474 | static inline void hdspm_write(hdspm_t * hdspm, unsigned int reg, | ||
475 | unsigned int val) | ||
476 | { | ||
477 | writel(val, hdspm->iobase + reg); | ||
478 | } | ||
479 | |||
480 | static inline unsigned int hdspm_read(hdspm_t * hdspm, unsigned int reg) | ||
481 | { | ||
482 | return readl(hdspm->iobase + reg); | ||
483 | } | ||
484 | |||
485 | /* for each output channel (chan) I have an Input (in) and Playback (pb) Fader | ||
486 | mixer is write only on hardware so we have to cache him for read | ||
487 | each fader is a u32, but uses only the first 16 bit */ | ||
488 | |||
489 | static inline int hdspm_read_in_gain(hdspm_t * hdspm, unsigned int chan, | ||
490 | unsigned int in) | ||
491 | { | ||
492 | if (chan > HDSPM_MIXER_CHANNELS || in > HDSPM_MIXER_CHANNELS) | ||
493 | return 0; | ||
494 | |||
495 | return hdspm->mixer->ch[chan].in[in]; | ||
496 | } | ||
497 | |||
498 | static inline int hdspm_read_pb_gain(hdspm_t * hdspm, unsigned int chan, | ||
499 | unsigned int pb) | ||
500 | { | ||
501 | if (chan > HDSPM_MIXER_CHANNELS || pb > HDSPM_MIXER_CHANNELS) | ||
502 | return 0; | ||
503 | return hdspm->mixer->ch[chan].pb[pb]; | ||
504 | } | ||
505 | |||
506 | static inline int hdspm_write_in_gain(hdspm_t * hdspm, unsigned int chan, | ||
507 | unsigned int in, unsigned short data) | ||
508 | { | ||
509 | if (chan >= HDSPM_MIXER_CHANNELS || in >= HDSPM_MIXER_CHANNELS) | ||
510 | return -1; | ||
511 | |||
512 | hdspm_write(hdspm, | ||
513 | HDSPM_MADI_mixerBase + | ||
514 | ((in + 128 * chan) * sizeof(u32)), | ||
515 | (hdspm->mixer->ch[chan].in[in] = data & 0xFFFF)); | ||
516 | return 0; | ||
517 | } | ||
518 | |||
519 | static inline int hdspm_write_pb_gain(hdspm_t * hdspm, unsigned int chan, | ||
520 | unsigned int pb, unsigned short data) | ||
521 | { | ||
522 | if (chan >= HDSPM_MIXER_CHANNELS || pb >= HDSPM_MIXER_CHANNELS) | ||
523 | return -1; | ||
524 | |||
525 | hdspm_write(hdspm, | ||
526 | HDSPM_MADI_mixerBase + | ||
527 | ((64 + pb + 128 * chan) * sizeof(u32)), | ||
528 | (hdspm->mixer->ch[chan].pb[pb] = data & 0xFFFF)); | ||
529 | return 0; | ||
530 | } | ||
531 | |||
532 | |||
533 | /* enable DMA for specific channels, now available for DSP-MADI */ | ||
534 | static inline void snd_hdspm_enable_in(hdspm_t * hdspm, int i, int v) | ||
535 | { | ||
536 | hdspm_write(hdspm, HDSPM_inputEnableBase + (4 * i), v); | ||
537 | } | ||
538 | |||
539 | static inline void snd_hdspm_enable_out(hdspm_t * hdspm, int i, int v) | ||
540 | { | ||
541 | hdspm_write(hdspm, HDSPM_outputEnableBase + (4 * i), v); | ||
542 | } | ||
543 | |||
544 | /* check if same process is writing and reading */ | ||
545 | static inline int snd_hdspm_use_is_exclusive(hdspm_t * hdspm) | ||
546 | { | ||
547 | unsigned long flags; | ||
548 | int ret = 1; | ||
549 | |||
550 | spin_lock_irqsave(&hdspm->lock, flags); | ||
551 | if ((hdspm->playback_pid != hdspm->capture_pid) && | ||
552 | (hdspm->playback_pid >= 0) && (hdspm->capture_pid >= 0)) { | ||
553 | ret = 0; | ||
554 | } | ||
555 | spin_unlock_irqrestore(&hdspm->lock, flags); | ||
556 | return ret; | ||
557 | } | ||
558 | |||
559 | /* check for external sample rate */ | ||
560 | static inline int hdspm_external_sample_rate(hdspm_t * hdspm) | ||
561 | { | ||
562 | unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2); | ||
563 | unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister); | ||
564 | unsigned int rate_bits; | ||
565 | int rate = 0; | ||
566 | |||
567 | /* if wordclock has synced freq and wordclock is valid */ | ||
568 | if ((status2 & HDSPM_wcLock) != 0 && | ||
569 | (status & HDSPM_SelSyncRef0) == 0) { | ||
570 | |||
571 | rate_bits = status2 & HDSPM_wcFreqMask; | ||
572 | |||
573 | switch (rate_bits) { | ||
574 | case HDSPM_wcFreq32: | ||
575 | rate = 32000; | ||
576 | break; | ||
577 | case HDSPM_wcFreq44_1: | ||
578 | rate = 44100; | ||
579 | break; | ||
580 | case HDSPM_wcFreq48: | ||
581 | rate = 48000; | ||
582 | break; | ||
583 | case HDSPM_wcFreq64: | ||
584 | rate = 64000; | ||
585 | break; | ||
586 | case HDSPM_wcFreq88_2: | ||
587 | rate = 88200; | ||
588 | break; | ||
589 | case HDSPM_wcFreq96: | ||
590 | rate = 96000; | ||
591 | break; | ||
592 | /* Quadspeed Bit missing ???? */ | ||
593 | default: | ||
594 | rate = 0; | ||
595 | break; | ||
596 | } | ||
597 | } | ||
598 | |||
599 | /* if rate detected and Syncref is Word than have it, word has priority to MADI */ | ||
600 | if (rate != 0 | ||
601 | && (status2 & HDSPM_SelSyncRefMask) == HDSPM_SelSyncRef_WORD) | ||
602 | return rate; | ||
603 | |||
604 | /* maby a madi input (which is taken if sel sync is madi) */ | ||
605 | if (status & HDSPM_madiLock) { | ||
606 | rate_bits = status & HDSPM_madiFreqMask; | ||
607 | |||
608 | switch (rate_bits) { | ||
609 | case HDSPM_madiFreq32: | ||
610 | rate = 32000; | ||
611 | break; | ||
612 | case HDSPM_madiFreq44_1: | ||
613 | rate = 44100; | ||
614 | break; | ||
615 | case HDSPM_madiFreq48: | ||
616 | rate = 48000; | ||
617 | break; | ||
618 | case HDSPM_madiFreq64: | ||
619 | rate = 64000; | ||
620 | break; | ||
621 | case HDSPM_madiFreq88_2: | ||
622 | rate = 88200; | ||
623 | break; | ||
624 | case HDSPM_madiFreq96: | ||
625 | rate = 96000; | ||
626 | break; | ||
627 | case HDSPM_madiFreq128: | ||
628 | rate = 128000; | ||
629 | break; | ||
630 | case HDSPM_madiFreq176_4: | ||
631 | rate = 176400; | ||
632 | break; | ||
633 | case HDSPM_madiFreq192: | ||
634 | rate = 192000; | ||
635 | break; | ||
636 | default: | ||
637 | rate = 0; | ||
638 | break; | ||
639 | } | ||
640 | } | ||
641 | return rate; | ||
642 | } | ||
643 | |||
644 | /* Latency function */ | ||
645 | static inline void hdspm_compute_period_size(hdspm_t * hdspm) | ||
646 | { | ||
647 | hdspm->period_bytes = | ||
648 | 1 << ((hdspm_decode_latency(hdspm->control_register) + 8)); | ||
649 | } | ||
650 | |||
651 | static snd_pcm_uframes_t hdspm_hw_pointer(hdspm_t * hdspm) | ||
652 | { | ||
653 | int position; | ||
654 | |||
655 | position = hdspm_read(hdspm, HDSPM_statusRegister); | ||
656 | |||
657 | if (!hdspm->precise_ptr) { | ||
658 | return (position & HDSPM_BufferID) ? (hdspm->period_bytes / | ||
659 | 4) : 0; | ||
660 | } | ||
661 | |||
662 | /* hwpointer comes in bytes and is 64Bytes accurate (by docu since PCI Burst) | ||
663 | i have experimented that it is at most 64 Byte to much for playing | ||
664 | so substraction of 64 byte should be ok for ALSA, but use it only | ||
665 | for application where you know what you do since if you come to | ||
666 | near with record pointer it can be a disaster */ | ||
667 | |||
668 | position &= HDSPM_BufferPositionMask; | ||
669 | position = ((position - 64) % (2 * hdspm->period_bytes)) / 4; | ||
670 | |||
671 | return position; | ||
672 | } | ||
673 | |||
674 | |||
675 | static inline void hdspm_start_audio(hdspm_t * s) | ||
676 | { | ||
677 | s->control_register |= (HDSPM_AudioInterruptEnable | HDSPM_Start); | ||
678 | hdspm_write(s, HDSPM_controlRegister, s->control_register); | ||
679 | } | ||
680 | |||
681 | static inline void hdspm_stop_audio(hdspm_t * s) | ||
682 | { | ||
683 | s->control_register &= ~(HDSPM_Start | HDSPM_AudioInterruptEnable); | ||
684 | hdspm_write(s, HDSPM_controlRegister, s->control_register); | ||
685 | } | ||
686 | |||
687 | /* should I silence all or only opened ones ? doit all for first even is 4MB*/ | ||
688 | static inline void hdspm_silence_playback(hdspm_t * hdspm) | ||
689 | { | ||
690 | int i; | ||
691 | int n = hdspm->period_bytes; | ||
692 | void *buf = hdspm->playback_buffer; | ||
693 | |||
694 | snd_assert(buf != NULL, return); | ||
695 | |||
696 | for (i = 0; i < HDSPM_MAX_CHANNELS; i++) { | ||
697 | memset(buf, 0, n); | ||
698 | buf += HDSPM_CHANNEL_BUFFER_BYTES; | ||
699 | } | ||
700 | } | ||
701 | |||
702 | static int hdspm_set_interrupt_interval(hdspm_t * s, unsigned int frames) | ||
703 | { | ||
704 | int n; | ||
705 | |||
706 | spin_lock_irq(&s->lock); | ||
707 | |||
708 | frames >>= 7; | ||
709 | n = 0; | ||
710 | while (frames) { | ||
711 | n++; | ||
712 | frames >>= 1; | ||
713 | } | ||
714 | s->control_register &= ~HDSPM_LatencyMask; | ||
715 | s->control_register |= hdspm_encode_latency(n); | ||
716 | |||
717 | hdspm_write(s, HDSPM_controlRegister, s->control_register); | ||
718 | |||
719 | hdspm_compute_period_size(s); | ||
720 | |||
721 | spin_unlock_irq(&s->lock); | ||
722 | |||
723 | return 0; | ||
724 | } | ||
725 | |||
726 | |||
727 | /* dummy set rate lets see what happens */ | ||
728 | static int hdspm_set_rate(hdspm_t * hdspm, int rate, int called_internally) | ||
729 | { | ||
730 | int reject_if_open = 0; | ||
731 | int current_rate; | ||
732 | int rate_bits; | ||
733 | int not_set = 0; | ||
734 | |||
735 | /* ASSUMPTION: hdspm->lock is either set, or there is no need for | ||
736 | it (e.g. during module initialization). | ||
737 | */ | ||
738 | |||
739 | if (!(hdspm->control_register & HDSPM_ClockModeMaster)) { | ||
740 | |||
741 | /* SLAVE --- */ | ||
742 | if (called_internally) { | ||
743 | |||
744 | /* request from ctl or card initialization | ||
745 | just make a warning an remember setting | ||
746 | for future master mode switching */ | ||
747 | |||
748 | snd_printk | ||
749 | (KERN_WARNING "HDSPM: Warning: device is not running as a clock master.\n"); | ||
750 | not_set = 1; | ||
751 | } else { | ||
752 | |||
753 | /* hw_param request while in AutoSync mode */ | ||
754 | int external_freq = | ||
755 | hdspm_external_sample_rate(hdspm); | ||
756 | |||
757 | if ((hdspm_autosync_ref(hdspm) == | ||
758 | HDSPM_AUTOSYNC_FROM_NONE)) { | ||
759 | |||
760 | snd_printk(KERN_WARNING "HDSPM: Detected no Externel Sync \n"); | ||
761 | not_set = 1; | ||
762 | |||
763 | } else if (rate != external_freq) { | ||
764 | |||
765 | snd_printk | ||
766 | (KERN_WARNING "HDSPM: Warning: No AutoSync source for requested rate\n"); | ||
767 | not_set = 1; | ||
768 | } | ||
769 | } | ||
770 | } | ||
771 | |||
772 | current_rate = hdspm->system_sample_rate; | ||
773 | |||
774 | /* Changing between Singe, Double and Quad speed is not | ||
775 | allowed if any substreams are open. This is because such a change | ||
776 | causes a shift in the location of the DMA buffers and a reduction | ||
777 | in the number of available buffers. | ||
778 | |||
779 | Note that a similar but essentially insoluble problem exists for | ||
780 | externally-driven rate changes. All we can do is to flag rate | ||
781 | changes in the read/write routines. | ||
782 | */ | ||
783 | |||
784 | switch (rate) { | ||
785 | case 32000: | ||
786 | if (current_rate > 48000) { | ||
787 | reject_if_open = 1; | ||
788 | } | ||
789 | rate_bits = HDSPM_Frequency32KHz; | ||
790 | break; | ||
791 | case 44100: | ||
792 | if (current_rate > 48000) { | ||
793 | reject_if_open = 1; | ||
794 | } | ||
795 | rate_bits = HDSPM_Frequency44_1KHz; | ||
796 | break; | ||
797 | case 48000: | ||
798 | if (current_rate > 48000) { | ||
799 | reject_if_open = 1; | ||
800 | } | ||
801 | rate_bits = HDSPM_Frequency48KHz; | ||
802 | break; | ||
803 | case 64000: | ||
804 | if (current_rate <= 48000) { | ||
805 | reject_if_open = 1; | ||
806 | } | ||
807 | rate_bits = HDSPM_Frequency64KHz; | ||
808 | break; | ||
809 | case 88200: | ||
810 | if (current_rate <= 48000) { | ||
811 | reject_if_open = 1; | ||
812 | } | ||
813 | rate_bits = HDSPM_Frequency88_2KHz; | ||
814 | break; | ||
815 | case 96000: | ||
816 | if (current_rate <= 48000) { | ||
817 | reject_if_open = 1; | ||
818 | } | ||
819 | rate_bits = HDSPM_Frequency96KHz; | ||
820 | break; | ||
821 | default: | ||
822 | return -EINVAL; | ||
823 | } | ||
824 | |||
825 | if (reject_if_open | ||
826 | && (hdspm->capture_pid >= 0 || hdspm->playback_pid >= 0)) { | ||
827 | snd_printk | ||
828 | (KERN_ERR "HDSPM: cannot change between single- and double-speed mode (capture PID = %d, playback PID = %d)\n", | ||
829 | hdspm->capture_pid, hdspm->playback_pid); | ||
830 | return -EBUSY; | ||
831 | } | ||
832 | |||
833 | hdspm->control_register &= ~HDSPM_FrequencyMask; | ||
834 | hdspm->control_register |= rate_bits; | ||
835 | hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); | ||
836 | |||
837 | if (rate > 64000) | ||
838 | hdspm->channel_map = channel_map_madi_qs; | ||
839 | else if (rate > 48000) | ||
840 | hdspm->channel_map = channel_map_madi_ds; | ||
841 | else | ||
842 | hdspm->channel_map = channel_map_madi_ss; | ||
843 | |||
844 | hdspm->system_sample_rate = rate; | ||
845 | |||
846 | if (not_set != 0) | ||
847 | return -1; | ||
848 | |||
849 | return 0; | ||
850 | } | ||
851 | |||
852 | /* mainly for init to 0 on load */ | ||
853 | static void all_in_all_mixer(hdspm_t * hdspm, int sgain) | ||
854 | { | ||
855 | int i, j; | ||
856 | unsigned int gain = | ||
857 | (sgain > UNITY_GAIN) ? UNITY_GAIN : (sgain < 0) ? 0 : sgain; | ||
858 | |||
859 | for (i = 0; i < HDSPM_MIXER_CHANNELS; i++) | ||
860 | for (j = 0; j < HDSPM_MIXER_CHANNELS; j++) { | ||
861 | hdspm_write_in_gain(hdspm, i, j, gain); | ||
862 | hdspm_write_pb_gain(hdspm, i, j, gain); | ||
863 | } | ||
864 | } | ||
865 | |||
866 | /*---------------------------------------------------------------------------- | ||
867 | MIDI | ||
868 | ----------------------------------------------------------------------------*/ | ||
869 | |||
870 | static inline unsigned char snd_hdspm_midi_read_byte (hdspm_t *hdspm, int id) | ||
871 | { | ||
872 | /* the hardware already does the relevant bit-mask with 0xff */ | ||
873 | if (id) | ||
874 | return hdspm_read(hdspm, HDSPM_midiDataIn1); | ||
875 | else | ||
876 | return hdspm_read(hdspm, HDSPM_midiDataIn0); | ||
877 | } | ||
878 | |||
879 | static inline void snd_hdspm_midi_write_byte (hdspm_t *hdspm, int id, int val) | ||
880 | { | ||
881 | /* the hardware already does the relevant bit-mask with 0xff */ | ||
882 | if (id) | ||
883 | return hdspm_write(hdspm, HDSPM_midiDataOut1, val); | ||
884 | else | ||
885 | return hdspm_write(hdspm, HDSPM_midiDataOut0, val); | ||
886 | } | ||
887 | |||
888 | static inline int snd_hdspm_midi_input_available (hdspm_t *hdspm, int id) | ||
889 | { | ||
890 | if (id) | ||
891 | return (hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xff); | ||
892 | else | ||
893 | return (hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xff); | ||
894 | } | ||
895 | |||
896 | static inline int snd_hdspm_midi_output_possible (hdspm_t *hdspm, int id) | ||
897 | { | ||
898 | int fifo_bytes_used; | ||
899 | |||
900 | if (id) | ||
901 | fifo_bytes_used = hdspm_read(hdspm, HDSPM_midiStatusOut1) & 0xff; | ||
902 | else | ||
903 | fifo_bytes_used = hdspm_read(hdspm, HDSPM_midiStatusOut0) & 0xff; | ||
904 | |||
905 | if (fifo_bytes_used < 128) | ||
906 | return 128 - fifo_bytes_used; | ||
907 | else | ||
908 | return 0; | ||
909 | } | ||
910 | |||
911 | static inline void snd_hdspm_flush_midi_input (hdspm_t *hdspm, int id) | ||
912 | { | ||
913 | while (snd_hdspm_midi_input_available (hdspm, id)) | ||
914 | snd_hdspm_midi_read_byte (hdspm, id); | ||
915 | } | ||
916 | |||
917 | static int snd_hdspm_midi_output_write (hdspm_midi_t *hmidi) | ||
918 | { | ||
919 | unsigned long flags; | ||
920 | int n_pending; | ||
921 | int to_write; | ||
922 | int i; | ||
923 | unsigned char buf[128]; | ||
924 | |||
925 | /* Output is not interrupt driven */ | ||
926 | |||
927 | spin_lock_irqsave (&hmidi->lock, flags); | ||
928 | if (hmidi->output) { | ||
929 | if (!snd_rawmidi_transmit_empty (hmidi->output)) { | ||
930 | if ((n_pending = snd_hdspm_midi_output_possible (hmidi->hdspm, hmidi->id)) > 0) { | ||
931 | if (n_pending > (int)sizeof (buf)) | ||
932 | n_pending = sizeof (buf); | ||
933 | |||
934 | if ((to_write = snd_rawmidi_transmit (hmidi->output, buf, n_pending)) > 0) { | ||
935 | for (i = 0; i < to_write; ++i) | ||
936 | snd_hdspm_midi_write_byte (hmidi->hdspm, hmidi->id, buf[i]); | ||
937 | } | ||
938 | } | ||
939 | } | ||
940 | } | ||
941 | spin_unlock_irqrestore (&hmidi->lock, flags); | ||
942 | return 0; | ||
943 | } | ||
944 | |||
945 | static int snd_hdspm_midi_input_read (hdspm_midi_t *hmidi) | ||
946 | { | ||
947 | unsigned char buf[128]; /* this buffer is designed to match the MIDI input FIFO size */ | ||
948 | unsigned long flags; | ||
949 | int n_pending; | ||
950 | int i; | ||
951 | |||
952 | spin_lock_irqsave (&hmidi->lock, flags); | ||
953 | if ((n_pending = snd_hdspm_midi_input_available (hmidi->hdspm, hmidi->id)) > 0) { | ||
954 | if (hmidi->input) { | ||
955 | if (n_pending > (int)sizeof (buf)) { | ||
956 | n_pending = sizeof (buf); | ||
957 | } | ||
958 | for (i = 0; i < n_pending; ++i) { | ||
959 | buf[i] = snd_hdspm_midi_read_byte (hmidi->hdspm, hmidi->id); | ||
960 | } | ||
961 | if (n_pending) { | ||
962 | snd_rawmidi_receive (hmidi->input, buf, n_pending); | ||
963 | } | ||
964 | } else { | ||
965 | /* flush the MIDI input FIFO */ | ||
966 | while (n_pending--) { | ||
967 | snd_hdspm_midi_read_byte (hmidi->hdspm, hmidi->id); | ||
968 | } | ||
969 | } | ||
970 | } | ||
971 | hmidi->pending = 0; | ||
972 | if (hmidi->id) { | ||
973 | hmidi->hdspm->control_register |= HDSPM_Midi1InterruptEnable; | ||
974 | } else { | ||
975 | hmidi->hdspm->control_register |= HDSPM_Midi0InterruptEnable; | ||
976 | } | ||
977 | hdspm_write(hmidi->hdspm, HDSPM_controlRegister, hmidi->hdspm->control_register); | ||
978 | spin_unlock_irqrestore (&hmidi->lock, flags); | ||
979 | return snd_hdspm_midi_output_write (hmidi); | ||
980 | } | ||
981 | |||
982 | static void snd_hdspm_midi_input_trigger(snd_rawmidi_substream_t * substream, int up) | ||
983 | { | ||
984 | hdspm_t *hdspm; | ||
985 | hdspm_midi_t *hmidi; | ||
986 | unsigned long flags; | ||
987 | u32 ie; | ||
988 | |||
989 | hmidi = (hdspm_midi_t *) substream->rmidi->private_data; | ||
990 | hdspm = hmidi->hdspm; | ||
991 | ie = hmidi->id ? HDSPM_Midi1InterruptEnable : HDSPM_Midi0InterruptEnable; | ||
992 | spin_lock_irqsave (&hdspm->lock, flags); | ||
993 | if (up) { | ||
994 | if (!(hdspm->control_register & ie)) { | ||
995 | snd_hdspm_flush_midi_input (hdspm, hmidi->id); | ||
996 | hdspm->control_register |= ie; | ||
997 | } | ||
998 | } else { | ||
999 | hdspm->control_register &= ~ie; | ||
1000 | } | ||
1001 | |||
1002 | hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); | ||
1003 | spin_unlock_irqrestore (&hdspm->lock, flags); | ||
1004 | } | ||
1005 | |||
1006 | static void snd_hdspm_midi_output_timer(unsigned long data) | ||
1007 | { | ||
1008 | hdspm_midi_t *hmidi = (hdspm_midi_t *) data; | ||
1009 | unsigned long flags; | ||
1010 | |||
1011 | snd_hdspm_midi_output_write(hmidi); | ||
1012 | spin_lock_irqsave (&hmidi->lock, flags); | ||
1013 | |||
1014 | /* this does not bump hmidi->istimer, because the | ||
1015 | kernel automatically removed the timer when it | ||
1016 | expired, and we are now adding it back, thus | ||
1017 | leaving istimer wherever it was set before. | ||
1018 | */ | ||
1019 | |||
1020 | if (hmidi->istimer) { | ||
1021 | hmidi->timer.expires = 1 + jiffies; | ||
1022 | add_timer(&hmidi->timer); | ||
1023 | } | ||
1024 | |||
1025 | spin_unlock_irqrestore (&hmidi->lock, flags); | ||
1026 | } | ||
1027 | |||
1028 | static void snd_hdspm_midi_output_trigger(snd_rawmidi_substream_t * substream, int up) | ||
1029 | { | ||
1030 | hdspm_midi_t *hmidi; | ||
1031 | unsigned long flags; | ||
1032 | |||
1033 | hmidi = (hdspm_midi_t *) substream->rmidi->private_data; | ||
1034 | spin_lock_irqsave (&hmidi->lock, flags); | ||
1035 | if (up) { | ||
1036 | if (!hmidi->istimer) { | ||
1037 | init_timer(&hmidi->timer); | ||
1038 | hmidi->timer.function = snd_hdspm_midi_output_timer; | ||
1039 | hmidi->timer.data = (unsigned long) hmidi; | ||
1040 | hmidi->timer.expires = 1 + jiffies; | ||
1041 | add_timer(&hmidi->timer); | ||
1042 | hmidi->istimer++; | ||
1043 | } | ||
1044 | } else { | ||
1045 | if (hmidi->istimer && --hmidi->istimer <= 0) { | ||
1046 | del_timer (&hmidi->timer); | ||
1047 | } | ||
1048 | } | ||
1049 | spin_unlock_irqrestore (&hmidi->lock, flags); | ||
1050 | if (up) | ||
1051 | snd_hdspm_midi_output_write(hmidi); | ||
1052 | } | ||
1053 | |||
1054 | static int snd_hdspm_midi_input_open(snd_rawmidi_substream_t * substream) | ||
1055 | { | ||
1056 | hdspm_midi_t *hmidi; | ||
1057 | |||
1058 | hmidi = (hdspm_midi_t *) substream->rmidi->private_data; | ||
1059 | spin_lock_irq (&hmidi->lock); | ||
1060 | snd_hdspm_flush_midi_input (hmidi->hdspm, hmidi->id); | ||
1061 | hmidi->input = substream; | ||
1062 | spin_unlock_irq (&hmidi->lock); | ||
1063 | |||
1064 | return 0; | ||
1065 | } | ||
1066 | |||
1067 | static int snd_hdspm_midi_output_open(snd_rawmidi_substream_t * substream) | ||
1068 | { | ||
1069 | hdspm_midi_t *hmidi; | ||
1070 | |||
1071 | hmidi = (hdspm_midi_t *) substream->rmidi->private_data; | ||
1072 | spin_lock_irq (&hmidi->lock); | ||
1073 | hmidi->output = substream; | ||
1074 | spin_unlock_irq (&hmidi->lock); | ||
1075 | |||
1076 | return 0; | ||
1077 | } | ||
1078 | |||
1079 | static int snd_hdspm_midi_input_close(snd_rawmidi_substream_t * substream) | ||
1080 | { | ||
1081 | hdspm_midi_t *hmidi; | ||
1082 | |||
1083 | snd_hdspm_midi_input_trigger (substream, 0); | ||
1084 | |||
1085 | hmidi = (hdspm_midi_t *) substream->rmidi->private_data; | ||
1086 | spin_lock_irq (&hmidi->lock); | ||
1087 | hmidi->input = NULL; | ||
1088 | spin_unlock_irq (&hmidi->lock); | ||
1089 | |||
1090 | return 0; | ||
1091 | } | ||
1092 | |||
1093 | static int snd_hdspm_midi_output_close(snd_rawmidi_substream_t * substream) | ||
1094 | { | ||
1095 | hdspm_midi_t *hmidi; | ||
1096 | |||
1097 | snd_hdspm_midi_output_trigger (substream, 0); | ||
1098 | |||
1099 | hmidi = (hdspm_midi_t *) substream->rmidi->private_data; | ||
1100 | spin_lock_irq (&hmidi->lock); | ||
1101 | hmidi->output = NULL; | ||
1102 | spin_unlock_irq (&hmidi->lock); | ||
1103 | |||
1104 | return 0; | ||
1105 | } | ||
1106 | |||
1107 | snd_rawmidi_ops_t snd_hdspm_midi_output = | ||
1108 | { | ||
1109 | .open = snd_hdspm_midi_output_open, | ||
1110 | .close = snd_hdspm_midi_output_close, | ||
1111 | .trigger = snd_hdspm_midi_output_trigger, | ||
1112 | }; | ||
1113 | |||
1114 | snd_rawmidi_ops_t snd_hdspm_midi_input = | ||
1115 | { | ||
1116 | .open = snd_hdspm_midi_input_open, | ||
1117 | .close = snd_hdspm_midi_input_close, | ||
1118 | .trigger = snd_hdspm_midi_input_trigger, | ||
1119 | }; | ||
1120 | |||
1121 | static int __devinit snd_hdspm_create_midi (snd_card_t *card, hdspm_t *hdspm, int id) | ||
1122 | { | ||
1123 | int err; | ||
1124 | char buf[32]; | ||
1125 | |||
1126 | hdspm->midi[id].id = id; | ||
1127 | hdspm->midi[id].rmidi = NULL; | ||
1128 | hdspm->midi[id].input = NULL; | ||
1129 | hdspm->midi[id].output = NULL; | ||
1130 | hdspm->midi[id].hdspm = hdspm; | ||
1131 | hdspm->midi[id].istimer = 0; | ||
1132 | hdspm->midi[id].pending = 0; | ||
1133 | spin_lock_init (&hdspm->midi[id].lock); | ||
1134 | |||
1135 | sprintf (buf, "%s MIDI %d", card->shortname, id+1); | ||
1136 | if ((err = snd_rawmidi_new (card, buf, id, 1, 1, &hdspm->midi[id].rmidi)) < 0) | ||
1137 | return err; | ||
1138 | |||
1139 | sprintf (hdspm->midi[id].rmidi->name, "%s MIDI %d", card->id, id+1); | ||
1140 | hdspm->midi[id].rmidi->private_data = &hdspm->midi[id]; | ||
1141 | |||
1142 | snd_rawmidi_set_ops (hdspm->midi[id].rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_hdspm_midi_output); | ||
1143 | snd_rawmidi_set_ops (hdspm->midi[id].rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_hdspm_midi_input); | ||
1144 | |||
1145 | hdspm->midi[id].rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | | ||
1146 | SNDRV_RAWMIDI_INFO_INPUT | | ||
1147 | SNDRV_RAWMIDI_INFO_DUPLEX; | ||
1148 | |||
1149 | return 0; | ||
1150 | } | ||
1151 | |||
1152 | |||
1153 | static void hdspm_midi_tasklet(unsigned long arg) | ||
1154 | { | ||
1155 | hdspm_t *hdspm = (hdspm_t *)arg; | ||
1156 | |||
1157 | if (hdspm->midi[0].pending) | ||
1158 | snd_hdspm_midi_input_read (&hdspm->midi[0]); | ||
1159 | if (hdspm->midi[1].pending) | ||
1160 | snd_hdspm_midi_input_read (&hdspm->midi[1]); | ||
1161 | } | ||
1162 | |||
1163 | |||
1164 | /*----------------------------------------------------------------------------- | ||
1165 | Status Interface | ||
1166 | ----------------------------------------------------------------------------*/ | ||
1167 | |||
1168 | /* get the system sample rate which is set */ | ||
1169 | |||
1170 | #define HDSPM_SYSTEM_SAMPLE_RATE(xname, xindex) \ | ||
1171 | { .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ | ||
1172 | .name = xname, \ | ||
1173 | .index = xindex, \ | ||
1174 | .access = SNDRV_CTL_ELEM_ACCESS_READ, \ | ||
1175 | .info = snd_hdspm_info_system_sample_rate, \ | ||
1176 | .get = snd_hdspm_get_system_sample_rate \ | ||
1177 | } | ||
1178 | |||
1179 | static int snd_hdspm_info_system_sample_rate(snd_kcontrol_t * kcontrol, | ||
1180 | snd_ctl_elem_info_t * uinfo) | ||
1181 | { | ||
1182 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
1183 | uinfo->count = 1; | ||
1184 | return 0; | ||
1185 | } | ||
1186 | |||
1187 | static int snd_hdspm_get_system_sample_rate(snd_kcontrol_t * kcontrol, | ||
1188 | snd_ctl_elem_value_t * | ||
1189 | ucontrol) | ||
1190 | { | ||
1191 | hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); | ||
1192 | |||
1193 | ucontrol->value.enumerated.item[0] = hdspm->system_sample_rate; | ||
1194 | return 0; | ||
1195 | } | ||
1196 | |||
1197 | #define HDSPM_AUTOSYNC_SAMPLE_RATE(xname, xindex) \ | ||
1198 | { .iface = SNDRV_CTL_ELEM_IFACE_PCM, \ | ||
1199 | .name = xname, \ | ||
1200 | .index = xindex, \ | ||
1201 | .access = SNDRV_CTL_ELEM_ACCESS_READ, \ | ||
1202 | .info = snd_hdspm_info_autosync_sample_rate, \ | ||
1203 | .get = snd_hdspm_get_autosync_sample_rate \ | ||
1204 | } | ||
1205 | |||
1206 | static int snd_hdspm_info_autosync_sample_rate(snd_kcontrol_t * kcontrol, | ||
1207 | snd_ctl_elem_info_t * uinfo) | ||
1208 | { | ||
1209 | static char *texts[] = { "32000", "44100", "48000", | ||
1210 | "64000", "88200", "96000", | ||
1211 | "128000", "176400", "192000", | ||
1212 | "None" | ||
1213 | }; | ||
1214 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
1215 | uinfo->count = 1; | ||
1216 | uinfo->value.enumerated.items = 10; | ||
1217 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) | ||
1218 | uinfo->value.enumerated.item = | ||
1219 | uinfo->value.enumerated.items - 1; | ||
1220 | strcpy(uinfo->value.enumerated.name, | ||
1221 | texts[uinfo->value.enumerated.item]); | ||
1222 | return 0; | ||
1223 | } | ||
1224 | |||
1225 | static int snd_hdspm_get_autosync_sample_rate(snd_kcontrol_t * kcontrol, | ||
1226 | snd_ctl_elem_value_t * | ||
1227 | ucontrol) | ||
1228 | { | ||
1229 | hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); | ||
1230 | |||
1231 | switch (hdspm_external_sample_rate(hdspm)) { | ||
1232 | case 32000: | ||
1233 | ucontrol->value.enumerated.item[0] = 0; | ||
1234 | break; | ||
1235 | case 44100: | ||
1236 | ucontrol->value.enumerated.item[0] = 1; | ||
1237 | break; | ||
1238 | case 48000: | ||
1239 | ucontrol->value.enumerated.item[0] = 2; | ||
1240 | break; | ||
1241 | case 64000: | ||
1242 | ucontrol->value.enumerated.item[0] = 3; | ||
1243 | break; | ||
1244 | case 88200: | ||
1245 | ucontrol->value.enumerated.item[0] = 4; | ||
1246 | break; | ||
1247 | case 96000: | ||
1248 | ucontrol->value.enumerated.item[0] = 5; | ||
1249 | break; | ||
1250 | case 128000: | ||
1251 | ucontrol->value.enumerated.item[0] = 6; | ||
1252 | break; | ||
1253 | case 176400: | ||
1254 | ucontrol->value.enumerated.item[0] = 7; | ||
1255 | break; | ||
1256 | case 192000: | ||
1257 | ucontrol->value.enumerated.item[0] = 8; | ||
1258 | break; | ||
1259 | |||
1260 | default: | ||
1261 | ucontrol->value.enumerated.item[0] = 9; | ||
1262 | } | ||
1263 | return 0; | ||
1264 | } | ||
1265 | |||
1266 | #define HDSPM_SYSTEM_CLOCK_MODE(xname, xindex) \ | ||
1267 | { .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ | ||
1268 | .name = xname, \ | ||
1269 | .index = xindex, \ | ||
1270 | .access = SNDRV_CTL_ELEM_ACCESS_READ, \ | ||
1271 | .info = snd_hdspm_info_system_clock_mode, \ | ||
1272 | .get = snd_hdspm_get_system_clock_mode, \ | ||
1273 | } | ||
1274 | |||
1275 | |||
1276 | |||
1277 | static int hdspm_system_clock_mode(hdspm_t * hdspm) | ||
1278 | { | ||
1279 | /* Always reflect the hardware info, rme is never wrong !!!! */ | ||
1280 | |||
1281 | if (hdspm->control_register & HDSPM_ClockModeMaster) | ||
1282 | return 0; | ||
1283 | return 1; | ||
1284 | } | ||
1285 | |||
1286 | static int snd_hdspm_info_system_clock_mode(snd_kcontrol_t * kcontrol, | ||
1287 | snd_ctl_elem_info_t * uinfo) | ||
1288 | { | ||
1289 | static char *texts[] = { "Master", "Slave" }; | ||
1290 | |||
1291 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
1292 | uinfo->count = 1; | ||
1293 | uinfo->value.enumerated.items = 2; | ||
1294 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) | ||
1295 | uinfo->value.enumerated.item = | ||
1296 | uinfo->value.enumerated.items - 1; | ||
1297 | strcpy(uinfo->value.enumerated.name, | ||
1298 | texts[uinfo->value.enumerated.item]); | ||
1299 | return 0; | ||
1300 | } | ||
1301 | |||
1302 | static int snd_hdspm_get_system_clock_mode(snd_kcontrol_t * kcontrol, | ||
1303 | snd_ctl_elem_value_t * ucontrol) | ||
1304 | { | ||
1305 | hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); | ||
1306 | |||
1307 | ucontrol->value.enumerated.item[0] = | ||
1308 | hdspm_system_clock_mode(hdspm); | ||
1309 | return 0; | ||
1310 | } | ||
1311 | |||
1312 | #define HDSPM_CLOCK_SOURCE(xname, xindex) \ | ||
1313 | { .iface = SNDRV_CTL_ELEM_IFACE_PCM, \ | ||
1314 | .name = xname, \ | ||
1315 | .index = xindex, \ | ||
1316 | .info = snd_hdspm_info_clock_source, \ | ||
1317 | .get = snd_hdspm_get_clock_source, \ | ||
1318 | .put = snd_hdspm_put_clock_source \ | ||
1319 | } | ||
1320 | |||
1321 | static int hdspm_clock_source(hdspm_t * hdspm) | ||
1322 | { | ||
1323 | if (hdspm->control_register & HDSPM_ClockModeMaster) { | ||
1324 | switch (hdspm->system_sample_rate) { | ||
1325 | case 32000: | ||
1326 | return 1; | ||
1327 | case 44100: | ||
1328 | return 2; | ||
1329 | case 48000: | ||
1330 | return 3; | ||
1331 | case 64000: | ||
1332 | return 4; | ||
1333 | case 88200: | ||
1334 | return 5; | ||
1335 | case 96000: | ||
1336 | return 6; | ||
1337 | case 128000: | ||
1338 | return 7; | ||
1339 | case 176400: | ||
1340 | return 8; | ||
1341 | case 192000: | ||
1342 | return 9; | ||
1343 | default: | ||
1344 | return 3; | ||
1345 | } | ||
1346 | } else { | ||
1347 | return 0; | ||
1348 | } | ||
1349 | } | ||
1350 | |||
1351 | static int hdspm_set_clock_source(hdspm_t * hdspm, int mode) | ||
1352 | { | ||
1353 | int rate; | ||
1354 | switch (mode) { | ||
1355 | |||
1356 | case HDSPM_CLOCK_SOURCE_AUTOSYNC: | ||
1357 | if (hdspm_external_sample_rate(hdspm) != 0) { | ||
1358 | hdspm->control_register &= ~HDSPM_ClockModeMaster; | ||
1359 | hdspm_write(hdspm, HDSPM_controlRegister, | ||
1360 | hdspm->control_register); | ||
1361 | return 0; | ||
1362 | } | ||
1363 | return -1; | ||
1364 | case HDSPM_CLOCK_SOURCE_INTERNAL_32KHZ: | ||
1365 | rate = 32000; | ||
1366 | break; | ||
1367 | case HDSPM_CLOCK_SOURCE_INTERNAL_44_1KHZ: | ||
1368 | rate = 44100; | ||
1369 | break; | ||
1370 | case HDSPM_CLOCK_SOURCE_INTERNAL_48KHZ: | ||
1371 | rate = 48000; | ||
1372 | break; | ||
1373 | case HDSPM_CLOCK_SOURCE_INTERNAL_64KHZ: | ||
1374 | rate = 64000; | ||
1375 | break; | ||
1376 | case HDSPM_CLOCK_SOURCE_INTERNAL_88_2KHZ: | ||
1377 | rate = 88200; | ||
1378 | break; | ||
1379 | case HDSPM_CLOCK_SOURCE_INTERNAL_96KHZ: | ||
1380 | rate = 96000; | ||
1381 | break; | ||
1382 | case HDSPM_CLOCK_SOURCE_INTERNAL_128KHZ: | ||
1383 | rate = 128000; | ||
1384 | break; | ||
1385 | case HDSPM_CLOCK_SOURCE_INTERNAL_176_4KHZ: | ||
1386 | rate = 176400; | ||
1387 | break; | ||
1388 | case HDSPM_CLOCK_SOURCE_INTERNAL_192KHZ: | ||
1389 | rate = 192000; | ||
1390 | break; | ||
1391 | |||
1392 | default: | ||
1393 | rate = 44100; | ||
1394 | } | ||
1395 | hdspm->control_register |= HDSPM_ClockModeMaster; | ||
1396 | hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); | ||
1397 | hdspm_set_rate(hdspm, rate, 1); | ||
1398 | return 0; | ||
1399 | } | ||
1400 | |||
1401 | static int snd_hdspm_info_clock_source(snd_kcontrol_t * kcontrol, | ||
1402 | snd_ctl_elem_info_t * uinfo) | ||
1403 | { | ||
1404 | static char *texts[] = { "AutoSync", | ||
1405 | "Internal 32.0 kHz", "Internal 44.1 kHz", | ||
1406 | "Internal 48.0 kHz", | ||
1407 | "Internal 64.0 kHz", "Internal 88.2 kHz", | ||
1408 | "Internal 96.0 kHz", | ||
1409 | "Internal 128.0 kHz", "Internal 176.4 kHz", | ||
1410 | "Internal 192.0 kHz" | ||
1411 | }; | ||
1412 | |||
1413 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
1414 | uinfo->count = 1; | ||
1415 | uinfo->value.enumerated.items = 10; | ||
1416 | |||
1417 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) | ||
1418 | uinfo->value.enumerated.item = | ||
1419 | uinfo->value.enumerated.items - 1; | ||
1420 | |||
1421 | strcpy(uinfo->value.enumerated.name, | ||
1422 | texts[uinfo->value.enumerated.item]); | ||
1423 | |||
1424 | return 0; | ||
1425 | } | ||
1426 | |||
1427 | static int snd_hdspm_get_clock_source(snd_kcontrol_t * kcontrol, | ||
1428 | snd_ctl_elem_value_t * ucontrol) | ||
1429 | { | ||
1430 | hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); | ||
1431 | |||
1432 | ucontrol->value.enumerated.item[0] = hdspm_clock_source(hdspm); | ||
1433 | return 0; | ||
1434 | } | ||
1435 | |||
1436 | static int snd_hdspm_put_clock_source(snd_kcontrol_t * kcontrol, | ||
1437 | snd_ctl_elem_value_t * ucontrol) | ||
1438 | { | ||
1439 | hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); | ||
1440 | int change; | ||
1441 | int val; | ||
1442 | |||
1443 | if (!snd_hdspm_use_is_exclusive(hdspm)) | ||
1444 | return -EBUSY; | ||
1445 | val = ucontrol->value.enumerated.item[0]; | ||
1446 | if (val < 0) | ||
1447 | val = 0; | ||
1448 | if (val > 6) | ||
1449 | val = 6; | ||
1450 | spin_lock_irq(&hdspm->lock); | ||
1451 | if (val != hdspm_clock_source(hdspm)) | ||
1452 | change = (hdspm_set_clock_source(hdspm, val) == 0) ? 1 : 0; | ||
1453 | else | ||
1454 | change = 0; | ||
1455 | spin_unlock_irq(&hdspm->lock); | ||
1456 | return change; | ||
1457 | } | ||
1458 | |||
1459 | #define HDSPM_PREF_SYNC_REF(xname, xindex) \ | ||
1460 | { .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ | ||
1461 | .name = xname, \ | ||
1462 | .index = xindex, \ | ||
1463 | .info = snd_hdspm_info_pref_sync_ref, \ | ||
1464 | .get = snd_hdspm_get_pref_sync_ref, \ | ||
1465 | .put = snd_hdspm_put_pref_sync_ref \ | ||
1466 | } | ||
1467 | |||
1468 | static int hdspm_pref_sync_ref(hdspm_t * hdspm) | ||
1469 | { | ||
1470 | /* Notice that this looks at the requested sync source, | ||
1471 | not the one actually in use. | ||
1472 | */ | ||
1473 | switch (hdspm->control_register & HDSPM_SyncRefMask) { | ||
1474 | case HDSPM_SyncRef_Word: | ||
1475 | return HDSPM_SYNC_FROM_WORD; | ||
1476 | case HDSPM_SyncRef_MADI: | ||
1477 | return HDSPM_SYNC_FROM_MADI; | ||
1478 | } | ||
1479 | |||
1480 | return HDSPM_SYNC_FROM_WORD; | ||
1481 | } | ||
1482 | |||
1483 | static int hdspm_set_pref_sync_ref(hdspm_t * hdspm, int pref) | ||
1484 | { | ||
1485 | hdspm->control_register &= ~HDSPM_SyncRefMask; | ||
1486 | |||
1487 | switch (pref) { | ||
1488 | case HDSPM_SYNC_FROM_MADI: | ||
1489 | hdspm->control_register |= HDSPM_SyncRef_MADI; | ||
1490 | break; | ||
1491 | case HDSPM_SYNC_FROM_WORD: | ||
1492 | hdspm->control_register |= HDSPM_SyncRef_Word; | ||
1493 | break; | ||
1494 | default: | ||
1495 | return -1; | ||
1496 | } | ||
1497 | hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); | ||
1498 | return 0; | ||
1499 | } | ||
1500 | |||
1501 | static int snd_hdspm_info_pref_sync_ref(snd_kcontrol_t * kcontrol, | ||
1502 | snd_ctl_elem_info_t * uinfo) | ||
1503 | { | ||
1504 | static char *texts[] = { "Word", "MADI" }; | ||
1505 | |||
1506 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
1507 | uinfo->count = 1; | ||
1508 | |||
1509 | uinfo->value.enumerated.items = 2; | ||
1510 | |||
1511 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) | ||
1512 | uinfo->value.enumerated.item = | ||
1513 | uinfo->value.enumerated.items - 1; | ||
1514 | strcpy(uinfo->value.enumerated.name, | ||
1515 | texts[uinfo->value.enumerated.item]); | ||
1516 | return 0; | ||
1517 | } | ||
1518 | |||
1519 | static int snd_hdspm_get_pref_sync_ref(snd_kcontrol_t * kcontrol, | ||
1520 | snd_ctl_elem_value_t * ucontrol) | ||
1521 | { | ||
1522 | hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); | ||
1523 | |||
1524 | ucontrol->value.enumerated.item[0] = hdspm_pref_sync_ref(hdspm); | ||
1525 | return 0; | ||
1526 | } | ||
1527 | |||
1528 | static int snd_hdspm_put_pref_sync_ref(snd_kcontrol_t * kcontrol, | ||
1529 | snd_ctl_elem_value_t * ucontrol) | ||
1530 | { | ||
1531 | hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); | ||
1532 | int change, max; | ||
1533 | unsigned int val; | ||
1534 | |||
1535 | max = 2; | ||
1536 | |||
1537 | if (!snd_hdspm_use_is_exclusive(hdspm)) | ||
1538 | return -EBUSY; | ||
1539 | |||
1540 | val = ucontrol->value.enumerated.item[0] % max; | ||
1541 | |||
1542 | spin_lock_irq(&hdspm->lock); | ||
1543 | change = (int) val != hdspm_pref_sync_ref(hdspm); | ||
1544 | hdspm_set_pref_sync_ref(hdspm, val); | ||
1545 | spin_unlock_irq(&hdspm->lock); | ||
1546 | return change; | ||
1547 | } | ||
1548 | |||
1549 | #define HDSPM_AUTOSYNC_REF(xname, xindex) \ | ||
1550 | { .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ | ||
1551 | .name = xname, \ | ||
1552 | .index = xindex, \ | ||
1553 | .access = SNDRV_CTL_ELEM_ACCESS_READ, \ | ||
1554 | .info = snd_hdspm_info_autosync_ref, \ | ||
1555 | .get = snd_hdspm_get_autosync_ref, \ | ||
1556 | } | ||
1557 | |||
1558 | static int hdspm_autosync_ref(hdspm_t * hdspm) | ||
1559 | { | ||
1560 | /* This looks at the autosync selected sync reference */ | ||
1561 | unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2); | ||
1562 | |||
1563 | switch (status2 & HDSPM_SelSyncRefMask) { | ||
1564 | |||
1565 | case HDSPM_SelSyncRef_WORD: | ||
1566 | return HDSPM_AUTOSYNC_FROM_WORD; | ||
1567 | |||
1568 | case HDSPM_SelSyncRef_MADI: | ||
1569 | return HDSPM_AUTOSYNC_FROM_MADI; | ||
1570 | |||
1571 | case HDSPM_SelSyncRef_NVALID: | ||
1572 | return HDSPM_AUTOSYNC_FROM_NONE; | ||
1573 | |||
1574 | default: | ||
1575 | return 0; | ||
1576 | } | ||
1577 | |||
1578 | return 0; | ||
1579 | } | ||
1580 | |||
1581 | static int snd_hdspm_info_autosync_ref(snd_kcontrol_t * kcontrol, | ||
1582 | snd_ctl_elem_info_t * uinfo) | ||
1583 | { | ||
1584 | static char *texts[] = { "WordClock", "MADI", "None" }; | ||
1585 | |||
1586 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
1587 | uinfo->count = 1; | ||
1588 | uinfo->value.enumerated.items = 3; | ||
1589 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) | ||
1590 | uinfo->value.enumerated.item = | ||
1591 | uinfo->value.enumerated.items - 1; | ||
1592 | strcpy(uinfo->value.enumerated.name, | ||
1593 | texts[uinfo->value.enumerated.item]); | ||
1594 | return 0; | ||
1595 | } | ||
1596 | |||
1597 | static int snd_hdspm_get_autosync_ref(snd_kcontrol_t * kcontrol, | ||
1598 | snd_ctl_elem_value_t * ucontrol) | ||
1599 | { | ||
1600 | hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); | ||
1601 | |||
1602 | ucontrol->value.enumerated.item[0] = hdspm_pref_sync_ref(hdspm); | ||
1603 | return 0; | ||
1604 | } | ||
1605 | |||
1606 | #define HDSPM_LINE_OUT(xname, xindex) \ | ||
1607 | { .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ | ||
1608 | .name = xname, \ | ||
1609 | .index = xindex, \ | ||
1610 | .info = snd_hdspm_info_line_out, \ | ||
1611 | .get = snd_hdspm_get_line_out, \ | ||
1612 | .put = snd_hdspm_put_line_out \ | ||
1613 | } | ||
1614 | |||
1615 | static int hdspm_line_out(hdspm_t * hdspm) | ||
1616 | { | ||
1617 | return (hdspm->control_register & HDSPM_LineOut) ? 1 : 0; | ||
1618 | } | ||
1619 | |||
1620 | |||
1621 | static int hdspm_set_line_output(hdspm_t * hdspm, int out) | ||
1622 | { | ||
1623 | if (out) | ||
1624 | hdspm->control_register |= HDSPM_LineOut; | ||
1625 | else | ||
1626 | hdspm->control_register &= ~HDSPM_LineOut; | ||
1627 | hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); | ||
1628 | |||
1629 | return 0; | ||
1630 | } | ||
1631 | |||
1632 | static int snd_hdspm_info_line_out(snd_kcontrol_t * kcontrol, | ||
1633 | snd_ctl_elem_info_t * uinfo) | ||
1634 | { | ||
1635 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
1636 | uinfo->count = 1; | ||
1637 | uinfo->value.integer.min = 0; | ||
1638 | uinfo->value.integer.max = 1; | ||
1639 | return 0; | ||
1640 | } | ||
1641 | |||
1642 | static int snd_hdspm_get_line_out(snd_kcontrol_t * kcontrol, | ||
1643 | snd_ctl_elem_value_t * ucontrol) | ||
1644 | { | ||
1645 | hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); | ||
1646 | |||
1647 | spin_lock_irq(&hdspm->lock); | ||
1648 | ucontrol->value.integer.value[0] = hdspm_line_out(hdspm); | ||
1649 | spin_unlock_irq(&hdspm->lock); | ||
1650 | return 0; | ||
1651 | } | ||
1652 | |||
1653 | static int snd_hdspm_put_line_out(snd_kcontrol_t * kcontrol, | ||
1654 | snd_ctl_elem_value_t * ucontrol) | ||
1655 | { | ||
1656 | hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); | ||
1657 | int change; | ||
1658 | unsigned int val; | ||
1659 | |||
1660 | if (!snd_hdspm_use_is_exclusive(hdspm)) | ||
1661 | return -EBUSY; | ||
1662 | val = ucontrol->value.integer.value[0] & 1; | ||
1663 | spin_lock_irq(&hdspm->lock); | ||
1664 | change = (int) val != hdspm_line_out(hdspm); | ||
1665 | hdspm_set_line_output(hdspm, val); | ||
1666 | spin_unlock_irq(&hdspm->lock); | ||
1667 | return change; | ||
1668 | } | ||
1669 | |||
1670 | #define HDSPM_TX_64(xname, xindex) \ | ||
1671 | { .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ | ||
1672 | .name = xname, \ | ||
1673 | .index = xindex, \ | ||
1674 | .info = snd_hdspm_info_tx_64, \ | ||
1675 | .get = snd_hdspm_get_tx_64, \ | ||
1676 | .put = snd_hdspm_put_tx_64 \ | ||
1677 | } | ||
1678 | |||
1679 | static int hdspm_tx_64(hdspm_t * hdspm) | ||
1680 | { | ||
1681 | return (hdspm->control_register & HDSPM_TX_64ch) ? 1 : 0; | ||
1682 | } | ||
1683 | |||
1684 | static int hdspm_set_tx_64(hdspm_t * hdspm, int out) | ||
1685 | { | ||
1686 | if (out) | ||
1687 | hdspm->control_register |= HDSPM_TX_64ch; | ||
1688 | else | ||
1689 | hdspm->control_register &= ~HDSPM_TX_64ch; | ||
1690 | hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); | ||
1691 | |||
1692 | return 0; | ||
1693 | } | ||
1694 | |||
1695 | static int snd_hdspm_info_tx_64(snd_kcontrol_t * kcontrol, | ||
1696 | snd_ctl_elem_info_t * uinfo) | ||
1697 | { | ||
1698 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
1699 | uinfo->count = 1; | ||
1700 | uinfo->value.integer.min = 0; | ||
1701 | uinfo->value.integer.max = 1; | ||
1702 | return 0; | ||
1703 | } | ||
1704 | |||
1705 | static int snd_hdspm_get_tx_64(snd_kcontrol_t * kcontrol, | ||
1706 | snd_ctl_elem_value_t * ucontrol) | ||
1707 | { | ||
1708 | hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); | ||
1709 | |||
1710 | spin_lock_irq(&hdspm->lock); | ||
1711 | ucontrol->value.integer.value[0] = hdspm_tx_64(hdspm); | ||
1712 | spin_unlock_irq(&hdspm->lock); | ||
1713 | return 0; | ||
1714 | } | ||
1715 | |||
1716 | static int snd_hdspm_put_tx_64(snd_kcontrol_t * kcontrol, | ||
1717 | snd_ctl_elem_value_t * ucontrol) | ||
1718 | { | ||
1719 | hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); | ||
1720 | int change; | ||
1721 | unsigned int val; | ||
1722 | |||
1723 | if (!snd_hdspm_use_is_exclusive(hdspm)) | ||
1724 | return -EBUSY; | ||
1725 | val = ucontrol->value.integer.value[0] & 1; | ||
1726 | spin_lock_irq(&hdspm->lock); | ||
1727 | change = (int) val != hdspm_tx_64(hdspm); | ||
1728 | hdspm_set_tx_64(hdspm, val); | ||
1729 | spin_unlock_irq(&hdspm->lock); | ||
1730 | return change; | ||
1731 | } | ||
1732 | |||
1733 | #define HDSPM_C_TMS(xname, xindex) \ | ||
1734 | { .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ | ||
1735 | .name = xname, \ | ||
1736 | .index = xindex, \ | ||
1737 | .info = snd_hdspm_info_c_tms, \ | ||
1738 | .get = snd_hdspm_get_c_tms, \ | ||
1739 | .put = snd_hdspm_put_c_tms \ | ||
1740 | } | ||
1741 | |||
1742 | static int hdspm_c_tms(hdspm_t * hdspm) | ||
1743 | { | ||
1744 | return (hdspm->control_register & HDSPM_clr_tms) ? 1 : 0; | ||
1745 | } | ||
1746 | |||
1747 | static int hdspm_set_c_tms(hdspm_t * hdspm, int out) | ||
1748 | { | ||
1749 | if (out) | ||
1750 | hdspm->control_register |= HDSPM_clr_tms; | ||
1751 | else | ||
1752 | hdspm->control_register &= ~HDSPM_clr_tms; | ||
1753 | hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); | ||
1754 | |||
1755 | return 0; | ||
1756 | } | ||
1757 | |||
1758 | static int snd_hdspm_info_c_tms(snd_kcontrol_t * kcontrol, | ||
1759 | snd_ctl_elem_info_t * uinfo) | ||
1760 | { | ||
1761 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
1762 | uinfo->count = 1; | ||
1763 | uinfo->value.integer.min = 0; | ||
1764 | uinfo->value.integer.max = 1; | ||
1765 | return 0; | ||
1766 | } | ||
1767 | |||
1768 | static int snd_hdspm_get_c_tms(snd_kcontrol_t * kcontrol, | ||
1769 | snd_ctl_elem_value_t * ucontrol) | ||
1770 | { | ||
1771 | hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); | ||
1772 | |||
1773 | spin_lock_irq(&hdspm->lock); | ||
1774 | ucontrol->value.integer.value[0] = hdspm_c_tms(hdspm); | ||
1775 | spin_unlock_irq(&hdspm->lock); | ||
1776 | return 0; | ||
1777 | } | ||
1778 | |||
1779 | static int snd_hdspm_put_c_tms(snd_kcontrol_t * kcontrol, | ||
1780 | snd_ctl_elem_value_t * ucontrol) | ||
1781 | { | ||
1782 | hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); | ||
1783 | int change; | ||
1784 | unsigned int val; | ||
1785 | |||
1786 | if (!snd_hdspm_use_is_exclusive(hdspm)) | ||
1787 | return -EBUSY; | ||
1788 | val = ucontrol->value.integer.value[0] & 1; | ||
1789 | spin_lock_irq(&hdspm->lock); | ||
1790 | change = (int) val != hdspm_c_tms(hdspm); | ||
1791 | hdspm_set_c_tms(hdspm, val); | ||
1792 | spin_unlock_irq(&hdspm->lock); | ||
1793 | return change; | ||
1794 | } | ||
1795 | |||
1796 | #define HDSPM_SAFE_MODE(xname, xindex) \ | ||
1797 | { .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ | ||
1798 | .name = xname, \ | ||
1799 | .index = xindex, \ | ||
1800 | .info = snd_hdspm_info_safe_mode, \ | ||
1801 | .get = snd_hdspm_get_safe_mode, \ | ||
1802 | .put = snd_hdspm_put_safe_mode \ | ||
1803 | } | ||
1804 | |||
1805 | static int hdspm_safe_mode(hdspm_t * hdspm) | ||
1806 | { | ||
1807 | return (hdspm->control_register & HDSPM_AutoInp) ? 1 : 0; | ||
1808 | } | ||
1809 | |||
1810 | static int hdspm_set_safe_mode(hdspm_t * hdspm, int out) | ||
1811 | { | ||
1812 | if (out) | ||
1813 | hdspm->control_register |= HDSPM_AutoInp; | ||
1814 | else | ||
1815 | hdspm->control_register &= ~HDSPM_AutoInp; | ||
1816 | hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); | ||
1817 | |||
1818 | return 0; | ||
1819 | } | ||
1820 | |||
1821 | static int snd_hdspm_info_safe_mode(snd_kcontrol_t * kcontrol, | ||
1822 | snd_ctl_elem_info_t * uinfo) | ||
1823 | { | ||
1824 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
1825 | uinfo->count = 1; | ||
1826 | uinfo->value.integer.min = 0; | ||
1827 | uinfo->value.integer.max = 1; | ||
1828 | return 0; | ||
1829 | } | ||
1830 | |||
1831 | static int snd_hdspm_get_safe_mode(snd_kcontrol_t * kcontrol, | ||
1832 | snd_ctl_elem_value_t * ucontrol) | ||
1833 | { | ||
1834 | hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); | ||
1835 | |||
1836 | spin_lock_irq(&hdspm->lock); | ||
1837 | ucontrol->value.integer.value[0] = hdspm_safe_mode(hdspm); | ||
1838 | spin_unlock_irq(&hdspm->lock); | ||
1839 | return 0; | ||
1840 | } | ||
1841 | |||
1842 | static int snd_hdspm_put_safe_mode(snd_kcontrol_t * kcontrol, | ||
1843 | snd_ctl_elem_value_t * ucontrol) | ||
1844 | { | ||
1845 | hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); | ||
1846 | int change; | ||
1847 | unsigned int val; | ||
1848 | |||
1849 | if (!snd_hdspm_use_is_exclusive(hdspm)) | ||
1850 | return -EBUSY; | ||
1851 | val = ucontrol->value.integer.value[0] & 1; | ||
1852 | spin_lock_irq(&hdspm->lock); | ||
1853 | change = (int) val != hdspm_safe_mode(hdspm); | ||
1854 | hdspm_set_safe_mode(hdspm, val); | ||
1855 | spin_unlock_irq(&hdspm->lock); | ||
1856 | return change; | ||
1857 | } | ||
1858 | |||
1859 | #define HDSPM_INPUT_SELECT(xname, xindex) \ | ||
1860 | { .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ | ||
1861 | .name = xname, \ | ||
1862 | .index = xindex, \ | ||
1863 | .info = snd_hdspm_info_input_select, \ | ||
1864 | .get = snd_hdspm_get_input_select, \ | ||
1865 | .put = snd_hdspm_put_input_select \ | ||
1866 | } | ||
1867 | |||
1868 | static int hdspm_input_select(hdspm_t * hdspm) | ||
1869 | { | ||
1870 | return (hdspm->control_register & HDSPM_InputSelect0) ? 1 : 0; | ||
1871 | } | ||
1872 | |||
1873 | static int hdspm_set_input_select(hdspm_t * hdspm, int out) | ||
1874 | { | ||
1875 | if (out) | ||
1876 | hdspm->control_register |= HDSPM_InputSelect0; | ||
1877 | else | ||
1878 | hdspm->control_register &= ~HDSPM_InputSelect0; | ||
1879 | hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); | ||
1880 | |||
1881 | return 0; | ||
1882 | } | ||
1883 | |||
1884 | static int snd_hdspm_info_input_select(snd_kcontrol_t * kcontrol, | ||
1885 | snd_ctl_elem_info_t * uinfo) | ||
1886 | { | ||
1887 | static char *texts[] = { "optical", "coaxial" }; | ||
1888 | |||
1889 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
1890 | uinfo->count = 1; | ||
1891 | uinfo->value.enumerated.items = 2; | ||
1892 | |||
1893 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) | ||
1894 | uinfo->value.enumerated.item = | ||
1895 | uinfo->value.enumerated.items - 1; | ||
1896 | strcpy(uinfo->value.enumerated.name, | ||
1897 | texts[uinfo->value.enumerated.item]); | ||
1898 | |||
1899 | return 0; | ||
1900 | } | ||
1901 | |||
1902 | static int snd_hdspm_get_input_select(snd_kcontrol_t * kcontrol, | ||
1903 | snd_ctl_elem_value_t * ucontrol) | ||
1904 | { | ||
1905 | hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); | ||
1906 | |||
1907 | spin_lock_irq(&hdspm->lock); | ||
1908 | ucontrol->value.enumerated.item[0] = hdspm_input_select(hdspm); | ||
1909 | spin_unlock_irq(&hdspm->lock); | ||
1910 | return 0; | ||
1911 | } | ||
1912 | |||
1913 | static int snd_hdspm_put_input_select(snd_kcontrol_t * kcontrol, | ||
1914 | snd_ctl_elem_value_t * ucontrol) | ||
1915 | { | ||
1916 | hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); | ||
1917 | int change; | ||
1918 | unsigned int val; | ||
1919 | |||
1920 | if (!snd_hdspm_use_is_exclusive(hdspm)) | ||
1921 | return -EBUSY; | ||
1922 | val = ucontrol->value.integer.value[0] & 1; | ||
1923 | spin_lock_irq(&hdspm->lock); | ||
1924 | change = (int) val != hdspm_input_select(hdspm); | ||
1925 | hdspm_set_input_select(hdspm, val); | ||
1926 | spin_unlock_irq(&hdspm->lock); | ||
1927 | return change; | ||
1928 | } | ||
1929 | |||
1930 | /* Simple Mixer | ||
1931 | deprecated since to much faders ??? | ||
1932 | MIXER interface says output (source, destination, value) | ||
1933 | where source > MAX_channels are playback channels | ||
1934 | on MADICARD | ||
1935 | - playback mixer matrix: [channelout+64] [output] [value] | ||
1936 | - input(thru) mixer matrix: [channelin] [output] [value] | ||
1937 | (better do 2 kontrols for seperation ?) | ||
1938 | */ | ||
1939 | |||
1940 | #define HDSPM_MIXER(xname, xindex) \ | ||
1941 | { .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ | ||
1942 | .name = xname, \ | ||
1943 | .index = xindex, \ | ||
1944 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ | ||
1945 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ | ||
1946 | .info = snd_hdspm_info_mixer, \ | ||
1947 | .get = snd_hdspm_get_mixer, \ | ||
1948 | .put = snd_hdspm_put_mixer \ | ||
1949 | } | ||
1950 | |||
1951 | static int snd_hdspm_info_mixer(snd_kcontrol_t * kcontrol, | ||
1952 | snd_ctl_elem_info_t * uinfo) | ||
1953 | { | ||
1954 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
1955 | uinfo->count = 3; | ||
1956 | uinfo->value.integer.min = 0; | ||
1957 | uinfo->value.integer.max = 65535; | ||
1958 | uinfo->value.integer.step = 1; | ||
1959 | return 0; | ||
1960 | } | ||
1961 | |||
1962 | static int snd_hdspm_get_mixer(snd_kcontrol_t * kcontrol, | ||
1963 | snd_ctl_elem_value_t * ucontrol) | ||
1964 | { | ||
1965 | hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); | ||
1966 | int source; | ||
1967 | int destination; | ||
1968 | |||
1969 | source = ucontrol->value.integer.value[0]; | ||
1970 | if (source < 0) | ||
1971 | source = 0; | ||
1972 | else if (source >= 2 * HDSPM_MAX_CHANNELS) | ||
1973 | source = 2 * HDSPM_MAX_CHANNELS - 1; | ||
1974 | |||
1975 | destination = ucontrol->value.integer.value[1]; | ||
1976 | if (destination < 0) | ||
1977 | destination = 0; | ||
1978 | else if (destination >= HDSPM_MAX_CHANNELS) | ||
1979 | destination = HDSPM_MAX_CHANNELS - 1; | ||
1980 | |||
1981 | spin_lock_irq(&hdspm->lock); | ||
1982 | if (source >= HDSPM_MAX_CHANNELS) | ||
1983 | ucontrol->value.integer.value[2] = | ||
1984 | hdspm_read_pb_gain(hdspm, destination, | ||
1985 | source - HDSPM_MAX_CHANNELS); | ||
1986 | else | ||
1987 | ucontrol->value.integer.value[2] = | ||
1988 | hdspm_read_in_gain(hdspm, destination, source); | ||
1989 | |||
1990 | spin_unlock_irq(&hdspm->lock); | ||
1991 | |||
1992 | return 0; | ||
1993 | } | ||
1994 | |||
1995 | static int snd_hdspm_put_mixer(snd_kcontrol_t * kcontrol, | ||
1996 | snd_ctl_elem_value_t * ucontrol) | ||
1997 | { | ||
1998 | hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); | ||
1999 | int change; | ||
2000 | int source; | ||
2001 | int destination; | ||
2002 | int gain; | ||
2003 | |||
2004 | if (!snd_hdspm_use_is_exclusive(hdspm)) | ||
2005 | return -EBUSY; | ||
2006 | |||
2007 | source = ucontrol->value.integer.value[0]; | ||
2008 | destination = ucontrol->value.integer.value[1]; | ||
2009 | |||
2010 | if (source < 0 || source >= 2 * HDSPM_MAX_CHANNELS) | ||
2011 | return -1; | ||
2012 | if (destination < 0 || destination >= HDSPM_MAX_CHANNELS) | ||
2013 | return -1; | ||
2014 | |||
2015 | gain = ucontrol->value.integer.value[2]; | ||
2016 | |||
2017 | spin_lock_irq(&hdspm->lock); | ||
2018 | |||
2019 | if (source >= HDSPM_MAX_CHANNELS) | ||
2020 | change = gain != hdspm_read_pb_gain(hdspm, destination, | ||
2021 | source - | ||
2022 | HDSPM_MAX_CHANNELS); | ||
2023 | else | ||
2024 | change = | ||
2025 | gain != hdspm_read_in_gain(hdspm, destination, source); | ||
2026 | |||
2027 | if (change) { | ||
2028 | if (source >= HDSPM_MAX_CHANNELS) | ||
2029 | hdspm_write_pb_gain(hdspm, destination, | ||
2030 | source - HDSPM_MAX_CHANNELS, | ||
2031 | gain); | ||
2032 | else | ||
2033 | hdspm_write_in_gain(hdspm, destination, source, | ||
2034 | gain); | ||
2035 | } | ||
2036 | spin_unlock_irq(&hdspm->lock); | ||
2037 | |||
2038 | return change; | ||
2039 | } | ||
2040 | |||
2041 | /* The simple mixer control(s) provide gain control for the | ||
2042 | basic 1:1 mappings of playback streams to output | ||
2043 | streams. | ||
2044 | */ | ||
2045 | |||
2046 | #define HDSPM_PLAYBACK_MIXER \ | ||
2047 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
2048 | .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_WRITE | \ | ||
2049 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ | ||
2050 | .info = snd_hdspm_info_playback_mixer, \ | ||
2051 | .get = snd_hdspm_get_playback_mixer, \ | ||
2052 | .put = snd_hdspm_put_playback_mixer \ | ||
2053 | } | ||
2054 | |||
2055 | static int snd_hdspm_info_playback_mixer(snd_kcontrol_t * kcontrol, | ||
2056 | snd_ctl_elem_info_t * uinfo) | ||
2057 | { | ||
2058 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
2059 | uinfo->count = 1; | ||
2060 | uinfo->value.integer.min = 0; | ||
2061 | uinfo->value.integer.max = 65536; | ||
2062 | uinfo->value.integer.step = 1; | ||
2063 | return 0; | ||
2064 | } | ||
2065 | |||
2066 | static int snd_hdspm_get_playback_mixer(snd_kcontrol_t * kcontrol, | ||
2067 | snd_ctl_elem_value_t * ucontrol) | ||
2068 | { | ||
2069 | hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); | ||
2070 | int channel; | ||
2071 | int mapped_channel; | ||
2072 | |||
2073 | channel = ucontrol->id.index - 1; | ||
2074 | |||
2075 | snd_assert(channel >= 0 | ||
2076 | || channel < HDSPM_MAX_CHANNELS, return -EINVAL); | ||
2077 | |||
2078 | if ((mapped_channel = hdspm->channel_map[channel]) < 0) | ||
2079 | return -EINVAL; | ||
2080 | |||
2081 | spin_lock_irq(&hdspm->lock); | ||
2082 | ucontrol->value.integer.value[0] = | ||
2083 | hdspm_read_pb_gain(hdspm, mapped_channel, mapped_channel); | ||
2084 | spin_unlock_irq(&hdspm->lock); | ||
2085 | |||
2086 | /* snd_printdd("get pb mixer index %d, channel %d, mapped_channel %d, value %d\n", | ||
2087 | ucontrol->id.index, channel, mapped_channel, ucontrol->value.integer.value[0]); | ||
2088 | */ | ||
2089 | |||
2090 | return 0; | ||
2091 | } | ||
2092 | |||
2093 | static int snd_hdspm_put_playback_mixer(snd_kcontrol_t * kcontrol, | ||
2094 | snd_ctl_elem_value_t * ucontrol) | ||
2095 | { | ||
2096 | hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); | ||
2097 | int change; | ||
2098 | int channel; | ||
2099 | int mapped_channel; | ||
2100 | int gain; | ||
2101 | |||
2102 | if (!snd_hdspm_use_is_exclusive(hdspm)) | ||
2103 | return -EBUSY; | ||
2104 | |||
2105 | channel = ucontrol->id.index - 1; | ||
2106 | |||
2107 | snd_assert(channel >= 0 | ||
2108 | || channel < HDSPM_MAX_CHANNELS, return -EINVAL); | ||
2109 | |||
2110 | if ((mapped_channel = hdspm->channel_map[channel]) < 0) | ||
2111 | return -EINVAL; | ||
2112 | |||
2113 | gain = ucontrol->value.integer.value[0]; | ||
2114 | |||
2115 | spin_lock_irq(&hdspm->lock); | ||
2116 | change = | ||
2117 | gain != hdspm_read_pb_gain(hdspm, mapped_channel, | ||
2118 | mapped_channel); | ||
2119 | if (change) | ||
2120 | hdspm_write_pb_gain(hdspm, mapped_channel, mapped_channel, | ||
2121 | gain); | ||
2122 | spin_unlock_irq(&hdspm->lock); | ||
2123 | return change; | ||
2124 | } | ||
2125 | |||
2126 | #define HDSPM_WC_SYNC_CHECK(xname, xindex) \ | ||
2127 | { .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ | ||
2128 | .name = xname, \ | ||
2129 | .index = xindex, \ | ||
2130 | .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ | ||
2131 | .info = snd_hdspm_info_sync_check, \ | ||
2132 | .get = snd_hdspm_get_wc_sync_check \ | ||
2133 | } | ||
2134 | |||
2135 | static int snd_hdspm_info_sync_check(snd_kcontrol_t * kcontrol, | ||
2136 | snd_ctl_elem_info_t * uinfo) | ||
2137 | { | ||
2138 | static char *texts[] = { "No Lock", "Lock", "Sync" }; | ||
2139 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
2140 | uinfo->count = 1; | ||
2141 | uinfo->value.enumerated.items = 3; | ||
2142 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) | ||
2143 | uinfo->value.enumerated.item = | ||
2144 | uinfo->value.enumerated.items - 1; | ||
2145 | strcpy(uinfo->value.enumerated.name, | ||
2146 | texts[uinfo->value.enumerated.item]); | ||
2147 | return 0; | ||
2148 | } | ||
2149 | |||
2150 | static int hdspm_wc_sync_check(hdspm_t * hdspm) | ||
2151 | { | ||
2152 | int status2 = hdspm_read(hdspm, HDSPM_statusRegister2); | ||
2153 | if (status2 & HDSPM_wcLock) { | ||
2154 | if (status2 & HDSPM_wcSync) | ||
2155 | return 2; | ||
2156 | else | ||
2157 | return 1; | ||
2158 | } | ||
2159 | return 0; | ||
2160 | } | ||
2161 | |||
2162 | static int snd_hdspm_get_wc_sync_check(snd_kcontrol_t * kcontrol, | ||
2163 | snd_ctl_elem_value_t * ucontrol) | ||
2164 | { | ||
2165 | hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); | ||
2166 | |||
2167 | ucontrol->value.enumerated.item[0] = hdspm_wc_sync_check(hdspm); | ||
2168 | return 0; | ||
2169 | } | ||
2170 | |||
2171 | |||
2172 | #define HDSPM_MADI_SYNC_CHECK(xname, xindex) \ | ||
2173 | { .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ | ||
2174 | .name = xname, \ | ||
2175 | .index = xindex, \ | ||
2176 | .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ | ||
2177 | .info = snd_hdspm_info_sync_check, \ | ||
2178 | .get = snd_hdspm_get_madisync_sync_check \ | ||
2179 | } | ||
2180 | |||
2181 | static int hdspm_madisync_sync_check(hdspm_t * hdspm) | ||
2182 | { | ||
2183 | int status = hdspm_read(hdspm, HDSPM_statusRegister); | ||
2184 | if (status & HDSPM_madiLock) { | ||
2185 | if (status & HDSPM_madiSync) | ||
2186 | return 2; | ||
2187 | else | ||
2188 | return 1; | ||
2189 | } | ||
2190 | return 0; | ||
2191 | } | ||
2192 | |||
2193 | static int snd_hdspm_get_madisync_sync_check(snd_kcontrol_t * kcontrol, | ||
2194 | snd_ctl_elem_value_t * | ||
2195 | ucontrol) | ||
2196 | { | ||
2197 | hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); | ||
2198 | |||
2199 | ucontrol->value.enumerated.item[0] = | ||
2200 | hdspm_madisync_sync_check(hdspm); | ||
2201 | return 0; | ||
2202 | } | ||
2203 | |||
2204 | |||
2205 | |||
2206 | |||
2207 | static snd_kcontrol_new_t snd_hdspm_controls[] = { | ||
2208 | |||
2209 | HDSPM_MIXER("Mixer", 0), | ||
2210 | /* 'Sample Clock Source' complies with the alsa control naming scheme */ | ||
2211 | HDSPM_CLOCK_SOURCE("Sample Clock Source", 0), | ||
2212 | |||
2213 | HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0), | ||
2214 | HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0), | ||
2215 | HDSPM_AUTOSYNC_REF("AutoSync Reference", 0), | ||
2216 | HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0), | ||
2217 | /* 'External Rate' complies with the alsa control naming scheme */ | ||
2218 | HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0), | ||
2219 | HDSPM_WC_SYNC_CHECK("Word Clock Lock Status", 0), | ||
2220 | HDSPM_MADI_SYNC_CHECK("MADI Sync Lock Status", 0), | ||
2221 | HDSPM_LINE_OUT("Line Out", 0), | ||
2222 | HDSPM_TX_64("TX 64 channels mode", 0), | ||
2223 | HDSPM_C_TMS("Clear Track Marker", 0), | ||
2224 | HDSPM_SAFE_MODE("Safe Mode", 0), | ||
2225 | HDSPM_INPUT_SELECT("Input Select", 0), | ||
2226 | }; | ||
2227 | |||
2228 | static snd_kcontrol_new_t snd_hdspm_playback_mixer = HDSPM_PLAYBACK_MIXER; | ||
2229 | |||
2230 | |||
2231 | static int hdspm_update_simple_mixer_controls(hdspm_t * hdspm) | ||
2232 | { | ||
2233 | int i; | ||
2234 | |||
2235 | for (i = hdspm->ds_channels; i < hdspm->ss_channels; ++i) { | ||
2236 | if (hdspm->system_sample_rate > 48000) { | ||
2237 | hdspm->playback_mixer_ctls[i]->vd[0].access = | ||
2238 | SNDRV_CTL_ELEM_ACCESS_INACTIVE | | ||
2239 | SNDRV_CTL_ELEM_ACCESS_READ | | ||
2240 | SNDRV_CTL_ELEM_ACCESS_VOLATILE; | ||
2241 | } else { | ||
2242 | hdspm->playback_mixer_ctls[i]->vd[0].access = | ||
2243 | SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
2244 | SNDRV_CTL_ELEM_ACCESS_VOLATILE; | ||
2245 | } | ||
2246 | snd_ctl_notify(hdspm->card, SNDRV_CTL_EVENT_MASK_VALUE | | ||
2247 | SNDRV_CTL_EVENT_MASK_INFO, | ||
2248 | &hdspm->playback_mixer_ctls[i]->id); | ||
2249 | } | ||
2250 | |||
2251 | return 0; | ||
2252 | } | ||
2253 | |||
2254 | |||
2255 | static int snd_hdspm_create_controls(snd_card_t * card, hdspm_t * hdspm) | ||
2256 | { | ||
2257 | unsigned int idx, limit; | ||
2258 | int err; | ||
2259 | snd_kcontrol_t *kctl; | ||
2260 | |||
2261 | /* add control list first */ | ||
2262 | |||
2263 | for (idx = 0; idx < ARRAY_SIZE(snd_hdspm_controls); idx++) { | ||
2264 | if ((err = | ||
2265 | snd_ctl_add(card, kctl = | ||
2266 | snd_ctl_new1(&snd_hdspm_controls[idx], | ||
2267 | hdspm))) < 0) { | ||
2268 | return err; | ||
2269 | } | ||
2270 | } | ||
2271 | |||
2272 | /* Channel playback mixer as default control | ||
2273 | Note: the whole matrix would be 128*HDSPM_MIXER_CHANNELS Faders, thats to big for any alsamixer | ||
2274 | they are accesible via special IOCTL on hwdep | ||
2275 | and the mixer 2dimensional mixer control */ | ||
2276 | |||
2277 | snd_hdspm_playback_mixer.name = "Chn"; | ||
2278 | limit = HDSPM_MAX_CHANNELS; | ||
2279 | |||
2280 | /* The index values are one greater than the channel ID so that alsamixer | ||
2281 | will display them correctly. We want to use the index for fast lookup | ||
2282 | of the relevant channel, but if we use it at all, most ALSA software | ||
2283 | does the wrong thing with it ... | ||
2284 | */ | ||
2285 | |||
2286 | for (idx = 0; idx < limit; ++idx) { | ||
2287 | snd_hdspm_playback_mixer.index = idx + 1; | ||
2288 | if ((err = snd_ctl_add(card, | ||
2289 | kctl = | ||
2290 | snd_ctl_new1 | ||
2291 | (&snd_hdspm_playback_mixer, | ||
2292 | hdspm)))) { | ||
2293 | return err; | ||
2294 | } | ||
2295 | hdspm->playback_mixer_ctls[idx] = kctl; | ||
2296 | } | ||
2297 | |||
2298 | return 0; | ||
2299 | } | ||
2300 | |||
2301 | /*------------------------------------------------------------ | ||
2302 | /proc interface | ||
2303 | ------------------------------------------------------------*/ | ||
2304 | |||
2305 | static void | ||
2306 | snd_hdspm_proc_read(snd_info_entry_t * entry, snd_info_buffer_t * buffer) | ||
2307 | { | ||
2308 | hdspm_t *hdspm = (hdspm_t *) entry->private_data; | ||
2309 | unsigned int status; | ||
2310 | unsigned int status2; | ||
2311 | char *pref_sync_ref; | ||
2312 | char *autosync_ref; | ||
2313 | char *system_clock_mode; | ||
2314 | char *clock_source; | ||
2315 | char *insel; | ||
2316 | char *syncref; | ||
2317 | int x, x2; | ||
2318 | |||
2319 | status = hdspm_read(hdspm, HDSPM_statusRegister); | ||
2320 | status2 = hdspm_read(hdspm, HDSPM_statusRegister2); | ||
2321 | |||
2322 | snd_iprintf(buffer, "%s (Card #%d) Rev.%x Status2first3bits: %x\n", | ||
2323 | hdspm->card_name, hdspm->card->number + 1, | ||
2324 | hdspm->firmware_rev, | ||
2325 | (status2 & HDSPM_version0) | | ||
2326 | (status2 & HDSPM_version1) | (status2 & | ||
2327 | HDSPM_version2)); | ||
2328 | |||
2329 | snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n", | ||
2330 | hdspm->irq, hdspm->port, (unsigned long)hdspm->iobase); | ||
2331 | |||
2332 | snd_iprintf(buffer, "--- System ---\n"); | ||
2333 | |||
2334 | snd_iprintf(buffer, | ||
2335 | "IRQ Pending: Audio=%d, MIDI0=%d, MIDI1=%d, IRQcount=%d\n", | ||
2336 | status & HDSPM_audioIRQPending, | ||
2337 | (status & HDSPM_midi0IRQPending) ? 1 : 0, | ||
2338 | (status & HDSPM_midi1IRQPending) ? 1 : 0, | ||
2339 | hdspm->irq_count); | ||
2340 | snd_iprintf(buffer, | ||
2341 | "HW pointer: id = %d, rawptr = %d (%d->%d) estimated= %ld (bytes)\n", | ||
2342 | ((status & HDSPM_BufferID) ? 1 : 0), | ||
2343 | (status & HDSPM_BufferPositionMask), | ||
2344 | (status & HDSPM_BufferPositionMask) % (2 * | ||
2345 | (int)hdspm-> | ||
2346 | period_bytes), | ||
2347 | ((status & HDSPM_BufferPositionMask) - | ||
2348 | 64) % (2 * (int)hdspm->period_bytes), | ||
2349 | (long) hdspm_hw_pointer(hdspm) * 4); | ||
2350 | |||
2351 | snd_iprintf(buffer, | ||
2352 | "MIDI FIFO: Out1=0x%x, Out2=0x%x, In1=0x%x, In2=0x%x \n", | ||
2353 | hdspm_read(hdspm, HDSPM_midiStatusOut0) & 0xFF, | ||
2354 | hdspm_read(hdspm, HDSPM_midiStatusOut1) & 0xFF, | ||
2355 | hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xFF, | ||
2356 | hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xFF); | ||
2357 | snd_iprintf(buffer, | ||
2358 | "Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, status2=0x%x\n", | ||
2359 | hdspm->control_register, hdspm->control2_register, | ||
2360 | status, status2); | ||
2361 | |||
2362 | snd_iprintf(buffer, "--- Settings ---\n"); | ||
2363 | |||
2364 | x = 1 << (6 + | ||
2365 | hdspm_decode_latency(hdspm-> | ||
2366 | control_register & | ||
2367 | HDSPM_LatencyMask)); | ||
2368 | |||
2369 | snd_iprintf(buffer, | ||
2370 | "Size (Latency): %d samples (2 periods of %lu bytes)\n", | ||
2371 | x, (unsigned long) hdspm->period_bytes); | ||
2372 | |||
2373 | snd_iprintf(buffer, "Line out: %s, Precise Pointer: %s\n", | ||
2374 | (hdspm-> | ||
2375 | control_register & HDSPM_LineOut) ? "on " : "off", | ||
2376 | (hdspm->precise_ptr) ? "on" : "off"); | ||
2377 | |||
2378 | switch (hdspm->control_register & HDSPM_InputMask) { | ||
2379 | case HDSPM_InputOptical: | ||
2380 | insel = "Optical"; | ||
2381 | break; | ||
2382 | case HDSPM_InputCoaxial: | ||
2383 | insel = "Coaxial"; | ||
2384 | break; | ||
2385 | default: | ||
2386 | insel = "Unkown"; | ||
2387 | } | ||
2388 | |||
2389 | switch (hdspm->control_register & HDSPM_SyncRefMask) { | ||
2390 | case HDSPM_SyncRef_Word: | ||
2391 | syncref = "WordClock"; | ||
2392 | break; | ||
2393 | case HDSPM_SyncRef_MADI: | ||
2394 | syncref = "MADI"; | ||
2395 | break; | ||
2396 | default: | ||
2397 | syncref = "Unkown"; | ||
2398 | } | ||
2399 | snd_iprintf(buffer, "Inputsel = %s, SyncRef = %s\n", insel, | ||
2400 | syncref); | ||
2401 | |||
2402 | snd_iprintf(buffer, | ||
2403 | "ClearTrackMarker = %s, Transmit in %s Channel Mode, Auto Input %s\n", | ||
2404 | (hdspm-> | ||
2405 | control_register & HDSPM_clr_tms) ? "on" : "off", | ||
2406 | (hdspm-> | ||
2407 | control_register & HDSPM_TX_64ch) ? "64" : "56", | ||
2408 | (hdspm-> | ||
2409 | control_register & HDSPM_AutoInp) ? "on" : "off"); | ||
2410 | |||
2411 | switch (hdspm_clock_source(hdspm)) { | ||
2412 | case HDSPM_CLOCK_SOURCE_AUTOSYNC: | ||
2413 | clock_source = "AutoSync"; | ||
2414 | break; | ||
2415 | case HDSPM_CLOCK_SOURCE_INTERNAL_32KHZ: | ||
2416 | clock_source = "Internal 32 kHz"; | ||
2417 | break; | ||
2418 | case HDSPM_CLOCK_SOURCE_INTERNAL_44_1KHZ: | ||
2419 | clock_source = "Internal 44.1 kHz"; | ||
2420 | break; | ||
2421 | case HDSPM_CLOCK_SOURCE_INTERNAL_48KHZ: | ||
2422 | clock_source = "Internal 48 kHz"; | ||
2423 | break; | ||
2424 | case HDSPM_CLOCK_SOURCE_INTERNAL_64KHZ: | ||
2425 | clock_source = "Internal 64 kHz"; | ||
2426 | break; | ||
2427 | case HDSPM_CLOCK_SOURCE_INTERNAL_88_2KHZ: | ||
2428 | clock_source = "Internal 88.2 kHz"; | ||
2429 | break; | ||
2430 | case HDSPM_CLOCK_SOURCE_INTERNAL_96KHZ: | ||
2431 | clock_source = "Internal 96 kHz"; | ||
2432 | break; | ||
2433 | default: | ||
2434 | clock_source = "Error"; | ||
2435 | } | ||
2436 | snd_iprintf(buffer, "Sample Clock Source: %s\n", clock_source); | ||
2437 | if (!(hdspm->control_register & HDSPM_ClockModeMaster)) { | ||
2438 | system_clock_mode = "Slave"; | ||
2439 | } else { | ||
2440 | system_clock_mode = "Master"; | ||
2441 | } | ||
2442 | snd_iprintf(buffer, "System Clock Mode: %s\n", system_clock_mode); | ||
2443 | |||
2444 | switch (hdspm_pref_sync_ref(hdspm)) { | ||
2445 | case HDSPM_SYNC_FROM_WORD: | ||
2446 | pref_sync_ref = "Word Clock"; | ||
2447 | break; | ||
2448 | case HDSPM_SYNC_FROM_MADI: | ||
2449 | pref_sync_ref = "MADI Sync"; | ||
2450 | break; | ||
2451 | default: | ||
2452 | pref_sync_ref = "XXXX Clock"; | ||
2453 | break; | ||
2454 | } | ||
2455 | snd_iprintf(buffer, "Preferred Sync Reference: %s\n", | ||
2456 | pref_sync_ref); | ||
2457 | |||
2458 | snd_iprintf(buffer, "System Clock Frequency: %d\n", | ||
2459 | hdspm->system_sample_rate); | ||
2460 | |||
2461 | |||
2462 | snd_iprintf(buffer, "--- Status:\n"); | ||
2463 | |||
2464 | x = status & HDSPM_madiSync; | ||
2465 | x2 = status2 & HDSPM_wcSync; | ||
2466 | |||
2467 | snd_iprintf(buffer, "Inputs MADI=%s, WordClock=%s\n", | ||
2468 | (status & HDSPM_madiLock) ? (x ? "Sync" : "Lock") : | ||
2469 | "NoLock", | ||
2470 | (status2 & HDSPM_wcLock) ? (x2 ? "Sync" : "Lock") : | ||
2471 | "NoLock"); | ||
2472 | |||
2473 | switch (hdspm_autosync_ref(hdspm)) { | ||
2474 | case HDSPM_AUTOSYNC_FROM_WORD: | ||
2475 | autosync_ref = "Word Clock"; | ||
2476 | break; | ||
2477 | case HDSPM_AUTOSYNC_FROM_MADI: | ||
2478 | autosync_ref = "MADI Sync"; | ||
2479 | break; | ||
2480 | case HDSPM_AUTOSYNC_FROM_NONE: | ||
2481 | autosync_ref = "Input not valid"; | ||
2482 | break; | ||
2483 | default: | ||
2484 | autosync_ref = "---"; | ||
2485 | break; | ||
2486 | } | ||
2487 | snd_iprintf(buffer, | ||
2488 | "AutoSync: Reference= %s, Freq=%d (MADI = %d, Word = %d)\n", | ||
2489 | autosync_ref, hdspm_external_sample_rate(hdspm), | ||
2490 | (status & HDSPM_madiFreqMask) >> 22, | ||
2491 | (status2 & HDSPM_wcFreqMask) >> 5); | ||
2492 | |||
2493 | snd_iprintf(buffer, "Input: %s, Mode=%s\n", | ||
2494 | (status & HDSPM_AB_int) ? "Coax" : "Optical", | ||
2495 | (status & HDSPM_RX_64ch) ? "64 channels" : | ||
2496 | "56 channels"); | ||
2497 | |||
2498 | snd_iprintf(buffer, "\n"); | ||
2499 | } | ||
2500 | |||
2501 | static void __devinit snd_hdspm_proc_init(hdspm_t * hdspm) | ||
2502 | { | ||
2503 | snd_info_entry_t *entry; | ||
2504 | |||
2505 | if (!snd_card_proc_new(hdspm->card, "hdspm", &entry)) | ||
2506 | snd_info_set_text_ops(entry, hdspm, 1024, | ||
2507 | snd_hdspm_proc_read); | ||
2508 | } | ||
2509 | |||
2510 | /*------------------------------------------------------------ | ||
2511 | hdspm intitialize | ||
2512 | ------------------------------------------------------------*/ | ||
2513 | |||
2514 | static int snd_hdspm_set_defaults(hdspm_t * hdspm) | ||
2515 | { | ||
2516 | unsigned int i; | ||
2517 | |||
2518 | /* ASSUMPTION: hdspm->lock is either held, or there is no need to | ||
2519 | hold it (e.g. during module initalization). | ||
2520 | */ | ||
2521 | |||
2522 | /* set defaults: */ | ||
2523 | |||
2524 | hdspm->control_register = HDSPM_ClockModeMaster | /* Master Cloack Mode on */ | ||
2525 | hdspm_encode_latency(7) | /* latency maximum = 8192 samples */ | ||
2526 | HDSPM_InputCoaxial | /* Input Coax not Optical */ | ||
2527 | HDSPM_SyncRef_MADI | /* Madi is syncclock */ | ||
2528 | HDSPM_LineOut | /* Analog output in */ | ||
2529 | HDSPM_TX_64ch | /* transmit in 64ch mode */ | ||
2530 | HDSPM_AutoInp; /* AutoInput chossing (takeover) */ | ||
2531 | |||
2532 | /* ! HDSPM_Frequency0|HDSPM_Frequency1 = 44.1khz */ | ||
2533 | /* ! HDSPM_DoubleSpeed HDSPM_QuadSpeed = normal speed */ | ||
2534 | /* ! HDSPM_clr_tms = do not clear bits in track marks */ | ||
2535 | |||
2536 | hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); | ||
2537 | |||
2538 | #ifdef SNDRV_BIG_ENDIAN | ||
2539 | hdspm->control2_register = HDSPM_BIGENDIAN_MODE; | ||
2540 | #else | ||
2541 | hdspm->control2_register = 0; | ||
2542 | #endif | ||
2543 | |||
2544 | hdspm_write(hdspm, HDSPM_control2Reg, hdspm->control2_register); | ||
2545 | hdspm_compute_period_size(hdspm); | ||
2546 | |||
2547 | /* silence everything */ | ||
2548 | |||
2549 | all_in_all_mixer(hdspm, 0 * UNITY_GAIN); | ||
2550 | |||
2551 | if (line_outs_monitor[hdspm->dev]) { | ||
2552 | |||
2553 | snd_printk(KERN_INFO "HDSPM: sending all playback streams to line outs.\n"); | ||
2554 | |||
2555 | for (i = 0; i < HDSPM_MIXER_CHANNELS; i++) { | ||
2556 | if (hdspm_write_pb_gain(hdspm, i, i, UNITY_GAIN)) | ||
2557 | return -EIO; | ||
2558 | } | ||
2559 | } | ||
2560 | |||
2561 | /* set a default rate so that the channel map is set up. */ | ||
2562 | hdspm->channel_map = channel_map_madi_ss; | ||
2563 | hdspm_set_rate(hdspm, 44100, 1); | ||
2564 | |||
2565 | return 0; | ||
2566 | } | ||
2567 | |||
2568 | |||
2569 | /*------------------------------------------------------------ | ||
2570 | interupt | ||
2571 | ------------------------------------------------------------*/ | ||
2572 | |||
2573 | static irqreturn_t snd_hdspm_interrupt(int irq, void *dev_id, | ||
2574 | struct pt_regs *regs) | ||
2575 | { | ||
2576 | hdspm_t *hdspm = (hdspm_t *) dev_id; | ||
2577 | unsigned int status; | ||
2578 | int audio; | ||
2579 | int midi0; | ||
2580 | int midi1; | ||
2581 | unsigned int midi0status; | ||
2582 | unsigned int midi1status; | ||
2583 | int schedule = 0; | ||
2584 | |||
2585 | status = hdspm_read(hdspm, HDSPM_statusRegister); | ||
2586 | |||
2587 | audio = status & HDSPM_audioIRQPending; | ||
2588 | midi0 = status & HDSPM_midi0IRQPending; | ||
2589 | midi1 = status & HDSPM_midi1IRQPending; | ||
2590 | |||
2591 | if (!audio && !midi0 && !midi1) | ||
2592 | return IRQ_NONE; | ||
2593 | |||
2594 | hdspm_write(hdspm, HDSPM_interruptConfirmation, 0); | ||
2595 | hdspm->irq_count++; | ||
2596 | |||
2597 | midi0status = hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xff; | ||
2598 | midi1status = hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xff; | ||
2599 | |||
2600 | if (audio) { | ||
2601 | |||
2602 | if (hdspm->capture_substream) | ||
2603 | snd_pcm_period_elapsed(hdspm->pcm-> | ||
2604 | streams | ||
2605 | [SNDRV_PCM_STREAM_CAPTURE]. | ||
2606 | substream); | ||
2607 | |||
2608 | if (hdspm->playback_substream) | ||
2609 | snd_pcm_period_elapsed(hdspm->pcm-> | ||
2610 | streams | ||
2611 | [SNDRV_PCM_STREAM_PLAYBACK]. | ||
2612 | substream); | ||
2613 | } | ||
2614 | |||
2615 | if (midi0 && midi0status) { | ||
2616 | /* we disable interrupts for this input until processing is done */ | ||
2617 | hdspm->control_register &= ~HDSPM_Midi0InterruptEnable; | ||
2618 | hdspm_write(hdspm, HDSPM_controlRegister, | ||
2619 | hdspm->control_register); | ||
2620 | hdspm->midi[0].pending = 1; | ||
2621 | schedule = 1; | ||
2622 | } | ||
2623 | if (midi1 && midi1status) { | ||
2624 | /* we disable interrupts for this input until processing is done */ | ||
2625 | hdspm->control_register &= ~HDSPM_Midi1InterruptEnable; | ||
2626 | hdspm_write(hdspm, HDSPM_controlRegister, | ||
2627 | hdspm->control_register); | ||
2628 | hdspm->midi[1].pending = 1; | ||
2629 | schedule = 1; | ||
2630 | } | ||
2631 | if (schedule) | ||
2632 | tasklet_hi_schedule(&hdspm->midi_tasklet); | ||
2633 | return IRQ_HANDLED; | ||
2634 | } | ||
2635 | |||
2636 | /*------------------------------------------------------------ | ||
2637 | pcm interface | ||
2638 | ------------------------------------------------------------*/ | ||
2639 | |||
2640 | |||
2641 | static snd_pcm_uframes_t snd_hdspm_hw_pointer(snd_pcm_substream_t * | ||
2642 | substream) | ||
2643 | { | ||
2644 | hdspm_t *hdspm = snd_pcm_substream_chip(substream); | ||
2645 | return hdspm_hw_pointer(hdspm); | ||
2646 | } | ||
2647 | |||
2648 | static char *hdspm_channel_buffer_location(hdspm_t * hdspm, | ||
2649 | int stream, int channel) | ||
2650 | { | ||
2651 | int mapped_channel; | ||
2652 | |||
2653 | snd_assert(channel >= 0 | ||
2654 | || channel < HDSPM_MAX_CHANNELS, return NULL); | ||
2655 | |||
2656 | if ((mapped_channel = hdspm->channel_map[channel]) < 0) | ||
2657 | return NULL; | ||
2658 | |||
2659 | if (stream == SNDRV_PCM_STREAM_CAPTURE) { | ||
2660 | return hdspm->capture_buffer + | ||
2661 | mapped_channel * HDSPM_CHANNEL_BUFFER_BYTES; | ||
2662 | } else { | ||
2663 | return hdspm->playback_buffer + | ||
2664 | mapped_channel * HDSPM_CHANNEL_BUFFER_BYTES; | ||
2665 | } | ||
2666 | } | ||
2667 | |||
2668 | |||
2669 | /* dont know why need it ??? */ | ||
2670 | static int snd_hdspm_playback_copy(snd_pcm_substream_t * substream, | ||
2671 | int channel, snd_pcm_uframes_t pos, | ||
2672 | void __user *src, snd_pcm_uframes_t count) | ||
2673 | { | ||
2674 | hdspm_t *hdspm = snd_pcm_substream_chip(substream); | ||
2675 | char *channel_buf; | ||
2676 | |||
2677 | snd_assert(pos + count <= HDSPM_CHANNEL_BUFFER_BYTES / 4, | ||
2678 | return -EINVAL); | ||
2679 | |||
2680 | channel_buf = hdspm_channel_buffer_location(hdspm, | ||
2681 | substream->pstr-> | ||
2682 | stream, channel); | ||
2683 | |||
2684 | snd_assert(channel_buf != NULL, return -EIO); | ||
2685 | |||
2686 | return copy_from_user(channel_buf + pos * 4, src, count * 4); | ||
2687 | } | ||
2688 | |||
2689 | static int snd_hdspm_capture_copy(snd_pcm_substream_t * substream, | ||
2690 | int channel, snd_pcm_uframes_t pos, | ||
2691 | void __user *dst, snd_pcm_uframes_t count) | ||
2692 | { | ||
2693 | hdspm_t *hdspm = snd_pcm_substream_chip(substream); | ||
2694 | char *channel_buf; | ||
2695 | |||
2696 | snd_assert(pos + count <= HDSPM_CHANNEL_BUFFER_BYTES / 4, | ||
2697 | return -EINVAL); | ||
2698 | |||
2699 | channel_buf = hdspm_channel_buffer_location(hdspm, | ||
2700 | substream->pstr-> | ||
2701 | stream, channel); | ||
2702 | snd_assert(channel_buf != NULL, return -EIO); | ||
2703 | return copy_to_user(dst, channel_buf + pos * 4, count * 4); | ||
2704 | } | ||
2705 | |||
2706 | static int snd_hdspm_hw_silence(snd_pcm_substream_t * substream, | ||
2707 | int channel, snd_pcm_uframes_t pos, | ||
2708 | snd_pcm_uframes_t count) | ||
2709 | { | ||
2710 | hdspm_t *hdspm = snd_pcm_substream_chip(substream); | ||
2711 | char *channel_buf; | ||
2712 | |||
2713 | channel_buf = | ||
2714 | hdspm_channel_buffer_location(hdspm, substream->pstr->stream, | ||
2715 | channel); | ||
2716 | snd_assert(channel_buf != NULL, return -EIO); | ||
2717 | memset(channel_buf + pos * 4, 0, count * 4); | ||
2718 | return 0; | ||
2719 | } | ||
2720 | |||
2721 | static int snd_hdspm_reset(snd_pcm_substream_t * substream) | ||
2722 | { | ||
2723 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
2724 | hdspm_t *hdspm = snd_pcm_substream_chip(substream); | ||
2725 | snd_pcm_substream_t *other; | ||
2726 | |||
2727 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
2728 | other = hdspm->capture_substream; | ||
2729 | else | ||
2730 | other = hdspm->playback_substream; | ||
2731 | |||
2732 | if (hdspm->running) | ||
2733 | runtime->status->hw_ptr = hdspm_hw_pointer(hdspm); | ||
2734 | else | ||
2735 | runtime->status->hw_ptr = 0; | ||
2736 | if (other) { | ||
2737 | struct list_head *pos; | ||
2738 | snd_pcm_substream_t *s; | ||
2739 | snd_pcm_runtime_t *oruntime = other->runtime; | ||
2740 | snd_pcm_group_for_each(pos, substream) { | ||
2741 | s = snd_pcm_group_substream_entry(pos); | ||
2742 | if (s == other) { | ||
2743 | oruntime->status->hw_ptr = | ||
2744 | runtime->status->hw_ptr; | ||
2745 | break; | ||
2746 | } | ||
2747 | } | ||
2748 | } | ||
2749 | return 0; | ||
2750 | } | ||
2751 | |||
2752 | static int snd_hdspm_hw_params(snd_pcm_substream_t * substream, | ||
2753 | snd_pcm_hw_params_t * params) | ||
2754 | { | ||
2755 | hdspm_t *hdspm = snd_pcm_substream_chip(substream); | ||
2756 | int err; | ||
2757 | int i; | ||
2758 | pid_t this_pid; | ||
2759 | pid_t other_pid; | ||
2760 | struct snd_sg_buf *sgbuf; | ||
2761 | |||
2762 | |||
2763 | spin_lock_irq(&hdspm->lock); | ||
2764 | |||
2765 | if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
2766 | this_pid = hdspm->playback_pid; | ||
2767 | other_pid = hdspm->capture_pid; | ||
2768 | } else { | ||
2769 | this_pid = hdspm->capture_pid; | ||
2770 | other_pid = hdspm->playback_pid; | ||
2771 | } | ||
2772 | |||
2773 | if ((other_pid > 0) && (this_pid != other_pid)) { | ||
2774 | |||
2775 | /* The other stream is open, and not by the same | ||
2776 | task as this one. Make sure that the parameters | ||
2777 | that matter are the same. | ||
2778 | */ | ||
2779 | |||
2780 | if (params_rate(params) != hdspm->system_sample_rate) { | ||
2781 | spin_unlock_irq(&hdspm->lock); | ||
2782 | _snd_pcm_hw_param_setempty(params, | ||
2783 | SNDRV_PCM_HW_PARAM_RATE); | ||
2784 | return -EBUSY; | ||
2785 | } | ||
2786 | |||
2787 | if (params_period_size(params) != hdspm->period_bytes / 4) { | ||
2788 | spin_unlock_irq(&hdspm->lock); | ||
2789 | _snd_pcm_hw_param_setempty(params, | ||
2790 | SNDRV_PCM_HW_PARAM_PERIOD_SIZE); | ||
2791 | return -EBUSY; | ||
2792 | } | ||
2793 | |||
2794 | } | ||
2795 | /* We're fine. */ | ||
2796 | spin_unlock_irq(&hdspm->lock); | ||
2797 | |||
2798 | /* how to make sure that the rate matches an externally-set one ? */ | ||
2799 | |||
2800 | spin_lock_irq(&hdspm->lock); | ||
2801 | if ((err = hdspm_set_rate(hdspm, params_rate(params), 0)) < 0) { | ||
2802 | spin_unlock_irq(&hdspm->lock); | ||
2803 | _snd_pcm_hw_param_setempty(params, | ||
2804 | SNDRV_PCM_HW_PARAM_RATE); | ||
2805 | return err; | ||
2806 | } | ||
2807 | spin_unlock_irq(&hdspm->lock); | ||
2808 | |||
2809 | if ((err = | ||
2810 | hdspm_set_interrupt_interval(hdspm, | ||
2811 | params_period_size(params))) < | ||
2812 | 0) { | ||
2813 | _snd_pcm_hw_param_setempty(params, | ||
2814 | SNDRV_PCM_HW_PARAM_PERIOD_SIZE); | ||
2815 | return err; | ||
2816 | } | ||
2817 | |||
2818 | /* Memory allocation, takashi's method, dont know if we should spinlock */ | ||
2819 | /* malloc all buffer even if not enabled to get sure */ | ||
2820 | /* malloc only needed bytes */ | ||
2821 | err = | ||
2822 | snd_pcm_lib_malloc_pages(substream, | ||
2823 | HDSPM_CHANNEL_BUFFER_BYTES * | ||
2824 | params_channels(params)); | ||
2825 | if (err < 0) | ||
2826 | return err; | ||
2827 | |||
2828 | sgbuf = snd_pcm_substream_sgbuf(substream); | ||
2829 | |||
2830 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
2831 | |||
2832 | hdspm_set_sgbuf(hdspm, sgbuf, HDSPM_pageAddressBufferOut, | ||
2833 | params_channels(params)); | ||
2834 | |||
2835 | for (i = 0; i < params_channels(params); ++i) | ||
2836 | snd_hdspm_enable_out(hdspm, i, 1); | ||
2837 | |||
2838 | hdspm->playback_buffer = | ||
2839 | (unsigned char *) substream->runtime->dma_area; | ||
2840 | } else { | ||
2841 | hdspm_set_sgbuf(hdspm, sgbuf, HDSPM_pageAddressBufferIn, | ||
2842 | params_channels(params)); | ||
2843 | |||
2844 | for (i = 0; i < params_channels(params); ++i) | ||
2845 | snd_hdspm_enable_in(hdspm, i, 1); | ||
2846 | |||
2847 | hdspm->capture_buffer = | ||
2848 | (unsigned char *) substream->runtime->dma_area; | ||
2849 | } | ||
2850 | return 0; | ||
2851 | } | ||
2852 | |||
2853 | static int snd_hdspm_hw_free(snd_pcm_substream_t * substream) | ||
2854 | { | ||
2855 | int i; | ||
2856 | hdspm_t *hdspm = snd_pcm_substream_chip(substream); | ||
2857 | |||
2858 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
2859 | |||
2860 | /* params_channels(params) should be enough, | ||
2861 | but to get sure in case of error */ | ||
2862 | for (i = 0; i < HDSPM_MAX_CHANNELS; ++i) | ||
2863 | snd_hdspm_enable_out(hdspm, i, 0); | ||
2864 | |||
2865 | hdspm->playback_buffer = NULL; | ||
2866 | } else { | ||
2867 | for (i = 0; i < HDSPM_MAX_CHANNELS; ++i) | ||
2868 | snd_hdspm_enable_in(hdspm, i, 0); | ||
2869 | |||
2870 | hdspm->capture_buffer = NULL; | ||
2871 | |||
2872 | } | ||
2873 | |||
2874 | snd_pcm_lib_free_pages(substream); | ||
2875 | |||
2876 | return 0; | ||
2877 | } | ||
2878 | |||
2879 | static int snd_hdspm_channel_info(snd_pcm_substream_t * substream, | ||
2880 | snd_pcm_channel_info_t * info) | ||
2881 | { | ||
2882 | hdspm_t *hdspm = snd_pcm_substream_chip(substream); | ||
2883 | int mapped_channel; | ||
2884 | |||
2885 | snd_assert(info->channel < HDSPM_MAX_CHANNELS, return -EINVAL); | ||
2886 | |||
2887 | if ((mapped_channel = hdspm->channel_map[info->channel]) < 0) | ||
2888 | return -EINVAL; | ||
2889 | |||
2890 | info->offset = mapped_channel * HDSPM_CHANNEL_BUFFER_BYTES; | ||
2891 | info->first = 0; | ||
2892 | info->step = 32; | ||
2893 | return 0; | ||
2894 | } | ||
2895 | |||
2896 | static int snd_hdspm_ioctl(snd_pcm_substream_t * substream, | ||
2897 | unsigned int cmd, void *arg) | ||
2898 | { | ||
2899 | switch (cmd) { | ||
2900 | case SNDRV_PCM_IOCTL1_RESET: | ||
2901 | { | ||
2902 | return snd_hdspm_reset(substream); | ||
2903 | } | ||
2904 | |||
2905 | case SNDRV_PCM_IOCTL1_CHANNEL_INFO: | ||
2906 | { | ||
2907 | snd_pcm_channel_info_t *info = arg; | ||
2908 | return snd_hdspm_channel_info(substream, info); | ||
2909 | } | ||
2910 | default: | ||
2911 | break; | ||
2912 | } | ||
2913 | |||
2914 | return snd_pcm_lib_ioctl(substream, cmd, arg); | ||
2915 | } | ||
2916 | |||
2917 | static int snd_hdspm_trigger(snd_pcm_substream_t * substream, int cmd) | ||
2918 | { | ||
2919 | hdspm_t *hdspm = snd_pcm_substream_chip(substream); | ||
2920 | snd_pcm_substream_t *other; | ||
2921 | int running; | ||
2922 | |||
2923 | spin_lock(&hdspm->lock); | ||
2924 | running = hdspm->running; | ||
2925 | switch (cmd) { | ||
2926 | case SNDRV_PCM_TRIGGER_START: | ||
2927 | running |= 1 << substream->stream; | ||
2928 | break; | ||
2929 | case SNDRV_PCM_TRIGGER_STOP: | ||
2930 | running &= ~(1 << substream->stream); | ||
2931 | break; | ||
2932 | default: | ||
2933 | snd_BUG(); | ||
2934 | spin_unlock(&hdspm->lock); | ||
2935 | return -EINVAL; | ||
2936 | } | ||
2937 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
2938 | other = hdspm->capture_substream; | ||
2939 | else | ||
2940 | other = hdspm->playback_substream; | ||
2941 | |||
2942 | if (other) { | ||
2943 | struct list_head *pos; | ||
2944 | snd_pcm_substream_t *s; | ||
2945 | snd_pcm_group_for_each(pos, substream) { | ||
2946 | s = snd_pcm_group_substream_entry(pos); | ||
2947 | if (s == other) { | ||
2948 | snd_pcm_trigger_done(s, substream); | ||
2949 | if (cmd == SNDRV_PCM_TRIGGER_START) | ||
2950 | running |= 1 << s->stream; | ||
2951 | else | ||
2952 | running &= ~(1 << s->stream); | ||
2953 | goto _ok; | ||
2954 | } | ||
2955 | } | ||
2956 | if (cmd == SNDRV_PCM_TRIGGER_START) { | ||
2957 | if (!(running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) | ||
2958 | && substream->stream == | ||
2959 | SNDRV_PCM_STREAM_CAPTURE) | ||
2960 | hdspm_silence_playback(hdspm); | ||
2961 | } else { | ||
2962 | if (running && | ||
2963 | substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
2964 | hdspm_silence_playback(hdspm); | ||
2965 | } | ||
2966 | } else { | ||
2967 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) | ||
2968 | hdspm_silence_playback(hdspm); | ||
2969 | } | ||
2970 | _ok: | ||
2971 | snd_pcm_trigger_done(substream, substream); | ||
2972 | if (!hdspm->running && running) | ||
2973 | hdspm_start_audio(hdspm); | ||
2974 | else if (hdspm->running && !running) | ||
2975 | hdspm_stop_audio(hdspm); | ||
2976 | hdspm->running = running; | ||
2977 | spin_unlock(&hdspm->lock); | ||
2978 | |||
2979 | return 0; | ||
2980 | } | ||
2981 | |||
2982 | static int snd_hdspm_prepare(snd_pcm_substream_t * substream) | ||
2983 | { | ||
2984 | return 0; | ||
2985 | } | ||
2986 | |||
2987 | static unsigned int period_sizes[] = | ||
2988 | { 64, 128, 256, 512, 1024, 2048, 4096, 8192 }; | ||
2989 | |||
2990 | static snd_pcm_hardware_t snd_hdspm_playback_subinfo = { | ||
2991 | .info = (SNDRV_PCM_INFO_MMAP | | ||
2992 | SNDRV_PCM_INFO_MMAP_VALID | | ||
2993 | SNDRV_PCM_INFO_NONINTERLEAVED | | ||
2994 | SNDRV_PCM_INFO_SYNC_START | SNDRV_PCM_INFO_DOUBLE), | ||
2995 | .formats = SNDRV_PCM_FMTBIT_S32_LE, | ||
2996 | .rates = (SNDRV_PCM_RATE_32000 | | ||
2997 | SNDRV_PCM_RATE_44100 | | ||
2998 | SNDRV_PCM_RATE_48000 | | ||
2999 | SNDRV_PCM_RATE_64000 | | ||
3000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000), | ||
3001 | .rate_min = 32000, | ||
3002 | .rate_max = 96000, | ||
3003 | .channels_min = 1, | ||
3004 | .channels_max = HDSPM_MAX_CHANNELS, | ||
3005 | .buffer_bytes_max = | ||
3006 | HDSPM_CHANNEL_BUFFER_BYTES * HDSPM_MAX_CHANNELS, | ||
3007 | .period_bytes_min = (64 * 4), | ||
3008 | .period_bytes_max = (8192 * 4) * HDSPM_MAX_CHANNELS, | ||
3009 | .periods_min = 2, | ||
3010 | .periods_max = 2, | ||
3011 | .fifo_size = 0 | ||
3012 | }; | ||
3013 | |||
3014 | static snd_pcm_hardware_t snd_hdspm_capture_subinfo = { | ||
3015 | .info = (SNDRV_PCM_INFO_MMAP | | ||
3016 | SNDRV_PCM_INFO_MMAP_VALID | | ||
3017 | SNDRV_PCM_INFO_NONINTERLEAVED | | ||
3018 | SNDRV_PCM_INFO_SYNC_START), | ||
3019 | .formats = SNDRV_PCM_FMTBIT_S32_LE, | ||
3020 | .rates = (SNDRV_PCM_RATE_32000 | | ||
3021 | SNDRV_PCM_RATE_44100 | | ||
3022 | SNDRV_PCM_RATE_48000 | | ||
3023 | SNDRV_PCM_RATE_64000 | | ||
3024 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000), | ||
3025 | .rate_min = 32000, | ||
3026 | .rate_max = 96000, | ||
3027 | .channels_min = 1, | ||
3028 | .channels_max = HDSPM_MAX_CHANNELS, | ||
3029 | .buffer_bytes_max = | ||
3030 | HDSPM_CHANNEL_BUFFER_BYTES * HDSPM_MAX_CHANNELS, | ||
3031 | .period_bytes_min = (64 * 4), | ||
3032 | .period_bytes_max = (8192 * 4) * HDSPM_MAX_CHANNELS, | ||
3033 | .periods_min = 2, | ||
3034 | .periods_max = 2, | ||
3035 | .fifo_size = 0 | ||
3036 | }; | ||
3037 | |||
3038 | static snd_pcm_hw_constraint_list_t hw_constraints_period_sizes = { | ||
3039 | .count = ARRAY_SIZE(period_sizes), | ||
3040 | .list = period_sizes, | ||
3041 | .mask = 0 | ||
3042 | }; | ||
3043 | |||
3044 | |||
3045 | static int snd_hdspm_hw_rule_channels_rate(snd_pcm_hw_params_t * params, | ||
3046 | snd_pcm_hw_rule_t * rule) | ||
3047 | { | ||
3048 | hdspm_t *hdspm = rule->private; | ||
3049 | snd_interval_t *c = | ||
3050 | hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); | ||
3051 | snd_interval_t *r = | ||
3052 | hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); | ||
3053 | |||
3054 | if (r->min > 48000) { | ||
3055 | snd_interval_t t = { | ||
3056 | .min = 1, | ||
3057 | .max = hdspm->ds_channels, | ||
3058 | .integer = 1, | ||
3059 | }; | ||
3060 | return snd_interval_refine(c, &t); | ||
3061 | } else if (r->max < 64000) { | ||
3062 | snd_interval_t t = { | ||
3063 | .min = 1, | ||
3064 | .max = hdspm->ss_channels, | ||
3065 | .integer = 1, | ||
3066 | }; | ||
3067 | return snd_interval_refine(c, &t); | ||
3068 | } | ||
3069 | return 0; | ||
3070 | } | ||
3071 | |||
3072 | static int snd_hdspm_hw_rule_rate_channels(snd_pcm_hw_params_t * params, | ||
3073 | snd_pcm_hw_rule_t * rule) | ||
3074 | { | ||
3075 | hdspm_t *hdspm = rule->private; | ||
3076 | snd_interval_t *c = | ||
3077 | hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); | ||
3078 | snd_interval_t *r = | ||
3079 | hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); | ||
3080 | |||
3081 | if (c->min <= hdspm->ss_channels) { | ||
3082 | snd_interval_t t = { | ||
3083 | .min = 32000, | ||
3084 | .max = 48000, | ||
3085 | .integer = 1, | ||
3086 | }; | ||
3087 | return snd_interval_refine(r, &t); | ||
3088 | } else if (c->max > hdspm->ss_channels) { | ||
3089 | snd_interval_t t = { | ||
3090 | .min = 64000, | ||
3091 | .max = 96000, | ||
3092 | .integer = 1, | ||
3093 | }; | ||
3094 | |||
3095 | return snd_interval_refine(r, &t); | ||
3096 | } | ||
3097 | return 0; | ||
3098 | } | ||
3099 | |||
3100 | static int snd_hdspm_playback_open(snd_pcm_substream_t * substream) | ||
3101 | { | ||
3102 | hdspm_t *hdspm = snd_pcm_substream_chip(substream); | ||
3103 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
3104 | |||
3105 | snd_printdd("Open device substream %d\n", substream->stream); | ||
3106 | |||
3107 | spin_lock_irq(&hdspm->lock); | ||
3108 | |||
3109 | snd_pcm_set_sync(substream); | ||
3110 | |||
3111 | runtime->hw = snd_hdspm_playback_subinfo; | ||
3112 | |||
3113 | if (hdspm->capture_substream == NULL) | ||
3114 | hdspm_stop_audio(hdspm); | ||
3115 | |||
3116 | hdspm->playback_pid = current->pid; | ||
3117 | hdspm->playback_substream = substream; | ||
3118 | |||
3119 | spin_unlock_irq(&hdspm->lock); | ||
3120 | |||
3121 | snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); | ||
3122 | |||
3123 | snd_pcm_hw_constraint_list(runtime, 0, | ||
3124 | SNDRV_PCM_HW_PARAM_PERIOD_SIZE, | ||
3125 | &hw_constraints_period_sizes); | ||
3126 | |||
3127 | snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, | ||
3128 | snd_hdspm_hw_rule_channels_rate, hdspm, | ||
3129 | SNDRV_PCM_HW_PARAM_RATE, -1); | ||
3130 | |||
3131 | snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, | ||
3132 | snd_hdspm_hw_rule_rate_channels, hdspm, | ||
3133 | SNDRV_PCM_HW_PARAM_CHANNELS, -1); | ||
3134 | |||
3135 | return 0; | ||
3136 | } | ||
3137 | |||
3138 | static int snd_hdspm_playback_release(snd_pcm_substream_t * substream) | ||
3139 | { | ||
3140 | hdspm_t *hdspm = snd_pcm_substream_chip(substream); | ||
3141 | |||
3142 | spin_lock_irq(&hdspm->lock); | ||
3143 | |||
3144 | hdspm->playback_pid = -1; | ||
3145 | hdspm->playback_substream = NULL; | ||
3146 | |||
3147 | spin_unlock_irq(&hdspm->lock); | ||
3148 | |||
3149 | return 0; | ||
3150 | } | ||
3151 | |||
3152 | |||
3153 | static int snd_hdspm_capture_open(snd_pcm_substream_t * substream) | ||
3154 | { | ||
3155 | hdspm_t *hdspm = snd_pcm_substream_chip(substream); | ||
3156 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
3157 | |||
3158 | spin_lock_irq(&hdspm->lock); | ||
3159 | snd_pcm_set_sync(substream); | ||
3160 | runtime->hw = snd_hdspm_capture_subinfo; | ||
3161 | |||
3162 | if (hdspm->playback_substream == NULL) | ||
3163 | hdspm_stop_audio(hdspm); | ||
3164 | |||
3165 | hdspm->capture_pid = current->pid; | ||
3166 | hdspm->capture_substream = substream; | ||
3167 | |||
3168 | spin_unlock_irq(&hdspm->lock); | ||
3169 | |||
3170 | snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); | ||
3171 | snd_pcm_hw_constraint_list(runtime, 0, | ||
3172 | SNDRV_PCM_HW_PARAM_PERIOD_SIZE, | ||
3173 | &hw_constraints_period_sizes); | ||
3174 | |||
3175 | snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, | ||
3176 | snd_hdspm_hw_rule_channels_rate, hdspm, | ||
3177 | SNDRV_PCM_HW_PARAM_RATE, -1); | ||
3178 | |||
3179 | snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, | ||
3180 | snd_hdspm_hw_rule_rate_channels, hdspm, | ||
3181 | SNDRV_PCM_HW_PARAM_CHANNELS, -1); | ||
3182 | return 0; | ||
3183 | } | ||
3184 | |||
3185 | static int snd_hdspm_capture_release(snd_pcm_substream_t * substream) | ||
3186 | { | ||
3187 | hdspm_t *hdspm = snd_pcm_substream_chip(substream); | ||
3188 | |||
3189 | spin_lock_irq(&hdspm->lock); | ||
3190 | |||
3191 | hdspm->capture_pid = -1; | ||
3192 | hdspm->capture_substream = NULL; | ||
3193 | |||
3194 | spin_unlock_irq(&hdspm->lock); | ||
3195 | return 0; | ||
3196 | } | ||
3197 | |||
3198 | static int snd_hdspm_hwdep_dummy_op(snd_hwdep_t * hw, struct file *file) | ||
3199 | { | ||
3200 | /* we have nothing to initialize but the call is required */ | ||
3201 | return 0; | ||
3202 | } | ||
3203 | |||
3204 | |||
3205 | static int snd_hdspm_hwdep_ioctl(snd_hwdep_t * hw, struct file *file, | ||
3206 | unsigned int cmd, unsigned long arg) | ||
3207 | { | ||
3208 | hdspm_t *hdspm = (hdspm_t *) hw->private_data; | ||
3209 | struct sndrv_hdspm_mixer_ioctl mixer; | ||
3210 | hdspm_config_info_t info; | ||
3211 | hdspm_version_t hdspm_version; | ||
3212 | struct sndrv_hdspm_peak_rms_ioctl rms; | ||
3213 | |||
3214 | switch (cmd) { | ||
3215 | |||
3216 | |||
3217 | case SNDRV_HDSPM_IOCTL_GET_PEAK_RMS: | ||
3218 | if (copy_from_user(&rms, (void __user *)arg, sizeof(rms))) | ||
3219 | return -EFAULT; | ||
3220 | /* maybe there is a chance to memorymap in future so dont touch just copy */ | ||
3221 | if(copy_to_user_fromio((void __user *)rms.peak, | ||
3222 | hdspm->iobase+HDSPM_MADI_peakrmsbase, | ||
3223 | sizeof(hdspm_peak_rms_t)) != 0 ) | ||
3224 | return -EFAULT; | ||
3225 | |||
3226 | break; | ||
3227 | |||
3228 | |||
3229 | case SNDRV_HDSPM_IOCTL_GET_CONFIG_INFO: | ||
3230 | |||
3231 | spin_lock_irq(&hdspm->lock); | ||
3232 | info.pref_sync_ref = | ||
3233 | (unsigned char) hdspm_pref_sync_ref(hdspm); | ||
3234 | info.wordclock_sync_check = | ||
3235 | (unsigned char) hdspm_wc_sync_check(hdspm); | ||
3236 | |||
3237 | info.system_sample_rate = hdspm->system_sample_rate; | ||
3238 | info.autosync_sample_rate = | ||
3239 | hdspm_external_sample_rate(hdspm); | ||
3240 | info.system_clock_mode = | ||
3241 | (unsigned char) hdspm_system_clock_mode(hdspm); | ||
3242 | info.clock_source = | ||
3243 | (unsigned char) hdspm_clock_source(hdspm); | ||
3244 | info.autosync_ref = | ||
3245 | (unsigned char) hdspm_autosync_ref(hdspm); | ||
3246 | info.line_out = (unsigned char) hdspm_line_out(hdspm); | ||
3247 | info.passthru = 0; | ||
3248 | spin_unlock_irq(&hdspm->lock); | ||
3249 | if (copy_to_user((void __user *) arg, &info, sizeof(info))) | ||
3250 | return -EFAULT; | ||
3251 | break; | ||
3252 | |||
3253 | case SNDRV_HDSPM_IOCTL_GET_VERSION: | ||
3254 | hdspm_version.firmware_rev = hdspm->firmware_rev; | ||
3255 | if (copy_to_user((void __user *) arg, &hdspm_version, | ||
3256 | sizeof(hdspm_version))) | ||
3257 | return -EFAULT; | ||
3258 | break; | ||
3259 | |||
3260 | case SNDRV_HDSPM_IOCTL_GET_MIXER: | ||
3261 | if (copy_from_user(&mixer, (void __user *)arg, sizeof(mixer))) | ||
3262 | return -EFAULT; | ||
3263 | if (copy_to_user | ||
3264 | ((void __user *)mixer.mixer, hdspm->mixer, sizeof(hdspm_mixer_t))) | ||
3265 | return -EFAULT; | ||
3266 | break; | ||
3267 | |||
3268 | default: | ||
3269 | return -EINVAL; | ||
3270 | } | ||
3271 | return 0; | ||
3272 | } | ||
3273 | |||
3274 | static snd_pcm_ops_t snd_hdspm_playback_ops = { | ||
3275 | .open = snd_hdspm_playback_open, | ||
3276 | .close = snd_hdspm_playback_release, | ||
3277 | .ioctl = snd_hdspm_ioctl, | ||
3278 | .hw_params = snd_hdspm_hw_params, | ||
3279 | .hw_free = snd_hdspm_hw_free, | ||
3280 | .prepare = snd_hdspm_prepare, | ||
3281 | .trigger = snd_hdspm_trigger, | ||
3282 | .pointer = snd_hdspm_hw_pointer, | ||
3283 | .copy = snd_hdspm_playback_copy, | ||
3284 | .silence = snd_hdspm_hw_silence, | ||
3285 | .page = snd_pcm_sgbuf_ops_page, | ||
3286 | }; | ||
3287 | |||
3288 | static snd_pcm_ops_t snd_hdspm_capture_ops = { | ||
3289 | .open = snd_hdspm_capture_open, | ||
3290 | .close = snd_hdspm_capture_release, | ||
3291 | .ioctl = snd_hdspm_ioctl, | ||
3292 | .hw_params = snd_hdspm_hw_params, | ||
3293 | .hw_free = snd_hdspm_hw_free, | ||
3294 | .prepare = snd_hdspm_prepare, | ||
3295 | .trigger = snd_hdspm_trigger, | ||
3296 | .pointer = snd_hdspm_hw_pointer, | ||
3297 | .copy = snd_hdspm_capture_copy, | ||
3298 | .page = snd_pcm_sgbuf_ops_page, | ||
3299 | }; | ||
3300 | |||
3301 | static int __devinit snd_hdspm_create_hwdep(snd_card_t * card, | ||
3302 | hdspm_t * hdspm) | ||
3303 | { | ||
3304 | snd_hwdep_t *hw; | ||
3305 | int err; | ||
3306 | |||
3307 | if ((err = snd_hwdep_new(card, "HDSPM hwdep", 0, &hw)) < 0) | ||
3308 | return err; | ||
3309 | |||
3310 | hdspm->hwdep = hw; | ||
3311 | hw->private_data = hdspm; | ||
3312 | strcpy(hw->name, "HDSPM hwdep interface"); | ||
3313 | |||
3314 | hw->ops.open = snd_hdspm_hwdep_dummy_op; | ||
3315 | hw->ops.ioctl = snd_hdspm_hwdep_ioctl; | ||
3316 | hw->ops.release = snd_hdspm_hwdep_dummy_op; | ||
3317 | |||
3318 | return 0; | ||
3319 | } | ||
3320 | |||
3321 | |||
3322 | /*------------------------------------------------------------ | ||
3323 | memory interface | ||
3324 | ------------------------------------------------------------*/ | ||
3325 | static int __devinit snd_hdspm_preallocate_memory(hdspm_t * hdspm) | ||
3326 | { | ||
3327 | int err; | ||
3328 | snd_pcm_t *pcm; | ||
3329 | size_t wanted; | ||
3330 | |||
3331 | pcm = hdspm->pcm; | ||
3332 | |||
3333 | wanted = HDSPM_DMA_AREA_BYTES + 4096; /* dont know why, but it works */ | ||
3334 | |||
3335 | if ((err = | ||
3336 | snd_pcm_lib_preallocate_pages_for_all(pcm, | ||
3337 | SNDRV_DMA_TYPE_DEV_SG, | ||
3338 | snd_dma_pci_data(hdspm->pci), | ||
3339 | wanted, | ||
3340 | wanted)) < 0) { | ||
3341 | snd_printdd("Could not preallocate %d Bytes\n", wanted); | ||
3342 | |||
3343 | return err; | ||
3344 | } else | ||
3345 | snd_printdd(" Preallocated %d Bytes\n", wanted); | ||
3346 | |||
3347 | return 0; | ||
3348 | } | ||
3349 | |||
3350 | static int snd_hdspm_memory_free(hdspm_t * hdspm) | ||
3351 | { | ||
3352 | snd_printdd("memory_free_for_all %p\n", hdspm->pcm); | ||
3353 | |||
3354 | snd_pcm_lib_preallocate_free_for_all(hdspm->pcm); | ||
3355 | return 0; | ||
3356 | } | ||
3357 | |||
3358 | |||
3359 | static void hdspm_set_sgbuf(hdspm_t * hdspm, struct snd_sg_buf *sgbuf, | ||
3360 | unsigned int reg, int channels) | ||
3361 | { | ||
3362 | int i; | ||
3363 | for (i = 0; i < (channels * 16); i++) | ||
3364 | hdspm_write(hdspm, reg + 4 * i, | ||
3365 | snd_pcm_sgbuf_get_addr(sgbuf, | ||
3366 | (size_t) 4096 * i)); | ||
3367 | } | ||
3368 | |||
3369 | /* ------------- ALSA Devices ---------------------------- */ | ||
3370 | static int __devinit snd_hdspm_create_pcm(snd_card_t * card, | ||
3371 | hdspm_t * hdspm) | ||
3372 | { | ||
3373 | snd_pcm_t *pcm; | ||
3374 | int err; | ||
3375 | |||
3376 | if ((err = snd_pcm_new(card, hdspm->card_name, 0, 1, 1, &pcm)) < 0) | ||
3377 | return err; | ||
3378 | |||
3379 | hdspm->pcm = pcm; | ||
3380 | pcm->private_data = hdspm; | ||
3381 | strcpy(pcm->name, hdspm->card_name); | ||
3382 | |||
3383 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, | ||
3384 | &snd_hdspm_playback_ops); | ||
3385 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, | ||
3386 | &snd_hdspm_capture_ops); | ||
3387 | |||
3388 | pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX; | ||
3389 | |||
3390 | if ((err = snd_hdspm_preallocate_memory(hdspm)) < 0) | ||
3391 | return err; | ||
3392 | |||
3393 | return 0; | ||
3394 | } | ||
3395 | |||
3396 | static inline void snd_hdspm_initialize_midi_flush(hdspm_t * hdspm) | ||
3397 | { | ||
3398 | snd_hdspm_flush_midi_input(hdspm, 0); | ||
3399 | snd_hdspm_flush_midi_input(hdspm, 1); | ||
3400 | } | ||
3401 | |||
3402 | static int __devinit snd_hdspm_create_alsa_devices(snd_card_t * card, | ||
3403 | hdspm_t * hdspm) | ||
3404 | { | ||
3405 | int err; | ||
3406 | |||
3407 | snd_printdd("Create card...\n"); | ||
3408 | if ((err = snd_hdspm_create_pcm(card, hdspm)) < 0) | ||
3409 | return err; | ||
3410 | |||
3411 | if ((err = snd_hdspm_create_midi(card, hdspm, 0)) < 0) | ||
3412 | return err; | ||
3413 | |||
3414 | if ((err = snd_hdspm_create_midi(card, hdspm, 1)) < 0) | ||
3415 | return err; | ||
3416 | |||
3417 | if ((err = snd_hdspm_create_controls(card, hdspm)) < 0) | ||
3418 | return err; | ||
3419 | |||
3420 | if ((err = snd_hdspm_create_hwdep(card, hdspm)) < 0) | ||
3421 | return err; | ||
3422 | |||
3423 | snd_printdd("proc init...\n"); | ||
3424 | snd_hdspm_proc_init(hdspm); | ||
3425 | |||
3426 | hdspm->system_sample_rate = -1; | ||
3427 | hdspm->last_external_sample_rate = -1; | ||
3428 | hdspm->last_internal_sample_rate = -1; | ||
3429 | hdspm->playback_pid = -1; | ||
3430 | hdspm->capture_pid = -1; | ||
3431 | hdspm->capture_substream = NULL; | ||
3432 | hdspm->playback_substream = NULL; | ||
3433 | |||
3434 | snd_printdd("Set defaults...\n"); | ||
3435 | if ((err = snd_hdspm_set_defaults(hdspm)) < 0) | ||
3436 | return err; | ||
3437 | |||
3438 | snd_printdd("Update mixer controls...\n"); | ||
3439 | hdspm_update_simple_mixer_controls(hdspm); | ||
3440 | |||
3441 | snd_printdd("Initializeing complete ???\n"); | ||
3442 | |||
3443 | if ((err = snd_card_register(card)) < 0) { | ||
3444 | snd_printk(KERN_ERR "HDSPM: error registering card\n"); | ||
3445 | return err; | ||
3446 | } | ||
3447 | |||
3448 | snd_printdd("... yes now\n"); | ||
3449 | |||
3450 | return 0; | ||
3451 | } | ||
3452 | |||
3453 | static int __devinit snd_hdspm_create(snd_card_t * card, hdspm_t * hdspm, | ||
3454 | int precise_ptr, int enable_monitor) | ||
3455 | { | ||
3456 | struct pci_dev *pci = hdspm->pci; | ||
3457 | int err; | ||
3458 | int i; | ||
3459 | |||
3460 | unsigned long io_extent; | ||
3461 | |||
3462 | hdspm->irq = -1; | ||
3463 | hdspm->irq_count = 0; | ||
3464 | |||
3465 | hdspm->midi[0].rmidi = NULL; | ||
3466 | hdspm->midi[1].rmidi = NULL; | ||
3467 | hdspm->midi[0].input = NULL; | ||
3468 | hdspm->midi[1].input = NULL; | ||
3469 | hdspm->midi[0].output = NULL; | ||
3470 | hdspm->midi[1].output = NULL; | ||
3471 | spin_lock_init(&hdspm->midi[0].lock); | ||
3472 | spin_lock_init(&hdspm->midi[1].lock); | ||
3473 | hdspm->iobase = NULL; | ||
3474 | hdspm->control_register = 0; | ||
3475 | hdspm->control2_register = 0; | ||
3476 | |||
3477 | hdspm->playback_buffer = NULL; | ||
3478 | hdspm->capture_buffer = NULL; | ||
3479 | |||
3480 | for (i = 0; i < HDSPM_MAX_CHANNELS; ++i) | ||
3481 | hdspm->playback_mixer_ctls[i] = NULL; | ||
3482 | hdspm->mixer = NULL; | ||
3483 | |||
3484 | hdspm->card = card; | ||
3485 | |||
3486 | spin_lock_init(&hdspm->lock); | ||
3487 | |||
3488 | tasklet_init(&hdspm->midi_tasklet, | ||
3489 | hdspm_midi_tasklet, (unsigned long) hdspm); | ||
3490 | |||
3491 | pci_read_config_word(hdspm->pci, | ||
3492 | PCI_CLASS_REVISION, &hdspm->firmware_rev); | ||
3493 | |||
3494 | strcpy(card->driver, "HDSPM"); | ||
3495 | strcpy(card->mixername, "Xilinx FPGA"); | ||
3496 | hdspm->card_name = "RME HDSPM MADI"; | ||
3497 | |||
3498 | if ((err = pci_enable_device(pci)) < 0) | ||
3499 | return err; | ||
3500 | |||
3501 | pci_set_master(hdspm->pci); | ||
3502 | |||
3503 | if ((err = pci_request_regions(pci, "hdspm")) < 0) | ||
3504 | return err; | ||
3505 | |||
3506 | hdspm->port = pci_resource_start(pci, 0); | ||
3507 | io_extent = pci_resource_len(pci, 0); | ||
3508 | |||
3509 | snd_printdd("grabbed memory region 0x%lx-0x%lx\n", | ||
3510 | hdspm->port, hdspm->port + io_extent - 1); | ||
3511 | |||
3512 | |||
3513 | if ((hdspm->iobase = ioremap_nocache(hdspm->port, io_extent)) == NULL) { | ||
3514 | snd_printk(KERN_ERR "HDSPM: unable to remap region 0x%lx-0x%lx\n", | ||
3515 | hdspm->port, hdspm->port + io_extent - 1); | ||
3516 | return -EBUSY; | ||
3517 | } | ||
3518 | snd_printdd("remapped region (0x%lx) 0x%lx-0x%lx\n", | ||
3519 | (unsigned long)hdspm->iobase, hdspm->port, | ||
3520 | hdspm->port + io_extent - 1); | ||
3521 | |||
3522 | if (request_irq(pci->irq, snd_hdspm_interrupt, | ||
3523 | SA_INTERRUPT | SA_SHIRQ, "hdspm", | ||
3524 | (void *) hdspm)) { | ||
3525 | snd_printk(KERN_ERR "HDSPM: unable to use IRQ %d\n", pci->irq); | ||
3526 | return -EBUSY; | ||
3527 | } | ||
3528 | |||
3529 | snd_printdd("use IRQ %d\n", pci->irq); | ||
3530 | |||
3531 | hdspm->irq = pci->irq; | ||
3532 | hdspm->precise_ptr = precise_ptr; | ||
3533 | |||
3534 | hdspm->monitor_outs = enable_monitor; | ||
3535 | |||
3536 | snd_printdd("kmalloc Mixer memory of %d Bytes\n", | ||
3537 | sizeof(hdspm_mixer_t)); | ||
3538 | if ((hdspm->mixer = | ||
3539 | (hdspm_mixer_t *) kmalloc(sizeof(hdspm_mixer_t), GFP_KERNEL)) | ||
3540 | == NULL) { | ||
3541 | snd_printk(KERN_ERR "HDSPM: unable to kmalloc Mixer memory of %d Bytes\n", | ||
3542 | (int)sizeof(hdspm_mixer_t)); | ||
3543 | return err; | ||
3544 | } | ||
3545 | |||
3546 | hdspm->ss_channels = MADI_SS_CHANNELS; | ||
3547 | hdspm->ds_channels = MADI_DS_CHANNELS; | ||
3548 | hdspm->qs_channels = MADI_QS_CHANNELS; | ||
3549 | |||
3550 | snd_printdd("create alsa devices.\n"); | ||
3551 | if ((err = snd_hdspm_create_alsa_devices(card, hdspm)) < 0) | ||
3552 | return err; | ||
3553 | |||
3554 | snd_hdspm_initialize_midi_flush(hdspm); | ||
3555 | |||
3556 | return 0; | ||
3557 | } | ||
3558 | |||
3559 | static int snd_hdspm_free(hdspm_t * hdspm) | ||
3560 | { | ||
3561 | |||
3562 | if (hdspm->port) { | ||
3563 | |||
3564 | /* stop th audio, and cancel all interrupts */ | ||
3565 | hdspm->control_register &= | ||
3566 | ~(HDSPM_Start | HDSPM_AudioInterruptEnable | ||
3567 | | HDSPM_Midi0InterruptEnable | | ||
3568 | HDSPM_Midi1InterruptEnable); | ||
3569 | hdspm_write(hdspm, HDSPM_controlRegister, | ||
3570 | hdspm->control_register); | ||
3571 | } | ||
3572 | |||
3573 | if (hdspm->irq >= 0) | ||
3574 | free_irq(hdspm->irq, (void *) hdspm); | ||
3575 | |||
3576 | |||
3577 | if (hdspm->mixer) | ||
3578 | kfree(hdspm->mixer); | ||
3579 | |||
3580 | if (hdspm->iobase) | ||
3581 | iounmap(hdspm->iobase); | ||
3582 | |||
3583 | snd_hdspm_memory_free(hdspm); | ||
3584 | |||
3585 | if (hdspm->port) | ||
3586 | pci_release_regions(hdspm->pci); | ||
3587 | |||
3588 | pci_disable_device(hdspm->pci); | ||
3589 | return 0; | ||
3590 | } | ||
3591 | |||
3592 | static void snd_hdspm_card_free(snd_card_t * card) | ||
3593 | { | ||
3594 | hdspm_t *hdspm = (hdspm_t *) card->private_data; | ||
3595 | |||
3596 | if (hdspm) | ||
3597 | snd_hdspm_free(hdspm); | ||
3598 | } | ||
3599 | |||
3600 | static int __devinit snd_hdspm_probe(struct pci_dev *pci, | ||
3601 | const struct pci_device_id *pci_id) | ||
3602 | { | ||
3603 | static int dev; | ||
3604 | hdspm_t *hdspm; | ||
3605 | snd_card_t *card; | ||
3606 | int err; | ||
3607 | |||
3608 | if (dev >= SNDRV_CARDS) | ||
3609 | return -ENODEV; | ||
3610 | if (!enable[dev]) { | ||
3611 | dev++; | ||
3612 | return -ENOENT; | ||
3613 | } | ||
3614 | |||
3615 | if (!(card = snd_card_new(index[dev], id[dev], | ||
3616 | THIS_MODULE, sizeof(hdspm_t)))) | ||
3617 | return -ENOMEM; | ||
3618 | |||
3619 | hdspm = (hdspm_t *) card->private_data; | ||
3620 | card->private_free = snd_hdspm_card_free; | ||
3621 | hdspm->dev = dev; | ||
3622 | hdspm->pci = pci; | ||
3623 | |||
3624 | if ((err = | ||
3625 | snd_hdspm_create(card, hdspm, precise_ptr[dev], | ||
3626 | enable_monitor[dev])) < 0) { | ||
3627 | snd_card_free(card); | ||
3628 | return err; | ||
3629 | } | ||
3630 | |||
3631 | strcpy(card->shortname, "HDSPM MADI"); | ||
3632 | sprintf(card->longname, "%s at 0x%lx, irq %d", hdspm->card_name, | ||
3633 | hdspm->port, hdspm->irq); | ||
3634 | |||
3635 | if ((err = snd_card_register(card)) < 0) { | ||
3636 | snd_card_free(card); | ||
3637 | return err; | ||
3638 | } | ||
3639 | |||
3640 | pci_set_drvdata(pci, card); | ||
3641 | |||
3642 | dev++; | ||
3643 | return 0; | ||
3644 | } | ||
3645 | |||
3646 | static void __devexit snd_hdspm_remove(struct pci_dev *pci) | ||
3647 | { | ||
3648 | snd_card_free(pci_get_drvdata(pci)); | ||
3649 | pci_set_drvdata(pci, NULL); | ||
3650 | } | ||
3651 | |||
3652 | static struct pci_driver driver = { | ||
3653 | .name = "RME Hammerfall DSP MADI", | ||
3654 | .id_table = snd_hdspm_ids, | ||
3655 | .probe = snd_hdspm_probe, | ||
3656 | .remove = __devexit_p(snd_hdspm_remove), | ||
3657 | }; | ||
3658 | |||
3659 | |||
3660 | static int __init alsa_card_hdspm_init(void) | ||
3661 | { | ||
3662 | return pci_register_driver(&driver); | ||
3663 | } | ||
3664 | |||
3665 | static void __exit alsa_card_hdspm_exit(void) | ||
3666 | { | ||
3667 | pci_unregister_driver(&driver); | ||
3668 | } | ||
3669 | |||
3670 | module_init(alsa_card_hdspm_init) | ||
3671 | module_exit(alsa_card_hdspm_exit) | ||
diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c index 69cd81eaa111..f3037402d58f 100644 --- a/sound/pci/rme9652/rme9652.c +++ b/sound/pci/rme9652/rme9652.c | |||
@@ -303,18 +303,22 @@ static int snd_hammerfall_get_buffer(struct pci_dev *pci, struct snd_dma_buffer | |||
303 | { | 303 | { |
304 | dmab->dev.type = SNDRV_DMA_TYPE_DEV; | 304 | dmab->dev.type = SNDRV_DMA_TYPE_DEV; |
305 | dmab->dev.dev = snd_dma_pci_data(pci); | 305 | dmab->dev.dev = snd_dma_pci_data(pci); |
306 | if (! snd_dma_get_reserved_buf(dmab, snd_dma_pci_buf_id(pci))) { | 306 | if (snd_dma_get_reserved_buf(dmab, snd_dma_pci_buf_id(pci))) { |
307 | if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), | 307 | if (dmab->bytes >= size) |
308 | size, dmab) < 0) | 308 | return 0; |
309 | return -ENOMEM; | ||
310 | } | 309 | } |
310 | if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), | ||
311 | size, dmab) < 0) | ||
312 | return -ENOMEM; | ||
311 | return 0; | 313 | return 0; |
312 | } | 314 | } |
313 | 315 | ||
314 | static void snd_hammerfall_free_buffer(struct snd_dma_buffer *dmab, struct pci_dev *pci) | 316 | static void snd_hammerfall_free_buffer(struct snd_dma_buffer *dmab, struct pci_dev *pci) |
315 | { | 317 | { |
316 | if (dmab->area) | 318 | if (dmab->area) { |
319 | dmab->dev.dev = NULL; /* make it anonymous */ | ||
317 | snd_dma_reserve_buf(dmab, snd_dma_pci_buf_id(pci)); | 320 | snd_dma_reserve_buf(dmab, snd_dma_pci_buf_id(pci)); |
321 | } | ||
318 | } | 322 | } |
319 | 323 | ||
320 | 324 | ||
@@ -2664,7 +2668,7 @@ static struct pci_driver driver = { | |||
2664 | 2668 | ||
2665 | static int __init alsa_card_hammerfall_init(void) | 2669 | static int __init alsa_card_hammerfall_init(void) |
2666 | { | 2670 | { |
2667 | return pci_module_init(&driver); | 2671 | return pci_register_driver(&driver); |
2668 | } | 2672 | } |
2669 | 2673 | ||
2670 | static void __exit alsa_card_hammerfall_exit(void) | 2674 | static void __exit alsa_card_hammerfall_exit(void) |
diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c index cfd2c5fd6ddf..60ecb2bdb65e 100644 --- a/sound/pci/sonicvibes.c +++ b/sound/pci/sonicvibes.c | |||
@@ -1522,7 +1522,7 @@ static struct pci_driver driver = { | |||
1522 | 1522 | ||
1523 | static int __init alsa_card_sonicvibes_init(void) | 1523 | static int __init alsa_card_sonicvibes_init(void) |
1524 | { | 1524 | { |
1525 | return pci_module_init(&driver); | 1525 | return pci_register_driver(&driver); |
1526 | } | 1526 | } |
1527 | 1527 | ||
1528 | static void __exit alsa_card_sonicvibes_exit(void) | 1528 | static void __exit alsa_card_sonicvibes_exit(void) |
diff --git a/sound/pci/trident/trident.c b/sound/pci/trident/trident.c index ad58e08d66e2..940d531575c0 100644 --- a/sound/pci/trident/trident.c +++ b/sound/pci/trident/trident.c | |||
@@ -143,7 +143,8 @@ static int __devinit snd_trident_probe(struct pci_dev *pci, | |||
143 | return err; | 143 | return err; |
144 | } | 144 | } |
145 | } | 145 | } |
146 | if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_TRID4DWAVE, | 146 | if (trident->device != TRIDENT_DEVICE_ID_SI7018 && |
147 | (err = snd_mpu401_uart_new(card, 0, MPU401_HW_TRID4DWAVE, | ||
147 | trident->midi_port, 1, | 148 | trident->midi_port, 1, |
148 | trident->irq, 0, &trident->rmidi)) < 0) { | 149 | trident->irq, 0, &trident->rmidi)) < 0) { |
149 | snd_card_free(card); | 150 | snd_card_free(card); |
@@ -184,7 +185,7 @@ static struct pci_driver driver = { | |||
184 | 185 | ||
185 | static int __init alsa_card_trident_init(void) | 186 | static int __init alsa_card_trident_init(void) |
186 | { | 187 | { |
187 | return pci_module_init(&driver); | 188 | return pci_register_driver(&driver); |
188 | } | 189 | } |
189 | 190 | ||
190 | static void __exit alsa_card_trident_exit(void) | 191 | static void __exit alsa_card_trident_exit(void) |
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 9b4d74d49f98..42c48f0ce8e8 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c | |||
@@ -101,7 +101,7 @@ MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (default 48000Hz)."); | |||
101 | module_param_array(ac97_quirk, charp, NULL, 0444); | 101 | module_param_array(ac97_quirk, charp, NULL, 0444); |
102 | MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware."); | 102 | MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware."); |
103 | module_param_array(dxs_support, int, NULL, 0444); | 103 | module_param_array(dxs_support, int, NULL, 0444); |
104 | MODULE_PARM_DESC(dxs_support, "Support for DXS channels (0 = auto, 1 = enable, 2 = disable, 3 = 48k only, 4 = no VRA)"); | 104 | 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)"); |
105 | 105 | ||
106 | 106 | ||
107 | /* pci ids */ | 107 | /* pci ids */ |
@@ -302,6 +302,7 @@ DEFINE_VIA_REGSET(CAPTURE_8233, 0x60); | |||
302 | #define VIA_DXS_DISABLE 2 | 302 | #define VIA_DXS_DISABLE 2 |
303 | #define VIA_DXS_48K 3 | 303 | #define VIA_DXS_48K 3 |
304 | #define VIA_DXS_NO_VRA 4 | 304 | #define VIA_DXS_NO_VRA 4 |
305 | #define VIA_DXS_SRC 5 | ||
305 | 306 | ||
306 | 307 | ||
307 | /* | 308 | /* |
@@ -380,6 +381,7 @@ struct _snd_via82xx { | |||
380 | struct via_rate_lock rates[2]; /* playback and capture */ | 381 | struct via_rate_lock rates[2]; /* playback and capture */ |
381 | unsigned int dxs_fixed: 1; /* DXS channel accepts only 48kHz */ | 382 | unsigned int dxs_fixed: 1; /* DXS channel accepts only 48kHz */ |
382 | unsigned int no_vra: 1; /* no need to set VRA on DXS channels */ | 383 | unsigned int no_vra: 1; /* no need to set VRA on DXS channels */ |
384 | unsigned int dxs_src: 1; /* use full SRC capabilities of DXS */ | ||
383 | unsigned int spdif_on: 1; /* only spdif rates work to external DACs */ | 385 | unsigned int spdif_on: 1; /* only spdif rates work to external DACs */ |
384 | 386 | ||
385 | snd_pcm_t *pcms[2]; | 387 | snd_pcm_t *pcms[2]; |
@@ -489,10 +491,8 @@ static int clean_via_table(viadev_t *dev, snd_pcm_substream_t *substream, | |||
489 | snd_dma_free_pages(&dev->table); | 491 | snd_dma_free_pages(&dev->table); |
490 | dev->table.area = NULL; | 492 | dev->table.area = NULL; |
491 | } | 493 | } |
492 | if (dev->idx_table) { | 494 | kfree(dev->idx_table); |
493 | kfree(dev->idx_table); | 495 | dev->idx_table = NULL; |
494 | dev->idx_table = NULL; | ||
495 | } | ||
496 | return 0; | 496 | return 0; |
497 | } | 497 | } |
498 | 498 | ||
@@ -924,15 +924,17 @@ static int snd_via8233_playback_prepare(snd_pcm_substream_t *substream) | |||
924 | via82xx_t *chip = snd_pcm_substream_chip(substream); | 924 | via82xx_t *chip = snd_pcm_substream_chip(substream); |
925 | viadev_t *viadev = (viadev_t *)substream->runtime->private_data; | 925 | viadev_t *viadev = (viadev_t *)substream->runtime->private_data; |
926 | snd_pcm_runtime_t *runtime = substream->runtime; | 926 | snd_pcm_runtime_t *runtime = substream->runtime; |
927 | int ac97_rate = chip->dxs_src ? 48000 : runtime->rate; | ||
927 | int rate_changed; | 928 | int rate_changed; |
928 | u32 rbits; | 929 | u32 rbits; |
929 | 930 | ||
930 | if ((rate_changed = via_lock_rate(&chip->rates[0], runtime->rate)) < 0) | 931 | if ((rate_changed = via_lock_rate(&chip->rates[0], ac97_rate)) < 0) |
931 | return rate_changed; | 932 | return rate_changed; |
932 | if (rate_changed) { | 933 | if (rate_changed) { |
933 | snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE, | 934 | snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE, |
934 | chip->no_vra ? 48000 : runtime->rate); | 935 | chip->no_vra ? 48000 : runtime->rate); |
935 | snd_ac97_set_rate(chip->ac97, AC97_SPDIF, runtime->rate); | 936 | snd_ac97_set_rate(chip->ac97, AC97_SPDIF, |
937 | chip->no_vra ? 48000 : runtime->rate); | ||
936 | } | 938 | } |
937 | if (runtime->rate == 48000) | 939 | if (runtime->rate == 48000) |
938 | rbits = 0xfffff; | 940 | rbits = 0xfffff; |
@@ -1074,6 +1076,12 @@ static int snd_via82xx_pcm_open(via82xx_t *chip, viadev_t *viadev, snd_pcm_subst | |||
1074 | /* fixed DXS playback rate */ | 1076 | /* fixed DXS playback rate */ |
1075 | runtime->hw.rates = SNDRV_PCM_RATE_48000; | 1077 | runtime->hw.rates = SNDRV_PCM_RATE_48000; |
1076 | runtime->hw.rate_min = runtime->hw.rate_max = 48000; | 1078 | runtime->hw.rate_min = runtime->hw.rate_max = 48000; |
1079 | } else if (chip->dxs_src && viadev->reg_offset < 0x40) { | ||
1080 | /* use full SRC capabilities of DXS */ | ||
1081 | runtime->hw.rates = (SNDRV_PCM_RATE_CONTINUOUS | | ||
1082 | SNDRV_PCM_RATE_8000_48000); | ||
1083 | runtime->hw.rate_min = 8000; | ||
1084 | runtime->hw.rate_max = 48000; | ||
1077 | } else if (! ratep->rate) { | 1085 | } else if (! ratep->rate) { |
1078 | int idx = viadev->direction ? AC97_RATES_ADC : AC97_RATES_FRONT_DAC; | 1086 | int idx = viadev->direction ? AC97_RATES_ADC : AC97_RATES_FRONT_DAC; |
1079 | runtime->hw.rates = chip->ac97->rates[idx]; | 1087 | runtime->hw.rates = chip->ac97->rates[idx]; |
@@ -1550,51 +1558,51 @@ static void snd_via82xx_mixer_free_ac97(ac97_t *ac97) | |||
1550 | 1558 | ||
1551 | static struct ac97_quirk ac97_quirks[] = { | 1559 | static struct ac97_quirk ac97_quirks[] = { |
1552 | { | 1560 | { |
1553 | .vendor = 0x1106, | 1561 | .subvendor = 0x1106, |
1554 | .device = 0x4161, | 1562 | .subdevice = 0x4161, |
1555 | .codec_id = 0x56494161, /* VT1612A */ | 1563 | .codec_id = 0x56494161, /* VT1612A */ |
1556 | .name = "Soltek SL-75DRV5", | 1564 | .name = "Soltek SL-75DRV5", |
1557 | .type = AC97_TUNE_NONE | 1565 | .type = AC97_TUNE_NONE |
1558 | }, | 1566 | }, |
1559 | { /* FIXME: which codec? */ | 1567 | { /* FIXME: which codec? */ |
1560 | .vendor = 0x1106, | 1568 | .subvendor = 0x1106, |
1561 | .device = 0x4161, | 1569 | .subdevice = 0x4161, |
1562 | .name = "ASRock K7VT2", | 1570 | .name = "ASRock K7VT2", |
1563 | .type = AC97_TUNE_HP_ONLY | 1571 | .type = AC97_TUNE_HP_ONLY |
1564 | }, | 1572 | }, |
1565 | { | 1573 | { |
1566 | .vendor = 0x1019, | 1574 | .subvendor = 0x1019, |
1567 | .device = 0x0a81, | 1575 | .subdevice = 0x0a81, |
1568 | .name = "ECS K7VTA3", | 1576 | .name = "ECS K7VTA3", |
1569 | .type = AC97_TUNE_HP_ONLY | 1577 | .type = AC97_TUNE_HP_ONLY |
1570 | }, | 1578 | }, |
1571 | { | 1579 | { |
1572 | .vendor = 0x1019, | 1580 | .subvendor = 0x1019, |
1573 | .device = 0x0a85, | 1581 | .subdevice = 0x0a85, |
1574 | .name = "ECS L7VMM2", | 1582 | .name = "ECS L7VMM2", |
1575 | .type = AC97_TUNE_HP_ONLY | 1583 | .type = AC97_TUNE_HP_ONLY |
1576 | }, | 1584 | }, |
1577 | { | 1585 | { |
1578 | .vendor = 0x1849, | 1586 | .subvendor = 0x1849, |
1579 | .device = 0x3059, | 1587 | .subdevice = 0x3059, |
1580 | .name = "ASRock K7VM2", | 1588 | .name = "ASRock K7VM2", |
1581 | .type = AC97_TUNE_HP_ONLY /* VT1616 */ | 1589 | .type = AC97_TUNE_HP_ONLY /* VT1616 */ |
1582 | }, | 1590 | }, |
1583 | { | 1591 | { |
1584 | .vendor = 0x14cd, | 1592 | .subvendor = 0x14cd, |
1585 | .device = 0x7002, | 1593 | .subdevice = 0x7002, |
1586 | .name = "Unknown", | 1594 | .name = "Unknown", |
1587 | .type = AC97_TUNE_ALC_JACK | 1595 | .type = AC97_TUNE_ALC_JACK |
1588 | }, | 1596 | }, |
1589 | { | 1597 | { |
1590 | .vendor = 0x1071, | 1598 | .subvendor = 0x1071, |
1591 | .device = 0x8590, | 1599 | .subdevice = 0x8590, |
1592 | .name = "Mitac Mobo", | 1600 | .name = "Mitac Mobo", |
1593 | .type = AC97_TUNE_ALC_JACK | 1601 | .type = AC97_TUNE_ALC_JACK |
1594 | }, | 1602 | }, |
1595 | { | 1603 | { |
1596 | .vendor = 0x161f, | 1604 | .subvendor = 0x161f, |
1597 | .device = 0x202b, | 1605 | .subdevice = 0x202b, |
1598 | .name = "Arima Notebook", | 1606 | .name = "Arima Notebook", |
1599 | .type = AC97_TUNE_HP_ONLY, | 1607 | .type = AC97_TUNE_HP_ONLY, |
1600 | }, | 1608 | }, |
@@ -2132,8 +2140,8 @@ static struct via823x_info via823x_cards[] __devinitdata = { | |||
2132 | * auto detection of DXS channel supports. | 2140 | * auto detection of DXS channel supports. |
2133 | */ | 2141 | */ |
2134 | struct dxs_whitelist { | 2142 | struct dxs_whitelist { |
2135 | unsigned short vendor; | 2143 | unsigned short subvendor; |
2136 | unsigned short device; | 2144 | unsigned short subdevice; |
2137 | unsigned short mask; | 2145 | unsigned short mask; |
2138 | short action; /* new dxs_support value */ | 2146 | short action; /* new dxs_support value */ |
2139 | }; | 2147 | }; |
@@ -2141,38 +2149,44 @@ struct dxs_whitelist { | |||
2141 | static int __devinit check_dxs_list(struct pci_dev *pci) | 2149 | static int __devinit check_dxs_list(struct pci_dev *pci) |
2142 | { | 2150 | { |
2143 | static struct dxs_whitelist whitelist[] = { | 2151 | static struct dxs_whitelist whitelist[] = { |
2144 | { .vendor = 0x1005, .device = 0x4710, .action = VIA_DXS_ENABLE }, /* Avance Logic Mobo */ | 2152 | { .subvendor = 0x1005, .subdevice = 0x4710, .action = VIA_DXS_ENABLE }, /* Avance Logic Mobo */ |
2145 | { .vendor = 0x1019, .device = 0x0996, .action = VIA_DXS_48K }, | 2153 | { .subvendor = 0x1019, .subdevice = 0x0996, .action = VIA_DXS_48K }, |
2146 | { .vendor = 0x1019, .device = 0x0a81, .action = VIA_DXS_NO_VRA }, /* ECS K7VTA3 v8.0 */ | 2154 | { .subvendor = 0x1019, .subdevice = 0x0a81, .action = VIA_DXS_NO_VRA }, /* ECS K7VTA3 v8.0 */ |
2147 | { .vendor = 0x1019, .device = 0x0a85, .action = VIA_DXS_NO_VRA }, /* ECS L7VMM2 */ | 2155 | { .subvendor = 0x1019, .subdevice = 0x0a85, .action = VIA_DXS_NO_VRA }, /* ECS L7VMM2 */ |
2148 | { .vendor = 0x1025, .device = 0x0033, .action = VIA_DXS_NO_VRA }, /* Acer Inspire 1353LM */ | 2156 | { .subvendor = 0x1025, .subdevice = 0x0033, .action = VIA_DXS_NO_VRA }, /* Acer Inspire 1353LM */ |
2149 | { .vendor = 0x1043, .device = 0x8095, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8X (FIXME: possibly VIA_DXS_ENABLE?)*/ | 2157 | { .subvendor = 0x1043, .subdevice = 0x8095, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8X (FIXME: possibly VIA_DXS_ENABLE?)*/ |
2150 | { .vendor = 0x1043, .device = 0x80a1, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8-X */ | 2158 | { .subvendor = 0x1043, .subdevice = 0x80a1, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8-X */ |
2151 | { .vendor = 0x1043, .device = 0x80b0, .action = VIA_DXS_NO_VRA }, /* ASUS A7V600 & K8V*/ | 2159 | { .subvendor = 0x1043, .subdevice = 0x80b0, .action = VIA_DXS_NO_VRA }, /* ASUS A7V600 & K8V*/ |
2152 | { .vendor = 0x1071, .device = 0x8375, .action = VIA_DXS_NO_VRA }, /* Vobis/Yakumo/Mitac notebook */ | 2160 | { .subvendor = 0x1043, .subdevice = 0x812a, .action = VIA_DXS_SRC }, /* ASUS A8V Deluxe */ |
2153 | { .vendor = 0x10cf, .device = 0x118e, .action = VIA_DXS_ENABLE }, /* FSC laptop */ | 2161 | { .subvendor = 0x1071, .subdevice = 0x8375, .action = VIA_DXS_NO_VRA }, /* Vobis/Yakumo/Mitac notebook */ |
2154 | { .vendor = 0x1106, .device = 0x4161, .action = VIA_DXS_NO_VRA }, /* ASRock K7VT2 */ | 2162 | { .subvendor = 0x1071, .subdevice = 0x8399, .action = VIA_DXS_NO_VRA }, /* Umax AB 595T (VIA K8N800A - VT8237) */ |
2155 | { .vendor = 0x1106, .device = 0x4552, .action = VIA_DXS_NO_VRA }, /* QDI Kudoz 7X/600-6AL */ | 2163 | { .subvendor = 0x10cf, .subdevice = 0x118e, .action = VIA_DXS_ENABLE }, /* FSC laptop */ |
2156 | { .vendor = 0x1106, .device = 0xaa01, .action = VIA_DXS_NO_VRA }, /* EPIA MII */ | 2164 | { .subvendor = 0x1106, .subdevice = 0x4161, .action = VIA_DXS_NO_VRA }, /* ASRock K7VT2 */ |
2157 | { .vendor = 0x1297, .device = 0xa232, .action = VIA_DXS_ENABLE }, /* Shuttle ?? */ | 2165 | { .subvendor = 0x1106, .subdevice = 0x4552, .action = VIA_DXS_NO_VRA }, /* QDI Kudoz 7X/600-6AL */ |
2158 | { .vendor = 0x1297, .device = 0xc160, .action = VIA_DXS_ENABLE }, /* Shuttle SK41G */ | 2166 | { .subvendor = 0x1106, .subdevice = 0xaa01, .action = VIA_DXS_NO_VRA }, /* EPIA MII */ |
2159 | { .vendor = 0x1458, .device = 0xa002, .action = VIA_DXS_ENABLE }, /* Gigabyte GA-7VAXP */ | 2167 | { .subvendor = 0x1106, .subdevice = 0xc001, .action = VIA_DXS_SRC }, /* Insight P4-ITX */ |
2160 | { .vendor = 0x1462, .device = 0x3800, .action = VIA_DXS_ENABLE }, /* MSI KT266 */ | 2168 | { .subvendor = 0x1297, .subdevice = 0xa232, .action = VIA_DXS_ENABLE }, /* Shuttle ?? */ |
2161 | { .vendor = 0x1462, .device = 0x5901, .action = VIA_DXS_NO_VRA }, /* MSI KT6 Delta-SR */ | 2169 | { .subvendor = 0x1297, .subdevice = 0xc160, .action = VIA_DXS_ENABLE }, /* Shuttle SK41G */ |
2162 | { .vendor = 0x1462, .device = 0x7023, .action = VIA_DXS_NO_VRA }, /* MSI K8T Neo2-FI */ | 2170 | { .subvendor = 0x1458, .subdevice = 0xa002, .action = VIA_DXS_ENABLE }, /* Gigabyte GA-7VAXP */ |
2163 | { .vendor = 0x1462, .device = 0x7120, .action = VIA_DXS_ENABLE }, /* MSI KT4V */ | 2171 | { .subvendor = 0x1462, .subdevice = 0x0080, .action = VIA_DXS_SRC }, /* MSI K8T Neo-FIS2R */ |
2164 | { .vendor = 0x147b, .device = 0x1401, .action = VIA_DXS_ENABLE }, /* ABIT KD7(-RAID) */ | 2172 | { .subvendor = 0x1462, .subdevice = 0x3800, .action = VIA_DXS_ENABLE }, /* MSI KT266 */ |
2165 | { .vendor = 0x147b, .device = 0x1411, .action = VIA_DXS_ENABLE }, /* ABIT VA-20 */ | 2173 | { .subvendor = 0x1462, .subdevice = 0x5901, .action = VIA_DXS_NO_VRA }, /* MSI KT6 Delta-SR */ |
2166 | { .vendor = 0x147b, .device = 0x1413, .action = VIA_DXS_ENABLE }, /* ABIT KV8 Pro */ | 2174 | { .subvendor = 0x1462, .subdevice = 0x7023, .action = VIA_DXS_NO_VRA }, /* MSI K8T Neo2-FI */ |
2167 | { .vendor = 0x147b, .device = 0x1415, .action = VIA_DXS_NO_VRA }, /* Abit AV8 */ | 2175 | { .subvendor = 0x1462, .subdevice = 0x7120, .action = VIA_DXS_ENABLE }, /* MSI KT4V */ |
2168 | { .vendor = 0x14ff, .device = 0x0403, .action = VIA_DXS_ENABLE }, /* Twinhead mobo */ | 2176 | { .subvendor = 0x147b, .subdevice = 0x1401, .action = VIA_DXS_ENABLE }, /* ABIT KD7(-RAID) */ |
2169 | { .vendor = 0x1584, .device = 0x8120, .action = VIA_DXS_ENABLE }, /* Gericom/Targa/Vobis/Uniwill laptop */ | 2177 | { .subvendor = 0x147b, .subdevice = 0x1411, .action = VIA_DXS_ENABLE }, /* ABIT VA-20 */ |
2170 | { .vendor = 0x1584, .device = 0x8123, .action = VIA_DXS_NO_VRA }, /* Uniwill (Targa Visionary XP-210) */ | 2178 | { .subvendor = 0x147b, .subdevice = 0x1413, .action = VIA_DXS_ENABLE }, /* ABIT KV8 Pro */ |
2171 | { .vendor = 0x161f, .device = 0x202b, .action = VIA_DXS_NO_VRA }, /* Amira Note book */ | 2179 | { .subvendor = 0x147b, .subdevice = 0x1415, .action = VIA_DXS_NO_VRA }, /* Abit AV8 */ |
2172 | { .vendor = 0x161f, .device = 0x2032, .action = VIA_DXS_48K }, /* m680x machines */ | 2180 | { .subvendor = 0x14ff, .subdevice = 0x0403, .action = VIA_DXS_ENABLE }, /* Twinhead mobo */ |
2173 | { .vendor = 0x1631, .device = 0xe004, .action = VIA_DXS_ENABLE }, /* Easy Note 3174, Packard Bell */ | 2181 | { .subvendor = 0x14ff, .subdevice = 0x0408, .action = VIA_DXS_NO_VRA }, /* Twinhead mobo */ |
2174 | { .vendor = 0x1695, .device = 0x3005, .action = VIA_DXS_ENABLE }, /* EPoX EP-8K9A */ | 2182 | { .subvendor = 0x1584, .subdevice = 0x8120, .action = VIA_DXS_ENABLE }, /* Gericom/Targa/Vobis/Uniwill laptop */ |
2175 | { .vendor = 0x1849, .device = 0x3059, .action = VIA_DXS_NO_VRA }, /* ASRock K7VM2 */ | 2183 | { .subvendor = 0x1584, .subdevice = 0x8123, .action = VIA_DXS_NO_VRA }, /* Uniwill (Targa Visionary XP-210) */ |
2184 | { .subvendor = 0x161f, .subdevice = 0x202b, .action = VIA_DXS_NO_VRA }, /* Amira Note book */ | ||
2185 | { .subvendor = 0x161f, .subdevice = 0x2032, .action = VIA_DXS_48K }, /* m680x machines */ | ||
2186 | { .subvendor = 0x1631, .subdevice = 0xe004, .action = VIA_DXS_ENABLE }, /* Easy Note 3174, Packard Bell */ | ||
2187 | { .subvendor = 0x1695, .subdevice = 0x3005, .action = VIA_DXS_ENABLE }, /* EPoX EP-8K9A */ | ||
2188 | { .subvendor = 0x1849, .subdevice = 0x3059, .action = VIA_DXS_NO_VRA }, /* ASRock K7VM2 */ | ||
2189 | { .subvendor = 0x1919, .subdevice = 0x200a, .action = VIA_DXS_NO_VRA }, /* Soltek SL-K8Tpro-939 */ | ||
2176 | { } /* terminator */ | 2190 | { } /* terminator */ |
2177 | }; | 2191 | }; |
2178 | struct dxs_whitelist *w; | 2192 | struct dxs_whitelist *w; |
@@ -2182,14 +2196,14 @@ static int __devinit check_dxs_list(struct pci_dev *pci) | |||
2182 | pci_read_config_word(pci, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor); | 2196 | pci_read_config_word(pci, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor); |
2183 | pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &subsystem_device); | 2197 | pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &subsystem_device); |
2184 | 2198 | ||
2185 | for (w = whitelist; w->vendor; w++) { | 2199 | for (w = whitelist; w->subvendor; w++) { |
2186 | if (w->vendor != subsystem_vendor) | 2200 | if (w->subvendor != subsystem_vendor) |
2187 | continue; | 2201 | continue; |
2188 | if (w->mask) { | 2202 | if (w->mask) { |
2189 | if ((w->mask & subsystem_device) == w->device) | 2203 | if ((w->mask & subsystem_device) == w->subdevice) |
2190 | return w->action; | 2204 | return w->action; |
2191 | } else { | 2205 | } else { |
2192 | if (subsystem_device == w->device) | 2206 | if (subsystem_device == w->subdevice) |
2193 | return w->action; | 2207 | return w->action; |
2194 | } | 2208 | } |
2195 | } | 2209 | } |
@@ -2198,8 +2212,9 @@ static int __devinit check_dxs_list(struct pci_dev *pci) | |||
2198 | * not detected, try 48k rate only to be sure. | 2212 | * not detected, try 48k rate only to be sure. |
2199 | */ | 2213 | */ |
2200 | printk(KERN_INFO "via82xx: Assuming DXS channels with 48k fixed sample rate.\n"); | 2214 | printk(KERN_INFO "via82xx: Assuming DXS channels with 48k fixed sample rate.\n"); |
2201 | printk(KERN_INFO " Please try dxs_support=1 or dxs_support=4 option\n"); | 2215 | printk(KERN_INFO " Please try dxs_support=5 option\n"); |
2202 | printk(KERN_INFO " and report if it works on your machine.\n"); | 2216 | printk(KERN_INFO " and report if it works on your machine.\n"); |
2217 | printk(KERN_INFO " For more details, read ALSA-Configuration.txt.\n"); | ||
2203 | return VIA_DXS_48K; | 2218 | return VIA_DXS_48K; |
2204 | }; | 2219 | }; |
2205 | 2220 | ||
@@ -2288,6 +2303,10 @@ static int __devinit snd_via82xx_probe(struct pci_dev *pci, | |||
2288 | chip->dxs_fixed = 1; | 2303 | chip->dxs_fixed = 1; |
2289 | else if (dxs_support[dev] == VIA_DXS_NO_VRA) | 2304 | else if (dxs_support[dev] == VIA_DXS_NO_VRA) |
2290 | chip->no_vra = 1; | 2305 | chip->no_vra = 1; |
2306 | else if (dxs_support[dev] == VIA_DXS_SRC) { | ||
2307 | chip->no_vra = 1; | ||
2308 | chip->dxs_src = 1; | ||
2309 | } | ||
2291 | } | 2310 | } |
2292 | if ((err = snd_via8233_init_misc(chip, dev)) < 0) | 2311 | if ((err = snd_via8233_init_misc(chip, dev)) < 0) |
2293 | goto __error; | 2312 | goto __error; |
@@ -2334,7 +2353,7 @@ static struct pci_driver driver = { | |||
2334 | 2353 | ||
2335 | static int __init alsa_card_via82xx_init(void) | 2354 | static int __init alsa_card_via82xx_init(void) |
2336 | { | 2355 | { |
2337 | return pci_module_init(&driver); | 2356 | return pci_register_driver(&driver); |
2338 | } | 2357 | } |
2339 | 2358 | ||
2340 | static void __exit alsa_card_via82xx_exit(void) | 2359 | static void __exit alsa_card_via82xx_exit(void) |
diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c index ea5c6f640159..5896d289f9ac 100644 --- a/sound/pci/via82xx_modem.c +++ b/sound/pci/via82xx_modem.c | |||
@@ -352,10 +352,8 @@ static int clean_via_table(viadev_t *dev, snd_pcm_substream_t *substream, | |||
352 | snd_dma_free_pages(&dev->table); | 352 | snd_dma_free_pages(&dev->table); |
353 | dev->table.area = NULL; | 353 | dev->table.area = NULL; |
354 | } | 354 | } |
355 | if (dev->idx_table) { | 355 | kfree(dev->idx_table); |
356 | kfree(dev->idx_table); | 356 | dev->idx_table = NULL; |
357 | dev->idx_table = NULL; | ||
358 | } | ||
359 | return 0; | 357 | return 0; |
360 | } | 358 | } |
361 | 359 | ||
@@ -420,7 +418,10 @@ static void snd_via82xx_codec_write(ac97_t *ac97, | |||
420 | { | 418 | { |
421 | via82xx_t *chip = ac97->private_data; | 419 | via82xx_t *chip = ac97->private_data; |
422 | unsigned int xval; | 420 | unsigned int xval; |
423 | 421 | if(reg == AC97_GPIO_STATUS) { | |
422 | outl(val, VIAREG(chip, GPI_STATUS)); | ||
423 | return; | ||
424 | } | ||
424 | xval = !ac97->num ? VIA_REG_AC97_CODEC_ID_PRIMARY : VIA_REG_AC97_CODEC_ID_SECONDARY; | 425 | xval = !ac97->num ? VIA_REG_AC97_CODEC_ID_PRIMARY : VIA_REG_AC97_CODEC_ID_SECONDARY; |
425 | xval <<= VIA_REG_AC97_CODEC_ID_SHIFT; | 426 | xval <<= VIA_REG_AC97_CODEC_ID_SHIFT; |
426 | xval |= reg << VIA_REG_AC97_CMD_SHIFT; | 427 | xval |= reg << VIA_REG_AC97_CMD_SHIFT; |
@@ -544,25 +545,6 @@ static int snd_via82xx_pcm_trigger(snd_pcm_substream_t * substream, int cmd) | |||
544 | return 0; | 545 | return 0; |
545 | } | 546 | } |
546 | 547 | ||
547 | static int snd_via82xx_modem_pcm_trigger(snd_pcm_substream_t * substream, int cmd) | ||
548 | { | ||
549 | via82xx_t *chip = snd_pcm_substream_chip(substream); | ||
550 | unsigned int val = 0; | ||
551 | switch (cmd) { | ||
552 | case SNDRV_PCM_TRIGGER_START: | ||
553 | val = snd_ac97_read(chip->ac97, AC97_GPIO_STATUS); | ||
554 | outl(val|AC97_GPIO_LINE1_OH, VIAREG(chip, GPI_STATUS)); | ||
555 | break; | ||
556 | case SNDRV_PCM_TRIGGER_STOP: | ||
557 | val = snd_ac97_read(chip->ac97, AC97_GPIO_STATUS); | ||
558 | outl(val&~AC97_GPIO_LINE1_OH, VIAREG(chip, GPI_STATUS)); | ||
559 | break; | ||
560 | default: | ||
561 | break; | ||
562 | } | ||
563 | return snd_via82xx_pcm_trigger(substream, cmd); | ||
564 | } | ||
565 | |||
566 | /* | 548 | /* |
567 | * pointer callbacks | 549 | * pointer callbacks |
568 | */ | 550 | */ |
@@ -806,7 +788,7 @@ static snd_pcm_ops_t snd_via686_playback_ops = { | |||
806 | .hw_params = snd_via82xx_hw_params, | 788 | .hw_params = snd_via82xx_hw_params, |
807 | .hw_free = snd_via82xx_hw_free, | 789 | .hw_free = snd_via82xx_hw_free, |
808 | .prepare = snd_via82xx_pcm_prepare, | 790 | .prepare = snd_via82xx_pcm_prepare, |
809 | .trigger = snd_via82xx_modem_pcm_trigger, | 791 | .trigger = snd_via82xx_pcm_trigger, |
810 | .pointer = snd_via686_pcm_pointer, | 792 | .pointer = snd_via686_pcm_pointer, |
811 | .page = snd_pcm_sgbuf_ops_page, | 793 | .page = snd_pcm_sgbuf_ops_page, |
812 | }; | 794 | }; |
@@ -819,7 +801,7 @@ static snd_pcm_ops_t snd_via686_capture_ops = { | |||
819 | .hw_params = snd_via82xx_hw_params, | 801 | .hw_params = snd_via82xx_hw_params, |
820 | .hw_free = snd_via82xx_hw_free, | 802 | .hw_free = snd_via82xx_hw_free, |
821 | .prepare = snd_via82xx_pcm_prepare, | 803 | .prepare = snd_via82xx_pcm_prepare, |
822 | .trigger = snd_via82xx_modem_pcm_trigger, | 804 | .trigger = snd_via82xx_pcm_trigger, |
823 | .pointer = snd_via686_pcm_pointer, | 805 | .pointer = snd_via686_pcm_pointer, |
824 | .page = snd_pcm_sgbuf_ops_page, | 806 | .page = snd_pcm_sgbuf_ops_page, |
825 | }; | 807 | }; |
@@ -938,7 +920,7 @@ static void __devinit snd_via82xx_proc_init(via82xx_t *chip) | |||
938 | * | 920 | * |
939 | */ | 921 | */ |
940 | 922 | ||
941 | static int __devinit snd_via82xx_chip_init(via82xx_t *chip) | 923 | static int snd_via82xx_chip_init(via82xx_t *chip) |
942 | { | 924 | { |
943 | unsigned int val; | 925 | unsigned int val; |
944 | int max_count; | 926 | int max_count; |
@@ -1233,7 +1215,7 @@ static struct pci_driver driver = { | |||
1233 | 1215 | ||
1234 | static int __init alsa_card_via82xx_init(void) | 1216 | static int __init alsa_card_via82xx_init(void) |
1235 | { | 1217 | { |
1236 | return pci_module_init(&driver); | 1218 | return pci_register_driver(&driver); |
1237 | } | 1219 | } |
1238 | 1220 | ||
1239 | static void __exit alsa_card_via82xx_exit(void) | 1221 | static void __exit alsa_card_via82xx_exit(void) |
diff --git a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c index 4ffbb25658a5..dca6bd2c7580 100644 --- a/sound/pci/vx222/vx222.c +++ b/sound/pci/vx222/vx222.c | |||
@@ -260,7 +260,7 @@ static struct pci_driver driver = { | |||
260 | 260 | ||
261 | static int __init alsa_card_vx222_init(void) | 261 | static int __init alsa_card_vx222_init(void) |
262 | { | 262 | { |
263 | return pci_module_init(&driver); | 263 | return pci_register_driver(&driver); |
264 | } | 264 | } |
265 | 265 | ||
266 | static void __exit alsa_card_vx222_exit(void) | 266 | static void __exit alsa_card_vx222_exit(void) |
diff --git a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c index 9f3ef22df08d..5b5b624b47d0 100644 --- a/sound/pci/ymfpci/ymfpci.c +++ b/sound/pci/ymfpci/ymfpci.c | |||
@@ -360,7 +360,7 @@ static struct pci_driver driver = { | |||
360 | 360 | ||
361 | static int __init alsa_card_ymfpci_init(void) | 361 | static int __init alsa_card_ymfpci_init(void) |
362 | { | 362 | { |
363 | return pci_module_init(&driver); | 363 | return pci_register_driver(&driver); |
364 | } | 364 | } |
365 | 365 | ||
366 | static void __exit alsa_card_ymfpci_exit(void) | 366 | static void __exit alsa_card_ymfpci_exit(void) |
diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index 05f1629760bc..2ae79610ecb5 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c | |||
@@ -829,9 +829,7 @@ static snd_pcm_hardware_t snd_ymfpci_capture = | |||
829 | 829 | ||
830 | static void snd_ymfpci_pcm_free_substream(snd_pcm_runtime_t *runtime) | 830 | static void snd_ymfpci_pcm_free_substream(snd_pcm_runtime_t *runtime) |
831 | { | 831 | { |
832 | ymfpci_pcm_t *ypcm = runtime->private_data; | 832 | kfree(runtime->private_data); |
833 | |||
834 | kfree(ypcm); | ||
835 | } | 833 | } |
836 | 834 | ||
837 | static int snd_ymfpci_playback_open_1(snd_pcm_substream_t * substream) | 835 | static int snd_ymfpci_playback_open_1(snd_pcm_substream_t * substream) |
@@ -1421,17 +1419,15 @@ static snd_kcontrol_new_t snd_ymfpci_drec_source __devinitdata = { | |||
1421 | 1419 | ||
1422 | static int snd_ymfpci_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) | 1420 | static int snd_ymfpci_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) |
1423 | { | 1421 | { |
1424 | unsigned int mask = 1; | ||
1425 | |||
1426 | switch (kcontrol->private_value) { | 1422 | switch (kcontrol->private_value) { |
1427 | case YDSXGR_SPDIFOUTCTRL: break; | 1423 | case YDSXGR_SPDIFOUTCTRL: break; |
1428 | case YDSXGR_SPDIFINCTRL: break; | 1424 | case YDSXGR_SPDIFINCTRL: break; |
1429 | default: return -EINVAL; | 1425 | default: return -EINVAL; |
1430 | } | 1426 | } |
1431 | uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; | 1427 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; |
1432 | uinfo->count = 1; | 1428 | uinfo->count = 1; |
1433 | uinfo->value.integer.min = 0; | 1429 | uinfo->value.integer.min = 0; |
1434 | uinfo->value.integer.max = mask; | 1430 | uinfo->value.integer.max = 1; |
1435 | return 0; | 1431 | return 0; |
1436 | } | 1432 | } |
1437 | 1433 | ||
@@ -1439,7 +1435,7 @@ static int snd_ymfpci_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t | |||
1439 | { | 1435 | { |
1440 | ymfpci_t *chip = snd_kcontrol_chip(kcontrol); | 1436 | ymfpci_t *chip = snd_kcontrol_chip(kcontrol); |
1441 | int reg = kcontrol->private_value; | 1437 | int reg = kcontrol->private_value; |
1442 | unsigned int shift = 0, mask = 1, invert = 0; | 1438 | unsigned int shift = 0, mask = 1; |
1443 | 1439 | ||
1444 | switch (kcontrol->private_value) { | 1440 | switch (kcontrol->private_value) { |
1445 | case YDSXGR_SPDIFOUTCTRL: break; | 1441 | case YDSXGR_SPDIFOUTCTRL: break; |
@@ -1447,8 +1443,6 @@ static int snd_ymfpci_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t | |||
1447 | default: return -EINVAL; | 1443 | default: return -EINVAL; |
1448 | } | 1444 | } |
1449 | ucontrol->value.integer.value[0] = (snd_ymfpci_readl(chip, reg) >> shift) & mask; | 1445 | ucontrol->value.integer.value[0] = (snd_ymfpci_readl(chip, reg) >> shift) & mask; |
1450 | if (invert) | ||
1451 | ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; | ||
1452 | return 0; | 1446 | return 0; |
1453 | } | 1447 | } |
1454 | 1448 | ||
@@ -1456,7 +1450,7 @@ static int snd_ymfpci_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t | |||
1456 | { | 1450 | { |
1457 | ymfpci_t *chip = snd_kcontrol_chip(kcontrol); | 1451 | ymfpci_t *chip = snd_kcontrol_chip(kcontrol); |
1458 | int reg = kcontrol->private_value; | 1452 | int reg = kcontrol->private_value; |
1459 | unsigned int shift = 0, mask = 1, invert = 0; | 1453 | unsigned int shift = 0, mask = 1; |
1460 | int change; | 1454 | int change; |
1461 | unsigned int val, oval; | 1455 | unsigned int val, oval; |
1462 | 1456 | ||
@@ -1466,8 +1460,6 @@ static int snd_ymfpci_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t | |||
1466 | default: return -EINVAL; | 1460 | default: return -EINVAL; |
1467 | } | 1461 | } |
1468 | val = (ucontrol->value.integer.value[0] & mask); | 1462 | val = (ucontrol->value.integer.value[0] & mask); |
1469 | if (invert) | ||
1470 | val = mask - val; | ||
1471 | val <<= shift; | 1463 | val <<= shift; |
1472 | spin_lock_irq(&chip->reg_lock); | 1464 | spin_lock_irq(&chip->reg_lock); |
1473 | oval = snd_ymfpci_readl(chip, reg); | 1465 | oval = snd_ymfpci_readl(chip, reg); |
@@ -1487,14 +1479,13 @@ static int snd_ymfpci_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t | |||
1487 | static int snd_ymfpci_info_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) | 1479 | static int snd_ymfpci_info_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) |
1488 | { | 1480 | { |
1489 | unsigned int reg = kcontrol->private_value; | 1481 | unsigned int reg = kcontrol->private_value; |
1490 | unsigned int mask = 16383; | ||
1491 | 1482 | ||
1492 | if (reg < 0x80 || reg >= 0xc0) | 1483 | if (reg < 0x80 || reg >= 0xc0) |
1493 | return -EINVAL; | 1484 | return -EINVAL; |
1494 | uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; | 1485 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
1495 | uinfo->count = 2; | 1486 | uinfo->count = 2; |
1496 | uinfo->value.integer.min = 0; | 1487 | uinfo->value.integer.min = 0; |
1497 | uinfo->value.integer.max = mask; | 1488 | uinfo->value.integer.max = 16383; |
1498 | return 0; | 1489 | return 0; |
1499 | } | 1490 | } |
1500 | 1491 | ||
@@ -1502,7 +1493,7 @@ static int snd_ymfpci_get_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t | |||
1502 | { | 1493 | { |
1503 | ymfpci_t *chip = snd_kcontrol_chip(kcontrol); | 1494 | ymfpci_t *chip = snd_kcontrol_chip(kcontrol); |
1504 | unsigned int reg = kcontrol->private_value; | 1495 | unsigned int reg = kcontrol->private_value; |
1505 | unsigned int shift_left = 0, shift_right = 16, mask = 16383, invert = 0; | 1496 | unsigned int shift_left = 0, shift_right = 16, mask = 16383; |
1506 | unsigned int val; | 1497 | unsigned int val; |
1507 | 1498 | ||
1508 | if (reg < 0x80 || reg >= 0xc0) | 1499 | if (reg < 0x80 || reg >= 0xc0) |
@@ -1512,10 +1503,6 @@ static int snd_ymfpci_get_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t | |||
1512 | spin_unlock_irq(&chip->reg_lock); | 1503 | spin_unlock_irq(&chip->reg_lock); |
1513 | ucontrol->value.integer.value[0] = (val >> shift_left) & mask; | 1504 | ucontrol->value.integer.value[0] = (val >> shift_left) & mask; |
1514 | ucontrol->value.integer.value[1] = (val >> shift_right) & mask; | 1505 | ucontrol->value.integer.value[1] = (val >> shift_right) & mask; |
1515 | if (invert) { | ||
1516 | ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; | ||
1517 | ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1]; | ||
1518 | } | ||
1519 | return 0; | 1506 | return 0; |
1520 | } | 1507 | } |
1521 | 1508 | ||
@@ -1523,7 +1510,7 @@ static int snd_ymfpci_put_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t | |||
1523 | { | 1510 | { |
1524 | ymfpci_t *chip = snd_kcontrol_chip(kcontrol); | 1511 | ymfpci_t *chip = snd_kcontrol_chip(kcontrol); |
1525 | unsigned int reg = kcontrol->private_value; | 1512 | unsigned int reg = kcontrol->private_value; |
1526 | unsigned int shift_left = 0, shift_right = 16, mask = 16383, invert = 0; | 1513 | unsigned int shift_left = 0, shift_right = 16, mask = 16383; |
1527 | int change; | 1514 | int change; |
1528 | unsigned int val1, val2, oval; | 1515 | unsigned int val1, val2, oval; |
1529 | 1516 | ||
@@ -1531,10 +1518,6 @@ static int snd_ymfpci_put_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t | |||
1531 | return -EINVAL; | 1518 | return -EINVAL; |
1532 | val1 = ucontrol->value.integer.value[0] & mask; | 1519 | val1 = ucontrol->value.integer.value[0] & mask; |
1533 | val2 = ucontrol->value.integer.value[1] & mask; | 1520 | val2 = ucontrol->value.integer.value[1] & mask; |
1534 | if (invert) { | ||
1535 | val1 = mask - val1; | ||
1536 | val2 = mask - val2; | ||
1537 | } | ||
1538 | val1 <<= shift_left; | 1521 | val1 <<= shift_left; |
1539 | val2 <<= shift_right; | 1522 | val2 <<= shift_right; |
1540 | spin_lock_irq(&chip->reg_lock); | 1523 | spin_lock_irq(&chip->reg_lock); |
diff --git a/sound/pcmcia/vx/vx_entry.c b/sound/pcmcia/vx/vx_entry.c index 53d8172c52ae..332bbca3dfc4 100644 --- a/sound/pcmcia/vx/vx_entry.c +++ b/sound/pcmcia/vx/vx_entry.c | |||
@@ -68,8 +68,7 @@ static int snd_vxpocket_free(vx_core_t *chip) | |||
68 | if (hw) | 68 | if (hw) |
69 | hw->card_list[vxp->index] = NULL; | 69 | hw->card_list[vxp->index] = NULL; |
70 | chip->card = NULL; | 70 | chip->card = NULL; |
71 | if (chip->dev) | 71 | kfree(chip->dev); |
72 | kfree(chip->dev); | ||
73 | 72 | ||
74 | snd_vx_free_firmware(chip); | 73 | snd_vx_free_firmware(chip); |
75 | kfree(chip); | 74 | kfree(chip); |
diff --git a/sound/synth/emux/emux_effect.c b/sound/synth/emux/emux_effect.c index ec3fc1ba7fca..4764940f11a0 100644 --- a/sound/synth/emux/emux_effect.c +++ b/sound/synth/emux/emux_effect.c | |||
@@ -291,10 +291,8 @@ snd_emux_create_effect(snd_emux_port_t *p) | |||
291 | void | 291 | void |
292 | snd_emux_delete_effect(snd_emux_port_t *p) | 292 | snd_emux_delete_effect(snd_emux_port_t *p) |
293 | { | 293 | { |
294 | if (p->effect) { | 294 | kfree(p->effect); |
295 | kfree(p->effect); | 295 | p->effect = NULL; |
296 | p->effect = NULL; | ||
297 | } | ||
298 | } | 296 | } |
299 | 297 | ||
300 | void | 298 | void |
diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index 9329e992c841..f05d02f5b69f 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig | |||
@@ -6,6 +6,7 @@ menu "USB devices" | |||
6 | config SND_USB_AUDIO | 6 | config SND_USB_AUDIO |
7 | tristate "USB Audio/MIDI driver" | 7 | tristate "USB Audio/MIDI driver" |
8 | depends on SND && USB | 8 | depends on SND && USB |
9 | select SND_HWDEP | ||
9 | select SND_RAWMIDI | 10 | select SND_RAWMIDI |
10 | select SND_PCM | 11 | select SND_PCM |
11 | help | 12 | help |
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index aae66144d411..a75695045f29 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c | |||
@@ -98,7 +98,7 @@ MODULE_PARM_DESC(async_unlink, "Use async unlink mode."); | |||
98 | #define MAX_PACKS 10 | 98 | #define MAX_PACKS 10 |
99 | #define MAX_PACKS_HS (MAX_PACKS * 8) /* in high speed mode */ | 99 | #define MAX_PACKS_HS (MAX_PACKS * 8) /* in high speed mode */ |
100 | #define MAX_URBS 5 /* max. 20ms long packets */ | 100 | #define MAX_URBS 5 /* max. 20ms long packets */ |
101 | #define SYNC_URBS 2 /* always two urbs for sync */ | 101 | #define SYNC_URBS 4 /* always four urbs for sync */ |
102 | #define MIN_PACKS_URB 1 /* minimum 1 packet per urb */ | 102 | #define MIN_PACKS_URB 1 /* minimum 1 packet per urb */ |
103 | 103 | ||
104 | typedef struct snd_usb_substream snd_usb_substream_t; | 104 | typedef struct snd_usb_substream snd_usb_substream_t; |
@@ -177,7 +177,7 @@ struct snd_usb_substream { | |||
177 | unsigned int nurbs; /* # urbs */ | 177 | unsigned int nurbs; /* # urbs */ |
178 | snd_urb_ctx_t dataurb[MAX_URBS]; /* data urb table */ | 178 | snd_urb_ctx_t dataurb[MAX_URBS]; /* data urb table */ |
179 | snd_urb_ctx_t syncurb[SYNC_URBS]; /* sync urb table */ | 179 | snd_urb_ctx_t syncurb[SYNC_URBS]; /* sync urb table */ |
180 | char syncbuf[SYNC_URBS * MAX_PACKS * 4]; /* sync buffer; it's so small - let's get static */ | 180 | char syncbuf[SYNC_URBS * 4]; /* sync buffer; it's so small - let's get static */ |
181 | char *tmpbuf; /* temporary buffer for playback */ | 181 | char *tmpbuf; /* temporary buffer for playback */ |
182 | 182 | ||
183 | u64 formats; /* format bitmasks (all or'ed) */ | 183 | u64 formats; /* format bitmasks (all or'ed) */ |
@@ -251,17 +251,13 @@ static int prepare_capture_sync_urb(snd_usb_substream_t *subs, | |||
251 | { | 251 | { |
252 | unsigned char *cp = urb->transfer_buffer; | 252 | unsigned char *cp = urb->transfer_buffer; |
253 | snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context; | 253 | snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context; |
254 | int i, offs; | ||
255 | 254 | ||
256 | urb->number_of_packets = ctx->packets; | ||
257 | urb->dev = ctx->subs->dev; /* we need to set this at each time */ | 255 | urb->dev = ctx->subs->dev; /* we need to set this at each time */ |
258 | for (i = offs = 0; i < urb->number_of_packets; i++, offs += 4, cp += 4) { | 256 | urb->iso_frame_desc[0].length = 3; |
259 | urb->iso_frame_desc[i].length = 3; | 257 | urb->iso_frame_desc[0].offset = 0; |
260 | urb->iso_frame_desc[i].offset = offs; | 258 | cp[0] = subs->freqn >> 2; |
261 | cp[0] = subs->freqn >> 2; | 259 | cp[1] = subs->freqn >> 10; |
262 | cp[1] = subs->freqn >> 10; | 260 | cp[2] = subs->freqn >> 18; |
263 | cp[2] = subs->freqn >> 18; | ||
264 | } | ||
265 | return 0; | 261 | return 0; |
266 | } | 262 | } |
267 | 263 | ||
@@ -277,18 +273,14 @@ static int prepare_capture_sync_urb_hs(snd_usb_substream_t *subs, | |||
277 | { | 273 | { |
278 | unsigned char *cp = urb->transfer_buffer; | 274 | unsigned char *cp = urb->transfer_buffer; |
279 | snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context; | 275 | snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context; |
280 | int i, offs; | ||
281 | 276 | ||
282 | urb->number_of_packets = ctx->packets; | ||
283 | urb->dev = ctx->subs->dev; /* we need to set this at each time */ | 277 | urb->dev = ctx->subs->dev; /* we need to set this at each time */ |
284 | for (i = offs = 0; i < urb->number_of_packets; i++, offs += 4, cp += 4) { | 278 | urb->iso_frame_desc[0].length = 4; |
285 | urb->iso_frame_desc[i].length = 4; | 279 | urb->iso_frame_desc[0].offset = 0; |
286 | urb->iso_frame_desc[i].offset = offs; | 280 | cp[0] = subs->freqn; |
287 | cp[0] = subs->freqn; | 281 | cp[1] = subs->freqn >> 8; |
288 | cp[1] = subs->freqn >> 8; | 282 | cp[2] = subs->freqn >> 16; |
289 | cp[2] = subs->freqn >> 16; | 283 | cp[3] = subs->freqn >> 24; |
290 | cp[3] = subs->freqn >> 24; | ||
291 | } | ||
292 | return 0; | 284 | return 0; |
293 | } | 285 | } |
294 | 286 | ||
@@ -418,15 +410,11 @@ static int prepare_playback_sync_urb(snd_usb_substream_t *subs, | |||
418 | snd_pcm_runtime_t *runtime, | 410 | snd_pcm_runtime_t *runtime, |
419 | struct urb *urb) | 411 | struct urb *urb) |
420 | { | 412 | { |
421 | int i, offs; | ||
422 | snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context; | 413 | snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context; |
423 | 414 | ||
424 | urb->number_of_packets = ctx->packets; | ||
425 | urb->dev = ctx->subs->dev; /* we need to set this at each time */ | 415 | urb->dev = ctx->subs->dev; /* we need to set this at each time */ |
426 | for (i = offs = 0; i < urb->number_of_packets; i++, offs += 4) { | 416 | urb->iso_frame_desc[0].length = 3; |
427 | urb->iso_frame_desc[i].length = 3; | 417 | urb->iso_frame_desc[0].offset = 0; |
428 | urb->iso_frame_desc[i].offset = offs; | ||
429 | } | ||
430 | return 0; | 418 | return 0; |
431 | } | 419 | } |
432 | 420 | ||
@@ -440,15 +428,11 @@ static int prepare_playback_sync_urb_hs(snd_usb_substream_t *subs, | |||
440 | snd_pcm_runtime_t *runtime, | 428 | snd_pcm_runtime_t *runtime, |
441 | struct urb *urb) | 429 | struct urb *urb) |
442 | { | 430 | { |
443 | int i, offs; | ||
444 | snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context; | 431 | snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context; |
445 | 432 | ||
446 | urb->number_of_packets = ctx->packets; | ||
447 | urb->dev = ctx->subs->dev; /* we need to set this at each time */ | 433 | urb->dev = ctx->subs->dev; /* we need to set this at each time */ |
448 | for (i = offs = 0; i < urb->number_of_packets; i++, offs += 4) { | 434 | urb->iso_frame_desc[0].length = 4; |
449 | urb->iso_frame_desc[i].length = 4; | 435 | urb->iso_frame_desc[0].offset = 0; |
450 | urb->iso_frame_desc[i].offset = offs; | ||
451 | } | ||
452 | return 0; | 436 | return 0; |
453 | } | 437 | } |
454 | 438 | ||
@@ -462,31 +446,17 @@ static int retire_playback_sync_urb(snd_usb_substream_t *subs, | |||
462 | snd_pcm_runtime_t *runtime, | 446 | snd_pcm_runtime_t *runtime, |
463 | struct urb *urb) | 447 | struct urb *urb) |
464 | { | 448 | { |
465 | int i; | 449 | unsigned int f; |
466 | unsigned int f, found; | ||
467 | unsigned char *cp = urb->transfer_buffer; | ||
468 | unsigned long flags; | 450 | unsigned long flags; |
469 | 451 | ||
470 | found = 0; | 452 | if (urb->iso_frame_desc[0].status == 0 && |
471 | for (i = 0; i < urb->number_of_packets; i++, cp += 4) { | 453 | urb->iso_frame_desc[0].actual_length == 3) { |
472 | if (urb->iso_frame_desc[i].status || | 454 | f = combine_triple((u8*)urb->transfer_buffer) << 2; |
473 | urb->iso_frame_desc[i].actual_length < 3) | 455 | if (f >= subs->freqn - subs->freqn / 8 && f <= subs->freqmax) { |
474 | continue; | 456 | spin_lock_irqsave(&subs->lock, flags); |
475 | f = combine_triple(cp) << 2; | 457 | subs->freqm = f; |
476 | #if 0 | 458 | spin_unlock_irqrestore(&subs->lock, flags); |
477 | if (f < subs->freqn - (subs->freqn>>3) || f > subs->freqmax) { | ||
478 | snd_printd(KERN_WARNING "requested frequency %d (%u,%03uHz) out of range (current nominal %d (%u,%03uHz))\n", | ||
479 | f, f >> 14, (f & ((1 << 14) - 1) * 1000) / ((1 << 14) - 1), | ||
480 | subs->freqn, subs->freqn >> 14, (subs->freqn & ((1 << 14) - 1) * 1000) / ((1 << 14) - 1)); | ||
481 | continue; | ||
482 | } | 459 | } |
483 | #endif | ||
484 | found = f; | ||
485 | } | ||
486 | if (found) { | ||
487 | spin_lock_irqsave(&subs->lock, flags); | ||
488 | subs->freqm = found; | ||
489 | spin_unlock_irqrestore(&subs->lock, flags); | ||
490 | } | 460 | } |
491 | 461 | ||
492 | return 0; | 462 | return 0; |
@@ -502,22 +472,17 @@ static int retire_playback_sync_urb_hs(snd_usb_substream_t *subs, | |||
502 | snd_pcm_runtime_t *runtime, | 472 | snd_pcm_runtime_t *runtime, |
503 | struct urb *urb) | 473 | struct urb *urb) |
504 | { | 474 | { |
505 | int i; | 475 | unsigned int f; |
506 | unsigned int found; | ||
507 | unsigned char *cp = urb->transfer_buffer; | ||
508 | unsigned long flags; | 476 | unsigned long flags; |
509 | 477 | ||
510 | found = 0; | 478 | if (urb->iso_frame_desc[0].status == 0 && |
511 | for (i = 0; i < urb->number_of_packets; i++, cp += 4) { | 479 | urb->iso_frame_desc[0].actual_length == 4) { |
512 | if (urb->iso_frame_desc[i].status || | 480 | f = combine_quad((u8*)urb->transfer_buffer) & 0x0fffffff; |
513 | urb->iso_frame_desc[i].actual_length < 4) | 481 | if (f >= subs->freqn - subs->freqn / 8 && f <= subs->freqmax) { |
514 | continue; | 482 | spin_lock_irqsave(&subs->lock, flags); |
515 | found = combine_quad(cp) & 0x0fffffff; | 483 | subs->freqm = f; |
516 | } | 484 | spin_unlock_irqrestore(&subs->lock, flags); |
517 | if (found) { | 485 | } |
518 | spin_lock_irqsave(&subs->lock, flags); | ||
519 | subs->freqm = found; | ||
520 | spin_unlock_irqrestore(&subs->lock, flags); | ||
521 | } | 486 | } |
522 | 487 | ||
523 | return 0; | 488 | return 0; |
@@ -600,6 +565,8 @@ static int prepare_playback_urb(snd_usb_substream_t *subs, | |||
600 | /* set the buffer pointer */ | 565 | /* set the buffer pointer */ |
601 | urb->transfer_buffer = runtime->dma_area + subs->hwptr * stride; | 566 | urb->transfer_buffer = runtime->dma_area + subs->hwptr * stride; |
602 | subs->hwptr += offs; | 567 | subs->hwptr += offs; |
568 | if (subs->hwptr == runtime->buffer_size) | ||
569 | subs->hwptr = 0; | ||
603 | } | 570 | } |
604 | spin_unlock_irqrestore(&subs->lock, flags); | 571 | spin_unlock_irqrestore(&subs->lock, flags); |
605 | urb->transfer_buffer_length = offs * stride; | 572 | urb->transfer_buffer_length = offs * stride; |
@@ -892,10 +859,8 @@ static void release_urb_ctx(snd_urb_ctx_t *u) | |||
892 | usb_free_urb(u->urb); | 859 | usb_free_urb(u->urb); |
893 | u->urb = NULL; | 860 | u->urb = NULL; |
894 | } | 861 | } |
895 | if (u->buf) { | 862 | kfree(u->buf); |
896 | kfree(u->buf); | 863 | u->buf = NULL; |
897 | u->buf = NULL; | ||
898 | } | ||
899 | } | 864 | } |
900 | 865 | ||
901 | /* | 866 | /* |
@@ -913,10 +878,8 @@ static void release_substream_urbs(snd_usb_substream_t *subs, int force) | |||
913 | release_urb_ctx(&subs->dataurb[i]); | 878 | release_urb_ctx(&subs->dataurb[i]); |
914 | for (i = 0; i < SYNC_URBS; i++) | 879 | for (i = 0; i < SYNC_URBS; i++) |
915 | release_urb_ctx(&subs->syncurb[i]); | 880 | release_urb_ctx(&subs->syncurb[i]); |
916 | if (subs->tmpbuf) { | 881 | kfree(subs->tmpbuf); |
917 | kfree(subs->tmpbuf); | 882 | subs->tmpbuf = NULL; |
918 | subs->tmpbuf = NULL; | ||
919 | } | ||
920 | subs->nurbs = 0; | 883 | subs->nurbs = 0; |
921 | } | 884 | } |
922 | 885 | ||
@@ -1039,22 +1002,19 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by | |||
1039 | snd_urb_ctx_t *u = &subs->syncurb[i]; | 1002 | snd_urb_ctx_t *u = &subs->syncurb[i]; |
1040 | u->index = i; | 1003 | u->index = i; |
1041 | u->subs = subs; | 1004 | u->subs = subs; |
1042 | u->packets = nrpacks; | 1005 | u->packets = 1; |
1043 | u->urb = usb_alloc_urb(u->packets, GFP_KERNEL); | 1006 | u->urb = usb_alloc_urb(1, GFP_KERNEL); |
1044 | if (! u->urb) { | 1007 | if (! u->urb) { |
1045 | release_substream_urbs(subs, 0); | 1008 | release_substream_urbs(subs, 0); |
1046 | return -ENOMEM; | 1009 | return -ENOMEM; |
1047 | } | 1010 | } |
1048 | u->urb->transfer_buffer = subs->syncbuf + i * nrpacks * 4; | 1011 | u->urb->transfer_buffer = subs->syncbuf + i * 4; |
1049 | u->urb->transfer_buffer_length = nrpacks * 4; | 1012 | u->urb->transfer_buffer_length = 4; |
1050 | u->urb->dev = subs->dev; | 1013 | u->urb->dev = subs->dev; |
1051 | u->urb->pipe = subs->syncpipe; | 1014 | u->urb->pipe = subs->syncpipe; |
1052 | u->urb->transfer_flags = URB_ISO_ASAP; | 1015 | u->urb->transfer_flags = URB_ISO_ASAP; |
1053 | u->urb->number_of_packets = u->packets; | 1016 | u->urb->number_of_packets = 1; |
1054 | if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH) | 1017 | u->urb->interval = 1 << subs->syncinterval; |
1055 | u->urb->interval = 8; | ||
1056 | else | ||
1057 | u->urb->interval = 1; | ||
1058 | u->urb->context = u; | 1018 | u->urb->context = u; |
1059 | u->urb->complete = snd_usb_complete_callback(snd_complete_sync_urb); | 1019 | u->urb->complete = snd_usb_complete_callback(snd_complete_sync_urb); |
1060 | } | 1020 | } |
@@ -1272,7 +1232,17 @@ static int set_format(snd_usb_substream_t *subs, struct audioformat *fmt) | |||
1272 | subs->syncpipe = usb_rcvisocpipe(dev, ep); | 1232 | subs->syncpipe = usb_rcvisocpipe(dev, ep); |
1273 | else | 1233 | else |
1274 | subs->syncpipe = usb_sndisocpipe(dev, ep); | 1234 | subs->syncpipe = usb_sndisocpipe(dev, ep); |
1275 | subs->syncinterval = get_endpoint(alts, 1)->bRefresh; | 1235 | if (get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE && |
1236 | get_endpoint(alts, 1)->bRefresh >= 1 && | ||
1237 | get_endpoint(alts, 1)->bRefresh <= 9) | ||
1238 | subs->syncinterval = get_endpoint(alts, 1)->bRefresh; | ||
1239 | else if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) | ||
1240 | subs->syncinterval = 1; | ||
1241 | else if (get_endpoint(alts, 1)->bInterval >= 1 && | ||
1242 | get_endpoint(alts, 1)->bInterval <= 16) | ||
1243 | subs->syncinterval = get_endpoint(alts, 1)->bInterval - 1; | ||
1244 | else | ||
1245 | subs->syncinterval = 3; | ||
1276 | } | 1246 | } |
1277 | 1247 | ||
1278 | /* always fill max packet size */ | 1248 | /* always fill max packet size */ |
@@ -1990,10 +1960,11 @@ static void proc_dump_substream_status(snd_usb_substream_t *subs, snd_info_buffe | |||
1990 | snd_iprintf(buffer, "%d ", subs->dataurb[i].packets); | 1960 | snd_iprintf(buffer, "%d ", subs->dataurb[i].packets); |
1991 | snd_iprintf(buffer, "]\n"); | 1961 | snd_iprintf(buffer, "]\n"); |
1992 | snd_iprintf(buffer, " Packet Size = %d\n", subs->curpacksize); | 1962 | snd_iprintf(buffer, " Packet Size = %d\n", subs->curpacksize); |
1993 | snd_iprintf(buffer, " Momentary freq = %u Hz\n", | 1963 | snd_iprintf(buffer, " Momentary freq = %u Hz (%#x.%04x)\n", |
1994 | snd_usb_get_speed(subs->dev) == USB_SPEED_FULL | 1964 | snd_usb_get_speed(subs->dev) == USB_SPEED_FULL |
1995 | ? get_full_speed_hz(subs->freqm) | 1965 | ? get_full_speed_hz(subs->freqm) |
1996 | : get_high_speed_hz(subs->freqm)); | 1966 | : get_high_speed_hz(subs->freqm), |
1967 | subs->freqm >> 16, subs->freqm & 0xffff); | ||
1997 | } else { | 1968 | } else { |
1998 | snd_iprintf(buffer, " Status: Stop\n"); | 1969 | snd_iprintf(buffer, " Status: Stop\n"); |
1999 | } | 1970 | } |
@@ -2183,17 +2154,15 @@ static int add_audio_endpoint(snd_usb_audio_t *chip, int stream, struct audiofor | |||
2183 | /* | 2154 | /* |
2184 | * check if the device uses big-endian samples | 2155 | * check if the device uses big-endian samples |
2185 | */ | 2156 | */ |
2186 | static int is_big_endian_format(struct usb_device *dev, struct audioformat *fp) | 2157 | static int is_big_endian_format(snd_usb_audio_t *chip, struct audioformat *fp) |
2187 | { | 2158 | { |
2188 | /* M-Audio */ | 2159 | switch (chip->usb_id) { |
2189 | if (le16_to_cpu(dev->descriptor.idVendor) == 0x0763) { | 2160 | case USB_ID(0x0763, 0x2001): /* M-Audio Quattro: captured data only */ |
2190 | /* Quattro: captured data only */ | 2161 | if (fp->endpoint & USB_DIR_IN) |
2191 | if (le16_to_cpu(dev->descriptor.idProduct) == 0x2001 && | ||
2192 | fp->endpoint & USB_DIR_IN) | ||
2193 | return 1; | ||
2194 | /* Audiophile USB */ | ||
2195 | if (le16_to_cpu(dev->descriptor.idProduct) == 0x2003) | ||
2196 | return 1; | 2162 | return 1; |
2163 | break; | ||
2164 | case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */ | ||
2165 | return 1; | ||
2197 | } | 2166 | } |
2198 | return 0; | 2167 | return 0; |
2199 | } | 2168 | } |
@@ -2207,7 +2176,7 @@ static int is_big_endian_format(struct usb_device *dev, struct audioformat *fp) | |||
2207 | * @format: the format tag (wFormatTag) | 2176 | * @format: the format tag (wFormatTag) |
2208 | * @fmt: the format type descriptor | 2177 | * @fmt: the format type descriptor |
2209 | */ | 2178 | */ |
2210 | static int parse_audio_format_i_type(struct usb_device *dev, struct audioformat *fp, | 2179 | static int parse_audio_format_i_type(snd_usb_audio_t *chip, struct audioformat *fp, |
2211 | int format, unsigned char *fmt) | 2180 | int format, unsigned char *fmt) |
2212 | { | 2181 | { |
2213 | int pcm_format; | 2182 | int pcm_format; |
@@ -2220,12 +2189,12 @@ static int parse_audio_format_i_type(struct usb_device *dev, struct audioformat | |||
2220 | switch (format) { | 2189 | switch (format) { |
2221 | case 0: /* some devices don't define this correctly... */ | 2190 | case 0: /* some devices don't define this correctly... */ |
2222 | snd_printdd(KERN_INFO "%d:%u:%d : format type 0 is detected, processed as PCM\n", | 2191 | snd_printdd(KERN_INFO "%d:%u:%d : format type 0 is detected, processed as PCM\n", |
2223 | dev->devnum, fp->iface, fp->altsetting); | 2192 | chip->dev->devnum, fp->iface, fp->altsetting); |
2224 | /* fall-through */ | 2193 | /* fall-through */ |
2225 | case USB_AUDIO_FORMAT_PCM: | 2194 | case USB_AUDIO_FORMAT_PCM: |
2226 | if (sample_width > sample_bytes * 8) { | 2195 | if (sample_width > sample_bytes * 8) { |
2227 | snd_printk(KERN_INFO "%d:%u:%d : sample bitwidth %d in over sample bytes %d\n", | 2196 | snd_printk(KERN_INFO "%d:%u:%d : sample bitwidth %d in over sample bytes %d\n", |
2228 | dev->devnum, fp->iface, fp->altsetting, | 2197 | chip->dev->devnum, fp->iface, fp->altsetting, |
2229 | sample_width, sample_bytes); | 2198 | sample_width, sample_bytes); |
2230 | } | 2199 | } |
2231 | /* check the format byte size */ | 2200 | /* check the format byte size */ |
@@ -2234,13 +2203,13 @@ static int parse_audio_format_i_type(struct usb_device *dev, struct audioformat | |||
2234 | pcm_format = SNDRV_PCM_FORMAT_S8; | 2203 | pcm_format = SNDRV_PCM_FORMAT_S8; |
2235 | break; | 2204 | break; |
2236 | case 2: | 2205 | case 2: |
2237 | if (is_big_endian_format(dev, fp)) | 2206 | if (is_big_endian_format(chip, fp)) |
2238 | pcm_format = SNDRV_PCM_FORMAT_S16_BE; /* grrr, big endian!! */ | 2207 | pcm_format = SNDRV_PCM_FORMAT_S16_BE; /* grrr, big endian!! */ |
2239 | else | 2208 | else |
2240 | pcm_format = SNDRV_PCM_FORMAT_S16_LE; | 2209 | pcm_format = SNDRV_PCM_FORMAT_S16_LE; |
2241 | break; | 2210 | break; |
2242 | case 3: | 2211 | case 3: |
2243 | if (is_big_endian_format(dev, fp)) | 2212 | if (is_big_endian_format(chip, fp)) |
2244 | pcm_format = SNDRV_PCM_FORMAT_S24_3BE; /* grrr, big endian!! */ | 2213 | pcm_format = SNDRV_PCM_FORMAT_S24_3BE; /* grrr, big endian!! */ |
2245 | else | 2214 | else |
2246 | pcm_format = SNDRV_PCM_FORMAT_S24_3LE; | 2215 | pcm_format = SNDRV_PCM_FORMAT_S24_3LE; |
@@ -2250,14 +2219,14 @@ static int parse_audio_format_i_type(struct usb_device *dev, struct audioformat | |||
2250 | break; | 2219 | break; |
2251 | default: | 2220 | default: |
2252 | snd_printk(KERN_INFO "%d:%u:%d : unsupported sample bitwidth %d in %d bytes\n", | 2221 | snd_printk(KERN_INFO "%d:%u:%d : unsupported sample bitwidth %d in %d bytes\n", |
2253 | dev->devnum, fp->iface, fp->altsetting, sample_width, sample_bytes); | 2222 | chip->dev->devnum, fp->iface, |
2223 | fp->altsetting, sample_width, sample_bytes); | ||
2254 | break; | 2224 | break; |
2255 | } | 2225 | } |
2256 | break; | 2226 | break; |
2257 | case USB_AUDIO_FORMAT_PCM8: | 2227 | case USB_AUDIO_FORMAT_PCM8: |
2258 | /* Dallas DS4201 workaround */ | 2228 | /* Dallas DS4201 workaround */ |
2259 | if (le16_to_cpu(dev->descriptor.idVendor) == 0x04fa && | 2229 | if (chip->usb_id == USB_ID(0x04fa, 0x4201)) |
2260 | le16_to_cpu(dev->descriptor.idProduct) == 0x4201) | ||
2261 | pcm_format = SNDRV_PCM_FORMAT_S8; | 2230 | pcm_format = SNDRV_PCM_FORMAT_S8; |
2262 | else | 2231 | else |
2263 | pcm_format = SNDRV_PCM_FORMAT_U8; | 2232 | pcm_format = SNDRV_PCM_FORMAT_U8; |
@@ -2273,7 +2242,7 @@ static int parse_audio_format_i_type(struct usb_device *dev, struct audioformat | |||
2273 | break; | 2242 | break; |
2274 | default: | 2243 | default: |
2275 | snd_printk(KERN_INFO "%d:%u:%d : unsupported format type %d\n", | 2244 | snd_printk(KERN_INFO "%d:%u:%d : unsupported format type %d\n", |
2276 | dev->devnum, fp->iface, fp->altsetting, format); | 2245 | chip->dev->devnum, fp->iface, fp->altsetting, format); |
2277 | break; | 2246 | break; |
2278 | } | 2247 | } |
2279 | return pcm_format; | 2248 | return pcm_format; |
@@ -2290,13 +2259,13 @@ static int parse_audio_format_i_type(struct usb_device *dev, struct audioformat | |||
2290 | * @offset: the start offset of descriptor pointing the rate type | 2259 | * @offset: the start offset of descriptor pointing the rate type |
2291 | * (7 for type I and II, 8 for type II) | 2260 | * (7 for type I and II, 8 for type II) |
2292 | */ | 2261 | */ |
2293 | static int parse_audio_format_rates(struct usb_device *dev, struct audioformat *fp, | 2262 | static int parse_audio_format_rates(snd_usb_audio_t *chip, struct audioformat *fp, |
2294 | unsigned char *fmt, int offset) | 2263 | unsigned char *fmt, int offset) |
2295 | { | 2264 | { |
2296 | int nr_rates = fmt[offset]; | 2265 | int nr_rates = fmt[offset]; |
2297 | if (fmt[0] < offset + 1 + 3 * (nr_rates ? nr_rates : 2)) { | 2266 | if (fmt[0] < offset + 1 + 3 * (nr_rates ? nr_rates : 2)) { |
2298 | snd_printk(KERN_ERR "%d:%u:%d : invalid FORMAT_TYPE desc\n", | 2267 | snd_printk(KERN_ERR "%d:%u:%d : invalid FORMAT_TYPE desc\n", |
2299 | dev->devnum, fp->iface, fp->altsetting); | 2268 | chip->dev->devnum, fp->iface, fp->altsetting); |
2300 | return -1; | 2269 | return -1; |
2301 | } | 2270 | } |
2302 | 2271 | ||
@@ -2343,7 +2312,7 @@ static int parse_audio_format_rates(struct usb_device *dev, struct audioformat * | |||
2343 | /* | 2312 | /* |
2344 | * parse the format type I and III descriptors | 2313 | * parse the format type I and III descriptors |
2345 | */ | 2314 | */ |
2346 | static int parse_audio_format_i(struct usb_device *dev, struct audioformat *fp, | 2315 | static int parse_audio_format_i(snd_usb_audio_t *chip, struct audioformat *fp, |
2347 | int format, unsigned char *fmt) | 2316 | int format, unsigned char *fmt) |
2348 | { | 2317 | { |
2349 | int pcm_format; | 2318 | int pcm_format; |
@@ -2355,7 +2324,7 @@ static int parse_audio_format_i(struct usb_device *dev, struct audioformat *fp, | |||
2355 | */ | 2324 | */ |
2356 | pcm_format = SNDRV_PCM_FORMAT_S16_LE; | 2325 | pcm_format = SNDRV_PCM_FORMAT_S16_LE; |
2357 | } else { | 2326 | } else { |
2358 | pcm_format = parse_audio_format_i_type(dev, fp, format, fmt); | 2327 | pcm_format = parse_audio_format_i_type(chip, fp, format, fmt); |
2359 | if (pcm_format < 0) | 2328 | if (pcm_format < 0) |
2360 | return -1; | 2329 | return -1; |
2361 | } | 2330 | } |
@@ -2363,16 +2332,16 @@ static int parse_audio_format_i(struct usb_device *dev, struct audioformat *fp, | |||
2363 | fp->channels = fmt[4]; | 2332 | fp->channels = fmt[4]; |
2364 | if (fp->channels < 1) { | 2333 | if (fp->channels < 1) { |
2365 | snd_printk(KERN_ERR "%d:%u:%d : invalid channels %d\n", | 2334 | snd_printk(KERN_ERR "%d:%u:%d : invalid channels %d\n", |
2366 | dev->devnum, fp->iface, fp->altsetting, fp->channels); | 2335 | chip->dev->devnum, fp->iface, fp->altsetting, fp->channels); |
2367 | return -1; | 2336 | return -1; |
2368 | } | 2337 | } |
2369 | return parse_audio_format_rates(dev, fp, fmt, 7); | 2338 | return parse_audio_format_rates(chip, fp, fmt, 7); |
2370 | } | 2339 | } |
2371 | 2340 | ||
2372 | /* | 2341 | /* |
2373 | * prase the format type II descriptor | 2342 | * prase the format type II descriptor |
2374 | */ | 2343 | */ |
2375 | static int parse_audio_format_ii(struct usb_device *dev, struct audioformat *fp, | 2344 | static int parse_audio_format_ii(snd_usb_audio_t *chip, struct audioformat *fp, |
2376 | int format, unsigned char *fmt) | 2345 | int format, unsigned char *fmt) |
2377 | { | 2346 | { |
2378 | int brate, framesize; | 2347 | int brate, framesize; |
@@ -2387,7 +2356,7 @@ static int parse_audio_format_ii(struct usb_device *dev, struct audioformat *fp, | |||
2387 | break; | 2356 | break; |
2388 | default: | 2357 | default: |
2389 | snd_printd(KERN_INFO "%d:%u:%d : unknown format tag 0x%x is detected. processed as MPEG.\n", | 2358 | snd_printd(KERN_INFO "%d:%u:%d : unknown format tag 0x%x is detected. processed as MPEG.\n", |
2390 | dev->devnum, fp->iface, fp->altsetting, format); | 2359 | chip->dev->devnum, fp->iface, fp->altsetting, format); |
2391 | fp->format = SNDRV_PCM_FORMAT_MPEG; | 2360 | fp->format = SNDRV_PCM_FORMAT_MPEG; |
2392 | break; | 2361 | break; |
2393 | } | 2362 | } |
@@ -2396,10 +2365,10 @@ static int parse_audio_format_ii(struct usb_device *dev, struct audioformat *fp, | |||
2396 | framesize = combine_word(&fmt[6]); /* fmt[6,7]: wSamplesPerFrame */ | 2365 | framesize = combine_word(&fmt[6]); /* fmt[6,7]: wSamplesPerFrame */ |
2397 | snd_printd(KERN_INFO "found format II with max.bitrate = %d, frame size=%d\n", brate, framesize); | 2366 | snd_printd(KERN_INFO "found format II with max.bitrate = %d, frame size=%d\n", brate, framesize); |
2398 | fp->frame_size = framesize; | 2367 | fp->frame_size = framesize; |
2399 | return parse_audio_format_rates(dev, fp, fmt, 8); /* fmt[8..] sample rates */ | 2368 | return parse_audio_format_rates(chip, fp, fmt, 8); /* fmt[8..] sample rates */ |
2400 | } | 2369 | } |
2401 | 2370 | ||
2402 | static int parse_audio_format(struct usb_device *dev, struct audioformat *fp, | 2371 | static int parse_audio_format(snd_usb_audio_t *chip, struct audioformat *fp, |
2403 | int format, unsigned char *fmt, int stream) | 2372 | int format, unsigned char *fmt, int stream) |
2404 | { | 2373 | { |
2405 | int err; | 2374 | int err; |
@@ -2407,29 +2376,30 @@ static int parse_audio_format(struct usb_device *dev, struct audioformat *fp, | |||
2407 | switch (fmt[3]) { | 2376 | switch (fmt[3]) { |
2408 | case USB_FORMAT_TYPE_I: | 2377 | case USB_FORMAT_TYPE_I: |
2409 | case USB_FORMAT_TYPE_III: | 2378 | case USB_FORMAT_TYPE_III: |
2410 | err = parse_audio_format_i(dev, fp, format, fmt); | 2379 | err = parse_audio_format_i(chip, fp, format, fmt); |
2411 | break; | 2380 | break; |
2412 | case USB_FORMAT_TYPE_II: | 2381 | case USB_FORMAT_TYPE_II: |
2413 | err = parse_audio_format_ii(dev, fp, format, fmt); | 2382 | err = parse_audio_format_ii(chip, fp, format, fmt); |
2414 | break; | 2383 | break; |
2415 | default: | 2384 | default: |
2416 | snd_printd(KERN_INFO "%d:%u:%d : format type %d is not supported yet\n", | 2385 | snd_printd(KERN_INFO "%d:%u:%d : format type %d is not supported yet\n", |
2417 | dev->devnum, fp->iface, fp->altsetting, fmt[3]); | 2386 | chip->dev->devnum, fp->iface, fp->altsetting, fmt[3]); |
2418 | return -1; | 2387 | return -1; |
2419 | } | 2388 | } |
2420 | fp->fmt_type = fmt[3]; | 2389 | fp->fmt_type = fmt[3]; |
2421 | if (err < 0) | 2390 | if (err < 0) |
2422 | return err; | 2391 | return err; |
2423 | #if 1 | 2392 | #if 1 |
2424 | /* FIXME: temporary hack for extigy */ | 2393 | /* FIXME: temporary hack for extigy/audigy 2 nx */ |
2425 | /* extigy apparently supports sample rates other than 48k | 2394 | /* extigy apparently supports sample rates other than 48k |
2426 | * but not in ordinary way. so we enable only 48k atm. | 2395 | * but not in ordinary way. so we enable only 48k atm. |
2427 | */ | 2396 | */ |
2428 | if (le16_to_cpu(dev->descriptor.idVendor) == 0x041e && | 2397 | if (chip->usb_id == USB_ID(0x041e, 0x3000) || |
2429 | le16_to_cpu(dev->descriptor.idProduct) == 0x3000) { | 2398 | chip->usb_id == USB_ID(0x041e, 0x3020)) { |
2430 | if (fmt[3] == USB_FORMAT_TYPE_I && | 2399 | if (fmt[3] == USB_FORMAT_TYPE_I && |
2431 | stream == SNDRV_PCM_STREAM_PLAYBACK && | 2400 | stream == SNDRV_PCM_STREAM_PLAYBACK && |
2432 | fp->rates != SNDRV_PCM_RATE_48000) | 2401 | fp->rates != SNDRV_PCM_RATE_48000 && |
2402 | fp->rates != SNDRV_PCM_RATE_96000) | ||
2433 | return -1; /* use 48k only */ | 2403 | return -1; /* use 48k only */ |
2434 | } | 2404 | } |
2435 | #endif | 2405 | #endif |
@@ -2528,40 +2498,35 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no) | |||
2528 | 2498 | ||
2529 | /* some quirks for attributes here */ | 2499 | /* some quirks for attributes here */ |
2530 | 2500 | ||
2531 | /* workaround for AudioTrak Optoplay */ | 2501 | switch (chip->usb_id) { |
2532 | if (le16_to_cpu(dev->descriptor.idVendor) == 0x0a92 && | 2502 | case USB_ID(0x0a92, 0x0053): /* AudioTrak Optoplay */ |
2533 | le16_to_cpu(dev->descriptor.idProduct) == 0x0053) { | ||
2534 | /* Optoplay sets the sample rate attribute although | 2503 | /* Optoplay sets the sample rate attribute although |
2535 | * it seems not supporting it in fact. | 2504 | * it seems not supporting it in fact. |
2536 | */ | 2505 | */ |
2537 | fp->attributes &= ~EP_CS_ATTR_SAMPLE_RATE; | 2506 | fp->attributes &= ~EP_CS_ATTR_SAMPLE_RATE; |
2538 | } | 2507 | break; |
2539 | 2508 | case USB_ID(0x041e, 0x3020): /* Creative SB Audigy 2 NX */ | |
2540 | /* workaround for M-Audio Audiophile USB */ | 2509 | case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */ |
2541 | if (le16_to_cpu(dev->descriptor.idVendor) == 0x0763 && | ||
2542 | le16_to_cpu(dev->descriptor.idProduct) == 0x2003) { | ||
2543 | /* doesn't set the sample rate attribute, but supports it */ | 2510 | /* doesn't set the sample rate attribute, but supports it */ |
2544 | fp->attributes |= EP_CS_ATTR_SAMPLE_RATE; | 2511 | fp->attributes |= EP_CS_ATTR_SAMPLE_RATE; |
2545 | } | 2512 | break; |
2546 | 2513 | case USB_ID(0x047f, 0x0ca1): /* plantronics headset */ | |
2514 | case USB_ID(0x077d, 0x07af): /* Griffin iMic (note that there is | ||
2515 | an older model 77d:223) */ | ||
2547 | /* | 2516 | /* |
2548 | * plantronics headset and Griffin iMic have set adaptive-in | 2517 | * plantronics headset and Griffin iMic have set adaptive-in |
2549 | * although it's really not... | 2518 | * although it's really not... |
2550 | */ | 2519 | */ |
2551 | if ((le16_to_cpu(dev->descriptor.idVendor) == 0x047f && | ||
2552 | le16_to_cpu(dev->descriptor.idProduct) == 0x0ca1) || | ||
2553 | /* Griffin iMic (note that there is an older model 77d:223) */ | ||
2554 | (le16_to_cpu(dev->descriptor.idVendor) == 0x077d && | ||
2555 | le16_to_cpu(dev->descriptor.idProduct) == 0x07af)) { | ||
2556 | fp->ep_attr &= ~EP_ATTR_MASK; | 2520 | fp->ep_attr &= ~EP_ATTR_MASK; |
2557 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) | 2521 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) |
2558 | fp->ep_attr |= EP_ATTR_ADAPTIVE; | 2522 | fp->ep_attr |= EP_ATTR_ADAPTIVE; |
2559 | else | 2523 | else |
2560 | fp->ep_attr |= EP_ATTR_SYNC; | 2524 | fp->ep_attr |= EP_ATTR_SYNC; |
2525 | break; | ||
2561 | } | 2526 | } |
2562 | 2527 | ||
2563 | /* ok, let's parse further... */ | 2528 | /* ok, let's parse further... */ |
2564 | if (parse_audio_format(dev, fp, format, fmt, stream) < 0) { | 2529 | if (parse_audio_format(chip, fp, format, fmt, stream) < 0) { |
2565 | kfree(fp->rate_table); | 2530 | kfree(fp->rate_table); |
2566 | kfree(fp); | 2531 | kfree(fp); |
2567 | continue; | 2532 | continue; |
@@ -2587,7 +2552,7 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no) | |||
2587 | * disconnect streams | 2552 | * disconnect streams |
2588 | * called from snd_usb_audio_disconnect() | 2553 | * called from snd_usb_audio_disconnect() |
2589 | */ | 2554 | */ |
2590 | static void snd_usb_stream_disconnect(struct list_head *head, struct usb_driver *driver) | 2555 | static void snd_usb_stream_disconnect(struct list_head *head) |
2591 | { | 2556 | { |
2592 | int idx; | 2557 | int idx; |
2593 | snd_usb_stream_t *as; | 2558 | snd_usb_stream_t *as; |
@@ -2796,7 +2761,7 @@ static int create_ua700_ua25_quirk(snd_usb_audio_t *chip, | |||
2796 | .type = QUIRK_MIDI_FIXED_ENDPOINT, | 2761 | .type = QUIRK_MIDI_FIXED_ENDPOINT, |
2797 | .data = &ua25_ep | 2762 | .data = &ua25_ep |
2798 | }; | 2763 | }; |
2799 | if (le16_to_cpu(chip->dev->descriptor.idProduct) == 0x002b) | 2764 | if (chip->usb_id == USB_ID(0x0582, 0x002b)) |
2800 | return snd_usb_create_midi_interface(chip, iface, | 2765 | return snd_usb_create_midi_interface(chip, iface, |
2801 | &ua700_quirk); | 2766 | &ua700_quirk); |
2802 | else | 2767 | else |
@@ -2959,6 +2924,25 @@ static int snd_usb_extigy_boot_quirk(struct usb_device *dev, struct usb_interfac | |||
2959 | return 0; | 2924 | return 0; |
2960 | } | 2925 | } |
2961 | 2926 | ||
2927 | static int snd_usb_audigy2nx_boot_quirk(struct usb_device *dev) | ||
2928 | { | ||
2929 | #if 0 | ||
2930 | /* TODO: enable this when high speed synchronization actually works */ | ||
2931 | u8 buf = 1; | ||
2932 | |||
2933 | snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), 0x2a, | ||
2934 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER, | ||
2935 | 0, 0, &buf, 1, 1000); | ||
2936 | if (buf == 0) { | ||
2937 | snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), 0x29, | ||
2938 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, | ||
2939 | 1, 2000, NULL, 0, 1000); | ||
2940 | return -ENODEV; | ||
2941 | } | ||
2942 | #endif | ||
2943 | return 0; | ||
2944 | } | ||
2945 | |||
2962 | 2946 | ||
2963 | /* | 2947 | /* |
2964 | * audio-interface quirks | 2948 | * audio-interface quirks |
@@ -3015,8 +2999,8 @@ static void proc_audio_usbid_read(snd_info_entry_t *entry, snd_info_buffer_t *bu | |||
3015 | snd_usb_audio_t *chip = entry->private_data; | 2999 | snd_usb_audio_t *chip = entry->private_data; |
3016 | if (! chip->shutdown) | 3000 | if (! chip->shutdown) |
3017 | snd_iprintf(buffer, "%04x:%04x\n", | 3001 | snd_iprintf(buffer, "%04x:%04x\n", |
3018 | le16_to_cpu(chip->dev->descriptor.idVendor), | 3002 | USB_ID_VENDOR(chip->usb_id), |
3019 | le16_to_cpu(chip->dev->descriptor.idProduct)); | 3003 | USB_ID_PRODUCT(chip->usb_id)); |
3020 | } | 3004 | } |
3021 | 3005 | ||
3022 | static void snd_usb_audio_create_proc(snd_usb_audio_t *chip) | 3006 | static void snd_usb_audio_create_proc(snd_usb_audio_t *chip) |
@@ -3086,8 +3070,11 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, | |||
3086 | chip->index = idx; | 3070 | chip->index = idx; |
3087 | chip->dev = dev; | 3071 | chip->dev = dev; |
3088 | chip->card = card; | 3072 | chip->card = card; |
3073 | chip->usb_id = USB_ID(le16_to_cpu(dev->descriptor.idVendor), | ||
3074 | le16_to_cpu(dev->descriptor.idProduct)); | ||
3089 | INIT_LIST_HEAD(&chip->pcm_list); | 3075 | INIT_LIST_HEAD(&chip->pcm_list); |
3090 | INIT_LIST_HEAD(&chip->midi_list); | 3076 | INIT_LIST_HEAD(&chip->midi_list); |
3077 | INIT_LIST_HEAD(&chip->mixer_list); | ||
3091 | 3078 | ||
3092 | if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { | 3079 | if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { |
3093 | snd_usb_audio_free(chip); | 3080 | snd_usb_audio_free(chip); |
@@ -3097,8 +3084,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, | |||
3097 | 3084 | ||
3098 | strcpy(card->driver, "USB-Audio"); | 3085 | strcpy(card->driver, "USB-Audio"); |
3099 | sprintf(component, "USB%04x:%04x", | 3086 | sprintf(component, "USB%04x:%04x", |
3100 | le16_to_cpu(dev->descriptor.idVendor), | 3087 | USB_ID_VENDOR(chip->usb_id), USB_ID_PRODUCT(chip->usb_id)); |
3101 | le16_to_cpu(dev->descriptor.idProduct)); | ||
3102 | snd_component_add(card, component); | 3088 | snd_component_add(card, component); |
3103 | 3089 | ||
3104 | /* retrieve the device string as shortname */ | 3090 | /* retrieve the device string as shortname */ |
@@ -3110,8 +3096,8 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, | |||
3110 | card->shortname, sizeof(card->shortname)) <= 0) { | 3096 | card->shortname, sizeof(card->shortname)) <= 0) { |
3111 | /* no name available from anywhere, so use ID */ | 3097 | /* no name available from anywhere, so use ID */ |
3112 | sprintf(card->shortname, "USB Device %#04x:%#04x", | 3098 | sprintf(card->shortname, "USB Device %#04x:%#04x", |
3113 | le16_to_cpu(dev->descriptor.idVendor), | 3099 | USB_ID_VENDOR(chip->usb_id), |
3114 | le16_to_cpu(dev->descriptor.idProduct)); | 3100 | USB_ID_PRODUCT(chip->usb_id)); |
3115 | } | 3101 | } |
3116 | } | 3102 | } |
3117 | 3103 | ||
@@ -3142,8 +3128,6 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, | |||
3142 | 3128 | ||
3143 | snd_usb_audio_create_proc(chip); | 3129 | snd_usb_audio_create_proc(chip); |
3144 | 3130 | ||
3145 | snd_card_set_dev(card, &dev->dev); | ||
3146 | |||
3147 | *rchip = chip; | 3131 | *rchip = chip; |
3148 | return 0; | 3132 | return 0; |
3149 | } | 3133 | } |
@@ -3169,21 +3153,28 @@ static void *snd_usb_audio_probe(struct usb_device *dev, | |||
3169 | snd_usb_audio_t *chip; | 3153 | snd_usb_audio_t *chip; |
3170 | struct usb_host_interface *alts; | 3154 | struct usb_host_interface *alts; |
3171 | int ifnum; | 3155 | int ifnum; |
3156 | u32 id; | ||
3172 | 3157 | ||
3173 | alts = &intf->altsetting[0]; | 3158 | alts = &intf->altsetting[0]; |
3174 | ifnum = get_iface_desc(alts)->bInterfaceNumber; | 3159 | ifnum = get_iface_desc(alts)->bInterfaceNumber; |
3160 | id = USB_ID(le16_to_cpu(dev->descriptor.idVendor), | ||
3161 | le16_to_cpu(dev->descriptor.idProduct)); | ||
3175 | 3162 | ||
3176 | if (quirk && quirk->ifnum >= 0 && ifnum != quirk->ifnum) | 3163 | if (quirk && quirk->ifnum >= 0 && ifnum != quirk->ifnum) |
3177 | goto __err_val; | 3164 | goto __err_val; |
3178 | 3165 | ||
3179 | /* SB Extigy needs special boot-up sequence */ | 3166 | /* SB Extigy needs special boot-up sequence */ |
3180 | /* if more models come, this will go to the quirk list. */ | 3167 | /* if more models come, this will go to the quirk list. */ |
3181 | if (le16_to_cpu(dev->descriptor.idVendor) == 0x041e && | 3168 | if (id == USB_ID(0x041e, 0x3000)) { |
3182 | le16_to_cpu(dev->descriptor.idProduct) == 0x3000) { | ||
3183 | if (snd_usb_extigy_boot_quirk(dev, intf) < 0) | 3169 | if (snd_usb_extigy_boot_quirk(dev, intf) < 0) |
3184 | goto __err_val; | 3170 | goto __err_val; |
3185 | config = dev->actconfig; | 3171 | config = dev->actconfig; |
3186 | } | 3172 | } |
3173 | /* SB Audigy 2 NX needs its own boot-up magic, too */ | ||
3174 | if (id == USB_ID(0x041e, 0x3020)) { | ||
3175 | if (snd_usb_audigy2nx_boot_quirk(dev) < 0) | ||
3176 | goto __err_val; | ||
3177 | } | ||
3187 | 3178 | ||
3188 | /* | 3179 | /* |
3189 | * found a config. now register to ALSA | 3180 | * found a config. now register to ALSA |
@@ -3213,11 +3204,12 @@ static void *snd_usb_audio_probe(struct usb_device *dev, | |||
3213 | } | 3204 | } |
3214 | for (i = 0; i < SNDRV_CARDS; i++) | 3205 | for (i = 0; i < SNDRV_CARDS; i++) |
3215 | if (enable[i] && ! usb_chip[i] && | 3206 | if (enable[i] && ! usb_chip[i] && |
3216 | (vid[i] == -1 || vid[i] == le16_to_cpu(dev->descriptor.idVendor)) && | 3207 | (vid[i] == -1 || vid[i] == USB_ID_VENDOR(id)) && |
3217 | (pid[i] == -1 || pid[i] == le16_to_cpu(dev->descriptor.idProduct))) { | 3208 | (pid[i] == -1 || pid[i] == USB_ID_PRODUCT(id))) { |
3218 | if (snd_usb_audio_create(dev, i, quirk, &chip) < 0) { | 3209 | if (snd_usb_audio_create(dev, i, quirk, &chip) < 0) { |
3219 | goto __error; | 3210 | goto __error; |
3220 | } | 3211 | } |
3212 | snd_card_set_dev(chip->card, &intf->dev); | ||
3221 | break; | 3213 | break; |
3222 | } | 3214 | } |
3223 | if (! chip) { | 3215 | if (! chip) { |
@@ -3281,11 +3273,15 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr) | |||
3281 | snd_card_disconnect(card); | 3273 | snd_card_disconnect(card); |
3282 | /* release the pcm resources */ | 3274 | /* release the pcm resources */ |
3283 | list_for_each(p, &chip->pcm_list) { | 3275 | list_for_each(p, &chip->pcm_list) { |
3284 | snd_usb_stream_disconnect(p, &usb_audio_driver); | 3276 | snd_usb_stream_disconnect(p); |
3285 | } | 3277 | } |
3286 | /* release the midi resources */ | 3278 | /* release the midi resources */ |
3287 | list_for_each(p, &chip->midi_list) { | 3279 | list_for_each(p, &chip->midi_list) { |
3288 | snd_usbmidi_disconnect(p, &usb_audio_driver); | 3280 | snd_usbmidi_disconnect(p); |
3281 | } | ||
3282 | /* release mixer resources */ | ||
3283 | list_for_each(p, &chip->mixer_list) { | ||
3284 | snd_usb_mixer_disconnect(p); | ||
3289 | } | 3285 | } |
3290 | usb_chip[chip->index] = NULL; | 3286 | usb_chip[chip->index] = NULL; |
3291 | up(®ister_mutex); | 3287 | up(®ister_mutex); |
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index eecbf19fcb6f..aedb42aaa749 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h | |||
@@ -118,6 +118,11 @@ | |||
118 | /* maximum number of endpoints per interface */ | 118 | /* maximum number of endpoints per interface */ |
119 | #define MIDI_MAX_ENDPOINTS 2 | 119 | #define MIDI_MAX_ENDPOINTS 2 |
120 | 120 | ||
121 | /* handling of USB vendor/product ID pairs as 32-bit numbers */ | ||
122 | #define USB_ID(vendor, product) (((vendor) << 16) | (product)) | ||
123 | #define USB_ID_VENDOR(id) ((id) >> 16) | ||
124 | #define USB_ID_PRODUCT(id) ((u16)(id)) | ||
125 | |||
121 | /* | 126 | /* |
122 | */ | 127 | */ |
123 | 128 | ||
@@ -127,6 +132,7 @@ struct snd_usb_audio { | |||
127 | int index; | 132 | int index; |
128 | struct usb_device *dev; | 133 | struct usb_device *dev; |
129 | snd_card_t *card; | 134 | snd_card_t *card; |
135 | u32 usb_id; | ||
130 | int shutdown; | 136 | int shutdown; |
131 | int num_interfaces; | 137 | int num_interfaces; |
132 | 138 | ||
@@ -136,7 +142,7 @@ struct snd_usb_audio { | |||
136 | struct list_head midi_list; /* list of midi interfaces */ | 142 | struct list_head midi_list; /* list of midi interfaces */ |
137 | int next_midi_device; | 143 | int next_midi_device; |
138 | 144 | ||
139 | unsigned int ignore_ctl_error; /* for mixer */ | 145 | struct list_head mixer_list; /* list of mixer interfaces */ |
140 | }; | 146 | }; |
141 | 147 | ||
142 | /* | 148 | /* |
@@ -219,11 +225,12 @@ void *snd_usb_find_csint_desc(void *descstart, int desclen, void *after, u8 dsub | |||
219 | 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); | 225 | 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); |
220 | 226 | ||
221 | int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif); | 227 | int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif); |
228 | void snd_usb_mixer_disconnect(struct list_head *p); | ||
222 | 229 | ||
223 | int snd_usb_create_midi_interface(snd_usb_audio_t *chip, struct usb_interface *iface, const snd_usb_audio_quirk_t *quirk); | 230 | int snd_usb_create_midi_interface(snd_usb_audio_t *chip, struct usb_interface *iface, const snd_usb_audio_quirk_t *quirk); |
224 | void snd_usbmidi_input_stop(struct list_head* p); | 231 | void snd_usbmidi_input_stop(struct list_head* p); |
225 | void snd_usbmidi_input_start(struct list_head* p); | 232 | void snd_usbmidi_input_start(struct list_head* p); |
226 | void snd_usbmidi_disconnect(struct list_head *p, struct usb_driver *driver); | 233 | void snd_usbmidi_disconnect(struct list_head *p); |
227 | 234 | ||
228 | /* | 235 | /* |
229 | * retrieve usb_interface descriptor from the host interface | 236 | * retrieve usb_interface descriptor from the host interface |
diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c index 5d32857ff955..bee70068dce0 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/usbmidi.c | |||
@@ -912,7 +912,7 @@ static void snd_usbmidi_free(snd_usb_midi_t* umidi) | |||
912 | /* | 912 | /* |
913 | * Unlinks all URBs (must be done before the usb_device is deleted). | 913 | * Unlinks all URBs (must be done before the usb_device is deleted). |
914 | */ | 914 | */ |
915 | void snd_usbmidi_disconnect(struct list_head* p, struct usb_driver *driver) | 915 | void snd_usbmidi_disconnect(struct list_head* p) |
916 | { | 916 | { |
917 | snd_usb_midi_t* umidi; | 917 | snd_usb_midi_t* umidi; |
918 | int i; | 918 | int i; |
@@ -955,88 +955,87 @@ static snd_rawmidi_substream_t* snd_usbmidi_find_substream(snd_usb_midi_t* umidi | |||
955 | * such as internal control or synthesizer ports. | 955 | * such as internal control or synthesizer ports. |
956 | */ | 956 | */ |
957 | static struct { | 957 | static struct { |
958 | __u16 vendor; | 958 | u32 id; |
959 | __u16 product; | ||
960 | int port; | 959 | int port; |
961 | const char *name_format; | 960 | const char *name_format; |
962 | } snd_usbmidi_port_names[] = { | 961 | } snd_usbmidi_port_names[] = { |
963 | /* Roland UA-100 */ | 962 | /* Roland UA-100 */ |
964 | {0x0582, 0x0000, 2, "%s Control"}, | 963 | { USB_ID(0x0582, 0x0000), 2, "%s Control" }, |
965 | /* Roland SC-8850 */ | 964 | /* Roland SC-8850 */ |
966 | {0x0582, 0x0003, 0, "%s Part A"}, | 965 | { USB_ID(0x0582, 0x0003), 0, "%s Part A" }, |
967 | {0x0582, 0x0003, 1, "%s Part B"}, | 966 | { USB_ID(0x0582, 0x0003), 1, "%s Part B" }, |
968 | {0x0582, 0x0003, 2, "%s Part C"}, | 967 | { USB_ID(0x0582, 0x0003), 2, "%s Part C" }, |
969 | {0x0582, 0x0003, 3, "%s Part D"}, | 968 | { USB_ID(0x0582, 0x0003), 3, "%s Part D" }, |
970 | {0x0582, 0x0003, 4, "%s MIDI 1"}, | 969 | { USB_ID(0x0582, 0x0003), 4, "%s MIDI 1" }, |
971 | {0x0582, 0x0003, 5, "%s MIDI 2"}, | 970 | { USB_ID(0x0582, 0x0003), 5, "%s MIDI 2" }, |
972 | /* Roland U-8 */ | 971 | /* Roland U-8 */ |
973 | {0x0582, 0x0004, 0, "%s MIDI"}, | 972 | { USB_ID(0x0582, 0x0004), 0, "%s MIDI" }, |
974 | {0x0582, 0x0004, 1, "%s Control"}, | 973 | { USB_ID(0x0582, 0x0004), 1, "%s Control" }, |
975 | /* Roland SC-8820 */ | 974 | /* Roland SC-8820 */ |
976 | {0x0582, 0x0007, 0, "%s Part A"}, | 975 | { USB_ID(0x0582, 0x0007), 0, "%s Part A" }, |
977 | {0x0582, 0x0007, 1, "%s Part B"}, | 976 | { USB_ID(0x0582, 0x0007), 1, "%s Part B" }, |
978 | {0x0582, 0x0007, 2, "%s MIDI"}, | 977 | { USB_ID(0x0582, 0x0007), 2, "%s MIDI" }, |
979 | /* Roland SK-500 */ | 978 | /* Roland SK-500 */ |
980 | {0x0582, 0x000b, 0, "%s Part A"}, | 979 | { USB_ID(0x0582, 0x000b), 0, "%s Part A" }, |
981 | {0x0582, 0x000b, 1, "%s Part B"}, | 980 | { USB_ID(0x0582, 0x000b), 1, "%s Part B" }, |
982 | {0x0582, 0x000b, 2, "%s MIDI"}, | 981 | { USB_ID(0x0582, 0x000b), 2, "%s MIDI" }, |
983 | /* Roland SC-D70 */ | 982 | /* Roland SC-D70 */ |
984 | {0x0582, 0x000c, 0, "%s Part A"}, | 983 | { USB_ID(0x0582, 0x000c), 0, "%s Part A" }, |
985 | {0x0582, 0x000c, 1, "%s Part B"}, | 984 | { USB_ID(0x0582, 0x000c), 1, "%s Part B" }, |
986 | {0x0582, 0x000c, 2, "%s MIDI"}, | 985 | { USB_ID(0x0582, 0x000c), 2, "%s MIDI" }, |
987 | /* Edirol UM-880 */ | 986 | /* Edirol UM-880 */ |
988 | {0x0582, 0x0014, 8, "%s Control"}, | 987 | { USB_ID(0x0582, 0x0014), 8, "%s Control" }, |
989 | /* Edirol SD-90 */ | 988 | /* Edirol SD-90 */ |
990 | {0x0582, 0x0016, 0, "%s Part A"}, | 989 | { USB_ID(0x0582, 0x0016), 0, "%s Part A" }, |
991 | {0x0582, 0x0016, 1, "%s Part B"}, | 990 | { USB_ID(0x0582, 0x0016), 1, "%s Part B" }, |
992 | {0x0582, 0x0016, 2, "%s MIDI 1"}, | 991 | { USB_ID(0x0582, 0x0016), 2, "%s MIDI 1" }, |
993 | {0x0582, 0x0016, 3, "%s MIDI 2"}, | 992 | { USB_ID(0x0582, 0x0016), 3, "%s MIDI 2" }, |
994 | /* Edirol UM-550 */ | 993 | /* Edirol UM-550 */ |
995 | {0x0582, 0x0023, 5, "%s Control"}, | 994 | { USB_ID(0x0582, 0x0023), 5, "%s Control" }, |
996 | /* Edirol SD-20 */ | 995 | /* Edirol SD-20 */ |
997 | {0x0582, 0x0027, 0, "%s Part A"}, | 996 | { USB_ID(0x0582, 0x0027), 0, "%s Part A" }, |
998 | {0x0582, 0x0027, 1, "%s Part B"}, | 997 | { USB_ID(0x0582, 0x0027), 1, "%s Part B" }, |
999 | {0x0582, 0x0027, 2, "%s MIDI"}, | 998 | { USB_ID(0x0582, 0x0027), 2, "%s MIDI" }, |
1000 | /* Edirol SD-80 */ | 999 | /* Edirol SD-80 */ |
1001 | {0x0582, 0x0029, 0, "%s Part A"}, | 1000 | { USB_ID(0x0582, 0x0029), 0, "%s Part A" }, |
1002 | {0x0582, 0x0029, 1, "%s Part B"}, | 1001 | { USB_ID(0x0582, 0x0029), 1, "%s Part B" }, |
1003 | {0x0582, 0x0029, 2, "%s MIDI 1"}, | 1002 | { USB_ID(0x0582, 0x0029), 2, "%s MIDI 1" }, |
1004 | {0x0582, 0x0029, 3, "%s MIDI 2"}, | 1003 | { USB_ID(0x0582, 0x0029), 3, "%s MIDI 2" }, |
1005 | /* Edirol UA-700 */ | 1004 | /* Edirol UA-700 */ |
1006 | {0x0582, 0x002b, 0, "%s MIDI"}, | 1005 | { USB_ID(0x0582, 0x002b), 0, "%s MIDI" }, |
1007 | {0x0582, 0x002b, 1, "%s Control"}, | 1006 | { USB_ID(0x0582, 0x002b), 1, "%s Control" }, |
1008 | /* Roland VariOS */ | 1007 | /* Roland VariOS */ |
1009 | {0x0582, 0x002f, 0, "%s MIDI"}, | 1008 | { USB_ID(0x0582, 0x002f), 0, "%s MIDI" }, |
1010 | {0x0582, 0x002f, 1, "%s External MIDI"}, | 1009 | { USB_ID(0x0582, 0x002f), 1, "%s External MIDI" }, |
1011 | {0x0582, 0x002f, 2, "%s Sync"}, | 1010 | { USB_ID(0x0582, 0x002f), 2, "%s Sync" }, |
1012 | /* Edirol PCR */ | 1011 | /* Edirol PCR */ |
1013 | {0x0582, 0x0033, 0, "%s MIDI"}, | 1012 | { USB_ID(0x0582, 0x0033), 0, "%s MIDI" }, |
1014 | {0x0582, 0x0033, 1, "%s 1"}, | 1013 | { USB_ID(0x0582, 0x0033), 1, "%s 1" }, |
1015 | {0x0582, 0x0033, 2, "%s 2"}, | 1014 | { USB_ID(0x0582, 0x0033), 2, "%s 2" }, |
1016 | /* BOSS GS-10 */ | 1015 | /* BOSS GS-10 */ |
1017 | {0x0582, 0x003b, 0, "%s MIDI"}, | 1016 | { USB_ID(0x0582, 0x003b), 0, "%s MIDI" }, |
1018 | {0x0582, 0x003b, 1, "%s Control"}, | 1017 | { USB_ID(0x0582, 0x003b), 1, "%s Control" }, |
1019 | /* Edirol UA-1000 */ | 1018 | /* Edirol UA-1000 */ |
1020 | {0x0582, 0x0044, 0, "%s MIDI"}, | 1019 | { USB_ID(0x0582, 0x0044), 0, "%s MIDI" }, |
1021 | {0x0582, 0x0044, 1, "%s Control"}, | 1020 | { USB_ID(0x0582, 0x0044), 1, "%s Control" }, |
1022 | /* Edirol UR-80 */ | 1021 | /* Edirol UR-80 */ |
1023 | {0x0582, 0x0048, 0, "%s MIDI"}, | 1022 | { USB_ID(0x0582, 0x0048), 0, "%s MIDI" }, |
1024 | {0x0582, 0x0048, 1, "%s 1"}, | 1023 | { USB_ID(0x0582, 0x0048), 1, "%s 1" }, |
1025 | {0x0582, 0x0048, 2, "%s 2"}, | 1024 | { USB_ID(0x0582, 0x0048), 2, "%s 2" }, |
1026 | /* Edirol PCR-A */ | 1025 | /* Edirol PCR-A */ |
1027 | {0x0582, 0x004d, 0, "%s MIDI"}, | 1026 | { USB_ID(0x0582, 0x004d), 0, "%s MIDI" }, |
1028 | {0x0582, 0x004d, 1, "%s 1"}, | 1027 | { USB_ID(0x0582, 0x004d), 1, "%s 1" }, |
1029 | {0x0582, 0x004d, 2, "%s 2"}, | 1028 | { USB_ID(0x0582, 0x004d), 2, "%s 2" }, |
1030 | /* M-Audio MidiSport 8x8 */ | 1029 | /* M-Audio MidiSport 8x8 */ |
1031 | {0x0763, 0x1031, 8, "%s Control"}, | 1030 | { USB_ID(0x0763, 0x1031), 8, "%s Control" }, |
1032 | {0x0763, 0x1033, 8, "%s Control"}, | 1031 | { USB_ID(0x0763, 0x1033), 8, "%s Control" }, |
1033 | /* MOTU Fastlane */ | 1032 | /* MOTU Fastlane */ |
1034 | {0x07fd, 0x0001, 0, "%s MIDI A"}, | 1033 | { USB_ID(0x07fd, 0x0001), 0, "%s MIDI A" }, |
1035 | {0x07fd, 0x0001, 1, "%s MIDI B"}, | 1034 | { USB_ID(0x07fd, 0x0001), 1, "%s MIDI B" }, |
1036 | /* Emagic Unitor8/AMT8/MT4 */ | 1035 | /* Emagic Unitor8/AMT8/MT4 */ |
1037 | {0x086a, 0x0001, 8, "%s Broadcast"}, | 1036 | { USB_ID(0x086a, 0x0001), 8, "%s Broadcast" }, |
1038 | {0x086a, 0x0002, 8, "%s Broadcast"}, | 1037 | { USB_ID(0x086a, 0x0002), 8, "%s Broadcast" }, |
1039 | {0x086a, 0x0003, 4, "%s Broadcast"}, | 1038 | { USB_ID(0x086a, 0x0003), 4, "%s Broadcast" }, |
1040 | }; | 1039 | }; |
1041 | 1040 | ||
1042 | static void snd_usbmidi_init_substream(snd_usb_midi_t* umidi, | 1041 | static void snd_usbmidi_init_substream(snd_usb_midi_t* umidi, |
@@ -1044,7 +1043,6 @@ static void snd_usbmidi_init_substream(snd_usb_midi_t* umidi, | |||
1044 | snd_rawmidi_substream_t** rsubstream) | 1043 | snd_rawmidi_substream_t** rsubstream) |
1045 | { | 1044 | { |
1046 | int i; | 1045 | int i; |
1047 | __u16 vendor, product; | ||
1048 | const char *name_format; | 1046 | const char *name_format; |
1049 | 1047 | ||
1050 | snd_rawmidi_substream_t* substream = snd_usbmidi_find_substream(umidi, stream, number); | 1048 | snd_rawmidi_substream_t* substream = snd_usbmidi_find_substream(umidi, stream, number); |
@@ -1055,11 +1053,8 @@ static void snd_usbmidi_init_substream(snd_usb_midi_t* umidi, | |||
1055 | 1053 | ||
1056 | /* TODO: read port name from jack descriptor */ | 1054 | /* TODO: read port name from jack descriptor */ |
1057 | name_format = "%s MIDI %d"; | 1055 | name_format = "%s MIDI %d"; |
1058 | vendor = le16_to_cpu(umidi->chip->dev->descriptor.idVendor); | ||
1059 | product = le16_to_cpu(umidi->chip->dev->descriptor.idProduct); | ||
1060 | for (i = 0; i < ARRAY_SIZE(snd_usbmidi_port_names); ++i) { | 1056 | for (i = 0; i < ARRAY_SIZE(snd_usbmidi_port_names); ++i) { |
1061 | if (snd_usbmidi_port_names[i].vendor == vendor && | 1057 | if (snd_usbmidi_port_names[i].id == umidi->chip->usb_id && |
1062 | snd_usbmidi_port_names[i].product == product && | ||
1063 | snd_usbmidi_port_names[i].port == number) { | 1058 | snd_usbmidi_port_names[i].port == number) { |
1064 | name_format = snd_usbmidi_port_names[i].name_format; | 1059 | name_format = snd_usbmidi_port_names[i].name_format; |
1065 | break; | 1060 | break; |
@@ -1226,9 +1221,12 @@ static int snd_usbmidi_detect_endpoints(snd_usb_midi_t* umidi, | |||
1226 | struct usb_endpoint_descriptor* epd; | 1221 | struct usb_endpoint_descriptor* epd; |
1227 | int i, out_eps = 0, in_eps = 0; | 1222 | int i, out_eps = 0, in_eps = 0; |
1228 | 1223 | ||
1229 | if (le16_to_cpu(umidi->chip->dev->descriptor.idVendor) == 0x0582) | 1224 | if (USB_ID_VENDOR(umidi->chip->usb_id) == 0x0582) |
1230 | snd_usbmidi_switch_roland_altsetting(umidi); | 1225 | snd_usbmidi_switch_roland_altsetting(umidi); |
1231 | 1226 | ||
1227 | if (endpoint[0].out_ep || endpoint[0].in_ep) | ||
1228 | return 0; | ||
1229 | |||
1232 | intf = umidi->iface; | 1230 | intf = umidi->iface; |
1233 | if (!intf || intf->num_altsetting < 1) | 1231 | if (!intf || intf->num_altsetting < 1) |
1234 | return -ENOENT; | 1232 | return -ENOENT; |
diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index 5f1906915aa6..e73c1c9d3e73 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c | |||
@@ -35,10 +35,11 @@ | |||
35 | #include <linux/usb.h> | 35 | #include <linux/usb.h> |
36 | #include <sound/core.h> | 36 | #include <sound/core.h> |
37 | #include <sound/control.h> | 37 | #include <sound/control.h> |
38 | #include <sound/hwdep.h> | ||
39 | #include <sound/info.h> | ||
38 | 40 | ||
39 | #include "usbaudio.h" | 41 | #include "usbaudio.h" |
40 | 42 | ||
41 | |||
42 | /* | 43 | /* |
43 | */ | 44 | */ |
44 | 45 | ||
@@ -50,6 +51,31 @@ typedef struct usb_audio_term usb_audio_term_t; | |||
50 | typedef struct usb_mixer_elem_info usb_mixer_elem_info_t; | 51 | typedef struct usb_mixer_elem_info usb_mixer_elem_info_t; |
51 | 52 | ||
52 | 53 | ||
54 | struct usb_mixer_interface { | ||
55 | snd_usb_audio_t *chip; | ||
56 | unsigned int ctrlif; | ||
57 | struct list_head list; | ||
58 | unsigned int ignore_ctl_error; | ||
59 | struct urb *urb; | ||
60 | usb_mixer_elem_info_t **id_elems; /* array[256], indexed by unit id */ | ||
61 | |||
62 | /* Sound Blaster remote control stuff */ | ||
63 | enum { | ||
64 | RC_NONE, | ||
65 | RC_EXTIGY, | ||
66 | RC_AUDIGY2NX, | ||
67 | } rc_type; | ||
68 | unsigned long rc_hwdep_open; | ||
69 | u32 rc_code; | ||
70 | wait_queue_head_t rc_waitq; | ||
71 | struct urb *rc_urb; | ||
72 | struct usb_ctrlrequest *rc_setup_packet; | ||
73 | u8 rc_buffer[6]; | ||
74 | |||
75 | u8 audigy2nx_leds[3]; | ||
76 | }; | ||
77 | |||
78 | |||
53 | struct usb_audio_term { | 79 | struct usb_audio_term { |
54 | int id; | 80 | int id; |
55 | int type; | 81 | int type; |
@@ -62,26 +88,26 @@ struct usbmix_name_map; | |||
62 | 88 | ||
63 | struct usb_mixer_build { | 89 | struct usb_mixer_build { |
64 | snd_usb_audio_t *chip; | 90 | snd_usb_audio_t *chip; |
91 | struct usb_mixer_interface *mixer; | ||
65 | unsigned char *buffer; | 92 | unsigned char *buffer; |
66 | unsigned int buflen; | 93 | unsigned int buflen; |
67 | unsigned int ctrlif; | 94 | DECLARE_BITMAP(unitbitmap, 256); |
68 | unsigned short vendor; | ||
69 | unsigned short product; | ||
70 | DECLARE_BITMAP(unitbitmap, 32*32); | ||
71 | usb_audio_term_t oterm; | 95 | usb_audio_term_t oterm; |
72 | const struct usbmix_name_map *map; | 96 | const struct usbmix_name_map *map; |
97 | const struct usbmix_selector_map *selector_map; | ||
73 | }; | 98 | }; |
74 | 99 | ||
75 | struct usb_mixer_elem_info { | 100 | struct usb_mixer_elem_info { |
76 | snd_usb_audio_t *chip; | 101 | struct usb_mixer_interface *mixer; |
77 | unsigned int ctrlif; | 102 | usb_mixer_elem_info_t *next_id_elem; /* list of controls with same id */ |
103 | snd_ctl_elem_id_t *elem_id; | ||
78 | unsigned int id; | 104 | unsigned int id; |
79 | unsigned int control; /* CS or ICN (high byte) */ | 105 | unsigned int control; /* CS or ICN (high byte) */ |
80 | unsigned int cmask; /* channel mask bitmap: 0 = master */ | 106 | unsigned int cmask; /* channel mask bitmap: 0 = master */ |
81 | int channels; | 107 | int channels; |
82 | int val_type; | 108 | int val_type; |
83 | int min, max, res; | 109 | int min, max, res; |
84 | unsigned int initialized: 1; | 110 | u8 initialized; |
85 | }; | 111 | }; |
86 | 112 | ||
87 | 113 | ||
@@ -187,6 +213,21 @@ static int check_ignored_ctl(mixer_build_t *state, int unitid, int control) | |||
187 | return 0; | 213 | return 0; |
188 | } | 214 | } |
189 | 215 | ||
216 | /* get the mapped selector source name */ | ||
217 | static int check_mapped_selector_name(mixer_build_t *state, int unitid, | ||
218 | int index, char *buf, int buflen) | ||
219 | { | ||
220 | const struct usbmix_selector_map *p; | ||
221 | |||
222 | if (! state->selector_map) | ||
223 | return 0; | ||
224 | for (p = state->selector_map; p->id; p++) { | ||
225 | if (p->id == unitid && index < p->count) | ||
226 | return strlcpy(buf, p->names[index], buflen); | ||
227 | } | ||
228 | return 0; | ||
229 | } | ||
230 | |||
190 | /* | 231 | /* |
191 | * find an audio control unit with the given unit id | 232 | * find an audio control unit with the given unit id |
192 | */ | 233 | */ |
@@ -301,16 +342,18 @@ static int get_ctl_value(usb_mixer_elem_info_t *cval, int request, int validx, i | |||
301 | int timeout = 10; | 342 | int timeout = 10; |
302 | 343 | ||
303 | while (timeout-- > 0) { | 344 | while (timeout-- > 0) { |
304 | if (snd_usb_ctl_msg(cval->chip->dev, usb_rcvctrlpipe(cval->chip->dev, 0), | 345 | if (snd_usb_ctl_msg(cval->mixer->chip->dev, |
346 | usb_rcvctrlpipe(cval->mixer->chip->dev, 0), | ||
305 | request, | 347 | request, |
306 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, | 348 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, |
307 | validx, cval->ctrlif | (cval->id << 8), | 349 | validx, cval->mixer->ctrlif | (cval->id << 8), |
308 | buf, val_len, 100) >= 0) { | 350 | buf, val_len, 100) >= 0) { |
309 | *value_ret = convert_signed_value(cval, snd_usb_combine_bytes(buf, val_len)); | 351 | *value_ret = convert_signed_value(cval, snd_usb_combine_bytes(buf, val_len)); |
310 | return 0; | 352 | return 0; |
311 | } | 353 | } |
312 | } | 354 | } |
313 | 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); | 355 | snd_printdd(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n", |
356 | request, validx, cval->mixer->ctrlif | (cval->id << 8), cval->val_type); | ||
314 | return -EINVAL; | 357 | return -EINVAL; |
315 | } | 358 | } |
316 | 359 | ||
@@ -339,13 +382,15 @@ static int set_ctl_value(usb_mixer_elem_info_t *cval, int request, int validx, i | |||
339 | buf[0] = value_set & 0xff; | 382 | buf[0] = value_set & 0xff; |
340 | buf[1] = (value_set >> 8) & 0xff; | 383 | buf[1] = (value_set >> 8) & 0xff; |
341 | while (timeout -- > 0) | 384 | while (timeout -- > 0) |
342 | if (snd_usb_ctl_msg(cval->chip->dev, usb_sndctrlpipe(cval->chip->dev, 0), | 385 | if (snd_usb_ctl_msg(cval->mixer->chip->dev, |
386 | usb_sndctrlpipe(cval->mixer->chip->dev, 0), | ||
343 | request, | 387 | request, |
344 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, | 388 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, |
345 | validx, cval->ctrlif | (cval->id << 8), | 389 | validx, cval->mixer->ctrlif | (cval->id << 8), |
346 | buf, val_len, 100) >= 0) | 390 | buf, val_len, 100) >= 0) |
347 | return 0; | 391 | return 0; |
348 | 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]); | 392 | snd_printdd(KERN_ERR "cannot set ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d, data = %#x/%#x\n", |
393 | request, validx, cval->mixer->ctrlif | (cval->id << 8), cval->val_type, buf[0], buf[1]); | ||
349 | return -EINVAL; | 394 | return -EINVAL; |
350 | } | 395 | } |
351 | 396 | ||
@@ -385,16 +430,22 @@ static int check_matrix_bitmap(unsigned char *bmap, int ich, int och, int num_ou | |||
385 | * if failed, give up and free the control instance. | 430 | * if failed, give up and free the control instance. |
386 | */ | 431 | */ |
387 | 432 | ||
388 | static int add_control_to_empty(snd_card_t *card, snd_kcontrol_t *kctl) | 433 | static int add_control_to_empty(mixer_build_t *state, snd_kcontrol_t *kctl) |
389 | { | 434 | { |
435 | usb_mixer_elem_info_t *cval = kctl->private_data; | ||
390 | int err; | 436 | int err; |
391 | while (snd_ctl_find_id(card, &kctl->id)) | 437 | |
438 | while (snd_ctl_find_id(state->chip->card, &kctl->id)) | ||
392 | kctl->id.index++; | 439 | kctl->id.index++; |
393 | if ((err = snd_ctl_add(card, kctl)) < 0) { | 440 | if ((err = snd_ctl_add(state->chip->card, kctl)) < 0) { |
394 | snd_printd(KERN_ERR "cannot add control (err = %d)\n", err); | 441 | snd_printd(KERN_ERR "cannot add control (err = %d)\n", err); |
395 | snd_ctl_free_one(kctl); | 442 | snd_ctl_free_one(kctl); |
443 | return err; | ||
396 | } | 444 | } |
397 | return err; | 445 | cval->elem_id = &kctl->id; |
446 | cval->next_id_elem = state->mixer->id_elems[cval->id]; | ||
447 | state->mixer->id_elems[cval->id] = cval; | ||
448 | return 0; | ||
398 | } | 449 | } |
399 | 450 | ||
400 | 451 | ||
@@ -572,10 +623,8 @@ static struct usb_feature_control_info audio_feature_info[] = { | |||
572 | /* private_free callback */ | 623 | /* private_free callback */ |
573 | static void usb_mixer_elem_free(snd_kcontrol_t *kctl) | 624 | static void usb_mixer_elem_free(snd_kcontrol_t *kctl) |
574 | { | 625 | { |
575 | if (kctl->private_data) { | 626 | kfree(kctl->private_data); |
576 | kfree(kctl->private_data); | 627 | kctl->private_data = NULL; |
577 | kctl->private_data = NULL; | ||
578 | } | ||
579 | } | 628 | } |
580 | 629 | ||
581 | 630 | ||
@@ -608,7 +657,8 @@ static int get_min_max(usb_mixer_elem_info_t *cval, int default_min) | |||
608 | } | 657 | } |
609 | if (get_ctl_value(cval, GET_MAX, (cval->control << 8) | minchn, &cval->max) < 0 || | 658 | if (get_ctl_value(cval, GET_MAX, (cval->control << 8) | minchn, &cval->max) < 0 || |
610 | get_ctl_value(cval, GET_MIN, (cval->control << 8) | minchn, &cval->min) < 0) { | 659 | get_ctl_value(cval, GET_MIN, (cval->control << 8) | minchn, &cval->min) < 0) { |
611 | 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); | 660 | snd_printd(KERN_ERR "%d:%d: cannot get min/max values for control %d (id %d)\n", |
661 | cval->id, cval->mixer->ctrlif, cval->control, cval->id); | ||
612 | return -EINVAL; | 662 | return -EINVAL; |
613 | } | 663 | } |
614 | if (get_ctl_value(cval, GET_RES, (cval->control << 8) | minchn, &cval->res) < 0) { | 664 | if (get_ctl_value(cval, GET_RES, (cval->control << 8) | minchn, &cval->res) < 0) { |
@@ -668,7 +718,7 @@ static int mixer_ctl_feature_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t | |||
668 | if (cval->cmask & (1 << c)) { | 718 | if (cval->cmask & (1 << c)) { |
669 | err = get_cur_mix_value(cval, c + 1, &val); | 719 | err = get_cur_mix_value(cval, c + 1, &val); |
670 | if (err < 0) { | 720 | if (err < 0) { |
671 | if (cval->chip->ignore_ctl_error) { | 721 | if (cval->mixer->ignore_ctl_error) { |
672 | ucontrol->value.integer.value[0] = cval->min; | 722 | ucontrol->value.integer.value[0] = cval->min; |
673 | return 0; | 723 | return 0; |
674 | } | 724 | } |
@@ -684,7 +734,7 @@ static int mixer_ctl_feature_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t | |||
684 | /* master channel */ | 734 | /* master channel */ |
685 | err = get_cur_mix_value(cval, 0, &val); | 735 | err = get_cur_mix_value(cval, 0, &val); |
686 | if (err < 0) { | 736 | if (err < 0) { |
687 | if (cval->chip->ignore_ctl_error) { | 737 | if (cval->mixer->ignore_ctl_error) { |
688 | ucontrol->value.integer.value[0] = cval->min; | 738 | ucontrol->value.integer.value[0] = cval->min; |
689 | return 0; | 739 | return 0; |
690 | } | 740 | } |
@@ -710,7 +760,7 @@ static int mixer_ctl_feature_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t | |||
710 | if (cval->cmask & (1 << c)) { | 760 | if (cval->cmask & (1 << c)) { |
711 | err = get_cur_mix_value(cval, c + 1, &oval); | 761 | err = get_cur_mix_value(cval, c + 1, &oval); |
712 | if (err < 0) { | 762 | if (err < 0) { |
713 | if (cval->chip->ignore_ctl_error) | 763 | if (cval->mixer->ignore_ctl_error) |
714 | return 0; | 764 | return 0; |
715 | return err; | 765 | return err; |
716 | } | 766 | } |
@@ -727,7 +777,7 @@ static int mixer_ctl_feature_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t | |||
727 | } else { | 777 | } else { |
728 | /* master channel */ | 778 | /* master channel */ |
729 | err = get_cur_mix_value(cval, 0, &oval); | 779 | err = get_cur_mix_value(cval, 0, &oval); |
730 | if (err < 0 && cval->chip->ignore_ctl_error) | 780 | if (err < 0 && cval->mixer->ignore_ctl_error) |
731 | return 0; | 781 | return 0; |
732 | if (err < 0) | 782 | if (err < 0) |
733 | return err; | 783 | return err; |
@@ -779,8 +829,7 @@ static void build_feature_ctl(mixer_build_t *state, unsigned char *desc, | |||
779 | snd_printk(KERN_ERR "cannot malloc kcontrol\n"); | 829 | snd_printk(KERN_ERR "cannot malloc kcontrol\n"); |
780 | return; | 830 | return; |
781 | } | 831 | } |
782 | cval->chip = state->chip; | 832 | cval->mixer = state->mixer; |
783 | cval->ctrlif = state->ctrlif; | ||
784 | cval->id = unitid; | 833 | cval->id = unitid; |
785 | cval->control = control; | 834 | cval->control = control; |
786 | cval->cmask = ctl_mask; | 835 | cval->cmask = ctl_mask; |
@@ -855,16 +904,21 @@ static void build_feature_ctl(mixer_build_t *state, unsigned char *desc, | |||
855 | /* note that detection between firmware 2.1.1.7 (N101) and later 2.1.1.21 */ | 904 | /* note that detection between firmware 2.1.1.7 (N101) and later 2.1.1.21 */ |
856 | /* is not very clear from datasheets */ | 905 | /* is not very clear from datasheets */ |
857 | /* I hope that the min value is -15360 for newer firmware --jk */ | 906 | /* I hope that the min value is -15360 for newer firmware --jk */ |
858 | if (((state->vendor == 0x471 && (state->product == 0x104 || state->product == 0x105 || state->product == 0x101)) || | 907 | switch (state->chip->usb_id) { |
859 | (state->vendor == 0x672 && state->product == 0x1041)) && !strcmp(kctl->id.name, "PCM Playback Volume") && | 908 | case USB_ID(0x0471, 0x0101): |
860 | cval->min == -15616) { | 909 | case USB_ID(0x0471, 0x0104): |
861 | snd_printk("USB Audio: using volume control quirk for the UDA1321/N101 chip\n"); | 910 | case USB_ID(0x0471, 0x0105): |
862 | cval->max = -256; | 911 | case USB_ID(0x0672, 0x1041): |
912 | if (!strcmp(kctl->id.name, "PCM Playback Volume") && | ||
913 | cval->min == -15616) { | ||
914 | snd_printk("using volume control quirk for the UDA1321/N101 chip\n"); | ||
915 | cval->max = -256; | ||
916 | } | ||
863 | } | 917 | } |
864 | 918 | ||
865 | snd_printdd(KERN_INFO "[%d] FU [%s] ch = %d, val = %d/%d/%d\n", | 919 | snd_printdd(KERN_INFO "[%d] FU [%s] ch = %d, val = %d/%d/%d\n", |
866 | cval->id, kctl->id.name, cval->channels, cval->min, cval->max, cval->res); | 920 | cval->id, kctl->id.name, cval->channels, cval->min, cval->max, cval->res); |
867 | add_control_to_empty(state->chip->card, kctl); | 921 | add_control_to_empty(state, kctl); |
868 | } | 922 | } |
869 | 923 | ||
870 | 924 | ||
@@ -947,8 +1001,7 @@ static void build_mixer_unit_ctl(mixer_build_t *state, unsigned char *desc, | |||
947 | if (! cval) | 1001 | if (! cval) |
948 | return; | 1002 | return; |
949 | 1003 | ||
950 | cval->chip = state->chip; | 1004 | cval->mixer = state->mixer; |
951 | cval->ctrlif = state->ctrlif; | ||
952 | cval->id = unitid; | 1005 | cval->id = unitid; |
953 | cval->control = in_ch + 1; /* based on 1 */ | 1006 | cval->control = in_ch + 1; /* based on 1 */ |
954 | cval->val_type = USB_MIXER_S16; | 1007 | cval->val_type = USB_MIXER_S16; |
@@ -979,7 +1032,7 @@ static void build_mixer_unit_ctl(mixer_build_t *state, unsigned char *desc, | |||
979 | 1032 | ||
980 | snd_printdd(KERN_INFO "[%d] MU [%s] ch = %d, val = %d/%d\n", | 1033 | snd_printdd(KERN_INFO "[%d] MU [%s] ch = %d, val = %d/%d\n", |
981 | cval->id, kctl->id.name, cval->channels, cval->min, cval->max); | 1034 | cval->id, kctl->id.name, cval->channels, cval->min, cval->max); |
982 | add_control_to_empty(state->chip->card, kctl); | 1035 | add_control_to_empty(state, kctl); |
983 | } | 1036 | } |
984 | 1037 | ||
985 | 1038 | ||
@@ -1042,7 +1095,7 @@ static int mixer_ctl_procunit_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t | |||
1042 | int err, val; | 1095 | int err, val; |
1043 | 1096 | ||
1044 | err = get_cur_ctl_value(cval, cval->control << 8, &val); | 1097 | err = get_cur_ctl_value(cval, cval->control << 8, &val); |
1045 | if (err < 0 && cval->chip->ignore_ctl_error) { | 1098 | if (err < 0 && cval->mixer->ignore_ctl_error) { |
1046 | ucontrol->value.integer.value[0] = cval->min; | 1099 | ucontrol->value.integer.value[0] = cval->min; |
1047 | return 0; | 1100 | return 0; |
1048 | } | 1101 | } |
@@ -1061,7 +1114,7 @@ static int mixer_ctl_procunit_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t | |||
1061 | 1114 | ||
1062 | err = get_cur_ctl_value(cval, cval->control << 8, &oval); | 1115 | err = get_cur_ctl_value(cval, cval->control << 8, &oval); |
1063 | if (err < 0) { | 1116 | if (err < 0) { |
1064 | if (cval->chip->ignore_ctl_error) | 1117 | if (cval->mixer->ignore_ctl_error) |
1065 | return 0; | 1118 | return 0; |
1066 | return err; | 1119 | return err; |
1067 | } | 1120 | } |
@@ -1179,9 +1232,6 @@ static int build_audio_procunit(mixer_build_t *state, int unitid, unsigned char | |||
1179 | } | 1232 | } |
1180 | 1233 | ||
1181 | type = combine_word(&dsc[4]); | 1234 | type = combine_word(&dsc[4]); |
1182 | if (! type) | ||
1183 | return 0; /* undefined? */ | ||
1184 | |||
1185 | for (info = list; info && info->type; info++) | 1235 | for (info = list; info && info->type; info++) |
1186 | if (info->type == type) | 1236 | if (info->type == type) |
1187 | break; | 1237 | break; |
@@ -1199,8 +1249,7 @@ static int build_audio_procunit(mixer_build_t *state, int unitid, unsigned char | |||
1199 | snd_printk(KERN_ERR "cannot malloc kcontrol\n"); | 1249 | snd_printk(KERN_ERR "cannot malloc kcontrol\n"); |
1200 | return -ENOMEM; | 1250 | return -ENOMEM; |
1201 | } | 1251 | } |
1202 | cval->chip = state->chip; | 1252 | cval->mixer = state->mixer; |
1203 | cval->ctrlif = state->ctrlif; | ||
1204 | cval->id = unitid; | 1253 | cval->id = unitid; |
1205 | cval->control = valinfo->control; | 1254 | cval->control = valinfo->control; |
1206 | cval->val_type = valinfo->val_type; | 1255 | cval->val_type = valinfo->val_type; |
@@ -1241,7 +1290,7 @@ static int build_audio_procunit(mixer_build_t *state, int unitid, unsigned char | |||
1241 | 1290 | ||
1242 | snd_printdd(KERN_INFO "[%d] PU [%s] ch = %d, val = %d/%d\n", | 1291 | snd_printdd(KERN_INFO "[%d] PU [%s] ch = %d, val = %d/%d\n", |
1243 | cval->id, kctl->id.name, cval->channels, cval->min, cval->max); | 1292 | cval->id, kctl->id.name, cval->channels, cval->min, cval->max); |
1244 | if ((err = add_control_to_empty(state->chip->card, kctl)) < 0) | 1293 | if ((err = add_control_to_empty(state, kctl)) < 0) |
1245 | return err; | 1294 | return err; |
1246 | } | 1295 | } |
1247 | return 0; | 1296 | return 0; |
@@ -1289,7 +1338,7 @@ static int mixer_ctl_selector_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t | |||
1289 | 1338 | ||
1290 | err = get_cur_ctl_value(cval, 0, &val); | 1339 | err = get_cur_ctl_value(cval, 0, &val); |
1291 | if (err < 0) { | 1340 | if (err < 0) { |
1292 | if (cval->chip->ignore_ctl_error) { | 1341 | if (cval->mixer->ignore_ctl_error) { |
1293 | ucontrol->value.enumerated.item[0] = 0; | 1342 | ucontrol->value.enumerated.item[0] = 0; |
1294 | return 0; | 1343 | return 0; |
1295 | } | 1344 | } |
@@ -1308,7 +1357,7 @@ static int mixer_ctl_selector_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t | |||
1308 | 1357 | ||
1309 | err = get_cur_ctl_value(cval, 0, &oval); | 1358 | err = get_cur_ctl_value(cval, 0, &oval); |
1310 | if (err < 0) { | 1359 | if (err < 0) { |
1311 | if (cval->chip->ignore_ctl_error) | 1360 | if (cval->mixer->ignore_ctl_error) |
1312 | return 0; | 1361 | return 0; |
1313 | return err; | 1362 | return err; |
1314 | } | 1363 | } |
@@ -1386,8 +1435,7 @@ static int parse_audio_selector_unit(mixer_build_t *state, int unitid, unsigned | |||
1386 | snd_printk(KERN_ERR "cannot malloc kcontrol\n"); | 1435 | snd_printk(KERN_ERR "cannot malloc kcontrol\n"); |
1387 | return -ENOMEM; | 1436 | return -ENOMEM; |
1388 | } | 1437 | } |
1389 | cval->chip = state->chip; | 1438 | cval->mixer = state->mixer; |
1390 | cval->ctrlif = state->ctrlif; | ||
1391 | cval->id = unitid; | 1439 | cval->id = unitid; |
1392 | cval->val_type = USB_MIXER_U8; | 1440 | cval->val_type = USB_MIXER_U8; |
1393 | cval->channels = 1; | 1441 | cval->channels = 1; |
@@ -1415,7 +1463,9 @@ static int parse_audio_selector_unit(mixer_build_t *state, int unitid, unsigned | |||
1415 | kfree(cval); | 1463 | kfree(cval); |
1416 | return -ENOMEM; | 1464 | return -ENOMEM; |
1417 | } | 1465 | } |
1418 | if (check_input_term(state, desc[5 + i], &iterm) >= 0) | 1466 | len = check_mapped_selector_name(state, unitid, i, namelist[i], |
1467 | MAX_ITEM_NAME_LEN); | ||
1468 | if (! len && check_input_term(state, desc[5 + i], &iterm) >= 0) | ||
1419 | len = get_term_name(state, &iterm, namelist[i], MAX_ITEM_NAME_LEN, 0); | 1469 | len = get_term_name(state, &iterm, namelist[i], MAX_ITEM_NAME_LEN, 0); |
1420 | if (! len) | 1470 | if (! len) |
1421 | sprintf(namelist[i], "Input %d", i); | 1471 | sprintf(namelist[i], "Input %d", i); |
@@ -1450,7 +1500,7 @@ static int parse_audio_selector_unit(mixer_build_t *state, int unitid, unsigned | |||
1450 | 1500 | ||
1451 | snd_printdd(KERN_INFO "[%d] SU [%s] items = %d\n", | 1501 | snd_printdd(KERN_INFO "[%d] SU [%s] items = %d\n", |
1452 | cval->id, kctl->id.name, num_ins); | 1502 | cval->id, kctl->id.name, num_ins); |
1453 | if ((err = add_control_to_empty(state->chip->card, kctl)) < 0) | 1503 | if ((err = add_control_to_empty(state, kctl)) < 0) |
1454 | return err; | 1504 | return err; |
1455 | 1505 | ||
1456 | return 0; | 1506 | return 0; |
@@ -1493,41 +1543,55 @@ static int parse_audio_unit(mixer_build_t *state, int unitid) | |||
1493 | } | 1543 | } |
1494 | } | 1544 | } |
1495 | 1545 | ||
1546 | static void snd_usb_mixer_free(struct usb_mixer_interface *mixer) | ||
1547 | { | ||
1548 | kfree(mixer->id_elems); | ||
1549 | if (mixer->urb) { | ||
1550 | kfree(mixer->urb->transfer_buffer); | ||
1551 | usb_free_urb(mixer->urb); | ||
1552 | } | ||
1553 | if (mixer->rc_urb) | ||
1554 | usb_free_urb(mixer->rc_urb); | ||
1555 | kfree(mixer->rc_setup_packet); | ||
1556 | kfree(mixer); | ||
1557 | } | ||
1558 | |||
1559 | static int snd_usb_mixer_dev_free(snd_device_t *device) | ||
1560 | { | ||
1561 | struct usb_mixer_interface *mixer = device->device_data; | ||
1562 | snd_usb_mixer_free(mixer); | ||
1563 | return 0; | ||
1564 | } | ||
1565 | |||
1496 | /* | 1566 | /* |
1497 | * create mixer controls | 1567 | * create mixer controls |
1498 | * | 1568 | * |
1499 | * walk through all OUTPUT_TERMINAL descriptors to search for mixers | 1569 | * walk through all OUTPUT_TERMINAL descriptors to search for mixers |
1500 | */ | 1570 | */ |
1501 | int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) | 1571 | static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) |
1502 | { | 1572 | { |
1503 | unsigned char *desc; | 1573 | unsigned char *desc; |
1504 | mixer_build_t state; | 1574 | mixer_build_t state; |
1505 | int err; | 1575 | int err; |
1506 | const struct usbmix_ctl_map *map; | 1576 | const struct usbmix_ctl_map *map; |
1507 | struct usb_device_descriptor *dev = &chip->dev->descriptor; | 1577 | struct usb_host_interface *hostif; |
1508 | struct usb_host_interface *hostif = &usb_ifnum_to_if(chip->dev, ctrlif)->altsetting[0]; | ||
1509 | |||
1510 | strcpy(chip->card->mixername, "USB Mixer"); | ||
1511 | 1578 | ||
1579 | hostif = &usb_ifnum_to_if(mixer->chip->dev, mixer->ctrlif)->altsetting[0]; | ||
1512 | memset(&state, 0, sizeof(state)); | 1580 | memset(&state, 0, sizeof(state)); |
1513 | state.chip = chip; | 1581 | state.chip = mixer->chip; |
1582 | state.mixer = mixer; | ||
1514 | state.buffer = hostif->extra; | 1583 | state.buffer = hostif->extra; |
1515 | state.buflen = hostif->extralen; | 1584 | state.buflen = hostif->extralen; |
1516 | state.ctrlif = ctrlif; | ||
1517 | state.vendor = le16_to_cpu(dev->idVendor); | ||
1518 | state.product = le16_to_cpu(dev->idProduct); | ||
1519 | 1585 | ||
1520 | /* check the mapping table */ | 1586 | /* check the mapping table */ |
1521 | for (map = usbmix_ctl_maps; map->vendor; map++) { | 1587 | for (map = usbmix_ctl_maps; map->id; map++) { |
1522 | if (map->vendor == state.vendor && map->product == state.product) { | 1588 | if (map->id == state.chip->usb_id) { |
1523 | state.map = map->map; | 1589 | state.map = map->map; |
1524 | chip->ignore_ctl_error = map->ignore_ctl_error; | 1590 | state.selector_map = map->selector_map; |
1591 | mixer->ignore_ctl_error = map->ignore_ctl_error; | ||
1525 | break; | 1592 | break; |
1526 | } | 1593 | } |
1527 | } | 1594 | } |
1528 | #ifdef IGNORE_CTL_ERROR | ||
1529 | chip->ignore_ctl_error = 1; | ||
1530 | #endif | ||
1531 | 1595 | ||
1532 | desc = NULL; | 1596 | desc = NULL; |
1533 | while ((desc = snd_usb_find_csint_desc(hostif->extra, hostif->extralen, desc, OUTPUT_TERMINAL)) != NULL) { | 1597 | while ((desc = snd_usb_find_csint_desc(hostif->extra, hostif->extralen, desc, OUTPUT_TERMINAL)) != NULL) { |
@@ -1543,3 +1607,393 @@ int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) | |||
1543 | } | 1607 | } |
1544 | return 0; | 1608 | return 0; |
1545 | } | 1609 | } |
1610 | |||
1611 | static void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, | ||
1612 | int unitid) | ||
1613 | { | ||
1614 | usb_mixer_elem_info_t *info; | ||
1615 | |||
1616 | for (info = mixer->id_elems[unitid]; info; info = info->next_id_elem) | ||
1617 | snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
1618 | info->elem_id); | ||
1619 | } | ||
1620 | |||
1621 | static void snd_usb_mixer_memory_change(struct usb_mixer_interface *mixer, | ||
1622 | int unitid) | ||
1623 | { | ||
1624 | if (mixer->rc_type == RC_NONE) | ||
1625 | return; | ||
1626 | /* unit ids specific to Extigy/Audigy 2 NX: */ | ||
1627 | switch (unitid) { | ||
1628 | case 0: /* remote control */ | ||
1629 | mixer->rc_urb->dev = mixer->chip->dev; | ||
1630 | usb_submit_urb(mixer->rc_urb, GFP_ATOMIC); | ||
1631 | break; | ||
1632 | case 4: /* digital in jack */ | ||
1633 | case 7: /* line in jacks */ | ||
1634 | case 19: /* speaker out jacks */ | ||
1635 | case 20: /* headphones out jack */ | ||
1636 | break; | ||
1637 | default: | ||
1638 | snd_printd(KERN_DEBUG "memory change in unknown unit %d\n", unitid); | ||
1639 | break; | ||
1640 | } | ||
1641 | } | ||
1642 | |||
1643 | static void snd_usb_mixer_status_complete(struct urb *urb, struct pt_regs *regs) | ||
1644 | { | ||
1645 | struct usb_mixer_interface *mixer = urb->context; | ||
1646 | |||
1647 | if (urb->status == 0) { | ||
1648 | u8 *buf = urb->transfer_buffer; | ||
1649 | int i; | ||
1650 | |||
1651 | for (i = urb->actual_length; i >= 2; buf += 2, i -= 2) { | ||
1652 | snd_printd(KERN_DEBUG "status interrupt: %02x %02x\n", | ||
1653 | buf[0], buf[1]); | ||
1654 | /* ignore any notifications not from the control interface */ | ||
1655 | if ((buf[0] & 0x0f) != 0) | ||
1656 | continue; | ||
1657 | if (!(buf[0] & 0x40)) | ||
1658 | snd_usb_mixer_notify_id(mixer, buf[1]); | ||
1659 | else | ||
1660 | snd_usb_mixer_memory_change(mixer, buf[1]); | ||
1661 | } | ||
1662 | } | ||
1663 | if (urb->status != -ENOENT && urb->status != -ECONNRESET) { | ||
1664 | urb->dev = mixer->chip->dev; | ||
1665 | usb_submit_urb(urb, GFP_ATOMIC); | ||
1666 | } | ||
1667 | } | ||
1668 | |||
1669 | /* create the handler for the optional status interrupt endpoint */ | ||
1670 | static int snd_usb_mixer_status_create(struct usb_mixer_interface *mixer) | ||
1671 | { | ||
1672 | struct usb_host_interface *hostif; | ||
1673 | struct usb_endpoint_descriptor *ep; | ||
1674 | void *transfer_buffer; | ||
1675 | int buffer_length; | ||
1676 | unsigned int epnum; | ||
1677 | |||
1678 | hostif = &usb_ifnum_to_if(mixer->chip->dev, mixer->ctrlif)->altsetting[0]; | ||
1679 | /* we need one interrupt input endpoint */ | ||
1680 | if (get_iface_desc(hostif)->bNumEndpoints < 1) | ||
1681 | return 0; | ||
1682 | ep = get_endpoint(hostif, 0); | ||
1683 | if ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) != USB_DIR_IN || | ||
1684 | (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) | ||
1685 | return 0; | ||
1686 | |||
1687 | epnum = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; | ||
1688 | buffer_length = le16_to_cpu(ep->wMaxPacketSize); | ||
1689 | transfer_buffer = kmalloc(buffer_length, GFP_KERNEL); | ||
1690 | if (!transfer_buffer) | ||
1691 | return -ENOMEM; | ||
1692 | mixer->urb = usb_alloc_urb(0, GFP_KERNEL); | ||
1693 | if (!mixer->urb) { | ||
1694 | kfree(transfer_buffer); | ||
1695 | return -ENOMEM; | ||
1696 | } | ||
1697 | usb_fill_int_urb(mixer->urb, mixer->chip->dev, | ||
1698 | usb_rcvintpipe(mixer->chip->dev, epnum), | ||
1699 | transfer_buffer, buffer_length, | ||
1700 | snd_usb_mixer_status_complete, mixer, ep->bInterval); | ||
1701 | usb_submit_urb(mixer->urb, GFP_KERNEL); | ||
1702 | return 0; | ||
1703 | } | ||
1704 | |||
1705 | static void snd_usb_soundblaster_remote_complete(struct urb *urb, | ||
1706 | struct pt_regs *regs) | ||
1707 | { | ||
1708 | struct usb_mixer_interface *mixer = urb->context; | ||
1709 | /* | ||
1710 | * format of remote control data: | ||
1711 | * Extigy: xx 00 | ||
1712 | * Audigy 2 NX: 06 80 xx 00 00 00 | ||
1713 | */ | ||
1714 | int offset = mixer->rc_type == RC_EXTIGY ? 0 : 2; | ||
1715 | u32 code; | ||
1716 | |||
1717 | if (urb->status < 0 || urb->actual_length <= offset) | ||
1718 | return; | ||
1719 | code = mixer->rc_buffer[offset]; | ||
1720 | /* the Mute button actually changes the mixer control */ | ||
1721 | if (code == 13) | ||
1722 | snd_usb_mixer_notify_id(mixer, 18); | ||
1723 | mixer->rc_code = code; | ||
1724 | wmb(); | ||
1725 | wake_up(&mixer->rc_waitq); | ||
1726 | } | ||
1727 | |||
1728 | static int snd_usb_sbrc_hwdep_open(snd_hwdep_t *hw, struct file *file) | ||
1729 | { | ||
1730 | struct usb_mixer_interface *mixer = hw->private_data; | ||
1731 | |||
1732 | if (test_and_set_bit(0, &mixer->rc_hwdep_open)) | ||
1733 | return -EBUSY; | ||
1734 | return 0; | ||
1735 | } | ||
1736 | |||
1737 | static int snd_usb_sbrc_hwdep_release(snd_hwdep_t *hw, struct file *file) | ||
1738 | { | ||
1739 | struct usb_mixer_interface *mixer = hw->private_data; | ||
1740 | |||
1741 | clear_bit(0, &mixer->rc_hwdep_open); | ||
1742 | smp_mb__after_clear_bit(); | ||
1743 | return 0; | ||
1744 | } | ||
1745 | |||
1746 | static long snd_usb_sbrc_hwdep_read(snd_hwdep_t *hw, char __user *buf, | ||
1747 | long count, loff_t *offset) | ||
1748 | { | ||
1749 | struct usb_mixer_interface *mixer = hw->private_data; | ||
1750 | int err; | ||
1751 | u32 rc_code; | ||
1752 | |||
1753 | if (count != 1 && count != 4) | ||
1754 | return -EINVAL; | ||
1755 | err = wait_event_interruptible(mixer->rc_waitq, | ||
1756 | (rc_code = xchg(&mixer->rc_code, 0)) != 0); | ||
1757 | if (err == 0) { | ||
1758 | if (count == 1) | ||
1759 | err = put_user(rc_code, buf); | ||
1760 | else | ||
1761 | err = put_user(rc_code, (u32 __user *)buf); | ||
1762 | } | ||
1763 | return err < 0 ? err : count; | ||
1764 | } | ||
1765 | |||
1766 | static unsigned int snd_usb_sbrc_hwdep_poll(snd_hwdep_t *hw, struct file *file, | ||
1767 | poll_table *wait) | ||
1768 | { | ||
1769 | struct usb_mixer_interface *mixer = hw->private_data; | ||
1770 | |||
1771 | poll_wait(file, &mixer->rc_waitq, wait); | ||
1772 | return mixer->rc_code ? POLLIN | POLLRDNORM : 0; | ||
1773 | } | ||
1774 | |||
1775 | static int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer) | ||
1776 | { | ||
1777 | snd_hwdep_t *hwdep; | ||
1778 | int err, len; | ||
1779 | |||
1780 | switch (mixer->chip->usb_id) { | ||
1781 | case USB_ID(0x041e, 0x3000): | ||
1782 | mixer->rc_type = RC_EXTIGY; | ||
1783 | len = 2; | ||
1784 | break; | ||
1785 | case USB_ID(0x041e, 0x3020): | ||
1786 | mixer->rc_type = RC_AUDIGY2NX; | ||
1787 | len = 6; | ||
1788 | break; | ||
1789 | default: | ||
1790 | return 0; | ||
1791 | } | ||
1792 | |||
1793 | init_waitqueue_head(&mixer->rc_waitq); | ||
1794 | err = snd_hwdep_new(mixer->chip->card, "SB remote control", 0, &hwdep); | ||
1795 | if (err < 0) | ||
1796 | return err; | ||
1797 | snprintf(hwdep->name, sizeof(hwdep->name), | ||
1798 | "%s remote control", mixer->chip->card->shortname); | ||
1799 | hwdep->iface = SNDRV_HWDEP_IFACE_SB_RC; | ||
1800 | hwdep->private_data = mixer; | ||
1801 | hwdep->ops.read = snd_usb_sbrc_hwdep_read; | ||
1802 | hwdep->ops.open = snd_usb_sbrc_hwdep_open; | ||
1803 | hwdep->ops.release = snd_usb_sbrc_hwdep_release; | ||
1804 | hwdep->ops.poll = snd_usb_sbrc_hwdep_poll; | ||
1805 | |||
1806 | mixer->rc_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
1807 | if (!mixer->rc_urb) | ||
1808 | return -ENOMEM; | ||
1809 | mixer->rc_setup_packet = kmalloc(sizeof(*mixer->rc_setup_packet), GFP_KERNEL); | ||
1810 | if (!mixer->rc_setup_packet) { | ||
1811 | usb_free_urb(mixer->rc_urb); | ||
1812 | mixer->rc_urb = NULL; | ||
1813 | return -ENOMEM; | ||
1814 | } | ||
1815 | mixer->rc_setup_packet->bRequestType = | ||
1816 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE; | ||
1817 | mixer->rc_setup_packet->bRequest = GET_MEM; | ||
1818 | mixer->rc_setup_packet->wValue = cpu_to_le16(0); | ||
1819 | mixer->rc_setup_packet->wIndex = cpu_to_le16(0); | ||
1820 | mixer->rc_setup_packet->wLength = cpu_to_le16(len); | ||
1821 | usb_fill_control_urb(mixer->rc_urb, mixer->chip->dev, | ||
1822 | usb_rcvctrlpipe(mixer->chip->dev, 0), | ||
1823 | (u8*)mixer->rc_setup_packet, mixer->rc_buffer, len, | ||
1824 | snd_usb_soundblaster_remote_complete, mixer); | ||
1825 | return 0; | ||
1826 | } | ||
1827 | |||
1828 | static int snd_audigy2nx_led_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) | ||
1829 | { | ||
1830 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
1831 | uinfo->count = 1; | ||
1832 | uinfo->value.integer.min = 0; | ||
1833 | uinfo->value.integer.max = 1; | ||
1834 | return 0; | ||
1835 | } | ||
1836 | |||
1837 | static int snd_audigy2nx_led_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
1838 | { | ||
1839 | struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); | ||
1840 | int index = kcontrol->private_value; | ||
1841 | |||
1842 | ucontrol->value.integer.value[0] = mixer->audigy2nx_leds[index]; | ||
1843 | return 0; | ||
1844 | } | ||
1845 | |||
1846 | static int snd_audigy2nx_led_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
1847 | { | ||
1848 | struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); | ||
1849 | int index = kcontrol->private_value; | ||
1850 | int value = ucontrol->value.integer.value[0]; | ||
1851 | int err, changed; | ||
1852 | |||
1853 | if (value > 1) | ||
1854 | return -EINVAL; | ||
1855 | changed = value != mixer->audigy2nx_leds[index]; | ||
1856 | err = snd_usb_ctl_msg(mixer->chip->dev, | ||
1857 | usb_sndctrlpipe(mixer->chip->dev, 0), 0x24, | ||
1858 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, | ||
1859 | value, index + 2, NULL, 0, 100); | ||
1860 | if (err < 0) | ||
1861 | return err; | ||
1862 | mixer->audigy2nx_leds[index] = value; | ||
1863 | return changed; | ||
1864 | } | ||
1865 | |||
1866 | static snd_kcontrol_new_t snd_audigy2nx_controls[] = { | ||
1867 | { | ||
1868 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1869 | .name = "CMSS LED Switch", | ||
1870 | .info = snd_audigy2nx_led_info, | ||
1871 | .get = snd_audigy2nx_led_get, | ||
1872 | .put = snd_audigy2nx_led_put, | ||
1873 | .private_value = 0, | ||
1874 | }, | ||
1875 | { | ||
1876 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1877 | .name = "Power LED Switch", | ||
1878 | .info = snd_audigy2nx_led_info, | ||
1879 | .get = snd_audigy2nx_led_get, | ||
1880 | .put = snd_audigy2nx_led_put, | ||
1881 | .private_value = 1, | ||
1882 | }, | ||
1883 | { | ||
1884 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1885 | .name = "Dolby Digital LED Switch", | ||
1886 | .info = snd_audigy2nx_led_info, | ||
1887 | .get = snd_audigy2nx_led_get, | ||
1888 | .put = snd_audigy2nx_led_put, | ||
1889 | .private_value = 2, | ||
1890 | }, | ||
1891 | }; | ||
1892 | |||
1893 | static int snd_audigy2nx_controls_create(struct usb_mixer_interface *mixer) | ||
1894 | { | ||
1895 | int i, err; | ||
1896 | |||
1897 | for (i = 0; i < ARRAY_SIZE(snd_audigy2nx_controls); ++i) { | ||
1898 | err = snd_ctl_add(mixer->chip->card, | ||
1899 | snd_ctl_new1(&snd_audigy2nx_controls[i], mixer)); | ||
1900 | if (err < 0) | ||
1901 | return err; | ||
1902 | } | ||
1903 | mixer->audigy2nx_leds[1] = 1; /* Power LED is on by default */ | ||
1904 | return 0; | ||
1905 | } | ||
1906 | |||
1907 | static void snd_audigy2nx_proc_read(snd_info_entry_t *entry, | ||
1908 | snd_info_buffer_t *buffer) | ||
1909 | { | ||
1910 | static const struct { | ||
1911 | int unitid; | ||
1912 | const char *name; | ||
1913 | } jacks[] = { | ||
1914 | {4, "dig in "}, | ||
1915 | {7, "line in"}, | ||
1916 | {19, "spk out"}, | ||
1917 | {20, "hph out"}, | ||
1918 | }; | ||
1919 | struct usb_mixer_interface *mixer = entry->private_data; | ||
1920 | int i, err; | ||
1921 | u8 buf[3]; | ||
1922 | |||
1923 | snd_iprintf(buffer, "%s jacks\n\n", mixer->chip->card->shortname); | ||
1924 | for (i = 0; i < ARRAY_SIZE(jacks); ++i) { | ||
1925 | snd_iprintf(buffer, "%s: ", jacks[i].name); | ||
1926 | err = snd_usb_ctl_msg(mixer->chip->dev, | ||
1927 | usb_rcvctrlpipe(mixer->chip->dev, 0), | ||
1928 | GET_MEM, USB_DIR_IN | USB_TYPE_CLASS | | ||
1929 | USB_RECIP_INTERFACE, 0, | ||
1930 | jacks[i].unitid << 8, buf, 3, 100); | ||
1931 | if (err == 3 && buf[0] == 3) | ||
1932 | snd_iprintf(buffer, "%02x %02x\n", buf[1], buf[2]); | ||
1933 | else | ||
1934 | snd_iprintf(buffer, "?\n"); | ||
1935 | } | ||
1936 | } | ||
1937 | |||
1938 | int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) | ||
1939 | { | ||
1940 | static snd_device_ops_t dev_ops = { | ||
1941 | .dev_free = snd_usb_mixer_dev_free | ||
1942 | }; | ||
1943 | struct usb_mixer_interface *mixer; | ||
1944 | int err; | ||
1945 | |||
1946 | strcpy(chip->card->mixername, "USB Mixer"); | ||
1947 | |||
1948 | mixer = kcalloc(1, sizeof(*mixer), GFP_KERNEL); | ||
1949 | if (!mixer) | ||
1950 | return -ENOMEM; | ||
1951 | mixer->chip = chip; | ||
1952 | mixer->ctrlif = ctrlif; | ||
1953 | #ifdef IGNORE_CTL_ERROR | ||
1954 | mixer->ignore_ctl_error = 1; | ||
1955 | #endif | ||
1956 | mixer->id_elems = kcalloc(256, sizeof(*mixer->id_elems), GFP_KERNEL); | ||
1957 | if (!mixer->id_elems) { | ||
1958 | kfree(mixer); | ||
1959 | return -ENOMEM; | ||
1960 | } | ||
1961 | |||
1962 | if ((err = snd_usb_mixer_controls(mixer)) < 0 || | ||
1963 | (err = snd_usb_mixer_status_create(mixer)) < 0) | ||
1964 | goto _error; | ||
1965 | |||
1966 | if ((err = snd_usb_soundblaster_remote_init(mixer)) < 0) | ||
1967 | goto _error; | ||
1968 | |||
1969 | if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020)) { | ||
1970 | snd_info_entry_t *entry; | ||
1971 | |||
1972 | if ((err = snd_audigy2nx_controls_create(mixer)) < 0) | ||
1973 | goto _error; | ||
1974 | if (!snd_card_proc_new(chip->card, "audigy2nx", &entry)) | ||
1975 | snd_info_set_text_ops(entry, mixer, 1024, | ||
1976 | snd_audigy2nx_proc_read); | ||
1977 | } | ||
1978 | |||
1979 | err = snd_device_new(chip->card, SNDRV_DEV_LOWLEVEL, mixer, &dev_ops); | ||
1980 | if (err < 0) | ||
1981 | goto _error; | ||
1982 | list_add(&mixer->list, &chip->mixer_list); | ||
1983 | return 0; | ||
1984 | |||
1985 | _error: | ||
1986 | snd_usb_mixer_free(mixer); | ||
1987 | return err; | ||
1988 | } | ||
1989 | |||
1990 | void snd_usb_mixer_disconnect(struct list_head *p) | ||
1991 | { | ||
1992 | struct usb_mixer_interface *mixer; | ||
1993 | |||
1994 | mixer = list_entry(p, struct usb_mixer_interface, list); | ||
1995 | if (mixer->urb) | ||
1996 | usb_kill_urb(mixer->urb); | ||
1997 | if (mixer->rc_urb) | ||
1998 | usb_kill_urb(mixer->rc_urb); | ||
1999 | } | ||
diff --git a/sound/usb/usbmixer_maps.c b/sound/usb/usbmixer_maps.c index c69b4b0875f8..f05500b05ec0 100644 --- a/sound/usb/usbmixer_maps.c +++ b/sound/usb/usbmixer_maps.c | |||
@@ -26,10 +26,16 @@ struct usbmix_name_map { | |||
26 | int control; | 26 | int control; |
27 | }; | 27 | }; |
28 | 28 | ||
29 | struct usbmix_selector_map { | ||
30 | int id; | ||
31 | int count; | ||
32 | const char **names; | ||
33 | }; | ||
34 | |||
29 | struct usbmix_ctl_map { | 35 | struct usbmix_ctl_map { |
30 | int vendor; | 36 | u32 id; |
31 | int product; | ||
32 | const struct usbmix_name_map *map; | 37 | const struct usbmix_name_map *map; |
38 | const struct usbmix_selector_map *selector_map; | ||
33 | int ignore_ctl_error; | 39 | int ignore_ctl_error; |
34 | }; | 40 | }; |
35 | 41 | ||
@@ -91,6 +97,96 @@ static struct usbmix_name_map extigy_map[] = { | |||
91 | { 0 } /* terminator */ | 97 | { 0 } /* terminator */ |
92 | }; | 98 | }; |
93 | 99 | ||
100 | /* Sound Blaster MP3+ controls mapping | ||
101 | * The default mixer channels have totally misleading names, | ||
102 | * e.g. no Master and fake PCM volume | ||
103 | * Pavel Mihaylov <bin@bash.info> | ||
104 | */ | ||
105 | static struct usbmix_name_map mp3plus_map[] = { | ||
106 | /* 1: IT pcm */ | ||
107 | /* 2: IT mic */ | ||
108 | /* 3: IT line */ | ||
109 | /* 4: IT digital in */ | ||
110 | /* 5: OT digital out */ | ||
111 | /* 6: OT speaker */ | ||
112 | /* 7: OT pcm capture */ | ||
113 | { 8, "Capture Input Source" }, /* FU, default PCM Capture Source */ | ||
114 | /* (Mic, Input 1 = Line input, Input 2 = Optical input) */ | ||
115 | { 9, "Master Playback" }, /* FU, default Speaker 1 */ | ||
116 | /* { 10, "Mic Capture", 1 }, */ /* FU, Mic Capture */ | ||
117 | /* { 10, "Mic Capture", 2 }, */ /* FU, Mic Capture */ | ||
118 | { 10, "Mic Boost", 7 }, /* FU, default Auto Gain Input */ | ||
119 | { 11, "Line Capture" }, /* FU, default PCM Capture */ | ||
120 | { 12, "Digital In Playback" }, /* FU, default PCM 1 */ | ||
121 | /* { 13, "Mic Playback" }, */ /* FU, default Mic Playback */ | ||
122 | { 14, "Line Playback" }, /* FU, default Speaker */ | ||
123 | /* 15: MU */ | ||
124 | { 0 } /* terminator */ | ||
125 | }; | ||
126 | |||
127 | /* Topology of SB Audigy 2 NX | ||
128 | |||
129 | +----------------------------->EU[27]--+ | ||
130 | | v | ||
131 | | +----------------------------------->SU[29]---->FU[22]-->Dig_OUT[24] | ||
132 | | | ^ | ||
133 | USB_IN[1]-+------------+ +->EU[17]->+->FU[11]-+ | ||
134 | | v | v | | ||
135 | Dig_IN[4]---+->FU[6]-->MU[16]->FU[18]-+->EU[21]->SU[31]----->FU[30]->Hph_OUT[20] | ||
136 | | ^ | | | ||
137 | Lin_IN[7]-+--->FU[8]---+ +->EU[23]->FU[28]------------->Spk_OUT[19] | ||
138 | | | v | ||
139 | +--->FU[12]------------------------------------->SU[14]--->USB_OUT[15] | ||
140 | | ^ | ||
141 | +->FU[13]--------------------------------------+ | ||
142 | */ | ||
143 | static struct usbmix_name_map audigy2nx_map[] = { | ||
144 | /* 1: IT pcm playback */ | ||
145 | /* 4: IT digital in */ | ||
146 | { 6, "Digital In Playback" }, /* FU */ | ||
147 | /* 7: IT line in */ | ||
148 | { 8, "Line Playback" }, /* FU */ | ||
149 | { 11, "What-U-Hear Capture" }, /* FU */ | ||
150 | { 12, "Line Capture" }, /* FU */ | ||
151 | { 13, "Digital In Capture" }, /* FU */ | ||
152 | { 14, "Capture Source" }, /* SU */ | ||
153 | /* 15: OT pcm capture */ | ||
154 | /* 16: MU w/o controls */ | ||
155 | { 17, NULL }, /* DISABLED: EU (for what?) */ | ||
156 | { 18, "Master Playback" }, /* FU */ | ||
157 | /* 19: OT speaker */ | ||
158 | /* 20: OT headphone */ | ||
159 | { 21, NULL }, /* DISABLED: EU (for what?) */ | ||
160 | { 22, "Digital Out Playback" }, /* FU */ | ||
161 | { 23, NULL }, /* DISABLED: EU (for what?) */ | ||
162 | /* 24: OT digital out */ | ||
163 | { 27, NULL }, /* DISABLED: EU (for what?) */ | ||
164 | { 28, "Speaker Playback" }, /* FU */ | ||
165 | { 29, "Digital Out Source" }, /* SU */ | ||
166 | { 30, "Headphone Playback" }, /* FU */ | ||
167 | { 31, "Headphone Source" }, /* SU */ | ||
168 | { 0 } /* terminator */ | ||
169 | }; | ||
170 | |||
171 | static struct usbmix_selector_map audigy2nx_selectors[] = { | ||
172 | { | ||
173 | .id = 14, /* Capture Source */ | ||
174 | .count = 3, | ||
175 | .names = (const char*[]) {"Line", "Digital In", "What-U-Hear"} | ||
176 | }, | ||
177 | { | ||
178 | .id = 29, /* Digital Out Source */ | ||
179 | .count = 3, | ||
180 | .names = (const char*[]) {"Front", "PCM", "Digital In"} | ||
181 | }, | ||
182 | { | ||
183 | .id = 31, /* Headphone Source */ | ||
184 | .count = 2, | ||
185 | .names = (const char*[]) {"Front", "Side"} | ||
186 | }, | ||
187 | { 0 } /* terminator */ | ||
188 | }; | ||
189 | |||
94 | /* LineX FM Transmitter entry - needed to bypass controls bug */ | 190 | /* LineX FM Transmitter entry - needed to bypass controls bug */ |
95 | static struct usbmix_name_map linex_map[] = { | 191 | static struct usbmix_name_map linex_map[] = { |
96 | /* 1: IT pcm */ | 192 | /* 1: IT pcm */ |
@@ -127,9 +223,29 @@ static struct usbmix_name_map justlink_map[] = { | |||
127 | */ | 223 | */ |
128 | 224 | ||
129 | static struct usbmix_ctl_map usbmix_ctl_maps[] = { | 225 | static struct usbmix_ctl_map usbmix_ctl_maps[] = { |
130 | { 0x41e, 0x3000, extigy_map, 1 }, | 226 | { |
131 | { 0x8bb, 0x2702, linex_map, 1 }, | 227 | .id = USB_ID(0x041e, 0x3000), |
132 | { 0xc45, 0x1158, justlink_map, 0 }, | 228 | .map = extigy_map, |
229 | .ignore_ctl_error = 1, | ||
230 | }, | ||
231 | { | ||
232 | .id = USB_ID(0x041e, 0x3010), | ||
233 | .map = mp3plus_map, | ||
234 | }, | ||
235 | { | ||
236 | .id = USB_ID(0x041e, 0x3020), | ||
237 | .map = audigy2nx_map, | ||
238 | .selector_map = audigy2nx_selectors, | ||
239 | }, | ||
240 | { | ||
241 | .id = USB_ID(0x08bb, 0x2702), | ||
242 | .map = linex_map, | ||
243 | .ignore_ctl_error = 1, | ||
244 | }, | ||
245 | { | ||
246 | .id = USB_ID(0x0c45, 0x1158), | ||
247 | .map = justlink_map, | ||
248 | }, | ||
133 | { 0 } /* terminator */ | 249 | { 0 } /* terminator */ |
134 | }; | 250 | }; |
135 | 251 | ||
diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h index 88bbd944d4be..f5135641b3e2 100644 --- a/sound/usb/usbquirks.h +++ b/sound/usb/usbquirks.h | |||
@@ -203,11 +203,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
203 | .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { | 203 | .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { |
204 | .vendor_name = "EDIROL", | 204 | .vendor_name = "EDIROL", |
205 | .product_name = "UM-4", | 205 | .product_name = "UM-4", |
206 | .ifnum = 2, | 206 | .ifnum = QUIRK_ANY_INTERFACE, |
207 | .type = QUIRK_MIDI_FIXED_ENDPOINT, | 207 | .type = QUIRK_COMPOSITE, |
208 | .data = & (const snd_usb_midi_endpoint_info_t) { | 208 | .data = (const snd_usb_audio_quirk_t[]) { |
209 | .out_cables = 0x000f, | 209 | { |
210 | .in_cables = 0x000f | 210 | .ifnum = 0, |
211 | .type = QUIRK_IGNORE_INTERFACE | ||
212 | }, | ||
213 | { | ||
214 | .ifnum = 1, | ||
215 | .type = QUIRK_IGNORE_INTERFACE | ||
216 | }, | ||
217 | { | ||
218 | .ifnum = 2, | ||
219 | .type = QUIRK_MIDI_FIXED_ENDPOINT, | ||
220 | .data = & (const snd_usb_midi_endpoint_info_t) { | ||
221 | .out_cables = 0x000f, | ||
222 | .in_cables = 0x000f | ||
223 | } | ||
224 | }, | ||
225 | { | ||
226 | .ifnum = -1 | ||
227 | } | ||
211 | } | 228 | } |
212 | } | 229 | } |
213 | }, | 230 | }, |
@@ -216,11 +233,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
216 | .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { | 233 | .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { |
217 | .vendor_name = "Roland", | 234 | .vendor_name = "Roland", |
218 | .product_name = "SC-8850", | 235 | .product_name = "SC-8850", |
219 | .ifnum = 2, | 236 | .ifnum = QUIRK_ANY_INTERFACE, |
220 | .type = QUIRK_MIDI_FIXED_ENDPOINT, | 237 | .type = QUIRK_COMPOSITE, |
221 | .data = & (const snd_usb_midi_endpoint_info_t) { | 238 | .data = (const snd_usb_audio_quirk_t[]) { |
222 | .out_cables = 0x003f, | 239 | { |
223 | .in_cables = 0x003f | 240 | .ifnum = 0, |
241 | .type = QUIRK_IGNORE_INTERFACE | ||
242 | }, | ||
243 | { | ||
244 | .ifnum = 1, | ||
245 | .type = QUIRK_IGNORE_INTERFACE | ||
246 | }, | ||
247 | { | ||
248 | .ifnum = 2, | ||
249 | .type = QUIRK_MIDI_FIXED_ENDPOINT, | ||
250 | .data = & (const snd_usb_midi_endpoint_info_t) { | ||
251 | .out_cables = 0x003f, | ||
252 | .in_cables = 0x003f | ||
253 | } | ||
254 | }, | ||
255 | { | ||
256 | .ifnum = -1 | ||
257 | } | ||
224 | } | 258 | } |
225 | } | 259 | } |
226 | }, | 260 | }, |
@@ -229,11 +263,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
229 | .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { | 263 | .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { |
230 | .vendor_name = "Roland", | 264 | .vendor_name = "Roland", |
231 | .product_name = "U-8", | 265 | .product_name = "U-8", |
232 | .ifnum = 2, | 266 | .ifnum = QUIRK_ANY_INTERFACE, |
233 | .type = QUIRK_MIDI_FIXED_ENDPOINT, | 267 | .type = QUIRK_COMPOSITE, |
234 | .data = & (const snd_usb_midi_endpoint_info_t) { | 268 | .data = (const snd_usb_audio_quirk_t[]) { |
235 | .out_cables = 0x0005, | 269 | { |
236 | .in_cables = 0x0005 | 270 | .ifnum = 0, |
271 | .type = QUIRK_IGNORE_INTERFACE | ||
272 | }, | ||
273 | { | ||
274 | .ifnum = 1, | ||
275 | .type = QUIRK_IGNORE_INTERFACE | ||
276 | }, | ||
277 | { | ||
278 | .ifnum = 2, | ||
279 | .type = QUIRK_MIDI_FIXED_ENDPOINT, | ||
280 | .data = & (const snd_usb_midi_endpoint_info_t) { | ||
281 | .out_cables = 0x0005, | ||
282 | .in_cables = 0x0005 | ||
283 | } | ||
284 | }, | ||
285 | { | ||
286 | .ifnum = -1 | ||
287 | } | ||
237 | } | 288 | } |
238 | } | 289 | } |
239 | }, | 290 | }, |
@@ -242,11 +293,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
242 | .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { | 293 | .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { |
243 | .vendor_name = "EDIROL", | 294 | .vendor_name = "EDIROL", |
244 | .product_name = "UM-2", | 295 | .product_name = "UM-2", |
245 | .ifnum = 2, | 296 | .ifnum = QUIRK_ANY_INTERFACE, |
246 | .type = QUIRK_MIDI_FIXED_ENDPOINT, | 297 | .type = QUIRK_COMPOSITE, |
247 | .data = & (const snd_usb_midi_endpoint_info_t) { | 298 | .data = (const snd_usb_audio_quirk_t[]) { |
248 | .out_cables = 0x0003, | 299 | { |
249 | .in_cables = 0x0003 | 300 | .ifnum = 0, |
301 | .type = QUIRK_IGNORE_INTERFACE | ||
302 | }, | ||
303 | { | ||
304 | .ifnum = 1, | ||
305 | .type = QUIRK_IGNORE_INTERFACE | ||
306 | }, | ||
307 | { | ||
308 | .ifnum = 2, | ||
309 | .type = QUIRK_MIDI_FIXED_ENDPOINT, | ||
310 | .data = & (const snd_usb_midi_endpoint_info_t) { | ||
311 | .out_cables = 0x0003, | ||
312 | .in_cables = 0x0003 | ||
313 | } | ||
314 | }, | ||
315 | { | ||
316 | .ifnum = -1 | ||
317 | } | ||
250 | } | 318 | } |
251 | } | 319 | } |
252 | }, | 320 | }, |
@@ -255,11 +323,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
255 | .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { | 323 | .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { |
256 | .vendor_name = "Roland", | 324 | .vendor_name = "Roland", |
257 | .product_name = "SC-8820", | 325 | .product_name = "SC-8820", |
258 | .ifnum = 2, | 326 | .ifnum = QUIRK_ANY_INTERFACE, |
259 | .type = QUIRK_MIDI_FIXED_ENDPOINT, | 327 | .type = QUIRK_COMPOSITE, |
260 | .data = & (const snd_usb_midi_endpoint_info_t) { | 328 | .data = (const snd_usb_audio_quirk_t[]) { |
261 | .out_cables = 0x0013, | 329 | { |
262 | .in_cables = 0x0013 | 330 | .ifnum = 0, |
331 | .type = QUIRK_IGNORE_INTERFACE | ||
332 | }, | ||
333 | { | ||
334 | .ifnum = 1, | ||
335 | .type = QUIRK_IGNORE_INTERFACE | ||
336 | }, | ||
337 | { | ||
338 | .ifnum = 2, | ||
339 | .type = QUIRK_MIDI_FIXED_ENDPOINT, | ||
340 | .data = & (const snd_usb_midi_endpoint_info_t) { | ||
341 | .out_cables = 0x0013, | ||
342 | .in_cables = 0x0013 | ||
343 | } | ||
344 | }, | ||
345 | { | ||
346 | .ifnum = -1 | ||
347 | } | ||
263 | } | 348 | } |
264 | } | 349 | } |
265 | }, | 350 | }, |
@@ -268,11 +353,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
268 | .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { | 353 | .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { |
269 | .vendor_name = "Roland", | 354 | .vendor_name = "Roland", |
270 | .product_name = "PC-300", | 355 | .product_name = "PC-300", |
271 | .ifnum = 2, | 356 | .ifnum = QUIRK_ANY_INTERFACE, |
272 | .type = QUIRK_MIDI_FIXED_ENDPOINT, | 357 | .type = QUIRK_COMPOSITE, |
273 | .data = & (const snd_usb_midi_endpoint_info_t) { | 358 | .data = (const snd_usb_audio_quirk_t[]) { |
274 | .out_cables = 0x0001, | 359 | { |
275 | .in_cables = 0x0001 | 360 | .ifnum = 0, |
361 | .type = QUIRK_IGNORE_INTERFACE | ||
362 | }, | ||
363 | { | ||
364 | .ifnum = 1, | ||
365 | .type = QUIRK_IGNORE_INTERFACE | ||
366 | }, | ||
367 | { | ||
368 | .ifnum = 2, | ||
369 | .type = QUIRK_MIDI_FIXED_ENDPOINT, | ||
370 | .data = & (const snd_usb_midi_endpoint_info_t) { | ||
371 | .out_cables = 0x0001, | ||
372 | .in_cables = 0x0001 | ||
373 | } | ||
374 | }, | ||
375 | { | ||
376 | .ifnum = -1 | ||
377 | } | ||
276 | } | 378 | } |
277 | } | 379 | } |
278 | }, | 380 | }, |
@@ -281,11 +383,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
281 | .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { | 383 | .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { |
282 | .vendor_name = "EDIROL", | 384 | .vendor_name = "EDIROL", |
283 | .product_name = "UM-1", | 385 | .product_name = "UM-1", |
284 | .ifnum = 2, | 386 | .ifnum = QUIRK_ANY_INTERFACE, |
285 | .type = QUIRK_MIDI_FIXED_ENDPOINT, | 387 | .type = QUIRK_COMPOSITE, |
286 | .data = & (const snd_usb_midi_endpoint_info_t) { | 388 | .data = (const snd_usb_audio_quirk_t[]) { |
287 | .out_cables = 0x0001, | 389 | { |
288 | .in_cables = 0x0001 | 390 | .ifnum = 0, |
391 | .type = QUIRK_IGNORE_INTERFACE | ||
392 | }, | ||
393 | { | ||
394 | .ifnum = 1, | ||
395 | .type = QUIRK_IGNORE_INTERFACE | ||
396 | }, | ||
397 | { | ||
398 | .ifnum = 2, | ||
399 | .type = QUIRK_MIDI_FIXED_ENDPOINT, | ||
400 | .data = & (const snd_usb_midi_endpoint_info_t) { | ||
401 | .out_cables = 0x0001, | ||
402 | .in_cables = 0x0001 | ||
403 | } | ||
404 | }, | ||
405 | { | ||
406 | .ifnum = -1 | ||
407 | } | ||
289 | } | 408 | } |
290 | } | 409 | } |
291 | }, | 410 | }, |
@@ -294,11 +413,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
294 | .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { | 413 | .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { |
295 | .vendor_name = "Roland", | 414 | .vendor_name = "Roland", |
296 | .product_name = "SK-500", | 415 | .product_name = "SK-500", |
297 | .ifnum = 2, | 416 | .ifnum = QUIRK_ANY_INTERFACE, |
298 | .type = QUIRK_MIDI_FIXED_ENDPOINT, | 417 | .type = QUIRK_COMPOSITE, |
299 | .data = & (const snd_usb_midi_endpoint_info_t) { | 418 | .data = (const snd_usb_audio_quirk_t[]) { |
300 | .out_cables = 0x0013, | 419 | { |
301 | .in_cables = 0x0013 | 420 | .ifnum = 0, |
421 | .type = QUIRK_IGNORE_INTERFACE | ||
422 | }, | ||
423 | { | ||
424 | .ifnum = 1, | ||
425 | .type = QUIRK_IGNORE_INTERFACE | ||
426 | }, | ||
427 | { | ||
428 | .ifnum = 2, | ||
429 | .type = QUIRK_MIDI_FIXED_ENDPOINT, | ||
430 | .data = & (const snd_usb_midi_endpoint_info_t) { | ||
431 | .out_cables = 0x0013, | ||
432 | .in_cables = 0x0013 | ||
433 | } | ||
434 | }, | ||
435 | { | ||
436 | .ifnum = -1 | ||
437 | } | ||
302 | } | 438 | } |
303 | } | 439 | } |
304 | }, | 440 | }, |
@@ -421,11 +557,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
421 | .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { | 557 | .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { |
422 | .vendor_name = "EDIROL", | 558 | .vendor_name = "EDIROL", |
423 | .product_name = "SD-90", | 559 | .product_name = "SD-90", |
424 | .ifnum = 2, | 560 | .ifnum = QUIRK_ANY_INTERFACE, |
425 | .type = QUIRK_MIDI_FIXED_ENDPOINT, | 561 | .type = QUIRK_COMPOSITE, |
426 | .data = & (const snd_usb_midi_endpoint_info_t) { | 562 | .data = (const snd_usb_audio_quirk_t[]) { |
427 | .out_cables = 0x000f, | 563 | { |
428 | .in_cables = 0x000f | 564 | .ifnum = 0, |
565 | .type = QUIRK_IGNORE_INTERFACE | ||
566 | }, | ||
567 | { | ||
568 | .ifnum = 1, | ||
569 | .type = QUIRK_IGNORE_INTERFACE | ||
570 | }, | ||
571 | { | ||
572 | .ifnum = 2, | ||
573 | .type = QUIRK_MIDI_FIXED_ENDPOINT, | ||
574 | .data = & (const snd_usb_midi_endpoint_info_t) { | ||
575 | .out_cables = 0x000f, | ||
576 | .in_cables = 0x000f | ||
577 | } | ||
578 | }, | ||
579 | { | ||
580 | .ifnum = -1 | ||
581 | } | ||
429 | } | 582 | } |
430 | } | 583 | } |
431 | }, | 584 | }, |
@@ -434,11 +587,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
434 | .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { | 587 | .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { |
435 | .vendor_name = "Roland", | 588 | .vendor_name = "Roland", |
436 | .product_name = "MMP-2", | 589 | .product_name = "MMP-2", |
437 | .ifnum = 2, | 590 | .ifnum = QUIRK_ANY_INTERFACE, |
438 | .type = QUIRK_MIDI_FIXED_ENDPOINT, | 591 | .type = QUIRK_COMPOSITE, |
439 | .data = & (const snd_usb_midi_endpoint_info_t) { | 592 | .data = (const snd_usb_audio_quirk_t[]) { |
440 | .out_cables = 0x0001, | 593 | { |
441 | .in_cables = 0x0001 | 594 | .ifnum = 0, |
595 | .type = QUIRK_IGNORE_INTERFACE | ||
596 | }, | ||
597 | { | ||
598 | .ifnum = 1, | ||
599 | .type = QUIRK_IGNORE_INTERFACE | ||
600 | }, | ||
601 | { | ||
602 | .ifnum = 2, | ||
603 | .type = QUIRK_MIDI_FIXED_ENDPOINT, | ||
604 | .data = & (const snd_usb_midi_endpoint_info_t) { | ||
605 | .out_cables = 0x0001, | ||
606 | .in_cables = 0x0001 | ||
607 | } | ||
608 | }, | ||
609 | { | ||
610 | .ifnum = -1 | ||
611 | } | ||
442 | } | 612 | } |
443 | } | 613 | } |
444 | }, | 614 | }, |
@@ -609,15 +779,33 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
609 | } | 779 | } |
610 | }, | 780 | }, |
611 | { | 781 | { |
782 | /* | ||
783 | * This quirk is for the "Advanced Driver" mode. If off, the GS-10 | ||
784 | * has ID 0x003c and is standard compliant, but has only 16-bit PCM | ||
785 | * and no MIDI. | ||
786 | */ | ||
612 | USB_DEVICE_VENDOR_SPEC(0x0582, 0x003b), | 787 | USB_DEVICE_VENDOR_SPEC(0x0582, 0x003b), |
613 | .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { | 788 | .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { |
614 | .vendor_name = "BOSS", | 789 | .vendor_name = "BOSS", |
615 | .product_name = "GS-10", | 790 | .product_name = "GS-10", |
616 | .ifnum = 3, | 791 | .ifnum = QUIRK_ANY_INTERFACE, |
617 | .type = QUIRK_MIDI_FIXED_ENDPOINT, | 792 | .type = QUIRK_COMPOSITE, |
618 | .data = & (const snd_usb_midi_endpoint_info_t) { | 793 | .data = & (const snd_usb_audio_quirk_t[]) { |
619 | .out_cables = 0x0003, | 794 | { |
620 | .in_cables = 0x0003 | 795 | .ifnum = 1, |
796 | .type = QUIRK_AUDIO_STANDARD_INTERFACE | ||
797 | }, | ||
798 | { | ||
799 | .ifnum = 2, | ||
800 | .type = QUIRK_AUDIO_STANDARD_INTERFACE | ||
801 | }, | ||
802 | { | ||
803 | .ifnum = 3, | ||
804 | .type = QUIRK_MIDI_STANDARD_INTERFACE | ||
805 | }, | ||
806 | { | ||
807 | .ifnum = -1 | ||
808 | } | ||
621 | } | 809 | } |
622 | } | 810 | } |
623 | }, | 811 | }, |
diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c index 89ee8b732013..e6e6da159671 100644 --- a/sound/usb/usx2y/usbusx2y.c +++ b/sound/usb/usx2y/usbusx2y.c | |||
@@ -442,7 +442,7 @@ static void usX2Y_usb_disconnect(struct usb_device* device, void* ptr) | |||
442 | snd_card_disconnect((snd_card_t*)ptr); | 442 | snd_card_disconnect((snd_card_t*)ptr); |
443 | /* release the midi resources */ | 443 | /* release the midi resources */ |
444 | list_for_each(p, &usX2Y->chip.midi_list) { | 444 | list_for_each(p, &usX2Y->chip.midi_list) { |
445 | snd_usbmidi_disconnect(p, &snd_usX2Y_usb_driver); | 445 | snd_usbmidi_disconnect(p); |
446 | } | 446 | } |
447 | if (usX2Y->us428ctls_sharedmem) | 447 | if (usX2Y->us428ctls_sharedmem) |
448 | wake_up(&usX2Y->us428ctls_wait_queue_head); | 448 | wake_up(&usX2Y->us428ctls_wait_queue_head); |
diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c index 4c292e090069..62dfd28b3b07 100644 --- a/sound/usb/usx2y/usbusx2yaudio.c +++ b/sound/usb/usx2y/usbusx2yaudio.c | |||
@@ -401,10 +401,8 @@ static void usX2Y_urbs_release(snd_usX2Y_substream_t *subs) | |||
401 | for (i = 0; i < NRURBS; i++) | 401 | for (i = 0; i < NRURBS; i++) |
402 | usX2Y_urb_release(subs->urb + i, subs != subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK]); | 402 | usX2Y_urb_release(subs->urb + i, subs != subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK]); |
403 | 403 | ||
404 | if (subs->tmpbuf) { | 404 | kfree(subs->tmpbuf); |
405 | kfree(subs->tmpbuf); | 405 | subs->tmpbuf = NULL; |
406 | subs->tmpbuf = NULL; | ||
407 | } | ||
408 | } | 406 | } |
409 | /* | 407 | /* |
410 | * initialize a substream's urbs | 408 | * initialize a substream's urbs |