Commit f398778aa336a2919ee04ba45d915007230c6957
Exists in
master
and in
7 other branches
Merge branch 'video' into release
Conflicts: Documentation/kernel-parameters.txt Signed-off-by: Len Brown <len.brown@intel.com>
Showing 16 changed files Inline Diff
- Documentation/kernel-parameters.txt
- drivers/acpi/Makefile
- drivers/acpi/glue.c
- drivers/acpi/scan.c
- drivers/acpi/video.c
- drivers/acpi/video_detect.c
- drivers/misc/acer-wmi.c
- drivers/misc/asus-laptop.c
- drivers/misc/compal-laptop.c
- drivers/misc/eeepc-laptop.c
- drivers/misc/fujitsu-laptop.c
- drivers/misc/msi-laptop.c
- drivers/misc/sony-laptop.c
- drivers/misc/thinkpad_acpi.c
- include/acpi/acpi_bus.h
- include/linux/acpi.h
Documentation/kernel-parameters.txt
1 | Kernel Parameters | 1 | Kernel Parameters |
2 | ~~~~~~~~~~~~~~~~~ | 2 | ~~~~~~~~~~~~~~~~~ |
3 | 3 | ||
4 | The following is a consolidated list of the kernel parameters as implemented | 4 | The following is a consolidated list of the kernel parameters as implemented |
5 | (mostly) by the __setup() macro and sorted into English Dictionary order | 5 | (mostly) by the __setup() macro and sorted into English Dictionary order |
6 | (defined as ignoring all punctuation and sorting digits before letters in a | 6 | (defined as ignoring all punctuation and sorting digits before letters in a |
7 | case insensitive manner), and with descriptions where known. | 7 | case insensitive manner), and with descriptions where known. |
8 | 8 | ||
9 | Module parameters for loadable modules are specified only as the | 9 | Module parameters for loadable modules are specified only as the |
10 | parameter name with optional '=' and value as appropriate, such as: | 10 | parameter name with optional '=' and value as appropriate, such as: |
11 | 11 | ||
12 | modprobe usbcore blinkenlights=1 | 12 | modprobe usbcore blinkenlights=1 |
13 | 13 | ||
14 | Module parameters for modules that are built into the kernel image | 14 | Module parameters for modules that are built into the kernel image |
15 | are specified on the kernel command line with the module name plus | 15 | are specified on the kernel command line with the module name plus |
16 | '.' plus parameter name, with '=' and value if appropriate, such as: | 16 | '.' plus parameter name, with '=' and value if appropriate, such as: |
17 | 17 | ||
18 | usbcore.blinkenlights=1 | 18 | usbcore.blinkenlights=1 |
19 | 19 | ||
20 | This document may not be entirely up to date and comprehensive. The command | 20 | This document may not be entirely up to date and comprehensive. The command |
21 | "modinfo -p ${modulename}" shows a current list of all parameters of a loadable | 21 | "modinfo -p ${modulename}" shows a current list of all parameters of a loadable |
22 | module. Loadable modules, after being loaded into the running kernel, also | 22 | module. Loadable modules, after being loaded into the running kernel, also |
23 | reveal their parameters in /sys/module/${modulename}/parameters/. Some of these | 23 | reveal their parameters in /sys/module/${modulename}/parameters/. Some of these |
24 | parameters may be changed at runtime by the command | 24 | parameters may be changed at runtime by the command |
25 | "echo -n ${value} > /sys/module/${modulename}/parameters/${parm}". | 25 | "echo -n ${value} > /sys/module/${modulename}/parameters/${parm}". |
26 | 26 | ||
27 | The parameters listed below are only valid if certain kernel build options were | 27 | The parameters listed below are only valid if certain kernel build options were |
28 | enabled and if respective hardware is present. The text in square brackets at | 28 | enabled and if respective hardware is present. The text in square brackets at |
29 | the beginning of each description states the restrictions within which a | 29 | the beginning of each description states the restrictions within which a |
30 | parameter is applicable: | 30 | parameter is applicable: |
31 | 31 | ||
32 | ACPI ACPI support is enabled. | 32 | ACPI ACPI support is enabled. |
33 | AGP AGP (Accelerated Graphics Port) is enabled. | 33 | AGP AGP (Accelerated Graphics Port) is enabled. |
34 | ALSA ALSA sound support is enabled. | 34 | ALSA ALSA sound support is enabled. |
35 | APIC APIC support is enabled. | 35 | APIC APIC support is enabled. |
36 | APM Advanced Power Management support is enabled. | 36 | APM Advanced Power Management support is enabled. |
37 | AVR32 AVR32 architecture is enabled. | 37 | AVR32 AVR32 architecture is enabled. |
38 | AX25 Appropriate AX.25 support is enabled. | 38 | AX25 Appropriate AX.25 support is enabled. |
39 | BLACKFIN Blackfin architecture is enabled. | 39 | BLACKFIN Blackfin architecture is enabled. |
40 | DRM Direct Rendering Management support is enabled. | 40 | DRM Direct Rendering Management support is enabled. |
41 | EDD BIOS Enhanced Disk Drive Services (EDD) is enabled | 41 | EDD BIOS Enhanced Disk Drive Services (EDD) is enabled |
42 | EFI EFI Partitioning (GPT) is enabled | 42 | EFI EFI Partitioning (GPT) is enabled |
43 | EIDE EIDE/ATAPI support is enabled. | 43 | EIDE EIDE/ATAPI support is enabled. |
44 | FB The frame buffer device is enabled. | 44 | FB The frame buffer device is enabled. |
45 | HW Appropriate hardware is enabled. | 45 | HW Appropriate hardware is enabled. |
46 | IA-64 IA-64 architecture is enabled. | 46 | IA-64 IA-64 architecture is enabled. |
47 | IOSCHED More than one I/O scheduler is enabled. | 47 | IOSCHED More than one I/O scheduler is enabled. |
48 | IP_PNP IP DHCP, BOOTP, or RARP is enabled. | 48 | IP_PNP IP DHCP, BOOTP, or RARP is enabled. |
49 | ISAPNP ISA PnP code is enabled. | 49 | ISAPNP ISA PnP code is enabled. |
50 | ISDN Appropriate ISDN support is enabled. | 50 | ISDN Appropriate ISDN support is enabled. |
51 | JOY Appropriate joystick support is enabled. | 51 | JOY Appropriate joystick support is enabled. |
52 | LIBATA Libata driver is enabled | 52 | LIBATA Libata driver is enabled |
53 | LP Printer support is enabled. | 53 | LP Printer support is enabled. |
54 | LOOP Loopback device support is enabled. | 54 | LOOP Loopback device support is enabled. |
55 | M68k M68k architecture is enabled. | 55 | M68k M68k architecture is enabled. |
56 | These options have more detailed description inside of | 56 | These options have more detailed description inside of |
57 | Documentation/m68k/kernel-options.txt. | 57 | Documentation/m68k/kernel-options.txt. |
58 | MCA MCA bus support is enabled. | 58 | MCA MCA bus support is enabled. |
59 | MDA MDA console support is enabled. | 59 | MDA MDA console support is enabled. |
60 | MOUSE Appropriate mouse support is enabled. | 60 | MOUSE Appropriate mouse support is enabled. |
61 | MSI Message Signaled Interrupts (PCI). | 61 | MSI Message Signaled Interrupts (PCI). |
62 | MTD MTD (Memory Technology Device) support is enabled. | 62 | MTD MTD (Memory Technology Device) support is enabled. |
63 | NET Appropriate network support is enabled. | 63 | NET Appropriate network support is enabled. |
64 | NUMA NUMA support is enabled. | 64 | NUMA NUMA support is enabled. |
65 | GENERIC_TIME The generic timeofday code is enabled. | 65 | GENERIC_TIME The generic timeofday code is enabled. |
66 | NFS Appropriate NFS support is enabled. | 66 | NFS Appropriate NFS support is enabled. |
67 | OSS OSS sound support is enabled. | 67 | OSS OSS sound support is enabled. |
68 | PV_OPS A paravirtualized kernel is enabled. | 68 | PV_OPS A paravirtualized kernel is enabled. |
69 | PARIDE The ParIDE (parallel port IDE) subsystem is enabled. | 69 | PARIDE The ParIDE (parallel port IDE) subsystem is enabled. |
70 | PARISC The PA-RISC architecture is enabled. | 70 | PARISC The PA-RISC architecture is enabled. |
71 | PCI PCI bus support is enabled. | 71 | PCI PCI bus support is enabled. |
72 | PCIE PCI Express support is enabled. | 72 | PCIE PCI Express support is enabled. |
73 | PCMCIA The PCMCIA subsystem is enabled. | 73 | PCMCIA The PCMCIA subsystem is enabled. |
74 | PNP Plug & Play support is enabled. | 74 | PNP Plug & Play support is enabled. |
75 | PPC PowerPC architecture is enabled. | 75 | PPC PowerPC architecture is enabled. |
76 | PPT Parallel port support is enabled. | 76 | PPT Parallel port support is enabled. |
77 | PS2 Appropriate PS/2 support is enabled. | 77 | PS2 Appropriate PS/2 support is enabled. |
78 | RAM RAM disk support is enabled. | 78 | RAM RAM disk support is enabled. |
79 | ROOTPLUG The example Root Plug LSM is enabled. | 79 | ROOTPLUG The example Root Plug LSM is enabled. |
80 | S390 S390 architecture is enabled. | 80 | S390 S390 architecture is enabled. |
81 | SCSI Appropriate SCSI support is enabled. | 81 | SCSI Appropriate SCSI support is enabled. |
82 | A lot of drivers has their options described inside of | 82 | A lot of drivers has their options described inside of |
83 | Documentation/scsi/. | 83 | Documentation/scsi/. |
84 | SECURITY Different security models are enabled. | 84 | SECURITY Different security models are enabled. |
85 | SELINUX SELinux support is enabled. | 85 | SELINUX SELinux support is enabled. |
86 | SERIAL Serial support is enabled. | 86 | SERIAL Serial support is enabled. |
87 | SH SuperH architecture is enabled. | 87 | SH SuperH architecture is enabled. |
88 | SMP The kernel is an SMP kernel. | 88 | SMP The kernel is an SMP kernel. |
89 | SPARC Sparc architecture is enabled. | 89 | SPARC Sparc architecture is enabled. |
90 | SWSUSP Software suspend (hibernation) is enabled. | 90 | SWSUSP Software suspend (hibernation) is enabled. |
91 | SUSPEND System suspend states are enabled. | 91 | SUSPEND System suspend states are enabled. |
92 | TS Appropriate touchscreen support is enabled. | 92 | TS Appropriate touchscreen support is enabled. |
93 | USB USB support is enabled. | 93 | USB USB support is enabled. |
94 | USBHID USB Human Interface Device support is enabled. | 94 | USBHID USB Human Interface Device support is enabled. |
95 | V4L Video For Linux support is enabled. | 95 | V4L Video For Linux support is enabled. |
96 | VGA The VGA console has been enabled. | 96 | VGA The VGA console has been enabled. |
97 | VT Virtual terminal support is enabled. | 97 | VT Virtual terminal support is enabled. |
98 | WDT Watchdog support is enabled. | 98 | WDT Watchdog support is enabled. |
99 | XT IBM PC/XT MFM hard disk support is enabled. | 99 | XT IBM PC/XT MFM hard disk support is enabled. |
100 | X86-32 X86-32, aka i386 architecture is enabled. | 100 | X86-32 X86-32, aka i386 architecture is enabled. |
101 | X86-64 X86-64 architecture is enabled. | 101 | X86-64 X86-64 architecture is enabled. |
102 | More X86-64 boot options can be found in | 102 | More X86-64 boot options can be found in |
103 | Documentation/x86/x86_64/boot-options.txt . | 103 | Documentation/x86/x86_64/boot-options.txt . |
104 | X86 Either 32bit or 64bit x86 (same as X86-32+X86-64) | 104 | X86 Either 32bit or 64bit x86 (same as X86-32+X86-64) |
105 | 105 | ||
106 | In addition, the following text indicates that the option: | 106 | In addition, the following text indicates that the option: |
107 | 107 | ||
108 | BUGS= Relates to possible processor bugs on the said processor. | 108 | BUGS= Relates to possible processor bugs on the said processor. |
109 | KNL Is a kernel start-up parameter. | 109 | KNL Is a kernel start-up parameter. |
110 | BOOT Is a boot loader parameter. | 110 | BOOT Is a boot loader parameter. |
111 | 111 | ||
112 | Parameters denoted with BOOT are actually interpreted by the boot | 112 | Parameters denoted with BOOT are actually interpreted by the boot |
113 | loader, and have no meaning to the kernel directly. | 113 | loader, and have no meaning to the kernel directly. |
114 | Do not modify the syntax of boot loader parameters without extreme | 114 | Do not modify the syntax of boot loader parameters without extreme |
115 | need or coordination with <Documentation/x86/i386/boot.txt>. | 115 | need or coordination with <Documentation/x86/i386/boot.txt>. |
116 | 116 | ||
117 | There are also arch-specific kernel-parameters not documented here. | 117 | There are also arch-specific kernel-parameters not documented here. |
118 | See for example <Documentation/x86/x86_64/boot-options.txt>. | 118 | See for example <Documentation/x86/x86_64/boot-options.txt>. |
119 | 119 | ||
120 | Note that ALL kernel parameters listed below are CASE SENSITIVE, and that | 120 | Note that ALL kernel parameters listed below are CASE SENSITIVE, and that |
121 | a trailing = on the name of any parameter states that that parameter will | 121 | a trailing = on the name of any parameter states that that parameter will |
122 | be entered as an environment variable, whereas its absence indicates that | 122 | be entered as an environment variable, whereas its absence indicates that |
123 | it will appear as a kernel argument readable via /proc/cmdline by programs | 123 | it will appear as a kernel argument readable via /proc/cmdline by programs |
124 | running once the system is up. | 124 | running once the system is up. |
125 | 125 | ||
126 | The number of kernel parameters is not limited, but the length of the | 126 | The number of kernel parameters is not limited, but the length of the |
127 | complete command line (parameters including spaces etc.) is limited to | 127 | complete command line (parameters including spaces etc.) is limited to |
128 | a fixed number of characters. This limit depends on the architecture | 128 | a fixed number of characters. This limit depends on the architecture |
129 | and is between 256 and 4096 characters. It is defined in the file | 129 | and is between 256 and 4096 characters. It is defined in the file |
130 | ./include/asm/setup.h as COMMAND_LINE_SIZE. | 130 | ./include/asm/setup.h as COMMAND_LINE_SIZE. |
131 | 131 | ||
132 | 132 | ||
133 | acpi= [HW,ACPI,X86-64,i386] | 133 | acpi= [HW,ACPI,X86-64,i386] |
134 | Advanced Configuration and Power Interface | 134 | Advanced Configuration and Power Interface |
135 | Format: { force | off | ht | strict | noirq } | 135 | Format: { force | off | ht | strict | noirq } |
136 | force -- enable ACPI if default was off | 136 | force -- enable ACPI if default was off |
137 | off -- disable ACPI if default was on | 137 | off -- disable ACPI if default was on |
138 | noirq -- do not use ACPI for IRQ routing | 138 | noirq -- do not use ACPI for IRQ routing |
139 | ht -- run only enough ACPI to enable Hyper Threading | 139 | ht -- run only enough ACPI to enable Hyper Threading |
140 | strict -- Be less tolerant of platforms that are not | 140 | strict -- Be less tolerant of platforms that are not |
141 | strictly ACPI specification compliant. | 141 | strictly ACPI specification compliant. |
142 | 142 | ||
143 | See also Documentation/power/pm.txt, pci=noacpi | 143 | See also Documentation/power/pm.txt, pci=noacpi |
144 | 144 | ||
145 | acpi_apic_instance= [ACPI, IOAPIC] | 145 | acpi_apic_instance= [ACPI, IOAPIC] |
146 | Format: <int> | 146 | Format: <int> |
147 | 2: use 2nd APIC table, if available | 147 | 2: use 2nd APIC table, if available |
148 | 1,0: use 1st APIC table | 148 | 1,0: use 1st APIC table |
149 | default: 0 | 149 | default: 0 |
150 | 150 | ||
151 | acpi_sleep= [HW,ACPI] Sleep options | 151 | acpi_sleep= [HW,ACPI] Sleep options |
152 | Format: { s3_bios, s3_mode, s3_beep, s4_nohwsig, old_ordering } | 152 | Format: { s3_bios, s3_mode, s3_beep, s4_nohwsig, old_ordering } |
153 | See Documentation/power/video.txt for s3_bios and s3_mode. | 153 | See Documentation/power/video.txt for s3_bios and s3_mode. |
154 | s3_beep is for debugging; it makes the PC's speaker beep | 154 | s3_beep is for debugging; it makes the PC's speaker beep |
155 | as soon as the kernel's real-mode entry point is called. | 155 | as soon as the kernel's real-mode entry point is called. |
156 | s4_nohwsig prevents ACPI hardware signature from being | 156 | s4_nohwsig prevents ACPI hardware signature from being |
157 | used during resume from hibernation. | 157 | used during resume from hibernation. |
158 | old_ordering causes the ACPI 1.0 ordering of the _PTS | 158 | old_ordering causes the ACPI 1.0 ordering of the _PTS |
159 | control method, wrt putting devices into low power | 159 | control method, wrt putting devices into low power |
160 | states, to be enforced (the ACPI 2.0 ordering of _PTS is | 160 | states, to be enforced (the ACPI 2.0 ordering of _PTS is |
161 | used by default). | 161 | used by default). |
162 | 162 | ||
163 | acpi_sci= [HW,ACPI] ACPI System Control Interrupt trigger mode | 163 | acpi_sci= [HW,ACPI] ACPI System Control Interrupt trigger mode |
164 | Format: { level | edge | high | low } | 164 | Format: { level | edge | high | low } |
165 | 165 | ||
166 | acpi_irq_balance [HW,ACPI] | 166 | acpi_irq_balance [HW,ACPI] |
167 | ACPI will balance active IRQs | 167 | ACPI will balance active IRQs |
168 | default in APIC mode | 168 | default in APIC mode |
169 | 169 | ||
170 | acpi_irq_nobalance [HW,ACPI] | 170 | acpi_irq_nobalance [HW,ACPI] |
171 | ACPI will not move active IRQs (default) | 171 | ACPI will not move active IRQs (default) |
172 | default in PIC mode | 172 | default in PIC mode |
173 | 173 | ||
174 | acpi_irq_pci= [HW,ACPI] If irq_balance, clear listed IRQs for | 174 | acpi_irq_pci= [HW,ACPI] If irq_balance, clear listed IRQs for |
175 | use by PCI | 175 | use by PCI |
176 | Format: <irq>,<irq>... | 176 | Format: <irq>,<irq>... |
177 | 177 | ||
178 | acpi_irq_isa= [HW,ACPI] If irq_balance, mark listed IRQs used by ISA | 178 | acpi_irq_isa= [HW,ACPI] If irq_balance, mark listed IRQs used by ISA |
179 | Format: <irq>,<irq>... | 179 | Format: <irq>,<irq>... |
180 | 180 | ||
181 | acpi_no_auto_ssdt [HW,ACPI] Disable automatic loading of SSDT | 181 | acpi_no_auto_ssdt [HW,ACPI] Disable automatic loading of SSDT |
182 | 182 | ||
183 | acpi_os_name= [HW,ACPI] Tell ACPI BIOS the name of the OS | 183 | acpi_os_name= [HW,ACPI] Tell ACPI BIOS the name of the OS |
184 | Format: To spoof as Windows 98: ="Microsoft Windows" | 184 | Format: To spoof as Windows 98: ="Microsoft Windows" |
185 | 185 | ||
186 | acpi_osi= [HW,ACPI] Modify list of supported OS interface strings | 186 | acpi_osi= [HW,ACPI] Modify list of supported OS interface strings |
187 | acpi_osi="string1" # add string1 -- only one string | 187 | acpi_osi="string1" # add string1 -- only one string |
188 | acpi_osi="!string2" # remove built-in string2 | 188 | acpi_osi="!string2" # remove built-in string2 |
189 | acpi_osi= # disable all strings | 189 | acpi_osi= # disable all strings |
190 | 190 | ||
191 | acpi_serialize [HW,ACPI] force serialization of AML methods | 191 | acpi_serialize [HW,ACPI] force serialization of AML methods |
192 | 192 | ||
193 | acpi_skip_timer_override [HW,ACPI] | 193 | acpi_skip_timer_override [HW,ACPI] |
194 | Recognize and ignore IRQ0/pin2 Interrupt Override. | 194 | Recognize and ignore IRQ0/pin2 Interrupt Override. |
195 | For broken nForce2 BIOS resulting in XT-PIC timer. | 195 | For broken nForce2 BIOS resulting in XT-PIC timer. |
196 | acpi_use_timer_override [HW,ACPI} | 196 | acpi_use_timer_override [HW,ACPI} |
197 | Use timer override. For some broken Nvidia NF5 boards | 197 | Use timer override. For some broken Nvidia NF5 boards |
198 | that require a timer override, but don't have | 198 | that require a timer override, but don't have |
199 | HPET | 199 | HPET |
200 | 200 | ||
201 | acpi_backlight= [HW,ACPI] | ||
202 | acpi_backlight=vendor | ||
203 | acpi_backlight=video | ||
204 | If set to vendor, prefer vendor specific driver | ||
205 | (e.g. thinkpad_acpi, sony_acpi, etc.) instead | ||
206 | of the ACPI video.ko driver. | ||
207 | |||
208 | acpi_display_output= [HW,ACPI] | ||
209 | acpi_display_output=vendor | ||
210 | acpi_display_output=video | ||
211 | See above. | ||
212 | |||
201 | acpi.debug_layer= [HW,ACPI,ACPI_DEBUG] | 213 | acpi.debug_layer= [HW,ACPI,ACPI_DEBUG] |
202 | acpi.debug_level= [HW,ACPI,ACPI_DEBUG] | 214 | acpi.debug_level= [HW,ACPI,ACPI_DEBUG] |
203 | Format: <int> | 215 | Format: <int> |
204 | CONFIG_ACPI_DEBUG must be enabled to produce any ACPI | 216 | CONFIG_ACPI_DEBUG must be enabled to produce any ACPI |
205 | debug output. Bits in debug_layer correspond to a | 217 | debug output. Bits in debug_layer correspond to a |
206 | _COMPONENT in an ACPI source file, e.g., | 218 | _COMPONENT in an ACPI source file, e.g., |
207 | #define _COMPONENT ACPI_PCI_COMPONENT | 219 | #define _COMPONENT ACPI_PCI_COMPONENT |
208 | Bits in debug_level correspond to a level in | 220 | Bits in debug_level correspond to a level in |
209 | ACPI_DEBUG_PRINT statements, e.g., | 221 | ACPI_DEBUG_PRINT statements, e.g., |
210 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, ... | 222 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, ... |
211 | See Documentation/acpi/debug.txt for more information | 223 | See Documentation/acpi/debug.txt for more information |
212 | about debug layers and levels. | 224 | about debug layers and levels. |
213 | 225 | ||
214 | Enable AML "Debug" output, i.e., stores to the Debug | 226 | Enable AML "Debug" output, i.e., stores to the Debug |
215 | object while interpreting AML: | 227 | object while interpreting AML: |
216 | acpi.debug_layer=0xffffffff acpi.debug_level=0x2 | 228 | acpi.debug_layer=0xffffffff acpi.debug_level=0x2 |
217 | Enable PCI/PCI interrupt routing info messages: | 229 | Enable PCI/PCI interrupt routing info messages: |
218 | acpi.debug_layer=0x400000 acpi.debug_level=0x4 | 230 | acpi.debug_layer=0x400000 acpi.debug_level=0x4 |
219 | Enable all messages related to ACPI hardware: | 231 | Enable all messages related to ACPI hardware: |
220 | acpi.debug_layer=0x2 acpi.debug_level=0xffffffff | 232 | acpi.debug_layer=0x2 acpi.debug_level=0xffffffff |
221 | 233 | ||
222 | Some values produce so much output that the system is | 234 | Some values produce so much output that the system is |
223 | unusable. The "log_buf_len" parameter may be useful | 235 | unusable. The "log_buf_len" parameter may be useful |
224 | if you need to capture more output. | 236 | if you need to capture more output. |
225 | 237 | ||
226 | acpi.power_nocheck= [HW,ACPI] | 238 | acpi.power_nocheck= [HW,ACPI] |
227 | Format: 1/0 enable/disable the check of power state. | 239 | Format: 1/0 enable/disable the check of power state. |
228 | On some bogus BIOS the _PSC object/_STA object of | 240 | On some bogus BIOS the _PSC object/_STA object of |
229 | power resource can't return the correct device power | 241 | power resource can't return the correct device power |
230 | state. In such case it is unneccessary to check its | 242 | state. In such case it is unneccessary to check its |
231 | power state again in power transition. | 243 | power state again in power transition. |
232 | 1 : disable the power state check | 244 | 1 : disable the power state check |
233 | 245 | ||
234 | acpi_pm_good [X86-32,X86-64] | 246 | acpi_pm_good [X86-32,X86-64] |
235 | Override the pmtimer bug detection: force the kernel | 247 | Override the pmtimer bug detection: force the kernel |
236 | to assume that this machine's pmtimer latches its value | 248 | to assume that this machine's pmtimer latches its value |
237 | and always returns good values. | 249 | and always returns good values. |
238 | 250 | ||
239 | agp= [AGP] | 251 | agp= [AGP] |
240 | { off | try_unsupported } | 252 | { off | try_unsupported } |
241 | off: disable AGP support | 253 | off: disable AGP support |
242 | try_unsupported: try to drive unsupported chipsets | 254 | try_unsupported: try to drive unsupported chipsets |
243 | (may crash computer or cause data corruption) | 255 | (may crash computer or cause data corruption) |
244 | 256 | ||
245 | enable_timer_pin_1 [i386,x86-64] | 257 | enable_timer_pin_1 [i386,x86-64] |
246 | Enable PIN 1 of APIC timer | 258 | Enable PIN 1 of APIC timer |
247 | Can be useful to work around chipset bugs | 259 | Can be useful to work around chipset bugs |
248 | (in particular on some ATI chipsets). | 260 | (in particular on some ATI chipsets). |
249 | The kernel tries to set a reasonable default. | 261 | The kernel tries to set a reasonable default. |
250 | 262 | ||
251 | disable_timer_pin_1 [i386,x86-64] | 263 | disable_timer_pin_1 [i386,x86-64] |
252 | Disable PIN 1 of APIC timer | 264 | Disable PIN 1 of APIC timer |
253 | Can be useful to work around chipset bugs. | 265 | Can be useful to work around chipset bugs. |
254 | 266 | ||
255 | ad1848= [HW,OSS] | 267 | ad1848= [HW,OSS] |
256 | Format: <io>,<irq>,<dma>,<dma2>,<type> | 268 | Format: <io>,<irq>,<dma>,<dma2>,<type> |
257 | 269 | ||
258 | advansys= [HW,SCSI] | 270 | advansys= [HW,SCSI] |
259 | See header of drivers/scsi/advansys.c. | 271 | See header of drivers/scsi/advansys.c. |
260 | 272 | ||
261 | advwdt= [HW,WDT] Advantech WDT | 273 | advwdt= [HW,WDT] Advantech WDT |
262 | Format: <iostart>,<iostop> | 274 | Format: <iostart>,<iostop> |
263 | 275 | ||
264 | aedsp16= [HW,OSS] Audio Excel DSP 16 | 276 | aedsp16= [HW,OSS] Audio Excel DSP 16 |
265 | Format: <io>,<irq>,<dma>,<mss_io>,<mpu_io>,<mpu_irq> | 277 | Format: <io>,<irq>,<dma>,<mss_io>,<mpu_io>,<mpu_irq> |
266 | See also header of sound/oss/aedsp16.c. | 278 | See also header of sound/oss/aedsp16.c. |
267 | 279 | ||
268 | aha152x= [HW,SCSI] | 280 | aha152x= [HW,SCSI] |
269 | See Documentation/scsi/aha152x.txt. | 281 | See Documentation/scsi/aha152x.txt. |
270 | 282 | ||
271 | aha1542= [HW,SCSI] | 283 | aha1542= [HW,SCSI] |
272 | Format: <portbase>[,<buson>,<busoff>[,<dmaspeed>]] | 284 | Format: <portbase>[,<buson>,<busoff>[,<dmaspeed>]] |
273 | 285 | ||
274 | aic7xxx= [HW,SCSI] | 286 | aic7xxx= [HW,SCSI] |
275 | See Documentation/scsi/aic7xxx.txt. | 287 | See Documentation/scsi/aic7xxx.txt. |
276 | 288 | ||
277 | aic79xx= [HW,SCSI] | 289 | aic79xx= [HW,SCSI] |
278 | See Documentation/scsi/aic79xx.txt. | 290 | See Documentation/scsi/aic79xx.txt. |
279 | 291 | ||
280 | amd_iommu= [HW,X86-84] | 292 | amd_iommu= [HW,X86-84] |
281 | Pass parameters to the AMD IOMMU driver in the system. | 293 | Pass parameters to the AMD IOMMU driver in the system. |
282 | Possible values are: | 294 | Possible values are: |
283 | isolate - enable device isolation (each device, as far | 295 | isolate - enable device isolation (each device, as far |
284 | as possible, will get its own protection | 296 | as possible, will get its own protection |
285 | domain) | 297 | domain) |
286 | fullflush - enable flushing of IO/TLB entries when | 298 | fullflush - enable flushing of IO/TLB entries when |
287 | they are unmapped. Otherwise they are | 299 | they are unmapped. Otherwise they are |
288 | flushed before they will be reused, which | 300 | flushed before they will be reused, which |
289 | is a lot of faster | 301 | is a lot of faster |
290 | 302 | ||
291 | amd_iommu_size= [HW,X86-64] | 303 | amd_iommu_size= [HW,X86-64] |
292 | Define the size of the aperture for the AMD IOMMU | 304 | Define the size of the aperture for the AMD IOMMU |
293 | driver. Possible values are: | 305 | driver. Possible values are: |
294 | '32M', '64M' (default), '128M', '256M', '512M', '1G' | 306 | '32M', '64M' (default), '128M', '256M', '512M', '1G' |
295 | 307 | ||
296 | amijoy.map= [HW,JOY] Amiga joystick support | 308 | amijoy.map= [HW,JOY] Amiga joystick support |
297 | Map of devices attached to JOY0DAT and JOY1DAT | 309 | Map of devices attached to JOY0DAT and JOY1DAT |
298 | Format: <a>,<b> | 310 | Format: <a>,<b> |
299 | See also Documentation/kernel/input/joystick.txt | 311 | See also Documentation/kernel/input/joystick.txt |
300 | 312 | ||
301 | analog.map= [HW,JOY] Analog joystick and gamepad support | 313 | analog.map= [HW,JOY] Analog joystick and gamepad support |
302 | Specifies type or capabilities of an analog joystick | 314 | Specifies type or capabilities of an analog joystick |
303 | connected to one of 16 gameports | 315 | connected to one of 16 gameports |
304 | Format: <type1>,<type2>,..<type16> | 316 | Format: <type1>,<type2>,..<type16> |
305 | 317 | ||
306 | apc= [HW,SPARC] | 318 | apc= [HW,SPARC] |
307 | Power management functions (SPARCstation-4/5 + deriv.) | 319 | Power management functions (SPARCstation-4/5 + deriv.) |
308 | Format: noidle | 320 | Format: noidle |
309 | Disable APC CPU standby support. SPARCstation-Fox does | 321 | Disable APC CPU standby support. SPARCstation-Fox does |
310 | not play well with APC CPU idle - disable it if you have | 322 | not play well with APC CPU idle - disable it if you have |
311 | APC and your system crashes randomly. | 323 | APC and your system crashes randomly. |
312 | 324 | ||
313 | apic= [APIC,i386] Advanced Programmable Interrupt Controller | 325 | apic= [APIC,i386] Advanced Programmable Interrupt Controller |
314 | Change the output verbosity whilst booting | 326 | Change the output verbosity whilst booting |
315 | Format: { quiet (default) | verbose | debug } | 327 | Format: { quiet (default) | verbose | debug } |
316 | Change the amount of debugging information output | 328 | Change the amount of debugging information output |
317 | when initialising the APIC and IO-APIC components. | 329 | when initialising the APIC and IO-APIC components. |
318 | 330 | ||
319 | apm= [APM] Advanced Power Management | 331 | apm= [APM] Advanced Power Management |
320 | See header of arch/x86/kernel/apm_32.c. | 332 | See header of arch/x86/kernel/apm_32.c. |
321 | 333 | ||
322 | arcrimi= [HW,NET] ARCnet - "RIM I" (entirely mem-mapped) cards | 334 | arcrimi= [HW,NET] ARCnet - "RIM I" (entirely mem-mapped) cards |
323 | Format: <io>,<irq>,<nodeID> | 335 | Format: <io>,<irq>,<nodeID> |
324 | 336 | ||
325 | ataflop= [HW,M68k] | 337 | ataflop= [HW,M68k] |
326 | 338 | ||
327 | atarimouse= [HW,MOUSE] Atari Mouse | 339 | atarimouse= [HW,MOUSE] Atari Mouse |
328 | 340 | ||
329 | atascsi= [HW,SCSI] Atari SCSI | 341 | atascsi= [HW,SCSI] Atari SCSI |
330 | 342 | ||
331 | atkbd.extra= [HW] Enable extra LEDs and keys on IBM RapidAccess, | 343 | atkbd.extra= [HW] Enable extra LEDs and keys on IBM RapidAccess, |
332 | EzKey and similar keyboards | 344 | EzKey and similar keyboards |
333 | 345 | ||
334 | atkbd.reset= [HW] Reset keyboard during initialization | 346 | atkbd.reset= [HW] Reset keyboard during initialization |
335 | 347 | ||
336 | atkbd.set= [HW] Select keyboard code set | 348 | atkbd.set= [HW] Select keyboard code set |
337 | Format: <int> (2 = AT (default), 3 = PS/2) | 349 | Format: <int> (2 = AT (default), 3 = PS/2) |
338 | 350 | ||
339 | atkbd.scroll= [HW] Enable scroll wheel on MS Office and similar | 351 | atkbd.scroll= [HW] Enable scroll wheel on MS Office and similar |
340 | keyboards | 352 | keyboards |
341 | 353 | ||
342 | atkbd.softraw= [HW] Choose between synthetic and real raw mode | 354 | atkbd.softraw= [HW] Choose between synthetic and real raw mode |
343 | Format: <bool> (0 = real, 1 = synthetic (default)) | 355 | Format: <bool> (0 = real, 1 = synthetic (default)) |
344 | 356 | ||
345 | atkbd.softrepeat= [HW] | 357 | atkbd.softrepeat= [HW] |
346 | Use software keyboard repeat | 358 | Use software keyboard repeat |
347 | 359 | ||
348 | autotest [IA64] | 360 | autotest [IA64] |
349 | 361 | ||
350 | baycom_epp= [HW,AX25] | 362 | baycom_epp= [HW,AX25] |
351 | Format: <io>,<mode> | 363 | Format: <io>,<mode> |
352 | 364 | ||
353 | baycom_par= [HW,AX25] BayCom Parallel Port AX.25 Modem | 365 | baycom_par= [HW,AX25] BayCom Parallel Port AX.25 Modem |
354 | Format: <io>,<mode> | 366 | Format: <io>,<mode> |
355 | See header of drivers/net/hamradio/baycom_par.c. | 367 | See header of drivers/net/hamradio/baycom_par.c. |
356 | 368 | ||
357 | baycom_ser_fdx= [HW,AX25] | 369 | baycom_ser_fdx= [HW,AX25] |
358 | BayCom Serial Port AX.25 Modem (Full Duplex Mode) | 370 | BayCom Serial Port AX.25 Modem (Full Duplex Mode) |
359 | Format: <io>,<irq>,<mode>[,<baud>] | 371 | Format: <io>,<irq>,<mode>[,<baud>] |
360 | See header of drivers/net/hamradio/baycom_ser_fdx.c. | 372 | See header of drivers/net/hamradio/baycom_ser_fdx.c. |
361 | 373 | ||
362 | baycom_ser_hdx= [HW,AX25] | 374 | baycom_ser_hdx= [HW,AX25] |
363 | BayCom Serial Port AX.25 Modem (Half Duplex Mode) | 375 | BayCom Serial Port AX.25 Modem (Half Duplex Mode) |
364 | Format: <io>,<irq>,<mode> | 376 | Format: <io>,<irq>,<mode> |
365 | See header of drivers/net/hamradio/baycom_ser_hdx.c. | 377 | See header of drivers/net/hamradio/baycom_ser_hdx.c. |
366 | 378 | ||
367 | boot_delay= Milliseconds to delay each printk during boot. | 379 | boot_delay= Milliseconds to delay each printk during boot. |
368 | Values larger than 10 seconds (10000) are changed to | 380 | Values larger than 10 seconds (10000) are changed to |
369 | no delay (0). | 381 | no delay (0). |
370 | Format: integer | 382 | Format: integer |
371 | 383 | ||
372 | bootmem_debug [KNL] Enable bootmem allocator debug messages. | 384 | bootmem_debug [KNL] Enable bootmem allocator debug messages. |
373 | 385 | ||
374 | bttv.card= [HW,V4L] bttv (bt848 + bt878 based grabber cards) | 386 | bttv.card= [HW,V4L] bttv (bt848 + bt878 based grabber cards) |
375 | bttv.radio= Most important insmod options are available as | 387 | bttv.radio= Most important insmod options are available as |
376 | kernel args too. | 388 | kernel args too. |
377 | bttv.pll= See Documentation/video4linux/bttv/Insmod-options | 389 | bttv.pll= See Documentation/video4linux/bttv/Insmod-options |
378 | bttv.tuner= and Documentation/video4linux/bttv/CARDLIST | 390 | bttv.tuner= and Documentation/video4linux/bttv/CARDLIST |
379 | 391 | ||
380 | BusLogic= [HW,SCSI] | 392 | BusLogic= [HW,SCSI] |
381 | See drivers/scsi/BusLogic.c, comment before function | 393 | See drivers/scsi/BusLogic.c, comment before function |
382 | BusLogic_ParseDriverOptions(). | 394 | BusLogic_ParseDriverOptions(). |
383 | 395 | ||
384 | c101= [NET] Moxa C101 synchronous serial card | 396 | c101= [NET] Moxa C101 synchronous serial card |
385 | 397 | ||
386 | cachesize= [BUGS=X86-32] Override level 2 CPU cache size detection. | 398 | cachesize= [BUGS=X86-32] Override level 2 CPU cache size detection. |
387 | Sometimes CPU hardware bugs make them report the cache | 399 | Sometimes CPU hardware bugs make them report the cache |
388 | size incorrectly. The kernel will attempt work arounds | 400 | size incorrectly. The kernel will attempt work arounds |
389 | to fix known problems, but for some CPUs it is not | 401 | to fix known problems, but for some CPUs it is not |
390 | possible to determine what the correct size should be. | 402 | possible to determine what the correct size should be. |
391 | This option provides an override for these situations. | 403 | This option provides an override for these situations. |
392 | 404 | ||
393 | security= [SECURITY] Choose a security module to enable at boot. | 405 | security= [SECURITY] Choose a security module to enable at boot. |
394 | If this boot parameter is not specified, only the first | 406 | If this boot parameter is not specified, only the first |
395 | security module asking for security registration will be | 407 | security module asking for security registration will be |
396 | loaded. An invalid security module name will be treated | 408 | loaded. An invalid security module name will be treated |
397 | as if no module has been chosen. | 409 | as if no module has been chosen. |
398 | 410 | ||
399 | capability.disable= | 411 | capability.disable= |
400 | [SECURITY] Disable capabilities. This would normally | 412 | [SECURITY] Disable capabilities. This would normally |
401 | be used only if an alternative security model is to be | 413 | be used only if an alternative security model is to be |
402 | configured. Potentially dangerous and should only be | 414 | configured. Potentially dangerous and should only be |
403 | used if you are entirely sure of the consequences. | 415 | used if you are entirely sure of the consequences. |
404 | 416 | ||
405 | ccw_timeout_log [S390] | 417 | ccw_timeout_log [S390] |
406 | See Documentation/s390/CommonIO for details. | 418 | See Documentation/s390/CommonIO for details. |
407 | 419 | ||
408 | cgroup_disable= [KNL] Disable a particular controller | 420 | cgroup_disable= [KNL] Disable a particular controller |
409 | Format: {name of the controller(s) to disable} | 421 | Format: {name of the controller(s) to disable} |
410 | {Currently supported controllers - "memory"} | 422 | {Currently supported controllers - "memory"} |
411 | 423 | ||
412 | checkreqprot [SELINUX] Set initial checkreqprot flag value. | 424 | checkreqprot [SELINUX] Set initial checkreqprot flag value. |
413 | Format: { "0" | "1" } | 425 | Format: { "0" | "1" } |
414 | See security/selinux/Kconfig help text. | 426 | See security/selinux/Kconfig help text. |
415 | 0 -- check protection applied by kernel (includes | 427 | 0 -- check protection applied by kernel (includes |
416 | any implied execute protection). | 428 | any implied execute protection). |
417 | 1 -- check protection requested by application. | 429 | 1 -- check protection requested by application. |
418 | Default value is set via a kernel config option. | 430 | Default value is set via a kernel config option. |
419 | Value can be changed at runtime via | 431 | Value can be changed at runtime via |
420 | /selinux/checkreqprot. | 432 | /selinux/checkreqprot. |
421 | 433 | ||
422 | cio_ignore= [S390] | 434 | cio_ignore= [S390] |
423 | See Documentation/s390/CommonIO for details. | 435 | See Documentation/s390/CommonIO for details. |
424 | 436 | ||
425 | clock= [BUGS=X86-32, HW] gettimeofday clocksource override. | 437 | clock= [BUGS=X86-32, HW] gettimeofday clocksource override. |
426 | [Deprecated] | 438 | [Deprecated] |
427 | Forces specified clocksource (if available) to be used | 439 | Forces specified clocksource (if available) to be used |
428 | when calculating gettimeofday(). If specified | 440 | when calculating gettimeofday(). If specified |
429 | clocksource is not available, it defaults to PIT. | 441 | clocksource is not available, it defaults to PIT. |
430 | Format: { pit | tsc | cyclone | pmtmr } | 442 | Format: { pit | tsc | cyclone | pmtmr } |
431 | 443 | ||
432 | clocksource= [GENERIC_TIME] Override the default clocksource | 444 | clocksource= [GENERIC_TIME] Override the default clocksource |
433 | Format: <string> | 445 | Format: <string> |
434 | Override the default clocksource and use the clocksource | 446 | Override the default clocksource and use the clocksource |
435 | with the name specified. | 447 | with the name specified. |
436 | Some clocksource names to choose from, depending on | 448 | Some clocksource names to choose from, depending on |
437 | the platform: | 449 | the platform: |
438 | [all] jiffies (this is the base, fallback clocksource) | 450 | [all] jiffies (this is the base, fallback clocksource) |
439 | [ACPI] acpi_pm | 451 | [ACPI] acpi_pm |
440 | [ARM] imx_timer1,OSTS,netx_timer,mpu_timer2, | 452 | [ARM] imx_timer1,OSTS,netx_timer,mpu_timer2, |
441 | pxa_timer,timer3,32k_counter,timer0_1 | 453 | pxa_timer,timer3,32k_counter,timer0_1 |
442 | [AVR32] avr32 | 454 | [AVR32] avr32 |
443 | [X86-32] pit,hpet,tsc,vmi-timer; | 455 | [X86-32] pit,hpet,tsc,vmi-timer; |
444 | scx200_hrt on Geode; cyclone on IBM x440 | 456 | scx200_hrt on Geode; cyclone on IBM x440 |
445 | [MIPS] MIPS | 457 | [MIPS] MIPS |
446 | [PARISC] cr16 | 458 | [PARISC] cr16 |
447 | [S390] tod | 459 | [S390] tod |
448 | [SH] SuperH | 460 | [SH] SuperH |
449 | [SPARC64] tick | 461 | [SPARC64] tick |
450 | [X86-64] hpet,tsc | 462 | [X86-64] hpet,tsc |
451 | 463 | ||
452 | clearcpuid=BITNUM [X86] | 464 | clearcpuid=BITNUM [X86] |
453 | Disable CPUID feature X for the kernel. See | 465 | Disable CPUID feature X for the kernel. See |
454 | include/asm-x86/cpufeature.h for the valid bit numbers. | 466 | include/asm-x86/cpufeature.h for the valid bit numbers. |
455 | Note the Linux specific bits are not necessarily | 467 | Note the Linux specific bits are not necessarily |
456 | stable over kernel options, but the vendor specific | 468 | stable over kernel options, but the vendor specific |
457 | ones should be. | 469 | ones should be. |
458 | Also note that user programs calling CPUID directly | 470 | Also note that user programs calling CPUID directly |
459 | or using the feature without checking anything | 471 | or using the feature without checking anything |
460 | will still see it. This just prevents it from | 472 | will still see it. This just prevents it from |
461 | being used by the kernel or shown in /proc/cpuinfo. | 473 | being used by the kernel or shown in /proc/cpuinfo. |
462 | Also note the kernel might malfunction if you disable | 474 | Also note the kernel might malfunction if you disable |
463 | some critical bits. | 475 | some critical bits. |
464 | 476 | ||
465 | code_bytes [IA32/X86_64] How many bytes of object code to print | 477 | code_bytes [IA32/X86_64] How many bytes of object code to print |
466 | in an oops report. | 478 | in an oops report. |
467 | Range: 0 - 8192 | 479 | Range: 0 - 8192 |
468 | Default: 64 | 480 | Default: 64 |
469 | 481 | ||
470 | hpet= [X86-32,HPET] option to control HPET usage | 482 | hpet= [X86-32,HPET] option to control HPET usage |
471 | Format: { enable (default) | disable | force } | 483 | Format: { enable (default) | disable | force } |
472 | disable: disable HPET and use PIT instead | 484 | disable: disable HPET and use PIT instead |
473 | force: allow force enabled of undocumented chips (ICH4, | 485 | force: allow force enabled of undocumented chips (ICH4, |
474 | VIA, nVidia) | 486 | VIA, nVidia) |
475 | 487 | ||
476 | com20020= [HW,NET] ARCnet - COM20020 chipset | 488 | com20020= [HW,NET] ARCnet - COM20020 chipset |
477 | Format: | 489 | Format: |
478 | <io>[,<irq>[,<nodeID>[,<backplane>[,<ckp>[,<timeout>]]]]] | 490 | <io>[,<irq>[,<nodeID>[,<backplane>[,<ckp>[,<timeout>]]]]] |
479 | 491 | ||
480 | com90io= [HW,NET] ARCnet - COM90xx chipset (IO-mapped buffers) | 492 | com90io= [HW,NET] ARCnet - COM90xx chipset (IO-mapped buffers) |
481 | Format: <io>[,<irq>] | 493 | Format: <io>[,<irq>] |
482 | 494 | ||
483 | com90xx= [HW,NET] | 495 | com90xx= [HW,NET] |
484 | ARCnet - COM90xx chipset (memory-mapped buffers) | 496 | ARCnet - COM90xx chipset (memory-mapped buffers) |
485 | Format: <io>[,<irq>[,<memstart>]] | 497 | Format: <io>[,<irq>[,<memstart>]] |
486 | 498 | ||
487 | condev= [HW,S390] console device | 499 | condev= [HW,S390] console device |
488 | conmode= | 500 | conmode= |
489 | 501 | ||
490 | console= [KNL] Output console device and options. | 502 | console= [KNL] Output console device and options. |
491 | 503 | ||
492 | tty<n> Use the virtual console device <n>. | 504 | tty<n> Use the virtual console device <n>. |
493 | 505 | ||
494 | ttyS<n>[,options] | 506 | ttyS<n>[,options] |
495 | ttyUSB0[,options] | 507 | ttyUSB0[,options] |
496 | Use the specified serial port. The options are of | 508 | Use the specified serial port. The options are of |
497 | the form "bbbbpnf", where "bbbb" is the baud rate, | 509 | the form "bbbbpnf", where "bbbb" is the baud rate, |
498 | "p" is parity ("n", "o", or "e"), "n" is number of | 510 | "p" is parity ("n", "o", or "e"), "n" is number of |
499 | bits, and "f" is flow control ("r" for RTS or | 511 | bits, and "f" is flow control ("r" for RTS or |
500 | omit it). Default is "9600n8". | 512 | omit it). Default is "9600n8". |
501 | 513 | ||
502 | See Documentation/serial-console.txt for more | 514 | See Documentation/serial-console.txt for more |
503 | information. See | 515 | information. See |
504 | Documentation/networking/netconsole.txt for an | 516 | Documentation/networking/netconsole.txt for an |
505 | alternative. | 517 | alternative. |
506 | 518 | ||
507 | uart[8250],io,<addr>[,options] | 519 | uart[8250],io,<addr>[,options] |
508 | uart[8250],mmio,<addr>[,options] | 520 | uart[8250],mmio,<addr>[,options] |
509 | Start an early, polled-mode console on the 8250/16550 | 521 | Start an early, polled-mode console on the 8250/16550 |
510 | UART at the specified I/O port or MMIO address, | 522 | UART at the specified I/O port or MMIO address, |
511 | switching to the matching ttyS device later. The | 523 | switching to the matching ttyS device later. The |
512 | options are the same as for ttyS, above. | 524 | options are the same as for ttyS, above. |
513 | 525 | ||
514 | If the device connected to the port is not a TTY but a braille | 526 | If the device connected to the port is not a TTY but a braille |
515 | device, prepend "brl," before the device type, for instance | 527 | device, prepend "brl," before the device type, for instance |
516 | console=brl,ttyS0 | 528 | console=brl,ttyS0 |
517 | For now, only VisioBraille is supported. | 529 | For now, only VisioBraille is supported. |
518 | 530 | ||
519 | earlycon= [KNL] Output early console device and options. | 531 | earlycon= [KNL] Output early console device and options. |
520 | uart[8250],io,<addr>[,options] | 532 | uart[8250],io,<addr>[,options] |
521 | uart[8250],mmio,<addr>[,options] | 533 | uart[8250],mmio,<addr>[,options] |
522 | Start an early, polled-mode console on the 8250/16550 | 534 | Start an early, polled-mode console on the 8250/16550 |
523 | UART at the specified I/O port or MMIO address. | 535 | UART at the specified I/O port or MMIO address. |
524 | The options are the same as for ttyS, above. | 536 | The options are the same as for ttyS, above. |
525 | 537 | ||
526 | no_console_suspend | 538 | no_console_suspend |
527 | [HW] Never suspend the console | 539 | [HW] Never suspend the console |
528 | Disable suspending of consoles during suspend and | 540 | Disable suspending of consoles during suspend and |
529 | hibernate operations. Once disabled, debugging | 541 | hibernate operations. Once disabled, debugging |
530 | messages can reach various consoles while the rest | 542 | messages can reach various consoles while the rest |
531 | of the system is being put to sleep (ie, while | 543 | of the system is being put to sleep (ie, while |
532 | debugging driver suspend/resume hooks). This may | 544 | debugging driver suspend/resume hooks). This may |
533 | not work reliably with all consoles, but is known | 545 | not work reliably with all consoles, but is known |
534 | to work with serial and VGA consoles. | 546 | to work with serial and VGA consoles. |
535 | 547 | ||
536 | cpcihp_generic= [HW,PCI] Generic port I/O CompactPCI driver | 548 | cpcihp_generic= [HW,PCI] Generic port I/O CompactPCI driver |
537 | Format: | 549 | Format: |
538 | <first_slot>,<last_slot>,<port>,<enum_bit>[,<debug>] | 550 | <first_slot>,<last_slot>,<port>,<enum_bit>[,<debug>] |
539 | 551 | ||
540 | crashkernel=nn[KMG]@ss[KMG] | 552 | crashkernel=nn[KMG]@ss[KMG] |
541 | [KNL] Reserve a chunk of physical memory to | 553 | [KNL] Reserve a chunk of physical memory to |
542 | hold a kernel to switch to with kexec on panic. | 554 | hold a kernel to switch to with kexec on panic. |
543 | 555 | ||
544 | crashkernel=range1:size1[,range2:size2,...][@offset] | 556 | crashkernel=range1:size1[,range2:size2,...][@offset] |
545 | [KNL] Same as above, but depends on the memory | 557 | [KNL] Same as above, but depends on the memory |
546 | in the running system. The syntax of range is | 558 | in the running system. The syntax of range is |
547 | start-[end] where start and end are both | 559 | start-[end] where start and end are both |
548 | a memory unit (amount[KMG]). See also | 560 | a memory unit (amount[KMG]). See also |
549 | Documentation/kdump/kdump.txt for a example. | 561 | Documentation/kdump/kdump.txt for a example. |
550 | 562 | ||
551 | cs4232= [HW,OSS] | 563 | cs4232= [HW,OSS] |
552 | Format: <io>,<irq>,<dma>,<dma2>,<mpuio>,<mpuirq> | 564 | Format: <io>,<irq>,<dma>,<dma2>,<mpuio>,<mpuirq> |
553 | 565 | ||
554 | cs89x0_dma= [HW,NET] | 566 | cs89x0_dma= [HW,NET] |
555 | Format: <dma> | 567 | Format: <dma> |
556 | 568 | ||
557 | cs89x0_media= [HW,NET] | 569 | cs89x0_media= [HW,NET] |
558 | Format: { rj45 | aui | bnc } | 570 | Format: { rj45 | aui | bnc } |
559 | 571 | ||
560 | dasd= [HW,NET] | 572 | dasd= [HW,NET] |
561 | See header of drivers/s390/block/dasd_devmap.c. | 573 | See header of drivers/s390/block/dasd_devmap.c. |
562 | 574 | ||
563 | db9.dev[2|3]= [HW,JOY] Multisystem joystick support via parallel port | 575 | db9.dev[2|3]= [HW,JOY] Multisystem joystick support via parallel port |
564 | (one device per port) | 576 | (one device per port) |
565 | Format: <port#>,<type> | 577 | Format: <port#>,<type> |
566 | See also Documentation/input/joystick-parport.txt | 578 | See also Documentation/input/joystick-parport.txt |
567 | 579 | ||
568 | debug [KNL] Enable kernel debugging (events log level). | 580 | debug [KNL] Enable kernel debugging (events log level). |
569 | 581 | ||
570 | debug_locks_verbose= | 582 | debug_locks_verbose= |
571 | [KNL] verbose self-tests | 583 | [KNL] verbose self-tests |
572 | Format=<0|1> | 584 | Format=<0|1> |
573 | Print debugging info while doing the locking API | 585 | Print debugging info while doing the locking API |
574 | self-tests. | 586 | self-tests. |
575 | We default to 0 (no extra messages), setting it to | 587 | We default to 0 (no extra messages), setting it to |
576 | 1 will print _a lot_ more information - normally | 588 | 1 will print _a lot_ more information - normally |
577 | only useful to kernel developers. | 589 | only useful to kernel developers. |
578 | 590 | ||
579 | debug_objects [KNL] Enable object debugging | 591 | debug_objects [KNL] Enable object debugging |
580 | 592 | ||
581 | debugpat [X86] Enable PAT debugging | 593 | debugpat [X86] Enable PAT debugging |
582 | 594 | ||
583 | decnet.addr= [HW,NET] | 595 | decnet.addr= [HW,NET] |
584 | Format: <area>[,<node>] | 596 | Format: <area>[,<node>] |
585 | See also Documentation/networking/decnet.txt. | 597 | See also Documentation/networking/decnet.txt. |
586 | 598 | ||
587 | vt.default_blu= [VT] | 599 | vt.default_blu= [VT] |
588 | Format: <blue0>,<blue1>,<blue2>,...,<blue15> | 600 | Format: <blue0>,<blue1>,<blue2>,...,<blue15> |
589 | Change the default blue palette of the console. | 601 | Change the default blue palette of the console. |
590 | This is a 16-member array composed of values | 602 | This is a 16-member array composed of values |
591 | ranging from 0-255. | 603 | ranging from 0-255. |
592 | 604 | ||
593 | vt.default_grn= [VT] | 605 | vt.default_grn= [VT] |
594 | Format: <green0>,<green1>,<green2>,...,<green15> | 606 | Format: <green0>,<green1>,<green2>,...,<green15> |
595 | Change the default green palette of the console. | 607 | Change the default green palette of the console. |
596 | This is a 16-member array composed of values | 608 | This is a 16-member array composed of values |
597 | ranging from 0-255. | 609 | ranging from 0-255. |
598 | 610 | ||
599 | vt.default_red= [VT] | 611 | vt.default_red= [VT] |
600 | Format: <red0>,<red1>,<red2>,...,<red15> | 612 | Format: <red0>,<red1>,<red2>,...,<red15> |
601 | Change the default red palette of the console. | 613 | Change the default red palette of the console. |
602 | This is a 16-member array composed of values | 614 | This is a 16-member array composed of values |
603 | ranging from 0-255. | 615 | ranging from 0-255. |
604 | 616 | ||
605 | vt.default_utf8= | 617 | vt.default_utf8= |
606 | [VT] | 618 | [VT] |
607 | Format=<0|1> | 619 | Format=<0|1> |
608 | Set system-wide default UTF-8 mode for all tty's. | 620 | Set system-wide default UTF-8 mode for all tty's. |
609 | Default is 1, i.e. UTF-8 mode is enabled for all | 621 | Default is 1, i.e. UTF-8 mode is enabled for all |
610 | newly opened terminals. | 622 | newly opened terminals. |
611 | 623 | ||
612 | dhash_entries= [KNL] | 624 | dhash_entries= [KNL] |
613 | Set number of hash buckets for dentry cache. | 625 | Set number of hash buckets for dentry cache. |
614 | 626 | ||
615 | digi= [HW,SERIAL] | 627 | digi= [HW,SERIAL] |
616 | IO parameters + enable/disable command. | 628 | IO parameters + enable/disable command. |
617 | 629 | ||
618 | digiepca= [HW,SERIAL] | 630 | digiepca= [HW,SERIAL] |
619 | See drivers/char/README.epca and | 631 | See drivers/char/README.epca and |
620 | Documentation/digiepca.txt. | 632 | Documentation/digiepca.txt. |
621 | 633 | ||
622 | disable_mtrr_cleanup [X86] | 634 | disable_mtrr_cleanup [X86] |
623 | enable_mtrr_cleanup [X86] | 635 | enable_mtrr_cleanup [X86] |
624 | The kernel tries to adjust MTRR layout from continuous | 636 | The kernel tries to adjust MTRR layout from continuous |
625 | to discrete, to make X server driver able to add WB | 637 | to discrete, to make X server driver able to add WB |
626 | entry later. This parameter enables/disables that. | 638 | entry later. This parameter enables/disables that. |
627 | 639 | ||
628 | mtrr_chunk_size=nn[KMG] [X86] | 640 | mtrr_chunk_size=nn[KMG] [X86] |
629 | used for mtrr cleanup. It is largest continous chunk | 641 | used for mtrr cleanup. It is largest continous chunk |
630 | that could hold holes aka. UC entries. | 642 | that could hold holes aka. UC entries. |
631 | 643 | ||
632 | mtrr_gran_size=nn[KMG] [X86] | 644 | mtrr_gran_size=nn[KMG] [X86] |
633 | Used for mtrr cleanup. It is granularity of mtrr block. | 645 | Used for mtrr cleanup. It is granularity of mtrr block. |
634 | Default is 1. | 646 | Default is 1. |
635 | Large value could prevent small alignment from | 647 | Large value could prevent small alignment from |
636 | using up MTRRs. | 648 | using up MTRRs. |
637 | 649 | ||
638 | mtrr_spare_reg_nr=n [X86] | 650 | mtrr_spare_reg_nr=n [X86] |
639 | Format: <integer> | 651 | Format: <integer> |
640 | Range: 0,7 : spare reg number | 652 | Range: 0,7 : spare reg number |
641 | Default : 1 | 653 | Default : 1 |
642 | Used for mtrr cleanup. It is spare mtrr entries number. | 654 | Used for mtrr cleanup. It is spare mtrr entries number. |
643 | Set to 2 or more if your graphical card needs more. | 655 | Set to 2 or more if your graphical card needs more. |
644 | 656 | ||
645 | disable_mtrr_trim [X86, Intel and AMD only] | 657 | disable_mtrr_trim [X86, Intel and AMD only] |
646 | By default the kernel will trim any uncacheable | 658 | By default the kernel will trim any uncacheable |
647 | memory out of your available memory pool based on | 659 | memory out of your available memory pool based on |
648 | MTRR settings. This parameter disables that behavior, | 660 | MTRR settings. This parameter disables that behavior, |
649 | possibly causing your machine to run very slowly. | 661 | possibly causing your machine to run very slowly. |
650 | 662 | ||
651 | dmasound= [HW,OSS] Sound subsystem buffers | 663 | dmasound= [HW,OSS] Sound subsystem buffers |
652 | 664 | ||
653 | dscc4.setup= [NET] | 665 | dscc4.setup= [NET] |
654 | 666 | ||
655 | dtc3181e= [HW,SCSI] | 667 | dtc3181e= [HW,SCSI] |
656 | 668 | ||
657 | earlyprintk= [X86-32,X86-64,SH,BLACKFIN] | 669 | earlyprintk= [X86-32,X86-64,SH,BLACKFIN] |
658 | earlyprintk=vga | 670 | earlyprintk=vga |
659 | earlyprintk=serial[,ttySn[,baudrate]] | 671 | earlyprintk=serial[,ttySn[,baudrate]] |
660 | earlyprintk=dbgp | 672 | earlyprintk=dbgp |
661 | 673 | ||
662 | Append ",keep" to not disable it when the real console | 674 | Append ",keep" to not disable it when the real console |
663 | takes over. | 675 | takes over. |
664 | 676 | ||
665 | Only vga or serial or usb debug port at a time. | 677 | Only vga or serial or usb debug port at a time. |
666 | 678 | ||
667 | Currently only ttyS0 and ttyS1 are supported. | 679 | Currently only ttyS0 and ttyS1 are supported. |
668 | 680 | ||
669 | Interaction with the standard serial driver is not | 681 | Interaction with the standard serial driver is not |
670 | very good. | 682 | very good. |
671 | 683 | ||
672 | The VGA output is eventually overwritten by the real | 684 | The VGA output is eventually overwritten by the real |
673 | console. | 685 | console. |
674 | 686 | ||
675 | eata= [HW,SCSI] | 687 | eata= [HW,SCSI] |
676 | 688 | ||
677 | edd= [EDD] | 689 | edd= [EDD] |
678 | Format: {"off" | "on" | "skip[mbr]"} | 690 | Format: {"off" | "on" | "skip[mbr]"} |
679 | 691 | ||
680 | eisa_irq_edge= [PARISC,HW] | 692 | eisa_irq_edge= [PARISC,HW] |
681 | See header of drivers/parisc/eisa.c. | 693 | See header of drivers/parisc/eisa.c. |
682 | 694 | ||
683 | elanfreq= [X86-32] | 695 | elanfreq= [X86-32] |
684 | See comment before function elanfreq_setup() in | 696 | See comment before function elanfreq_setup() in |
685 | arch/x86/kernel/cpu/cpufreq/elanfreq.c. | 697 | arch/x86/kernel/cpu/cpufreq/elanfreq.c. |
686 | 698 | ||
687 | elevator= [IOSCHED] | 699 | elevator= [IOSCHED] |
688 | Format: {"anticipatory" | "cfq" | "deadline" | "noop"} | 700 | Format: {"anticipatory" | "cfq" | "deadline" | "noop"} |
689 | See Documentation/block/as-iosched.txt and | 701 | See Documentation/block/as-iosched.txt and |
690 | Documentation/block/deadline-iosched.txt for details. | 702 | Documentation/block/deadline-iosched.txt for details. |
691 | 703 | ||
692 | elfcorehdr= [IA64,PPC,SH,X86-32,X86_64] | 704 | elfcorehdr= [IA64,PPC,SH,X86-32,X86_64] |
693 | Specifies physical address of start of kernel core | 705 | Specifies physical address of start of kernel core |
694 | image elf header. Generally kexec loader will | 706 | image elf header. Generally kexec loader will |
695 | pass this option to capture kernel. | 707 | pass this option to capture kernel. |
696 | See Documentation/kdump/kdump.txt for details. | 708 | See Documentation/kdump/kdump.txt for details. |
697 | 709 | ||
698 | enforcing [SELINUX] Set initial enforcing status. | 710 | enforcing [SELINUX] Set initial enforcing status. |
699 | Format: {"0" | "1"} | 711 | Format: {"0" | "1"} |
700 | See security/selinux/Kconfig help text. | 712 | See security/selinux/Kconfig help text. |
701 | 0 -- permissive (log only, no denials). | 713 | 0 -- permissive (log only, no denials). |
702 | 1 -- enforcing (deny and log). | 714 | 1 -- enforcing (deny and log). |
703 | Default value is 0. | 715 | Default value is 0. |
704 | Value can be changed at runtime via /selinux/enforce. | 716 | Value can be changed at runtime via /selinux/enforce. |
705 | 717 | ||
706 | es1371= [HW,OSS] | 718 | es1371= [HW,OSS] |
707 | Format: <spdif>,[<nomix>,[<amplifier>]] | 719 | Format: <spdif>,[<nomix>,[<amplifier>]] |
708 | See also header of sound/oss/es1371.c. | 720 | See also header of sound/oss/es1371.c. |
709 | 721 | ||
710 | ether= [HW,NET] Ethernet cards parameters | 722 | ether= [HW,NET] Ethernet cards parameters |
711 | This option is obsoleted by the "netdev=" option, which | 723 | This option is obsoleted by the "netdev=" option, which |
712 | has equivalent usage. See its documentation for details. | 724 | has equivalent usage. See its documentation for details. |
713 | 725 | ||
714 | eurwdt= [HW,WDT] Eurotech CPU-1220/1410 onboard watchdog. | 726 | eurwdt= [HW,WDT] Eurotech CPU-1220/1410 onboard watchdog. |
715 | Format: <io>[,<irq>] | 727 | Format: <io>[,<irq>] |
716 | 728 | ||
717 | failslab= | 729 | failslab= |
718 | fail_page_alloc= | 730 | fail_page_alloc= |
719 | fail_make_request=[KNL] | 731 | fail_make_request=[KNL] |
720 | General fault injection mechanism. | 732 | General fault injection mechanism. |
721 | Format: <interval>,<probability>,<space>,<times> | 733 | Format: <interval>,<probability>,<space>,<times> |
722 | See also /Documentation/fault-injection/. | 734 | See also /Documentation/fault-injection/. |
723 | 735 | ||
724 | fd_mcs= [HW,SCSI] | 736 | fd_mcs= [HW,SCSI] |
725 | See header of drivers/scsi/fd_mcs.c. | 737 | See header of drivers/scsi/fd_mcs.c. |
726 | 738 | ||
727 | fdomain= [HW,SCSI] | 739 | fdomain= [HW,SCSI] |
728 | See header of drivers/scsi/fdomain.c. | 740 | See header of drivers/scsi/fdomain.c. |
729 | 741 | ||
730 | floppy= [HW] | 742 | floppy= [HW] |
731 | See Documentation/floppy.txt. | 743 | See Documentation/floppy.txt. |
732 | 744 | ||
733 | force_pal_cache_flush | 745 | force_pal_cache_flush |
734 | [IA-64] Avoid check_sal_cache_flush which may hang on | 746 | [IA-64] Avoid check_sal_cache_flush which may hang on |
735 | buggy SAL_CACHE_FLUSH implementations. Using this | 747 | buggy SAL_CACHE_FLUSH implementations. Using this |
736 | parameter will force ia64_sal_cache_flush to call | 748 | parameter will force ia64_sal_cache_flush to call |
737 | ia64_pal_cache_flush instead of SAL_CACHE_FLUSH. | 749 | ia64_pal_cache_flush instead of SAL_CACHE_FLUSH. |
738 | 750 | ||
739 | gamecon.map[2|3]= | 751 | gamecon.map[2|3]= |
740 | [HW,JOY] Multisystem joystick and NES/SNES/PSX pad | 752 | [HW,JOY] Multisystem joystick and NES/SNES/PSX pad |
741 | support via parallel port (up to 5 devices per port) | 753 | support via parallel port (up to 5 devices per port) |
742 | Format: <port#>,<pad1>,<pad2>,<pad3>,<pad4>,<pad5> | 754 | Format: <port#>,<pad1>,<pad2>,<pad3>,<pad4>,<pad5> |
743 | See also Documentation/input/joystick-parport.txt | 755 | See also Documentation/input/joystick-parport.txt |
744 | 756 | ||
745 | gamma= [HW,DRM] | 757 | gamma= [HW,DRM] |
746 | 758 | ||
747 | gart_fix_e820= [X86_64] disable the fix e820 for K8 GART | 759 | gart_fix_e820= [X86_64] disable the fix e820 for K8 GART |
748 | Format: off | on | 760 | Format: off | on |
749 | default: on | 761 | default: on |
750 | 762 | ||
751 | gdth= [HW,SCSI] | 763 | gdth= [HW,SCSI] |
752 | See header of drivers/scsi/gdth.c. | 764 | See header of drivers/scsi/gdth.c. |
753 | 765 | ||
754 | gpt [EFI] Forces disk with valid GPT signature but | 766 | gpt [EFI] Forces disk with valid GPT signature but |
755 | invalid Protective MBR to be treated as GPT. | 767 | invalid Protective MBR to be treated as GPT. |
756 | 768 | ||
757 | gvp11= [HW,SCSI] | 769 | gvp11= [HW,SCSI] |
758 | 770 | ||
759 | hashdist= [KNL,NUMA] Large hashes allocated during boot | 771 | hashdist= [KNL,NUMA] Large hashes allocated during boot |
760 | are distributed across NUMA nodes. Defaults on | 772 | are distributed across NUMA nodes. Defaults on |
761 | for IA-64, off otherwise. | 773 | for IA-64, off otherwise. |
762 | Format: 0 | 1 (for off | on) | 774 | Format: 0 | 1 (for off | on) |
763 | 775 | ||
764 | hcl= [IA-64] SGI's Hardware Graph compatibility layer | 776 | hcl= [IA-64] SGI's Hardware Graph compatibility layer |
765 | 777 | ||
766 | hd= [EIDE] (E)IDE hard drive subsystem geometry | 778 | hd= [EIDE] (E)IDE hard drive subsystem geometry |
767 | Format: <cyl>,<head>,<sect> | 779 | Format: <cyl>,<head>,<sect> |
768 | 780 | ||
769 | highmem=nn[KMG] [KNL,BOOT] forces the highmem zone to have an exact | 781 | highmem=nn[KMG] [KNL,BOOT] forces the highmem zone to have an exact |
770 | size of <nn>. This works even on boxes that have no | 782 | size of <nn>. This works even on boxes that have no |
771 | highmem otherwise. This also works to reduce highmem | 783 | highmem otherwise. This also works to reduce highmem |
772 | size on bigger boxes. | 784 | size on bigger boxes. |
773 | 785 | ||
774 | highres= [KNL] Enable/disable high resolution timer mode. | 786 | highres= [KNL] Enable/disable high resolution timer mode. |
775 | Valid parameters: "on", "off" | 787 | Valid parameters: "on", "off" |
776 | Default: "on" | 788 | Default: "on" |
777 | 789 | ||
778 | hisax= [HW,ISDN] | 790 | hisax= [HW,ISDN] |
779 | See Documentation/isdn/README.HiSax. | 791 | See Documentation/isdn/README.HiSax. |
780 | 792 | ||
781 | hugepages= [HW,X86-32,IA-64] HugeTLB pages to allocate at boot. | 793 | hugepages= [HW,X86-32,IA-64] HugeTLB pages to allocate at boot. |
782 | hugepagesz= [HW,IA-64,PPC,X86-64] The size of the HugeTLB pages. | 794 | hugepagesz= [HW,IA-64,PPC,X86-64] The size of the HugeTLB pages. |
783 | On x86-64 and powerpc, this option can be specified | 795 | On x86-64 and powerpc, this option can be specified |
784 | multiple times interleaved with hugepages= to reserve | 796 | multiple times interleaved with hugepages= to reserve |
785 | huge pages of different sizes. Valid pages sizes on | 797 | huge pages of different sizes. Valid pages sizes on |
786 | x86-64 are 2M (when the CPU supports "pse") and 1G | 798 | x86-64 are 2M (when the CPU supports "pse") and 1G |
787 | (when the CPU supports the "pdpe1gb" cpuinfo flag) | 799 | (when the CPU supports the "pdpe1gb" cpuinfo flag) |
788 | Note that 1GB pages can only be allocated at boot time | 800 | Note that 1GB pages can only be allocated at boot time |
789 | using hugepages= and not freed afterwards. | 801 | using hugepages= and not freed afterwards. |
790 | default_hugepagesz= | 802 | default_hugepagesz= |
791 | [same as hugepagesz=] The size of the default | 803 | [same as hugepagesz=] The size of the default |
792 | HugeTLB page size. This is the size represented by | 804 | HugeTLB page size. This is the size represented by |
793 | the legacy /proc/ hugepages APIs, used for SHM, and | 805 | the legacy /proc/ hugepages APIs, used for SHM, and |
794 | default size when mounting hugetlbfs filesystems. | 806 | default size when mounting hugetlbfs filesystems. |
795 | Defaults to the default architecture's huge page size | 807 | Defaults to the default architecture's huge page size |
796 | if not specified. | 808 | if not specified. |
797 | 809 | ||
798 | hlt [BUGS=ARM,SH] | 810 | hlt [BUGS=ARM,SH] |
799 | 811 | ||
800 | i8042.debug [HW] Toggle i8042 debug mode | 812 | i8042.debug [HW] Toggle i8042 debug mode |
801 | i8042.direct [HW] Put keyboard port into non-translated mode | 813 | i8042.direct [HW] Put keyboard port into non-translated mode |
802 | i8042.dumbkbd [HW] Pretend that controller can only read data from | 814 | i8042.dumbkbd [HW] Pretend that controller can only read data from |
803 | keyboard and cannot control its state | 815 | keyboard and cannot control its state |
804 | (Don't attempt to blink the leds) | 816 | (Don't attempt to blink the leds) |
805 | i8042.noaux [HW] Don't check for auxiliary (== mouse) port | 817 | i8042.noaux [HW] Don't check for auxiliary (== mouse) port |
806 | i8042.nokbd [HW] Don't check/create keyboard port | 818 | i8042.nokbd [HW] Don't check/create keyboard port |
807 | i8042.noloop [HW] Disable the AUX Loopback command while probing | 819 | i8042.noloop [HW] Disable the AUX Loopback command while probing |
808 | for the AUX port | 820 | for the AUX port |
809 | i8042.nomux [HW] Don't check presence of an active multiplexing | 821 | i8042.nomux [HW] Don't check presence of an active multiplexing |
810 | controller | 822 | controller |
811 | i8042.nopnp [HW] Don't use ACPIPnP / PnPBIOS to discover KBD/AUX | 823 | i8042.nopnp [HW] Don't use ACPIPnP / PnPBIOS to discover KBD/AUX |
812 | controllers | 824 | controllers |
813 | i8042.panicblink= | 825 | i8042.panicblink= |
814 | [HW] Frequency with which keyboard LEDs should blink | 826 | [HW] Frequency with which keyboard LEDs should blink |
815 | when kernel panics (default is 0.5 sec) | 827 | when kernel panics (default is 0.5 sec) |
816 | i8042.reset [HW] Reset the controller during init and cleanup | 828 | i8042.reset [HW] Reset the controller during init and cleanup |
817 | i8042.unlock [HW] Unlock (ignore) the keylock | 829 | i8042.unlock [HW] Unlock (ignore) the keylock |
818 | 830 | ||
819 | i810= [HW,DRM] | 831 | i810= [HW,DRM] |
820 | 832 | ||
821 | i8k.ignore_dmi [HW] Continue probing hardware even if DMI data | 833 | i8k.ignore_dmi [HW] Continue probing hardware even if DMI data |
822 | indicates that the driver is running on unsupported | 834 | indicates that the driver is running on unsupported |
823 | hardware. | 835 | hardware. |
824 | i8k.force [HW] Activate i8k driver even if SMM BIOS signature | 836 | i8k.force [HW] Activate i8k driver even if SMM BIOS signature |
825 | does not match list of supported models. | 837 | does not match list of supported models. |
826 | i8k.power_status | 838 | i8k.power_status |
827 | [HW] Report power status in /proc/i8k | 839 | [HW] Report power status in /proc/i8k |
828 | (disabled by default) | 840 | (disabled by default) |
829 | i8k.restricted [HW] Allow controlling fans only if SYS_ADMIN | 841 | i8k.restricted [HW] Allow controlling fans only if SYS_ADMIN |
830 | capability is set. | 842 | capability is set. |
831 | 843 | ||
832 | ibmmcascsi= [HW,MCA,SCSI] IBM MicroChannel SCSI adapter | 844 | ibmmcascsi= [HW,MCA,SCSI] IBM MicroChannel SCSI adapter |
833 | See Documentation/mca.txt. | 845 | See Documentation/mca.txt. |
834 | 846 | ||
835 | icn= [HW,ISDN] | 847 | icn= [HW,ISDN] |
836 | Format: <io>[,<membase>[,<icn_id>[,<icn_id2>]]] | 848 | Format: <io>[,<membase>[,<icn_id>[,<icn_id2>]]] |
837 | 849 | ||
838 | ide= [HW] (E)IDE subsystem | 850 | ide= [HW] (E)IDE subsystem |
839 | Format: ide=nodma or ide=doubler | 851 | Format: ide=nodma or ide=doubler |
840 | See Documentation/ide/ide.txt. | 852 | See Documentation/ide/ide.txt. |
841 | 853 | ||
842 | idebus= [HW] (E)IDE subsystem - VLB/PCI bus speed | 854 | idebus= [HW] (E)IDE subsystem - VLB/PCI bus speed |
843 | See Documentation/ide/ide.txt. | 855 | See Documentation/ide/ide.txt. |
844 | 856 | ||
845 | idle= [X86] | 857 | idle= [X86] |
846 | Format: idle=poll or idle=mwait, idle=halt, idle=nomwait | 858 | Format: idle=poll or idle=mwait, idle=halt, idle=nomwait |
847 | Poll forces a polling idle loop that can slightly improves the performance | 859 | Poll forces a polling idle loop that can slightly improves the performance |
848 | of waking up a idle CPU, but will use a lot of power and make the system | 860 | of waking up a idle CPU, but will use a lot of power and make the system |
849 | run hot. Not recommended. | 861 | run hot. Not recommended. |
850 | idle=mwait. On systems which support MONITOR/MWAIT but the kernel chose | 862 | idle=mwait. On systems which support MONITOR/MWAIT but the kernel chose |
851 | to not use it because it doesn't save as much power as a normal idle | 863 | to not use it because it doesn't save as much power as a normal idle |
852 | loop use the MONITOR/MWAIT idle loop anyways. Performance should be the same | 864 | loop use the MONITOR/MWAIT idle loop anyways. Performance should be the same |
853 | as idle=poll. | 865 | as idle=poll. |
854 | idle=halt. Halt is forced to be used for CPU idle. | 866 | idle=halt. Halt is forced to be used for CPU idle. |
855 | In such case C2/C3 won't be used again. | 867 | In such case C2/C3 won't be used again. |
856 | idle=nomwait. Disable mwait for CPU C-states | 868 | idle=nomwait. Disable mwait for CPU C-states |
857 | 869 | ||
858 | ide-pci-generic.all-generic-ide [HW] (E)IDE subsystem | 870 | ide-pci-generic.all-generic-ide [HW] (E)IDE subsystem |
859 | Claim all unknown PCI IDE storage controllers. | 871 | Claim all unknown PCI IDE storage controllers. |
860 | 872 | ||
861 | ignore_loglevel [KNL] | 873 | ignore_loglevel [KNL] |
862 | Ignore loglevel setting - this will print /all/ | 874 | Ignore loglevel setting - this will print /all/ |
863 | kernel messages to the console. Useful for debugging. | 875 | kernel messages to the console. Useful for debugging. |
864 | 876 | ||
865 | ihash_entries= [KNL] | 877 | ihash_entries= [KNL] |
866 | Set number of hash buckets for inode cache. | 878 | Set number of hash buckets for inode cache. |
867 | 879 | ||
868 | in2000= [HW,SCSI] | 880 | in2000= [HW,SCSI] |
869 | See header of drivers/scsi/in2000.c. | 881 | See header of drivers/scsi/in2000.c. |
870 | 882 | ||
871 | init= [KNL] | 883 | init= [KNL] |
872 | Format: <full_path> | 884 | Format: <full_path> |
873 | Run specified binary instead of /sbin/init as init | 885 | Run specified binary instead of /sbin/init as init |
874 | process. | 886 | process. |
875 | 887 | ||
876 | initcall_debug [KNL] Trace initcalls as they are executed. Useful | 888 | initcall_debug [KNL] Trace initcalls as they are executed. Useful |
877 | for working out where the kernel is dying during | 889 | for working out where the kernel is dying during |
878 | startup. | 890 | startup. |
879 | 891 | ||
880 | initrd= [BOOT] Specify the location of the initial ramdisk | 892 | initrd= [BOOT] Specify the location of the initial ramdisk |
881 | 893 | ||
882 | inport.irq= [HW] Inport (ATI XL and Microsoft) busmouse driver | 894 | inport.irq= [HW] Inport (ATI XL and Microsoft) busmouse driver |
883 | Format: <irq> | 895 | Format: <irq> |
884 | 896 | ||
885 | inttest= [IA64] | 897 | inttest= [IA64] |
886 | 898 | ||
887 | iommu= [x86] | 899 | iommu= [x86] |
888 | off | 900 | off |
889 | force | 901 | force |
890 | noforce | 902 | noforce |
891 | biomerge | 903 | biomerge |
892 | panic | 904 | panic |
893 | nopanic | 905 | nopanic |
894 | merge | 906 | merge |
895 | nomerge | 907 | nomerge |
896 | forcesac | 908 | forcesac |
897 | soft | 909 | soft |
898 | 910 | ||
899 | 911 | ||
900 | intel_iommu= [DMAR] Intel IOMMU driver (DMAR) option | 912 | intel_iommu= [DMAR] Intel IOMMU driver (DMAR) option |
901 | off | 913 | off |
902 | Disable intel iommu driver. | 914 | Disable intel iommu driver. |
903 | igfx_off [Default Off] | 915 | igfx_off [Default Off] |
904 | By default, gfx is mapped as normal device. If a gfx | 916 | By default, gfx is mapped as normal device. If a gfx |
905 | device has a dedicated DMAR unit, the DMAR unit is | 917 | device has a dedicated DMAR unit, the DMAR unit is |
906 | bypassed by not enabling DMAR with this option. In | 918 | bypassed by not enabling DMAR with this option. In |
907 | this case, gfx device will use physical address for | 919 | this case, gfx device will use physical address for |
908 | DMA. | 920 | DMA. |
909 | forcedac [x86_64] | 921 | forcedac [x86_64] |
910 | With this option iommu will not optimize to look | 922 | With this option iommu will not optimize to look |
911 | for io virtual address below 32 bit forcing dual | 923 | for io virtual address below 32 bit forcing dual |
912 | address cycle on pci bus for cards supporting greater | 924 | address cycle on pci bus for cards supporting greater |
913 | than 32 bit addressing. The default is to look | 925 | than 32 bit addressing. The default is to look |
914 | for translation below 32 bit and if not available | 926 | for translation below 32 bit and if not available |
915 | then look in the higher range. | 927 | then look in the higher range. |
916 | strict [Default Off] | 928 | strict [Default Off] |
917 | With this option on every unmap_single operation will | 929 | With this option on every unmap_single operation will |
918 | result in a hardware IOTLB flush operation as opposed | 930 | result in a hardware IOTLB flush operation as opposed |
919 | to batching them for performance. | 931 | to batching them for performance. |
920 | 932 | ||
921 | io_delay= [X86-32,X86-64] I/O delay method | 933 | io_delay= [X86-32,X86-64] I/O delay method |
922 | 0x80 | 934 | 0x80 |
923 | Standard port 0x80 based delay | 935 | Standard port 0x80 based delay |
924 | 0xed | 936 | 0xed |
925 | Alternate port 0xed based delay (needed on some systems) | 937 | Alternate port 0xed based delay (needed on some systems) |
926 | udelay | 938 | udelay |
927 | Simple two microseconds delay | 939 | Simple two microseconds delay |
928 | none | 940 | none |
929 | No delay | 941 | No delay |
930 | 942 | ||
931 | io7= [HW] IO7 for Marvel based alpha systems | 943 | io7= [HW] IO7 for Marvel based alpha systems |
932 | See comment before marvel_specify_io7 in | 944 | See comment before marvel_specify_io7 in |
933 | arch/alpha/kernel/core_marvel.c. | 945 | arch/alpha/kernel/core_marvel.c. |
934 | 946 | ||
935 | ip= [IP_PNP] | 947 | ip= [IP_PNP] |
936 | See Documentation/filesystems/nfsroot.txt. | 948 | See Documentation/filesystems/nfsroot.txt. |
937 | 949 | ||
938 | ip2= [HW] Set IO/IRQ pairs for up to 4 IntelliPort boards | 950 | ip2= [HW] Set IO/IRQ pairs for up to 4 IntelliPort boards |
939 | See comment before ip2_setup() in | 951 | See comment before ip2_setup() in |
940 | drivers/char/ip2/ip2base.c. | 952 | drivers/char/ip2/ip2base.c. |
941 | 953 | ||
942 | ips= [HW,SCSI] Adaptec / IBM ServeRAID controller | 954 | ips= [HW,SCSI] Adaptec / IBM ServeRAID controller |
943 | See header of drivers/scsi/ips.c. | 955 | See header of drivers/scsi/ips.c. |
944 | 956 | ||
945 | ports= [IP_VS_FTP] IPVS ftp helper module | 957 | ports= [IP_VS_FTP] IPVS ftp helper module |
946 | Default is 21. | 958 | Default is 21. |
947 | Up to 8 (IP_VS_APP_MAX_PORTS) ports | 959 | Up to 8 (IP_VS_APP_MAX_PORTS) ports |
948 | may be specified. | 960 | may be specified. |
949 | Format: <port>,<port>.... | 961 | Format: <port>,<port>.... |
950 | 962 | ||
951 | irqfixup [HW] | 963 | irqfixup [HW] |
952 | When an interrupt is not handled search all handlers | 964 | When an interrupt is not handled search all handlers |
953 | for it. Intended to get systems with badly broken | 965 | for it. Intended to get systems with badly broken |
954 | firmware running. | 966 | firmware running. |
955 | 967 | ||
956 | irqpoll [HW] | 968 | irqpoll [HW] |
957 | When an interrupt is not handled search all handlers | 969 | When an interrupt is not handled search all handlers |
958 | for it. Also check all handlers each timer | 970 | for it. Also check all handlers each timer |
959 | interrupt. Intended to get systems with badly broken | 971 | interrupt. Intended to get systems with badly broken |
960 | firmware running. | 972 | firmware running. |
961 | 973 | ||
962 | isapnp= [ISAPNP] | 974 | isapnp= [ISAPNP] |
963 | Format: <RDP>,<reset>,<pci_scan>,<verbosity> | 975 | Format: <RDP>,<reset>,<pci_scan>,<verbosity> |
964 | 976 | ||
965 | isolcpus= [KNL,SMP] Isolate CPUs from the general scheduler. | 977 | isolcpus= [KNL,SMP] Isolate CPUs from the general scheduler. |
966 | Format: | 978 | Format: |
967 | <cpu number>,...,<cpu number> | 979 | <cpu number>,...,<cpu number> |
968 | or | 980 | or |
969 | <cpu number>-<cpu number> | 981 | <cpu number>-<cpu number> |
970 | (must be a positive range in ascending order) | 982 | (must be a positive range in ascending order) |
971 | or a mixture | 983 | or a mixture |
972 | <cpu number>,...,<cpu number>-<cpu number> | 984 | <cpu number>,...,<cpu number>-<cpu number> |
973 | 985 | ||
974 | This option can be used to specify one or more CPUs | 986 | This option can be used to specify one or more CPUs |
975 | to isolate from the general SMP balancing and scheduling | 987 | to isolate from the general SMP balancing and scheduling |
976 | algorithms. You can move a process onto or off an | 988 | algorithms. You can move a process onto or off an |
977 | "isolated" CPU via the CPU affinity syscalls or cpuset. | 989 | "isolated" CPU via the CPU affinity syscalls or cpuset. |
978 | <cpu number> begins at 0 and the maximum value is | 990 | <cpu number> begins at 0 and the maximum value is |
979 | "number of CPUs in system - 1". | 991 | "number of CPUs in system - 1". |
980 | 992 | ||
981 | This option is the preferred way to isolate CPUs. The | 993 | This option is the preferred way to isolate CPUs. The |
982 | alternative -- manually setting the CPU mask of all | 994 | alternative -- manually setting the CPU mask of all |
983 | tasks in the system -- can cause problems and | 995 | tasks in the system -- can cause problems and |
984 | suboptimal load balancer performance. | 996 | suboptimal load balancer performance. |
985 | 997 | ||
986 | iucv= [HW,NET] | 998 | iucv= [HW,NET] |
987 | 999 | ||
988 | js= [HW,JOY] Analog joystick | 1000 | js= [HW,JOY] Analog joystick |
989 | See Documentation/input/joystick.txt. | 1001 | See Documentation/input/joystick.txt. |
990 | 1002 | ||
991 | kernelcore=nn[KMG] [KNL,X86-32,IA-64,PPC,X86-64] This parameter | 1003 | kernelcore=nn[KMG] [KNL,X86-32,IA-64,PPC,X86-64] This parameter |
992 | specifies the amount of memory usable by the kernel | 1004 | specifies the amount of memory usable by the kernel |
993 | for non-movable allocations. The requested amount is | 1005 | for non-movable allocations. The requested amount is |
994 | spread evenly throughout all nodes in the system. The | 1006 | spread evenly throughout all nodes in the system. The |
995 | remaining memory in each node is used for Movable | 1007 | remaining memory in each node is used for Movable |
996 | pages. In the event, a node is too small to have both | 1008 | pages. In the event, a node is too small to have both |
997 | kernelcore and Movable pages, kernelcore pages will | 1009 | kernelcore and Movable pages, kernelcore pages will |
998 | take priority and other nodes will have a larger number | 1010 | take priority and other nodes will have a larger number |
999 | of kernelcore pages. The Movable zone is used for the | 1011 | of kernelcore pages. The Movable zone is used for the |
1000 | allocation of pages that may be reclaimed or moved | 1012 | allocation of pages that may be reclaimed or moved |
1001 | by the page migration subsystem. This means that | 1013 | by the page migration subsystem. This means that |
1002 | HugeTLB pages may not be allocated from this zone. | 1014 | HugeTLB pages may not be allocated from this zone. |
1003 | Note that allocations like PTEs-from-HighMem still | 1015 | Note that allocations like PTEs-from-HighMem still |
1004 | use the HighMem zone if it exists, and the Normal | 1016 | use the HighMem zone if it exists, and the Normal |
1005 | zone if it does not. | 1017 | zone if it does not. |
1006 | 1018 | ||
1007 | movablecore=nn[KMG] [KNL,X86-32,IA-64,PPC,X86-64] This parameter | 1019 | movablecore=nn[KMG] [KNL,X86-32,IA-64,PPC,X86-64] This parameter |
1008 | is similar to kernelcore except it specifies the | 1020 | is similar to kernelcore except it specifies the |
1009 | amount of memory used for migratable allocations. | 1021 | amount of memory used for migratable allocations. |
1010 | If both kernelcore and movablecore is specified, | 1022 | If both kernelcore and movablecore is specified, |
1011 | then kernelcore will be at *least* the specified | 1023 | then kernelcore will be at *least* the specified |
1012 | value but may be more. If movablecore on its own | 1024 | value but may be more. If movablecore on its own |
1013 | is specified, the administrator must be careful | 1025 | is specified, the administrator must be careful |
1014 | that the amount of memory usable for all allocations | 1026 | that the amount of memory usable for all allocations |
1015 | is not too small. | 1027 | is not too small. |
1016 | 1028 | ||
1017 | keepinitrd [HW,ARM] | 1029 | keepinitrd [HW,ARM] |
1018 | 1030 | ||
1019 | kstack=N [X86-32,X86-64] Print N words from the kernel stack | 1031 | kstack=N [X86-32,X86-64] Print N words from the kernel stack |
1020 | in oops dumps. | 1032 | in oops dumps. |
1021 | 1033 | ||
1022 | kgdboc= [HW] kgdb over consoles. | 1034 | kgdboc= [HW] kgdb over consoles. |
1023 | Requires a tty driver that supports console polling. | 1035 | Requires a tty driver that supports console polling. |
1024 | (only serial suported for now) | 1036 | (only serial suported for now) |
1025 | Format: <serial_device>[,baud] | 1037 | Format: <serial_device>[,baud] |
1026 | 1038 | ||
1027 | kmac= [MIPS] korina ethernet MAC address. | 1039 | kmac= [MIPS] korina ethernet MAC address. |
1028 | Configure the RouterBoard 532 series on-chip | 1040 | Configure the RouterBoard 532 series on-chip |
1029 | Ethernet adapter MAC address. | 1041 | Ethernet adapter MAC address. |
1030 | 1042 | ||
1031 | l2cr= [PPC] | 1043 | l2cr= [PPC] |
1032 | 1044 | ||
1033 | l3cr= [PPC] | 1045 | l3cr= [PPC] |
1034 | 1046 | ||
1035 | lapic [X86-32,APIC] Enable the local APIC even if BIOS | 1047 | lapic [X86-32,APIC] Enable the local APIC even if BIOS |
1036 | disabled it. | 1048 | disabled it. |
1037 | 1049 | ||
1038 | lapic_timer_c2_ok [X86-32,x86-64,APIC] trust the local apic timer in | 1050 | lapic_timer_c2_ok [X86-32,x86-64,APIC] trust the local apic timer in |
1039 | C2 power state. | 1051 | C2 power state. |
1040 | 1052 | ||
1041 | libata.dma= [LIBATA] DMA control | 1053 | libata.dma= [LIBATA] DMA control |
1042 | libata.dma=0 Disable all PATA and SATA DMA | 1054 | libata.dma=0 Disable all PATA and SATA DMA |
1043 | libata.dma=1 PATA and SATA Disk DMA only | 1055 | libata.dma=1 PATA and SATA Disk DMA only |
1044 | libata.dma=2 ATAPI (CDROM) DMA only | 1056 | libata.dma=2 ATAPI (CDROM) DMA only |
1045 | libata.dma=4 Compact Flash DMA only | 1057 | libata.dma=4 Compact Flash DMA only |
1046 | Combinations also work, so libata.dma=3 enables DMA | 1058 | Combinations also work, so libata.dma=3 enables DMA |
1047 | for disks and CDROMs, but not CFs. | 1059 | for disks and CDROMs, but not CFs. |
1048 | 1060 | ||
1049 | libata.noacpi [LIBATA] Disables use of ACPI in libata suspend/resume | 1061 | libata.noacpi [LIBATA] Disables use of ACPI in libata suspend/resume |
1050 | when set. | 1062 | when set. |
1051 | Format: <int> | 1063 | Format: <int> |
1052 | 1064 | ||
1053 | libata.force= [LIBATA] Force configurations. The format is comma | 1065 | libata.force= [LIBATA] Force configurations. The format is comma |
1054 | separated list of "[ID:]VAL" where ID is | 1066 | separated list of "[ID:]VAL" where ID is |
1055 | PORT[:DEVICE]. PORT and DEVICE are decimal numbers | 1067 | PORT[:DEVICE]. PORT and DEVICE are decimal numbers |
1056 | matching port, link or device. Basically, it matches | 1068 | matching port, link or device. Basically, it matches |
1057 | the ATA ID string printed on console by libata. If | 1069 | the ATA ID string printed on console by libata. If |
1058 | the whole ID part is omitted, the last PORT and DEVICE | 1070 | the whole ID part is omitted, the last PORT and DEVICE |
1059 | values are used. If ID hasn't been specified yet, the | 1071 | values are used. If ID hasn't been specified yet, the |
1060 | configuration applies to all ports, links and devices. | 1072 | configuration applies to all ports, links and devices. |
1061 | 1073 | ||
1062 | If only DEVICE is omitted, the parameter applies to | 1074 | If only DEVICE is omitted, the parameter applies to |
1063 | the port and all links and devices behind it. DEVICE | 1075 | the port and all links and devices behind it. DEVICE |
1064 | number of 0 either selects the first device or the | 1076 | number of 0 either selects the first device or the |
1065 | first fan-out link behind PMP device. It does not | 1077 | first fan-out link behind PMP device. It does not |
1066 | select the host link. DEVICE number of 15 selects the | 1078 | select the host link. DEVICE number of 15 selects the |
1067 | host link and device attached to it. | 1079 | host link and device attached to it. |
1068 | 1080 | ||
1069 | The VAL specifies the configuration to force. As long | 1081 | The VAL specifies the configuration to force. As long |
1070 | as there's no ambiguity shortcut notation is allowed. | 1082 | as there's no ambiguity shortcut notation is allowed. |
1071 | For example, both 1.5 and 1.5G would work for 1.5Gbps. | 1083 | For example, both 1.5 and 1.5G would work for 1.5Gbps. |
1072 | The following configurations can be forced. | 1084 | The following configurations can be forced. |
1073 | 1085 | ||
1074 | * Cable type: 40c, 80c, short40c, unk, ign or sata. | 1086 | * Cable type: 40c, 80c, short40c, unk, ign or sata. |
1075 | Any ID with matching PORT is used. | 1087 | Any ID with matching PORT is used. |
1076 | 1088 | ||
1077 | * SATA link speed limit: 1.5Gbps or 3.0Gbps. | 1089 | * SATA link speed limit: 1.5Gbps or 3.0Gbps. |
1078 | 1090 | ||
1079 | * Transfer mode: pio[0-7], mwdma[0-4] and udma[0-7]. | 1091 | * Transfer mode: pio[0-7], mwdma[0-4] and udma[0-7]. |
1080 | udma[/][16,25,33,44,66,100,133] notation is also | 1092 | udma[/][16,25,33,44,66,100,133] notation is also |
1081 | allowed. | 1093 | allowed. |
1082 | 1094 | ||
1083 | * [no]ncq: Turn on or off NCQ. | 1095 | * [no]ncq: Turn on or off NCQ. |
1084 | 1096 | ||
1085 | * nohrst, nosrst, norst: suppress hard, soft | 1097 | * nohrst, nosrst, norst: suppress hard, soft |
1086 | and both resets. | 1098 | and both resets. |
1087 | 1099 | ||
1088 | If there are multiple matching configurations changing | 1100 | If there are multiple matching configurations changing |
1089 | the same attribute, the last one is used. | 1101 | the same attribute, the last one is used. |
1090 | 1102 | ||
1091 | load_ramdisk= [RAM] List of ramdisks to load from floppy | 1103 | load_ramdisk= [RAM] List of ramdisks to load from floppy |
1092 | See Documentation/ramdisk.txt. | 1104 | See Documentation/ramdisk.txt. |
1093 | 1105 | ||
1094 | lockd.nlm_grace_period=P [NFS] Assign grace period. | 1106 | lockd.nlm_grace_period=P [NFS] Assign grace period. |
1095 | Format: <integer> | 1107 | Format: <integer> |
1096 | 1108 | ||
1097 | lockd.nlm_tcpport=N [NFS] Assign TCP port. | 1109 | lockd.nlm_tcpport=N [NFS] Assign TCP port. |
1098 | Format: <integer> | 1110 | Format: <integer> |
1099 | 1111 | ||
1100 | lockd.nlm_timeout=T [NFS] Assign timeout value. | 1112 | lockd.nlm_timeout=T [NFS] Assign timeout value. |
1101 | Format: <integer> | 1113 | Format: <integer> |
1102 | 1114 | ||
1103 | lockd.nlm_udpport=M [NFS] Assign UDP port. | 1115 | lockd.nlm_udpport=M [NFS] Assign UDP port. |
1104 | Format: <integer> | 1116 | Format: <integer> |
1105 | 1117 | ||
1106 | logibm.irq= [HW,MOUSE] Logitech Bus Mouse Driver | 1118 | logibm.irq= [HW,MOUSE] Logitech Bus Mouse Driver |
1107 | Format: <irq> | 1119 | Format: <irq> |
1108 | 1120 | ||
1109 | loglevel= All Kernel Messages with a loglevel smaller than the | 1121 | loglevel= All Kernel Messages with a loglevel smaller than the |
1110 | console loglevel will be printed to the console. It can | 1122 | console loglevel will be printed to the console. It can |
1111 | also be changed with klogd or other programs. The | 1123 | also be changed with klogd or other programs. The |
1112 | loglevels are defined as follows: | 1124 | loglevels are defined as follows: |
1113 | 1125 | ||
1114 | 0 (KERN_EMERG) system is unusable | 1126 | 0 (KERN_EMERG) system is unusable |
1115 | 1 (KERN_ALERT) action must be taken immediately | 1127 | 1 (KERN_ALERT) action must be taken immediately |
1116 | 2 (KERN_CRIT) critical conditions | 1128 | 2 (KERN_CRIT) critical conditions |
1117 | 3 (KERN_ERR) error conditions | 1129 | 3 (KERN_ERR) error conditions |
1118 | 4 (KERN_WARNING) warning conditions | 1130 | 4 (KERN_WARNING) warning conditions |
1119 | 5 (KERN_NOTICE) normal but significant condition | 1131 | 5 (KERN_NOTICE) normal but significant condition |
1120 | 6 (KERN_INFO) informational | 1132 | 6 (KERN_INFO) informational |
1121 | 7 (KERN_DEBUG) debug-level messages | 1133 | 7 (KERN_DEBUG) debug-level messages |
1122 | 1134 | ||
1123 | log_buf_len=n Sets the size of the printk ring buffer, in bytes. | 1135 | log_buf_len=n Sets the size of the printk ring buffer, in bytes. |
1124 | Format: { n | nk | nM } | 1136 | Format: { n | nk | nM } |
1125 | n must be a power of two. The default size | 1137 | n must be a power of two. The default size |
1126 | is set in the kernel config file. | 1138 | is set in the kernel config file. |
1127 | 1139 | ||
1128 | logo.nologo [FB] Disables display of the built-in Linux logo. | 1140 | logo.nologo [FB] Disables display of the built-in Linux logo. |
1129 | This may be used to provide more screen space for | 1141 | This may be used to provide more screen space for |
1130 | kernel log messages and is useful when debugging | 1142 | kernel log messages and is useful when debugging |
1131 | kernel boot problems. | 1143 | kernel boot problems. |
1132 | 1144 | ||
1133 | lp=0 [LP] Specify parallel ports to use, e.g, | 1145 | lp=0 [LP] Specify parallel ports to use, e.g, |
1134 | lp=port[,port...] lp=none,parport0 (lp0 not configured, lp1 uses | 1146 | lp=port[,port...] lp=none,parport0 (lp0 not configured, lp1 uses |
1135 | lp=reset first parallel port). 'lp=0' disables the | 1147 | lp=reset first parallel port). 'lp=0' disables the |
1136 | lp=auto printer driver. 'lp=reset' (which can be | 1148 | lp=auto printer driver. 'lp=reset' (which can be |
1137 | specified in addition to the ports) causes | 1149 | specified in addition to the ports) causes |
1138 | attached printers to be reset. Using | 1150 | attached printers to be reset. Using |
1139 | lp=port1,port2,... specifies the parallel ports | 1151 | lp=port1,port2,... specifies the parallel ports |
1140 | to associate lp devices with, starting with | 1152 | to associate lp devices with, starting with |
1141 | lp0. A port specification may be 'none' to skip | 1153 | lp0. A port specification may be 'none' to skip |
1142 | that lp device, or a parport name such as | 1154 | that lp device, or a parport name such as |
1143 | 'parport0'. Specifying 'lp=auto' instead of a | 1155 | 'parport0'. Specifying 'lp=auto' instead of a |
1144 | port specification list means that device IDs | 1156 | port specification list means that device IDs |
1145 | from each port should be examined, to see if | 1157 | from each port should be examined, to see if |
1146 | an IEEE 1284-compliant printer is attached; if | 1158 | an IEEE 1284-compliant printer is attached; if |
1147 | so, the driver will manage that printer. | 1159 | so, the driver will manage that printer. |
1148 | See also header of drivers/char/lp.c. | 1160 | See also header of drivers/char/lp.c. |
1149 | 1161 | ||
1150 | lpj=n [KNL] | 1162 | lpj=n [KNL] |
1151 | Sets loops_per_jiffy to given constant, thus avoiding | 1163 | Sets loops_per_jiffy to given constant, thus avoiding |
1152 | time-consuming boot-time autodetection (up to 250 ms per | 1164 | time-consuming boot-time autodetection (up to 250 ms per |
1153 | CPU). 0 enables autodetection (default). To determine | 1165 | CPU). 0 enables autodetection (default). To determine |
1154 | the correct value for your kernel, boot with normal | 1166 | the correct value for your kernel, boot with normal |
1155 | autodetection and see what value is printed. Note that | 1167 | autodetection and see what value is printed. Note that |
1156 | on SMP systems the preset will be applied to all CPUs, | 1168 | on SMP systems the preset will be applied to all CPUs, |
1157 | which is likely to cause problems if your CPUs need | 1169 | which is likely to cause problems if your CPUs need |
1158 | significantly divergent settings. An incorrect value | 1170 | significantly divergent settings. An incorrect value |
1159 | will cause delays in the kernel to be wrong, leading to | 1171 | will cause delays in the kernel to be wrong, leading to |
1160 | unpredictable I/O errors and other breakage. Although | 1172 | unpredictable I/O errors and other breakage. Although |
1161 | unlikely, in the extreme case this might damage your | 1173 | unlikely, in the extreme case this might damage your |
1162 | hardware. | 1174 | hardware. |
1163 | 1175 | ||
1164 | ltpc= [NET] | 1176 | ltpc= [NET] |
1165 | Format: <io>,<irq>,<dma> | 1177 | Format: <io>,<irq>,<dma> |
1166 | 1178 | ||
1167 | mac5380= [HW,SCSI] Format: | 1179 | mac5380= [HW,SCSI] Format: |
1168 | <can_queue>,<cmd_per_lun>,<sg_tablesize>,<hostid>,<use_tags> | 1180 | <can_queue>,<cmd_per_lun>,<sg_tablesize>,<hostid>,<use_tags> |
1169 | 1181 | ||
1170 | machvec= [IA64] Force the use of a particular machine-vector | 1182 | machvec= [IA64] Force the use of a particular machine-vector |
1171 | (machvec) in a generic kernel. | 1183 | (machvec) in a generic kernel. |
1172 | Example: machvec=hpzx1_swiotlb | 1184 | Example: machvec=hpzx1_swiotlb |
1173 | 1185 | ||
1174 | max_loop= [LOOP] Maximum number of loopback devices that can | 1186 | max_loop= [LOOP] Maximum number of loopback devices that can |
1175 | be mounted | 1187 | be mounted |
1176 | Format: <1-256> | 1188 | Format: <1-256> |
1177 | 1189 | ||
1178 | maxcpus= [SMP] Maximum number of processors that an SMP kernel | 1190 | maxcpus= [SMP] Maximum number of processors that an SMP kernel |
1179 | should make use of. maxcpus=n : n >= 0 limits the | 1191 | should make use of. maxcpus=n : n >= 0 limits the |
1180 | kernel to using 'n' processors. n=0 is a special case, | 1192 | kernel to using 'n' processors. n=0 is a special case, |
1181 | it is equivalent to "nosmp", which also disables | 1193 | it is equivalent to "nosmp", which also disables |
1182 | the IO APIC. | 1194 | the IO APIC. |
1183 | 1195 | ||
1184 | max_addr=[KMG] [KNL,BOOT,ia64] All physical memory greater than or | 1196 | max_addr=[KMG] [KNL,BOOT,ia64] All physical memory greater than or |
1185 | equal to this physical address is ignored. | 1197 | equal to this physical address is ignored. |
1186 | 1198 | ||
1187 | max_luns= [SCSI] Maximum number of LUNs to probe. | 1199 | max_luns= [SCSI] Maximum number of LUNs to probe. |
1188 | Should be between 1 and 2^32-1. | 1200 | Should be between 1 and 2^32-1. |
1189 | 1201 | ||
1190 | max_report_luns= | 1202 | max_report_luns= |
1191 | [SCSI] Maximum number of LUNs received. | 1203 | [SCSI] Maximum number of LUNs received. |
1192 | Should be between 1 and 16384. | 1204 | Should be between 1 and 16384. |
1193 | 1205 | ||
1194 | mcatest= [IA-64] | 1206 | mcatest= [IA-64] |
1195 | 1207 | ||
1196 | mce [X86-32] Machine Check Exception | 1208 | mce [X86-32] Machine Check Exception |
1197 | 1209 | ||
1198 | mce=option [X86-64] See Documentation/x86/x86_64/boot-options.txt | 1210 | mce=option [X86-64] See Documentation/x86/x86_64/boot-options.txt |
1199 | 1211 | ||
1200 | md= [HW] RAID subsystems devices and level | 1212 | md= [HW] RAID subsystems devices and level |
1201 | See Documentation/md.txt. | 1213 | See Documentation/md.txt. |
1202 | 1214 | ||
1203 | mdacon= [MDA] | 1215 | mdacon= [MDA] |
1204 | Format: <first>,<last> | 1216 | Format: <first>,<last> |
1205 | Specifies range of consoles to be captured by the MDA. | 1217 | Specifies range of consoles to be captured by the MDA. |
1206 | 1218 | ||
1207 | mem=nn[KMG] [KNL,BOOT] Force usage of a specific amount of memory | 1219 | mem=nn[KMG] [KNL,BOOT] Force usage of a specific amount of memory |
1208 | Amount of memory to be used when the kernel is not able | 1220 | Amount of memory to be used when the kernel is not able |
1209 | to see the whole system memory or for test. | 1221 | to see the whole system memory or for test. |
1210 | [X86-32] Use together with memmap= to avoid physical | 1222 | [X86-32] Use together with memmap= to avoid physical |
1211 | address space collisions. Without memmap= PCI devices | 1223 | address space collisions. Without memmap= PCI devices |
1212 | could be placed at addresses belonging to unused RAM. | 1224 | could be placed at addresses belonging to unused RAM. |
1213 | 1225 | ||
1214 | mem=nopentium [BUGS=X86-32] Disable usage of 4MB pages for kernel | 1226 | mem=nopentium [BUGS=X86-32] Disable usage of 4MB pages for kernel |
1215 | memory. | 1227 | memory. |
1216 | 1228 | ||
1217 | memchunk=nn[KMG] | 1229 | memchunk=nn[KMG] |
1218 | [KNL,SH] Allow user to override the default size for | 1230 | [KNL,SH] Allow user to override the default size for |
1219 | per-device physically contiguous DMA buffers. | 1231 | per-device physically contiguous DMA buffers. |
1220 | 1232 | ||
1221 | memmap=exactmap [KNL,X86-32,X86_64] Enable setting of an exact | 1233 | memmap=exactmap [KNL,X86-32,X86_64] Enable setting of an exact |
1222 | E820 memory map, as specified by the user. | 1234 | E820 memory map, as specified by the user. |
1223 | Such memmap=exactmap lines can be constructed based on | 1235 | Such memmap=exactmap lines can be constructed based on |
1224 | BIOS output or other requirements. See the memmap=nn@ss | 1236 | BIOS output or other requirements. See the memmap=nn@ss |
1225 | option description. | 1237 | option description. |
1226 | 1238 | ||
1227 | memmap=nn[KMG]@ss[KMG] | 1239 | memmap=nn[KMG]@ss[KMG] |
1228 | [KNL] Force usage of a specific region of memory | 1240 | [KNL] Force usage of a specific region of memory |
1229 | Region of memory to be used, from ss to ss+nn. | 1241 | Region of memory to be used, from ss to ss+nn. |
1230 | 1242 | ||
1231 | memmap=nn[KMG]#ss[KMG] | 1243 | memmap=nn[KMG]#ss[KMG] |
1232 | [KNL,ACPI] Mark specific memory as ACPI data. | 1244 | [KNL,ACPI] Mark specific memory as ACPI data. |
1233 | Region of memory to be used, from ss to ss+nn. | 1245 | Region of memory to be used, from ss to ss+nn. |
1234 | 1246 | ||
1235 | memmap=nn[KMG]$ss[KMG] | 1247 | memmap=nn[KMG]$ss[KMG] |
1236 | [KNL,ACPI] Mark specific memory as reserved. | 1248 | [KNL,ACPI] Mark specific memory as reserved. |
1237 | Region of memory to be used, from ss to ss+nn. | 1249 | Region of memory to be used, from ss to ss+nn. |
1238 | Example: Exclude memory from 0x18690000-0x1869ffff | 1250 | Example: Exclude memory from 0x18690000-0x1869ffff |
1239 | memmap=64K$0x18690000 | 1251 | memmap=64K$0x18690000 |
1240 | or | 1252 | or |
1241 | memmap=0x10000$0x18690000 | 1253 | memmap=0x10000$0x18690000 |
1242 | 1254 | ||
1243 | memory_corruption_check=0/1 [X86] | 1255 | memory_corruption_check=0/1 [X86] |
1244 | Some BIOSes seem to corrupt the first 64k of | 1256 | Some BIOSes seem to corrupt the first 64k of |
1245 | memory when doing things like suspend/resume. | 1257 | memory when doing things like suspend/resume. |
1246 | Setting this option will scan the memory | 1258 | Setting this option will scan the memory |
1247 | looking for corruption. Enabling this will | 1259 | looking for corruption. Enabling this will |
1248 | both detect corruption and prevent the kernel | 1260 | both detect corruption and prevent the kernel |
1249 | from using the memory being corrupted. | 1261 | from using the memory being corrupted. |
1250 | However, its intended as a diagnostic tool; if | 1262 | However, its intended as a diagnostic tool; if |
1251 | repeatable BIOS-originated corruption always | 1263 | repeatable BIOS-originated corruption always |
1252 | affects the same memory, you can use memmap= | 1264 | affects the same memory, you can use memmap= |
1253 | to prevent the kernel from using that memory. | 1265 | to prevent the kernel from using that memory. |
1254 | 1266 | ||
1255 | memory_corruption_check_size=size [X86] | 1267 | memory_corruption_check_size=size [X86] |
1256 | By default it checks for corruption in the low | 1268 | By default it checks for corruption in the low |
1257 | 64k, making this memory unavailable for normal | 1269 | 64k, making this memory unavailable for normal |
1258 | use. Use this parameter to scan for | 1270 | use. Use this parameter to scan for |
1259 | corruption in more or less memory. | 1271 | corruption in more or less memory. |
1260 | 1272 | ||
1261 | memory_corruption_check_period=seconds [X86] | 1273 | memory_corruption_check_period=seconds [X86] |
1262 | By default it checks for corruption every 60 | 1274 | By default it checks for corruption every 60 |
1263 | seconds. Use this parameter to check at some | 1275 | seconds. Use this parameter to check at some |
1264 | other rate. 0 disables periodic checking. | 1276 | other rate. 0 disables periodic checking. |
1265 | 1277 | ||
1266 | memtest= [KNL,X86] Enable memtest | 1278 | memtest= [KNL,X86] Enable memtest |
1267 | Format: <integer> | 1279 | Format: <integer> |
1268 | range: 0,4 : pattern number | 1280 | range: 0,4 : pattern number |
1269 | default : 0 <disable> | 1281 | default : 0 <disable> |
1270 | 1282 | ||
1271 | meye.*= [HW] Set MotionEye Camera parameters | 1283 | meye.*= [HW] Set MotionEye Camera parameters |
1272 | See Documentation/video4linux/meye.txt. | 1284 | See Documentation/video4linux/meye.txt. |
1273 | 1285 | ||
1274 | mfgpt_irq= [IA-32] Specify the IRQ to use for the | 1286 | mfgpt_irq= [IA-32] Specify the IRQ to use for the |
1275 | Multi-Function General Purpose Timers on AMD Geode | 1287 | Multi-Function General Purpose Timers on AMD Geode |
1276 | platforms. | 1288 | platforms. |
1277 | 1289 | ||
1278 | mfgptfix [X86-32] Fix MFGPT timers on AMD Geode platforms when | 1290 | mfgptfix [X86-32] Fix MFGPT timers on AMD Geode platforms when |
1279 | the BIOS has incorrectly applied a workaround. TinyBIOS | 1291 | the BIOS has incorrectly applied a workaround. TinyBIOS |
1280 | version 0.98 is known to be affected, 0.99 fixes the | 1292 | version 0.98 is known to be affected, 0.99 fixes the |
1281 | problem by letting the user disable the workaround. | 1293 | problem by letting the user disable the workaround. |
1282 | 1294 | ||
1283 | mga= [HW,DRM] | 1295 | mga= [HW,DRM] |
1284 | 1296 | ||
1285 | mminit_loglevel= | 1297 | mminit_loglevel= |
1286 | [KNL] When CONFIG_DEBUG_MEMORY_INIT is set, this | 1298 | [KNL] When CONFIG_DEBUG_MEMORY_INIT is set, this |
1287 | parameter allows control of the logging verbosity for | 1299 | parameter allows control of the logging verbosity for |
1288 | the additional memory initialisation checks. A value | 1300 | the additional memory initialisation checks. A value |
1289 | of 0 disables mminit logging and a level of 4 will | 1301 | of 0 disables mminit logging and a level of 4 will |
1290 | log everything. Information is printed at KERN_DEBUG | 1302 | log everything. Information is printed at KERN_DEBUG |
1291 | so loglevel=8 may also need to be specified. | 1303 | so loglevel=8 may also need to be specified. |
1292 | 1304 | ||
1293 | mousedev.tap_time= | 1305 | mousedev.tap_time= |
1294 | [MOUSE] Maximum time between finger touching and | 1306 | [MOUSE] Maximum time between finger touching and |
1295 | leaving touchpad surface for touch to be considered | 1307 | leaving touchpad surface for touch to be considered |
1296 | a tap and be reported as a left button click (for | 1308 | a tap and be reported as a left button click (for |
1297 | touchpads working in absolute mode only). | 1309 | touchpads working in absolute mode only). |
1298 | Format: <msecs> | 1310 | Format: <msecs> |
1299 | mousedev.xres= [MOUSE] Horizontal screen resolution, used for devices | 1311 | mousedev.xres= [MOUSE] Horizontal screen resolution, used for devices |
1300 | reporting absolute coordinates, such as tablets | 1312 | reporting absolute coordinates, such as tablets |
1301 | mousedev.yres= [MOUSE] Vertical screen resolution, used for devices | 1313 | mousedev.yres= [MOUSE] Vertical screen resolution, used for devices |
1302 | reporting absolute coordinates, such as tablets | 1314 | reporting absolute coordinates, such as tablets |
1303 | 1315 | ||
1304 | mpu401= [HW,OSS] | 1316 | mpu401= [HW,OSS] |
1305 | Format: <io>,<irq> | 1317 | Format: <io>,<irq> |
1306 | 1318 | ||
1307 | MTD_Partition= [MTD] | 1319 | MTD_Partition= [MTD] |
1308 | Format: <name>,<region-number>,<size>,<offset> | 1320 | Format: <name>,<region-number>,<size>,<offset> |
1309 | 1321 | ||
1310 | MTD_Region= [MTD] Format: | 1322 | MTD_Region= [MTD] Format: |
1311 | <name>,<region-number>[,<base>,<size>,<buswidth>,<altbuswidth>] | 1323 | <name>,<region-number>[,<base>,<size>,<buswidth>,<altbuswidth>] |
1312 | 1324 | ||
1313 | mtdparts= [MTD] | 1325 | mtdparts= [MTD] |
1314 | See drivers/mtd/cmdlinepart.c. | 1326 | See drivers/mtd/cmdlinepart.c. |
1315 | 1327 | ||
1316 | mtdset= [ARM] | 1328 | mtdset= [ARM] |
1317 | ARM/S3C2412 JIVE boot control | 1329 | ARM/S3C2412 JIVE boot control |
1318 | 1330 | ||
1319 | See arch/arm/mach-s3c2412/mach-jive.c | 1331 | See arch/arm/mach-s3c2412/mach-jive.c |
1320 | 1332 | ||
1321 | mtouchusb.raw_coordinates= | 1333 | mtouchusb.raw_coordinates= |
1322 | [HW] Make the MicroTouch USB driver use raw coordinates | 1334 | [HW] Make the MicroTouch USB driver use raw coordinates |
1323 | ('y', default) or cooked coordinates ('n') | 1335 | ('y', default) or cooked coordinates ('n') |
1324 | 1336 | ||
1325 | n2= [NET] SDL Inc. RISCom/N2 synchronous serial card | 1337 | n2= [NET] SDL Inc. RISCom/N2 synchronous serial card |
1326 | 1338 | ||
1327 | NCR_D700= [HW,SCSI] | 1339 | NCR_D700= [HW,SCSI] |
1328 | See header of drivers/scsi/NCR_D700.c. | 1340 | See header of drivers/scsi/NCR_D700.c. |
1329 | 1341 | ||
1330 | ncr5380= [HW,SCSI] | 1342 | ncr5380= [HW,SCSI] |
1331 | 1343 | ||
1332 | ncr53c400= [HW,SCSI] | 1344 | ncr53c400= [HW,SCSI] |
1333 | 1345 | ||
1334 | ncr53c400a= [HW,SCSI] | 1346 | ncr53c400a= [HW,SCSI] |
1335 | 1347 | ||
1336 | ncr53c406a= [HW,SCSI] | 1348 | ncr53c406a= [HW,SCSI] |
1337 | 1349 | ||
1338 | ncr53c8xx= [HW,SCSI] | 1350 | ncr53c8xx= [HW,SCSI] |
1339 | 1351 | ||
1340 | netdev= [NET] Network devices parameters | 1352 | netdev= [NET] Network devices parameters |
1341 | Format: <irq>,<io>,<mem_start>,<mem_end>,<name> | 1353 | Format: <irq>,<io>,<mem_start>,<mem_end>,<name> |
1342 | Note that mem_start is often overloaded to mean | 1354 | Note that mem_start is often overloaded to mean |
1343 | something different and driver-specific. | 1355 | something different and driver-specific. |
1344 | This usage is only documented in each driver source | 1356 | This usage is only documented in each driver source |
1345 | file if at all. | 1357 | file if at all. |
1346 | 1358 | ||
1347 | nf_conntrack.acct= | 1359 | nf_conntrack.acct= |
1348 | [NETFILTER] Enable connection tracking flow accounting | 1360 | [NETFILTER] Enable connection tracking flow accounting |
1349 | 0 to disable accounting | 1361 | 0 to disable accounting |
1350 | 1 to enable accounting | 1362 | 1 to enable accounting |
1351 | Default value depends on CONFIG_NF_CT_ACCT that is | 1363 | Default value depends on CONFIG_NF_CT_ACCT that is |
1352 | going to be removed in 2.6.29. | 1364 | going to be removed in 2.6.29. |
1353 | 1365 | ||
1354 | nfsaddrs= [NFS] | 1366 | nfsaddrs= [NFS] |
1355 | See Documentation/filesystems/nfsroot.txt. | 1367 | See Documentation/filesystems/nfsroot.txt. |
1356 | 1368 | ||
1357 | nfsroot= [NFS] nfs root filesystem for disk-less boxes. | 1369 | nfsroot= [NFS] nfs root filesystem for disk-less boxes. |
1358 | See Documentation/filesystems/nfsroot.txt. | 1370 | See Documentation/filesystems/nfsroot.txt. |
1359 | 1371 | ||
1360 | nfs.callback_tcpport= | 1372 | nfs.callback_tcpport= |
1361 | [NFS] set the TCP port on which the NFSv4 callback | 1373 | [NFS] set the TCP port on which the NFSv4 callback |
1362 | channel should listen. | 1374 | channel should listen. |
1363 | 1375 | ||
1364 | nfs.idmap_cache_timeout= | 1376 | nfs.idmap_cache_timeout= |
1365 | [NFS] set the maximum lifetime for idmapper cache | 1377 | [NFS] set the maximum lifetime for idmapper cache |
1366 | entries. | 1378 | entries. |
1367 | 1379 | ||
1368 | nfs.enable_ino64= | 1380 | nfs.enable_ino64= |
1369 | [NFS] enable 64-bit inode numbers. | 1381 | [NFS] enable 64-bit inode numbers. |
1370 | If zero, the NFS client will fake up a 32-bit inode | 1382 | If zero, the NFS client will fake up a 32-bit inode |
1371 | number for the readdir() and stat() syscalls instead | 1383 | number for the readdir() and stat() syscalls instead |
1372 | of returning the full 64-bit number. | 1384 | of returning the full 64-bit number. |
1373 | The default is to return 64-bit inode numbers. | 1385 | The default is to return 64-bit inode numbers. |
1374 | 1386 | ||
1375 | nmi_debug= [KNL,AVR32] Specify one or more actions to take | 1387 | nmi_debug= [KNL,AVR32] Specify one or more actions to take |
1376 | when a NMI is triggered. | 1388 | when a NMI is triggered. |
1377 | Format: [state][,regs][,debounce][,die] | 1389 | Format: [state][,regs][,debounce][,die] |
1378 | 1390 | ||
1379 | nmi_watchdog= [KNL,BUGS=X86-32] Debugging features for SMP kernels | 1391 | nmi_watchdog= [KNL,BUGS=X86-32] Debugging features for SMP kernels |
1380 | 1392 | ||
1381 | no387 [BUGS=X86-32] Tells the kernel to use the 387 maths | 1393 | no387 [BUGS=X86-32] Tells the kernel to use the 387 maths |
1382 | emulation library even if a 387 maths coprocessor | 1394 | emulation library even if a 387 maths coprocessor |
1383 | is present. | 1395 | is present. |
1384 | 1396 | ||
1385 | noaliencache [MM, NUMA, SLAB] Disables the allocation of alien | 1397 | noaliencache [MM, NUMA, SLAB] Disables the allocation of alien |
1386 | caches in the slab allocator. Saves per-node memory, | 1398 | caches in the slab allocator. Saves per-node memory, |
1387 | but will impact performance. | 1399 | but will impact performance. |
1388 | 1400 | ||
1389 | noalign [KNL,ARM] | 1401 | noalign [KNL,ARM] |
1390 | 1402 | ||
1391 | noapic [SMP,APIC] Tells the kernel to not make use of any | 1403 | noapic [SMP,APIC] Tells the kernel to not make use of any |
1392 | IOAPICs that may be present in the system. | 1404 | IOAPICs that may be present in the system. |
1393 | 1405 | ||
1394 | nobats [PPC] Do not use BATs for mapping kernel lowmem | 1406 | nobats [PPC] Do not use BATs for mapping kernel lowmem |
1395 | on "Classic" PPC cores. | 1407 | on "Classic" PPC cores. |
1396 | 1408 | ||
1397 | nocache [ARM] | 1409 | nocache [ARM] |
1398 | 1410 | ||
1399 | nodelayacct [KNL] Disable per-task delay accounting | 1411 | nodelayacct [KNL] Disable per-task delay accounting |
1400 | 1412 | ||
1401 | nodisconnect [HW,SCSI,M68K] Disables SCSI disconnects. | 1413 | nodisconnect [HW,SCSI,M68K] Disables SCSI disconnects. |
1402 | 1414 | ||
1403 | nodsp [SH] Disable hardware DSP at boot time. | 1415 | nodsp [SH] Disable hardware DSP at boot time. |
1404 | 1416 | ||
1405 | noefi [X86-32,X86-64] Disable EFI runtime services support. | 1417 | noefi [X86-32,X86-64] Disable EFI runtime services support. |
1406 | 1418 | ||
1407 | noexec [IA-64] | 1419 | noexec [IA-64] |
1408 | 1420 | ||
1409 | noexec [X86-32,X86-64] | 1421 | noexec [X86-32,X86-64] |
1410 | On X86-32 available only on PAE configured kernels. | 1422 | On X86-32 available only on PAE configured kernels. |
1411 | noexec=on: enable non-executable mappings (default) | 1423 | noexec=on: enable non-executable mappings (default) |
1412 | noexec=off: disable non-executable mappings | 1424 | noexec=off: disable non-executable mappings |
1413 | 1425 | ||
1414 | noexec32 [X86-64] | 1426 | noexec32 [X86-64] |
1415 | This affects only 32-bit executables. | 1427 | This affects only 32-bit executables. |
1416 | noexec32=on: enable non-executable mappings (default) | 1428 | noexec32=on: enable non-executable mappings (default) |
1417 | read doesn't imply executable mappings | 1429 | read doesn't imply executable mappings |
1418 | noexec32=off: disable non-executable mappings | 1430 | noexec32=off: disable non-executable mappings |
1419 | read implies executable mappings | 1431 | read implies executable mappings |
1420 | 1432 | ||
1421 | nofpu [SH] Disable hardware FPU at boot time. | 1433 | nofpu [SH] Disable hardware FPU at boot time. |
1422 | 1434 | ||
1423 | nofxsr [BUGS=X86-32] Disables x86 floating point extended | 1435 | nofxsr [BUGS=X86-32] Disables x86 floating point extended |
1424 | register save and restore. The kernel will only save | 1436 | register save and restore. The kernel will only save |
1425 | legacy floating-point registers on task switch. | 1437 | legacy floating-point registers on task switch. |
1426 | 1438 | ||
1427 | noclflush [BUGS=X86] Don't use the CLFLUSH instruction | 1439 | noclflush [BUGS=X86] Don't use the CLFLUSH instruction |
1428 | 1440 | ||
1429 | nohlt [BUGS=ARM,SH] | 1441 | nohlt [BUGS=ARM,SH] |
1430 | 1442 | ||
1431 | no-hlt [BUGS=X86-32] Tells the kernel that the hlt | 1443 | no-hlt [BUGS=X86-32] Tells the kernel that the hlt |
1432 | instruction doesn't work correctly and not to | 1444 | instruction doesn't work correctly and not to |
1433 | use it. | 1445 | use it. |
1434 | 1446 | ||
1435 | nohalt [IA-64] Tells the kernel not to use the power saving | 1447 | nohalt [IA-64] Tells the kernel not to use the power saving |
1436 | function PAL_HALT_LIGHT when idle. This increases | 1448 | function PAL_HALT_LIGHT when idle. This increases |
1437 | power-consumption. On the positive side, it reduces | 1449 | power-consumption. On the positive side, it reduces |
1438 | interrupt wake-up latency, which may improve performance | 1450 | interrupt wake-up latency, which may improve performance |
1439 | in certain environments such as networked servers or | 1451 | in certain environments such as networked servers or |
1440 | real-time systems. | 1452 | real-time systems. |
1441 | 1453 | ||
1442 | nohz= [KNL] Boottime enable/disable dynamic ticks | 1454 | nohz= [KNL] Boottime enable/disable dynamic ticks |
1443 | Valid arguments: on, off | 1455 | Valid arguments: on, off |
1444 | Default: on | 1456 | Default: on |
1445 | 1457 | ||
1446 | noirqdebug [X86-32] Disables the code which attempts to detect and | 1458 | noirqdebug [X86-32] Disables the code which attempts to detect and |
1447 | disable unhandled interrupt sources. | 1459 | disable unhandled interrupt sources. |
1448 | 1460 | ||
1449 | no_timer_check [X86-32,X86_64,APIC] Disables the code which tests for | 1461 | no_timer_check [X86-32,X86_64,APIC] Disables the code which tests for |
1450 | broken timer IRQ sources. | 1462 | broken timer IRQ sources. |
1451 | 1463 | ||
1452 | noisapnp [ISAPNP] Disables ISA PnP code. | 1464 | noisapnp [ISAPNP] Disables ISA PnP code. |
1453 | 1465 | ||
1454 | noinitrd [RAM] Tells the kernel not to load any configured | 1466 | noinitrd [RAM] Tells the kernel not to load any configured |
1455 | initial RAM disk. | 1467 | initial RAM disk. |
1456 | 1468 | ||
1457 | nointroute [IA-64] | 1469 | nointroute [IA-64] |
1458 | 1470 | ||
1459 | nojitter [IA64] Disables jitter checking for ITC timers. | 1471 | nojitter [IA64] Disables jitter checking for ITC timers. |
1460 | 1472 | ||
1461 | nolapic [X86-32,APIC] Do not enable or use the local APIC. | 1473 | nolapic [X86-32,APIC] Do not enable or use the local APIC. |
1462 | 1474 | ||
1463 | nolapic_timer [X86-32,APIC] Do not use the local APIC timer. | 1475 | nolapic_timer [X86-32,APIC] Do not use the local APIC timer. |
1464 | 1476 | ||
1465 | nox2apic [X86-64,APIC] Do not enable x2APIC mode. | 1477 | nox2apic [X86-64,APIC] Do not enable x2APIC mode. |
1466 | 1478 | ||
1467 | x2apic_phys [X86-64,APIC] Use x2apic physical mode instead of | 1479 | x2apic_phys [X86-64,APIC] Use x2apic physical mode instead of |
1468 | default x2apic cluster mode on platforms | 1480 | default x2apic cluster mode on platforms |
1469 | supporting x2apic. | 1481 | supporting x2apic. |
1470 | 1482 | ||
1471 | noltlbs [PPC] Do not use large page/tlb entries for kernel | 1483 | noltlbs [PPC] Do not use large page/tlb entries for kernel |
1472 | lowmem mapping on PPC40x. | 1484 | lowmem mapping on PPC40x. |
1473 | 1485 | ||
1474 | nomca [IA-64] Disable machine check abort handling | 1486 | nomca [IA-64] Disable machine check abort handling |
1475 | 1487 | ||
1476 | nomce [X86-32] Machine Check Exception | 1488 | nomce [X86-32] Machine Check Exception |
1477 | 1489 | ||
1478 | nomfgpt [X86-32] Disable Multi-Function General Purpose | 1490 | nomfgpt [X86-32] Disable Multi-Function General Purpose |
1479 | Timer usage (for AMD Geode machines). | 1491 | Timer usage (for AMD Geode machines). |
1480 | 1492 | ||
1481 | noreplace-paravirt [X86-32,PV_OPS] Don't patch paravirt_ops | 1493 | noreplace-paravirt [X86-32,PV_OPS] Don't patch paravirt_ops |
1482 | 1494 | ||
1483 | noreplace-smp [X86-32,SMP] Don't replace SMP instructions | 1495 | noreplace-smp [X86-32,SMP] Don't replace SMP instructions |
1484 | with UP alternatives | 1496 | with UP alternatives |
1485 | 1497 | ||
1486 | noresidual [PPC] Don't use residual data on PReP machines. | 1498 | noresidual [PPC] Don't use residual data on PReP machines. |
1487 | 1499 | ||
1488 | noresume [SWSUSP] Disables resume and restores original swap | 1500 | noresume [SWSUSP] Disables resume and restores original swap |
1489 | space. | 1501 | space. |
1490 | 1502 | ||
1491 | no-scroll [VGA] Disables scrollback. | 1503 | no-scroll [VGA] Disables scrollback. |
1492 | This is required for the Braillex ib80-piezo Braille | 1504 | This is required for the Braillex ib80-piezo Braille |
1493 | reader made by F.H. Papenmeier (Germany). | 1505 | reader made by F.H. Papenmeier (Germany). |
1494 | 1506 | ||
1495 | nosbagart [IA-64] | 1507 | nosbagart [IA-64] |
1496 | 1508 | ||
1497 | nosep [BUGS=X86-32] Disables x86 SYSENTER/SYSEXIT support. | 1509 | nosep [BUGS=X86-32] Disables x86 SYSENTER/SYSEXIT support. |
1498 | 1510 | ||
1499 | nosmp [SMP] Tells an SMP kernel to act as a UP kernel, | 1511 | nosmp [SMP] Tells an SMP kernel to act as a UP kernel, |
1500 | and disable the IO APIC. legacy for "maxcpus=0". | 1512 | and disable the IO APIC. legacy for "maxcpus=0". |
1501 | 1513 | ||
1502 | nosoftlockup [KNL] Disable the soft-lockup detector. | 1514 | nosoftlockup [KNL] Disable the soft-lockup detector. |
1503 | 1515 | ||
1504 | nosync [HW,M68K] Disables sync negotiation for all devices. | 1516 | nosync [HW,M68K] Disables sync negotiation for all devices. |
1505 | 1517 | ||
1506 | notsc [BUGS=X86-32] Disable Time Stamp Counter | 1518 | notsc [BUGS=X86-32] Disable Time Stamp Counter |
1507 | 1519 | ||
1508 | nousb [USB] Disable the USB subsystem | 1520 | nousb [USB] Disable the USB subsystem |
1509 | 1521 | ||
1510 | nowb [ARM] | 1522 | nowb [ARM] |
1511 | 1523 | ||
1512 | nptcg= [IA64] Override max number of concurrent global TLB | 1524 | nptcg= [IA64] Override max number of concurrent global TLB |
1513 | purges which is reported from either PAL_VM_SUMMARY or | 1525 | purges which is reported from either PAL_VM_SUMMARY or |
1514 | SAL PALO. | 1526 | SAL PALO. |
1515 | 1527 | ||
1516 | numa_zonelist_order= [KNL, BOOT] Select zonelist order for NUMA. | 1528 | numa_zonelist_order= [KNL, BOOT] Select zonelist order for NUMA. |
1517 | one of ['zone', 'node', 'default'] can be specified | 1529 | one of ['zone', 'node', 'default'] can be specified |
1518 | This can be set from sysctl after boot. | 1530 | This can be set from sysctl after boot. |
1519 | See Documentation/sysctl/vm.txt for details. | 1531 | See Documentation/sysctl/vm.txt for details. |
1520 | 1532 | ||
1521 | nr_uarts= [SERIAL] maximum number of UARTs to be registered. | 1533 | nr_uarts= [SERIAL] maximum number of UARTs to be registered. |
1522 | 1534 | ||
1523 | olpc_ec_timeout= [OLPC] ms delay when issuing EC commands | 1535 | olpc_ec_timeout= [OLPC] ms delay when issuing EC commands |
1524 | Rather than timing out after 20 ms if an EC | 1536 | Rather than timing out after 20 ms if an EC |
1525 | command is not properly ACKed, override the length | 1537 | command is not properly ACKed, override the length |
1526 | of the timeout. We have interrupts disabled while | 1538 | of the timeout. We have interrupts disabled while |
1527 | waiting for the ACK, so if this is set too high | 1539 | waiting for the ACK, so if this is set too high |
1528 | interrupts *may* be lost! | 1540 | interrupts *may* be lost! |
1529 | 1541 | ||
1530 | opl3= [HW,OSS] | 1542 | opl3= [HW,OSS] |
1531 | Format: <io> | 1543 | Format: <io> |
1532 | 1544 | ||
1533 | oprofile.timer= [HW] | 1545 | oprofile.timer= [HW] |
1534 | Use timer interrupt instead of performance counters | 1546 | Use timer interrupt instead of performance counters |
1535 | 1547 | ||
1536 | osst= [HW,SCSI] SCSI Tape Driver | 1548 | osst= [HW,SCSI] SCSI Tape Driver |
1537 | Format: <buffer_size>,<write_threshold> | 1549 | Format: <buffer_size>,<write_threshold> |
1538 | See also Documentation/scsi/st.txt. | 1550 | See also Documentation/scsi/st.txt. |
1539 | 1551 | ||
1540 | panic= [KNL] Kernel behaviour on panic | 1552 | panic= [KNL] Kernel behaviour on panic |
1541 | Format: <timeout> | 1553 | Format: <timeout> |
1542 | 1554 | ||
1543 | parkbd.port= [HW] Parallel port number the keyboard adapter is | 1555 | parkbd.port= [HW] Parallel port number the keyboard adapter is |
1544 | connected to, default is 0. | 1556 | connected to, default is 0. |
1545 | Format: <parport#> | 1557 | Format: <parport#> |
1546 | parkbd.mode= [HW] Parallel port keyboard adapter mode of operation, | 1558 | parkbd.mode= [HW] Parallel port keyboard adapter mode of operation, |
1547 | 0 for XT, 1 for AT (default is AT). | 1559 | 0 for XT, 1 for AT (default is AT). |
1548 | Format: <mode> | 1560 | Format: <mode> |
1549 | 1561 | ||
1550 | parport= [HW,PPT] Specify parallel ports. 0 disables. | 1562 | parport= [HW,PPT] Specify parallel ports. 0 disables. |
1551 | Format: { 0 | auto | 0xBBB[,IRQ[,DMA]] } | 1563 | Format: { 0 | auto | 0xBBB[,IRQ[,DMA]] } |
1552 | Use 'auto' to force the driver to use any | 1564 | Use 'auto' to force the driver to use any |
1553 | IRQ/DMA settings detected (the default is to | 1565 | IRQ/DMA settings detected (the default is to |
1554 | ignore detected IRQ/DMA settings because of | 1566 | ignore detected IRQ/DMA settings because of |
1555 | possible conflicts). You can specify the base | 1567 | possible conflicts). You can specify the base |
1556 | address, IRQ, and DMA settings; IRQ and DMA | 1568 | address, IRQ, and DMA settings; IRQ and DMA |
1557 | should be numbers, or 'auto' (for using detected | 1569 | should be numbers, or 'auto' (for using detected |
1558 | settings on that particular port), or 'nofifo' | 1570 | settings on that particular port), or 'nofifo' |
1559 | (to avoid using a FIFO even if it is detected). | 1571 | (to avoid using a FIFO even if it is detected). |
1560 | Parallel ports are assigned in the order they | 1572 | Parallel ports are assigned in the order they |
1561 | are specified on the command line, starting | 1573 | are specified on the command line, starting |
1562 | with parport0. | 1574 | with parport0. |
1563 | 1575 | ||
1564 | parport_init_mode= [HW,PPT] | 1576 | parport_init_mode= [HW,PPT] |
1565 | Configure VIA parallel port to operate in | 1577 | Configure VIA parallel port to operate in |
1566 | a specific mode. This is necessary on Pegasos | 1578 | a specific mode. This is necessary on Pegasos |
1567 | computer where firmware has no options for setting | 1579 | computer where firmware has no options for setting |
1568 | up parallel port mode and sets it to spp. | 1580 | up parallel port mode and sets it to spp. |
1569 | Currently this function knows 686a and 8231 chips. | 1581 | Currently this function knows 686a and 8231 chips. |
1570 | Format: [spp|ps2|epp|ecp|ecpepp] | 1582 | Format: [spp|ps2|epp|ecp|ecpepp] |
1571 | 1583 | ||
1572 | pas2= [HW,OSS] Format: | 1584 | pas2= [HW,OSS] Format: |
1573 | <io>,<irq>,<dma>,<dma16>,<sb_io>,<sb_irq>,<sb_dma>,<sb_dma16> | 1585 | <io>,<irq>,<dma>,<dma16>,<sb_io>,<sb_irq>,<sb_dma>,<sb_dma16> |
1574 | 1586 | ||
1575 | pas16= [HW,SCSI] | 1587 | pas16= [HW,SCSI] |
1576 | See header of drivers/scsi/pas16.c. | 1588 | See header of drivers/scsi/pas16.c. |
1577 | 1589 | ||
1578 | pause_on_oops= | 1590 | pause_on_oops= |
1579 | Halt all CPUs after the first oops has been printed for | 1591 | Halt all CPUs after the first oops has been printed for |
1580 | the specified number of seconds. This is to be used if | 1592 | the specified number of seconds. This is to be used if |
1581 | your oopses keep scrolling off the screen. | 1593 | your oopses keep scrolling off the screen. |
1582 | 1594 | ||
1583 | pcbit= [HW,ISDN] | 1595 | pcbit= [HW,ISDN] |
1584 | 1596 | ||
1585 | pcd. [PARIDE] | 1597 | pcd. [PARIDE] |
1586 | See header of drivers/block/paride/pcd.c. | 1598 | See header of drivers/block/paride/pcd.c. |
1587 | See also Documentation/paride.txt. | 1599 | See also Documentation/paride.txt. |
1588 | 1600 | ||
1589 | pci=option[,option...] [PCI] various PCI subsystem options: | 1601 | pci=option[,option...] [PCI] various PCI subsystem options: |
1590 | off [X86] don't probe for the PCI bus | 1602 | off [X86] don't probe for the PCI bus |
1591 | bios [X86-32] force use of PCI BIOS, don't access | 1603 | bios [X86-32] force use of PCI BIOS, don't access |
1592 | the hardware directly. Use this if your machine | 1604 | the hardware directly. Use this if your machine |
1593 | has a non-standard PCI host bridge. | 1605 | has a non-standard PCI host bridge. |
1594 | nobios [X86-32] disallow use of PCI BIOS, only direct | 1606 | nobios [X86-32] disallow use of PCI BIOS, only direct |
1595 | hardware access methods are allowed. Use this | 1607 | hardware access methods are allowed. Use this |
1596 | if you experience crashes upon bootup and you | 1608 | if you experience crashes upon bootup and you |
1597 | suspect they are caused by the BIOS. | 1609 | suspect they are caused by the BIOS. |
1598 | conf1 [X86] Force use of PCI Configuration | 1610 | conf1 [X86] Force use of PCI Configuration |
1599 | Mechanism 1. | 1611 | Mechanism 1. |
1600 | conf2 [X86] Force use of PCI Configuration | 1612 | conf2 [X86] Force use of PCI Configuration |
1601 | Mechanism 2. | 1613 | Mechanism 2. |
1602 | noaer [PCIE] If the PCIEAER kernel config parameter is | 1614 | noaer [PCIE] If the PCIEAER kernel config parameter is |
1603 | enabled, this kernel boot option can be used to | 1615 | enabled, this kernel boot option can be used to |
1604 | disable the use of PCIE advanced error reporting. | 1616 | disable the use of PCIE advanced error reporting. |
1605 | nodomains [PCI] Disable support for multiple PCI | 1617 | nodomains [PCI] Disable support for multiple PCI |
1606 | root domains (aka PCI segments, in ACPI-speak). | 1618 | root domains (aka PCI segments, in ACPI-speak). |
1607 | nommconf [X86-32,X86_64] Disable use of MMCONFIG for PCI | 1619 | nommconf [X86-32,X86_64] Disable use of MMCONFIG for PCI |
1608 | Configuration | 1620 | Configuration |
1609 | nomsi [MSI] If the PCI_MSI kernel config parameter is | 1621 | nomsi [MSI] If the PCI_MSI kernel config parameter is |
1610 | enabled, this kernel boot option can be used to | 1622 | enabled, this kernel boot option can be used to |
1611 | disable the use of MSI interrupts system-wide. | 1623 | disable the use of MSI interrupts system-wide. |
1612 | biosirq [X86-32] Use PCI BIOS calls to get the interrupt | 1624 | biosirq [X86-32] Use PCI BIOS calls to get the interrupt |
1613 | routing table. These calls are known to be buggy | 1625 | routing table. These calls are known to be buggy |
1614 | on several machines and they hang the machine | 1626 | on several machines and they hang the machine |
1615 | when used, but on other computers it's the only | 1627 | when used, but on other computers it's the only |
1616 | way to get the interrupt routing table. Try | 1628 | way to get the interrupt routing table. Try |
1617 | this option if the kernel is unable to allocate | 1629 | this option if the kernel is unable to allocate |
1618 | IRQs or discover secondary PCI buses on your | 1630 | IRQs or discover secondary PCI buses on your |
1619 | motherboard. | 1631 | motherboard. |
1620 | rom [X86] Assign address space to expansion ROMs. | 1632 | rom [X86] Assign address space to expansion ROMs. |
1621 | Use with caution as certain devices share | 1633 | Use with caution as certain devices share |
1622 | address decoders between ROMs and other | 1634 | address decoders between ROMs and other |
1623 | resources. | 1635 | resources. |
1624 | norom [X86] Do not assign address space to | 1636 | norom [X86] Do not assign address space to |
1625 | expansion ROMs that do not already have | 1637 | expansion ROMs that do not already have |
1626 | BIOS assigned address ranges. | 1638 | BIOS assigned address ranges. |
1627 | irqmask=0xMMMM [X86] Set a bit mask of IRQs allowed to be | 1639 | irqmask=0xMMMM [X86] Set a bit mask of IRQs allowed to be |
1628 | assigned automatically to PCI devices. You can | 1640 | assigned automatically to PCI devices. You can |
1629 | make the kernel exclude IRQs of your ISA cards | 1641 | make the kernel exclude IRQs of your ISA cards |
1630 | this way. | 1642 | this way. |
1631 | pirqaddr=0xAAAAA [X86] Specify the physical address | 1643 | pirqaddr=0xAAAAA [X86] Specify the physical address |
1632 | of the PIRQ table (normally generated | 1644 | of the PIRQ table (normally generated |
1633 | by the BIOS) if it is outside the | 1645 | by the BIOS) if it is outside the |
1634 | F0000h-100000h range. | 1646 | F0000h-100000h range. |
1635 | lastbus=N [X86] Scan all buses thru bus #N. Can be | 1647 | lastbus=N [X86] Scan all buses thru bus #N. Can be |
1636 | useful if the kernel is unable to find your | 1648 | useful if the kernel is unable to find your |
1637 | secondary buses and you want to tell it | 1649 | secondary buses and you want to tell it |
1638 | explicitly which ones they are. | 1650 | explicitly which ones they are. |
1639 | assign-busses [X86] Always assign all PCI bus | 1651 | assign-busses [X86] Always assign all PCI bus |
1640 | numbers ourselves, overriding | 1652 | numbers ourselves, overriding |
1641 | whatever the firmware may have done. | 1653 | whatever the firmware may have done. |
1642 | usepirqmask [X86] Honor the possible IRQ mask stored | 1654 | usepirqmask [X86] Honor the possible IRQ mask stored |
1643 | in the BIOS $PIR table. This is needed on | 1655 | in the BIOS $PIR table. This is needed on |
1644 | some systems with broken BIOSes, notably | 1656 | some systems with broken BIOSes, notably |
1645 | some HP Pavilion N5400 and Omnibook XE3 | 1657 | some HP Pavilion N5400 and Omnibook XE3 |
1646 | notebooks. This will have no effect if ACPI | 1658 | notebooks. This will have no effect if ACPI |
1647 | IRQ routing is enabled. | 1659 | IRQ routing is enabled. |
1648 | noacpi [X86] Do not use ACPI for IRQ routing | 1660 | noacpi [X86] Do not use ACPI for IRQ routing |
1649 | or for PCI scanning. | 1661 | or for PCI scanning. |
1650 | use_crs [X86] Use _CRS for PCI resource | 1662 | use_crs [X86] Use _CRS for PCI resource |
1651 | allocation. | 1663 | allocation. |
1652 | routeirq Do IRQ routing for all PCI devices. | 1664 | routeirq Do IRQ routing for all PCI devices. |
1653 | This is normally done in pci_enable_device(), | 1665 | This is normally done in pci_enable_device(), |
1654 | so this option is a temporary workaround | 1666 | so this option is a temporary workaround |
1655 | for broken drivers that don't call it. | 1667 | for broken drivers that don't call it. |
1656 | skip_isa_align [X86] do not align io start addr, so can | 1668 | skip_isa_align [X86] do not align io start addr, so can |
1657 | handle more pci cards | 1669 | handle more pci cards |
1658 | firmware [ARM] Do not re-enumerate the bus but instead | 1670 | firmware [ARM] Do not re-enumerate the bus but instead |
1659 | just use the configuration from the | 1671 | just use the configuration from the |
1660 | bootloader. This is currently used on | 1672 | bootloader. This is currently used on |
1661 | IXP2000 systems where the bus has to be | 1673 | IXP2000 systems where the bus has to be |
1662 | configured a certain way for adjunct CPUs. | 1674 | configured a certain way for adjunct CPUs. |
1663 | noearly [X86] Don't do any early type 1 scanning. | 1675 | noearly [X86] Don't do any early type 1 scanning. |
1664 | This might help on some broken boards which | 1676 | This might help on some broken boards which |
1665 | machine check when some devices' config space | 1677 | machine check when some devices' config space |
1666 | is read. But various workarounds are disabled | 1678 | is read. But various workarounds are disabled |
1667 | and some IOMMU drivers will not work. | 1679 | and some IOMMU drivers will not work. |
1668 | bfsort Sort PCI devices into breadth-first order. | 1680 | bfsort Sort PCI devices into breadth-first order. |
1669 | This sorting is done to get a device | 1681 | This sorting is done to get a device |
1670 | order compatible with older (<= 2.4) kernels. | 1682 | order compatible with older (<= 2.4) kernels. |
1671 | nobfsort Don't sort PCI devices into breadth-first order. | 1683 | nobfsort Don't sort PCI devices into breadth-first order. |
1672 | cbiosize=nn[KMG] The fixed amount of bus space which is | 1684 | cbiosize=nn[KMG] The fixed amount of bus space which is |
1673 | reserved for the CardBus bridge's IO window. | 1685 | reserved for the CardBus bridge's IO window. |
1674 | The default value is 256 bytes. | 1686 | The default value is 256 bytes. |
1675 | cbmemsize=nn[KMG] The fixed amount of bus space which is | 1687 | cbmemsize=nn[KMG] The fixed amount of bus space which is |
1676 | reserved for the CardBus bridge's memory | 1688 | reserved for the CardBus bridge's memory |
1677 | window. The default value is 64 megabytes. | 1689 | window. The default value is 64 megabytes. |
1678 | 1690 | ||
1679 | pcie_aspm= [PCIE] Forcibly enable or disable PCIe Active State Power | 1691 | pcie_aspm= [PCIE] Forcibly enable or disable PCIe Active State Power |
1680 | Management. | 1692 | Management. |
1681 | off Disable ASPM. | 1693 | off Disable ASPM. |
1682 | force Enable ASPM even on devices that claim not to support it. | 1694 | force Enable ASPM even on devices that claim not to support it. |
1683 | WARNING: Forcing ASPM on may cause system lockups. | 1695 | WARNING: Forcing ASPM on may cause system lockups. |
1684 | 1696 | ||
1685 | pcmv= [HW,PCMCIA] BadgePAD 4 | 1697 | pcmv= [HW,PCMCIA] BadgePAD 4 |
1686 | 1698 | ||
1687 | pd. [PARIDE] | 1699 | pd. [PARIDE] |
1688 | See Documentation/paride.txt. | 1700 | See Documentation/paride.txt. |
1689 | 1701 | ||
1690 | pdcchassis= [PARISC,HW] Disable/Enable PDC Chassis Status codes at | 1702 | pdcchassis= [PARISC,HW] Disable/Enable PDC Chassis Status codes at |
1691 | boot time. | 1703 | boot time. |
1692 | Format: { 0 | 1 } | 1704 | Format: { 0 | 1 } |
1693 | See arch/parisc/kernel/pdc_chassis.c | 1705 | See arch/parisc/kernel/pdc_chassis.c |
1694 | 1706 | ||
1695 | pf. [PARIDE] | 1707 | pf. [PARIDE] |
1696 | See Documentation/paride.txt. | 1708 | See Documentation/paride.txt. |
1697 | 1709 | ||
1698 | pg. [PARIDE] | 1710 | pg. [PARIDE] |
1699 | See Documentation/paride.txt. | 1711 | See Documentation/paride.txt. |
1700 | 1712 | ||
1701 | pirq= [SMP,APIC] Manual mp-table setup | 1713 | pirq= [SMP,APIC] Manual mp-table setup |
1702 | See Documentation/x86/i386/IO-APIC.txt. | 1714 | See Documentation/x86/i386/IO-APIC.txt. |
1703 | 1715 | ||
1704 | plip= [PPT,NET] Parallel port network link | 1716 | plip= [PPT,NET] Parallel port network link |
1705 | Format: { parport<nr> | timid | 0 } | 1717 | Format: { parport<nr> | timid | 0 } |
1706 | See also Documentation/parport.txt. | 1718 | See also Documentation/parport.txt. |
1707 | 1719 | ||
1708 | pmtmr= [X86] Manual setup of pmtmr I/O Port. | 1720 | pmtmr= [X86] Manual setup of pmtmr I/O Port. |
1709 | Override pmtimer IOPort with a hex value. | 1721 | Override pmtimer IOPort with a hex value. |
1710 | e.g. pmtmr=0x508 | 1722 | e.g. pmtmr=0x508 |
1711 | 1723 | ||
1712 | pnp.debug [PNP] | 1724 | pnp.debug [PNP] |
1713 | Enable PNP debug messages. This depends on the | 1725 | Enable PNP debug messages. This depends on the |
1714 | CONFIG_PNP_DEBUG_MESSAGES option. | 1726 | CONFIG_PNP_DEBUG_MESSAGES option. |
1715 | 1727 | ||
1716 | pnpacpi= [ACPI] | 1728 | pnpacpi= [ACPI] |
1717 | { off } | 1729 | { off } |
1718 | 1730 | ||
1719 | pnpbios= [ISAPNP] | 1731 | pnpbios= [ISAPNP] |
1720 | { on | off | curr | res | no-curr | no-res } | 1732 | { on | off | curr | res | no-curr | no-res } |
1721 | 1733 | ||
1722 | pnp_reserve_irq= | 1734 | pnp_reserve_irq= |
1723 | [ISAPNP] Exclude IRQs for the autoconfiguration | 1735 | [ISAPNP] Exclude IRQs for the autoconfiguration |
1724 | 1736 | ||
1725 | pnp_reserve_dma= | 1737 | pnp_reserve_dma= |
1726 | [ISAPNP] Exclude DMAs for the autoconfiguration | 1738 | [ISAPNP] Exclude DMAs for the autoconfiguration |
1727 | 1739 | ||
1728 | pnp_reserve_io= [ISAPNP] Exclude I/O ports for the autoconfiguration | 1740 | pnp_reserve_io= [ISAPNP] Exclude I/O ports for the autoconfiguration |
1729 | Ranges are in pairs (I/O port base and size). | 1741 | Ranges are in pairs (I/O port base and size). |
1730 | 1742 | ||
1731 | pnp_reserve_mem= | 1743 | pnp_reserve_mem= |
1732 | [ISAPNP] Exclude memory regions for the | 1744 | [ISAPNP] Exclude memory regions for the |
1733 | autoconfiguration. | 1745 | autoconfiguration. |
1734 | Ranges are in pairs (memory base and size). | 1746 | Ranges are in pairs (memory base and size). |
1735 | 1747 | ||
1736 | dynamic_printk | 1748 | dynamic_printk |
1737 | Enables pr_debug()/dev_dbg() calls if | 1749 | Enables pr_debug()/dev_dbg() calls if |
1738 | CONFIG_DYNAMIC_PRINTK_DEBUG has been enabled. These can also | 1750 | CONFIG_DYNAMIC_PRINTK_DEBUG has been enabled. These can also |
1739 | be switched on/off via <debugfs>/dynamic_printk/modules | 1751 | be switched on/off via <debugfs>/dynamic_printk/modules |
1740 | 1752 | ||
1741 | print-fatal-signals= | 1753 | print-fatal-signals= |
1742 | [KNL] debug: print fatal signals | 1754 | [KNL] debug: print fatal signals |
1743 | print-fatal-signals=1: print segfault info to | 1755 | print-fatal-signals=1: print segfault info to |
1744 | the kernel console. | 1756 | the kernel console. |
1745 | default: off. | 1757 | default: off. |
1746 | 1758 | ||
1747 | printk.time= Show timing data prefixed to each printk message line | 1759 | printk.time= Show timing data prefixed to each printk message line |
1748 | Format: <bool> (1/Y/y=enable, 0/N/n=disable) | 1760 | Format: <bool> (1/Y/y=enable, 0/N/n=disable) |
1749 | 1761 | ||
1750 | profile= [KNL] Enable kernel profiling via /proc/profile | 1762 | profile= [KNL] Enable kernel profiling via /proc/profile |
1751 | Format: [schedule,]<number> | 1763 | Format: [schedule,]<number> |
1752 | Param: "schedule" - profile schedule points. | 1764 | Param: "schedule" - profile schedule points. |
1753 | Param: <number> - step/bucket size as a power of 2 for | 1765 | Param: <number> - step/bucket size as a power of 2 for |
1754 | statistical time based profiling. | 1766 | statistical time based profiling. |
1755 | Param: "sleep" - profile D-state sleeping (millisecs). | 1767 | Param: "sleep" - profile D-state sleeping (millisecs). |
1756 | Requires CONFIG_SCHEDSTATS | 1768 | Requires CONFIG_SCHEDSTATS |
1757 | Param: "kvm" - profile VM exits. | 1769 | Param: "kvm" - profile VM exits. |
1758 | 1770 | ||
1759 | processor.max_cstate= [HW,ACPI] | 1771 | processor.max_cstate= [HW,ACPI] |
1760 | Limit processor to maximum C-state | 1772 | Limit processor to maximum C-state |
1761 | max_cstate=9 overrides any DMI blacklist limit. | 1773 | max_cstate=9 overrides any DMI blacklist limit. |
1762 | 1774 | ||
1763 | processor.nocst [HW,ACPI] | 1775 | processor.nocst [HW,ACPI] |
1764 | Ignore the _CST method to determine C-states, | 1776 | Ignore the _CST method to determine C-states, |
1765 | instead using the legacy FADT method | 1777 | instead using the legacy FADT method |
1766 | 1778 | ||
1767 | prompt_ramdisk= [RAM] List of RAM disks to prompt for floppy disk | 1779 | prompt_ramdisk= [RAM] List of RAM disks to prompt for floppy disk |
1768 | before loading. | 1780 | before loading. |
1769 | See Documentation/ramdisk.txt. | 1781 | See Documentation/ramdisk.txt. |
1770 | 1782 | ||
1771 | psmouse.proto= [HW,MOUSE] Highest PS2 mouse protocol extension to | 1783 | psmouse.proto= [HW,MOUSE] Highest PS2 mouse protocol extension to |
1772 | probe for; one of (bare|imps|exps|lifebook|any). | 1784 | probe for; one of (bare|imps|exps|lifebook|any). |
1773 | psmouse.rate= [HW,MOUSE] Set desired mouse report rate, in reports | 1785 | psmouse.rate= [HW,MOUSE] Set desired mouse report rate, in reports |
1774 | per second. | 1786 | per second. |
1775 | psmouse.resetafter= [HW,MOUSE] | 1787 | psmouse.resetafter= [HW,MOUSE] |
1776 | Try to reset the device after so many bad packets | 1788 | Try to reset the device after so many bad packets |
1777 | (0 = never). | 1789 | (0 = never). |
1778 | psmouse.resolution= | 1790 | psmouse.resolution= |
1779 | [HW,MOUSE] Set desired mouse resolution, in dpi. | 1791 | [HW,MOUSE] Set desired mouse resolution, in dpi. |
1780 | psmouse.smartscroll= | 1792 | psmouse.smartscroll= |
1781 | [HW,MOUSE] Controls Logitech smartscroll autorepeat. | 1793 | [HW,MOUSE] Controls Logitech smartscroll autorepeat. |
1782 | 0 = disabled, 1 = enabled (default). | 1794 | 0 = disabled, 1 = enabled (default). |
1783 | 1795 | ||
1784 | pss= [HW,OSS] Personal Sound System (ECHO ESC614) | 1796 | pss= [HW,OSS] Personal Sound System (ECHO ESC614) |
1785 | Format: | 1797 | Format: |
1786 | <io>,<mss_io>,<mss_irq>,<mss_dma>,<mpu_io>,<mpu_irq> | 1798 | <io>,<mss_io>,<mss_irq>,<mss_dma>,<mpu_io>,<mpu_irq> |
1787 | 1799 | ||
1788 | pt. [PARIDE] | 1800 | pt. [PARIDE] |
1789 | See Documentation/paride.txt. | 1801 | See Documentation/paride.txt. |
1790 | 1802 | ||
1791 | pty.legacy_count= | 1803 | pty.legacy_count= |
1792 | [KNL] Number of legacy pty's. Overwrites compiled-in | 1804 | [KNL] Number of legacy pty's. Overwrites compiled-in |
1793 | default number. | 1805 | default number. |
1794 | 1806 | ||
1795 | quiet [KNL] Disable most log messages | 1807 | quiet [KNL] Disable most log messages |
1796 | 1808 | ||
1797 | r128= [HW,DRM] | 1809 | r128= [HW,DRM] |
1798 | 1810 | ||
1799 | raid= [HW,RAID] | 1811 | raid= [HW,RAID] |
1800 | See Documentation/md.txt. | 1812 | See Documentation/md.txt. |
1801 | 1813 | ||
1802 | ramdisk_blocksize= [RAM] | 1814 | ramdisk_blocksize= [RAM] |
1803 | See Documentation/ramdisk.txt. | 1815 | See Documentation/ramdisk.txt. |
1804 | 1816 | ||
1805 | ramdisk_size= [RAM] Sizes of RAM disks in kilobytes | 1817 | ramdisk_size= [RAM] Sizes of RAM disks in kilobytes |
1806 | See Documentation/ramdisk.txt. | 1818 | See Documentation/ramdisk.txt. |
1807 | 1819 | ||
1808 | rcupdate.blimit= [KNL,BOOT] | 1820 | rcupdate.blimit= [KNL,BOOT] |
1809 | Set maximum number of finished RCU callbacks to process | 1821 | Set maximum number of finished RCU callbacks to process |
1810 | in one batch. | 1822 | in one batch. |
1811 | 1823 | ||
1812 | rcupdate.qhimark= [KNL,BOOT] | 1824 | rcupdate.qhimark= [KNL,BOOT] |
1813 | Set threshold of queued | 1825 | Set threshold of queued |
1814 | RCU callbacks over which batch limiting is disabled. | 1826 | RCU callbacks over which batch limiting is disabled. |
1815 | 1827 | ||
1816 | rcupdate.qlowmark= [KNL,BOOT] | 1828 | rcupdate.qlowmark= [KNL,BOOT] |
1817 | Set threshold of queued RCU callbacks below which | 1829 | Set threshold of queued RCU callbacks below which |
1818 | batch limiting is re-enabled. | 1830 | batch limiting is re-enabled. |
1819 | 1831 | ||
1820 | rdinit= [KNL] | 1832 | rdinit= [KNL] |
1821 | Format: <full_path> | 1833 | Format: <full_path> |
1822 | Run specified binary instead of /init from the ramdisk, | 1834 | Run specified binary instead of /init from the ramdisk, |
1823 | used for early userspace startup. See initrd. | 1835 | used for early userspace startup. See initrd. |
1824 | 1836 | ||
1825 | reboot= [BUGS=X86-32,BUGS=ARM,BUGS=IA-64] Rebooting mode | 1837 | reboot= [BUGS=X86-32,BUGS=ARM,BUGS=IA-64] Rebooting mode |
1826 | Format: <reboot_mode>[,<reboot_mode2>[,...]] | 1838 | Format: <reboot_mode>[,<reboot_mode2>[,...]] |
1827 | See arch/*/kernel/reboot.c or arch/*/kernel/process.c | 1839 | See arch/*/kernel/reboot.c or arch/*/kernel/process.c |
1828 | 1840 | ||
1829 | relax_domain_level= | 1841 | relax_domain_level= |
1830 | [KNL, SMP] Set scheduler's default relax_domain_level. | 1842 | [KNL, SMP] Set scheduler's default relax_domain_level. |
1831 | See Documentation/cpusets.txt. | 1843 | See Documentation/cpusets.txt. |
1832 | 1844 | ||
1833 | reserve= [KNL,BUGS] Force the kernel to ignore some iomem area | 1845 | reserve= [KNL,BUGS] Force the kernel to ignore some iomem area |
1834 | 1846 | ||
1835 | reservetop= [X86-32] | 1847 | reservetop= [X86-32] |
1836 | Format: nn[KMG] | 1848 | Format: nn[KMG] |
1837 | Reserves a hole at the top of the kernel virtual | 1849 | Reserves a hole at the top of the kernel virtual |
1838 | address space. | 1850 | address space. |
1839 | 1851 | ||
1840 | reset_devices [KNL] Force drivers to reset the underlying device | 1852 | reset_devices [KNL] Force drivers to reset the underlying device |
1841 | during initialization. | 1853 | during initialization. |
1842 | 1854 | ||
1843 | resume= [SWSUSP] | 1855 | resume= [SWSUSP] |
1844 | Specify the partition device for software suspend | 1856 | Specify the partition device for software suspend |
1845 | 1857 | ||
1846 | resume_offset= [SWSUSP] | 1858 | resume_offset= [SWSUSP] |
1847 | Specify the offset from the beginning of the partition | 1859 | Specify the offset from the beginning of the partition |
1848 | given by "resume=" at which the swap header is located, | 1860 | given by "resume=" at which the swap header is located, |
1849 | in <PAGE_SIZE> units (needed only for swap files). | 1861 | in <PAGE_SIZE> units (needed only for swap files). |
1850 | See Documentation/power/swsusp-and-swap-files.txt | 1862 | See Documentation/power/swsusp-and-swap-files.txt |
1851 | 1863 | ||
1852 | retain_initrd [RAM] Keep initrd memory after extraction | 1864 | retain_initrd [RAM] Keep initrd memory after extraction |
1853 | 1865 | ||
1854 | rhash_entries= [KNL,NET] | 1866 | rhash_entries= [KNL,NET] |
1855 | Set number of hash buckets for route cache | 1867 | Set number of hash buckets for route cache |
1856 | 1868 | ||
1857 | riscom8= [HW,SERIAL] | 1869 | riscom8= [HW,SERIAL] |
1858 | Format: <io_board1>[,<io_board2>[,...<io_boardN>]] | 1870 | Format: <io_board1>[,<io_board2>[,...<io_boardN>]] |
1859 | 1871 | ||
1860 | ro [KNL] Mount root device read-only on boot | 1872 | ro [KNL] Mount root device read-only on boot |
1861 | 1873 | ||
1862 | root= [KNL] Root filesystem | 1874 | root= [KNL] Root filesystem |
1863 | 1875 | ||
1864 | rootdelay= [KNL] Delay (in seconds) to pause before attempting to | 1876 | rootdelay= [KNL] Delay (in seconds) to pause before attempting to |
1865 | mount the root filesystem | 1877 | mount the root filesystem |
1866 | 1878 | ||
1867 | rootflags= [KNL] Set root filesystem mount option string | 1879 | rootflags= [KNL] Set root filesystem mount option string |
1868 | 1880 | ||
1869 | rootfstype= [KNL] Set root filesystem type | 1881 | rootfstype= [KNL] Set root filesystem type |
1870 | 1882 | ||
1871 | rootwait [KNL] Wait (indefinitely) for root device to show up. | 1883 | rootwait [KNL] Wait (indefinitely) for root device to show up. |
1872 | Useful for devices that are detected asynchronously | 1884 | Useful for devices that are detected asynchronously |
1873 | (e.g. USB and MMC devices). | 1885 | (e.g. USB and MMC devices). |
1874 | 1886 | ||
1875 | root_plug.vendor_id= | 1887 | root_plug.vendor_id= |
1876 | [ROOTPLUG] Override the default vendor ID | 1888 | [ROOTPLUG] Override the default vendor ID |
1877 | 1889 | ||
1878 | root_plug.product_id= | 1890 | root_plug.product_id= |
1879 | [ROOTPLUG] Override the default product ID | 1891 | [ROOTPLUG] Override the default product ID |
1880 | 1892 | ||
1881 | root_plug.debug= | 1893 | root_plug.debug= |
1882 | [ROOTPLUG] Enable debugging output | 1894 | [ROOTPLUG] Enable debugging output |
1883 | 1895 | ||
1884 | rw [KNL] Mount root device read-write on boot | 1896 | rw [KNL] Mount root device read-write on boot |
1885 | 1897 | ||
1886 | S [KNL] Run init in single mode | 1898 | S [KNL] Run init in single mode |
1887 | 1899 | ||
1888 | sa1100ir [NET] | 1900 | sa1100ir [NET] |
1889 | See drivers/net/irda/sa1100_ir.c. | 1901 | See drivers/net/irda/sa1100_ir.c. |
1890 | 1902 | ||
1891 | sbni= [NET] Granch SBNI12 leased line adapter | 1903 | sbni= [NET] Granch SBNI12 leased line adapter |
1892 | 1904 | ||
1893 | sc1200wdt= [HW,WDT] SC1200 WDT (watchdog) driver | 1905 | sc1200wdt= [HW,WDT] SC1200 WDT (watchdog) driver |
1894 | Format: <io>[,<timeout>[,<isapnp>]] | 1906 | Format: <io>[,<timeout>[,<isapnp>]] |
1895 | 1907 | ||
1896 | scsi_debug_*= [SCSI] | 1908 | scsi_debug_*= [SCSI] |
1897 | See drivers/scsi/scsi_debug.c. | 1909 | See drivers/scsi/scsi_debug.c. |
1898 | 1910 | ||
1899 | scsi_default_dev_flags= | 1911 | scsi_default_dev_flags= |
1900 | [SCSI] SCSI default device flags | 1912 | [SCSI] SCSI default device flags |
1901 | Format: <integer> | 1913 | Format: <integer> |
1902 | 1914 | ||
1903 | scsi_dev_flags= [SCSI] Black/white list entry for vendor and model | 1915 | scsi_dev_flags= [SCSI] Black/white list entry for vendor and model |
1904 | Format: <vendor>:<model>:<flags> | 1916 | Format: <vendor>:<model>:<flags> |
1905 | (flags are integer value) | 1917 | (flags are integer value) |
1906 | 1918 | ||
1907 | scsi_logging_level= [SCSI] a bit mask of logging levels | 1919 | scsi_logging_level= [SCSI] a bit mask of logging levels |
1908 | See drivers/scsi/scsi_logging.h for bits. Also | 1920 | See drivers/scsi/scsi_logging.h for bits. Also |
1909 | settable via sysctl at dev.scsi.logging_level | 1921 | settable via sysctl at dev.scsi.logging_level |
1910 | (/proc/sys/dev/scsi/logging_level). | 1922 | (/proc/sys/dev/scsi/logging_level). |
1911 | There is also a nice 'scsi_logging_level' script in the | 1923 | There is also a nice 'scsi_logging_level' script in the |
1912 | S390-tools package, available for download at | 1924 | S390-tools package, available for download at |
1913 | http://www-128.ibm.com/developerworks/linux/linux390/s390-tools-1.5.4.html | 1925 | http://www-128.ibm.com/developerworks/linux/linux390/s390-tools-1.5.4.html |
1914 | 1926 | ||
1915 | scsi_mod.scan= [SCSI] sync (default) scans SCSI busses as they are | 1927 | scsi_mod.scan= [SCSI] sync (default) scans SCSI busses as they are |
1916 | discovered. async scans them in kernel threads, | 1928 | discovered. async scans them in kernel threads, |
1917 | allowing boot to proceed. none ignores them, expecting | 1929 | allowing boot to proceed. none ignores them, expecting |
1918 | user space to do the scan. | 1930 | user space to do the scan. |
1919 | 1931 | ||
1920 | selinux [SELINUX] Disable or enable SELinux at boot time. | 1932 | selinux [SELINUX] Disable or enable SELinux at boot time. |
1921 | Format: { "0" | "1" } | 1933 | Format: { "0" | "1" } |
1922 | See security/selinux/Kconfig help text. | 1934 | See security/selinux/Kconfig help text. |
1923 | 0 -- disable. | 1935 | 0 -- disable. |
1924 | 1 -- enable. | 1936 | 1 -- enable. |
1925 | Default value is set via kernel config option. | 1937 | Default value is set via kernel config option. |
1926 | If enabled at boot time, /selinux/disable can be used | 1938 | If enabled at boot time, /selinux/disable can be used |
1927 | later to disable prior to initial policy load. | 1939 | later to disable prior to initial policy load. |
1928 | 1940 | ||
1929 | selinux_compat_net = | 1941 | selinux_compat_net = |
1930 | [SELINUX] Set initial selinux_compat_net flag value. | 1942 | [SELINUX] Set initial selinux_compat_net flag value. |
1931 | Format: { "0" | "1" } | 1943 | Format: { "0" | "1" } |
1932 | 0 -- use new secmark-based packet controls | 1944 | 0 -- use new secmark-based packet controls |
1933 | 1 -- use legacy packet controls | 1945 | 1 -- use legacy packet controls |
1934 | Default value is 0 (preferred). | 1946 | Default value is 0 (preferred). |
1935 | Value can be changed at runtime via | 1947 | Value can be changed at runtime via |
1936 | /selinux/compat_net. | 1948 | /selinux/compat_net. |
1937 | 1949 | ||
1938 | serialnumber [BUGS=X86-32] | 1950 | serialnumber [BUGS=X86-32] |
1939 | 1951 | ||
1940 | shapers= [NET] | 1952 | shapers= [NET] |
1941 | Maximal number of shapers. | 1953 | Maximal number of shapers. |
1942 | 1954 | ||
1943 | show_msr= [x86] show boot-time MSR settings | 1955 | show_msr= [x86] show boot-time MSR settings |
1944 | Format: { <integer> } | 1956 | Format: { <integer> } |
1945 | Show boot-time (BIOS-initialized) MSR settings. | 1957 | Show boot-time (BIOS-initialized) MSR settings. |
1946 | The parameter means the number of CPUs to show, | 1958 | The parameter means the number of CPUs to show, |
1947 | for example 1 means boot CPU only. | 1959 | for example 1 means boot CPU only. |
1948 | 1960 | ||
1949 | sim710= [SCSI,HW] | 1961 | sim710= [SCSI,HW] |
1950 | See header of drivers/scsi/sim710.c. | 1962 | See header of drivers/scsi/sim710.c. |
1951 | 1963 | ||
1952 | simeth= [IA-64] | 1964 | simeth= [IA-64] |
1953 | simscsi= | 1965 | simscsi= |
1954 | 1966 | ||
1955 | slram= [HW,MTD] | 1967 | slram= [HW,MTD] |
1956 | 1968 | ||
1957 | slub_debug[=options[,slabs]] [MM, SLUB] | 1969 | slub_debug[=options[,slabs]] [MM, SLUB] |
1958 | Enabling slub_debug allows one to determine the | 1970 | Enabling slub_debug allows one to determine the |
1959 | culprit if slab objects become corrupted. Enabling | 1971 | culprit if slab objects become corrupted. Enabling |
1960 | slub_debug can create guard zones around objects and | 1972 | slub_debug can create guard zones around objects and |
1961 | may poison objects when not in use. Also tracks the | 1973 | may poison objects when not in use. Also tracks the |
1962 | last alloc / free. For more information see | 1974 | last alloc / free. For more information see |
1963 | Documentation/vm/slub.txt. | 1975 | Documentation/vm/slub.txt. |
1964 | 1976 | ||
1965 | slub_max_order= [MM, SLUB] | 1977 | slub_max_order= [MM, SLUB] |
1966 | Determines the maximum allowed order for slabs. | 1978 | Determines the maximum allowed order for slabs. |
1967 | A high setting may cause OOMs due to memory | 1979 | A high setting may cause OOMs due to memory |
1968 | fragmentation. For more information see | 1980 | fragmentation. For more information see |
1969 | Documentation/vm/slub.txt. | 1981 | Documentation/vm/slub.txt. |
1970 | 1982 | ||
1971 | slub_min_objects= [MM, SLUB] | 1983 | slub_min_objects= [MM, SLUB] |
1972 | The minimum number of objects per slab. SLUB will | 1984 | The minimum number of objects per slab. SLUB will |
1973 | increase the slab order up to slub_max_order to | 1985 | increase the slab order up to slub_max_order to |
1974 | generate a sufficiently large slab able to contain | 1986 | generate a sufficiently large slab able to contain |
1975 | the number of objects indicated. The higher the number | 1987 | the number of objects indicated. The higher the number |
1976 | of objects the smaller the overhead of tracking slabs | 1988 | of objects the smaller the overhead of tracking slabs |
1977 | and the less frequently locks need to be acquired. | 1989 | and the less frequently locks need to be acquired. |
1978 | For more information see Documentation/vm/slub.txt. | 1990 | For more information see Documentation/vm/slub.txt. |
1979 | 1991 | ||
1980 | slub_min_order= [MM, SLUB] | 1992 | slub_min_order= [MM, SLUB] |
1981 | Determines the mininum page order for slabs. Must be | 1993 | Determines the mininum page order for slabs. Must be |
1982 | lower than slub_max_order. | 1994 | lower than slub_max_order. |
1983 | For more information see Documentation/vm/slub.txt. | 1995 | For more information see Documentation/vm/slub.txt. |
1984 | 1996 | ||
1985 | slub_nomerge [MM, SLUB] | 1997 | slub_nomerge [MM, SLUB] |
1986 | Disable merging of slabs with similar size. May be | 1998 | Disable merging of slabs with similar size. May be |
1987 | necessary if there is some reason to distinguish | 1999 | necessary if there is some reason to distinguish |
1988 | allocs to different slabs. Debug options disable | 2000 | allocs to different slabs. Debug options disable |
1989 | merging on their own. | 2001 | merging on their own. |
1990 | For more information see Documentation/vm/slub.txt. | 2002 | For more information see Documentation/vm/slub.txt. |
1991 | 2003 | ||
1992 | smart2= [HW] | 2004 | smart2= [HW] |
1993 | Format: <io1>[,<io2>[,...,<io8>]] | 2005 | Format: <io1>[,<io2>[,...,<io8>]] |
1994 | 2006 | ||
1995 | smp-alt-once [X86-32,SMP] On a hotplug CPU system, only | 2007 | smp-alt-once [X86-32,SMP] On a hotplug CPU system, only |
1996 | attempt to substitute SMP alternatives once at boot. | 2008 | attempt to substitute SMP alternatives once at boot. |
1997 | 2009 | ||
1998 | smsc-ircc2.nopnp [HW] Don't use PNP to discover SMC devices | 2010 | smsc-ircc2.nopnp [HW] Don't use PNP to discover SMC devices |
1999 | smsc-ircc2.ircc_cfg= [HW] Device configuration I/O port | 2011 | smsc-ircc2.ircc_cfg= [HW] Device configuration I/O port |
2000 | smsc-ircc2.ircc_sir= [HW] SIR base I/O port | 2012 | smsc-ircc2.ircc_sir= [HW] SIR base I/O port |
2001 | smsc-ircc2.ircc_fir= [HW] FIR base I/O port | 2013 | smsc-ircc2.ircc_fir= [HW] FIR base I/O port |
2002 | smsc-ircc2.ircc_irq= [HW] IRQ line | 2014 | smsc-ircc2.ircc_irq= [HW] IRQ line |
2003 | smsc-ircc2.ircc_dma= [HW] DMA channel | 2015 | smsc-ircc2.ircc_dma= [HW] DMA channel |
2004 | smsc-ircc2.ircc_transceiver= [HW] Transceiver type: | 2016 | smsc-ircc2.ircc_transceiver= [HW] Transceiver type: |
2005 | 0: Toshiba Satellite 1800 (GP data pin select) | 2017 | 0: Toshiba Satellite 1800 (GP data pin select) |
2006 | 1: Fast pin select (default) | 2018 | 1: Fast pin select (default) |
2007 | 2: ATC IRMode | 2019 | 2: ATC IRMode |
2008 | 2020 | ||
2009 | snd-ad1816a= [HW,ALSA] | 2021 | snd-ad1816a= [HW,ALSA] |
2010 | 2022 | ||
2011 | snd-ad1848= [HW,ALSA] | 2023 | snd-ad1848= [HW,ALSA] |
2012 | 2024 | ||
2013 | snd-ali5451= [HW,ALSA] | 2025 | snd-ali5451= [HW,ALSA] |
2014 | 2026 | ||
2015 | snd-als100= [HW,ALSA] | 2027 | snd-als100= [HW,ALSA] |
2016 | 2028 | ||
2017 | snd-als4000= [HW,ALSA] | 2029 | snd-als4000= [HW,ALSA] |
2018 | 2030 | ||
2019 | snd-azt2320= [HW,ALSA] | 2031 | snd-azt2320= [HW,ALSA] |
2020 | 2032 | ||
2021 | snd-cmi8330= [HW,ALSA] | 2033 | snd-cmi8330= [HW,ALSA] |
2022 | 2034 | ||
2023 | snd-cmipci= [HW,ALSA] | 2035 | snd-cmipci= [HW,ALSA] |
2024 | 2036 | ||
2025 | snd-cs4231= [HW,ALSA] | 2037 | snd-cs4231= [HW,ALSA] |
2026 | 2038 | ||
2027 | snd-cs4232= [HW,ALSA] | 2039 | snd-cs4232= [HW,ALSA] |
2028 | 2040 | ||
2029 | snd-cs4236= [HW,ALSA] | 2041 | snd-cs4236= [HW,ALSA] |
2030 | 2042 | ||
2031 | snd-cs4281= [HW,ALSA] | 2043 | snd-cs4281= [HW,ALSA] |
2032 | 2044 | ||
2033 | snd-cs46xx= [HW,ALSA] | 2045 | snd-cs46xx= [HW,ALSA] |
2034 | 2046 | ||
2035 | snd-dt019x= [HW,ALSA] | 2047 | snd-dt019x= [HW,ALSA] |
2036 | 2048 | ||
2037 | snd-dummy= [HW,ALSA] | 2049 | snd-dummy= [HW,ALSA] |
2038 | 2050 | ||
2039 | snd-emu10k1= [HW,ALSA] | 2051 | snd-emu10k1= [HW,ALSA] |
2040 | 2052 | ||
2041 | snd-ens1370= [HW,ALSA] | 2053 | snd-ens1370= [HW,ALSA] |
2042 | 2054 | ||
2043 | snd-ens1371= [HW,ALSA] | 2055 | snd-ens1371= [HW,ALSA] |
2044 | 2056 | ||
2045 | snd-es968= [HW,ALSA] | 2057 | snd-es968= [HW,ALSA] |
2046 | 2058 | ||
2047 | snd-es1688= [HW,ALSA] | 2059 | snd-es1688= [HW,ALSA] |
2048 | 2060 | ||
2049 | snd-es18xx= [HW,ALSA] | 2061 | snd-es18xx= [HW,ALSA] |
2050 | 2062 | ||
2051 | snd-es1938= [HW,ALSA] | 2063 | snd-es1938= [HW,ALSA] |
2052 | 2064 | ||
2053 | snd-es1968= [HW,ALSA] | 2065 | snd-es1968= [HW,ALSA] |
2054 | 2066 | ||
2055 | snd-fm801= [HW,ALSA] | 2067 | snd-fm801= [HW,ALSA] |
2056 | 2068 | ||
2057 | snd-gusclassic= [HW,ALSA] | 2069 | snd-gusclassic= [HW,ALSA] |
2058 | 2070 | ||
2059 | snd-gusextreme= [HW,ALSA] | 2071 | snd-gusextreme= [HW,ALSA] |
2060 | 2072 | ||
2061 | snd-gusmax= [HW,ALSA] | 2073 | snd-gusmax= [HW,ALSA] |
2062 | 2074 | ||
2063 | snd-hdsp= [HW,ALSA] | 2075 | snd-hdsp= [HW,ALSA] |
2064 | 2076 | ||
2065 | snd-ice1712= [HW,ALSA] | 2077 | snd-ice1712= [HW,ALSA] |
2066 | 2078 | ||
2067 | snd-intel8x0= [HW,ALSA] | 2079 | snd-intel8x0= [HW,ALSA] |
2068 | 2080 | ||
2069 | snd-interwave= [HW,ALSA] | 2081 | snd-interwave= [HW,ALSA] |
2070 | 2082 | ||
2071 | snd-interwave-stb= | 2083 | snd-interwave-stb= |
2072 | [HW,ALSA] | 2084 | [HW,ALSA] |
2073 | 2085 | ||
2074 | snd-korg1212= [HW,ALSA] | 2086 | snd-korg1212= [HW,ALSA] |
2075 | 2087 | ||
2076 | snd-maestro3= [HW,ALSA] | 2088 | snd-maestro3= [HW,ALSA] |
2077 | 2089 | ||
2078 | snd-mpu401= [HW,ALSA] | 2090 | snd-mpu401= [HW,ALSA] |
2079 | 2091 | ||
2080 | snd-mtpav= [HW,ALSA] | 2092 | snd-mtpav= [HW,ALSA] |
2081 | 2093 | ||
2082 | snd-nm256= [HW,ALSA] | 2094 | snd-nm256= [HW,ALSA] |
2083 | 2095 | ||
2084 | snd-opl3sa2= [HW,ALSA] | 2096 | snd-opl3sa2= [HW,ALSA] |
2085 | 2097 | ||
2086 | snd-opti92x-ad1848= | 2098 | snd-opti92x-ad1848= |
2087 | [HW,ALSA] | 2099 | [HW,ALSA] |
2088 | 2100 | ||
2089 | snd-opti92x-cs4231= | 2101 | snd-opti92x-cs4231= |
2090 | [HW,ALSA] | 2102 | [HW,ALSA] |
2091 | 2103 | ||
2092 | snd-opti93x= [HW,ALSA] | 2104 | snd-opti93x= [HW,ALSA] |
2093 | 2105 | ||
2094 | snd-pmac= [HW,ALSA] | 2106 | snd-pmac= [HW,ALSA] |
2095 | 2107 | ||
2096 | snd-rme32= [HW,ALSA] | 2108 | snd-rme32= [HW,ALSA] |
2097 | 2109 | ||
2098 | snd-rme96= [HW,ALSA] | 2110 | snd-rme96= [HW,ALSA] |
2099 | 2111 | ||
2100 | snd-rme9652= [HW,ALSA] | 2112 | snd-rme9652= [HW,ALSA] |
2101 | 2113 | ||
2102 | snd-sb8= [HW,ALSA] | 2114 | snd-sb8= [HW,ALSA] |
2103 | 2115 | ||
2104 | snd-sb16= [HW,ALSA] | 2116 | snd-sb16= [HW,ALSA] |
2105 | 2117 | ||
2106 | snd-sbawe= [HW,ALSA] | 2118 | snd-sbawe= [HW,ALSA] |
2107 | 2119 | ||
2108 | snd-serial= [HW,ALSA] | 2120 | snd-serial= [HW,ALSA] |
2109 | 2121 | ||
2110 | snd-sgalaxy= [HW,ALSA] | 2122 | snd-sgalaxy= [HW,ALSA] |
2111 | 2123 | ||
2112 | snd-sonicvibes= [HW,ALSA] | 2124 | snd-sonicvibes= [HW,ALSA] |
2113 | 2125 | ||
2114 | snd-sun-amd7930= | 2126 | snd-sun-amd7930= |
2115 | [HW,ALSA] | 2127 | [HW,ALSA] |
2116 | 2128 | ||
2117 | snd-sun-cs4231= [HW,ALSA] | 2129 | snd-sun-cs4231= [HW,ALSA] |
2118 | 2130 | ||
2119 | snd-trident= [HW,ALSA] | 2131 | snd-trident= [HW,ALSA] |
2120 | 2132 | ||
2121 | snd-usb-audio= [HW,ALSA,USB] | 2133 | snd-usb-audio= [HW,ALSA,USB] |
2122 | 2134 | ||
2123 | snd-via82xx= [HW,ALSA] | 2135 | snd-via82xx= [HW,ALSA] |
2124 | 2136 | ||
2125 | snd-virmidi= [HW,ALSA] | 2137 | snd-virmidi= [HW,ALSA] |
2126 | 2138 | ||
2127 | snd-wavefront= [HW,ALSA] | 2139 | snd-wavefront= [HW,ALSA] |
2128 | 2140 | ||
2129 | snd-ymfpci= [HW,ALSA] | 2141 | snd-ymfpci= [HW,ALSA] |
2130 | 2142 | ||
2131 | softlockup_panic= | 2143 | softlockup_panic= |
2132 | [KNL] Should the soft-lockup detector generate panics. | 2144 | [KNL] Should the soft-lockup detector generate panics. |
2133 | 2145 | ||
2134 | sonypi.*= [HW] Sony Programmable I/O Control Device driver | 2146 | sonypi.*= [HW] Sony Programmable I/O Control Device driver |
2135 | See Documentation/sonypi.txt | 2147 | See Documentation/sonypi.txt |
2136 | 2148 | ||
2137 | specialix= [HW,SERIAL] Specialix multi-serial port adapter | 2149 | specialix= [HW,SERIAL] Specialix multi-serial port adapter |
2138 | See Documentation/specialix.txt. | 2150 | See Documentation/specialix.txt. |
2139 | 2151 | ||
2140 | spia_io_base= [HW,MTD] | 2152 | spia_io_base= [HW,MTD] |
2141 | spia_fio_base= | 2153 | spia_fio_base= |
2142 | spia_pedr= | 2154 | spia_pedr= |
2143 | spia_peddr= | 2155 | spia_peddr= |
2144 | 2156 | ||
2145 | sscape= [HW,OSS] | 2157 | sscape= [HW,OSS] |
2146 | Format: <io>,<irq>,<dma>,<mpu_io>,<mpu_irq> | 2158 | Format: <io>,<irq>,<dma>,<mpu_io>,<mpu_irq> |
2147 | 2159 | ||
2148 | st= [HW,SCSI] SCSI tape parameters (buffers, etc.) | 2160 | st= [HW,SCSI] SCSI tape parameters (buffers, etc.) |
2149 | See Documentation/scsi/st.txt. | 2161 | See Documentation/scsi/st.txt. |
2150 | 2162 | ||
2151 | sti= [PARISC,HW] | 2163 | sti= [PARISC,HW] |
2152 | Format: <num> | 2164 | Format: <num> |
2153 | Set the STI (builtin display/keyboard on the HP-PARISC | 2165 | Set the STI (builtin display/keyboard on the HP-PARISC |
2154 | machines) console (graphic card) which should be used | 2166 | machines) console (graphic card) which should be used |
2155 | as the initial boot-console. | 2167 | as the initial boot-console. |
2156 | See also comment in drivers/video/console/sticore.c. | 2168 | See also comment in drivers/video/console/sticore.c. |
2157 | 2169 | ||
2158 | sti_font= [HW] | 2170 | sti_font= [HW] |
2159 | See comment in drivers/video/console/sticore.c. | 2171 | See comment in drivers/video/console/sticore.c. |
2160 | 2172 | ||
2161 | stifb= [HW] | 2173 | stifb= [HW] |
2162 | Format: bpp:<bpp1>[:<bpp2>[:<bpp3>...]] | 2174 | Format: bpp:<bpp1>[:<bpp2>[:<bpp3>...]] |
2163 | 2175 | ||
2164 | sunrpc.pool_mode= | 2176 | sunrpc.pool_mode= |
2165 | [NFS] | 2177 | [NFS] |
2166 | Control how the NFS server code allocates CPUs to | 2178 | Control how the NFS server code allocates CPUs to |
2167 | service thread pools. Depending on how many NICs | 2179 | service thread pools. Depending on how many NICs |
2168 | you have and where their interrupts are bound, this | 2180 | you have and where their interrupts are bound, this |
2169 | option will affect which CPUs will do NFS serving. | 2181 | option will affect which CPUs will do NFS serving. |
2170 | Note: this parameter cannot be changed while the | 2182 | Note: this parameter cannot be changed while the |
2171 | NFS server is running. | 2183 | NFS server is running. |
2172 | 2184 | ||
2173 | auto the server chooses an appropriate mode | 2185 | auto the server chooses an appropriate mode |
2174 | automatically using heuristics | 2186 | automatically using heuristics |
2175 | global a single global pool contains all CPUs | 2187 | global a single global pool contains all CPUs |
2176 | percpu one pool for each CPU | 2188 | percpu one pool for each CPU |
2177 | pernode one pool for each NUMA node (equivalent | 2189 | pernode one pool for each NUMA node (equivalent |
2178 | to global on non-NUMA machines) | 2190 | to global on non-NUMA machines) |
2179 | 2191 | ||
2180 | swiotlb= [IA-64] Number of I/O TLB slabs | 2192 | swiotlb= [IA-64] Number of I/O TLB slabs |
2181 | 2193 | ||
2182 | switches= [HW,M68k] | 2194 | switches= [HW,M68k] |
2183 | 2195 | ||
2184 | sym53c416= [HW,SCSI] | 2196 | sym53c416= [HW,SCSI] |
2185 | See header of drivers/scsi/sym53c416.c. | 2197 | See header of drivers/scsi/sym53c416.c. |
2186 | 2198 | ||
2187 | sysrq_always_enabled | 2199 | sysrq_always_enabled |
2188 | [KNL] | 2200 | [KNL] |
2189 | Ignore sysrq setting - this boot parameter will | 2201 | Ignore sysrq setting - this boot parameter will |
2190 | neutralize any effect of /proc/sys/kernel/sysrq. | 2202 | neutralize any effect of /proc/sys/kernel/sysrq. |
2191 | Useful for debugging. | 2203 | Useful for debugging. |
2192 | 2204 | ||
2193 | t128= [HW,SCSI] | 2205 | t128= [HW,SCSI] |
2194 | See header of drivers/scsi/t128.c. | 2206 | See header of drivers/scsi/t128.c. |
2195 | 2207 | ||
2196 | tdfx= [HW,DRM] | 2208 | tdfx= [HW,DRM] |
2197 | 2209 | ||
2198 | test_suspend= [SUSPEND] | 2210 | test_suspend= [SUSPEND] |
2199 | Specify "mem" (for Suspend-to-RAM) or "standby" (for | 2211 | Specify "mem" (for Suspend-to-RAM) or "standby" (for |
2200 | standby suspend) as the system sleep state to briefly | 2212 | standby suspend) as the system sleep state to briefly |
2201 | enter during system startup. The system is woken from | 2213 | enter during system startup. The system is woken from |
2202 | this state using a wakeup-capable RTC alarm. | 2214 | this state using a wakeup-capable RTC alarm. |
2203 | 2215 | ||
2204 | thash_entries= [KNL,NET] | 2216 | thash_entries= [KNL,NET] |
2205 | Set number of hash buckets for TCP connection | 2217 | Set number of hash buckets for TCP connection |
2206 | 2218 | ||
2207 | thermal.act= [HW,ACPI] | 2219 | thermal.act= [HW,ACPI] |
2208 | -1: disable all active trip points in all thermal zones | 2220 | -1: disable all active trip points in all thermal zones |
2209 | <degrees C>: override all lowest active trip points | 2221 | <degrees C>: override all lowest active trip points |
2210 | 2222 | ||
2211 | thermal.crt= [HW,ACPI] | 2223 | thermal.crt= [HW,ACPI] |
2212 | -1: disable all critical trip points in all thermal zones | 2224 | -1: disable all critical trip points in all thermal zones |
2213 | <degrees C>: override all critical trip points | 2225 | <degrees C>: override all critical trip points |
2214 | 2226 | ||
2215 | thermal.nocrt= [HW,ACPI] | 2227 | thermal.nocrt= [HW,ACPI] |
2216 | Set to disable actions on ACPI thermal zone | 2228 | Set to disable actions on ACPI thermal zone |
2217 | critical and hot trip points. | 2229 | critical and hot trip points. |
2218 | 2230 | ||
2219 | thermal.off= [HW,ACPI] | 2231 | thermal.off= [HW,ACPI] |
2220 | 1: disable ACPI thermal control | 2232 | 1: disable ACPI thermal control |
2221 | 2233 | ||
2222 | thermal.psv= [HW,ACPI] | 2234 | thermal.psv= [HW,ACPI] |
2223 | -1: disable all passive trip points | 2235 | -1: disable all passive trip points |
2224 | <degrees C>: override all passive trip points to this value | 2236 | <degrees C>: override all passive trip points to this value |
2225 | 2237 | ||
2226 | thermal.tzp= [HW,ACPI] | 2238 | thermal.tzp= [HW,ACPI] |
2227 | Specify global default ACPI thermal zone polling rate | 2239 | Specify global default ACPI thermal zone polling rate |
2228 | <deci-seconds>: poll all this frequency | 2240 | <deci-seconds>: poll all this frequency |
2229 | 0: no polling (default) | 2241 | 0: no polling (default) |
2230 | 2242 | ||
2231 | tmscsim= [HW,SCSI] | 2243 | tmscsim= [HW,SCSI] |
2232 | See comment before function dc390_setup() in | 2244 | See comment before function dc390_setup() in |
2233 | drivers/scsi/tmscsim.c. | 2245 | drivers/scsi/tmscsim.c. |
2234 | 2246 | ||
2235 | tp720= [HW,PS2] | 2247 | tp720= [HW,PS2] |
2236 | 2248 | ||
2237 | trix= [HW,OSS] MediaTrix AudioTrix Pro | 2249 | trix= [HW,OSS] MediaTrix AudioTrix Pro |
2238 | Format: | 2250 | Format: |
2239 | <io>,<irq>,<dma>,<dma2>,<sb_io>,<sb_irq>,<sb_dma>,<mpu_io>,<mpu_irq> | 2251 | <io>,<irq>,<dma>,<dma2>,<sb_io>,<sb_irq>,<sb_dma>,<mpu_io>,<mpu_irq> |
2240 | 2252 | ||
2241 | turbografx.map[2|3]= [HW,JOY] | 2253 | turbografx.map[2|3]= [HW,JOY] |
2242 | TurboGraFX parallel port interface | 2254 | TurboGraFX parallel port interface |
2243 | Format: | 2255 | Format: |
2244 | <port#>,<js1>,<js2>,<js3>,<js4>,<js5>,<js6>,<js7> | 2256 | <port#>,<js1>,<js2>,<js3>,<js4>,<js5>,<js6>,<js7> |
2245 | See also Documentation/input/joystick-parport.txt | 2257 | See also Documentation/input/joystick-parport.txt |
2246 | 2258 | ||
2247 | u14-34f= [HW,SCSI] UltraStor 14F/34F SCSI host adapter | 2259 | u14-34f= [HW,SCSI] UltraStor 14F/34F SCSI host adapter |
2248 | See header of drivers/scsi/u14-34f.c. | 2260 | See header of drivers/scsi/u14-34f.c. |
2249 | 2261 | ||
2250 | uart401= [HW,OSS] | 2262 | uart401= [HW,OSS] |
2251 | Format: <io>,<irq> | 2263 | Format: <io>,<irq> |
2252 | 2264 | ||
2253 | uart6850= [HW,OSS] | 2265 | uart6850= [HW,OSS] |
2254 | Format: <io>,<irq> | 2266 | Format: <io>,<irq> |
2255 | 2267 | ||
2256 | uhci-hcd.ignore_oc= | 2268 | uhci-hcd.ignore_oc= |
2257 | [USB] Ignore overcurrent events (default N). | 2269 | [USB] Ignore overcurrent events (default N). |
2258 | Some badly-designed motherboards generate lots of | 2270 | Some badly-designed motherboards generate lots of |
2259 | bogus events, for ports that aren't wired to | 2271 | bogus events, for ports that aren't wired to |
2260 | anything. Set this parameter to avoid log spamming. | 2272 | anything. Set this parameter to avoid log spamming. |
2261 | Note that genuine overcurrent events won't be | 2273 | Note that genuine overcurrent events won't be |
2262 | reported either. | 2274 | reported either. |
2263 | 2275 | ||
2264 | unknown_nmi_panic | 2276 | unknown_nmi_panic |
2265 | [X86-32,X86-64] | 2277 | [X86-32,X86-64] |
2266 | Set unknown_nmi_panic=1 early on boot. | 2278 | Set unknown_nmi_panic=1 early on boot. |
2267 | 2279 | ||
2268 | usbcore.autosuspend= | 2280 | usbcore.autosuspend= |
2269 | [USB] The autosuspend time delay (in seconds) used | 2281 | [USB] The autosuspend time delay (in seconds) used |
2270 | for newly-detected USB devices (default 2). This | 2282 | for newly-detected USB devices (default 2). This |
2271 | is the time required before an idle device will be | 2283 | is the time required before an idle device will be |
2272 | autosuspended. Devices for which the delay is set | 2284 | autosuspended. Devices for which the delay is set |
2273 | to a negative value won't be autosuspended at all. | 2285 | to a negative value won't be autosuspended at all. |
2274 | 2286 | ||
2275 | usbcore.usbfs_snoop= | 2287 | usbcore.usbfs_snoop= |
2276 | [USB] Set to log all usbfs traffic (default 0 = off). | 2288 | [USB] Set to log all usbfs traffic (default 0 = off). |
2277 | 2289 | ||
2278 | usbcore.blinkenlights= | 2290 | usbcore.blinkenlights= |
2279 | [USB] Set to cycle leds on hubs (default 0 = off). | 2291 | [USB] Set to cycle leds on hubs (default 0 = off). |
2280 | 2292 | ||
2281 | usbcore.old_scheme_first= | 2293 | usbcore.old_scheme_first= |
2282 | [USB] Start with the old device initialization | 2294 | [USB] Start with the old device initialization |
2283 | scheme (default 0 = off). | 2295 | scheme (default 0 = off). |
2284 | 2296 | ||
2285 | usbcore.use_both_schemes= | 2297 | usbcore.use_both_schemes= |
2286 | [USB] Try the other device initialization scheme | 2298 | [USB] Try the other device initialization scheme |
2287 | if the first one fails (default 1 = enabled). | 2299 | if the first one fails (default 1 = enabled). |
2288 | 2300 | ||
2289 | usbcore.initial_descriptor_timeout= | 2301 | usbcore.initial_descriptor_timeout= |
2290 | [USB] Specifies timeout for the initial 64-byte | 2302 | [USB] Specifies timeout for the initial 64-byte |
2291 | USB_REQ_GET_DESCRIPTOR request in milliseconds | 2303 | USB_REQ_GET_DESCRIPTOR request in milliseconds |
2292 | (default 5000 = 5.0 seconds). | 2304 | (default 5000 = 5.0 seconds). |
2293 | 2305 | ||
2294 | usbhid.mousepoll= | 2306 | usbhid.mousepoll= |
2295 | [USBHID] The interval which mice are to be polled at. | 2307 | [USBHID] The interval which mice are to be polled at. |
2296 | 2308 | ||
2297 | add_efi_memmap [EFI; x86-32,X86-64] Include EFI memory map in | 2309 | add_efi_memmap [EFI; x86-32,X86-64] Include EFI memory map in |
2298 | kernel's map of available physical RAM. | 2310 | kernel's map of available physical RAM. |
2299 | 2311 | ||
2300 | vdso= [X86-32,SH,x86-64] | 2312 | vdso= [X86-32,SH,x86-64] |
2301 | vdso=2: enable compat VDSO (default with COMPAT_VDSO) | 2313 | vdso=2: enable compat VDSO (default with COMPAT_VDSO) |
2302 | vdso=1: enable VDSO (default) | 2314 | vdso=1: enable VDSO (default) |
2303 | vdso=0: disable VDSO mapping | 2315 | vdso=0: disable VDSO mapping |
2304 | 2316 | ||
2305 | vdso32= [X86-32,X86-64] | 2317 | vdso32= [X86-32,X86-64] |
2306 | vdso32=2: enable compat VDSO (default with COMPAT_VDSO) | 2318 | vdso32=2: enable compat VDSO (default with COMPAT_VDSO) |
2307 | vdso32=1: enable 32-bit VDSO (default) | 2319 | vdso32=1: enable 32-bit VDSO (default) |
2308 | vdso32=0: disable 32-bit VDSO mapping | 2320 | vdso32=0: disable 32-bit VDSO mapping |
2309 | 2321 | ||
2310 | vector= [IA-64,SMP] | 2322 | vector= [IA-64,SMP] |
2311 | vector=percpu: enable percpu vector domain | 2323 | vector=percpu: enable percpu vector domain |
2312 | 2324 | ||
2313 | video= [FB] Frame buffer configuration | 2325 | video= [FB] Frame buffer configuration |
2314 | See Documentation/fb/modedb.txt. | 2326 | See Documentation/fb/modedb.txt. |
2315 | 2327 | ||
2316 | vga= [BOOT,X86-32] Select a particular video mode | 2328 | vga= [BOOT,X86-32] Select a particular video mode |
2317 | See Documentation/x86/i386/boot.txt and | 2329 | See Documentation/x86/i386/boot.txt and |
2318 | Documentation/svga.txt. | 2330 | Documentation/svga.txt. |
2319 | Use vga=ask for menu. | 2331 | Use vga=ask for menu. |
2320 | This is actually a boot loader parameter; the value is | 2332 | This is actually a boot loader parameter; the value is |
2321 | passed to the kernel using a special protocol. | 2333 | passed to the kernel using a special protocol. |
2322 | 2334 | ||
2323 | vmalloc=nn[KMG] [KNL,BOOT] Forces the vmalloc area to have an exact | 2335 | vmalloc=nn[KMG] [KNL,BOOT] Forces the vmalloc area to have an exact |
2324 | size of <nn>. This can be used to increase the | 2336 | size of <nn>. This can be used to increase the |
2325 | minimum size (128MB on x86). It can also be used to | 2337 | minimum size (128MB on x86). It can also be used to |
2326 | decrease the size and leave more room for directly | 2338 | decrease the size and leave more room for directly |
2327 | mapped kernel RAM. | 2339 | mapped kernel RAM. |
2328 | 2340 | ||
2329 | vmhalt= [KNL,S390] Perform z/VM CP command after system halt. | 2341 | vmhalt= [KNL,S390] Perform z/VM CP command after system halt. |
2330 | Format: <command> | 2342 | Format: <command> |
2331 | 2343 | ||
2332 | vmpanic= [KNL,S390] Perform z/VM CP command after kernel panic. | 2344 | vmpanic= [KNL,S390] Perform z/VM CP command after kernel panic. |
2333 | Format: <command> | 2345 | Format: <command> |
2334 | 2346 | ||
2335 | vmpoff= [KNL,S390] Perform z/VM CP command after power off. | 2347 | vmpoff= [KNL,S390] Perform z/VM CP command after power off. |
2336 | Format: <command> | 2348 | Format: <command> |
2337 | 2349 | ||
2338 | waveartist= [HW,OSS] | 2350 | waveartist= [HW,OSS] |
2339 | Format: <io>,<irq>,<dma>,<dma2> | 2351 | Format: <io>,<irq>,<dma>,<dma2> |
2340 | 2352 | ||
2341 | wd33c93= [HW,SCSI] | 2353 | wd33c93= [HW,SCSI] |
2342 | See header of drivers/scsi/wd33c93.c. | 2354 | See header of drivers/scsi/wd33c93.c. |
2343 | 2355 | ||
2344 | wd7000= [HW,SCSI] | 2356 | wd7000= [HW,SCSI] |
2345 | See header of drivers/scsi/wd7000.c. | 2357 | See header of drivers/scsi/wd7000.c. |
2346 | 2358 | ||
2347 | wdt= [WDT] Watchdog | 2359 | wdt= [WDT] Watchdog |
2348 | See Documentation/watchdog/wdt.txt. | 2360 | See Documentation/watchdog/wdt.txt. |
2349 | 2361 | ||
2350 | xd= [HW,XT] Original XT pre-IDE (RLL encoded) disks. | 2362 | xd= [HW,XT] Original XT pre-IDE (RLL encoded) disks. |
2351 | xd_geo= See header of drivers/block/xd.c. | 2363 | xd_geo= See header of drivers/block/xd.c. |
2352 | 2364 | ||
2353 | xirc2ps_cs= [NET,PCMCIA] | 2365 | xirc2ps_cs= [NET,PCMCIA] |
2354 | Format: | 2366 | Format: |
2355 | <irq>,<irq_mask>,<io>,<full_duplex>,<do_sound>,<lockup_hack>[,<irq2>[,<irq3>[,<irq4>]]] | 2367 | <irq>,<irq_mask>,<io>,<full_duplex>,<do_sound>,<lockup_hack>[,<irq2>[,<irq3>[,<irq4>]]] |
2356 | 2368 | ||
2357 | norandmaps Don't use address space randomization | 2369 | norandmaps Don't use address space randomization |
2358 | Equivalent to echo 0 > /proc/sys/kernel/randomize_va_space | 2370 | Equivalent to echo 0 > /proc/sys/kernel/randomize_va_space |
2359 | 2371 | ||
2360 | ______________________________________________________________________ | 2372 | ______________________________________________________________________ |
2361 | 2373 | ||
2362 | TODO: | 2374 | TODO: |
2363 | 2375 | ||
2364 | Add documentation for ALSA options. | 2376 | Add documentation for ALSA options. |
2365 | Add more DRM drivers. | 2377 | Add more DRM drivers. |
2366 | 2378 |
drivers/acpi/Makefile
1 | # | 1 | # |
2 | # Makefile for the Linux ACPI interpreter | 2 | # Makefile for the Linux ACPI interpreter |
3 | # | 3 | # |
4 | 4 | ||
5 | export ACPI_CFLAGS | 5 | export ACPI_CFLAGS |
6 | 6 | ||
7 | ACPI_CFLAGS := -Os | 7 | ACPI_CFLAGS := -Os |
8 | 8 | ||
9 | ifdef CONFIG_ACPI_DEBUG | 9 | ifdef CONFIG_ACPI_DEBUG |
10 | ACPI_CFLAGS += -DACPI_DEBUG_OUTPUT | 10 | ACPI_CFLAGS += -DACPI_DEBUG_OUTPUT |
11 | endif | 11 | endif |
12 | 12 | ||
13 | EXTRA_CFLAGS += $(ACPI_CFLAGS) | 13 | EXTRA_CFLAGS += $(ACPI_CFLAGS) |
14 | 14 | ||
15 | # | 15 | # |
16 | # ACPI Boot-Time Table Parsing | 16 | # ACPI Boot-Time Table Parsing |
17 | # | 17 | # |
18 | obj-y += tables.o | 18 | obj-y += tables.o |
19 | obj-$(CONFIG_X86) += blacklist.o | 19 | obj-$(CONFIG_X86) += blacklist.o |
20 | 20 | ||
21 | # | 21 | # |
22 | # ACPI Core Subsystem (Interpreter) | 22 | # ACPI Core Subsystem (Interpreter) |
23 | # | 23 | # |
24 | obj-y += osl.o utils.o reboot.o\ | 24 | obj-y += osl.o utils.o reboot.o\ |
25 | dispatcher/ events/ executer/ hardware/ \ | 25 | dispatcher/ events/ executer/ hardware/ \ |
26 | namespace/ parser/ resources/ tables/ \ | 26 | namespace/ parser/ resources/ tables/ \ |
27 | utilities/ | 27 | utilities/ |
28 | 28 | ||
29 | # | 29 | # |
30 | # ACPI Bus and Device Drivers | 30 | # ACPI Bus and Device Drivers |
31 | # | 31 | # |
32 | processor-objs += processor_core.o processor_throttling.o \ | 32 | processor-objs += processor_core.o processor_throttling.o \ |
33 | processor_idle.o processor_thermal.o | 33 | processor_idle.o processor_thermal.o |
34 | ifdef CONFIG_CPU_FREQ | 34 | ifdef CONFIG_CPU_FREQ |
35 | processor-objs += processor_perflib.o | 35 | processor-objs += processor_perflib.o |
36 | endif | 36 | endif |
37 | 37 | ||
38 | obj-y += sleep/ | 38 | obj-y += sleep/ |
39 | obj-y += bus.o glue.o | 39 | obj-y += bus.o glue.o |
40 | obj-y += scan.o | 40 | obj-y += scan.o |
41 | # Keep EC driver first. Initialization of others depend on it. | 41 | # Keep EC driver first. Initialization of others depend on it. |
42 | obj-y += ec.o | 42 | obj-y += ec.o |
43 | obj-$(CONFIG_ACPI_AC) += ac.o | 43 | obj-$(CONFIG_ACPI_AC) += ac.o |
44 | obj-$(CONFIG_ACPI_BATTERY) += battery.o | 44 | obj-$(CONFIG_ACPI_BATTERY) += battery.o |
45 | obj-$(CONFIG_ACPI_BUTTON) += button.o | 45 | obj-$(CONFIG_ACPI_BUTTON) += button.o |
46 | obj-$(CONFIG_ACPI_FAN) += fan.o | 46 | obj-$(CONFIG_ACPI_FAN) += fan.o |
47 | obj-$(CONFIG_ACPI_DOCK) += dock.o | 47 | obj-$(CONFIG_ACPI_DOCK) += dock.o |
48 | obj-$(CONFIG_ACPI_VIDEO) += video.o | 48 | obj-$(CONFIG_ACPI_VIDEO) += video.o |
49 | ifdef CONFIG_ACPI_VIDEO | ||
50 | obj-y += video_detect.o | ||
51 | endif | ||
52 | |||
49 | obj-y += pci_root.o pci_link.o pci_irq.o pci_bind.o | 53 | obj-y += pci_root.o pci_link.o pci_irq.o pci_bind.o |
50 | obj-$(CONFIG_ACPI_PCI_SLOT) += pci_slot.o | 54 | obj-$(CONFIG_ACPI_PCI_SLOT) += pci_slot.o |
51 | obj-$(CONFIG_ACPI_PROCESSOR) += processor.o | 55 | obj-$(CONFIG_ACPI_PROCESSOR) += processor.o |
52 | obj-$(CONFIG_ACPI_CONTAINER) += container.o | 56 | obj-$(CONFIG_ACPI_CONTAINER) += container.o |
53 | obj-$(CONFIG_ACPI_THERMAL) += thermal.o | 57 | obj-$(CONFIG_ACPI_THERMAL) += thermal.o |
54 | obj-y += power.o | 58 | obj-y += power.o |
55 | obj-$(CONFIG_ACPI_SYSTEM) += system.o event.o | 59 | obj-$(CONFIG_ACPI_SYSTEM) += system.o event.o |
56 | obj-$(CONFIG_ACPI_DEBUG) += debug.o | 60 | obj-$(CONFIG_ACPI_DEBUG) += debug.o |
57 | obj-$(CONFIG_ACPI_NUMA) += numa.o | 61 | obj-$(CONFIG_ACPI_NUMA) += numa.o |
58 | obj-$(CONFIG_ACPI_WMI) += wmi.o | 62 | obj-$(CONFIG_ACPI_WMI) += wmi.o |
59 | obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o | 63 | obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o |
60 | obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o | 64 | obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o |
61 | obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o | 65 | obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o |
62 | obj-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o | 66 | obj-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o |
63 | obj-$(CONFIG_ACPI_SBS) += sbshc.o | 67 | obj-$(CONFIG_ACPI_SBS) += sbshc.o |
64 | obj-$(CONFIG_ACPI_SBS) += sbs.o | 68 | obj-$(CONFIG_ACPI_SBS) += sbs.o |
65 | 69 |
drivers/acpi/glue.c
1 | /* | 1 | /* |
2 | * Link physical devices with ACPI devices support | 2 | * Link physical devices with ACPI devices support |
3 | * | 3 | * |
4 | * Copyright (c) 2005 David Shaohua Li <shaohua.li@intel.com> | 4 | * Copyright (c) 2005 David Shaohua Li <shaohua.li@intel.com> |
5 | * Copyright (c) 2005 Intel Corp. | 5 | * Copyright (c) 2005 Intel Corp. |
6 | * | 6 | * |
7 | * This file is released under the GPLv2. | 7 | * This file is released under the GPLv2. |
8 | */ | 8 | */ |
9 | #include <linux/init.h> | 9 | #include <linux/init.h> |
10 | #include <linux/list.h> | 10 | #include <linux/list.h> |
11 | #include <linux/device.h> | 11 | #include <linux/device.h> |
12 | #include <linux/rwsem.h> | 12 | #include <linux/rwsem.h> |
13 | #include <linux/acpi.h> | 13 | #include <linux/acpi.h> |
14 | 14 | ||
15 | #define ACPI_GLUE_DEBUG 0 | 15 | #define ACPI_GLUE_DEBUG 0 |
16 | #if ACPI_GLUE_DEBUG | 16 | #if ACPI_GLUE_DEBUG |
17 | #define DBG(x...) printk(PREFIX x) | 17 | #define DBG(x...) printk(PREFIX x) |
18 | #else | 18 | #else |
19 | #define DBG(x...) do { } while(0) | 19 | #define DBG(x...) do { } while(0) |
20 | #endif | 20 | #endif |
21 | static LIST_HEAD(bus_type_list); | 21 | static LIST_HEAD(bus_type_list); |
22 | static DECLARE_RWSEM(bus_type_sem); | 22 | static DECLARE_RWSEM(bus_type_sem); |
23 | 23 | ||
24 | int register_acpi_bus_type(struct acpi_bus_type *type) | 24 | int register_acpi_bus_type(struct acpi_bus_type *type) |
25 | { | 25 | { |
26 | if (acpi_disabled) | 26 | if (acpi_disabled) |
27 | return -ENODEV; | 27 | return -ENODEV; |
28 | if (type && type->bus && type->find_device) { | 28 | if (type && type->bus && type->find_device) { |
29 | down_write(&bus_type_sem); | 29 | down_write(&bus_type_sem); |
30 | list_add_tail(&type->list, &bus_type_list); | 30 | list_add_tail(&type->list, &bus_type_list); |
31 | up_write(&bus_type_sem); | 31 | up_write(&bus_type_sem); |
32 | printk(KERN_INFO PREFIX "bus type %s registered\n", | 32 | printk(KERN_INFO PREFIX "bus type %s registered\n", |
33 | type->bus->name); | 33 | type->bus->name); |
34 | return 0; | 34 | return 0; |
35 | } | 35 | } |
36 | return -ENODEV; | 36 | return -ENODEV; |
37 | } | 37 | } |
38 | 38 | ||
39 | int unregister_acpi_bus_type(struct acpi_bus_type *type) | 39 | int unregister_acpi_bus_type(struct acpi_bus_type *type) |
40 | { | 40 | { |
41 | if (acpi_disabled) | 41 | if (acpi_disabled) |
42 | return 0; | 42 | return 0; |
43 | if (type) { | 43 | if (type) { |
44 | down_write(&bus_type_sem); | 44 | down_write(&bus_type_sem); |
45 | list_del_init(&type->list); | 45 | list_del_init(&type->list); |
46 | up_write(&bus_type_sem); | 46 | up_write(&bus_type_sem); |
47 | printk(KERN_INFO PREFIX "ACPI bus type %s unregistered\n", | 47 | printk(KERN_INFO PREFIX "ACPI bus type %s unregistered\n", |
48 | type->bus->name); | 48 | type->bus->name); |
49 | return 0; | 49 | return 0; |
50 | } | 50 | } |
51 | return -ENODEV; | 51 | return -ENODEV; |
52 | } | 52 | } |
53 | 53 | ||
54 | static struct acpi_bus_type *acpi_get_bus_type(struct bus_type *type) | 54 | static struct acpi_bus_type *acpi_get_bus_type(struct bus_type *type) |
55 | { | 55 | { |
56 | struct acpi_bus_type *tmp, *ret = NULL; | 56 | struct acpi_bus_type *tmp, *ret = NULL; |
57 | 57 | ||
58 | down_read(&bus_type_sem); | 58 | down_read(&bus_type_sem); |
59 | list_for_each_entry(tmp, &bus_type_list, list) { | 59 | list_for_each_entry(tmp, &bus_type_list, list) { |
60 | if (tmp->bus == type) { | 60 | if (tmp->bus == type) { |
61 | ret = tmp; | 61 | ret = tmp; |
62 | break; | 62 | break; |
63 | } | 63 | } |
64 | } | 64 | } |
65 | up_read(&bus_type_sem); | 65 | up_read(&bus_type_sem); |
66 | return ret; | 66 | return ret; |
67 | } | 67 | } |
68 | 68 | ||
69 | static int acpi_find_bridge_device(struct device *dev, acpi_handle * handle) | 69 | static int acpi_find_bridge_device(struct device *dev, acpi_handle * handle) |
70 | { | 70 | { |
71 | struct acpi_bus_type *tmp; | 71 | struct acpi_bus_type *tmp; |
72 | int ret = -ENODEV; | 72 | int ret = -ENODEV; |
73 | 73 | ||
74 | down_read(&bus_type_sem); | 74 | down_read(&bus_type_sem); |
75 | list_for_each_entry(tmp, &bus_type_list, list) { | 75 | list_for_each_entry(tmp, &bus_type_list, list) { |
76 | if (tmp->find_bridge && !tmp->find_bridge(dev, handle)) { | 76 | if (tmp->find_bridge && !tmp->find_bridge(dev, handle)) { |
77 | ret = 0; | 77 | ret = 0; |
78 | break; | 78 | break; |
79 | } | 79 | } |
80 | } | 80 | } |
81 | up_read(&bus_type_sem); | 81 | up_read(&bus_type_sem); |
82 | return ret; | 82 | return ret; |
83 | } | 83 | } |
84 | 84 | ||
85 | /* Get device's handler per its address under its parent */ | 85 | /* Get device's handler per its address under its parent */ |
86 | struct acpi_find_child { | 86 | struct acpi_find_child { |
87 | acpi_handle handle; | 87 | acpi_handle handle; |
88 | acpi_integer address; | 88 | acpi_integer address; |
89 | }; | 89 | }; |
90 | 90 | ||
91 | static acpi_status | 91 | static acpi_status |
92 | do_acpi_find_child(acpi_handle handle, u32 lvl, void *context, void **rv) | 92 | do_acpi_find_child(acpi_handle handle, u32 lvl, void *context, void **rv) |
93 | { | 93 | { |
94 | acpi_status status; | 94 | acpi_status status; |
95 | struct acpi_device_info *info; | 95 | struct acpi_device_info *info; |
96 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | 96 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
97 | struct acpi_find_child *find = context; | 97 | struct acpi_find_child *find = context; |
98 | 98 | ||
99 | status = acpi_get_object_info(handle, &buffer); | 99 | status = acpi_get_object_info(handle, &buffer); |
100 | if (ACPI_SUCCESS(status)) { | 100 | if (ACPI_SUCCESS(status)) { |
101 | info = buffer.pointer; | 101 | info = buffer.pointer; |
102 | if (info->address == find->address) | 102 | if (info->address == find->address) |
103 | find->handle = handle; | 103 | find->handle = handle; |
104 | kfree(buffer.pointer); | 104 | kfree(buffer.pointer); |
105 | } | 105 | } |
106 | return AE_OK; | 106 | return AE_OK; |
107 | } | 107 | } |
108 | 108 | ||
109 | acpi_handle acpi_get_child(acpi_handle parent, acpi_integer address) | 109 | acpi_handle acpi_get_child(acpi_handle parent, acpi_integer address) |
110 | { | 110 | { |
111 | struct acpi_find_child find = { NULL, address }; | 111 | struct acpi_find_child find = { NULL, address }; |
112 | 112 | ||
113 | if (!parent) | 113 | if (!parent) |
114 | return NULL; | 114 | return NULL; |
115 | acpi_walk_namespace(ACPI_TYPE_DEVICE, parent, | 115 | acpi_walk_namespace(ACPI_TYPE_DEVICE, parent, |
116 | 1, do_acpi_find_child, &find, NULL); | 116 | 1, do_acpi_find_child, &find, NULL); |
117 | return find.handle; | 117 | return find.handle; |
118 | } | 118 | } |
119 | 119 | ||
120 | EXPORT_SYMBOL(acpi_get_child); | 120 | EXPORT_SYMBOL(acpi_get_child); |
121 | 121 | ||
122 | /* Link ACPI devices with physical devices */ | 122 | /* Link ACPI devices with physical devices */ |
123 | static void acpi_glue_data_handler(acpi_handle handle, | 123 | static void acpi_glue_data_handler(acpi_handle handle, |
124 | u32 function, void *context) | 124 | u32 function, void *context) |
125 | { | 125 | { |
126 | /* we provide an empty handler */ | 126 | /* we provide an empty handler */ |
127 | } | 127 | } |
128 | 128 | ||
129 | /* Note: a success call will increase reference count by one */ | 129 | /* Note: a success call will increase reference count by one */ |
130 | struct device *acpi_get_physical_device(acpi_handle handle) | 130 | struct device *acpi_get_physical_device(acpi_handle handle) |
131 | { | 131 | { |
132 | acpi_status status; | 132 | acpi_status status; |
133 | struct device *dev; | 133 | struct device *dev; |
134 | 134 | ||
135 | status = acpi_get_data(handle, acpi_glue_data_handler, (void **)&dev); | 135 | status = acpi_get_data(handle, acpi_glue_data_handler, (void **)&dev); |
136 | if (ACPI_SUCCESS(status)) | 136 | if (ACPI_SUCCESS(status)) |
137 | return get_device(dev); | 137 | return get_device(dev); |
138 | return NULL; | 138 | return NULL; |
139 | } | 139 | } |
140 | 140 | ||
141 | EXPORT_SYMBOL(acpi_get_physical_device); | 141 | EXPORT_SYMBOL(acpi_get_physical_device); |
142 | 142 | ||
143 | /* ToDo: When a PCI bridge is found, return the PCI device behind the bridge | ||
144 | * This should work in general, but did not on a Lenovo T61 for the | ||
145 | * graphics card. But this must be fixed when the PCI device is | ||
146 | * bound and the kernel device struct is attached to the acpi device | ||
147 | * Note: A success call will increase reference count by one | ||
148 | * Do call put_device(dev) on the returned device then | ||
149 | */ | ||
150 | struct device *acpi_get_physical_pci_device(acpi_handle handle) | ||
151 | { | ||
152 | struct device *dev; | ||
153 | long long device_id; | ||
154 | acpi_status status; | ||
155 | |||
156 | status = | ||
157 | acpi_evaluate_integer(handle, "_ADR", NULL, &device_id); | ||
158 | |||
159 | if (ACPI_FAILURE(status)) | ||
160 | return NULL; | ||
161 | |||
162 | /* We need to attempt to determine whether the _ADR refers to a | ||
163 | PCI device or not. There's no terribly good way to do this, | ||
164 | so the best we can hope for is to assume that there'll never | ||
165 | be a device in the host bridge */ | ||
166 | if (device_id >= 0x10000) { | ||
167 | /* It looks like a PCI device. Does it exist? */ | ||
168 | dev = acpi_get_physical_device(handle); | ||
169 | } else { | ||
170 | /* It doesn't look like a PCI device. Does its parent | ||
171 | exist? */ | ||
172 | acpi_handle phandle; | ||
173 | if (acpi_get_parent(handle, &phandle)) | ||
174 | return NULL; | ||
175 | dev = acpi_get_physical_device(phandle); | ||
176 | } | ||
177 | if (!dev) | ||
178 | return NULL; | ||
179 | return dev; | ||
180 | } | ||
181 | EXPORT_SYMBOL(acpi_get_physical_pci_device); | ||
182 | |||
143 | static int acpi_bind_one(struct device *dev, acpi_handle handle) | 183 | static int acpi_bind_one(struct device *dev, acpi_handle handle) |
144 | { | 184 | { |
145 | struct acpi_device *acpi_dev; | 185 | struct acpi_device *acpi_dev; |
146 | acpi_status status; | 186 | acpi_status status; |
147 | 187 | ||
148 | if (dev->archdata.acpi_handle) { | 188 | if (dev->archdata.acpi_handle) { |
149 | dev_warn(dev, "Drivers changed 'acpi_handle'\n"); | 189 | dev_warn(dev, "Drivers changed 'acpi_handle'\n"); |
150 | return -EINVAL; | 190 | return -EINVAL; |
151 | } | 191 | } |
152 | get_device(dev); | 192 | get_device(dev); |
153 | status = acpi_attach_data(handle, acpi_glue_data_handler, dev); | 193 | status = acpi_attach_data(handle, acpi_glue_data_handler, dev); |
154 | if (ACPI_FAILURE(status)) { | 194 | if (ACPI_FAILURE(status)) { |
155 | put_device(dev); | 195 | put_device(dev); |
156 | return -EINVAL; | 196 | return -EINVAL; |
157 | } | 197 | } |
158 | dev->archdata.acpi_handle = handle; | 198 | dev->archdata.acpi_handle = handle; |
159 | 199 | ||
160 | status = acpi_bus_get_device(handle, &acpi_dev); | 200 | status = acpi_bus_get_device(handle, &acpi_dev); |
161 | if (!ACPI_FAILURE(status)) { | 201 | if (!ACPI_FAILURE(status)) { |
162 | int ret; | 202 | int ret; |
163 | 203 | ||
164 | ret = sysfs_create_link(&dev->kobj, &acpi_dev->dev.kobj, | 204 | ret = sysfs_create_link(&dev->kobj, &acpi_dev->dev.kobj, |
165 | "firmware_node"); | 205 | "firmware_node"); |
166 | ret = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj, | 206 | ret = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj, |
167 | "physical_node"); | 207 | "physical_node"); |
168 | if (acpi_dev->wakeup.flags.valid) { | 208 | if (acpi_dev->wakeup.flags.valid) { |
169 | device_set_wakeup_capable(dev, true); | 209 | device_set_wakeup_capable(dev, true); |
170 | device_set_wakeup_enable(dev, | 210 | device_set_wakeup_enable(dev, |
171 | acpi_dev->wakeup.state.enabled); | 211 | acpi_dev->wakeup.state.enabled); |
172 | } | 212 | } |
173 | } | 213 | } |
174 | 214 | ||
175 | return 0; | 215 | return 0; |
176 | } | 216 | } |
177 | 217 | ||
178 | static int acpi_unbind_one(struct device *dev) | 218 | static int acpi_unbind_one(struct device *dev) |
179 | { | 219 | { |
180 | if (!dev->archdata.acpi_handle) | 220 | if (!dev->archdata.acpi_handle) |
181 | return 0; | 221 | return 0; |
182 | if (dev == acpi_get_physical_device(dev->archdata.acpi_handle)) { | 222 | if (dev == acpi_get_physical_device(dev->archdata.acpi_handle)) { |
183 | struct acpi_device *acpi_dev; | 223 | struct acpi_device *acpi_dev; |
184 | 224 | ||
185 | /* acpi_get_physical_device increase refcnt by one */ | 225 | /* acpi_get_physical_device increase refcnt by one */ |
186 | put_device(dev); | 226 | put_device(dev); |
187 | 227 | ||
188 | if (!acpi_bus_get_device(dev->archdata.acpi_handle, | 228 | if (!acpi_bus_get_device(dev->archdata.acpi_handle, |
189 | &acpi_dev)) { | 229 | &acpi_dev)) { |
190 | sysfs_remove_link(&dev->kobj, "firmware_node"); | 230 | sysfs_remove_link(&dev->kobj, "firmware_node"); |
191 | sysfs_remove_link(&acpi_dev->dev.kobj, "physical_node"); | 231 | sysfs_remove_link(&acpi_dev->dev.kobj, "physical_node"); |
192 | } | 232 | } |
193 | 233 | ||
194 | acpi_detach_data(dev->archdata.acpi_handle, | 234 | acpi_detach_data(dev->archdata.acpi_handle, |
195 | acpi_glue_data_handler); | 235 | acpi_glue_data_handler); |
196 | dev->archdata.acpi_handle = NULL; | 236 | dev->archdata.acpi_handle = NULL; |
197 | /* acpi_bind_one increase refcnt by one */ | 237 | /* acpi_bind_one increase refcnt by one */ |
198 | put_device(dev); | 238 | put_device(dev); |
199 | } else { | 239 | } else { |
200 | dev_err(dev, "Oops, 'acpi_handle' corrupt\n"); | 240 | dev_err(dev, "Oops, 'acpi_handle' corrupt\n"); |
201 | } | 241 | } |
202 | return 0; | 242 | return 0; |
203 | } | 243 | } |
204 | 244 | ||
205 | static int acpi_platform_notify(struct device *dev) | 245 | static int acpi_platform_notify(struct device *dev) |
206 | { | 246 | { |
207 | struct acpi_bus_type *type; | 247 | struct acpi_bus_type *type; |
208 | acpi_handle handle; | 248 | acpi_handle handle; |
209 | int ret = -EINVAL; | 249 | int ret = -EINVAL; |
210 | 250 | ||
211 | if (!dev->bus || !dev->parent) { | 251 | if (!dev->bus || !dev->parent) { |
212 | /* bridge devices genernally haven't bus or parent */ | 252 | /* bridge devices genernally haven't bus or parent */ |
213 | ret = acpi_find_bridge_device(dev, &handle); | 253 | ret = acpi_find_bridge_device(dev, &handle); |
214 | goto end; | 254 | goto end; |
215 | } | 255 | } |
216 | type = acpi_get_bus_type(dev->bus); | 256 | type = acpi_get_bus_type(dev->bus); |
217 | if (!type) { | 257 | if (!type) { |
218 | DBG("No ACPI bus support for %s\n", dev->bus_id); | 258 | DBG("No ACPI bus support for %s\n", dev->bus_id); |
219 | ret = -EINVAL; | 259 | ret = -EINVAL; |
220 | goto end; | 260 | goto end; |
221 | } | 261 | } |
222 | if ((ret = type->find_device(dev, &handle)) != 0) | 262 | if ((ret = type->find_device(dev, &handle)) != 0) |
223 | DBG("Can't get handler for %s\n", dev->bus_id); | 263 | DBG("Can't get handler for %s\n", dev->bus_id); |
224 | end: | 264 | end: |
225 | if (!ret) | 265 | if (!ret) |
226 | acpi_bind_one(dev, handle); | 266 | acpi_bind_one(dev, handle); |
227 | 267 | ||
228 | #if ACPI_GLUE_DEBUG | 268 | #if ACPI_GLUE_DEBUG |
229 | if (!ret) { | 269 | if (!ret) { |
230 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | 270 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
231 | 271 | ||
232 | acpi_get_name(dev->archdata.acpi_handle, | 272 | acpi_get_name(dev->archdata.acpi_handle, |
233 | ACPI_FULL_PATHNAME, &buffer); | 273 | ACPI_FULL_PATHNAME, &buffer); |
234 | DBG("Device %s -> %s\n", dev->bus_id, (char *)buffer.pointer); | 274 | DBG("Device %s -> %s\n", dev->bus_id, (char *)buffer.pointer); |
235 | kfree(buffer.pointer); | 275 | kfree(buffer.pointer); |
236 | } else | 276 | } else |
237 | DBG("Device %s -> No ACPI support\n", dev->bus_id); | 277 | DBG("Device %s -> No ACPI support\n", dev->bus_id); |
238 | #endif | 278 | #endif |
239 | 279 | ||
240 | return ret; | 280 | return ret; |
241 | } | 281 | } |
242 | 282 | ||
243 | static int acpi_platform_notify_remove(struct device *dev) | 283 | static int acpi_platform_notify_remove(struct device *dev) |
244 | { | 284 | { |
245 | acpi_unbind_one(dev); | 285 | acpi_unbind_one(dev); |
246 | return 0; | 286 | return 0; |
247 | } | 287 | } |
248 | 288 | ||
249 | static int __init init_acpi_device_notify(void) | 289 | static int __init init_acpi_device_notify(void) |
250 | { | 290 | { |
251 | if (acpi_disabled) | 291 | if (acpi_disabled) |
252 | return 0; | 292 | return 0; |
253 | if (platform_notify || platform_notify_remove) { | 293 | if (platform_notify || platform_notify_remove) { |
254 | printk(KERN_ERR PREFIX "Can't use platform_notify\n"); | 294 | printk(KERN_ERR PREFIX "Can't use platform_notify\n"); |
255 | return 0; | 295 | return 0; |
256 | } | 296 | } |
257 | platform_notify = acpi_platform_notify; | 297 | platform_notify = acpi_platform_notify; |
258 | platform_notify_remove = acpi_platform_notify_remove; | 298 | platform_notify_remove = acpi_platform_notify_remove; |
259 | return 0; | 299 | return 0; |
260 | } | 300 | } |
261 | 301 | ||
262 | arch_initcall(init_acpi_device_notify); | 302 | arch_initcall(init_acpi_device_notify); |
263 | 303 |
drivers/acpi/scan.c
1 | /* | 1 | /* |
2 | * scan.c - support for transforming the ACPI namespace into individual objects | 2 | * scan.c - support for transforming the ACPI namespace into individual objects |
3 | */ | 3 | */ |
4 | 4 | ||
5 | #include <linux/module.h> | 5 | #include <linux/module.h> |
6 | #include <linux/init.h> | 6 | #include <linux/init.h> |
7 | #include <linux/kernel.h> | 7 | #include <linux/kernel.h> |
8 | #include <linux/acpi.h> | 8 | #include <linux/acpi.h> |
9 | #include <linux/signal.h> | 9 | #include <linux/signal.h> |
10 | #include <linux/kthread.h> | 10 | #include <linux/kthread.h> |
11 | 11 | ||
12 | #include <acpi/acpi_drivers.h> | 12 | #include <acpi/acpi_drivers.h> |
13 | #include <acpi/acinterp.h> /* for acpi_ex_eisa_id_to_string() */ | 13 | #include <acpi/acinterp.h> /* for acpi_ex_eisa_id_to_string() */ |
14 | 14 | ||
15 | #define _COMPONENT ACPI_BUS_COMPONENT | 15 | #define _COMPONENT ACPI_BUS_COMPONENT |
16 | ACPI_MODULE_NAME("scan"); | 16 | ACPI_MODULE_NAME("scan"); |
17 | #define STRUCT_TO_INT(s) (*((int*)&s)) | 17 | #define STRUCT_TO_INT(s) (*((int*)&s)) |
18 | extern struct acpi_device *acpi_root; | 18 | extern struct acpi_device *acpi_root; |
19 | 19 | ||
20 | #define ACPI_BUS_CLASS "system_bus" | 20 | #define ACPI_BUS_CLASS "system_bus" |
21 | #define ACPI_BUS_HID "LNXSYBUS" | 21 | #define ACPI_BUS_HID "LNXSYBUS" |
22 | #define ACPI_BUS_DEVICE_NAME "System Bus" | 22 | #define ACPI_BUS_DEVICE_NAME "System Bus" |
23 | 23 | ||
24 | static LIST_HEAD(acpi_device_list); | 24 | static LIST_HEAD(acpi_device_list); |
25 | static LIST_HEAD(acpi_bus_id_list); | 25 | static LIST_HEAD(acpi_bus_id_list); |
26 | DEFINE_SPINLOCK(acpi_device_lock); | 26 | DEFINE_SPINLOCK(acpi_device_lock); |
27 | LIST_HEAD(acpi_wakeup_device_list); | 27 | LIST_HEAD(acpi_wakeup_device_list); |
28 | 28 | ||
29 | struct acpi_device_bus_id{ | 29 | struct acpi_device_bus_id{ |
30 | char bus_id[15]; | 30 | char bus_id[15]; |
31 | unsigned int instance_no; | 31 | unsigned int instance_no; |
32 | struct list_head node; | 32 | struct list_head node; |
33 | }; | 33 | }; |
34 | 34 | ||
35 | /* | 35 | /* |
36 | * Creates hid/cid(s) string needed for modalias and uevent | 36 | * Creates hid/cid(s) string needed for modalias and uevent |
37 | * e.g. on a device with hid:IBM0001 and cid:ACPI0001 you get: | 37 | * e.g. on a device with hid:IBM0001 and cid:ACPI0001 you get: |
38 | * char *modalias: "acpi:IBM0001:ACPI0001" | 38 | * char *modalias: "acpi:IBM0001:ACPI0001" |
39 | */ | 39 | */ |
40 | static int create_modalias(struct acpi_device *acpi_dev, char *modalias, | 40 | static int create_modalias(struct acpi_device *acpi_dev, char *modalias, |
41 | int size) | 41 | int size) |
42 | { | 42 | { |
43 | int len; | 43 | int len; |
44 | int count; | 44 | int count; |
45 | 45 | ||
46 | if (!acpi_dev->flags.hardware_id && !acpi_dev->flags.compatible_ids) | 46 | if (!acpi_dev->flags.hardware_id && !acpi_dev->flags.compatible_ids) |
47 | return -ENODEV; | 47 | return -ENODEV; |
48 | 48 | ||
49 | len = snprintf(modalias, size, "acpi:"); | 49 | len = snprintf(modalias, size, "acpi:"); |
50 | size -= len; | 50 | size -= len; |
51 | 51 | ||
52 | if (acpi_dev->flags.hardware_id) { | 52 | if (acpi_dev->flags.hardware_id) { |
53 | count = snprintf(&modalias[len], size, "%s:", | 53 | count = snprintf(&modalias[len], size, "%s:", |
54 | acpi_dev->pnp.hardware_id); | 54 | acpi_dev->pnp.hardware_id); |
55 | if (count < 0 || count >= size) | 55 | if (count < 0 || count >= size) |
56 | return -EINVAL; | 56 | return -EINVAL; |
57 | len += count; | 57 | len += count; |
58 | size -= count; | 58 | size -= count; |
59 | } | 59 | } |
60 | 60 | ||
61 | if (acpi_dev->flags.compatible_ids) { | 61 | if (acpi_dev->flags.compatible_ids) { |
62 | struct acpi_compatible_id_list *cid_list; | 62 | struct acpi_compatible_id_list *cid_list; |
63 | int i; | 63 | int i; |
64 | 64 | ||
65 | cid_list = acpi_dev->pnp.cid_list; | 65 | cid_list = acpi_dev->pnp.cid_list; |
66 | for (i = 0; i < cid_list->count; i++) { | 66 | for (i = 0; i < cid_list->count; i++) { |
67 | count = snprintf(&modalias[len], size, "%s:", | 67 | count = snprintf(&modalias[len], size, "%s:", |
68 | cid_list->id[i].value); | 68 | cid_list->id[i].value); |
69 | if (count < 0 || count >= size) { | 69 | if (count < 0 || count >= size) { |
70 | printk(KERN_ERR PREFIX "%s cid[%i] exceeds event buffer size", | 70 | printk(KERN_ERR PREFIX "%s cid[%i] exceeds event buffer size", |
71 | acpi_dev->pnp.device_name, i); | 71 | acpi_dev->pnp.device_name, i); |
72 | break; | 72 | break; |
73 | } | 73 | } |
74 | len += count; | 74 | len += count; |
75 | size -= count; | 75 | size -= count; |
76 | } | 76 | } |
77 | } | 77 | } |
78 | 78 | ||
79 | modalias[len] = '\0'; | 79 | modalias[len] = '\0'; |
80 | return len; | 80 | return len; |
81 | } | 81 | } |
82 | 82 | ||
83 | static ssize_t | 83 | static ssize_t |
84 | acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, char *buf) { | 84 | acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, char *buf) { |
85 | struct acpi_device *acpi_dev = to_acpi_device(dev); | 85 | struct acpi_device *acpi_dev = to_acpi_device(dev); |
86 | int len; | 86 | int len; |
87 | 87 | ||
88 | /* Device has no HID and no CID or string is >1024 */ | 88 | /* Device has no HID and no CID or string is >1024 */ |
89 | len = create_modalias(acpi_dev, buf, 1024); | 89 | len = create_modalias(acpi_dev, buf, 1024); |
90 | if (len <= 0) | 90 | if (len <= 0) |
91 | return 0; | 91 | return 0; |
92 | buf[len++] = '\n'; | 92 | buf[len++] = '\n'; |
93 | return len; | 93 | return len; |
94 | } | 94 | } |
95 | static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL); | 95 | static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL); |
96 | 96 | ||
97 | static int acpi_bus_hot_remove_device(void *context) | 97 | static int acpi_bus_hot_remove_device(void *context) |
98 | { | 98 | { |
99 | struct acpi_device *device; | 99 | struct acpi_device *device; |
100 | acpi_handle handle = context; | 100 | acpi_handle handle = context; |
101 | struct acpi_object_list arg_list; | 101 | struct acpi_object_list arg_list; |
102 | union acpi_object arg; | 102 | union acpi_object arg; |
103 | acpi_status status = AE_OK; | 103 | acpi_status status = AE_OK; |
104 | 104 | ||
105 | if (acpi_bus_get_device(handle, &device)) | 105 | if (acpi_bus_get_device(handle, &device)) |
106 | return 0; | 106 | return 0; |
107 | 107 | ||
108 | if (!device) | 108 | if (!device) |
109 | return 0; | 109 | return 0; |
110 | 110 | ||
111 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | 111 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
112 | "Hot-removing device %s...\n", dev_name(&device->dev))); | 112 | "Hot-removing device %s...\n", dev_name(&device->dev))); |
113 | 113 | ||
114 | if (acpi_bus_trim(device, 1)) { | 114 | if (acpi_bus_trim(device, 1)) { |
115 | printk(KERN_ERR PREFIX | 115 | printk(KERN_ERR PREFIX |
116 | "Removing device failed\n"); | 116 | "Removing device failed\n"); |
117 | return -1; | 117 | return -1; |
118 | } | 118 | } |
119 | 119 | ||
120 | /* power off device */ | 120 | /* power off device */ |
121 | status = acpi_evaluate_object(handle, "_PS3", NULL, NULL); | 121 | status = acpi_evaluate_object(handle, "_PS3", NULL, NULL); |
122 | if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) | 122 | if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) |
123 | printk(KERN_WARNING PREFIX | 123 | printk(KERN_WARNING PREFIX |
124 | "Power-off device failed\n"); | 124 | "Power-off device failed\n"); |
125 | 125 | ||
126 | if (device->flags.lockable) { | 126 | if (device->flags.lockable) { |
127 | arg_list.count = 1; | 127 | arg_list.count = 1; |
128 | arg_list.pointer = &arg; | 128 | arg_list.pointer = &arg; |
129 | arg.type = ACPI_TYPE_INTEGER; | 129 | arg.type = ACPI_TYPE_INTEGER; |
130 | arg.integer.value = 0; | 130 | arg.integer.value = 0; |
131 | acpi_evaluate_object(handle, "_LCK", &arg_list, NULL); | 131 | acpi_evaluate_object(handle, "_LCK", &arg_list, NULL); |
132 | } | 132 | } |
133 | 133 | ||
134 | arg_list.count = 1; | 134 | arg_list.count = 1; |
135 | arg_list.pointer = &arg; | 135 | arg_list.pointer = &arg; |
136 | arg.type = ACPI_TYPE_INTEGER; | 136 | arg.type = ACPI_TYPE_INTEGER; |
137 | arg.integer.value = 1; | 137 | arg.integer.value = 1; |
138 | 138 | ||
139 | /* | 139 | /* |
140 | * TBD: _EJD support. | 140 | * TBD: _EJD support. |
141 | */ | 141 | */ |
142 | status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL); | 142 | status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL); |
143 | if (ACPI_FAILURE(status)) | 143 | if (ACPI_FAILURE(status)) |
144 | return -ENODEV; | 144 | return -ENODEV; |
145 | 145 | ||
146 | return 0; | 146 | return 0; |
147 | } | 147 | } |
148 | 148 | ||
149 | static ssize_t | 149 | static ssize_t |
150 | acpi_eject_store(struct device *d, struct device_attribute *attr, | 150 | acpi_eject_store(struct device *d, struct device_attribute *attr, |
151 | const char *buf, size_t count) | 151 | const char *buf, size_t count) |
152 | { | 152 | { |
153 | int ret = count; | 153 | int ret = count; |
154 | acpi_status status; | 154 | acpi_status status; |
155 | acpi_object_type type = 0; | 155 | acpi_object_type type = 0; |
156 | struct acpi_device *acpi_device = to_acpi_device(d); | 156 | struct acpi_device *acpi_device = to_acpi_device(d); |
157 | struct task_struct *task; | 157 | struct task_struct *task; |
158 | 158 | ||
159 | if ((!count) || (buf[0] != '1')) { | 159 | if ((!count) || (buf[0] != '1')) { |
160 | return -EINVAL; | 160 | return -EINVAL; |
161 | } | 161 | } |
162 | #ifndef FORCE_EJECT | 162 | #ifndef FORCE_EJECT |
163 | if (acpi_device->driver == NULL) { | 163 | if (acpi_device->driver == NULL) { |
164 | ret = -ENODEV; | 164 | ret = -ENODEV; |
165 | goto err; | 165 | goto err; |
166 | } | 166 | } |
167 | #endif | 167 | #endif |
168 | status = acpi_get_type(acpi_device->handle, &type); | 168 | status = acpi_get_type(acpi_device->handle, &type); |
169 | if (ACPI_FAILURE(status) || (!acpi_device->flags.ejectable)) { | 169 | if (ACPI_FAILURE(status) || (!acpi_device->flags.ejectable)) { |
170 | ret = -ENODEV; | 170 | ret = -ENODEV; |
171 | goto err; | 171 | goto err; |
172 | } | 172 | } |
173 | 173 | ||
174 | /* remove the device in another thread to fix the deadlock issue */ | 174 | /* remove the device in another thread to fix the deadlock issue */ |
175 | task = kthread_run(acpi_bus_hot_remove_device, | 175 | task = kthread_run(acpi_bus_hot_remove_device, |
176 | acpi_device->handle, "acpi_hot_remove_device"); | 176 | acpi_device->handle, "acpi_hot_remove_device"); |
177 | if (IS_ERR(task)) | 177 | if (IS_ERR(task)) |
178 | ret = PTR_ERR(task); | 178 | ret = PTR_ERR(task); |
179 | err: | 179 | err: |
180 | return ret; | 180 | return ret; |
181 | } | 181 | } |
182 | 182 | ||
183 | static DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store); | 183 | static DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store); |
184 | 184 | ||
185 | static ssize_t | 185 | static ssize_t |
186 | acpi_device_hid_show(struct device *dev, struct device_attribute *attr, char *buf) { | 186 | acpi_device_hid_show(struct device *dev, struct device_attribute *attr, char *buf) { |
187 | struct acpi_device *acpi_dev = to_acpi_device(dev); | 187 | struct acpi_device *acpi_dev = to_acpi_device(dev); |
188 | 188 | ||
189 | return sprintf(buf, "%s\n", acpi_dev->pnp.hardware_id); | 189 | return sprintf(buf, "%s\n", acpi_dev->pnp.hardware_id); |
190 | } | 190 | } |
191 | static DEVICE_ATTR(hid, 0444, acpi_device_hid_show, NULL); | 191 | static DEVICE_ATTR(hid, 0444, acpi_device_hid_show, NULL); |
192 | 192 | ||
193 | static ssize_t | 193 | static ssize_t |
194 | acpi_device_path_show(struct device *dev, struct device_attribute *attr, char *buf) { | 194 | acpi_device_path_show(struct device *dev, struct device_attribute *attr, char *buf) { |
195 | struct acpi_device *acpi_dev = to_acpi_device(dev); | 195 | struct acpi_device *acpi_dev = to_acpi_device(dev); |
196 | struct acpi_buffer path = {ACPI_ALLOCATE_BUFFER, NULL}; | 196 | struct acpi_buffer path = {ACPI_ALLOCATE_BUFFER, NULL}; |
197 | int result; | 197 | int result; |
198 | 198 | ||
199 | result = acpi_get_name(acpi_dev->handle, ACPI_FULL_PATHNAME, &path); | 199 | result = acpi_get_name(acpi_dev->handle, ACPI_FULL_PATHNAME, &path); |
200 | if(result) | 200 | if(result) |
201 | goto end; | 201 | goto end; |
202 | 202 | ||
203 | result = sprintf(buf, "%s\n", (char*)path.pointer); | 203 | result = sprintf(buf, "%s\n", (char*)path.pointer); |
204 | kfree(path.pointer); | 204 | kfree(path.pointer); |
205 | end: | 205 | end: |
206 | return result; | 206 | return result; |
207 | } | 207 | } |
208 | static DEVICE_ATTR(path, 0444, acpi_device_path_show, NULL); | 208 | static DEVICE_ATTR(path, 0444, acpi_device_path_show, NULL); |
209 | 209 | ||
210 | static int acpi_device_setup_files(struct acpi_device *dev) | 210 | static int acpi_device_setup_files(struct acpi_device *dev) |
211 | { | 211 | { |
212 | acpi_status status; | 212 | acpi_status status; |
213 | acpi_handle temp; | 213 | acpi_handle temp; |
214 | int result = 0; | 214 | int result = 0; |
215 | 215 | ||
216 | /* | 216 | /* |
217 | * Devices gotten from FADT don't have a "path" attribute | 217 | * Devices gotten from FADT don't have a "path" attribute |
218 | */ | 218 | */ |
219 | if(dev->handle) { | 219 | if(dev->handle) { |
220 | result = device_create_file(&dev->dev, &dev_attr_path); | 220 | result = device_create_file(&dev->dev, &dev_attr_path); |
221 | if(result) | 221 | if(result) |
222 | goto end; | 222 | goto end; |
223 | } | 223 | } |
224 | 224 | ||
225 | if(dev->flags.hardware_id) { | 225 | if(dev->flags.hardware_id) { |
226 | result = device_create_file(&dev->dev, &dev_attr_hid); | 226 | result = device_create_file(&dev->dev, &dev_attr_hid); |
227 | if(result) | 227 | if(result) |
228 | goto end; | 228 | goto end; |
229 | } | 229 | } |
230 | 230 | ||
231 | if (dev->flags.hardware_id || dev->flags.compatible_ids){ | 231 | if (dev->flags.hardware_id || dev->flags.compatible_ids){ |
232 | result = device_create_file(&dev->dev, &dev_attr_modalias); | 232 | result = device_create_file(&dev->dev, &dev_attr_modalias); |
233 | if(result) | 233 | if(result) |
234 | goto end; | 234 | goto end; |
235 | } | 235 | } |
236 | 236 | ||
237 | /* | 237 | /* |
238 | * If device has _EJ0, 'eject' file is created that is used to trigger | 238 | * If device has _EJ0, 'eject' file is created that is used to trigger |
239 | * hot-removal function from userland. | 239 | * hot-removal function from userland. |
240 | */ | 240 | */ |
241 | status = acpi_get_handle(dev->handle, "_EJ0", &temp); | 241 | status = acpi_get_handle(dev->handle, "_EJ0", &temp); |
242 | if (ACPI_SUCCESS(status)) | 242 | if (ACPI_SUCCESS(status)) |
243 | result = device_create_file(&dev->dev, &dev_attr_eject); | 243 | result = device_create_file(&dev->dev, &dev_attr_eject); |
244 | end: | 244 | end: |
245 | return result; | 245 | return result; |
246 | } | 246 | } |
247 | 247 | ||
248 | static void acpi_device_remove_files(struct acpi_device *dev) | 248 | static void acpi_device_remove_files(struct acpi_device *dev) |
249 | { | 249 | { |
250 | acpi_status status; | 250 | acpi_status status; |
251 | acpi_handle temp; | 251 | acpi_handle temp; |
252 | 252 | ||
253 | /* | 253 | /* |
254 | * If device has _EJ0, 'eject' file is created that is used to trigger | 254 | * If device has _EJ0, 'eject' file is created that is used to trigger |
255 | * hot-removal function from userland. | 255 | * hot-removal function from userland. |
256 | */ | 256 | */ |
257 | status = acpi_get_handle(dev->handle, "_EJ0", &temp); | 257 | status = acpi_get_handle(dev->handle, "_EJ0", &temp); |
258 | if (ACPI_SUCCESS(status)) | 258 | if (ACPI_SUCCESS(status)) |
259 | device_remove_file(&dev->dev, &dev_attr_eject); | 259 | device_remove_file(&dev->dev, &dev_attr_eject); |
260 | 260 | ||
261 | if (dev->flags.hardware_id || dev->flags.compatible_ids) | 261 | if (dev->flags.hardware_id || dev->flags.compatible_ids) |
262 | device_remove_file(&dev->dev, &dev_attr_modalias); | 262 | device_remove_file(&dev->dev, &dev_attr_modalias); |
263 | 263 | ||
264 | if(dev->flags.hardware_id) | 264 | if(dev->flags.hardware_id) |
265 | device_remove_file(&dev->dev, &dev_attr_hid); | 265 | device_remove_file(&dev->dev, &dev_attr_hid); |
266 | if(dev->handle) | 266 | if(dev->handle) |
267 | device_remove_file(&dev->dev, &dev_attr_path); | 267 | device_remove_file(&dev->dev, &dev_attr_path); |
268 | } | 268 | } |
269 | /* -------------------------------------------------------------------------- | 269 | /* -------------------------------------------------------------------------- |
270 | ACPI Bus operations | 270 | ACPI Bus operations |
271 | -------------------------------------------------------------------------- */ | 271 | -------------------------------------------------------------------------- */ |
272 | 272 | ||
273 | int acpi_match_device_ids(struct acpi_device *device, | 273 | int acpi_match_device_ids(struct acpi_device *device, |
274 | const struct acpi_device_id *ids) | 274 | const struct acpi_device_id *ids) |
275 | { | 275 | { |
276 | const struct acpi_device_id *id; | 276 | const struct acpi_device_id *id; |
277 | 277 | ||
278 | /* | 278 | /* |
279 | * If the device is not present, it is unnecessary to load device | 279 | * If the device is not present, it is unnecessary to load device |
280 | * driver for it. | 280 | * driver for it. |
281 | */ | 281 | */ |
282 | if (!device->status.present) | 282 | if (!device->status.present) |
283 | return -ENODEV; | 283 | return -ENODEV; |
284 | 284 | ||
285 | if (device->flags.hardware_id) { | 285 | if (device->flags.hardware_id) { |
286 | for (id = ids; id->id[0]; id++) { | 286 | for (id = ids; id->id[0]; id++) { |
287 | if (!strcmp((char*)id->id, device->pnp.hardware_id)) | 287 | if (!strcmp((char*)id->id, device->pnp.hardware_id)) |
288 | return 0; | 288 | return 0; |
289 | } | 289 | } |
290 | } | 290 | } |
291 | 291 | ||
292 | if (device->flags.compatible_ids) { | 292 | if (device->flags.compatible_ids) { |
293 | struct acpi_compatible_id_list *cid_list = device->pnp.cid_list; | 293 | struct acpi_compatible_id_list *cid_list = device->pnp.cid_list; |
294 | int i; | 294 | int i; |
295 | 295 | ||
296 | for (id = ids; id->id[0]; id++) { | 296 | for (id = ids; id->id[0]; id++) { |
297 | /* compare multiple _CID entries against driver ids */ | 297 | /* compare multiple _CID entries against driver ids */ |
298 | for (i = 0; i < cid_list->count; i++) { | 298 | for (i = 0; i < cid_list->count; i++) { |
299 | if (!strcmp((char*)id->id, | 299 | if (!strcmp((char*)id->id, |
300 | cid_list->id[i].value)) | 300 | cid_list->id[i].value)) |
301 | return 0; | 301 | return 0; |
302 | } | 302 | } |
303 | } | 303 | } |
304 | } | 304 | } |
305 | 305 | ||
306 | return -ENOENT; | 306 | return -ENOENT; |
307 | } | 307 | } |
308 | EXPORT_SYMBOL(acpi_match_device_ids); | 308 | EXPORT_SYMBOL(acpi_match_device_ids); |
309 | 309 | ||
310 | static void acpi_device_release(struct device *dev) | 310 | static void acpi_device_release(struct device *dev) |
311 | { | 311 | { |
312 | struct acpi_device *acpi_dev = to_acpi_device(dev); | 312 | struct acpi_device *acpi_dev = to_acpi_device(dev); |
313 | 313 | ||
314 | kfree(acpi_dev->pnp.cid_list); | 314 | kfree(acpi_dev->pnp.cid_list); |
315 | kfree(acpi_dev); | 315 | kfree(acpi_dev); |
316 | } | 316 | } |
317 | 317 | ||
318 | static int acpi_device_suspend(struct device *dev, pm_message_t state) | 318 | static int acpi_device_suspend(struct device *dev, pm_message_t state) |
319 | { | 319 | { |
320 | struct acpi_device *acpi_dev = to_acpi_device(dev); | 320 | struct acpi_device *acpi_dev = to_acpi_device(dev); |
321 | struct acpi_driver *acpi_drv = acpi_dev->driver; | 321 | struct acpi_driver *acpi_drv = acpi_dev->driver; |
322 | 322 | ||
323 | if (acpi_drv && acpi_drv->ops.suspend) | 323 | if (acpi_drv && acpi_drv->ops.suspend) |
324 | return acpi_drv->ops.suspend(acpi_dev, state); | 324 | return acpi_drv->ops.suspend(acpi_dev, state); |
325 | return 0; | 325 | return 0; |
326 | } | 326 | } |
327 | 327 | ||
328 | static int acpi_device_resume(struct device *dev) | 328 | static int acpi_device_resume(struct device *dev) |
329 | { | 329 | { |
330 | struct acpi_device *acpi_dev = to_acpi_device(dev); | 330 | struct acpi_device *acpi_dev = to_acpi_device(dev); |
331 | struct acpi_driver *acpi_drv = acpi_dev->driver; | 331 | struct acpi_driver *acpi_drv = acpi_dev->driver; |
332 | 332 | ||
333 | if (acpi_drv && acpi_drv->ops.resume) | 333 | if (acpi_drv && acpi_drv->ops.resume) |
334 | return acpi_drv->ops.resume(acpi_dev); | 334 | return acpi_drv->ops.resume(acpi_dev); |
335 | return 0; | 335 | return 0; |
336 | } | 336 | } |
337 | 337 | ||
338 | static int acpi_bus_match(struct device *dev, struct device_driver *drv) | 338 | static int acpi_bus_match(struct device *dev, struct device_driver *drv) |
339 | { | 339 | { |
340 | struct acpi_device *acpi_dev = to_acpi_device(dev); | 340 | struct acpi_device *acpi_dev = to_acpi_device(dev); |
341 | struct acpi_driver *acpi_drv = to_acpi_driver(drv); | 341 | struct acpi_driver *acpi_drv = to_acpi_driver(drv); |
342 | 342 | ||
343 | return !acpi_match_device_ids(acpi_dev, acpi_drv->ids); | 343 | return !acpi_match_device_ids(acpi_dev, acpi_drv->ids); |
344 | } | 344 | } |
345 | 345 | ||
346 | static int acpi_device_uevent(struct device *dev, struct kobj_uevent_env *env) | 346 | static int acpi_device_uevent(struct device *dev, struct kobj_uevent_env *env) |
347 | { | 347 | { |
348 | struct acpi_device *acpi_dev = to_acpi_device(dev); | 348 | struct acpi_device *acpi_dev = to_acpi_device(dev); |
349 | int len; | 349 | int len; |
350 | 350 | ||
351 | if (add_uevent_var(env, "MODALIAS=")) | 351 | if (add_uevent_var(env, "MODALIAS=")) |
352 | return -ENOMEM; | 352 | return -ENOMEM; |
353 | len = create_modalias(acpi_dev, &env->buf[env->buflen - 1], | 353 | len = create_modalias(acpi_dev, &env->buf[env->buflen - 1], |
354 | sizeof(env->buf) - env->buflen); | 354 | sizeof(env->buf) - env->buflen); |
355 | if (len >= (sizeof(env->buf) - env->buflen)) | 355 | if (len >= (sizeof(env->buf) - env->buflen)) |
356 | return -ENOMEM; | 356 | return -ENOMEM; |
357 | env->buflen += len; | 357 | env->buflen += len; |
358 | return 0; | 358 | return 0; |
359 | } | 359 | } |
360 | 360 | ||
361 | static int acpi_bus_driver_init(struct acpi_device *, struct acpi_driver *); | 361 | static int acpi_bus_driver_init(struct acpi_device *, struct acpi_driver *); |
362 | static int acpi_start_single_object(struct acpi_device *); | 362 | static int acpi_start_single_object(struct acpi_device *); |
363 | static int acpi_device_probe(struct device * dev) | 363 | static int acpi_device_probe(struct device * dev) |
364 | { | 364 | { |
365 | struct acpi_device *acpi_dev = to_acpi_device(dev); | 365 | struct acpi_device *acpi_dev = to_acpi_device(dev); |
366 | struct acpi_driver *acpi_drv = to_acpi_driver(dev->driver); | 366 | struct acpi_driver *acpi_drv = to_acpi_driver(dev->driver); |
367 | int ret; | 367 | int ret; |
368 | 368 | ||
369 | ret = acpi_bus_driver_init(acpi_dev, acpi_drv); | 369 | ret = acpi_bus_driver_init(acpi_dev, acpi_drv); |
370 | if (!ret) { | 370 | if (!ret) { |
371 | if (acpi_dev->bus_ops.acpi_op_start) | 371 | if (acpi_dev->bus_ops.acpi_op_start) |
372 | acpi_start_single_object(acpi_dev); | 372 | acpi_start_single_object(acpi_dev); |
373 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | 373 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
374 | "Found driver [%s] for device [%s]\n", | 374 | "Found driver [%s] for device [%s]\n", |
375 | acpi_drv->name, acpi_dev->pnp.bus_id)); | 375 | acpi_drv->name, acpi_dev->pnp.bus_id)); |
376 | get_device(dev); | 376 | get_device(dev); |
377 | } | 377 | } |
378 | return ret; | 378 | return ret; |
379 | } | 379 | } |
380 | 380 | ||
381 | static int acpi_device_remove(struct device * dev) | 381 | static int acpi_device_remove(struct device * dev) |
382 | { | 382 | { |
383 | struct acpi_device *acpi_dev = to_acpi_device(dev); | 383 | struct acpi_device *acpi_dev = to_acpi_device(dev); |
384 | struct acpi_driver *acpi_drv = acpi_dev->driver; | 384 | struct acpi_driver *acpi_drv = acpi_dev->driver; |
385 | 385 | ||
386 | if (acpi_drv) { | 386 | if (acpi_drv) { |
387 | if (acpi_drv->ops.stop) | 387 | if (acpi_drv->ops.stop) |
388 | acpi_drv->ops.stop(acpi_dev, acpi_dev->removal_type); | 388 | acpi_drv->ops.stop(acpi_dev, acpi_dev->removal_type); |
389 | if (acpi_drv->ops.remove) | 389 | if (acpi_drv->ops.remove) |
390 | acpi_drv->ops.remove(acpi_dev, acpi_dev->removal_type); | 390 | acpi_drv->ops.remove(acpi_dev, acpi_dev->removal_type); |
391 | } | 391 | } |
392 | acpi_dev->driver = NULL; | 392 | acpi_dev->driver = NULL; |
393 | acpi_dev->driver_data = NULL; | 393 | acpi_dev->driver_data = NULL; |
394 | 394 | ||
395 | put_device(dev); | 395 | put_device(dev); |
396 | return 0; | 396 | return 0; |
397 | } | 397 | } |
398 | 398 | ||
399 | static void acpi_device_shutdown(struct device *dev) | 399 | static void acpi_device_shutdown(struct device *dev) |
400 | { | 400 | { |
401 | struct acpi_device *acpi_dev = to_acpi_device(dev); | 401 | struct acpi_device *acpi_dev = to_acpi_device(dev); |
402 | struct acpi_driver *acpi_drv = acpi_dev->driver; | 402 | struct acpi_driver *acpi_drv = acpi_dev->driver; |
403 | 403 | ||
404 | if (acpi_drv && acpi_drv->ops.shutdown) | 404 | if (acpi_drv && acpi_drv->ops.shutdown) |
405 | acpi_drv->ops.shutdown(acpi_dev); | 405 | acpi_drv->ops.shutdown(acpi_dev); |
406 | 406 | ||
407 | return ; | 407 | return ; |
408 | } | 408 | } |
409 | 409 | ||
410 | struct bus_type acpi_bus_type = { | 410 | struct bus_type acpi_bus_type = { |
411 | .name = "acpi", | 411 | .name = "acpi", |
412 | .suspend = acpi_device_suspend, | 412 | .suspend = acpi_device_suspend, |
413 | .resume = acpi_device_resume, | 413 | .resume = acpi_device_resume, |
414 | .shutdown = acpi_device_shutdown, | 414 | .shutdown = acpi_device_shutdown, |
415 | .match = acpi_bus_match, | 415 | .match = acpi_bus_match, |
416 | .probe = acpi_device_probe, | 416 | .probe = acpi_device_probe, |
417 | .remove = acpi_device_remove, | 417 | .remove = acpi_device_remove, |
418 | .uevent = acpi_device_uevent, | 418 | .uevent = acpi_device_uevent, |
419 | }; | 419 | }; |
420 | 420 | ||
421 | static int acpi_device_register(struct acpi_device *device, | 421 | static int acpi_device_register(struct acpi_device *device, |
422 | struct acpi_device *parent) | 422 | struct acpi_device *parent) |
423 | { | 423 | { |
424 | int result; | 424 | int result; |
425 | struct acpi_device_bus_id *acpi_device_bus_id, *new_bus_id; | 425 | struct acpi_device_bus_id *acpi_device_bus_id, *new_bus_id; |
426 | int found = 0; | 426 | int found = 0; |
427 | /* | 427 | /* |
428 | * Linkage | 428 | * Linkage |
429 | * ------- | 429 | * ------- |
430 | * Link this device to its parent and siblings. | 430 | * Link this device to its parent and siblings. |
431 | */ | 431 | */ |
432 | INIT_LIST_HEAD(&device->children); | 432 | INIT_LIST_HEAD(&device->children); |
433 | INIT_LIST_HEAD(&device->node); | 433 | INIT_LIST_HEAD(&device->node); |
434 | INIT_LIST_HEAD(&device->g_list); | 434 | INIT_LIST_HEAD(&device->g_list); |
435 | INIT_LIST_HEAD(&device->wakeup_list); | 435 | INIT_LIST_HEAD(&device->wakeup_list); |
436 | 436 | ||
437 | new_bus_id = kzalloc(sizeof(struct acpi_device_bus_id), GFP_KERNEL); | 437 | new_bus_id = kzalloc(sizeof(struct acpi_device_bus_id), GFP_KERNEL); |
438 | if (!new_bus_id) { | 438 | if (!new_bus_id) { |
439 | printk(KERN_ERR PREFIX "Memory allocation error\n"); | 439 | printk(KERN_ERR PREFIX "Memory allocation error\n"); |
440 | return -ENOMEM; | 440 | return -ENOMEM; |
441 | } | 441 | } |
442 | 442 | ||
443 | spin_lock(&acpi_device_lock); | 443 | spin_lock(&acpi_device_lock); |
444 | /* | 444 | /* |
445 | * Find suitable bus_id and instance number in acpi_bus_id_list | 445 | * Find suitable bus_id and instance number in acpi_bus_id_list |
446 | * If failed, create one and link it into acpi_bus_id_list | 446 | * If failed, create one and link it into acpi_bus_id_list |
447 | */ | 447 | */ |
448 | list_for_each_entry(acpi_device_bus_id, &acpi_bus_id_list, node) { | 448 | list_for_each_entry(acpi_device_bus_id, &acpi_bus_id_list, node) { |
449 | if(!strcmp(acpi_device_bus_id->bus_id, device->flags.hardware_id? device->pnp.hardware_id : "device")) { | 449 | if(!strcmp(acpi_device_bus_id->bus_id, device->flags.hardware_id? device->pnp.hardware_id : "device")) { |
450 | acpi_device_bus_id->instance_no ++; | 450 | acpi_device_bus_id->instance_no ++; |
451 | found = 1; | 451 | found = 1; |
452 | kfree(new_bus_id); | 452 | kfree(new_bus_id); |
453 | break; | 453 | break; |
454 | } | 454 | } |
455 | } | 455 | } |
456 | if(!found) { | 456 | if(!found) { |
457 | acpi_device_bus_id = new_bus_id; | 457 | acpi_device_bus_id = new_bus_id; |
458 | strcpy(acpi_device_bus_id->bus_id, device->flags.hardware_id ? device->pnp.hardware_id : "device"); | 458 | strcpy(acpi_device_bus_id->bus_id, device->flags.hardware_id ? device->pnp.hardware_id : "device"); |
459 | acpi_device_bus_id->instance_no = 0; | 459 | acpi_device_bus_id->instance_no = 0; |
460 | list_add_tail(&acpi_device_bus_id->node, &acpi_bus_id_list); | 460 | list_add_tail(&acpi_device_bus_id->node, &acpi_bus_id_list); |
461 | } | 461 | } |
462 | dev_set_name(&device->dev, "%s:%02x", acpi_device_bus_id->bus_id, acpi_device_bus_id->instance_no); | 462 | dev_set_name(&device->dev, "%s:%02x", acpi_device_bus_id->bus_id, acpi_device_bus_id->instance_no); |
463 | 463 | ||
464 | if (device->parent) { | 464 | if (device->parent) { |
465 | list_add_tail(&device->node, &device->parent->children); | 465 | list_add_tail(&device->node, &device->parent->children); |
466 | list_add_tail(&device->g_list, &device->parent->g_list); | 466 | list_add_tail(&device->g_list, &device->parent->g_list); |
467 | } else | 467 | } else |
468 | list_add_tail(&device->g_list, &acpi_device_list); | 468 | list_add_tail(&device->g_list, &acpi_device_list); |
469 | if (device->wakeup.flags.valid) | 469 | if (device->wakeup.flags.valid) |
470 | list_add_tail(&device->wakeup_list, &acpi_wakeup_device_list); | 470 | list_add_tail(&device->wakeup_list, &acpi_wakeup_device_list); |
471 | spin_unlock(&acpi_device_lock); | 471 | spin_unlock(&acpi_device_lock); |
472 | 472 | ||
473 | if (device->parent) | 473 | if (device->parent) |
474 | device->dev.parent = &parent->dev; | 474 | device->dev.parent = &parent->dev; |
475 | device->dev.bus = &acpi_bus_type; | 475 | device->dev.bus = &acpi_bus_type; |
476 | device_initialize(&device->dev); | 476 | device_initialize(&device->dev); |
477 | device->dev.release = &acpi_device_release; | 477 | device->dev.release = &acpi_device_release; |
478 | result = device_add(&device->dev); | 478 | result = device_add(&device->dev); |
479 | if(result) { | 479 | if(result) { |
480 | dev_err(&device->dev, "Error adding device\n"); | 480 | dev_err(&device->dev, "Error adding device\n"); |
481 | goto end; | 481 | goto end; |
482 | } | 482 | } |
483 | 483 | ||
484 | result = acpi_device_setup_files(device); | 484 | result = acpi_device_setup_files(device); |
485 | if(result) | 485 | if(result) |
486 | printk(KERN_ERR PREFIX "Error creating sysfs interface for device %s\n", | 486 | printk(KERN_ERR PREFIX "Error creating sysfs interface for device %s\n", |
487 | dev_name(&device->dev)); | 487 | dev_name(&device->dev)); |
488 | 488 | ||
489 | device->removal_type = ACPI_BUS_REMOVAL_NORMAL; | 489 | device->removal_type = ACPI_BUS_REMOVAL_NORMAL; |
490 | return 0; | 490 | return 0; |
491 | end: | 491 | end: |
492 | spin_lock(&acpi_device_lock); | 492 | spin_lock(&acpi_device_lock); |
493 | if (device->parent) { | 493 | if (device->parent) { |
494 | list_del(&device->node); | 494 | list_del(&device->node); |
495 | list_del(&device->g_list); | 495 | list_del(&device->g_list); |
496 | } else | 496 | } else |
497 | list_del(&device->g_list); | 497 | list_del(&device->g_list); |
498 | list_del(&device->wakeup_list); | 498 | list_del(&device->wakeup_list); |
499 | spin_unlock(&acpi_device_lock); | 499 | spin_unlock(&acpi_device_lock); |
500 | return result; | 500 | return result; |
501 | } | 501 | } |
502 | 502 | ||
503 | static void acpi_device_unregister(struct acpi_device *device, int type) | 503 | static void acpi_device_unregister(struct acpi_device *device, int type) |
504 | { | 504 | { |
505 | spin_lock(&acpi_device_lock); | 505 | spin_lock(&acpi_device_lock); |
506 | if (device->parent) { | 506 | if (device->parent) { |
507 | list_del(&device->node); | 507 | list_del(&device->node); |
508 | list_del(&device->g_list); | 508 | list_del(&device->g_list); |
509 | } else | 509 | } else |
510 | list_del(&device->g_list); | 510 | list_del(&device->g_list); |
511 | 511 | ||
512 | list_del(&device->wakeup_list); | 512 | list_del(&device->wakeup_list); |
513 | spin_unlock(&acpi_device_lock); | 513 | spin_unlock(&acpi_device_lock); |
514 | 514 | ||
515 | acpi_detach_data(device->handle, acpi_bus_data_handler); | 515 | acpi_detach_data(device->handle, acpi_bus_data_handler); |
516 | 516 | ||
517 | acpi_device_remove_files(device); | 517 | acpi_device_remove_files(device); |
518 | device_unregister(&device->dev); | 518 | device_unregister(&device->dev); |
519 | } | 519 | } |
520 | 520 | ||
521 | /* -------------------------------------------------------------------------- | 521 | /* -------------------------------------------------------------------------- |
522 | Driver Management | 522 | Driver Management |
523 | -------------------------------------------------------------------------- */ | 523 | -------------------------------------------------------------------------- */ |
524 | /** | 524 | /** |
525 | * acpi_bus_driver_init - add a device to a driver | 525 | * acpi_bus_driver_init - add a device to a driver |
526 | * @device: the device to add and initialize | 526 | * @device: the device to add and initialize |
527 | * @driver: driver for the device | 527 | * @driver: driver for the device |
528 | * | 528 | * |
529 | * Used to initialize a device via its device driver. Called whenever a | 529 | * Used to initialize a device via its device driver. Called whenever a |
530 | * driver is bound to a device. Invokes the driver's add() ops. | 530 | * driver is bound to a device. Invokes the driver's add() ops. |
531 | */ | 531 | */ |
532 | static int | 532 | static int |
533 | acpi_bus_driver_init(struct acpi_device *device, struct acpi_driver *driver) | 533 | acpi_bus_driver_init(struct acpi_device *device, struct acpi_driver *driver) |
534 | { | 534 | { |
535 | int result = 0; | 535 | int result = 0; |
536 | 536 | ||
537 | 537 | ||
538 | if (!device || !driver) | 538 | if (!device || !driver) |
539 | return -EINVAL; | 539 | return -EINVAL; |
540 | 540 | ||
541 | if (!driver->ops.add) | 541 | if (!driver->ops.add) |
542 | return -ENOSYS; | 542 | return -ENOSYS; |
543 | 543 | ||
544 | result = driver->ops.add(device); | 544 | result = driver->ops.add(device); |
545 | if (result) { | 545 | if (result) { |
546 | device->driver = NULL; | 546 | device->driver = NULL; |
547 | device->driver_data = NULL; | 547 | device->driver_data = NULL; |
548 | return result; | 548 | return result; |
549 | } | 549 | } |
550 | 550 | ||
551 | device->driver = driver; | 551 | device->driver = driver; |
552 | 552 | ||
553 | /* | 553 | /* |
554 | * TBD - Configuration Management: Assign resources to device based | 554 | * TBD - Configuration Management: Assign resources to device based |
555 | * upon possible configuration and currently allocated resources. | 555 | * upon possible configuration and currently allocated resources. |
556 | */ | 556 | */ |
557 | 557 | ||
558 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | 558 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
559 | "Driver successfully bound to device\n")); | 559 | "Driver successfully bound to device\n")); |
560 | return 0; | 560 | return 0; |
561 | } | 561 | } |
562 | 562 | ||
563 | static int acpi_start_single_object(struct acpi_device *device) | 563 | static int acpi_start_single_object(struct acpi_device *device) |
564 | { | 564 | { |
565 | int result = 0; | 565 | int result = 0; |
566 | struct acpi_driver *driver; | 566 | struct acpi_driver *driver; |
567 | 567 | ||
568 | 568 | ||
569 | if (!(driver = device->driver)) | 569 | if (!(driver = device->driver)) |
570 | return 0; | 570 | return 0; |
571 | 571 | ||
572 | if (driver->ops.start) { | 572 | if (driver->ops.start) { |
573 | result = driver->ops.start(device); | 573 | result = driver->ops.start(device); |
574 | if (result && driver->ops.remove) | 574 | if (result && driver->ops.remove) |
575 | driver->ops.remove(device, ACPI_BUS_REMOVAL_NORMAL); | 575 | driver->ops.remove(device, ACPI_BUS_REMOVAL_NORMAL); |
576 | } | 576 | } |
577 | 577 | ||
578 | return result; | 578 | return result; |
579 | } | 579 | } |
580 | 580 | ||
581 | /** | 581 | /** |
582 | * acpi_bus_register_driver - register a driver with the ACPI bus | 582 | * acpi_bus_register_driver - register a driver with the ACPI bus |
583 | * @driver: driver being registered | 583 | * @driver: driver being registered |
584 | * | 584 | * |
585 | * Registers a driver with the ACPI bus. Searches the namespace for all | 585 | * Registers a driver with the ACPI bus. Searches the namespace for all |
586 | * devices that match the driver's criteria and binds. Returns zero for | 586 | * devices that match the driver's criteria and binds. Returns zero for |
587 | * success or a negative error status for failure. | 587 | * success or a negative error status for failure. |
588 | */ | 588 | */ |
589 | int acpi_bus_register_driver(struct acpi_driver *driver) | 589 | int acpi_bus_register_driver(struct acpi_driver *driver) |
590 | { | 590 | { |
591 | int ret; | 591 | int ret; |
592 | 592 | ||
593 | if (acpi_disabled) | 593 | if (acpi_disabled) |
594 | return -ENODEV; | 594 | return -ENODEV; |
595 | driver->drv.name = driver->name; | 595 | driver->drv.name = driver->name; |
596 | driver->drv.bus = &acpi_bus_type; | 596 | driver->drv.bus = &acpi_bus_type; |
597 | driver->drv.owner = driver->owner; | 597 | driver->drv.owner = driver->owner; |
598 | 598 | ||
599 | ret = driver_register(&driver->drv); | 599 | ret = driver_register(&driver->drv); |
600 | return ret; | 600 | return ret; |
601 | } | 601 | } |
602 | 602 | ||
603 | EXPORT_SYMBOL(acpi_bus_register_driver); | 603 | EXPORT_SYMBOL(acpi_bus_register_driver); |
604 | 604 | ||
605 | /** | 605 | /** |
606 | * acpi_bus_unregister_driver - unregisters a driver with the APIC bus | 606 | * acpi_bus_unregister_driver - unregisters a driver with the APIC bus |
607 | * @driver: driver to unregister | 607 | * @driver: driver to unregister |
608 | * | 608 | * |
609 | * Unregisters a driver with the ACPI bus. Searches the namespace for all | 609 | * Unregisters a driver with the ACPI bus. Searches the namespace for all |
610 | * devices that match the driver's criteria and unbinds. | 610 | * devices that match the driver's criteria and unbinds. |
611 | */ | 611 | */ |
612 | void acpi_bus_unregister_driver(struct acpi_driver *driver) | 612 | void acpi_bus_unregister_driver(struct acpi_driver *driver) |
613 | { | 613 | { |
614 | driver_unregister(&driver->drv); | 614 | driver_unregister(&driver->drv); |
615 | } | 615 | } |
616 | 616 | ||
617 | EXPORT_SYMBOL(acpi_bus_unregister_driver); | 617 | EXPORT_SYMBOL(acpi_bus_unregister_driver); |
618 | 618 | ||
619 | /* -------------------------------------------------------------------------- | 619 | /* -------------------------------------------------------------------------- |
620 | Device Enumeration | 620 | Device Enumeration |
621 | -------------------------------------------------------------------------- */ | 621 | -------------------------------------------------------------------------- */ |
622 | acpi_status | 622 | acpi_status |
623 | acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd) | 623 | acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd) |
624 | { | 624 | { |
625 | acpi_status status; | 625 | acpi_status status; |
626 | acpi_handle tmp; | 626 | acpi_handle tmp; |
627 | struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; | 627 | struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; |
628 | union acpi_object *obj; | 628 | union acpi_object *obj; |
629 | 629 | ||
630 | status = acpi_get_handle(handle, "_EJD", &tmp); | 630 | status = acpi_get_handle(handle, "_EJD", &tmp); |
631 | if (ACPI_FAILURE(status)) | 631 | if (ACPI_FAILURE(status)) |
632 | return status; | 632 | return status; |
633 | 633 | ||
634 | status = acpi_evaluate_object(handle, "_EJD", NULL, &buffer); | 634 | status = acpi_evaluate_object(handle, "_EJD", NULL, &buffer); |
635 | if (ACPI_SUCCESS(status)) { | 635 | if (ACPI_SUCCESS(status)) { |
636 | obj = buffer.pointer; | 636 | obj = buffer.pointer; |
637 | status = acpi_get_handle(ACPI_ROOT_OBJECT, obj->string.pointer, | 637 | status = acpi_get_handle(ACPI_ROOT_OBJECT, obj->string.pointer, |
638 | ejd); | 638 | ejd); |
639 | kfree(buffer.pointer); | 639 | kfree(buffer.pointer); |
640 | } | 640 | } |
641 | return status; | 641 | return status; |
642 | } | 642 | } |
643 | EXPORT_SYMBOL_GPL(acpi_bus_get_ejd); | 643 | EXPORT_SYMBOL_GPL(acpi_bus_get_ejd); |
644 | 644 | ||
645 | void acpi_bus_data_handler(acpi_handle handle, u32 function, void *context) | 645 | void acpi_bus_data_handler(acpi_handle handle, u32 function, void *context) |
646 | { | 646 | { |
647 | 647 | ||
648 | /* TBD */ | 648 | /* TBD */ |
649 | 649 | ||
650 | return; | 650 | return; |
651 | } | 651 | } |
652 | 652 | ||
653 | static int acpi_bus_get_perf_flags(struct acpi_device *device) | 653 | static int acpi_bus_get_perf_flags(struct acpi_device *device) |
654 | { | 654 | { |
655 | device->performance.state = ACPI_STATE_UNKNOWN; | 655 | device->performance.state = ACPI_STATE_UNKNOWN; |
656 | return 0; | 656 | return 0; |
657 | } | 657 | } |
658 | 658 | ||
659 | static acpi_status | 659 | static acpi_status |
660 | acpi_bus_extract_wakeup_device_power_package(struct acpi_device *device, | 660 | acpi_bus_extract_wakeup_device_power_package(struct acpi_device *device, |
661 | union acpi_object *package) | 661 | union acpi_object *package) |
662 | { | 662 | { |
663 | int i = 0; | 663 | int i = 0; |
664 | union acpi_object *element = NULL; | 664 | union acpi_object *element = NULL; |
665 | 665 | ||
666 | if (!device || !package || (package->package.count < 2)) | 666 | if (!device || !package || (package->package.count < 2)) |
667 | return AE_BAD_PARAMETER; | 667 | return AE_BAD_PARAMETER; |
668 | 668 | ||
669 | element = &(package->package.elements[0]); | 669 | element = &(package->package.elements[0]); |
670 | if (!element) | 670 | if (!element) |
671 | return AE_BAD_PARAMETER; | 671 | return AE_BAD_PARAMETER; |
672 | if (element->type == ACPI_TYPE_PACKAGE) { | 672 | if (element->type == ACPI_TYPE_PACKAGE) { |
673 | if ((element->package.count < 2) || | 673 | if ((element->package.count < 2) || |
674 | (element->package.elements[0].type != | 674 | (element->package.elements[0].type != |
675 | ACPI_TYPE_LOCAL_REFERENCE) | 675 | ACPI_TYPE_LOCAL_REFERENCE) |
676 | || (element->package.elements[1].type != ACPI_TYPE_INTEGER)) | 676 | || (element->package.elements[1].type != ACPI_TYPE_INTEGER)) |
677 | return AE_BAD_DATA; | 677 | return AE_BAD_DATA; |
678 | device->wakeup.gpe_device = | 678 | device->wakeup.gpe_device = |
679 | element->package.elements[0].reference.handle; | 679 | element->package.elements[0].reference.handle; |
680 | device->wakeup.gpe_number = | 680 | device->wakeup.gpe_number = |
681 | (u32) element->package.elements[1].integer.value; | 681 | (u32) element->package.elements[1].integer.value; |
682 | } else if (element->type == ACPI_TYPE_INTEGER) { | 682 | } else if (element->type == ACPI_TYPE_INTEGER) { |
683 | device->wakeup.gpe_number = element->integer.value; | 683 | device->wakeup.gpe_number = element->integer.value; |
684 | } else | 684 | } else |
685 | return AE_BAD_DATA; | 685 | return AE_BAD_DATA; |
686 | 686 | ||
687 | element = &(package->package.elements[1]); | 687 | element = &(package->package.elements[1]); |
688 | if (element->type != ACPI_TYPE_INTEGER) { | 688 | if (element->type != ACPI_TYPE_INTEGER) { |
689 | return AE_BAD_DATA; | 689 | return AE_BAD_DATA; |
690 | } | 690 | } |
691 | device->wakeup.sleep_state = element->integer.value; | 691 | device->wakeup.sleep_state = element->integer.value; |
692 | 692 | ||
693 | if ((package->package.count - 2) > ACPI_MAX_HANDLES) { | 693 | if ((package->package.count - 2) > ACPI_MAX_HANDLES) { |
694 | return AE_NO_MEMORY; | 694 | return AE_NO_MEMORY; |
695 | } | 695 | } |
696 | device->wakeup.resources.count = package->package.count - 2; | 696 | device->wakeup.resources.count = package->package.count - 2; |
697 | for (i = 0; i < device->wakeup.resources.count; i++) { | 697 | for (i = 0; i < device->wakeup.resources.count; i++) { |
698 | element = &(package->package.elements[i + 2]); | 698 | element = &(package->package.elements[i + 2]); |
699 | if (element->type != ACPI_TYPE_LOCAL_REFERENCE) | 699 | if (element->type != ACPI_TYPE_LOCAL_REFERENCE) |
700 | return AE_BAD_DATA; | 700 | return AE_BAD_DATA; |
701 | 701 | ||
702 | device->wakeup.resources.handles[i] = element->reference.handle; | 702 | device->wakeup.resources.handles[i] = element->reference.handle; |
703 | } | 703 | } |
704 | 704 | ||
705 | return AE_OK; | 705 | return AE_OK; |
706 | } | 706 | } |
707 | 707 | ||
708 | static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device) | 708 | static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device) |
709 | { | 709 | { |
710 | acpi_status status = 0; | 710 | acpi_status status = 0; |
711 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | 711 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
712 | union acpi_object *package = NULL; | 712 | union acpi_object *package = NULL; |
713 | int psw_error; | 713 | int psw_error; |
714 | 714 | ||
715 | struct acpi_device_id button_device_ids[] = { | 715 | struct acpi_device_id button_device_ids[] = { |
716 | {"PNP0C0D", 0}, | 716 | {"PNP0C0D", 0}, |
717 | {"PNP0C0C", 0}, | 717 | {"PNP0C0C", 0}, |
718 | {"PNP0C0E", 0}, | 718 | {"PNP0C0E", 0}, |
719 | {"", 0}, | 719 | {"", 0}, |
720 | }; | 720 | }; |
721 | 721 | ||
722 | /* _PRW */ | 722 | /* _PRW */ |
723 | status = acpi_evaluate_object(device->handle, "_PRW", NULL, &buffer); | 723 | status = acpi_evaluate_object(device->handle, "_PRW", NULL, &buffer); |
724 | if (ACPI_FAILURE(status)) { | 724 | if (ACPI_FAILURE(status)) { |
725 | ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRW")); | 725 | ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRW")); |
726 | goto end; | 726 | goto end; |
727 | } | 727 | } |
728 | 728 | ||
729 | package = (union acpi_object *)buffer.pointer; | 729 | package = (union acpi_object *)buffer.pointer; |
730 | status = acpi_bus_extract_wakeup_device_power_package(device, package); | 730 | status = acpi_bus_extract_wakeup_device_power_package(device, package); |
731 | if (ACPI_FAILURE(status)) { | 731 | if (ACPI_FAILURE(status)) { |
732 | ACPI_EXCEPTION((AE_INFO, status, "Extracting _PRW package")); | 732 | ACPI_EXCEPTION((AE_INFO, status, "Extracting _PRW package")); |
733 | goto end; | 733 | goto end; |
734 | } | 734 | } |
735 | 735 | ||
736 | kfree(buffer.pointer); | 736 | kfree(buffer.pointer); |
737 | 737 | ||
738 | device->wakeup.flags.valid = 1; | 738 | device->wakeup.flags.valid = 1; |
739 | /* Call _PSW/_DSW object to disable its ability to wake the sleeping | 739 | /* Call _PSW/_DSW object to disable its ability to wake the sleeping |
740 | * system for the ACPI device with the _PRW object. | 740 | * system for the ACPI device with the _PRW object. |
741 | * The _PSW object is depreciated in ACPI 3.0 and is replaced by _DSW. | 741 | * The _PSW object is depreciated in ACPI 3.0 and is replaced by _DSW. |
742 | * So it is necessary to call _DSW object first. Only when it is not | 742 | * So it is necessary to call _DSW object first. Only when it is not |
743 | * present will the _PSW object used. | 743 | * present will the _PSW object used. |
744 | */ | 744 | */ |
745 | psw_error = acpi_device_sleep_wake(device, 0, 0, 0); | 745 | psw_error = acpi_device_sleep_wake(device, 0, 0, 0); |
746 | if (psw_error) | 746 | if (psw_error) |
747 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | 747 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
748 | "error in _DSW or _PSW evaluation\n")); | 748 | "error in _DSW or _PSW evaluation\n")); |
749 | 749 | ||
750 | /* Power button, Lid switch always enable wakeup */ | 750 | /* Power button, Lid switch always enable wakeup */ |
751 | if (!acpi_match_device_ids(device, button_device_ids)) | 751 | if (!acpi_match_device_ids(device, button_device_ids)) |
752 | device->wakeup.flags.run_wake = 1; | 752 | device->wakeup.flags.run_wake = 1; |
753 | 753 | ||
754 | /* | 754 | /* |
755 | * Don't set Power button GPE as run_wake | 755 | * Don't set Power button GPE as run_wake |
756 | * if Fixed Power button is used | 756 | * if Fixed Power button is used |
757 | */ | 757 | */ |
758 | if (!strcmp(device->pnp.hardware_id, "PNP0C0C") && | 758 | if (!strcmp(device->pnp.hardware_id, "PNP0C0C") && |
759 | !(acpi_gbl_FADT.flags & ACPI_FADT_POWER_BUTTON)) { | 759 | !(acpi_gbl_FADT.flags & ACPI_FADT_POWER_BUTTON)) { |
760 | device->wakeup.flags.run_wake = 0; | 760 | device->wakeup.flags.run_wake = 0; |
761 | device->wakeup.flags.valid = 0; | 761 | device->wakeup.flags.valid = 0; |
762 | } | 762 | } |
763 | 763 | ||
764 | end: | 764 | end: |
765 | if (ACPI_FAILURE(status)) | 765 | if (ACPI_FAILURE(status)) |
766 | device->flags.wake_capable = 0; | 766 | device->flags.wake_capable = 0; |
767 | return 0; | 767 | return 0; |
768 | } | 768 | } |
769 | 769 | ||
770 | static int acpi_bus_get_power_flags(struct acpi_device *device) | 770 | static int acpi_bus_get_power_flags(struct acpi_device *device) |
771 | { | 771 | { |
772 | acpi_status status = 0; | 772 | acpi_status status = 0; |
773 | acpi_handle handle = NULL; | 773 | acpi_handle handle = NULL; |
774 | u32 i = 0; | 774 | u32 i = 0; |
775 | 775 | ||
776 | 776 | ||
777 | /* | 777 | /* |
778 | * Power Management Flags | 778 | * Power Management Flags |
779 | */ | 779 | */ |
780 | status = acpi_get_handle(device->handle, "_PSC", &handle); | 780 | status = acpi_get_handle(device->handle, "_PSC", &handle); |
781 | if (ACPI_SUCCESS(status)) | 781 | if (ACPI_SUCCESS(status)) |
782 | device->power.flags.explicit_get = 1; | 782 | device->power.flags.explicit_get = 1; |
783 | status = acpi_get_handle(device->handle, "_IRC", &handle); | 783 | status = acpi_get_handle(device->handle, "_IRC", &handle); |
784 | if (ACPI_SUCCESS(status)) | 784 | if (ACPI_SUCCESS(status)) |
785 | device->power.flags.inrush_current = 1; | 785 | device->power.flags.inrush_current = 1; |
786 | 786 | ||
787 | /* | 787 | /* |
788 | * Enumerate supported power management states | 788 | * Enumerate supported power management states |
789 | */ | 789 | */ |
790 | for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3; i++) { | 790 | for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3; i++) { |
791 | struct acpi_device_power_state *ps = &device->power.states[i]; | 791 | struct acpi_device_power_state *ps = &device->power.states[i]; |
792 | char object_name[5] = { '_', 'P', 'R', '0' + i, '\0' }; | 792 | char object_name[5] = { '_', 'P', 'R', '0' + i, '\0' }; |
793 | 793 | ||
794 | /* Evaluate "_PRx" to se if power resources are referenced */ | 794 | /* Evaluate "_PRx" to se if power resources are referenced */ |
795 | acpi_evaluate_reference(device->handle, object_name, NULL, | 795 | acpi_evaluate_reference(device->handle, object_name, NULL, |
796 | &ps->resources); | 796 | &ps->resources); |
797 | if (ps->resources.count) { | 797 | if (ps->resources.count) { |
798 | device->power.flags.power_resources = 1; | 798 | device->power.flags.power_resources = 1; |
799 | ps->flags.valid = 1; | 799 | ps->flags.valid = 1; |
800 | } | 800 | } |
801 | 801 | ||
802 | /* Evaluate "_PSx" to see if we can do explicit sets */ | 802 | /* Evaluate "_PSx" to see if we can do explicit sets */ |
803 | object_name[2] = 'S'; | 803 | object_name[2] = 'S'; |
804 | status = acpi_get_handle(device->handle, object_name, &handle); | 804 | status = acpi_get_handle(device->handle, object_name, &handle); |
805 | if (ACPI_SUCCESS(status)) { | 805 | if (ACPI_SUCCESS(status)) { |
806 | ps->flags.explicit_set = 1; | 806 | ps->flags.explicit_set = 1; |
807 | ps->flags.valid = 1; | 807 | ps->flags.valid = 1; |
808 | } | 808 | } |
809 | 809 | ||
810 | /* State is valid if we have some power control */ | 810 | /* State is valid if we have some power control */ |
811 | if (ps->resources.count || ps->flags.explicit_set) | 811 | if (ps->resources.count || ps->flags.explicit_set) |
812 | ps->flags.valid = 1; | 812 | ps->flags.valid = 1; |
813 | 813 | ||
814 | ps->power = -1; /* Unknown - driver assigned */ | 814 | ps->power = -1; /* Unknown - driver assigned */ |
815 | ps->latency = -1; /* Unknown - driver assigned */ | 815 | ps->latency = -1; /* Unknown - driver assigned */ |
816 | } | 816 | } |
817 | 817 | ||
818 | /* Set defaults for D0 and D3 states (always valid) */ | 818 | /* Set defaults for D0 and D3 states (always valid) */ |
819 | device->power.states[ACPI_STATE_D0].flags.valid = 1; | 819 | device->power.states[ACPI_STATE_D0].flags.valid = 1; |
820 | device->power.states[ACPI_STATE_D0].power = 100; | 820 | device->power.states[ACPI_STATE_D0].power = 100; |
821 | device->power.states[ACPI_STATE_D3].flags.valid = 1; | 821 | device->power.states[ACPI_STATE_D3].flags.valid = 1; |
822 | device->power.states[ACPI_STATE_D3].power = 0; | 822 | device->power.states[ACPI_STATE_D3].power = 0; |
823 | 823 | ||
824 | /* TBD: System wake support and resource requirements. */ | 824 | /* TBD: System wake support and resource requirements. */ |
825 | 825 | ||
826 | device->power.state = ACPI_STATE_UNKNOWN; | 826 | device->power.state = ACPI_STATE_UNKNOWN; |
827 | acpi_bus_get_power(device->handle, &(device->power.state)); | 827 | acpi_bus_get_power(device->handle, &(device->power.state)); |
828 | 828 | ||
829 | return 0; | 829 | return 0; |
830 | } | 830 | } |
831 | 831 | ||
832 | static int acpi_bus_get_flags(struct acpi_device *device) | 832 | static int acpi_bus_get_flags(struct acpi_device *device) |
833 | { | 833 | { |
834 | acpi_status status = AE_OK; | 834 | acpi_status status = AE_OK; |
835 | acpi_handle temp = NULL; | 835 | acpi_handle temp = NULL; |
836 | 836 | ||
837 | 837 | ||
838 | /* Presence of _STA indicates 'dynamic_status' */ | 838 | /* Presence of _STA indicates 'dynamic_status' */ |
839 | status = acpi_get_handle(device->handle, "_STA", &temp); | 839 | status = acpi_get_handle(device->handle, "_STA", &temp); |
840 | if (ACPI_SUCCESS(status)) | 840 | if (ACPI_SUCCESS(status)) |
841 | device->flags.dynamic_status = 1; | 841 | device->flags.dynamic_status = 1; |
842 | 842 | ||
843 | /* Presence of _CID indicates 'compatible_ids' */ | 843 | /* Presence of _CID indicates 'compatible_ids' */ |
844 | status = acpi_get_handle(device->handle, "_CID", &temp); | 844 | status = acpi_get_handle(device->handle, "_CID", &temp); |
845 | if (ACPI_SUCCESS(status)) | 845 | if (ACPI_SUCCESS(status)) |
846 | device->flags.compatible_ids = 1; | 846 | device->flags.compatible_ids = 1; |
847 | 847 | ||
848 | /* Presence of _RMV indicates 'removable' */ | 848 | /* Presence of _RMV indicates 'removable' */ |
849 | status = acpi_get_handle(device->handle, "_RMV", &temp); | 849 | status = acpi_get_handle(device->handle, "_RMV", &temp); |
850 | if (ACPI_SUCCESS(status)) | 850 | if (ACPI_SUCCESS(status)) |
851 | device->flags.removable = 1; | 851 | device->flags.removable = 1; |
852 | 852 | ||
853 | /* Presence of _EJD|_EJ0 indicates 'ejectable' */ | 853 | /* Presence of _EJD|_EJ0 indicates 'ejectable' */ |
854 | status = acpi_get_handle(device->handle, "_EJD", &temp); | 854 | status = acpi_get_handle(device->handle, "_EJD", &temp); |
855 | if (ACPI_SUCCESS(status)) | 855 | if (ACPI_SUCCESS(status)) |
856 | device->flags.ejectable = 1; | 856 | device->flags.ejectable = 1; |
857 | else { | 857 | else { |
858 | status = acpi_get_handle(device->handle, "_EJ0", &temp); | 858 | status = acpi_get_handle(device->handle, "_EJ0", &temp); |
859 | if (ACPI_SUCCESS(status)) | 859 | if (ACPI_SUCCESS(status)) |
860 | device->flags.ejectable = 1; | 860 | device->flags.ejectable = 1; |
861 | } | 861 | } |
862 | 862 | ||
863 | /* Presence of _LCK indicates 'lockable' */ | 863 | /* Presence of _LCK indicates 'lockable' */ |
864 | status = acpi_get_handle(device->handle, "_LCK", &temp); | 864 | status = acpi_get_handle(device->handle, "_LCK", &temp); |
865 | if (ACPI_SUCCESS(status)) | 865 | if (ACPI_SUCCESS(status)) |
866 | device->flags.lockable = 1; | 866 | device->flags.lockable = 1; |
867 | 867 | ||
868 | /* Presence of _PS0|_PR0 indicates 'power manageable' */ | 868 | /* Presence of _PS0|_PR0 indicates 'power manageable' */ |
869 | status = acpi_get_handle(device->handle, "_PS0", &temp); | 869 | status = acpi_get_handle(device->handle, "_PS0", &temp); |
870 | if (ACPI_FAILURE(status)) | 870 | if (ACPI_FAILURE(status)) |
871 | status = acpi_get_handle(device->handle, "_PR0", &temp); | 871 | status = acpi_get_handle(device->handle, "_PR0", &temp); |
872 | if (ACPI_SUCCESS(status)) | 872 | if (ACPI_SUCCESS(status)) |
873 | device->flags.power_manageable = 1; | 873 | device->flags.power_manageable = 1; |
874 | 874 | ||
875 | /* Presence of _PRW indicates wake capable */ | 875 | /* Presence of _PRW indicates wake capable */ |
876 | status = acpi_get_handle(device->handle, "_PRW", &temp); | 876 | status = acpi_get_handle(device->handle, "_PRW", &temp); |
877 | if (ACPI_SUCCESS(status)) | 877 | if (ACPI_SUCCESS(status)) |
878 | device->flags.wake_capable = 1; | 878 | device->flags.wake_capable = 1; |
879 | 879 | ||
880 | /* TBD: Performance management */ | 880 | /* TBD: Performance management */ |
881 | 881 | ||
882 | return 0; | 882 | return 0; |
883 | } | 883 | } |
884 | 884 | ||
885 | static void acpi_device_get_busid(struct acpi_device *device, | 885 | static void acpi_device_get_busid(struct acpi_device *device, |
886 | acpi_handle handle, int type) | 886 | acpi_handle handle, int type) |
887 | { | 887 | { |
888 | char bus_id[5] = { '?', 0 }; | 888 | char bus_id[5] = { '?', 0 }; |
889 | struct acpi_buffer buffer = { sizeof(bus_id), bus_id }; | 889 | struct acpi_buffer buffer = { sizeof(bus_id), bus_id }; |
890 | int i = 0; | 890 | int i = 0; |
891 | 891 | ||
892 | /* | 892 | /* |
893 | * Bus ID | 893 | * Bus ID |
894 | * ------ | 894 | * ------ |
895 | * The device's Bus ID is simply the object name. | 895 | * The device's Bus ID is simply the object name. |
896 | * TBD: Shouldn't this value be unique (within the ACPI namespace)? | 896 | * TBD: Shouldn't this value be unique (within the ACPI namespace)? |
897 | */ | 897 | */ |
898 | switch (type) { | 898 | switch (type) { |
899 | case ACPI_BUS_TYPE_SYSTEM: | 899 | case ACPI_BUS_TYPE_SYSTEM: |
900 | strcpy(device->pnp.bus_id, "ACPI"); | 900 | strcpy(device->pnp.bus_id, "ACPI"); |
901 | break; | 901 | break; |
902 | case ACPI_BUS_TYPE_POWER_BUTTON: | 902 | case ACPI_BUS_TYPE_POWER_BUTTON: |
903 | strcpy(device->pnp.bus_id, "PWRF"); | 903 | strcpy(device->pnp.bus_id, "PWRF"); |
904 | break; | 904 | break; |
905 | case ACPI_BUS_TYPE_SLEEP_BUTTON: | 905 | case ACPI_BUS_TYPE_SLEEP_BUTTON: |
906 | strcpy(device->pnp.bus_id, "SLPF"); | 906 | strcpy(device->pnp.bus_id, "SLPF"); |
907 | break; | 907 | break; |
908 | default: | 908 | default: |
909 | acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer); | 909 | acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer); |
910 | /* Clean up trailing underscores (if any) */ | 910 | /* Clean up trailing underscores (if any) */ |
911 | for (i = 3; i > 1; i--) { | 911 | for (i = 3; i > 1; i--) { |
912 | if (bus_id[i] == '_') | 912 | if (bus_id[i] == '_') |
913 | bus_id[i] = '\0'; | 913 | bus_id[i] = '\0'; |
914 | else | 914 | else |
915 | break; | 915 | break; |
916 | } | 916 | } |
917 | strcpy(device->pnp.bus_id, bus_id); | 917 | strcpy(device->pnp.bus_id, bus_id); |
918 | break; | 918 | break; |
919 | } | 919 | } |
920 | } | 920 | } |
921 | 921 | ||
922 | static int | ||
923 | acpi_video_bus_match(struct acpi_device *device) | ||
924 | { | ||
925 | acpi_handle h_dummy; | ||
926 | |||
927 | if (!device) | ||
928 | return -EINVAL; | ||
929 | |||
930 | /* Since there is no HID, CID for ACPI Video drivers, we have | ||
931 | * to check well known required nodes for each feature we support. | ||
932 | */ | ||
933 | |||
934 | /* Does this device able to support video switching ? */ | ||
935 | if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy)) && | ||
936 | ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy))) | ||
937 | return 0; | ||
938 | |||
939 | /* Does this device able to retrieve a video ROM ? */ | ||
940 | if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy))) | ||
941 | return 0; | ||
942 | |||
943 | /* Does this device able to configure which video head to be POSTed ? */ | ||
944 | if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy)) && | ||
945 | ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy)) && | ||
946 | ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy))) | ||
947 | return 0; | ||
948 | |||
949 | return -ENODEV; | ||
950 | } | ||
951 | |||
952 | /* | 922 | /* |
953 | * acpi_bay_match - see if a device is an ejectable driver bay | 923 | * acpi_bay_match - see if a device is an ejectable driver bay |
954 | * | 924 | * |
955 | * If an acpi object is ejectable and has one of the ACPI ATA methods defined, | 925 | * If an acpi object is ejectable and has one of the ACPI ATA methods defined, |
956 | * then we can safely call it an ejectable drive bay | 926 | * then we can safely call it an ejectable drive bay |
957 | */ | 927 | */ |
958 | static int acpi_bay_match(struct acpi_device *device){ | 928 | static int acpi_bay_match(struct acpi_device *device){ |
959 | acpi_status status; | 929 | acpi_status status; |
960 | acpi_handle handle; | 930 | acpi_handle handle; |
961 | acpi_handle tmp; | 931 | acpi_handle tmp; |
962 | acpi_handle phandle; | 932 | acpi_handle phandle; |
963 | 933 | ||
964 | handle = device->handle; | 934 | handle = device->handle; |
965 | 935 | ||
966 | status = acpi_get_handle(handle, "_EJ0", &tmp); | 936 | status = acpi_get_handle(handle, "_EJ0", &tmp); |
967 | if (ACPI_FAILURE(status)) | 937 | if (ACPI_FAILURE(status)) |
968 | return -ENODEV; | 938 | return -ENODEV; |
969 | 939 | ||
970 | if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) || | 940 | if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) || |
971 | (ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) || | 941 | (ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) || |
972 | (ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) || | 942 | (ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) || |
973 | (ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp)))) | 943 | (ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp)))) |
974 | return 0; | 944 | return 0; |
975 | 945 | ||
976 | if (acpi_get_parent(handle, &phandle)) | 946 | if (acpi_get_parent(handle, &phandle)) |
977 | return -ENODEV; | 947 | return -ENODEV; |
978 | 948 | ||
979 | if ((ACPI_SUCCESS(acpi_get_handle(phandle, "_GTF", &tmp))) || | 949 | if ((ACPI_SUCCESS(acpi_get_handle(phandle, "_GTF", &tmp))) || |
980 | (ACPI_SUCCESS(acpi_get_handle(phandle, "_GTM", &tmp))) || | 950 | (ACPI_SUCCESS(acpi_get_handle(phandle, "_GTM", &tmp))) || |
981 | (ACPI_SUCCESS(acpi_get_handle(phandle, "_STM", &tmp))) || | 951 | (ACPI_SUCCESS(acpi_get_handle(phandle, "_STM", &tmp))) || |
982 | (ACPI_SUCCESS(acpi_get_handle(phandle, "_SDD", &tmp)))) | 952 | (ACPI_SUCCESS(acpi_get_handle(phandle, "_SDD", &tmp)))) |
983 | return 0; | 953 | return 0; |
984 | 954 | ||
985 | return -ENODEV; | 955 | return -ENODEV; |
986 | } | 956 | } |
987 | 957 | ||
988 | /* | 958 | /* |
989 | * acpi_dock_match - see if a device has a _DCK method | 959 | * acpi_dock_match - see if a device has a _DCK method |
990 | */ | 960 | */ |
991 | static int acpi_dock_match(struct acpi_device *device) | 961 | static int acpi_dock_match(struct acpi_device *device) |
992 | { | 962 | { |
993 | acpi_handle tmp; | 963 | acpi_handle tmp; |
994 | return acpi_get_handle(device->handle, "_DCK", &tmp); | 964 | return acpi_get_handle(device->handle, "_DCK", &tmp); |
995 | } | 965 | } |
996 | 966 | ||
997 | static void acpi_device_set_id(struct acpi_device *device, | 967 | static void acpi_device_set_id(struct acpi_device *device, |
998 | struct acpi_device *parent, acpi_handle handle, | 968 | struct acpi_device *parent, acpi_handle handle, |
999 | int type) | 969 | int type) |
1000 | { | 970 | { |
1001 | struct acpi_device_info *info; | 971 | struct acpi_device_info *info; |
1002 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | 972 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
1003 | char *hid = NULL; | 973 | char *hid = NULL; |
1004 | char *uid = NULL; | 974 | char *uid = NULL; |
1005 | struct acpi_compatible_id_list *cid_list = NULL; | 975 | struct acpi_compatible_id_list *cid_list = NULL; |
1006 | const char *cid_add = NULL; | 976 | const char *cid_add = NULL; |
1007 | acpi_status status; | 977 | acpi_status status; |
1008 | 978 | ||
1009 | switch (type) { | 979 | switch (type) { |
1010 | case ACPI_BUS_TYPE_DEVICE: | 980 | case ACPI_BUS_TYPE_DEVICE: |
1011 | status = acpi_get_object_info(handle, &buffer); | 981 | status = acpi_get_object_info(handle, &buffer); |
1012 | if (ACPI_FAILURE(status)) { | 982 | if (ACPI_FAILURE(status)) { |
1013 | printk(KERN_ERR PREFIX "%s: Error reading device info\n", __func__); | 983 | printk(KERN_ERR PREFIX "%s: Error reading device info\n", __func__); |
1014 | return; | 984 | return; |
1015 | } | 985 | } |
1016 | 986 | ||
1017 | info = buffer.pointer; | 987 | info = buffer.pointer; |
1018 | if (info->valid & ACPI_VALID_HID) | 988 | if (info->valid & ACPI_VALID_HID) |
1019 | hid = info->hardware_id.value; | 989 | hid = info->hardware_id.value; |
1020 | if (info->valid & ACPI_VALID_UID) | 990 | if (info->valid & ACPI_VALID_UID) |
1021 | uid = info->unique_id.value; | 991 | uid = info->unique_id.value; |
1022 | if (info->valid & ACPI_VALID_CID) | 992 | if (info->valid & ACPI_VALID_CID) |
1023 | cid_list = &info->compatibility_id; | 993 | cid_list = &info->compatibility_id; |
1024 | if (info->valid & ACPI_VALID_ADR) { | 994 | if (info->valid & ACPI_VALID_ADR) { |
1025 | device->pnp.bus_address = info->address; | 995 | device->pnp.bus_address = info->address; |
1026 | device->flags.bus_address = 1; | 996 | device->flags.bus_address = 1; |
1027 | } | 997 | } |
1028 | 998 | ||
1029 | /* If we have a video/bay/dock device, add our selfdefined | 999 | /* If we have a video/bay/dock device, add our selfdefined |
1030 | HID to the CID list. Like that the video/bay/dock drivers | 1000 | HID to the CID list. Like that the video/bay/dock drivers |
1031 | will get autoloaded and the device might still match | 1001 | will get autoloaded and the device might still match |
1032 | against another driver. | 1002 | against another driver. |
1033 | */ | 1003 | */ |
1034 | if (ACPI_SUCCESS(acpi_video_bus_match(device))) | 1004 | if (acpi_is_video_device(device)) |
1035 | cid_add = ACPI_VIDEO_HID; | 1005 | cid_add = ACPI_VIDEO_HID; |
1036 | else if (ACPI_SUCCESS(acpi_bay_match(device))) | 1006 | else if (ACPI_SUCCESS(acpi_bay_match(device))) |
1037 | cid_add = ACPI_BAY_HID; | 1007 | cid_add = ACPI_BAY_HID; |
1038 | else if (ACPI_SUCCESS(acpi_dock_match(device))) | 1008 | else if (ACPI_SUCCESS(acpi_dock_match(device))) |
1039 | cid_add = ACPI_DOCK_HID; | 1009 | cid_add = ACPI_DOCK_HID; |
1040 | 1010 | ||
1041 | break; | 1011 | break; |
1042 | case ACPI_BUS_TYPE_POWER: | 1012 | case ACPI_BUS_TYPE_POWER: |
1043 | hid = ACPI_POWER_HID; | 1013 | hid = ACPI_POWER_HID; |
1044 | break; | 1014 | break; |
1045 | case ACPI_BUS_TYPE_PROCESSOR: | 1015 | case ACPI_BUS_TYPE_PROCESSOR: |
1046 | hid = ACPI_PROCESSOR_HID; | 1016 | hid = ACPI_PROCESSOR_HID; |
1047 | break; | 1017 | break; |
1048 | case ACPI_BUS_TYPE_SYSTEM: | 1018 | case ACPI_BUS_TYPE_SYSTEM: |
1049 | hid = ACPI_SYSTEM_HID; | 1019 | hid = ACPI_SYSTEM_HID; |
1050 | break; | 1020 | break; |
1051 | case ACPI_BUS_TYPE_THERMAL: | 1021 | case ACPI_BUS_TYPE_THERMAL: |
1052 | hid = ACPI_THERMAL_HID; | 1022 | hid = ACPI_THERMAL_HID; |
1053 | break; | 1023 | break; |
1054 | case ACPI_BUS_TYPE_POWER_BUTTON: | 1024 | case ACPI_BUS_TYPE_POWER_BUTTON: |
1055 | hid = ACPI_BUTTON_HID_POWERF; | 1025 | hid = ACPI_BUTTON_HID_POWERF; |
1056 | break; | 1026 | break; |
1057 | case ACPI_BUS_TYPE_SLEEP_BUTTON: | 1027 | case ACPI_BUS_TYPE_SLEEP_BUTTON: |
1058 | hid = ACPI_BUTTON_HID_SLEEPF; | 1028 | hid = ACPI_BUTTON_HID_SLEEPF; |
1059 | break; | 1029 | break; |
1060 | } | 1030 | } |
1061 | 1031 | ||
1062 | /* | 1032 | /* |
1063 | * \_SB | 1033 | * \_SB |
1064 | * ---- | 1034 | * ---- |
1065 | * Fix for the system root bus device -- the only root-level device. | 1035 | * Fix for the system root bus device -- the only root-level device. |
1066 | */ | 1036 | */ |
1067 | if (((acpi_handle)parent == ACPI_ROOT_OBJECT) && (type == ACPI_BUS_TYPE_DEVICE)) { | 1037 | if (((acpi_handle)parent == ACPI_ROOT_OBJECT) && (type == ACPI_BUS_TYPE_DEVICE)) { |
1068 | hid = ACPI_BUS_HID; | 1038 | hid = ACPI_BUS_HID; |
1069 | strcpy(device->pnp.device_name, ACPI_BUS_DEVICE_NAME); | 1039 | strcpy(device->pnp.device_name, ACPI_BUS_DEVICE_NAME); |
1070 | strcpy(device->pnp.device_class, ACPI_BUS_CLASS); | 1040 | strcpy(device->pnp.device_class, ACPI_BUS_CLASS); |
1071 | } | 1041 | } |
1072 | 1042 | ||
1073 | if (hid) { | 1043 | if (hid) { |
1074 | strcpy(device->pnp.hardware_id, hid); | 1044 | strcpy(device->pnp.hardware_id, hid); |
1075 | device->flags.hardware_id = 1; | 1045 | device->flags.hardware_id = 1; |
1076 | } | 1046 | } |
1077 | if (uid) { | 1047 | if (uid) { |
1078 | strcpy(device->pnp.unique_id, uid); | 1048 | strcpy(device->pnp.unique_id, uid); |
1079 | device->flags.unique_id = 1; | 1049 | device->flags.unique_id = 1; |
1080 | } | 1050 | } |
1081 | if (cid_list || cid_add) { | 1051 | if (cid_list || cid_add) { |
1082 | struct acpi_compatible_id_list *list; | 1052 | struct acpi_compatible_id_list *list; |
1083 | int size = 0; | 1053 | int size = 0; |
1084 | int count = 0; | 1054 | int count = 0; |
1085 | 1055 | ||
1086 | if (cid_list) { | 1056 | if (cid_list) { |
1087 | size = cid_list->size; | 1057 | size = cid_list->size; |
1088 | } else if (cid_add) { | 1058 | } else if (cid_add) { |
1089 | size = sizeof(struct acpi_compatible_id_list); | 1059 | size = sizeof(struct acpi_compatible_id_list); |
1090 | cid_list = ACPI_ALLOCATE_ZEROED((acpi_size) size); | 1060 | cid_list = ACPI_ALLOCATE_ZEROED((acpi_size) size); |
1091 | if (!cid_list) { | 1061 | if (!cid_list) { |
1092 | printk(KERN_ERR "Memory allocation error\n"); | 1062 | printk(KERN_ERR "Memory allocation error\n"); |
1093 | kfree(buffer.pointer); | 1063 | kfree(buffer.pointer); |
1094 | return; | 1064 | return; |
1095 | } else { | 1065 | } else { |
1096 | cid_list->count = 0; | 1066 | cid_list->count = 0; |
1097 | cid_list->size = size; | 1067 | cid_list->size = size; |
1098 | } | 1068 | } |
1099 | } | 1069 | } |
1100 | if (cid_add) | 1070 | if (cid_add) |
1101 | size += sizeof(struct acpi_compatible_id); | 1071 | size += sizeof(struct acpi_compatible_id); |
1102 | list = kmalloc(size, GFP_KERNEL); | 1072 | list = kmalloc(size, GFP_KERNEL); |
1103 | 1073 | ||
1104 | if (list) { | 1074 | if (list) { |
1105 | if (cid_list) { | 1075 | if (cid_list) { |
1106 | memcpy(list, cid_list, cid_list->size); | 1076 | memcpy(list, cid_list, cid_list->size); |
1107 | count = cid_list->count; | 1077 | count = cid_list->count; |
1108 | } | 1078 | } |
1109 | if (cid_add) { | 1079 | if (cid_add) { |
1110 | strncpy(list->id[count].value, cid_add, | 1080 | strncpy(list->id[count].value, cid_add, |
1111 | ACPI_MAX_CID_LENGTH); | 1081 | ACPI_MAX_CID_LENGTH); |
1112 | count++; | 1082 | count++; |
1113 | device->flags.compatible_ids = 1; | 1083 | device->flags.compatible_ids = 1; |
1114 | } | 1084 | } |
1115 | list->size = size; | 1085 | list->size = size; |
1116 | list->count = count; | 1086 | list->count = count; |
1117 | device->pnp.cid_list = list; | 1087 | device->pnp.cid_list = list; |
1118 | } else | 1088 | } else |
1119 | printk(KERN_ERR PREFIX "Memory allocation error\n"); | 1089 | printk(KERN_ERR PREFIX "Memory allocation error\n"); |
1120 | } | 1090 | } |
1121 | 1091 | ||
1122 | kfree(buffer.pointer); | 1092 | kfree(buffer.pointer); |
1123 | } | 1093 | } |
1124 | 1094 | ||
1125 | static int acpi_device_set_context(struct acpi_device *device, int type) | 1095 | static int acpi_device_set_context(struct acpi_device *device, int type) |
1126 | { | 1096 | { |
1127 | acpi_status status = AE_OK; | 1097 | acpi_status status = AE_OK; |
1128 | int result = 0; | 1098 | int result = 0; |
1129 | /* | 1099 | /* |
1130 | * Context | 1100 | * Context |
1131 | * ------- | 1101 | * ------- |
1132 | * Attach this 'struct acpi_device' to the ACPI object. This makes | 1102 | * Attach this 'struct acpi_device' to the ACPI object. This makes |
1133 | * resolutions from handle->device very efficient. Note that we need | 1103 | * resolutions from handle->device very efficient. Note that we need |
1134 | * to be careful with fixed-feature devices as they all attach to the | 1104 | * to be careful with fixed-feature devices as they all attach to the |
1135 | * root object. | 1105 | * root object. |
1136 | */ | 1106 | */ |
1137 | if (type != ACPI_BUS_TYPE_POWER_BUTTON && | 1107 | if (type != ACPI_BUS_TYPE_POWER_BUTTON && |
1138 | type != ACPI_BUS_TYPE_SLEEP_BUTTON) { | 1108 | type != ACPI_BUS_TYPE_SLEEP_BUTTON) { |
1139 | status = acpi_attach_data(device->handle, | 1109 | status = acpi_attach_data(device->handle, |
1140 | acpi_bus_data_handler, device); | 1110 | acpi_bus_data_handler, device); |
1141 | 1111 | ||
1142 | if (ACPI_FAILURE(status)) { | 1112 | if (ACPI_FAILURE(status)) { |
1143 | printk(KERN_ERR PREFIX "Error attaching device data\n"); | 1113 | printk(KERN_ERR PREFIX "Error attaching device data\n"); |
1144 | result = -ENODEV; | 1114 | result = -ENODEV; |
1145 | } | 1115 | } |
1146 | } | 1116 | } |
1147 | return result; | 1117 | return result; |
1148 | } | 1118 | } |
1149 | 1119 | ||
1150 | static int acpi_bus_remove(struct acpi_device *dev, int rmdevice) | 1120 | static int acpi_bus_remove(struct acpi_device *dev, int rmdevice) |
1151 | { | 1121 | { |
1152 | if (!dev) | 1122 | if (!dev) |
1153 | return -EINVAL; | 1123 | return -EINVAL; |
1154 | 1124 | ||
1155 | dev->removal_type = ACPI_BUS_REMOVAL_EJECT; | 1125 | dev->removal_type = ACPI_BUS_REMOVAL_EJECT; |
1156 | device_release_driver(&dev->dev); | 1126 | device_release_driver(&dev->dev); |
1157 | 1127 | ||
1158 | if (!rmdevice) | 1128 | if (!rmdevice) |
1159 | return 0; | 1129 | return 0; |
1160 | 1130 | ||
1161 | /* | 1131 | /* |
1162 | * unbind _ADR-Based Devices when hot removal | 1132 | * unbind _ADR-Based Devices when hot removal |
1163 | */ | 1133 | */ |
1164 | if (dev->flags.bus_address) { | 1134 | if (dev->flags.bus_address) { |
1165 | if ((dev->parent) && (dev->parent->ops.unbind)) | 1135 | if ((dev->parent) && (dev->parent->ops.unbind)) |
1166 | dev->parent->ops.unbind(dev); | 1136 | dev->parent->ops.unbind(dev); |
1167 | } | 1137 | } |
1168 | acpi_device_unregister(dev, ACPI_BUS_REMOVAL_EJECT); | 1138 | acpi_device_unregister(dev, ACPI_BUS_REMOVAL_EJECT); |
1169 | 1139 | ||
1170 | return 0; | 1140 | return 0; |
1171 | } | 1141 | } |
1172 | 1142 | ||
1173 | static int | 1143 | static int |
1174 | acpi_add_single_object(struct acpi_device **child, | 1144 | acpi_add_single_object(struct acpi_device **child, |
1175 | struct acpi_device *parent, acpi_handle handle, int type, | 1145 | struct acpi_device *parent, acpi_handle handle, int type, |
1176 | struct acpi_bus_ops *ops) | 1146 | struct acpi_bus_ops *ops) |
1177 | { | 1147 | { |
1178 | int result = 0; | 1148 | int result = 0; |
1179 | struct acpi_device *device = NULL; | 1149 | struct acpi_device *device = NULL; |
1180 | 1150 | ||
1181 | 1151 | ||
1182 | if (!child) | 1152 | if (!child) |
1183 | return -EINVAL; | 1153 | return -EINVAL; |
1184 | 1154 | ||
1185 | device = kzalloc(sizeof(struct acpi_device), GFP_KERNEL); | 1155 | device = kzalloc(sizeof(struct acpi_device), GFP_KERNEL); |
1186 | if (!device) { | 1156 | if (!device) { |
1187 | printk(KERN_ERR PREFIX "Memory allocation error\n"); | 1157 | printk(KERN_ERR PREFIX "Memory allocation error\n"); |
1188 | return -ENOMEM; | 1158 | return -ENOMEM; |
1189 | } | 1159 | } |
1190 | 1160 | ||
1191 | device->handle = handle; | 1161 | device->handle = handle; |
1192 | device->parent = parent; | 1162 | device->parent = parent; |
1193 | device->bus_ops = *ops; /* workround for not call .start */ | 1163 | device->bus_ops = *ops; /* workround for not call .start */ |
1194 | 1164 | ||
1195 | 1165 | ||
1196 | acpi_device_get_busid(device, handle, type); | 1166 | acpi_device_get_busid(device, handle, type); |
1197 | 1167 | ||
1198 | /* | 1168 | /* |
1199 | * Flags | 1169 | * Flags |
1200 | * ----- | 1170 | * ----- |
1201 | * Get prior to calling acpi_bus_get_status() so we know whether | 1171 | * Get prior to calling acpi_bus_get_status() so we know whether |
1202 | * or not _STA is present. Note that we only look for object | 1172 | * or not _STA is present. Note that we only look for object |
1203 | * handles -- cannot evaluate objects until we know the device is | 1173 | * handles -- cannot evaluate objects until we know the device is |
1204 | * present and properly initialized. | 1174 | * present and properly initialized. |
1205 | */ | 1175 | */ |
1206 | result = acpi_bus_get_flags(device); | 1176 | result = acpi_bus_get_flags(device); |
1207 | if (result) | 1177 | if (result) |
1208 | goto end; | 1178 | goto end; |
1209 | 1179 | ||
1210 | /* | 1180 | /* |
1211 | * Status | 1181 | * Status |
1212 | * ------ | 1182 | * ------ |
1213 | * See if the device is present. We always assume that non-Device | 1183 | * See if the device is present. We always assume that non-Device |
1214 | * and non-Processor objects (e.g. thermal zones, power resources, | 1184 | * and non-Processor objects (e.g. thermal zones, power resources, |
1215 | * etc.) are present, functioning, etc. (at least when parent object | 1185 | * etc.) are present, functioning, etc. (at least when parent object |
1216 | * is present). Note that _STA has a different meaning for some | 1186 | * is present). Note that _STA has a different meaning for some |
1217 | * objects (e.g. power resources) so we need to be careful how we use | 1187 | * objects (e.g. power resources) so we need to be careful how we use |
1218 | * it. | 1188 | * it. |
1219 | */ | 1189 | */ |
1220 | switch (type) { | 1190 | switch (type) { |
1221 | case ACPI_BUS_TYPE_PROCESSOR: | 1191 | case ACPI_BUS_TYPE_PROCESSOR: |
1222 | case ACPI_BUS_TYPE_DEVICE: | 1192 | case ACPI_BUS_TYPE_DEVICE: |
1223 | result = acpi_bus_get_status(device); | 1193 | result = acpi_bus_get_status(device); |
1224 | if (ACPI_FAILURE(result)) { | 1194 | if (ACPI_FAILURE(result)) { |
1225 | result = -ENODEV; | 1195 | result = -ENODEV; |
1226 | goto end; | 1196 | goto end; |
1227 | } | 1197 | } |
1228 | /* | 1198 | /* |
1229 | * When the device is neither present nor functional, the | 1199 | * When the device is neither present nor functional, the |
1230 | * device should not be added to Linux ACPI device tree. | 1200 | * device should not be added to Linux ACPI device tree. |
1231 | * When the status of the device is not present but functinal, | 1201 | * When the status of the device is not present but functinal, |
1232 | * it should be added to Linux ACPI tree. For example : bay | 1202 | * it should be added to Linux ACPI tree. For example : bay |
1233 | * device , dock device. | 1203 | * device , dock device. |
1234 | * In such conditions it is unncessary to check whether it is | 1204 | * In such conditions it is unncessary to check whether it is |
1235 | * bay device or dock device. | 1205 | * bay device or dock device. |
1236 | */ | 1206 | */ |
1237 | if (!device->status.present && !device->status.functional) { | 1207 | if (!device->status.present && !device->status.functional) { |
1238 | result = -ENODEV; | 1208 | result = -ENODEV; |
1239 | goto end; | 1209 | goto end; |
1240 | } | 1210 | } |
1241 | break; | 1211 | break; |
1242 | default: | 1212 | default: |
1243 | STRUCT_TO_INT(device->status) = | 1213 | STRUCT_TO_INT(device->status) = |
1244 | ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | | 1214 | ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | |
1245 | ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING; | 1215 | ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING; |
1246 | break; | 1216 | break; |
1247 | } | 1217 | } |
1248 | 1218 | ||
1249 | /* | 1219 | /* |
1250 | * Initialize Device | 1220 | * Initialize Device |
1251 | * ----------------- | 1221 | * ----------------- |
1252 | * TBD: Synch with Core's enumeration/initialization process. | 1222 | * TBD: Synch with Core's enumeration/initialization process. |
1253 | */ | 1223 | */ |
1254 | 1224 | ||
1255 | /* | 1225 | /* |
1256 | * Hardware ID, Unique ID, & Bus Address | 1226 | * Hardware ID, Unique ID, & Bus Address |
1257 | * ------------------------------------- | 1227 | * ------------------------------------- |
1258 | */ | 1228 | */ |
1259 | acpi_device_set_id(device, parent, handle, type); | 1229 | acpi_device_set_id(device, parent, handle, type); |
1260 | 1230 | ||
1261 | /* | 1231 | /* |
1262 | * The ACPI device is attached to acpi handle before getting | 1232 | * The ACPI device is attached to acpi handle before getting |
1263 | * the power/wakeup/peformance flags. Otherwise OS can't get | 1233 | * the power/wakeup/peformance flags. Otherwise OS can't get |
1264 | * the corresponding ACPI device by the acpi handle in the course | 1234 | * the corresponding ACPI device by the acpi handle in the course |
1265 | * of getting the power/wakeup/performance flags. | 1235 | * of getting the power/wakeup/performance flags. |
1266 | */ | 1236 | */ |
1267 | result = acpi_device_set_context(device, type); | 1237 | result = acpi_device_set_context(device, type); |
1268 | if (result) | 1238 | if (result) |
1269 | goto end; | 1239 | goto end; |
1270 | 1240 | ||
1271 | /* | 1241 | /* |
1272 | * Power Management | 1242 | * Power Management |
1273 | * ---------------- | 1243 | * ---------------- |
1274 | */ | 1244 | */ |
1275 | if (device->flags.power_manageable) { | 1245 | if (device->flags.power_manageable) { |
1276 | result = acpi_bus_get_power_flags(device); | 1246 | result = acpi_bus_get_power_flags(device); |
1277 | if (result) | 1247 | if (result) |
1278 | goto end; | 1248 | goto end; |
1279 | } | 1249 | } |
1280 | 1250 | ||
1281 | /* | 1251 | /* |
1282 | * Wakeup device management | 1252 | * Wakeup device management |
1283 | *----------------------- | 1253 | *----------------------- |
1284 | */ | 1254 | */ |
1285 | if (device->flags.wake_capable) { | 1255 | if (device->flags.wake_capable) { |
1286 | result = acpi_bus_get_wakeup_device_flags(device); | 1256 | result = acpi_bus_get_wakeup_device_flags(device); |
1287 | if (result) | 1257 | if (result) |
1288 | goto end; | 1258 | goto end; |
1289 | } | 1259 | } |
1290 | 1260 | ||
1291 | /* | 1261 | /* |
1292 | * Performance Management | 1262 | * Performance Management |
1293 | * ---------------------- | 1263 | * ---------------------- |
1294 | */ | 1264 | */ |
1295 | if (device->flags.performance_manageable) { | 1265 | if (device->flags.performance_manageable) { |
1296 | result = acpi_bus_get_perf_flags(device); | 1266 | result = acpi_bus_get_perf_flags(device); |
1297 | if (result) | 1267 | if (result) |
1298 | goto end; | 1268 | goto end; |
1299 | } | 1269 | } |
1300 | 1270 | ||
1301 | 1271 | ||
1302 | result = acpi_device_register(device, parent); | 1272 | result = acpi_device_register(device, parent); |
1303 | 1273 | ||
1304 | /* | 1274 | /* |
1305 | * Bind _ADR-Based Devices when hot add | 1275 | * Bind _ADR-Based Devices when hot add |
1306 | */ | 1276 | */ |
1307 | if (device->flags.bus_address) { | 1277 | if (device->flags.bus_address) { |
1308 | if (device->parent && device->parent->ops.bind) | 1278 | if (device->parent && device->parent->ops.bind) |
1309 | device->parent->ops.bind(device); | 1279 | device->parent->ops.bind(device); |
1310 | } | 1280 | } |
1311 | 1281 | ||
1312 | end: | 1282 | end: |
1313 | if (!result) | 1283 | if (!result) |
1314 | *child = device; | 1284 | *child = device; |
1315 | else { | 1285 | else { |
1316 | kfree(device->pnp.cid_list); | 1286 | kfree(device->pnp.cid_list); |
1317 | kfree(device); | 1287 | kfree(device); |
1318 | } | 1288 | } |
1319 | 1289 | ||
1320 | return result; | 1290 | return result; |
1321 | } | 1291 | } |
1322 | 1292 | ||
1323 | static int acpi_bus_scan(struct acpi_device *start, struct acpi_bus_ops *ops) | 1293 | static int acpi_bus_scan(struct acpi_device *start, struct acpi_bus_ops *ops) |
1324 | { | 1294 | { |
1325 | acpi_status status = AE_OK; | 1295 | acpi_status status = AE_OK; |
1326 | struct acpi_device *parent = NULL; | 1296 | struct acpi_device *parent = NULL; |
1327 | struct acpi_device *child = NULL; | 1297 | struct acpi_device *child = NULL; |
1328 | acpi_handle phandle = NULL; | 1298 | acpi_handle phandle = NULL; |
1329 | acpi_handle chandle = NULL; | 1299 | acpi_handle chandle = NULL; |
1330 | acpi_object_type type = 0; | 1300 | acpi_object_type type = 0; |
1331 | u32 level = 1; | 1301 | u32 level = 1; |
1332 | 1302 | ||
1333 | 1303 | ||
1334 | if (!start) | 1304 | if (!start) |
1335 | return -EINVAL; | 1305 | return -EINVAL; |
1336 | 1306 | ||
1337 | parent = start; | 1307 | parent = start; |
1338 | phandle = start->handle; | 1308 | phandle = start->handle; |
1339 | 1309 | ||
1340 | /* | 1310 | /* |
1341 | * Parse through the ACPI namespace, identify all 'devices', and | 1311 | * Parse through the ACPI namespace, identify all 'devices', and |
1342 | * create a new 'struct acpi_device' for each. | 1312 | * create a new 'struct acpi_device' for each. |
1343 | */ | 1313 | */ |
1344 | while ((level > 0) && parent) { | 1314 | while ((level > 0) && parent) { |
1345 | 1315 | ||
1346 | status = acpi_get_next_object(ACPI_TYPE_ANY, phandle, | 1316 | status = acpi_get_next_object(ACPI_TYPE_ANY, phandle, |
1347 | chandle, &chandle); | 1317 | chandle, &chandle); |
1348 | 1318 | ||
1349 | /* | 1319 | /* |
1350 | * If this scope is exhausted then move our way back up. | 1320 | * If this scope is exhausted then move our way back up. |
1351 | */ | 1321 | */ |
1352 | if (ACPI_FAILURE(status)) { | 1322 | if (ACPI_FAILURE(status)) { |
1353 | level--; | 1323 | level--; |
1354 | chandle = phandle; | 1324 | chandle = phandle; |
1355 | acpi_get_parent(phandle, &phandle); | 1325 | acpi_get_parent(phandle, &phandle); |
1356 | if (parent->parent) | 1326 | if (parent->parent) |
1357 | parent = parent->parent; | 1327 | parent = parent->parent; |
1358 | continue; | 1328 | continue; |
1359 | } | 1329 | } |
1360 | 1330 | ||
1361 | status = acpi_get_type(chandle, &type); | 1331 | status = acpi_get_type(chandle, &type); |
1362 | if (ACPI_FAILURE(status)) | 1332 | if (ACPI_FAILURE(status)) |
1363 | continue; | 1333 | continue; |
1364 | 1334 | ||
1365 | /* | 1335 | /* |
1366 | * If this is a scope object then parse it (depth-first). | 1336 | * If this is a scope object then parse it (depth-first). |
1367 | */ | 1337 | */ |
1368 | if (type == ACPI_TYPE_LOCAL_SCOPE) { | 1338 | if (type == ACPI_TYPE_LOCAL_SCOPE) { |
1369 | level++; | 1339 | level++; |
1370 | phandle = chandle; | 1340 | phandle = chandle; |
1371 | chandle = NULL; | 1341 | chandle = NULL; |
1372 | continue; | 1342 | continue; |
1373 | } | 1343 | } |
1374 | 1344 | ||
1375 | /* | 1345 | /* |
1376 | * We're only interested in objects that we consider 'devices'. | 1346 | * We're only interested in objects that we consider 'devices'. |
1377 | */ | 1347 | */ |
1378 | switch (type) { | 1348 | switch (type) { |
1379 | case ACPI_TYPE_DEVICE: | 1349 | case ACPI_TYPE_DEVICE: |
1380 | type = ACPI_BUS_TYPE_DEVICE; | 1350 | type = ACPI_BUS_TYPE_DEVICE; |
1381 | break; | 1351 | break; |
1382 | case ACPI_TYPE_PROCESSOR: | 1352 | case ACPI_TYPE_PROCESSOR: |
1383 | type = ACPI_BUS_TYPE_PROCESSOR; | 1353 | type = ACPI_BUS_TYPE_PROCESSOR; |
1384 | break; | 1354 | break; |
1385 | case ACPI_TYPE_THERMAL: | 1355 | case ACPI_TYPE_THERMAL: |
1386 | type = ACPI_BUS_TYPE_THERMAL; | 1356 | type = ACPI_BUS_TYPE_THERMAL; |
1387 | break; | 1357 | break; |
1388 | case ACPI_TYPE_POWER: | 1358 | case ACPI_TYPE_POWER: |
1389 | type = ACPI_BUS_TYPE_POWER; | 1359 | type = ACPI_BUS_TYPE_POWER; |
1390 | break; | 1360 | break; |
1391 | default: | 1361 | default: |
1392 | continue; | 1362 | continue; |
1393 | } | 1363 | } |
1394 | 1364 | ||
1395 | if (ops->acpi_op_add) | 1365 | if (ops->acpi_op_add) |
1396 | status = acpi_add_single_object(&child, parent, | 1366 | status = acpi_add_single_object(&child, parent, |
1397 | chandle, type, ops); | 1367 | chandle, type, ops); |
1398 | else | 1368 | else |
1399 | status = acpi_bus_get_device(chandle, &child); | 1369 | status = acpi_bus_get_device(chandle, &child); |
1400 | 1370 | ||
1401 | if (ACPI_FAILURE(status)) | 1371 | if (ACPI_FAILURE(status)) |
1402 | continue; | 1372 | continue; |
1403 | 1373 | ||
1404 | if (ops->acpi_op_start && !(ops->acpi_op_add)) { | 1374 | if (ops->acpi_op_start && !(ops->acpi_op_add)) { |
1405 | status = acpi_start_single_object(child); | 1375 | status = acpi_start_single_object(child); |
1406 | if (ACPI_FAILURE(status)) | 1376 | if (ACPI_FAILURE(status)) |
1407 | continue; | 1377 | continue; |
1408 | } | 1378 | } |
1409 | 1379 | ||
1410 | /* | 1380 | /* |
1411 | * If the device is present, enabled, and functioning then | 1381 | * If the device is present, enabled, and functioning then |
1412 | * parse its scope (depth-first). Note that we need to | 1382 | * parse its scope (depth-first). Note that we need to |
1413 | * represent absent devices to facilitate PnP notifications | 1383 | * represent absent devices to facilitate PnP notifications |
1414 | * -- but only the subtree head (not all of its children, | 1384 | * -- but only the subtree head (not all of its children, |
1415 | * which will be enumerated when the parent is inserted). | 1385 | * which will be enumerated when the parent is inserted). |
1416 | * | 1386 | * |
1417 | * TBD: Need notifications and other detection mechanisms | 1387 | * TBD: Need notifications and other detection mechanisms |
1418 | * in place before we can fully implement this. | 1388 | * in place before we can fully implement this. |
1419 | */ | 1389 | */ |
1420 | /* | 1390 | /* |
1421 | * When the device is not present but functional, it is also | 1391 | * When the device is not present but functional, it is also |
1422 | * necessary to scan the children of this device. | 1392 | * necessary to scan the children of this device. |
1423 | */ | 1393 | */ |
1424 | if (child->status.present || (!child->status.present && | 1394 | if (child->status.present || (!child->status.present && |
1425 | child->status.functional)) { | 1395 | child->status.functional)) { |
1426 | status = acpi_get_next_object(ACPI_TYPE_ANY, chandle, | 1396 | status = acpi_get_next_object(ACPI_TYPE_ANY, chandle, |
1427 | NULL, NULL); | 1397 | NULL, NULL); |
1428 | if (ACPI_SUCCESS(status)) { | 1398 | if (ACPI_SUCCESS(status)) { |
1429 | level++; | 1399 | level++; |
1430 | phandle = chandle; | 1400 | phandle = chandle; |
1431 | chandle = NULL; | 1401 | chandle = NULL; |
1432 | parent = child; | 1402 | parent = child; |
1433 | } | 1403 | } |
1434 | } | 1404 | } |
1435 | } | 1405 | } |
1436 | 1406 | ||
1437 | return 0; | 1407 | return 0; |
1438 | } | 1408 | } |
1439 | 1409 | ||
1440 | int | 1410 | int |
1441 | acpi_bus_add(struct acpi_device **child, | 1411 | acpi_bus_add(struct acpi_device **child, |
1442 | struct acpi_device *parent, acpi_handle handle, int type) | 1412 | struct acpi_device *parent, acpi_handle handle, int type) |
1443 | { | 1413 | { |
1444 | int result; | 1414 | int result; |
1445 | struct acpi_bus_ops ops; | 1415 | struct acpi_bus_ops ops; |
1446 | 1416 | ||
1447 | memset(&ops, 0, sizeof(ops)); | 1417 | memset(&ops, 0, sizeof(ops)); |
1448 | ops.acpi_op_add = 1; | 1418 | ops.acpi_op_add = 1; |
1449 | 1419 | ||
1450 | result = acpi_add_single_object(child, parent, handle, type, &ops); | 1420 | result = acpi_add_single_object(child, parent, handle, type, &ops); |
1451 | if (!result) | 1421 | if (!result) |
1452 | result = acpi_bus_scan(*child, &ops); | 1422 | result = acpi_bus_scan(*child, &ops); |
1453 | 1423 | ||
1454 | return result; | 1424 | return result; |
1455 | } | 1425 | } |
1456 | 1426 | ||
1457 | EXPORT_SYMBOL(acpi_bus_add); | 1427 | EXPORT_SYMBOL(acpi_bus_add); |
1458 | 1428 | ||
1459 | int acpi_bus_start(struct acpi_device *device) | 1429 | int acpi_bus_start(struct acpi_device *device) |
1460 | { | 1430 | { |
1461 | int result; | 1431 | int result; |
1462 | struct acpi_bus_ops ops; | 1432 | struct acpi_bus_ops ops; |
1463 | 1433 | ||
1464 | 1434 | ||
1465 | if (!device) | 1435 | if (!device) |
1466 | return -EINVAL; | 1436 | return -EINVAL; |
1467 | 1437 | ||
1468 | result = acpi_start_single_object(device); | 1438 | result = acpi_start_single_object(device); |
1469 | if (!result) { | 1439 | if (!result) { |
1470 | memset(&ops, 0, sizeof(ops)); | 1440 | memset(&ops, 0, sizeof(ops)); |
1471 | ops.acpi_op_start = 1; | 1441 | ops.acpi_op_start = 1; |
1472 | result = acpi_bus_scan(device, &ops); | 1442 | result = acpi_bus_scan(device, &ops); |
1473 | } | 1443 | } |
1474 | return result; | 1444 | return result; |
1475 | } | 1445 | } |
1476 | 1446 | ||
1477 | EXPORT_SYMBOL(acpi_bus_start); | 1447 | EXPORT_SYMBOL(acpi_bus_start); |
1478 | 1448 | ||
1479 | int acpi_bus_trim(struct acpi_device *start, int rmdevice) | 1449 | int acpi_bus_trim(struct acpi_device *start, int rmdevice) |
1480 | { | 1450 | { |
1481 | acpi_status status; | 1451 | acpi_status status; |
1482 | struct acpi_device *parent, *child; | 1452 | struct acpi_device *parent, *child; |
1483 | acpi_handle phandle, chandle; | 1453 | acpi_handle phandle, chandle; |
1484 | acpi_object_type type; | 1454 | acpi_object_type type; |
1485 | u32 level = 1; | 1455 | u32 level = 1; |
1486 | int err = 0; | 1456 | int err = 0; |
1487 | 1457 | ||
1488 | parent = start; | 1458 | parent = start; |
1489 | phandle = start->handle; | 1459 | phandle = start->handle; |
1490 | child = chandle = NULL; | 1460 | child = chandle = NULL; |
1491 | 1461 | ||
1492 | while ((level > 0) && parent && (!err)) { | 1462 | while ((level > 0) && parent && (!err)) { |
1493 | status = acpi_get_next_object(ACPI_TYPE_ANY, phandle, | 1463 | status = acpi_get_next_object(ACPI_TYPE_ANY, phandle, |
1494 | chandle, &chandle); | 1464 | chandle, &chandle); |
1495 | 1465 | ||
1496 | /* | 1466 | /* |
1497 | * If this scope is exhausted then move our way back up. | 1467 | * If this scope is exhausted then move our way back up. |
1498 | */ | 1468 | */ |
1499 | if (ACPI_FAILURE(status)) { | 1469 | if (ACPI_FAILURE(status)) { |
1500 | level--; | 1470 | level--; |
1501 | chandle = phandle; | 1471 | chandle = phandle; |
1502 | acpi_get_parent(phandle, &phandle); | 1472 | acpi_get_parent(phandle, &phandle); |
1503 | child = parent; | 1473 | child = parent; |
1504 | parent = parent->parent; | 1474 | parent = parent->parent; |
1505 | 1475 | ||
1506 | if (level == 0) | 1476 | if (level == 0) |
1507 | err = acpi_bus_remove(child, rmdevice); | 1477 | err = acpi_bus_remove(child, rmdevice); |
1508 | else | 1478 | else |
1509 | err = acpi_bus_remove(child, 1); | 1479 | err = acpi_bus_remove(child, 1); |
1510 | 1480 | ||
1511 | continue; | 1481 | continue; |
1512 | } | 1482 | } |
1513 | 1483 | ||
1514 | status = acpi_get_type(chandle, &type); | 1484 | status = acpi_get_type(chandle, &type); |
1515 | if (ACPI_FAILURE(status)) { | 1485 | if (ACPI_FAILURE(status)) { |
1516 | continue; | 1486 | continue; |
1517 | } | 1487 | } |
1518 | /* | 1488 | /* |
1519 | * If there is a device corresponding to chandle then | 1489 | * If there is a device corresponding to chandle then |
1520 | * parse it (depth-first). | 1490 | * parse it (depth-first). |
1521 | */ | 1491 | */ |
1522 | if (acpi_bus_get_device(chandle, &child) == 0) { | 1492 | if (acpi_bus_get_device(chandle, &child) == 0) { |
1523 | level++; | 1493 | level++; |
1524 | phandle = chandle; | 1494 | phandle = chandle; |
1525 | chandle = NULL; | 1495 | chandle = NULL; |
1526 | parent = child; | 1496 | parent = child; |
1527 | } | 1497 | } |
1528 | continue; | 1498 | continue; |
1529 | } | 1499 | } |
1530 | return err; | 1500 | return err; |
1531 | } | 1501 | } |
1532 | EXPORT_SYMBOL_GPL(acpi_bus_trim); | 1502 | EXPORT_SYMBOL_GPL(acpi_bus_trim); |
1533 | 1503 | ||
1534 | 1504 | ||
1535 | static int acpi_bus_scan_fixed(struct acpi_device *root) | 1505 | static int acpi_bus_scan_fixed(struct acpi_device *root) |
1536 | { | 1506 | { |
1537 | int result = 0; | 1507 | int result = 0; |
1538 | struct acpi_device *device = NULL; | 1508 | struct acpi_device *device = NULL; |
1539 | struct acpi_bus_ops ops; | 1509 | struct acpi_bus_ops ops; |
1540 | 1510 | ||
1541 | if (!root) | 1511 | if (!root) |
1542 | return -ENODEV; | 1512 | return -ENODEV; |
1543 | 1513 | ||
1544 | memset(&ops, 0, sizeof(ops)); | 1514 | memset(&ops, 0, sizeof(ops)); |
1545 | ops.acpi_op_add = 1; | 1515 | ops.acpi_op_add = 1; |
1546 | ops.acpi_op_start = 1; | 1516 | ops.acpi_op_start = 1; |
1547 | 1517 | ||
1548 | /* | 1518 | /* |
1549 | * Enumerate all fixed-feature devices. | 1519 | * Enumerate all fixed-feature devices. |
1550 | */ | 1520 | */ |
1551 | if ((acpi_gbl_FADT.flags & ACPI_FADT_POWER_BUTTON) == 0) { | 1521 | if ((acpi_gbl_FADT.flags & ACPI_FADT_POWER_BUTTON) == 0) { |
1552 | result = acpi_add_single_object(&device, acpi_root, | 1522 | result = acpi_add_single_object(&device, acpi_root, |
1553 | NULL, | 1523 | NULL, |
1554 | ACPI_BUS_TYPE_POWER_BUTTON, | 1524 | ACPI_BUS_TYPE_POWER_BUTTON, |
1555 | &ops); | 1525 | &ops); |
1556 | } | 1526 | } |
1557 | 1527 | ||
1558 | if ((acpi_gbl_FADT.flags & ACPI_FADT_SLEEP_BUTTON) == 0) { | 1528 | if ((acpi_gbl_FADT.flags & ACPI_FADT_SLEEP_BUTTON) == 0) { |
1559 | result = acpi_add_single_object(&device, acpi_root, | 1529 | result = acpi_add_single_object(&device, acpi_root, |
1560 | NULL, | 1530 | NULL, |
1561 | ACPI_BUS_TYPE_SLEEP_BUTTON, | 1531 | ACPI_BUS_TYPE_SLEEP_BUTTON, |
1562 | &ops); | 1532 | &ops); |
1563 | } | 1533 | } |
1564 | 1534 | ||
1565 | return result; | 1535 | return result; |
1566 | } | 1536 | } |
1567 | 1537 | ||
1568 | 1538 | ||
1569 | static int __init acpi_scan_init(void) | 1539 | static int __init acpi_scan_init(void) |
1570 | { | 1540 | { |
1571 | int result; | 1541 | int result; |
1572 | struct acpi_bus_ops ops; | 1542 | struct acpi_bus_ops ops; |
1573 | 1543 | ||
1574 | 1544 | ||
1575 | if (acpi_disabled) | 1545 | if (acpi_disabled) |
1576 | return 0; | 1546 | return 0; |
1577 | 1547 | ||
1578 | memset(&ops, 0, sizeof(ops)); | 1548 | memset(&ops, 0, sizeof(ops)); |
1579 | ops.acpi_op_add = 1; | 1549 | ops.acpi_op_add = 1; |
1580 | ops.acpi_op_start = 1; | 1550 | ops.acpi_op_start = 1; |
1581 | 1551 | ||
1582 | result = bus_register(&acpi_bus_type); | 1552 | result = bus_register(&acpi_bus_type); |
1583 | if (result) { | 1553 | if (result) { |
1584 | /* We don't want to quit even if we failed to add suspend/resume */ | 1554 | /* We don't want to quit even if we failed to add suspend/resume */ |
1585 | printk(KERN_ERR PREFIX "Could not register bus type\n"); | 1555 | printk(KERN_ERR PREFIX "Could not register bus type\n"); |
1586 | } | 1556 | } |
1587 | 1557 | ||
1588 | /* | 1558 | /* |
1589 | * Create the root device in the bus's device tree | 1559 | * Create the root device in the bus's device tree |
1590 | */ | 1560 | */ |
1591 | result = acpi_add_single_object(&acpi_root, NULL, ACPI_ROOT_OBJECT, | 1561 | result = acpi_add_single_object(&acpi_root, NULL, ACPI_ROOT_OBJECT, |
1592 | ACPI_BUS_TYPE_SYSTEM, &ops); | 1562 | ACPI_BUS_TYPE_SYSTEM, &ops); |
1593 | if (result) | 1563 | if (result) |
1594 | goto Done; | 1564 | goto Done; |
1595 | 1565 | ||
1596 | /* | 1566 | /* |
1597 | * Enumerate devices in the ACPI namespace. | 1567 | * Enumerate devices in the ACPI namespace. |
1598 | */ | 1568 | */ |
1599 | result = acpi_bus_scan_fixed(acpi_root); | 1569 | result = acpi_bus_scan_fixed(acpi_root); |
1600 | 1570 | ||
1601 | if (!result) | 1571 | if (!result) |
1602 | result = acpi_bus_scan(acpi_root, &ops); | 1572 | result = acpi_bus_scan(acpi_root, &ops); |
1603 | 1573 | ||
1604 | if (result) | 1574 | if (result) |
1605 | acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL); | 1575 | acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL); |
1606 | 1576 | ||
1607 | Done: | 1577 | Done: |
1608 | return result; | 1578 | return result; |
1609 | } | 1579 | } |
1610 | 1580 | ||
1611 | subsys_initcall(acpi_scan_init); | 1581 | subsys_initcall(acpi_scan_init); |
1612 | 1582 |
drivers/acpi/video.c
1 | /* | 1 | /* |
2 | * video.c - ACPI Video Driver ($Revision:$) | 2 | * video.c - ACPI Video Driver ($Revision:$) |
3 | * | 3 | * |
4 | * Copyright (C) 2004 Luming Yu <luming.yu@intel.com> | 4 | * Copyright (C) 2004 Luming Yu <luming.yu@intel.com> |
5 | * Copyright (C) 2004 Bruno Ducrot <ducrot@poupinou.org> | 5 | * Copyright (C) 2004 Bruno Ducrot <ducrot@poupinou.org> |
6 | * Copyright (C) 2006 Thomas Tuttle <linux-kernel@ttuttle.net> | 6 | * Copyright (C) 2006 Thomas Tuttle <linux-kernel@ttuttle.net> |
7 | * | 7 | * |
8 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 8 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 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 | 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 (at | 12 | * the Free Software Foundation; either version 2 of the License, or (at |
13 | * your option) any later version. | 13 | * your option) any later version. |
14 | * | 14 | * |
15 | * This program is distributed in the hope that it will be useful, but | 15 | * This program is distributed in the hope that it will be useful, but |
16 | * WITHOUT ANY WARRANTY; without even the implied warranty of | 16 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
18 | * General Public License for more details. | 18 | * General Public License for more details. |
19 | * | 19 | * |
20 | * You should have received a copy of the GNU General Public License along | 20 | * You should have received a copy of the GNU General Public License along |
21 | * with this program; if not, write to the Free Software Foundation, Inc., | 21 | * with this program; if not, write to the Free Software Foundation, Inc., |
22 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | 22 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. |
23 | * | 23 | * |
24 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 24 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
25 | */ | 25 | */ |
26 | 26 | ||
27 | #include <linux/kernel.h> | 27 | #include <linux/kernel.h> |
28 | #include <linux/module.h> | 28 | #include <linux/module.h> |
29 | #include <linux/init.h> | 29 | #include <linux/init.h> |
30 | #include <linux/types.h> | 30 | #include <linux/types.h> |
31 | #include <linux/list.h> | 31 | #include <linux/list.h> |
32 | #include <linux/mutex.h> | 32 | #include <linux/mutex.h> |
33 | #include <linux/proc_fs.h> | 33 | #include <linux/proc_fs.h> |
34 | #include <linux/seq_file.h> | 34 | #include <linux/seq_file.h> |
35 | #include <linux/input.h> | 35 | #include <linux/input.h> |
36 | #include <linux/backlight.h> | 36 | #include <linux/backlight.h> |
37 | #include <linux/thermal.h> | 37 | #include <linux/thermal.h> |
38 | #include <linux/video_output.h> | 38 | #include <linux/video_output.h> |
39 | #include <asm/uaccess.h> | 39 | #include <asm/uaccess.h> |
40 | 40 | ||
41 | #include <acpi/acpi_bus.h> | 41 | #include <acpi/acpi_bus.h> |
42 | #include <acpi/acpi_drivers.h> | 42 | #include <acpi/acpi_drivers.h> |
43 | 43 | ||
44 | #define ACPI_VIDEO_CLASS "video" | 44 | #define ACPI_VIDEO_CLASS "video" |
45 | #define ACPI_VIDEO_BUS_NAME "Video Bus" | 45 | #define ACPI_VIDEO_BUS_NAME "Video Bus" |
46 | #define ACPI_VIDEO_DEVICE_NAME "Video Device" | 46 | #define ACPI_VIDEO_DEVICE_NAME "Video Device" |
47 | #define ACPI_VIDEO_NOTIFY_SWITCH 0x80 | 47 | #define ACPI_VIDEO_NOTIFY_SWITCH 0x80 |
48 | #define ACPI_VIDEO_NOTIFY_PROBE 0x81 | 48 | #define ACPI_VIDEO_NOTIFY_PROBE 0x81 |
49 | #define ACPI_VIDEO_NOTIFY_CYCLE 0x82 | 49 | #define ACPI_VIDEO_NOTIFY_CYCLE 0x82 |
50 | #define ACPI_VIDEO_NOTIFY_NEXT_OUTPUT 0x83 | 50 | #define ACPI_VIDEO_NOTIFY_NEXT_OUTPUT 0x83 |
51 | #define ACPI_VIDEO_NOTIFY_PREV_OUTPUT 0x84 | 51 | #define ACPI_VIDEO_NOTIFY_PREV_OUTPUT 0x84 |
52 | 52 | ||
53 | #define ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS 0x85 | 53 | #define ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS 0x85 |
54 | #define ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS 0x86 | 54 | #define ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS 0x86 |
55 | #define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS 0x87 | 55 | #define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS 0x87 |
56 | #define ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS 0x88 | 56 | #define ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS 0x88 |
57 | #define ACPI_VIDEO_NOTIFY_DISPLAY_OFF 0x89 | 57 | #define ACPI_VIDEO_NOTIFY_DISPLAY_OFF 0x89 |
58 | 58 | ||
59 | #define MAX_NAME_LEN 20 | 59 | #define MAX_NAME_LEN 20 |
60 | 60 | ||
61 | #define ACPI_VIDEO_DISPLAY_CRT 1 | 61 | #define ACPI_VIDEO_DISPLAY_CRT 1 |
62 | #define ACPI_VIDEO_DISPLAY_TV 2 | 62 | #define ACPI_VIDEO_DISPLAY_TV 2 |
63 | #define ACPI_VIDEO_DISPLAY_DVI 3 | 63 | #define ACPI_VIDEO_DISPLAY_DVI 3 |
64 | #define ACPI_VIDEO_DISPLAY_LCD 4 | 64 | #define ACPI_VIDEO_DISPLAY_LCD 4 |
65 | 65 | ||
66 | #define _COMPONENT ACPI_VIDEO_COMPONENT | 66 | #define _COMPONENT ACPI_VIDEO_COMPONENT |
67 | ACPI_MODULE_NAME("video"); | 67 | ACPI_MODULE_NAME("video"); |
68 | 68 | ||
69 | MODULE_AUTHOR("Bruno Ducrot"); | 69 | MODULE_AUTHOR("Bruno Ducrot"); |
70 | MODULE_DESCRIPTION("ACPI Video Driver"); | 70 | MODULE_DESCRIPTION("ACPI Video Driver"); |
71 | MODULE_LICENSE("GPL"); | 71 | MODULE_LICENSE("GPL"); |
72 | 72 | ||
73 | static int brightness_switch_enabled = 1; | 73 | static int brightness_switch_enabled = 1; |
74 | module_param(brightness_switch_enabled, bool, 0644); | 74 | module_param(brightness_switch_enabled, bool, 0644); |
75 | 75 | ||
76 | static int acpi_video_bus_add(struct acpi_device *device); | 76 | static int acpi_video_bus_add(struct acpi_device *device); |
77 | static int acpi_video_bus_remove(struct acpi_device *device, int type); | 77 | static int acpi_video_bus_remove(struct acpi_device *device, int type); |
78 | static int acpi_video_resume(struct acpi_device *device); | 78 | static int acpi_video_resume(struct acpi_device *device); |
79 | 79 | ||
80 | static const struct acpi_device_id video_device_ids[] = { | 80 | static const struct acpi_device_id video_device_ids[] = { |
81 | {ACPI_VIDEO_HID, 0}, | 81 | {ACPI_VIDEO_HID, 0}, |
82 | {"", 0}, | 82 | {"", 0}, |
83 | }; | 83 | }; |
84 | MODULE_DEVICE_TABLE(acpi, video_device_ids); | 84 | MODULE_DEVICE_TABLE(acpi, video_device_ids); |
85 | 85 | ||
86 | static struct acpi_driver acpi_video_bus = { | 86 | static struct acpi_driver acpi_video_bus = { |
87 | .name = "video", | 87 | .name = "video", |
88 | .class = ACPI_VIDEO_CLASS, | 88 | .class = ACPI_VIDEO_CLASS, |
89 | .ids = video_device_ids, | 89 | .ids = video_device_ids, |
90 | .ops = { | 90 | .ops = { |
91 | .add = acpi_video_bus_add, | 91 | .add = acpi_video_bus_add, |
92 | .remove = acpi_video_bus_remove, | 92 | .remove = acpi_video_bus_remove, |
93 | .resume = acpi_video_resume, | 93 | .resume = acpi_video_resume, |
94 | }, | 94 | }, |
95 | }; | 95 | }; |
96 | 96 | ||
97 | struct acpi_video_bus_flags { | 97 | struct acpi_video_bus_flags { |
98 | u8 multihead:1; /* can switch video heads */ | 98 | u8 multihead:1; /* can switch video heads */ |
99 | u8 rom:1; /* can retrieve a video rom */ | 99 | u8 rom:1; /* can retrieve a video rom */ |
100 | u8 post:1; /* can configure the head to */ | 100 | u8 post:1; /* can configure the head to */ |
101 | u8 reserved:5; | 101 | u8 reserved:5; |
102 | }; | 102 | }; |
103 | 103 | ||
104 | struct acpi_video_bus_cap { | 104 | struct acpi_video_bus_cap { |
105 | u8 _DOS:1; /*Enable/Disable output switching */ | 105 | u8 _DOS:1; /*Enable/Disable output switching */ |
106 | u8 _DOD:1; /*Enumerate all devices attached to display adapter */ | 106 | u8 _DOD:1; /*Enumerate all devices attached to display adapter */ |
107 | u8 _ROM:1; /*Get ROM Data */ | 107 | u8 _ROM:1; /*Get ROM Data */ |
108 | u8 _GPD:1; /*Get POST Device */ | 108 | u8 _GPD:1; /*Get POST Device */ |
109 | u8 _SPD:1; /*Set POST Device */ | 109 | u8 _SPD:1; /*Set POST Device */ |
110 | u8 _VPO:1; /*Video POST Options */ | 110 | u8 _VPO:1; /*Video POST Options */ |
111 | u8 reserved:2; | 111 | u8 reserved:2; |
112 | }; | 112 | }; |
113 | 113 | ||
114 | struct acpi_video_device_attrib { | 114 | struct acpi_video_device_attrib { |
115 | u32 display_index:4; /* A zero-based instance of the Display */ | 115 | u32 display_index:4; /* A zero-based instance of the Display */ |
116 | u32 display_port_attachment:4; /*This field differentiates the display type */ | 116 | u32 display_port_attachment:4; /*This field differentiates the display type */ |
117 | u32 display_type:4; /*Describe the specific type in use */ | 117 | u32 display_type:4; /*Describe the specific type in use */ |
118 | u32 vendor_specific:4; /*Chipset Vendor Specific */ | 118 | u32 vendor_specific:4; /*Chipset Vendor Specific */ |
119 | u32 bios_can_detect:1; /*BIOS can detect the device */ | 119 | u32 bios_can_detect:1; /*BIOS can detect the device */ |
120 | u32 depend_on_vga:1; /*Non-VGA output device whose power is related to | 120 | u32 depend_on_vga:1; /*Non-VGA output device whose power is related to |
121 | the VGA device. */ | 121 | the VGA device. */ |
122 | u32 pipe_id:3; /*For VGA multiple-head devices. */ | 122 | u32 pipe_id:3; /*For VGA multiple-head devices. */ |
123 | u32 reserved:10; /*Must be 0 */ | 123 | u32 reserved:10; /*Must be 0 */ |
124 | u32 device_id_scheme:1; /*Device ID Scheme */ | 124 | u32 device_id_scheme:1; /*Device ID Scheme */ |
125 | }; | 125 | }; |
126 | 126 | ||
127 | struct acpi_video_enumerated_device { | 127 | struct acpi_video_enumerated_device { |
128 | union { | 128 | union { |
129 | u32 int_val; | 129 | u32 int_val; |
130 | struct acpi_video_device_attrib attrib; | 130 | struct acpi_video_device_attrib attrib; |
131 | } value; | 131 | } value; |
132 | struct acpi_video_device *bind_info; | 132 | struct acpi_video_device *bind_info; |
133 | }; | 133 | }; |
134 | 134 | ||
135 | struct acpi_video_bus { | 135 | struct acpi_video_bus { |
136 | struct acpi_device *device; | 136 | struct acpi_device *device; |
137 | u8 dos_setting; | 137 | u8 dos_setting; |
138 | struct acpi_video_enumerated_device *attached_array; | 138 | struct acpi_video_enumerated_device *attached_array; |
139 | u8 attached_count; | 139 | u8 attached_count; |
140 | struct acpi_video_bus_cap cap; | 140 | struct acpi_video_bus_cap cap; |
141 | struct acpi_video_bus_flags flags; | 141 | struct acpi_video_bus_flags flags; |
142 | struct list_head video_device_list; | 142 | struct list_head video_device_list; |
143 | struct mutex device_list_lock; /* protects video_device_list */ | 143 | struct mutex device_list_lock; /* protects video_device_list */ |
144 | struct proc_dir_entry *dir; | 144 | struct proc_dir_entry *dir; |
145 | struct input_dev *input; | 145 | struct input_dev *input; |
146 | char phys[32]; /* for input device */ | 146 | char phys[32]; /* for input device */ |
147 | }; | 147 | }; |
148 | 148 | ||
149 | struct acpi_video_device_flags { | 149 | struct acpi_video_device_flags { |
150 | u8 crt:1; | 150 | u8 crt:1; |
151 | u8 lcd:1; | 151 | u8 lcd:1; |
152 | u8 tvout:1; | 152 | u8 tvout:1; |
153 | u8 dvi:1; | 153 | u8 dvi:1; |
154 | u8 bios:1; | 154 | u8 bios:1; |
155 | u8 unknown:1; | 155 | u8 unknown:1; |
156 | u8 reserved:2; | 156 | u8 reserved:2; |
157 | }; | 157 | }; |
158 | 158 | ||
159 | struct acpi_video_device_cap { | 159 | struct acpi_video_device_cap { |
160 | u8 _ADR:1; /*Return the unique ID */ | 160 | u8 _ADR:1; /*Return the unique ID */ |
161 | u8 _BCL:1; /*Query list of brightness control levels supported */ | 161 | u8 _BCL:1; /*Query list of brightness control levels supported */ |
162 | u8 _BCM:1; /*Set the brightness level */ | 162 | u8 _BCM:1; /*Set the brightness level */ |
163 | u8 _BQC:1; /* Get current brightness level */ | 163 | u8 _BQC:1; /* Get current brightness level */ |
164 | u8 _DDC:1; /*Return the EDID for this device */ | 164 | u8 _DDC:1; /*Return the EDID for this device */ |
165 | u8 _DCS:1; /*Return status of output device */ | 165 | u8 _DCS:1; /*Return status of output device */ |
166 | u8 _DGS:1; /*Query graphics state */ | 166 | u8 _DGS:1; /*Query graphics state */ |
167 | u8 _DSS:1; /*Device state set */ | 167 | u8 _DSS:1; /*Device state set */ |
168 | }; | 168 | }; |
169 | 169 | ||
170 | struct acpi_video_device_brightness { | 170 | struct acpi_video_device_brightness { |
171 | int curr; | 171 | int curr; |
172 | int count; | 172 | int count; |
173 | int *levels; | 173 | int *levels; |
174 | }; | 174 | }; |
175 | 175 | ||
176 | struct acpi_video_device { | 176 | struct acpi_video_device { |
177 | unsigned long device_id; | 177 | unsigned long device_id; |
178 | struct acpi_video_device_flags flags; | 178 | struct acpi_video_device_flags flags; |
179 | struct acpi_video_device_cap cap; | 179 | struct acpi_video_device_cap cap; |
180 | struct list_head entry; | 180 | struct list_head entry; |
181 | struct acpi_video_bus *video; | 181 | struct acpi_video_bus *video; |
182 | struct acpi_device *dev; | 182 | struct acpi_device *dev; |
183 | struct acpi_video_device_brightness *brightness; | 183 | struct acpi_video_device_brightness *brightness; |
184 | struct backlight_device *backlight; | 184 | struct backlight_device *backlight; |
185 | struct thermal_cooling_device *cdev; | 185 | struct thermal_cooling_device *cdev; |
186 | struct output_device *output_dev; | 186 | struct output_device *output_dev; |
187 | }; | 187 | }; |
188 | 188 | ||
189 | /* bus */ | 189 | /* bus */ |
190 | static int acpi_video_bus_info_open_fs(struct inode *inode, struct file *file); | 190 | static int acpi_video_bus_info_open_fs(struct inode *inode, struct file *file); |
191 | static struct file_operations acpi_video_bus_info_fops = { | 191 | static struct file_operations acpi_video_bus_info_fops = { |
192 | .owner = THIS_MODULE, | 192 | .owner = THIS_MODULE, |
193 | .open = acpi_video_bus_info_open_fs, | 193 | .open = acpi_video_bus_info_open_fs, |
194 | .read = seq_read, | 194 | .read = seq_read, |
195 | .llseek = seq_lseek, | 195 | .llseek = seq_lseek, |
196 | .release = single_release, | 196 | .release = single_release, |
197 | }; | 197 | }; |
198 | 198 | ||
199 | static int acpi_video_bus_ROM_open_fs(struct inode *inode, struct file *file); | 199 | static int acpi_video_bus_ROM_open_fs(struct inode *inode, struct file *file); |
200 | static struct file_operations acpi_video_bus_ROM_fops = { | 200 | static struct file_operations acpi_video_bus_ROM_fops = { |
201 | .owner = THIS_MODULE, | 201 | .owner = THIS_MODULE, |
202 | .open = acpi_video_bus_ROM_open_fs, | 202 | .open = acpi_video_bus_ROM_open_fs, |
203 | .read = seq_read, | 203 | .read = seq_read, |
204 | .llseek = seq_lseek, | 204 | .llseek = seq_lseek, |
205 | .release = single_release, | 205 | .release = single_release, |
206 | }; | 206 | }; |
207 | 207 | ||
208 | static int acpi_video_bus_POST_info_open_fs(struct inode *inode, | 208 | static int acpi_video_bus_POST_info_open_fs(struct inode *inode, |
209 | struct file *file); | 209 | struct file *file); |
210 | static struct file_operations acpi_video_bus_POST_info_fops = { | 210 | static struct file_operations acpi_video_bus_POST_info_fops = { |
211 | .owner = THIS_MODULE, | 211 | .owner = THIS_MODULE, |
212 | .open = acpi_video_bus_POST_info_open_fs, | 212 | .open = acpi_video_bus_POST_info_open_fs, |
213 | .read = seq_read, | 213 | .read = seq_read, |
214 | .llseek = seq_lseek, | 214 | .llseek = seq_lseek, |
215 | .release = single_release, | 215 | .release = single_release, |
216 | }; | 216 | }; |
217 | 217 | ||
218 | static int acpi_video_bus_POST_open_fs(struct inode *inode, struct file *file); | 218 | static int acpi_video_bus_POST_open_fs(struct inode *inode, struct file *file); |
219 | static struct file_operations acpi_video_bus_POST_fops = { | 219 | static struct file_operations acpi_video_bus_POST_fops = { |
220 | .owner = THIS_MODULE, | 220 | .owner = THIS_MODULE, |
221 | .open = acpi_video_bus_POST_open_fs, | 221 | .open = acpi_video_bus_POST_open_fs, |
222 | .read = seq_read, | 222 | .read = seq_read, |
223 | .llseek = seq_lseek, | 223 | .llseek = seq_lseek, |
224 | .release = single_release, | 224 | .release = single_release, |
225 | }; | 225 | }; |
226 | 226 | ||
227 | static int acpi_video_bus_DOS_open_fs(struct inode *inode, struct file *file); | 227 | static int acpi_video_bus_DOS_open_fs(struct inode *inode, struct file *file); |
228 | static struct file_operations acpi_video_bus_DOS_fops = { | 228 | static struct file_operations acpi_video_bus_DOS_fops = { |
229 | .owner = THIS_MODULE, | 229 | .owner = THIS_MODULE, |
230 | .open = acpi_video_bus_DOS_open_fs, | 230 | .open = acpi_video_bus_DOS_open_fs, |
231 | .read = seq_read, | 231 | .read = seq_read, |
232 | .llseek = seq_lseek, | 232 | .llseek = seq_lseek, |
233 | .release = single_release, | 233 | .release = single_release, |
234 | }; | 234 | }; |
235 | 235 | ||
236 | /* device */ | 236 | /* device */ |
237 | static int acpi_video_device_info_open_fs(struct inode *inode, | 237 | static int acpi_video_device_info_open_fs(struct inode *inode, |
238 | struct file *file); | 238 | struct file *file); |
239 | static struct file_operations acpi_video_device_info_fops = { | 239 | static struct file_operations acpi_video_device_info_fops = { |
240 | .owner = THIS_MODULE, | 240 | .owner = THIS_MODULE, |
241 | .open = acpi_video_device_info_open_fs, | 241 | .open = acpi_video_device_info_open_fs, |
242 | .read = seq_read, | 242 | .read = seq_read, |
243 | .llseek = seq_lseek, | 243 | .llseek = seq_lseek, |
244 | .release = single_release, | 244 | .release = single_release, |
245 | }; | 245 | }; |
246 | 246 | ||
247 | static int acpi_video_device_state_open_fs(struct inode *inode, | 247 | static int acpi_video_device_state_open_fs(struct inode *inode, |
248 | struct file *file); | 248 | struct file *file); |
249 | static struct file_operations acpi_video_device_state_fops = { | 249 | static struct file_operations acpi_video_device_state_fops = { |
250 | .owner = THIS_MODULE, | 250 | .owner = THIS_MODULE, |
251 | .open = acpi_video_device_state_open_fs, | 251 | .open = acpi_video_device_state_open_fs, |
252 | .read = seq_read, | 252 | .read = seq_read, |
253 | .llseek = seq_lseek, | 253 | .llseek = seq_lseek, |
254 | .release = single_release, | 254 | .release = single_release, |
255 | }; | 255 | }; |
256 | 256 | ||
257 | static int acpi_video_device_brightness_open_fs(struct inode *inode, | 257 | static int acpi_video_device_brightness_open_fs(struct inode *inode, |
258 | struct file *file); | 258 | struct file *file); |
259 | static struct file_operations acpi_video_device_brightness_fops = { | 259 | static struct file_operations acpi_video_device_brightness_fops = { |
260 | .owner = THIS_MODULE, | 260 | .owner = THIS_MODULE, |
261 | .open = acpi_video_device_brightness_open_fs, | 261 | .open = acpi_video_device_brightness_open_fs, |
262 | .read = seq_read, | 262 | .read = seq_read, |
263 | .llseek = seq_lseek, | 263 | .llseek = seq_lseek, |
264 | .release = single_release, | 264 | .release = single_release, |
265 | }; | 265 | }; |
266 | 266 | ||
267 | static int acpi_video_device_EDID_open_fs(struct inode *inode, | 267 | static int acpi_video_device_EDID_open_fs(struct inode *inode, |
268 | struct file *file); | 268 | struct file *file); |
269 | static struct file_operations acpi_video_device_EDID_fops = { | 269 | static struct file_operations acpi_video_device_EDID_fops = { |
270 | .owner = THIS_MODULE, | 270 | .owner = THIS_MODULE, |
271 | .open = acpi_video_device_EDID_open_fs, | 271 | .open = acpi_video_device_EDID_open_fs, |
272 | .read = seq_read, | 272 | .read = seq_read, |
273 | .llseek = seq_lseek, | 273 | .llseek = seq_lseek, |
274 | .release = single_release, | 274 | .release = single_release, |
275 | }; | 275 | }; |
276 | 276 | ||
277 | static char device_decode[][30] = { | 277 | static char device_decode[][30] = { |
278 | "motherboard VGA device", | 278 | "motherboard VGA device", |
279 | "PCI VGA device", | 279 | "PCI VGA device", |
280 | "AGP VGA device", | 280 | "AGP VGA device", |
281 | "UNKNOWN", | 281 | "UNKNOWN", |
282 | }; | 282 | }; |
283 | 283 | ||
284 | static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data); | 284 | static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data); |
285 | static void acpi_video_device_rebind(struct acpi_video_bus *video); | 285 | static void acpi_video_device_rebind(struct acpi_video_bus *video); |
286 | static void acpi_video_device_bind(struct acpi_video_bus *video, | 286 | static void acpi_video_device_bind(struct acpi_video_bus *video, |
287 | struct acpi_video_device *device); | 287 | struct acpi_video_device *device); |
288 | static int acpi_video_device_enumerate(struct acpi_video_bus *video); | 288 | static int acpi_video_device_enumerate(struct acpi_video_bus *video); |
289 | static int acpi_video_device_lcd_set_level(struct acpi_video_device *device, | 289 | static int acpi_video_device_lcd_set_level(struct acpi_video_device *device, |
290 | int level); | 290 | int level); |
291 | static int acpi_video_device_lcd_get_level_current( | 291 | static int acpi_video_device_lcd_get_level_current( |
292 | struct acpi_video_device *device, | 292 | struct acpi_video_device *device, |
293 | unsigned long long *level); | 293 | unsigned long long *level); |
294 | static int acpi_video_get_next_level(struct acpi_video_device *device, | 294 | static int acpi_video_get_next_level(struct acpi_video_device *device, |
295 | u32 level_current, u32 event); | 295 | u32 level_current, u32 event); |
296 | static void acpi_video_switch_brightness(struct acpi_video_device *device, | 296 | static void acpi_video_switch_brightness(struct acpi_video_device *device, |
297 | int event); | 297 | int event); |
298 | static int acpi_video_device_get_state(struct acpi_video_device *device, | 298 | static int acpi_video_device_get_state(struct acpi_video_device *device, |
299 | unsigned long long *state); | 299 | unsigned long long *state); |
300 | static int acpi_video_output_get(struct output_device *od); | 300 | static int acpi_video_output_get(struct output_device *od); |
301 | static int acpi_video_device_set_state(struct acpi_video_device *device, int state); | 301 | static int acpi_video_device_set_state(struct acpi_video_device *device, int state); |
302 | 302 | ||
303 | /*backlight device sysfs support*/ | 303 | /*backlight device sysfs support*/ |
304 | static int acpi_video_get_brightness(struct backlight_device *bd) | 304 | static int acpi_video_get_brightness(struct backlight_device *bd) |
305 | { | 305 | { |
306 | unsigned long long cur_level; | 306 | unsigned long long cur_level; |
307 | int i; | 307 | int i; |
308 | struct acpi_video_device *vd = | 308 | struct acpi_video_device *vd = |
309 | (struct acpi_video_device *)bl_get_data(bd); | 309 | (struct acpi_video_device *)bl_get_data(bd); |
310 | acpi_video_device_lcd_get_level_current(vd, &cur_level); | 310 | acpi_video_device_lcd_get_level_current(vd, &cur_level); |
311 | for (i = 2; i < vd->brightness->count; i++) { | 311 | for (i = 2; i < vd->brightness->count; i++) { |
312 | if (vd->brightness->levels[i] == cur_level) | 312 | if (vd->brightness->levels[i] == cur_level) |
313 | /* The first two entries are special - see page 575 | 313 | /* The first two entries are special - see page 575 |
314 | of the ACPI spec 3.0 */ | 314 | of the ACPI spec 3.0 */ |
315 | return i-2; | 315 | return i-2; |
316 | } | 316 | } |
317 | return 0; | 317 | return 0; |
318 | } | 318 | } |
319 | 319 | ||
320 | static int acpi_video_set_brightness(struct backlight_device *bd) | 320 | static int acpi_video_set_brightness(struct backlight_device *bd) |
321 | { | 321 | { |
322 | int request_level = bd->props.brightness+2; | 322 | int request_level = bd->props.brightness+2; |
323 | struct acpi_video_device *vd = | 323 | struct acpi_video_device *vd = |
324 | (struct acpi_video_device *)bl_get_data(bd); | 324 | (struct acpi_video_device *)bl_get_data(bd); |
325 | acpi_video_device_lcd_set_level(vd, | 325 | acpi_video_device_lcd_set_level(vd, |
326 | vd->brightness->levels[request_level]); | 326 | vd->brightness->levels[request_level]); |
327 | return 0; | 327 | return 0; |
328 | } | 328 | } |
329 | 329 | ||
330 | static struct backlight_ops acpi_backlight_ops = { | 330 | static struct backlight_ops acpi_backlight_ops = { |
331 | .get_brightness = acpi_video_get_brightness, | 331 | .get_brightness = acpi_video_get_brightness, |
332 | .update_status = acpi_video_set_brightness, | 332 | .update_status = acpi_video_set_brightness, |
333 | }; | 333 | }; |
334 | 334 | ||
335 | /*video output device sysfs support*/ | 335 | /*video output device sysfs support*/ |
336 | static int acpi_video_output_get(struct output_device *od) | 336 | static int acpi_video_output_get(struct output_device *od) |
337 | { | 337 | { |
338 | unsigned long long state; | 338 | unsigned long long state; |
339 | struct acpi_video_device *vd = | 339 | struct acpi_video_device *vd = |
340 | (struct acpi_video_device *)dev_get_drvdata(&od->dev); | 340 | (struct acpi_video_device *)dev_get_drvdata(&od->dev); |
341 | acpi_video_device_get_state(vd, &state); | 341 | acpi_video_device_get_state(vd, &state); |
342 | return (int)state; | 342 | return (int)state; |
343 | } | 343 | } |
344 | 344 | ||
345 | static int acpi_video_output_set(struct output_device *od) | 345 | static int acpi_video_output_set(struct output_device *od) |
346 | { | 346 | { |
347 | unsigned long state = od->request_state; | 347 | unsigned long state = od->request_state; |
348 | struct acpi_video_device *vd= | 348 | struct acpi_video_device *vd= |
349 | (struct acpi_video_device *)dev_get_drvdata(&od->dev); | 349 | (struct acpi_video_device *)dev_get_drvdata(&od->dev); |
350 | return acpi_video_device_set_state(vd, state); | 350 | return acpi_video_device_set_state(vd, state); |
351 | } | 351 | } |
352 | 352 | ||
353 | static struct output_properties acpi_output_properties = { | 353 | static struct output_properties acpi_output_properties = { |
354 | .set_state = acpi_video_output_set, | 354 | .set_state = acpi_video_output_set, |
355 | .get_status = acpi_video_output_get, | 355 | .get_status = acpi_video_output_get, |
356 | }; | 356 | }; |
357 | 357 | ||
358 | 358 | ||
359 | /* thermal cooling device callbacks */ | 359 | /* thermal cooling device callbacks */ |
360 | static int video_get_max_state(struct thermal_cooling_device *cdev, char *buf) | 360 | static int video_get_max_state(struct thermal_cooling_device *cdev, char *buf) |
361 | { | 361 | { |
362 | struct acpi_device *device = cdev->devdata; | 362 | struct acpi_device *device = cdev->devdata; |
363 | struct acpi_video_device *video = acpi_driver_data(device); | 363 | struct acpi_video_device *video = acpi_driver_data(device); |
364 | 364 | ||
365 | return sprintf(buf, "%d\n", video->brightness->count - 3); | 365 | return sprintf(buf, "%d\n", video->brightness->count - 3); |
366 | } | 366 | } |
367 | 367 | ||
368 | static int video_get_cur_state(struct thermal_cooling_device *cdev, char *buf) | 368 | static int video_get_cur_state(struct thermal_cooling_device *cdev, char *buf) |
369 | { | 369 | { |
370 | struct acpi_device *device = cdev->devdata; | 370 | struct acpi_device *device = cdev->devdata; |
371 | struct acpi_video_device *video = acpi_driver_data(device); | 371 | struct acpi_video_device *video = acpi_driver_data(device); |
372 | unsigned long long level; | 372 | unsigned long long level; |
373 | int state; | 373 | int state; |
374 | 374 | ||
375 | acpi_video_device_lcd_get_level_current(video, &level); | 375 | acpi_video_device_lcd_get_level_current(video, &level); |
376 | for (state = 2; state < video->brightness->count; state++) | 376 | for (state = 2; state < video->brightness->count; state++) |
377 | if (level == video->brightness->levels[state]) | 377 | if (level == video->brightness->levels[state]) |
378 | return sprintf(buf, "%d\n", | 378 | return sprintf(buf, "%d\n", |
379 | video->brightness->count - state - 1); | 379 | video->brightness->count - state - 1); |
380 | 380 | ||
381 | return -EINVAL; | 381 | return -EINVAL; |
382 | } | 382 | } |
383 | 383 | ||
384 | static int | 384 | static int |
385 | video_set_cur_state(struct thermal_cooling_device *cdev, unsigned int state) | 385 | video_set_cur_state(struct thermal_cooling_device *cdev, unsigned int state) |
386 | { | 386 | { |
387 | struct acpi_device *device = cdev->devdata; | 387 | struct acpi_device *device = cdev->devdata; |
388 | struct acpi_video_device *video = acpi_driver_data(device); | 388 | struct acpi_video_device *video = acpi_driver_data(device); |
389 | int level; | 389 | int level; |
390 | 390 | ||
391 | if ( state >= video->brightness->count - 2) | 391 | if ( state >= video->brightness->count - 2) |
392 | return -EINVAL; | 392 | return -EINVAL; |
393 | 393 | ||
394 | state = video->brightness->count - state; | 394 | state = video->brightness->count - state; |
395 | level = video->brightness->levels[state -1]; | 395 | level = video->brightness->levels[state -1]; |
396 | return acpi_video_device_lcd_set_level(video, level); | 396 | return acpi_video_device_lcd_set_level(video, level); |
397 | } | 397 | } |
398 | 398 | ||
399 | static struct thermal_cooling_device_ops video_cooling_ops = { | 399 | static struct thermal_cooling_device_ops video_cooling_ops = { |
400 | .get_max_state = video_get_max_state, | 400 | .get_max_state = video_get_max_state, |
401 | .get_cur_state = video_get_cur_state, | 401 | .get_cur_state = video_get_cur_state, |
402 | .set_cur_state = video_set_cur_state, | 402 | .set_cur_state = video_set_cur_state, |
403 | }; | 403 | }; |
404 | 404 | ||
405 | /* -------------------------------------------------------------------------- | 405 | /* -------------------------------------------------------------------------- |
406 | Video Management | 406 | Video Management |
407 | -------------------------------------------------------------------------- */ | 407 | -------------------------------------------------------------------------- */ |
408 | 408 | ||
409 | /* device */ | 409 | /* device */ |
410 | 410 | ||
411 | static int | 411 | static int |
412 | acpi_video_device_query(struct acpi_video_device *device, unsigned long long *state) | 412 | acpi_video_device_query(struct acpi_video_device *device, unsigned long long *state) |
413 | { | 413 | { |
414 | int status; | 414 | int status; |
415 | 415 | ||
416 | status = acpi_evaluate_integer(device->dev->handle, "_DGS", NULL, state); | 416 | status = acpi_evaluate_integer(device->dev->handle, "_DGS", NULL, state); |
417 | 417 | ||
418 | return status; | 418 | return status; |
419 | } | 419 | } |
420 | 420 | ||
421 | static int | 421 | static int |
422 | acpi_video_device_get_state(struct acpi_video_device *device, | 422 | acpi_video_device_get_state(struct acpi_video_device *device, |
423 | unsigned long long *state) | 423 | unsigned long long *state) |
424 | { | 424 | { |
425 | int status; | 425 | int status; |
426 | 426 | ||
427 | status = acpi_evaluate_integer(device->dev->handle, "_DCS", NULL, state); | 427 | status = acpi_evaluate_integer(device->dev->handle, "_DCS", NULL, state); |
428 | 428 | ||
429 | return status; | 429 | return status; |
430 | } | 430 | } |
431 | 431 | ||
432 | static int | 432 | static int |
433 | acpi_video_device_set_state(struct acpi_video_device *device, int state) | 433 | acpi_video_device_set_state(struct acpi_video_device *device, int state) |
434 | { | 434 | { |
435 | int status; | 435 | int status; |
436 | union acpi_object arg0 = { ACPI_TYPE_INTEGER }; | 436 | union acpi_object arg0 = { ACPI_TYPE_INTEGER }; |
437 | struct acpi_object_list args = { 1, &arg0 }; | 437 | struct acpi_object_list args = { 1, &arg0 }; |
438 | unsigned long long ret; | 438 | unsigned long long ret; |
439 | 439 | ||
440 | 440 | ||
441 | arg0.integer.value = state; | 441 | arg0.integer.value = state; |
442 | status = acpi_evaluate_integer(device->dev->handle, "_DSS", &args, &ret); | 442 | status = acpi_evaluate_integer(device->dev->handle, "_DSS", &args, &ret); |
443 | 443 | ||
444 | return status; | 444 | return status; |
445 | } | 445 | } |
446 | 446 | ||
447 | static int | 447 | static int |
448 | acpi_video_device_lcd_query_levels(struct acpi_video_device *device, | 448 | acpi_video_device_lcd_query_levels(struct acpi_video_device *device, |
449 | union acpi_object **levels) | 449 | union acpi_object **levels) |
450 | { | 450 | { |
451 | int status; | 451 | int status; |
452 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | 452 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
453 | union acpi_object *obj; | 453 | union acpi_object *obj; |
454 | 454 | ||
455 | 455 | ||
456 | *levels = NULL; | 456 | *levels = NULL; |
457 | 457 | ||
458 | status = acpi_evaluate_object(device->dev->handle, "_BCL", NULL, &buffer); | 458 | status = acpi_evaluate_object(device->dev->handle, "_BCL", NULL, &buffer); |
459 | if (!ACPI_SUCCESS(status)) | 459 | if (!ACPI_SUCCESS(status)) |
460 | return status; | 460 | return status; |
461 | obj = (union acpi_object *)buffer.pointer; | 461 | obj = (union acpi_object *)buffer.pointer; |
462 | if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) { | 462 | if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) { |
463 | printk(KERN_ERR PREFIX "Invalid _BCL data\n"); | 463 | printk(KERN_ERR PREFIX "Invalid _BCL data\n"); |
464 | status = -EFAULT; | 464 | status = -EFAULT; |
465 | goto err; | 465 | goto err; |
466 | } | 466 | } |
467 | 467 | ||
468 | *levels = obj; | 468 | *levels = obj; |
469 | 469 | ||
470 | return 0; | 470 | return 0; |
471 | 471 | ||
472 | err: | 472 | err: |
473 | kfree(buffer.pointer); | 473 | kfree(buffer.pointer); |
474 | 474 | ||
475 | return status; | 475 | return status; |
476 | } | 476 | } |
477 | 477 | ||
478 | static int | 478 | static int |
479 | acpi_video_device_lcd_set_level(struct acpi_video_device *device, int level) | 479 | acpi_video_device_lcd_set_level(struct acpi_video_device *device, int level) |
480 | { | 480 | { |
481 | int status = AE_OK; | 481 | int status = AE_OK; |
482 | union acpi_object arg0 = { ACPI_TYPE_INTEGER }; | 482 | union acpi_object arg0 = { ACPI_TYPE_INTEGER }; |
483 | struct acpi_object_list args = { 1, &arg0 }; | 483 | struct acpi_object_list args = { 1, &arg0 }; |
484 | 484 | ||
485 | 485 | ||
486 | arg0.integer.value = level; | 486 | arg0.integer.value = level; |
487 | 487 | ||
488 | if (device->cap._BCM) | 488 | if (device->cap._BCM) |
489 | status = acpi_evaluate_object(device->dev->handle, "_BCM", | 489 | status = acpi_evaluate_object(device->dev->handle, "_BCM", |
490 | &args, NULL); | 490 | &args, NULL); |
491 | device->brightness->curr = level; | 491 | device->brightness->curr = level; |
492 | return status; | 492 | return status; |
493 | } | 493 | } |
494 | 494 | ||
495 | static int | 495 | static int |
496 | acpi_video_device_lcd_get_level_current(struct acpi_video_device *device, | 496 | acpi_video_device_lcd_get_level_current(struct acpi_video_device *device, |
497 | unsigned long long *level) | 497 | unsigned long long *level) |
498 | { | 498 | { |
499 | if (device->cap._BQC) | 499 | if (device->cap._BQC) |
500 | return acpi_evaluate_integer(device->dev->handle, "_BQC", NULL, | 500 | return acpi_evaluate_integer(device->dev->handle, "_BQC", NULL, |
501 | level); | 501 | level); |
502 | *level = device->brightness->curr; | 502 | *level = device->brightness->curr; |
503 | return AE_OK; | 503 | return AE_OK; |
504 | } | 504 | } |
505 | 505 | ||
506 | static int | 506 | static int |
507 | acpi_video_device_EDID(struct acpi_video_device *device, | 507 | acpi_video_device_EDID(struct acpi_video_device *device, |
508 | union acpi_object **edid, ssize_t length) | 508 | union acpi_object **edid, ssize_t length) |
509 | { | 509 | { |
510 | int status; | 510 | int status; |
511 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | 511 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
512 | union acpi_object *obj; | 512 | union acpi_object *obj; |
513 | union acpi_object arg0 = { ACPI_TYPE_INTEGER }; | 513 | union acpi_object arg0 = { ACPI_TYPE_INTEGER }; |
514 | struct acpi_object_list args = { 1, &arg0 }; | 514 | struct acpi_object_list args = { 1, &arg0 }; |
515 | 515 | ||
516 | 516 | ||
517 | *edid = NULL; | 517 | *edid = NULL; |
518 | 518 | ||
519 | if (!device) | 519 | if (!device) |
520 | return -ENODEV; | 520 | return -ENODEV; |
521 | if (length == 128) | 521 | if (length == 128) |
522 | arg0.integer.value = 1; | 522 | arg0.integer.value = 1; |
523 | else if (length == 256) | 523 | else if (length == 256) |
524 | arg0.integer.value = 2; | 524 | arg0.integer.value = 2; |
525 | else | 525 | else |
526 | return -EINVAL; | 526 | return -EINVAL; |
527 | 527 | ||
528 | status = acpi_evaluate_object(device->dev->handle, "_DDC", &args, &buffer); | 528 | status = acpi_evaluate_object(device->dev->handle, "_DDC", &args, &buffer); |
529 | if (ACPI_FAILURE(status)) | 529 | if (ACPI_FAILURE(status)) |
530 | return -ENODEV; | 530 | return -ENODEV; |
531 | 531 | ||
532 | obj = buffer.pointer; | 532 | obj = buffer.pointer; |
533 | 533 | ||
534 | if (obj && obj->type == ACPI_TYPE_BUFFER) | 534 | if (obj && obj->type == ACPI_TYPE_BUFFER) |
535 | *edid = obj; | 535 | *edid = obj; |
536 | else { | 536 | else { |
537 | printk(KERN_ERR PREFIX "Invalid _DDC data\n"); | 537 | printk(KERN_ERR PREFIX "Invalid _DDC data\n"); |
538 | status = -EFAULT; | 538 | status = -EFAULT; |
539 | kfree(obj); | 539 | kfree(obj); |
540 | } | 540 | } |
541 | 541 | ||
542 | return status; | 542 | return status; |
543 | } | 543 | } |
544 | 544 | ||
545 | /* bus */ | 545 | /* bus */ |
546 | 546 | ||
547 | static int | 547 | static int |
548 | acpi_video_bus_set_POST(struct acpi_video_bus *video, unsigned long option) | 548 | acpi_video_bus_set_POST(struct acpi_video_bus *video, unsigned long option) |
549 | { | 549 | { |
550 | int status; | 550 | int status; |
551 | unsigned long long tmp; | 551 | unsigned long long tmp; |
552 | union acpi_object arg0 = { ACPI_TYPE_INTEGER }; | 552 | union acpi_object arg0 = { ACPI_TYPE_INTEGER }; |
553 | struct acpi_object_list args = { 1, &arg0 }; | 553 | struct acpi_object_list args = { 1, &arg0 }; |
554 | 554 | ||
555 | 555 | ||
556 | arg0.integer.value = option; | 556 | arg0.integer.value = option; |
557 | 557 | ||
558 | status = acpi_evaluate_integer(video->device->handle, "_SPD", &args, &tmp); | 558 | status = acpi_evaluate_integer(video->device->handle, "_SPD", &args, &tmp); |
559 | if (ACPI_SUCCESS(status)) | 559 | if (ACPI_SUCCESS(status)) |
560 | status = tmp ? (-EINVAL) : (AE_OK); | 560 | status = tmp ? (-EINVAL) : (AE_OK); |
561 | 561 | ||
562 | return status; | 562 | return status; |
563 | } | 563 | } |
564 | 564 | ||
565 | static int | 565 | static int |
566 | acpi_video_bus_get_POST(struct acpi_video_bus *video, unsigned long long *id) | 566 | acpi_video_bus_get_POST(struct acpi_video_bus *video, unsigned long long *id) |
567 | { | 567 | { |
568 | int status; | 568 | int status; |
569 | 569 | ||
570 | status = acpi_evaluate_integer(video->device->handle, "_GPD", NULL, id); | 570 | status = acpi_evaluate_integer(video->device->handle, "_GPD", NULL, id); |
571 | 571 | ||
572 | return status; | 572 | return status; |
573 | } | 573 | } |
574 | 574 | ||
575 | static int | 575 | static int |
576 | acpi_video_bus_POST_options(struct acpi_video_bus *video, | 576 | acpi_video_bus_POST_options(struct acpi_video_bus *video, |
577 | unsigned long long *options) | 577 | unsigned long long *options) |
578 | { | 578 | { |
579 | int status; | 579 | int status; |
580 | 580 | ||
581 | status = acpi_evaluate_integer(video->device->handle, "_VPO", NULL, options); | 581 | status = acpi_evaluate_integer(video->device->handle, "_VPO", NULL, options); |
582 | *options &= 3; | 582 | *options &= 3; |
583 | 583 | ||
584 | return status; | 584 | return status; |
585 | } | 585 | } |
586 | 586 | ||
587 | /* | 587 | /* |
588 | * Arg: | 588 | * Arg: |
589 | * video : video bus device pointer | 589 | * video : video bus device pointer |
590 | * bios_flag : | 590 | * bios_flag : |
591 | * 0. The system BIOS should NOT automatically switch(toggle) | 591 | * 0. The system BIOS should NOT automatically switch(toggle) |
592 | * the active display output. | 592 | * the active display output. |
593 | * 1. The system BIOS should automatically switch (toggle) the | 593 | * 1. The system BIOS should automatically switch (toggle) the |
594 | * active display output. No switch event. | 594 | * active display output. No switch event. |
595 | * 2. The _DGS value should be locked. | 595 | * 2. The _DGS value should be locked. |
596 | * 3. The system BIOS should not automatically switch (toggle) the | 596 | * 3. The system BIOS should not automatically switch (toggle) the |
597 | * active display output, but instead generate the display switch | 597 | * active display output, but instead generate the display switch |
598 | * event notify code. | 598 | * event notify code. |
599 | * lcd_flag : | 599 | * lcd_flag : |
600 | * 0. The system BIOS should automatically control the brightness level | 600 | * 0. The system BIOS should automatically control the brightness level |
601 | * of the LCD when the power changes from AC to DC | 601 | * of the LCD when the power changes from AC to DC |
602 | * 1. The system BIOS should NOT automatically control the brightness | 602 | * 1. The system BIOS should NOT automatically control the brightness |
603 | * level of the LCD when the power changes from AC to DC. | 603 | * level of the LCD when the power changes from AC to DC. |
604 | * Return Value: | 604 | * Return Value: |
605 | * -1 wrong arg. | 605 | * -1 wrong arg. |
606 | */ | 606 | */ |
607 | 607 | ||
608 | static int | 608 | static int |
609 | acpi_video_bus_DOS(struct acpi_video_bus *video, int bios_flag, int lcd_flag) | 609 | acpi_video_bus_DOS(struct acpi_video_bus *video, int bios_flag, int lcd_flag) |
610 | { | 610 | { |
611 | acpi_integer status = 0; | 611 | acpi_integer status = 0; |
612 | union acpi_object arg0 = { ACPI_TYPE_INTEGER }; | 612 | union acpi_object arg0 = { ACPI_TYPE_INTEGER }; |
613 | struct acpi_object_list args = { 1, &arg0 }; | 613 | struct acpi_object_list args = { 1, &arg0 }; |
614 | 614 | ||
615 | 615 | ||
616 | if (bios_flag < 0 || bios_flag > 3 || lcd_flag < 0 || lcd_flag > 1) { | 616 | if (bios_flag < 0 || bios_flag > 3 || lcd_flag < 0 || lcd_flag > 1) { |
617 | status = -1; | 617 | status = -1; |
618 | goto Failed; | 618 | goto Failed; |
619 | } | 619 | } |
620 | arg0.integer.value = (lcd_flag << 2) | bios_flag; | 620 | arg0.integer.value = (lcd_flag << 2) | bios_flag; |
621 | video->dos_setting = arg0.integer.value; | 621 | video->dos_setting = arg0.integer.value; |
622 | acpi_evaluate_object(video->device->handle, "_DOS", &args, NULL); | 622 | acpi_evaluate_object(video->device->handle, "_DOS", &args, NULL); |
623 | 623 | ||
624 | Failed: | 624 | Failed: |
625 | return status; | 625 | return status; |
626 | } | 626 | } |
627 | 627 | ||
628 | /* | 628 | /* |
629 | * Arg: | 629 | * Arg: |
630 | * device : video output device (LCD, CRT, ..) | 630 | * device : video output device (LCD, CRT, ..) |
631 | * | 631 | * |
632 | * Return Value: | 632 | * Return Value: |
633 | * Maximum brightness level | 633 | * Maximum brightness level |
634 | * | 634 | * |
635 | * Allocate and initialize device->brightness. | 635 | * Allocate and initialize device->brightness. |
636 | */ | 636 | */ |
637 | 637 | ||
638 | static int | 638 | static int |
639 | acpi_video_init_brightness(struct acpi_video_device *device) | 639 | acpi_video_init_brightness(struct acpi_video_device *device) |
640 | { | 640 | { |
641 | union acpi_object *obj = NULL; | 641 | union acpi_object *obj = NULL; |
642 | int i, max_level = 0, count = 0; | 642 | int i, max_level = 0, count = 0; |
643 | union acpi_object *o; | 643 | union acpi_object *o; |
644 | struct acpi_video_device_brightness *br = NULL; | 644 | struct acpi_video_device_brightness *br = NULL; |
645 | 645 | ||
646 | if (!ACPI_SUCCESS(acpi_video_device_lcd_query_levels(device, &obj))) { | 646 | if (!ACPI_SUCCESS(acpi_video_device_lcd_query_levels(device, &obj))) { |
647 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Could not query available " | 647 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Could not query available " |
648 | "LCD brightness level\n")); | 648 | "LCD brightness level\n")); |
649 | goto out; | 649 | goto out; |
650 | } | 650 | } |
651 | 651 | ||
652 | if (obj->package.count < 2) | 652 | if (obj->package.count < 2) |
653 | goto out; | 653 | goto out; |
654 | 654 | ||
655 | br = kzalloc(sizeof(*br), GFP_KERNEL); | 655 | br = kzalloc(sizeof(*br), GFP_KERNEL); |
656 | if (!br) { | 656 | if (!br) { |
657 | printk(KERN_ERR "can't allocate memory\n"); | 657 | printk(KERN_ERR "can't allocate memory\n"); |
658 | goto out; | 658 | goto out; |
659 | } | 659 | } |
660 | 660 | ||
661 | br->levels = kmalloc(obj->package.count * sizeof *(br->levels), | 661 | br->levels = kmalloc(obj->package.count * sizeof *(br->levels), |
662 | GFP_KERNEL); | 662 | GFP_KERNEL); |
663 | if (!br->levels) | 663 | if (!br->levels) |
664 | goto out_free; | 664 | goto out_free; |
665 | 665 | ||
666 | for (i = 0; i < obj->package.count; i++) { | 666 | for (i = 0; i < obj->package.count; i++) { |
667 | o = (union acpi_object *)&obj->package.elements[i]; | 667 | o = (union acpi_object *)&obj->package.elements[i]; |
668 | if (o->type != ACPI_TYPE_INTEGER) { | 668 | if (o->type != ACPI_TYPE_INTEGER) { |
669 | printk(KERN_ERR PREFIX "Invalid data\n"); | 669 | printk(KERN_ERR PREFIX "Invalid data\n"); |
670 | continue; | 670 | continue; |
671 | } | 671 | } |
672 | br->levels[count] = (u32) o->integer.value; | 672 | br->levels[count] = (u32) o->integer.value; |
673 | 673 | ||
674 | if (br->levels[count] > max_level) | 674 | if (br->levels[count] > max_level) |
675 | max_level = br->levels[count]; | 675 | max_level = br->levels[count]; |
676 | count++; | 676 | count++; |
677 | } | 677 | } |
678 | 678 | ||
679 | if (count < 2) | 679 | if (count < 2) |
680 | goto out_free_levels; | 680 | goto out_free_levels; |
681 | 681 | ||
682 | br->count = count; | 682 | br->count = count; |
683 | device->brightness = br; | 683 | device->brightness = br; |
684 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "found %d brightness levels\n", count)); | 684 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "found %d brightness levels\n", count)); |
685 | kfree(obj); | 685 | kfree(obj); |
686 | return max_level; | 686 | return max_level; |
687 | 687 | ||
688 | out_free_levels: | 688 | out_free_levels: |
689 | kfree(br->levels); | 689 | kfree(br->levels); |
690 | out_free: | 690 | out_free: |
691 | kfree(br); | 691 | kfree(br); |
692 | out: | 692 | out: |
693 | device->brightness = NULL; | 693 | device->brightness = NULL; |
694 | kfree(obj); | 694 | kfree(obj); |
695 | return 0; | 695 | return 0; |
696 | } | 696 | } |
697 | 697 | ||
698 | /* | 698 | /* |
699 | * Arg: | 699 | * Arg: |
700 | * device : video output device (LCD, CRT, ..) | 700 | * device : video output device (LCD, CRT, ..) |
701 | * | 701 | * |
702 | * Return Value: | 702 | * Return Value: |
703 | * None | 703 | * None |
704 | * | 704 | * |
705 | * Find out all required AML methods defined under the output | 705 | * Find out all required AML methods defined under the output |
706 | * device. | 706 | * device. |
707 | */ | 707 | */ |
708 | 708 | ||
709 | static void acpi_video_device_find_cap(struct acpi_video_device *device) | 709 | static void acpi_video_device_find_cap(struct acpi_video_device *device) |
710 | { | 710 | { |
711 | acpi_handle h_dummy1; | 711 | acpi_handle h_dummy1; |
712 | u32 max_level = 0; | 712 | u32 max_level = 0; |
713 | 713 | ||
714 | 714 | ||
715 | memset(&device->cap, 0, sizeof(device->cap)); | 715 | memset(&device->cap, 0, sizeof(device->cap)); |
716 | 716 | ||
717 | if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_ADR", &h_dummy1))) { | 717 | if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_ADR", &h_dummy1))) { |
718 | device->cap._ADR = 1; | 718 | device->cap._ADR = 1; |
719 | } | 719 | } |
720 | if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_BCL", &h_dummy1))) { | 720 | if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_BCL", &h_dummy1))) { |
721 | device->cap._BCL = 1; | 721 | device->cap._BCL = 1; |
722 | } | 722 | } |
723 | if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_BCM", &h_dummy1))) { | 723 | if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_BCM", &h_dummy1))) { |
724 | device->cap._BCM = 1; | 724 | device->cap._BCM = 1; |
725 | } | 725 | } |
726 | if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle,"_BQC",&h_dummy1))) | 726 | if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle,"_BQC",&h_dummy1))) |
727 | device->cap._BQC = 1; | 727 | device->cap._BQC = 1; |
728 | if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DDC", &h_dummy1))) { | 728 | if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DDC", &h_dummy1))) { |
729 | device->cap._DDC = 1; | 729 | device->cap._DDC = 1; |
730 | } | 730 | } |
731 | if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DCS", &h_dummy1))) { | 731 | if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DCS", &h_dummy1))) { |
732 | device->cap._DCS = 1; | 732 | device->cap._DCS = 1; |
733 | } | 733 | } |
734 | if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DGS", &h_dummy1))) { | 734 | if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DGS", &h_dummy1))) { |
735 | device->cap._DGS = 1; | 735 | device->cap._DGS = 1; |
736 | } | 736 | } |
737 | if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DSS", &h_dummy1))) { | 737 | if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DSS", &h_dummy1))) { |
738 | device->cap._DSS = 1; | 738 | device->cap._DSS = 1; |
739 | } | 739 | } |
740 | 740 | ||
741 | max_level = acpi_video_init_brightness(device); | 741 | if (acpi_video_backlight_support()) |
742 | max_level = acpi_video_init_brightness(device); | ||
742 | 743 | ||
743 | if (device->cap._BCL && device->cap._BCM && max_level > 0) { | 744 | if (device->cap._BCL && device->cap._BCM && max_level > 0) { |
744 | int result; | 745 | int result; |
745 | static int count = 0; | 746 | static int count = 0; |
746 | char *name; | 747 | char *name; |
747 | name = kzalloc(MAX_NAME_LEN, GFP_KERNEL); | 748 | name = kzalloc(MAX_NAME_LEN, GFP_KERNEL); |
748 | if (!name) | 749 | if (!name) |
749 | return; | 750 | return; |
750 | 751 | ||
751 | sprintf(name, "acpi_video%d", count++); | 752 | sprintf(name, "acpi_video%d", count++); |
752 | device->backlight = backlight_device_register(name, | 753 | device->backlight = backlight_device_register(name, |
753 | NULL, device, &acpi_backlight_ops); | 754 | NULL, device, &acpi_backlight_ops); |
754 | device->backlight->props.max_brightness = device->brightness->count-3; | 755 | device->backlight->props.max_brightness = device->brightness->count-3; |
755 | /* | 756 | /* |
756 | * If there exists the _BQC object, the _BQC object will be | 757 | * If there exists the _BQC object, the _BQC object will be |
757 | * called to get the current backlight brightness. Otherwise | 758 | * called to get the current backlight brightness. Otherwise |
758 | * the brightness will be set to the maximum. | 759 | * the brightness will be set to the maximum. |
759 | */ | 760 | */ |
760 | if (device->cap._BQC) | 761 | if (device->cap._BQC) |
761 | device->backlight->props.brightness = | 762 | device->backlight->props.brightness = |
762 | acpi_video_get_brightness(device->backlight); | 763 | acpi_video_get_brightness(device->backlight); |
763 | else | 764 | else |
764 | device->backlight->props.brightness = | 765 | device->backlight->props.brightness = |
765 | device->backlight->props.max_brightness; | 766 | device->backlight->props.max_brightness; |
766 | backlight_update_status(device->backlight); | 767 | backlight_update_status(device->backlight); |
767 | kfree(name); | 768 | kfree(name); |
768 | 769 | ||
769 | device->cdev = thermal_cooling_device_register("LCD", | 770 | device->cdev = thermal_cooling_device_register("LCD", |
770 | device->dev, &video_cooling_ops); | 771 | device->dev, &video_cooling_ops); |
771 | if (IS_ERR(device->cdev)) | 772 | if (IS_ERR(device->cdev)) |
772 | return; | 773 | return; |
773 | 774 | ||
774 | dev_info(&device->dev->dev, "registered as cooling_device%d\n", | 775 | dev_info(&device->dev->dev, "registered as cooling_device%d\n", |
775 | device->cdev->id); | 776 | device->cdev->id); |
776 | result = sysfs_create_link(&device->dev->dev.kobj, | 777 | result = sysfs_create_link(&device->dev->dev.kobj, |
777 | &device->cdev->device.kobj, | 778 | &device->cdev->device.kobj, |
778 | "thermal_cooling"); | 779 | "thermal_cooling"); |
779 | if (result) | 780 | if (result) |
780 | printk(KERN_ERR PREFIX "Create sysfs link\n"); | 781 | printk(KERN_ERR PREFIX "Create sysfs link\n"); |
781 | result = sysfs_create_link(&device->cdev->device.kobj, | 782 | result = sysfs_create_link(&device->cdev->device.kobj, |
782 | &device->dev->dev.kobj, "device"); | 783 | &device->dev->dev.kobj, "device"); |
783 | if (result) | 784 | if (result) |
784 | printk(KERN_ERR PREFIX "Create sysfs link\n"); | 785 | printk(KERN_ERR PREFIX "Create sysfs link\n"); |
785 | 786 | ||
786 | } | 787 | } |
787 | if (device->cap._DCS && device->cap._DSS){ | 788 | |
788 | static int count = 0; | 789 | if (acpi_video_display_switch_support()) { |
789 | char *name; | 790 | |
790 | name = kzalloc(MAX_NAME_LEN, GFP_KERNEL); | 791 | if (device->cap._DCS && device->cap._DSS) { |
791 | if (!name) | 792 | static int count; |
792 | return; | 793 | char *name; |
793 | sprintf(name, "acpi_video%d", count++); | 794 | name = kzalloc(MAX_NAME_LEN, GFP_KERNEL); |
794 | device->output_dev = video_output_register(name, | 795 | if (!name) |
795 | NULL, device, &acpi_output_properties); | 796 | return; |
796 | kfree(name); | 797 | sprintf(name, "acpi_video%d", count++); |
798 | device->output_dev = video_output_register(name, | ||
799 | NULL, device, &acpi_output_properties); | ||
800 | kfree(name); | ||
801 | } | ||
797 | } | 802 | } |
798 | return; | ||
799 | } | 803 | } |
800 | 804 | ||
801 | /* | 805 | /* |
802 | * Arg: | 806 | * Arg: |
803 | * device : video output device (VGA) | 807 | * device : video output device (VGA) |
804 | * | 808 | * |
805 | * Return Value: | 809 | * Return Value: |
806 | * None | 810 | * None |
807 | * | 811 | * |
808 | * Find out all required AML methods defined under the video bus device. | 812 | * Find out all required AML methods defined under the video bus device. |
809 | */ | 813 | */ |
810 | 814 | ||
811 | static void acpi_video_bus_find_cap(struct acpi_video_bus *video) | 815 | static void acpi_video_bus_find_cap(struct acpi_video_bus *video) |
812 | { | 816 | { |
813 | acpi_handle h_dummy1; | 817 | acpi_handle h_dummy1; |
814 | 818 | ||
815 | memset(&video->cap, 0, sizeof(video->cap)); | 819 | memset(&video->cap, 0, sizeof(video->cap)); |
816 | if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_DOS", &h_dummy1))) { | 820 | if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_DOS", &h_dummy1))) { |
817 | video->cap._DOS = 1; | 821 | video->cap._DOS = 1; |
818 | } | 822 | } |
819 | if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_DOD", &h_dummy1))) { | 823 | if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_DOD", &h_dummy1))) { |
820 | video->cap._DOD = 1; | 824 | video->cap._DOD = 1; |
821 | } | 825 | } |
822 | if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_ROM", &h_dummy1))) { | 826 | if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_ROM", &h_dummy1))) { |
823 | video->cap._ROM = 1; | 827 | video->cap._ROM = 1; |
824 | } | 828 | } |
825 | if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_GPD", &h_dummy1))) { | 829 | if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_GPD", &h_dummy1))) { |
826 | video->cap._GPD = 1; | 830 | video->cap._GPD = 1; |
827 | } | 831 | } |
828 | if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_SPD", &h_dummy1))) { | 832 | if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_SPD", &h_dummy1))) { |
829 | video->cap._SPD = 1; | 833 | video->cap._SPD = 1; |
830 | } | 834 | } |
831 | if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_VPO", &h_dummy1))) { | 835 | if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_VPO", &h_dummy1))) { |
832 | video->cap._VPO = 1; | 836 | video->cap._VPO = 1; |
833 | } | 837 | } |
834 | } | 838 | } |
835 | 839 | ||
836 | /* | 840 | /* |
837 | * Check whether the video bus device has required AML method to | 841 | * Check whether the video bus device has required AML method to |
838 | * support the desired features | 842 | * support the desired features |
839 | */ | 843 | */ |
840 | 844 | ||
841 | static int acpi_video_bus_check(struct acpi_video_bus *video) | 845 | static int acpi_video_bus_check(struct acpi_video_bus *video) |
842 | { | 846 | { |
843 | acpi_status status = -ENOENT; | 847 | acpi_status status = -ENOENT; |
848 | struct device *dev; | ||
844 | 849 | ||
845 | |||
846 | if (!video) | 850 | if (!video) |
847 | return -EINVAL; | 851 | return -EINVAL; |
852 | |||
853 | dev = acpi_get_physical_pci_device(video->device->handle); | ||
854 | if (!dev) | ||
855 | return -ENODEV; | ||
856 | put_device(dev); | ||
848 | 857 | ||
849 | /* Since there is no HID, CID and so on for VGA driver, we have | 858 | /* Since there is no HID, CID and so on for VGA driver, we have |
850 | * to check well known required nodes. | 859 | * to check well known required nodes. |
851 | */ | 860 | */ |
852 | 861 | ||
853 | /* Does this device support video switching? */ | 862 | /* Does this device support video switching? */ |
854 | if (video->cap._DOS) { | 863 | if (video->cap._DOS) { |
855 | video->flags.multihead = 1; | 864 | video->flags.multihead = 1; |
856 | status = 0; | 865 | status = 0; |
857 | } | 866 | } |
858 | 867 | ||
859 | /* Does this device support retrieving a video ROM? */ | 868 | /* Does this device support retrieving a video ROM? */ |
860 | if (video->cap._ROM) { | 869 | if (video->cap._ROM) { |
861 | video->flags.rom = 1; | 870 | video->flags.rom = 1; |
862 | status = 0; | 871 | status = 0; |
863 | } | 872 | } |
864 | 873 | ||
865 | /* Does this device support configuring which video device to POST? */ | 874 | /* Does this device support configuring which video device to POST? */ |
866 | if (video->cap._GPD && video->cap._SPD && video->cap._VPO) { | 875 | if (video->cap._GPD && video->cap._SPD && video->cap._VPO) { |
867 | video->flags.post = 1; | 876 | video->flags.post = 1; |
868 | status = 0; | 877 | status = 0; |
869 | } | 878 | } |
870 | 879 | ||
871 | return status; | 880 | return status; |
872 | } | 881 | } |
873 | 882 | ||
874 | /* -------------------------------------------------------------------------- | 883 | /* -------------------------------------------------------------------------- |
875 | FS Interface (/proc) | 884 | FS Interface (/proc) |
876 | -------------------------------------------------------------------------- */ | 885 | -------------------------------------------------------------------------- */ |
877 | 886 | ||
878 | static struct proc_dir_entry *acpi_video_dir; | 887 | static struct proc_dir_entry *acpi_video_dir; |
879 | 888 | ||
880 | /* video devices */ | 889 | /* video devices */ |
881 | 890 | ||
882 | static int acpi_video_device_info_seq_show(struct seq_file *seq, void *offset) | 891 | static int acpi_video_device_info_seq_show(struct seq_file *seq, void *offset) |
883 | { | 892 | { |
884 | struct acpi_video_device *dev = seq->private; | 893 | struct acpi_video_device *dev = seq->private; |
885 | 894 | ||
886 | 895 | ||
887 | if (!dev) | 896 | if (!dev) |
888 | goto end; | 897 | goto end; |
889 | 898 | ||
890 | seq_printf(seq, "device_id: 0x%04x\n", (u32) dev->device_id); | 899 | seq_printf(seq, "device_id: 0x%04x\n", (u32) dev->device_id); |
891 | seq_printf(seq, "type: "); | 900 | seq_printf(seq, "type: "); |
892 | if (dev->flags.crt) | 901 | if (dev->flags.crt) |
893 | seq_printf(seq, "CRT\n"); | 902 | seq_printf(seq, "CRT\n"); |
894 | else if (dev->flags.lcd) | 903 | else if (dev->flags.lcd) |
895 | seq_printf(seq, "LCD\n"); | 904 | seq_printf(seq, "LCD\n"); |
896 | else if (dev->flags.tvout) | 905 | else if (dev->flags.tvout) |
897 | seq_printf(seq, "TVOUT\n"); | 906 | seq_printf(seq, "TVOUT\n"); |
898 | else if (dev->flags.dvi) | 907 | else if (dev->flags.dvi) |
899 | seq_printf(seq, "DVI\n"); | 908 | seq_printf(seq, "DVI\n"); |
900 | else | 909 | else |
901 | seq_printf(seq, "UNKNOWN\n"); | 910 | seq_printf(seq, "UNKNOWN\n"); |
902 | 911 | ||
903 | seq_printf(seq, "known by bios: %s\n", dev->flags.bios ? "yes" : "no"); | 912 | seq_printf(seq, "known by bios: %s\n", dev->flags.bios ? "yes" : "no"); |
904 | 913 | ||
905 | end: | 914 | end: |
906 | return 0; | 915 | return 0; |
907 | } | 916 | } |
908 | 917 | ||
909 | static int | 918 | static int |
910 | acpi_video_device_info_open_fs(struct inode *inode, struct file *file) | 919 | acpi_video_device_info_open_fs(struct inode *inode, struct file *file) |
911 | { | 920 | { |
912 | return single_open(file, acpi_video_device_info_seq_show, | 921 | return single_open(file, acpi_video_device_info_seq_show, |
913 | PDE(inode)->data); | 922 | PDE(inode)->data); |
914 | } | 923 | } |
915 | 924 | ||
916 | static int acpi_video_device_state_seq_show(struct seq_file *seq, void *offset) | 925 | static int acpi_video_device_state_seq_show(struct seq_file *seq, void *offset) |
917 | { | 926 | { |
918 | int status; | 927 | int status; |
919 | struct acpi_video_device *dev = seq->private; | 928 | struct acpi_video_device *dev = seq->private; |
920 | unsigned long long state; | 929 | unsigned long long state; |
921 | 930 | ||
922 | 931 | ||
923 | if (!dev) | 932 | if (!dev) |
924 | goto end; | 933 | goto end; |
925 | 934 | ||
926 | status = acpi_video_device_get_state(dev, &state); | 935 | status = acpi_video_device_get_state(dev, &state); |
927 | seq_printf(seq, "state: "); | 936 | seq_printf(seq, "state: "); |
928 | if (ACPI_SUCCESS(status)) | 937 | if (ACPI_SUCCESS(status)) |
929 | seq_printf(seq, "0x%02llx\n", state); | 938 | seq_printf(seq, "0x%02llx\n", state); |
930 | else | 939 | else |
931 | seq_printf(seq, "<not supported>\n"); | 940 | seq_printf(seq, "<not supported>\n"); |
932 | 941 | ||
933 | status = acpi_video_device_query(dev, &state); | 942 | status = acpi_video_device_query(dev, &state); |
934 | seq_printf(seq, "query: "); | 943 | seq_printf(seq, "query: "); |
935 | if (ACPI_SUCCESS(status)) | 944 | if (ACPI_SUCCESS(status)) |
936 | seq_printf(seq, "0x%02llx\n", state); | 945 | seq_printf(seq, "0x%02llx\n", state); |
937 | else | 946 | else |
938 | seq_printf(seq, "<not supported>\n"); | 947 | seq_printf(seq, "<not supported>\n"); |
939 | 948 | ||
940 | end: | 949 | end: |
941 | return 0; | 950 | return 0; |
942 | } | 951 | } |
943 | 952 | ||
944 | static int | 953 | static int |
945 | acpi_video_device_state_open_fs(struct inode *inode, struct file *file) | 954 | acpi_video_device_state_open_fs(struct inode *inode, struct file *file) |
946 | { | 955 | { |
947 | return single_open(file, acpi_video_device_state_seq_show, | 956 | return single_open(file, acpi_video_device_state_seq_show, |
948 | PDE(inode)->data); | 957 | PDE(inode)->data); |
949 | } | 958 | } |
950 | 959 | ||
951 | static ssize_t | 960 | static ssize_t |
952 | acpi_video_device_write_state(struct file *file, | 961 | acpi_video_device_write_state(struct file *file, |
953 | const char __user * buffer, | 962 | const char __user * buffer, |
954 | size_t count, loff_t * data) | 963 | size_t count, loff_t * data) |
955 | { | 964 | { |
956 | int status; | 965 | int status; |
957 | struct seq_file *m = file->private_data; | 966 | struct seq_file *m = file->private_data; |
958 | struct acpi_video_device *dev = m->private; | 967 | struct acpi_video_device *dev = m->private; |
959 | char str[12] = { 0 }; | 968 | char str[12] = { 0 }; |
960 | u32 state = 0; | 969 | u32 state = 0; |
961 | 970 | ||
962 | 971 | ||
963 | if (!dev || count + 1 > sizeof str) | 972 | if (!dev || count + 1 > sizeof str) |
964 | return -EINVAL; | 973 | return -EINVAL; |
965 | 974 | ||
966 | if (copy_from_user(str, buffer, count)) | 975 | if (copy_from_user(str, buffer, count)) |
967 | return -EFAULT; | 976 | return -EFAULT; |
968 | 977 | ||
969 | str[count] = 0; | 978 | str[count] = 0; |
970 | state = simple_strtoul(str, NULL, 0); | 979 | state = simple_strtoul(str, NULL, 0); |
971 | state &= ((1ul << 31) | (1ul << 30) | (1ul << 0)); | 980 | state &= ((1ul << 31) | (1ul << 30) | (1ul << 0)); |
972 | 981 | ||
973 | status = acpi_video_device_set_state(dev, state); | 982 | status = acpi_video_device_set_state(dev, state); |
974 | 983 | ||
975 | if (status) | 984 | if (status) |
976 | return -EFAULT; | 985 | return -EFAULT; |
977 | 986 | ||
978 | return count; | 987 | return count; |
979 | } | 988 | } |
980 | 989 | ||
981 | static int | 990 | static int |
982 | acpi_video_device_brightness_seq_show(struct seq_file *seq, void *offset) | 991 | acpi_video_device_brightness_seq_show(struct seq_file *seq, void *offset) |
983 | { | 992 | { |
984 | struct acpi_video_device *dev = seq->private; | 993 | struct acpi_video_device *dev = seq->private; |
985 | int i; | 994 | int i; |
986 | 995 | ||
987 | 996 | ||
988 | if (!dev || !dev->brightness) { | 997 | if (!dev || !dev->brightness) { |
989 | seq_printf(seq, "<not supported>\n"); | 998 | seq_printf(seq, "<not supported>\n"); |
990 | return 0; | 999 | return 0; |
991 | } | 1000 | } |
992 | 1001 | ||
993 | seq_printf(seq, "levels: "); | 1002 | seq_printf(seq, "levels: "); |
994 | for (i = 0; i < dev->brightness->count; i++) | 1003 | for (i = 0; i < dev->brightness->count; i++) |
995 | seq_printf(seq, " %d", dev->brightness->levels[i]); | 1004 | seq_printf(seq, " %d", dev->brightness->levels[i]); |
996 | seq_printf(seq, "\ncurrent: %d\n", dev->brightness->curr); | 1005 | seq_printf(seq, "\ncurrent: %d\n", dev->brightness->curr); |
997 | 1006 | ||
998 | return 0; | 1007 | return 0; |
999 | } | 1008 | } |
1000 | 1009 | ||
1001 | static int | 1010 | static int |
1002 | acpi_video_device_brightness_open_fs(struct inode *inode, struct file *file) | 1011 | acpi_video_device_brightness_open_fs(struct inode *inode, struct file *file) |
1003 | { | 1012 | { |
1004 | return single_open(file, acpi_video_device_brightness_seq_show, | 1013 | return single_open(file, acpi_video_device_brightness_seq_show, |
1005 | PDE(inode)->data); | 1014 | PDE(inode)->data); |
1006 | } | 1015 | } |
1007 | 1016 | ||
1008 | static ssize_t | 1017 | static ssize_t |
1009 | acpi_video_device_write_brightness(struct file *file, | 1018 | acpi_video_device_write_brightness(struct file *file, |
1010 | const char __user * buffer, | 1019 | const char __user * buffer, |
1011 | size_t count, loff_t * data) | 1020 | size_t count, loff_t * data) |
1012 | { | 1021 | { |
1013 | struct seq_file *m = file->private_data; | 1022 | struct seq_file *m = file->private_data; |
1014 | struct acpi_video_device *dev = m->private; | 1023 | struct acpi_video_device *dev = m->private; |
1015 | char str[5] = { 0 }; | 1024 | char str[5] = { 0 }; |
1016 | unsigned int level = 0; | 1025 | unsigned int level = 0; |
1017 | int i; | 1026 | int i; |
1018 | 1027 | ||
1019 | 1028 | ||
1020 | if (!dev || !dev->brightness || count + 1 > sizeof str) | 1029 | if (!dev || !dev->brightness || count + 1 > sizeof str) |
1021 | return -EINVAL; | 1030 | return -EINVAL; |
1022 | 1031 | ||
1023 | if (copy_from_user(str, buffer, count)) | 1032 | if (copy_from_user(str, buffer, count)) |
1024 | return -EFAULT; | 1033 | return -EFAULT; |
1025 | 1034 | ||
1026 | str[count] = 0; | 1035 | str[count] = 0; |
1027 | level = simple_strtoul(str, NULL, 0); | 1036 | level = simple_strtoul(str, NULL, 0); |
1028 | 1037 | ||
1029 | if (level > 100) | 1038 | if (level > 100) |
1030 | return -EFAULT; | 1039 | return -EFAULT; |
1031 | 1040 | ||
1032 | /* validate through the list of available levels */ | 1041 | /* validate through the list of available levels */ |
1033 | for (i = 0; i < dev->brightness->count; i++) | 1042 | for (i = 0; i < dev->brightness->count; i++) |
1034 | if (level == dev->brightness->levels[i]) { | 1043 | if (level == dev->brightness->levels[i]) { |
1035 | if (ACPI_SUCCESS | 1044 | if (ACPI_SUCCESS |
1036 | (acpi_video_device_lcd_set_level(dev, level))) | 1045 | (acpi_video_device_lcd_set_level(dev, level))) |
1037 | dev->brightness->curr = level; | 1046 | dev->brightness->curr = level; |
1038 | break; | 1047 | break; |
1039 | } | 1048 | } |
1040 | 1049 | ||
1041 | return count; | 1050 | return count; |
1042 | } | 1051 | } |
1043 | 1052 | ||
1044 | static int acpi_video_device_EDID_seq_show(struct seq_file *seq, void *offset) | 1053 | static int acpi_video_device_EDID_seq_show(struct seq_file *seq, void *offset) |
1045 | { | 1054 | { |
1046 | struct acpi_video_device *dev = seq->private; | 1055 | struct acpi_video_device *dev = seq->private; |
1047 | int status; | 1056 | int status; |
1048 | int i; | 1057 | int i; |
1049 | union acpi_object *edid = NULL; | 1058 | union acpi_object *edid = NULL; |
1050 | 1059 | ||
1051 | 1060 | ||
1052 | if (!dev) | 1061 | if (!dev) |
1053 | goto out; | 1062 | goto out; |
1054 | 1063 | ||
1055 | status = acpi_video_device_EDID(dev, &edid, 128); | 1064 | status = acpi_video_device_EDID(dev, &edid, 128); |
1056 | if (ACPI_FAILURE(status)) { | 1065 | if (ACPI_FAILURE(status)) { |
1057 | status = acpi_video_device_EDID(dev, &edid, 256); | 1066 | status = acpi_video_device_EDID(dev, &edid, 256); |
1058 | } | 1067 | } |
1059 | 1068 | ||
1060 | if (ACPI_FAILURE(status)) { | 1069 | if (ACPI_FAILURE(status)) { |
1061 | goto out; | 1070 | goto out; |
1062 | } | 1071 | } |
1063 | 1072 | ||
1064 | if (edid && edid->type == ACPI_TYPE_BUFFER) { | 1073 | if (edid && edid->type == ACPI_TYPE_BUFFER) { |
1065 | for (i = 0; i < edid->buffer.length; i++) | 1074 | for (i = 0; i < edid->buffer.length; i++) |
1066 | seq_putc(seq, edid->buffer.pointer[i]); | 1075 | seq_putc(seq, edid->buffer.pointer[i]); |
1067 | } | 1076 | } |
1068 | 1077 | ||
1069 | out: | 1078 | out: |
1070 | if (!edid) | 1079 | if (!edid) |
1071 | seq_printf(seq, "<not supported>\n"); | 1080 | seq_printf(seq, "<not supported>\n"); |
1072 | else | 1081 | else |
1073 | kfree(edid); | 1082 | kfree(edid); |
1074 | 1083 | ||
1075 | return 0; | 1084 | return 0; |
1076 | } | 1085 | } |
1077 | 1086 | ||
1078 | static int | 1087 | static int |
1079 | acpi_video_device_EDID_open_fs(struct inode *inode, struct file *file) | 1088 | acpi_video_device_EDID_open_fs(struct inode *inode, struct file *file) |
1080 | { | 1089 | { |
1081 | return single_open(file, acpi_video_device_EDID_seq_show, | 1090 | return single_open(file, acpi_video_device_EDID_seq_show, |
1082 | PDE(inode)->data); | 1091 | PDE(inode)->data); |
1083 | } | 1092 | } |
1084 | 1093 | ||
1085 | static int acpi_video_device_add_fs(struct acpi_device *device) | 1094 | static int acpi_video_device_add_fs(struct acpi_device *device) |
1086 | { | 1095 | { |
1087 | struct proc_dir_entry *entry, *device_dir; | 1096 | struct proc_dir_entry *entry, *device_dir; |
1088 | struct acpi_video_device *vid_dev; | 1097 | struct acpi_video_device *vid_dev; |
1089 | 1098 | ||
1090 | vid_dev = acpi_driver_data(device); | 1099 | vid_dev = acpi_driver_data(device); |
1091 | if (!vid_dev) | 1100 | if (!vid_dev) |
1092 | return -ENODEV; | 1101 | return -ENODEV; |
1093 | 1102 | ||
1094 | device_dir = proc_mkdir(acpi_device_bid(device), | 1103 | device_dir = proc_mkdir(acpi_device_bid(device), |
1095 | vid_dev->video->dir); | 1104 | vid_dev->video->dir); |
1096 | if (!device_dir) | 1105 | if (!device_dir) |
1097 | return -ENOMEM; | 1106 | return -ENOMEM; |
1098 | 1107 | ||
1099 | device_dir->owner = THIS_MODULE; | 1108 | device_dir->owner = THIS_MODULE; |
1100 | 1109 | ||
1101 | /* 'info' [R] */ | 1110 | /* 'info' [R] */ |
1102 | entry = proc_create_data("info", S_IRUGO, device_dir, | 1111 | entry = proc_create_data("info", S_IRUGO, device_dir, |
1103 | &acpi_video_device_info_fops, acpi_driver_data(device)); | 1112 | &acpi_video_device_info_fops, acpi_driver_data(device)); |
1104 | if (!entry) | 1113 | if (!entry) |
1105 | goto err_remove_dir; | 1114 | goto err_remove_dir; |
1106 | 1115 | ||
1107 | /* 'state' [R/W] */ | 1116 | /* 'state' [R/W] */ |
1108 | acpi_video_device_state_fops.write = acpi_video_device_write_state; | 1117 | acpi_video_device_state_fops.write = acpi_video_device_write_state; |
1109 | entry = proc_create_data("state", S_IFREG | S_IRUGO | S_IWUSR, | 1118 | entry = proc_create_data("state", S_IFREG | S_IRUGO | S_IWUSR, |
1110 | device_dir, | 1119 | device_dir, |
1111 | &acpi_video_device_state_fops, | 1120 | &acpi_video_device_state_fops, |
1112 | acpi_driver_data(device)); | 1121 | acpi_driver_data(device)); |
1113 | if (!entry) | 1122 | if (!entry) |
1114 | goto err_remove_info; | 1123 | goto err_remove_info; |
1115 | 1124 | ||
1116 | /* 'brightness' [R/W] */ | 1125 | /* 'brightness' [R/W] */ |
1117 | acpi_video_device_brightness_fops.write = | 1126 | acpi_video_device_brightness_fops.write = |
1118 | acpi_video_device_write_brightness; | 1127 | acpi_video_device_write_brightness; |
1119 | entry = proc_create_data("brightness", S_IFREG | S_IRUGO | S_IWUSR, | 1128 | entry = proc_create_data("brightness", S_IFREG | S_IRUGO | S_IWUSR, |
1120 | device_dir, | 1129 | device_dir, |
1121 | &acpi_video_device_brightness_fops, | 1130 | &acpi_video_device_brightness_fops, |
1122 | acpi_driver_data(device)); | 1131 | acpi_driver_data(device)); |
1123 | if (!entry) | 1132 | if (!entry) |
1124 | goto err_remove_state; | 1133 | goto err_remove_state; |
1125 | 1134 | ||
1126 | /* 'EDID' [R] */ | 1135 | /* 'EDID' [R] */ |
1127 | entry = proc_create_data("EDID", S_IRUGO, device_dir, | 1136 | entry = proc_create_data("EDID", S_IRUGO, device_dir, |
1128 | &acpi_video_device_EDID_fops, | 1137 | &acpi_video_device_EDID_fops, |
1129 | acpi_driver_data(device)); | 1138 | acpi_driver_data(device)); |
1130 | if (!entry) | 1139 | if (!entry) |
1131 | goto err_remove_brightness; | 1140 | goto err_remove_brightness; |
1132 | 1141 | ||
1133 | acpi_device_dir(device) = device_dir; | 1142 | acpi_device_dir(device) = device_dir; |
1134 | 1143 | ||
1135 | return 0; | 1144 | return 0; |
1136 | 1145 | ||
1137 | err_remove_brightness: | 1146 | err_remove_brightness: |
1138 | remove_proc_entry("brightness", device_dir); | 1147 | remove_proc_entry("brightness", device_dir); |
1139 | err_remove_state: | 1148 | err_remove_state: |
1140 | remove_proc_entry("state", device_dir); | 1149 | remove_proc_entry("state", device_dir); |
1141 | err_remove_info: | 1150 | err_remove_info: |
1142 | remove_proc_entry("info", device_dir); | 1151 | remove_proc_entry("info", device_dir); |
1143 | err_remove_dir: | 1152 | err_remove_dir: |
1144 | remove_proc_entry(acpi_device_bid(device), vid_dev->video->dir); | 1153 | remove_proc_entry(acpi_device_bid(device), vid_dev->video->dir); |
1145 | return -ENOMEM; | 1154 | return -ENOMEM; |
1146 | } | 1155 | } |
1147 | 1156 | ||
1148 | static int acpi_video_device_remove_fs(struct acpi_device *device) | 1157 | static int acpi_video_device_remove_fs(struct acpi_device *device) |
1149 | { | 1158 | { |
1150 | struct acpi_video_device *vid_dev; | 1159 | struct acpi_video_device *vid_dev; |
1151 | struct proc_dir_entry *device_dir; | 1160 | struct proc_dir_entry *device_dir; |
1152 | 1161 | ||
1153 | vid_dev = acpi_driver_data(device); | 1162 | vid_dev = acpi_driver_data(device); |
1154 | if (!vid_dev || !vid_dev->video || !vid_dev->video->dir) | 1163 | if (!vid_dev || !vid_dev->video || !vid_dev->video->dir) |
1155 | return -ENODEV; | 1164 | return -ENODEV; |
1156 | 1165 | ||
1157 | device_dir = acpi_device_dir(device); | 1166 | device_dir = acpi_device_dir(device); |
1158 | if (device_dir) { | 1167 | if (device_dir) { |
1159 | remove_proc_entry("info", device_dir); | 1168 | remove_proc_entry("info", device_dir); |
1160 | remove_proc_entry("state", device_dir); | 1169 | remove_proc_entry("state", device_dir); |
1161 | remove_proc_entry("brightness", device_dir); | 1170 | remove_proc_entry("brightness", device_dir); |
1162 | remove_proc_entry("EDID", device_dir); | 1171 | remove_proc_entry("EDID", device_dir); |
1163 | remove_proc_entry(acpi_device_bid(device), vid_dev->video->dir); | 1172 | remove_proc_entry(acpi_device_bid(device), vid_dev->video->dir); |
1164 | acpi_device_dir(device) = NULL; | 1173 | acpi_device_dir(device) = NULL; |
1165 | } | 1174 | } |
1166 | 1175 | ||
1167 | return 0; | 1176 | return 0; |
1168 | } | 1177 | } |
1169 | 1178 | ||
1170 | /* video bus */ | 1179 | /* video bus */ |
1171 | static int acpi_video_bus_info_seq_show(struct seq_file *seq, void *offset) | 1180 | static int acpi_video_bus_info_seq_show(struct seq_file *seq, void *offset) |
1172 | { | 1181 | { |
1173 | struct acpi_video_bus *video = seq->private; | 1182 | struct acpi_video_bus *video = seq->private; |
1174 | 1183 | ||
1175 | 1184 | ||
1176 | if (!video) | 1185 | if (!video) |
1177 | goto end; | 1186 | goto end; |
1178 | 1187 | ||
1179 | seq_printf(seq, "Switching heads: %s\n", | 1188 | seq_printf(seq, "Switching heads: %s\n", |
1180 | video->flags.multihead ? "yes" : "no"); | 1189 | video->flags.multihead ? "yes" : "no"); |
1181 | seq_printf(seq, "Video ROM: %s\n", | 1190 | seq_printf(seq, "Video ROM: %s\n", |
1182 | video->flags.rom ? "yes" : "no"); | 1191 | video->flags.rom ? "yes" : "no"); |
1183 | seq_printf(seq, "Device to be POSTed on boot: %s\n", | 1192 | seq_printf(seq, "Device to be POSTed on boot: %s\n", |
1184 | video->flags.post ? "yes" : "no"); | 1193 | video->flags.post ? "yes" : "no"); |
1185 | 1194 | ||
1186 | end: | 1195 | end: |
1187 | return 0; | 1196 | return 0; |
1188 | } | 1197 | } |
1189 | 1198 | ||
1190 | static int acpi_video_bus_info_open_fs(struct inode *inode, struct file *file) | 1199 | static int acpi_video_bus_info_open_fs(struct inode *inode, struct file *file) |
1191 | { | 1200 | { |
1192 | return single_open(file, acpi_video_bus_info_seq_show, | 1201 | return single_open(file, acpi_video_bus_info_seq_show, |
1193 | PDE(inode)->data); | 1202 | PDE(inode)->data); |
1194 | } | 1203 | } |
1195 | 1204 | ||
1196 | static int acpi_video_bus_ROM_seq_show(struct seq_file *seq, void *offset) | 1205 | static int acpi_video_bus_ROM_seq_show(struct seq_file *seq, void *offset) |
1197 | { | 1206 | { |
1198 | struct acpi_video_bus *video = seq->private; | 1207 | struct acpi_video_bus *video = seq->private; |
1199 | 1208 | ||
1200 | 1209 | ||
1201 | if (!video) | 1210 | if (!video) |
1202 | goto end; | 1211 | goto end; |
1203 | 1212 | ||
1204 | printk(KERN_INFO PREFIX "Please implement %s\n", __func__); | 1213 | printk(KERN_INFO PREFIX "Please implement %s\n", __func__); |
1205 | seq_printf(seq, "<TODO>\n"); | 1214 | seq_printf(seq, "<TODO>\n"); |
1206 | 1215 | ||
1207 | end: | 1216 | end: |
1208 | return 0; | 1217 | return 0; |
1209 | } | 1218 | } |
1210 | 1219 | ||
1211 | static int acpi_video_bus_ROM_open_fs(struct inode *inode, struct file *file) | 1220 | static int acpi_video_bus_ROM_open_fs(struct inode *inode, struct file *file) |
1212 | { | 1221 | { |
1213 | return single_open(file, acpi_video_bus_ROM_seq_show, PDE(inode)->data); | 1222 | return single_open(file, acpi_video_bus_ROM_seq_show, PDE(inode)->data); |
1214 | } | 1223 | } |
1215 | 1224 | ||
1216 | static int acpi_video_bus_POST_info_seq_show(struct seq_file *seq, void *offset) | 1225 | static int acpi_video_bus_POST_info_seq_show(struct seq_file *seq, void *offset) |
1217 | { | 1226 | { |
1218 | struct acpi_video_bus *video = seq->private; | 1227 | struct acpi_video_bus *video = seq->private; |
1219 | unsigned long long options; | 1228 | unsigned long long options; |
1220 | int status; | 1229 | int status; |
1221 | 1230 | ||
1222 | 1231 | ||
1223 | if (!video) | 1232 | if (!video) |
1224 | goto end; | 1233 | goto end; |
1225 | 1234 | ||
1226 | status = acpi_video_bus_POST_options(video, &options); | 1235 | status = acpi_video_bus_POST_options(video, &options); |
1227 | if (ACPI_SUCCESS(status)) { | 1236 | if (ACPI_SUCCESS(status)) { |
1228 | if (!(options & 1)) { | 1237 | if (!(options & 1)) { |
1229 | printk(KERN_WARNING PREFIX | 1238 | printk(KERN_WARNING PREFIX |
1230 | "The motherboard VGA device is not listed as a possible POST device.\n"); | 1239 | "The motherboard VGA device is not listed as a possible POST device.\n"); |
1231 | printk(KERN_WARNING PREFIX | 1240 | printk(KERN_WARNING PREFIX |
1232 | "This indicates a BIOS bug. Please contact the manufacturer.\n"); | 1241 | "This indicates a BIOS bug. Please contact the manufacturer.\n"); |
1233 | } | 1242 | } |
1234 | printk("%llx\n", options); | 1243 | printk("%llx\n", options); |
1235 | seq_printf(seq, "can POST: <integrated video>"); | 1244 | seq_printf(seq, "can POST: <integrated video>"); |
1236 | if (options & 2) | 1245 | if (options & 2) |
1237 | seq_printf(seq, " <PCI video>"); | 1246 | seq_printf(seq, " <PCI video>"); |
1238 | if (options & 4) | 1247 | if (options & 4) |
1239 | seq_printf(seq, " <AGP video>"); | 1248 | seq_printf(seq, " <AGP video>"); |
1240 | seq_putc(seq, '\n'); | 1249 | seq_putc(seq, '\n'); |
1241 | } else | 1250 | } else |
1242 | seq_printf(seq, "<not supported>\n"); | 1251 | seq_printf(seq, "<not supported>\n"); |
1243 | end: | 1252 | end: |
1244 | return 0; | 1253 | return 0; |
1245 | } | 1254 | } |
1246 | 1255 | ||
1247 | static int | 1256 | static int |
1248 | acpi_video_bus_POST_info_open_fs(struct inode *inode, struct file *file) | 1257 | acpi_video_bus_POST_info_open_fs(struct inode *inode, struct file *file) |
1249 | { | 1258 | { |
1250 | return single_open(file, acpi_video_bus_POST_info_seq_show, | 1259 | return single_open(file, acpi_video_bus_POST_info_seq_show, |
1251 | PDE(inode)->data); | 1260 | PDE(inode)->data); |
1252 | } | 1261 | } |
1253 | 1262 | ||
1254 | static int acpi_video_bus_POST_seq_show(struct seq_file *seq, void *offset) | 1263 | static int acpi_video_bus_POST_seq_show(struct seq_file *seq, void *offset) |
1255 | { | 1264 | { |
1256 | struct acpi_video_bus *video = seq->private; | 1265 | struct acpi_video_bus *video = seq->private; |
1257 | int status; | 1266 | int status; |
1258 | unsigned long long id; | 1267 | unsigned long long id; |
1259 | 1268 | ||
1260 | 1269 | ||
1261 | if (!video) | 1270 | if (!video) |
1262 | goto end; | 1271 | goto end; |
1263 | 1272 | ||
1264 | status = acpi_video_bus_get_POST(video, &id); | 1273 | status = acpi_video_bus_get_POST(video, &id); |
1265 | if (!ACPI_SUCCESS(status)) { | 1274 | if (!ACPI_SUCCESS(status)) { |
1266 | seq_printf(seq, "<not supported>\n"); | 1275 | seq_printf(seq, "<not supported>\n"); |
1267 | goto end; | 1276 | goto end; |
1268 | } | 1277 | } |
1269 | seq_printf(seq, "device POSTed is <%s>\n", device_decode[id & 3]); | 1278 | seq_printf(seq, "device POSTed is <%s>\n", device_decode[id & 3]); |
1270 | 1279 | ||
1271 | end: | 1280 | end: |
1272 | return 0; | 1281 | return 0; |
1273 | } | 1282 | } |
1274 | 1283 | ||
1275 | static int acpi_video_bus_DOS_seq_show(struct seq_file *seq, void *offset) | 1284 | static int acpi_video_bus_DOS_seq_show(struct seq_file *seq, void *offset) |
1276 | { | 1285 | { |
1277 | struct acpi_video_bus *video = seq->private; | 1286 | struct acpi_video_bus *video = seq->private; |
1278 | 1287 | ||
1279 | 1288 | ||
1280 | seq_printf(seq, "DOS setting: <%d>\n", video->dos_setting); | 1289 | seq_printf(seq, "DOS setting: <%d>\n", video->dos_setting); |
1281 | 1290 | ||
1282 | return 0; | 1291 | return 0; |
1283 | } | 1292 | } |
1284 | 1293 | ||
1285 | static int acpi_video_bus_POST_open_fs(struct inode *inode, struct file *file) | 1294 | static int acpi_video_bus_POST_open_fs(struct inode *inode, struct file *file) |
1286 | { | 1295 | { |
1287 | return single_open(file, acpi_video_bus_POST_seq_show, | 1296 | return single_open(file, acpi_video_bus_POST_seq_show, |
1288 | PDE(inode)->data); | 1297 | PDE(inode)->data); |
1289 | } | 1298 | } |
1290 | 1299 | ||
1291 | static int acpi_video_bus_DOS_open_fs(struct inode *inode, struct file *file) | 1300 | static int acpi_video_bus_DOS_open_fs(struct inode *inode, struct file *file) |
1292 | { | 1301 | { |
1293 | return single_open(file, acpi_video_bus_DOS_seq_show, PDE(inode)->data); | 1302 | return single_open(file, acpi_video_bus_DOS_seq_show, PDE(inode)->data); |
1294 | } | 1303 | } |
1295 | 1304 | ||
1296 | static ssize_t | 1305 | static ssize_t |
1297 | acpi_video_bus_write_POST(struct file *file, | 1306 | acpi_video_bus_write_POST(struct file *file, |
1298 | const char __user * buffer, | 1307 | const char __user * buffer, |
1299 | size_t count, loff_t * data) | 1308 | size_t count, loff_t * data) |
1300 | { | 1309 | { |
1301 | int status; | 1310 | int status; |
1302 | struct seq_file *m = file->private_data; | 1311 | struct seq_file *m = file->private_data; |
1303 | struct acpi_video_bus *video = m->private; | 1312 | struct acpi_video_bus *video = m->private; |
1304 | char str[12] = { 0 }; | 1313 | char str[12] = { 0 }; |
1305 | unsigned long long opt, options; | 1314 | unsigned long long opt, options; |
1306 | 1315 | ||
1307 | 1316 | ||
1308 | if (!video || count + 1 > sizeof str) | 1317 | if (!video || count + 1 > sizeof str) |
1309 | return -EINVAL; | 1318 | return -EINVAL; |
1310 | 1319 | ||
1311 | status = acpi_video_bus_POST_options(video, &options); | 1320 | status = acpi_video_bus_POST_options(video, &options); |
1312 | if (!ACPI_SUCCESS(status)) | 1321 | if (!ACPI_SUCCESS(status)) |
1313 | return -EINVAL; | 1322 | return -EINVAL; |
1314 | 1323 | ||
1315 | if (copy_from_user(str, buffer, count)) | 1324 | if (copy_from_user(str, buffer, count)) |
1316 | return -EFAULT; | 1325 | return -EFAULT; |
1317 | 1326 | ||
1318 | str[count] = 0; | 1327 | str[count] = 0; |
1319 | opt = strtoul(str, NULL, 0); | 1328 | opt = strtoul(str, NULL, 0); |
1320 | if (opt > 3) | 1329 | if (opt > 3) |
1321 | return -EFAULT; | 1330 | return -EFAULT; |
1322 | 1331 | ||
1323 | /* just in case an OEM 'forgot' the motherboard... */ | 1332 | /* just in case an OEM 'forgot' the motherboard... */ |
1324 | options |= 1; | 1333 | options |= 1; |
1325 | 1334 | ||
1326 | if (options & (1ul << opt)) { | 1335 | if (options & (1ul << opt)) { |
1327 | status = acpi_video_bus_set_POST(video, opt); | 1336 | status = acpi_video_bus_set_POST(video, opt); |
1328 | if (!ACPI_SUCCESS(status)) | 1337 | if (!ACPI_SUCCESS(status)) |
1329 | return -EFAULT; | 1338 | return -EFAULT; |
1330 | 1339 | ||
1331 | } | 1340 | } |
1332 | 1341 | ||
1333 | return count; | 1342 | return count; |
1334 | } | 1343 | } |
1335 | 1344 | ||
1336 | static ssize_t | 1345 | static ssize_t |
1337 | acpi_video_bus_write_DOS(struct file *file, | 1346 | acpi_video_bus_write_DOS(struct file *file, |
1338 | const char __user * buffer, | 1347 | const char __user * buffer, |
1339 | size_t count, loff_t * data) | 1348 | size_t count, loff_t * data) |
1340 | { | 1349 | { |
1341 | int status; | 1350 | int status; |
1342 | struct seq_file *m = file->private_data; | 1351 | struct seq_file *m = file->private_data; |
1343 | struct acpi_video_bus *video = m->private; | 1352 | struct acpi_video_bus *video = m->private; |
1344 | char str[12] = { 0 }; | 1353 | char str[12] = { 0 }; |
1345 | unsigned long opt; | 1354 | unsigned long opt; |
1346 | 1355 | ||
1347 | 1356 | ||
1348 | if (!video || count + 1 > sizeof str) | 1357 | if (!video || count + 1 > sizeof str) |
1349 | return -EINVAL; | 1358 | return -EINVAL; |
1350 | 1359 | ||
1351 | if (copy_from_user(str, buffer, count)) | 1360 | if (copy_from_user(str, buffer, count)) |
1352 | return -EFAULT; | 1361 | return -EFAULT; |
1353 | 1362 | ||
1354 | str[count] = 0; | 1363 | str[count] = 0; |
1355 | opt = strtoul(str, NULL, 0); | 1364 | opt = strtoul(str, NULL, 0); |
1356 | if (opt > 7) | 1365 | if (opt > 7) |
1357 | return -EFAULT; | 1366 | return -EFAULT; |
1358 | 1367 | ||
1359 | status = acpi_video_bus_DOS(video, opt & 0x3, (opt & 0x4) >> 2); | 1368 | status = acpi_video_bus_DOS(video, opt & 0x3, (opt & 0x4) >> 2); |
1360 | 1369 | ||
1361 | if (!ACPI_SUCCESS(status)) | 1370 | if (!ACPI_SUCCESS(status)) |
1362 | return -EFAULT; | 1371 | return -EFAULT; |
1363 | 1372 | ||
1364 | return count; | 1373 | return count; |
1365 | } | 1374 | } |
1366 | 1375 | ||
1367 | static int acpi_video_bus_add_fs(struct acpi_device *device) | 1376 | static int acpi_video_bus_add_fs(struct acpi_device *device) |
1368 | { | 1377 | { |
1369 | struct acpi_video_bus *video = acpi_driver_data(device); | 1378 | struct acpi_video_bus *video = acpi_driver_data(device); |
1370 | struct proc_dir_entry *device_dir; | 1379 | struct proc_dir_entry *device_dir; |
1371 | struct proc_dir_entry *entry; | 1380 | struct proc_dir_entry *entry; |
1372 | 1381 | ||
1373 | device_dir = proc_mkdir(acpi_device_bid(device), acpi_video_dir); | 1382 | device_dir = proc_mkdir(acpi_device_bid(device), acpi_video_dir); |
1374 | if (!device_dir) | 1383 | if (!device_dir) |
1375 | return -ENOMEM; | 1384 | return -ENOMEM; |
1376 | 1385 | ||
1377 | device_dir->owner = THIS_MODULE; | 1386 | device_dir->owner = THIS_MODULE; |
1378 | 1387 | ||
1379 | /* 'info' [R] */ | 1388 | /* 'info' [R] */ |
1380 | entry = proc_create_data("info", S_IRUGO, device_dir, | 1389 | entry = proc_create_data("info", S_IRUGO, device_dir, |
1381 | &acpi_video_bus_info_fops, | 1390 | &acpi_video_bus_info_fops, |
1382 | acpi_driver_data(device)); | 1391 | acpi_driver_data(device)); |
1383 | if (!entry) | 1392 | if (!entry) |
1384 | goto err_remove_dir; | 1393 | goto err_remove_dir; |
1385 | 1394 | ||
1386 | /* 'ROM' [R] */ | 1395 | /* 'ROM' [R] */ |
1387 | entry = proc_create_data("ROM", S_IRUGO, device_dir, | 1396 | entry = proc_create_data("ROM", S_IRUGO, device_dir, |
1388 | &acpi_video_bus_ROM_fops, | 1397 | &acpi_video_bus_ROM_fops, |
1389 | acpi_driver_data(device)); | 1398 | acpi_driver_data(device)); |
1390 | if (!entry) | 1399 | if (!entry) |
1391 | goto err_remove_info; | 1400 | goto err_remove_info; |
1392 | 1401 | ||
1393 | /* 'POST_info' [R] */ | 1402 | /* 'POST_info' [R] */ |
1394 | entry = proc_create_data("POST_info", S_IRUGO, device_dir, | 1403 | entry = proc_create_data("POST_info", S_IRUGO, device_dir, |
1395 | &acpi_video_bus_POST_info_fops, | 1404 | &acpi_video_bus_POST_info_fops, |
1396 | acpi_driver_data(device)); | 1405 | acpi_driver_data(device)); |
1397 | if (!entry) | 1406 | if (!entry) |
1398 | goto err_remove_rom; | 1407 | goto err_remove_rom; |
1399 | 1408 | ||
1400 | /* 'POST' [R/W] */ | 1409 | /* 'POST' [R/W] */ |
1401 | acpi_video_bus_POST_fops.write = acpi_video_bus_write_POST; | 1410 | acpi_video_bus_POST_fops.write = acpi_video_bus_write_POST; |
1402 | entry = proc_create_data("POST", S_IFREG | S_IRUGO | S_IWUSR, | 1411 | entry = proc_create_data("POST", S_IFREG | S_IRUGO | S_IWUSR, |
1403 | device_dir, | 1412 | device_dir, |
1404 | &acpi_video_bus_POST_fops, | 1413 | &acpi_video_bus_POST_fops, |
1405 | acpi_driver_data(device)); | 1414 | acpi_driver_data(device)); |
1406 | if (!entry) | 1415 | if (!entry) |
1407 | goto err_remove_post_info; | 1416 | goto err_remove_post_info; |
1408 | 1417 | ||
1409 | /* 'DOS' [R/W] */ | 1418 | /* 'DOS' [R/W] */ |
1410 | acpi_video_bus_DOS_fops.write = acpi_video_bus_write_DOS; | 1419 | acpi_video_bus_DOS_fops.write = acpi_video_bus_write_DOS; |
1411 | entry = proc_create_data("DOS", S_IFREG | S_IRUGO | S_IWUSR, | 1420 | entry = proc_create_data("DOS", S_IFREG | S_IRUGO | S_IWUSR, |
1412 | device_dir, | 1421 | device_dir, |
1413 | &acpi_video_bus_DOS_fops, | 1422 | &acpi_video_bus_DOS_fops, |
1414 | acpi_driver_data(device)); | 1423 | acpi_driver_data(device)); |
1415 | if (!entry) | 1424 | if (!entry) |
1416 | goto err_remove_post; | 1425 | goto err_remove_post; |
1417 | 1426 | ||
1418 | video->dir = acpi_device_dir(device) = device_dir; | 1427 | video->dir = acpi_device_dir(device) = device_dir; |
1419 | return 0; | 1428 | return 0; |
1420 | 1429 | ||
1421 | err_remove_post: | 1430 | err_remove_post: |
1422 | remove_proc_entry("POST", device_dir); | 1431 | remove_proc_entry("POST", device_dir); |
1423 | err_remove_post_info: | 1432 | err_remove_post_info: |
1424 | remove_proc_entry("POST_info", device_dir); | 1433 | remove_proc_entry("POST_info", device_dir); |
1425 | err_remove_rom: | 1434 | err_remove_rom: |
1426 | remove_proc_entry("ROM", device_dir); | 1435 | remove_proc_entry("ROM", device_dir); |
1427 | err_remove_info: | 1436 | err_remove_info: |
1428 | remove_proc_entry("info", device_dir); | 1437 | remove_proc_entry("info", device_dir); |
1429 | err_remove_dir: | 1438 | err_remove_dir: |
1430 | remove_proc_entry(acpi_device_bid(device), acpi_video_dir); | 1439 | remove_proc_entry(acpi_device_bid(device), acpi_video_dir); |
1431 | return -ENOMEM; | 1440 | return -ENOMEM; |
1432 | } | 1441 | } |
1433 | 1442 | ||
1434 | static int acpi_video_bus_remove_fs(struct acpi_device *device) | 1443 | static int acpi_video_bus_remove_fs(struct acpi_device *device) |
1435 | { | 1444 | { |
1436 | struct proc_dir_entry *device_dir = acpi_device_dir(device); | 1445 | struct proc_dir_entry *device_dir = acpi_device_dir(device); |
1437 | 1446 | ||
1438 | if (device_dir) { | 1447 | if (device_dir) { |
1439 | remove_proc_entry("info", device_dir); | 1448 | remove_proc_entry("info", device_dir); |
1440 | remove_proc_entry("ROM", device_dir); | 1449 | remove_proc_entry("ROM", device_dir); |
1441 | remove_proc_entry("POST_info", device_dir); | 1450 | remove_proc_entry("POST_info", device_dir); |
1442 | remove_proc_entry("POST", device_dir); | 1451 | remove_proc_entry("POST", device_dir); |
1443 | remove_proc_entry("DOS", device_dir); | 1452 | remove_proc_entry("DOS", device_dir); |
1444 | remove_proc_entry(acpi_device_bid(device), acpi_video_dir); | 1453 | remove_proc_entry(acpi_device_bid(device), acpi_video_dir); |
1445 | acpi_device_dir(device) = NULL; | 1454 | acpi_device_dir(device) = NULL; |
1446 | } | 1455 | } |
1447 | 1456 | ||
1448 | return 0; | 1457 | return 0; |
1449 | } | 1458 | } |
1450 | 1459 | ||
1451 | /* -------------------------------------------------------------------------- | 1460 | /* -------------------------------------------------------------------------- |
1452 | Driver Interface | 1461 | Driver Interface |
1453 | -------------------------------------------------------------------------- */ | 1462 | -------------------------------------------------------------------------- */ |
1454 | 1463 | ||
1455 | /* device interface */ | 1464 | /* device interface */ |
1456 | static struct acpi_video_device_attrib* | 1465 | static struct acpi_video_device_attrib* |
1457 | acpi_video_get_device_attr(struct acpi_video_bus *video, unsigned long device_id) | 1466 | acpi_video_get_device_attr(struct acpi_video_bus *video, unsigned long device_id) |
1458 | { | 1467 | { |
1459 | struct acpi_video_enumerated_device *ids; | 1468 | struct acpi_video_enumerated_device *ids; |
1460 | int i; | 1469 | int i; |
1461 | 1470 | ||
1462 | for (i = 0; i < video->attached_count; i++) { | 1471 | for (i = 0; i < video->attached_count; i++) { |
1463 | ids = &video->attached_array[i]; | 1472 | ids = &video->attached_array[i]; |
1464 | if ((ids->value.int_val & 0xffff) == device_id) | 1473 | if ((ids->value.int_val & 0xffff) == device_id) |
1465 | return &ids->value.attrib; | 1474 | return &ids->value.attrib; |
1466 | } | 1475 | } |
1467 | 1476 | ||
1468 | return NULL; | 1477 | return NULL; |
1469 | } | 1478 | } |
1470 | 1479 | ||
1471 | static int | 1480 | static int |
1472 | acpi_video_bus_get_one_device(struct acpi_device *device, | 1481 | acpi_video_bus_get_one_device(struct acpi_device *device, |
1473 | struct acpi_video_bus *video) | 1482 | struct acpi_video_bus *video) |
1474 | { | 1483 | { |
1475 | unsigned long long device_id; | 1484 | unsigned long long device_id; |
1476 | int status; | 1485 | int status; |
1477 | struct acpi_video_device *data; | 1486 | struct acpi_video_device *data; |
1478 | struct acpi_video_device_attrib* attribute; | 1487 | struct acpi_video_device_attrib* attribute; |
1479 | 1488 | ||
1480 | if (!device || !video) | 1489 | if (!device || !video) |
1481 | return -EINVAL; | 1490 | return -EINVAL; |
1482 | 1491 | ||
1483 | status = | 1492 | status = |
1484 | acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id); | 1493 | acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id); |
1485 | if (ACPI_SUCCESS(status)) { | 1494 | if (ACPI_SUCCESS(status)) { |
1486 | 1495 | ||
1487 | data = kzalloc(sizeof(struct acpi_video_device), GFP_KERNEL); | 1496 | data = kzalloc(sizeof(struct acpi_video_device), GFP_KERNEL); |
1488 | if (!data) | 1497 | if (!data) |
1489 | return -ENOMEM; | 1498 | return -ENOMEM; |
1490 | 1499 | ||
1491 | strcpy(acpi_device_name(device), ACPI_VIDEO_DEVICE_NAME); | 1500 | strcpy(acpi_device_name(device), ACPI_VIDEO_DEVICE_NAME); |
1492 | strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS); | 1501 | strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS); |
1493 | device->driver_data = data; | 1502 | device->driver_data = data; |
1494 | 1503 | ||
1495 | data->device_id = device_id; | 1504 | data->device_id = device_id; |
1496 | data->video = video; | 1505 | data->video = video; |
1497 | data->dev = device; | 1506 | data->dev = device; |
1498 | 1507 | ||
1499 | attribute = acpi_video_get_device_attr(video, device_id); | 1508 | attribute = acpi_video_get_device_attr(video, device_id); |
1500 | 1509 | ||
1501 | if((attribute != NULL) && attribute->device_id_scheme) { | 1510 | if((attribute != NULL) && attribute->device_id_scheme) { |
1502 | switch (attribute->display_type) { | 1511 | switch (attribute->display_type) { |
1503 | case ACPI_VIDEO_DISPLAY_CRT: | 1512 | case ACPI_VIDEO_DISPLAY_CRT: |
1504 | data->flags.crt = 1; | 1513 | data->flags.crt = 1; |
1505 | break; | 1514 | break; |
1506 | case ACPI_VIDEO_DISPLAY_TV: | 1515 | case ACPI_VIDEO_DISPLAY_TV: |
1507 | data->flags.tvout = 1; | 1516 | data->flags.tvout = 1; |
1508 | break; | 1517 | break; |
1509 | case ACPI_VIDEO_DISPLAY_DVI: | 1518 | case ACPI_VIDEO_DISPLAY_DVI: |
1510 | data->flags.dvi = 1; | 1519 | data->flags.dvi = 1; |
1511 | break; | 1520 | break; |
1512 | case ACPI_VIDEO_DISPLAY_LCD: | 1521 | case ACPI_VIDEO_DISPLAY_LCD: |
1513 | data->flags.lcd = 1; | 1522 | data->flags.lcd = 1; |
1514 | break; | 1523 | break; |
1515 | default: | 1524 | default: |
1516 | data->flags.unknown = 1; | 1525 | data->flags.unknown = 1; |
1517 | break; | 1526 | break; |
1518 | } | 1527 | } |
1519 | if(attribute->bios_can_detect) | 1528 | if(attribute->bios_can_detect) |
1520 | data->flags.bios = 1; | 1529 | data->flags.bios = 1; |
1521 | } else | 1530 | } else |
1522 | data->flags.unknown = 1; | 1531 | data->flags.unknown = 1; |
1523 | 1532 | ||
1524 | acpi_video_device_bind(video, data); | 1533 | acpi_video_device_bind(video, data); |
1525 | acpi_video_device_find_cap(data); | 1534 | acpi_video_device_find_cap(data); |
1526 | 1535 | ||
1527 | status = acpi_install_notify_handler(device->handle, | 1536 | status = acpi_install_notify_handler(device->handle, |
1528 | ACPI_DEVICE_NOTIFY, | 1537 | ACPI_DEVICE_NOTIFY, |
1529 | acpi_video_device_notify, | 1538 | acpi_video_device_notify, |
1530 | data); | 1539 | data); |
1531 | if (ACPI_FAILURE(status)) { | 1540 | if (ACPI_FAILURE(status)) { |
1532 | printk(KERN_ERR PREFIX | 1541 | printk(KERN_ERR PREFIX |
1533 | "Error installing notify handler\n"); | 1542 | "Error installing notify handler\n"); |
1534 | if(data->brightness) | 1543 | if(data->brightness) |
1535 | kfree(data->brightness->levels); | 1544 | kfree(data->brightness->levels); |
1536 | kfree(data->brightness); | 1545 | kfree(data->brightness); |
1537 | kfree(data); | 1546 | kfree(data); |
1538 | return -ENODEV; | 1547 | return -ENODEV; |
1539 | } | 1548 | } |
1540 | 1549 | ||
1541 | mutex_lock(&video->device_list_lock); | 1550 | mutex_lock(&video->device_list_lock); |
1542 | list_add_tail(&data->entry, &video->video_device_list); | 1551 | list_add_tail(&data->entry, &video->video_device_list); |
1543 | mutex_unlock(&video->device_list_lock); | 1552 | mutex_unlock(&video->device_list_lock); |
1544 | 1553 | ||
1545 | acpi_video_device_add_fs(device); | 1554 | acpi_video_device_add_fs(device); |
1546 | 1555 | ||
1547 | return 0; | 1556 | return 0; |
1548 | } | 1557 | } |
1549 | 1558 | ||
1550 | return -ENOENT; | 1559 | return -ENOENT; |
1551 | } | 1560 | } |
1552 | 1561 | ||
1553 | /* | 1562 | /* |
1554 | * Arg: | 1563 | * Arg: |
1555 | * video : video bus device | 1564 | * video : video bus device |
1556 | * | 1565 | * |
1557 | * Return: | 1566 | * Return: |
1558 | * none | 1567 | * none |
1559 | * | 1568 | * |
1560 | * Enumerate the video device list of the video bus, | 1569 | * Enumerate the video device list of the video bus, |
1561 | * bind the ids with the corresponding video devices | 1570 | * bind the ids with the corresponding video devices |
1562 | * under the video bus. | 1571 | * under the video bus. |
1563 | */ | 1572 | */ |
1564 | 1573 | ||
1565 | static void acpi_video_device_rebind(struct acpi_video_bus *video) | 1574 | static void acpi_video_device_rebind(struct acpi_video_bus *video) |
1566 | { | 1575 | { |
1567 | struct acpi_video_device *dev; | 1576 | struct acpi_video_device *dev; |
1568 | 1577 | ||
1569 | mutex_lock(&video->device_list_lock); | 1578 | mutex_lock(&video->device_list_lock); |
1570 | 1579 | ||
1571 | list_for_each_entry(dev, &video->video_device_list, entry) | 1580 | list_for_each_entry(dev, &video->video_device_list, entry) |
1572 | acpi_video_device_bind(video, dev); | 1581 | acpi_video_device_bind(video, dev); |
1573 | 1582 | ||
1574 | mutex_unlock(&video->device_list_lock); | 1583 | mutex_unlock(&video->device_list_lock); |
1575 | } | 1584 | } |
1576 | 1585 | ||
1577 | /* | 1586 | /* |
1578 | * Arg: | 1587 | * Arg: |
1579 | * video : video bus device | 1588 | * video : video bus device |
1580 | * device : video output device under the video | 1589 | * device : video output device under the video |
1581 | * bus | 1590 | * bus |
1582 | * | 1591 | * |
1583 | * Return: | 1592 | * Return: |
1584 | * none | 1593 | * none |
1585 | * | 1594 | * |
1586 | * Bind the ids with the corresponding video devices | 1595 | * Bind the ids with the corresponding video devices |
1587 | * under the video bus. | 1596 | * under the video bus. |
1588 | */ | 1597 | */ |
1589 | 1598 | ||
1590 | static void | 1599 | static void |
1591 | acpi_video_device_bind(struct acpi_video_bus *video, | 1600 | acpi_video_device_bind(struct acpi_video_bus *video, |
1592 | struct acpi_video_device *device) | 1601 | struct acpi_video_device *device) |
1593 | { | 1602 | { |
1594 | struct acpi_video_enumerated_device *ids; | 1603 | struct acpi_video_enumerated_device *ids; |
1595 | int i; | 1604 | int i; |
1596 | 1605 | ||
1597 | for (i = 0; i < video->attached_count; i++) { | 1606 | for (i = 0; i < video->attached_count; i++) { |
1598 | ids = &video->attached_array[i]; | 1607 | ids = &video->attached_array[i]; |
1599 | if (device->device_id == (ids->value.int_val & 0xffff)) { | 1608 | if (device->device_id == (ids->value.int_val & 0xffff)) { |
1600 | ids->bind_info = device; | 1609 | ids->bind_info = device; |
1601 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "device_bind %d\n", i)); | 1610 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "device_bind %d\n", i)); |
1602 | } | 1611 | } |
1603 | } | 1612 | } |
1604 | } | 1613 | } |
1605 | 1614 | ||
1606 | /* | 1615 | /* |
1607 | * Arg: | 1616 | * Arg: |
1608 | * video : video bus device | 1617 | * video : video bus device |
1609 | * | 1618 | * |
1610 | * Return: | 1619 | * Return: |
1611 | * < 0 : error | 1620 | * < 0 : error |
1612 | * | 1621 | * |
1613 | * Call _DOD to enumerate all devices attached to display adapter | 1622 | * Call _DOD to enumerate all devices attached to display adapter |
1614 | * | 1623 | * |
1615 | */ | 1624 | */ |
1616 | 1625 | ||
1617 | static int acpi_video_device_enumerate(struct acpi_video_bus *video) | 1626 | static int acpi_video_device_enumerate(struct acpi_video_bus *video) |
1618 | { | 1627 | { |
1619 | int status; | 1628 | int status; |
1620 | int count; | 1629 | int count; |
1621 | int i; | 1630 | int i; |
1622 | struct acpi_video_enumerated_device *active_list; | 1631 | struct acpi_video_enumerated_device *active_list; |
1623 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | 1632 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
1624 | union acpi_object *dod = NULL; | 1633 | union acpi_object *dod = NULL; |
1625 | union acpi_object *obj; | 1634 | union acpi_object *obj; |
1626 | 1635 | ||
1627 | status = acpi_evaluate_object(video->device->handle, "_DOD", NULL, &buffer); | 1636 | status = acpi_evaluate_object(video->device->handle, "_DOD", NULL, &buffer); |
1628 | if (!ACPI_SUCCESS(status)) { | 1637 | if (!ACPI_SUCCESS(status)) { |
1629 | ACPI_EXCEPTION((AE_INFO, status, "Evaluating _DOD")); | 1638 | ACPI_EXCEPTION((AE_INFO, status, "Evaluating _DOD")); |
1630 | return status; | 1639 | return status; |
1631 | } | 1640 | } |
1632 | 1641 | ||
1633 | dod = buffer.pointer; | 1642 | dod = buffer.pointer; |
1634 | if (!dod || (dod->type != ACPI_TYPE_PACKAGE)) { | 1643 | if (!dod || (dod->type != ACPI_TYPE_PACKAGE)) { |
1635 | ACPI_EXCEPTION((AE_INFO, status, "Invalid _DOD data")); | 1644 | ACPI_EXCEPTION((AE_INFO, status, "Invalid _DOD data")); |
1636 | status = -EFAULT; | 1645 | status = -EFAULT; |
1637 | goto out; | 1646 | goto out; |
1638 | } | 1647 | } |
1639 | 1648 | ||
1640 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d video heads in _DOD\n", | 1649 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d video heads in _DOD\n", |
1641 | dod->package.count)); | 1650 | dod->package.count)); |
1642 | 1651 | ||
1643 | active_list = kcalloc(1 + dod->package.count, | 1652 | active_list = kcalloc(1 + dod->package.count, |
1644 | sizeof(struct acpi_video_enumerated_device), | 1653 | sizeof(struct acpi_video_enumerated_device), |
1645 | GFP_KERNEL); | 1654 | GFP_KERNEL); |
1646 | if (!active_list) { | 1655 | if (!active_list) { |
1647 | status = -ENOMEM; | 1656 | status = -ENOMEM; |
1648 | goto out; | 1657 | goto out; |
1649 | } | 1658 | } |
1650 | 1659 | ||
1651 | count = 0; | 1660 | count = 0; |
1652 | for (i = 0; i < dod->package.count; i++) { | 1661 | for (i = 0; i < dod->package.count; i++) { |
1653 | obj = &dod->package.elements[i]; | 1662 | obj = &dod->package.elements[i]; |
1654 | 1663 | ||
1655 | if (obj->type != ACPI_TYPE_INTEGER) { | 1664 | if (obj->type != ACPI_TYPE_INTEGER) { |
1656 | printk(KERN_ERR PREFIX | 1665 | printk(KERN_ERR PREFIX |
1657 | "Invalid _DOD data in element %d\n", i); | 1666 | "Invalid _DOD data in element %d\n", i); |
1658 | continue; | 1667 | continue; |
1659 | } | 1668 | } |
1660 | 1669 | ||
1661 | active_list[count].value.int_val = obj->integer.value; | 1670 | active_list[count].value.int_val = obj->integer.value; |
1662 | active_list[count].bind_info = NULL; | 1671 | active_list[count].bind_info = NULL; |
1663 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "dod element[%d] = %d\n", i, | 1672 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "dod element[%d] = %d\n", i, |
1664 | (int)obj->integer.value)); | 1673 | (int)obj->integer.value)); |
1665 | count++; | 1674 | count++; |
1666 | } | 1675 | } |
1667 | 1676 | ||
1668 | kfree(video->attached_array); | 1677 | kfree(video->attached_array); |
1669 | 1678 | ||
1670 | video->attached_array = active_list; | 1679 | video->attached_array = active_list; |
1671 | video->attached_count = count; | 1680 | video->attached_count = count; |
1672 | 1681 | ||
1673 | out: | 1682 | out: |
1674 | kfree(buffer.pointer); | 1683 | kfree(buffer.pointer); |
1675 | return status; | 1684 | return status; |
1676 | } | 1685 | } |
1677 | 1686 | ||
1678 | static int | 1687 | static int |
1679 | acpi_video_get_next_level(struct acpi_video_device *device, | 1688 | acpi_video_get_next_level(struct acpi_video_device *device, |
1680 | u32 level_current, u32 event) | 1689 | u32 level_current, u32 event) |
1681 | { | 1690 | { |
1682 | int min, max, min_above, max_below, i, l, delta = 255; | 1691 | int min, max, min_above, max_below, i, l, delta = 255; |
1683 | max = max_below = 0; | 1692 | max = max_below = 0; |
1684 | min = min_above = 255; | 1693 | min = min_above = 255; |
1685 | /* Find closest level to level_current */ | 1694 | /* Find closest level to level_current */ |
1686 | for (i = 0; i < device->brightness->count; i++) { | 1695 | for (i = 0; i < device->brightness->count; i++) { |
1687 | l = device->brightness->levels[i]; | 1696 | l = device->brightness->levels[i]; |
1688 | if (abs(l - level_current) < abs(delta)) { | 1697 | if (abs(l - level_current) < abs(delta)) { |
1689 | delta = l - level_current; | 1698 | delta = l - level_current; |
1690 | if (!delta) | 1699 | if (!delta) |
1691 | break; | 1700 | break; |
1692 | } | 1701 | } |
1693 | } | 1702 | } |
1694 | /* Ajust level_current to closest available level */ | 1703 | /* Ajust level_current to closest available level */ |
1695 | level_current += delta; | 1704 | level_current += delta; |
1696 | for (i = 0; i < device->brightness->count; i++) { | 1705 | for (i = 0; i < device->brightness->count; i++) { |
1697 | l = device->brightness->levels[i]; | 1706 | l = device->brightness->levels[i]; |
1698 | if (l < min) | 1707 | if (l < min) |
1699 | min = l; | 1708 | min = l; |
1700 | if (l > max) | 1709 | if (l > max) |
1701 | max = l; | 1710 | max = l; |
1702 | if (l < min_above && l > level_current) | 1711 | if (l < min_above && l > level_current) |
1703 | min_above = l; | 1712 | min_above = l; |
1704 | if (l > max_below && l < level_current) | 1713 | if (l > max_below && l < level_current) |
1705 | max_below = l; | 1714 | max_below = l; |
1706 | } | 1715 | } |
1707 | 1716 | ||
1708 | switch (event) { | 1717 | switch (event) { |
1709 | case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS: | 1718 | case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS: |
1710 | return (level_current < max) ? min_above : min; | 1719 | return (level_current < max) ? min_above : min; |
1711 | case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS: | 1720 | case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS: |
1712 | return (level_current < max) ? min_above : max; | 1721 | return (level_current < max) ? min_above : max; |
1713 | case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS: | 1722 | case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS: |
1714 | return (level_current > min) ? max_below : min; | 1723 | return (level_current > min) ? max_below : min; |
1715 | case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS: | 1724 | case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS: |
1716 | case ACPI_VIDEO_NOTIFY_DISPLAY_OFF: | 1725 | case ACPI_VIDEO_NOTIFY_DISPLAY_OFF: |
1717 | return 0; | 1726 | return 0; |
1718 | default: | 1727 | default: |
1719 | return level_current; | 1728 | return level_current; |
1720 | } | 1729 | } |
1721 | } | 1730 | } |
1722 | 1731 | ||
1723 | static void | 1732 | static void |
1724 | acpi_video_switch_brightness(struct acpi_video_device *device, int event) | 1733 | acpi_video_switch_brightness(struct acpi_video_device *device, int event) |
1725 | { | 1734 | { |
1726 | unsigned long long level_current, level_next; | 1735 | unsigned long long level_current, level_next; |
1727 | if (!device->brightness) | 1736 | if (!device->brightness) |
1728 | return; | 1737 | return; |
1729 | acpi_video_device_lcd_get_level_current(device, &level_current); | 1738 | acpi_video_device_lcd_get_level_current(device, &level_current); |
1730 | level_next = acpi_video_get_next_level(device, level_current, event); | 1739 | level_next = acpi_video_get_next_level(device, level_current, event); |
1731 | acpi_video_device_lcd_set_level(device, level_next); | 1740 | acpi_video_device_lcd_set_level(device, level_next); |
1732 | } | 1741 | } |
1733 | 1742 | ||
1734 | static int | 1743 | static int |
1735 | acpi_video_bus_get_devices(struct acpi_video_bus *video, | 1744 | acpi_video_bus_get_devices(struct acpi_video_bus *video, |
1736 | struct acpi_device *device) | 1745 | struct acpi_device *device) |
1737 | { | 1746 | { |
1738 | int status = 0; | 1747 | int status = 0; |
1739 | struct acpi_device *dev; | 1748 | struct acpi_device *dev; |
1740 | 1749 | ||
1741 | acpi_video_device_enumerate(video); | 1750 | acpi_video_device_enumerate(video); |
1742 | 1751 | ||
1743 | list_for_each_entry(dev, &device->children, node) { | 1752 | list_for_each_entry(dev, &device->children, node) { |
1744 | 1753 | ||
1745 | status = acpi_video_bus_get_one_device(dev, video); | 1754 | status = acpi_video_bus_get_one_device(dev, video); |
1746 | if (ACPI_FAILURE(status)) { | 1755 | if (ACPI_FAILURE(status)) { |
1747 | printk(KERN_WARNING PREFIX | 1756 | printk(KERN_WARNING PREFIX |
1748 | "Cant attach device"); | 1757 | "Cant attach device"); |
1749 | continue; | 1758 | continue; |
1750 | } | 1759 | } |
1751 | } | 1760 | } |
1752 | return status; | 1761 | return status; |
1753 | } | 1762 | } |
1754 | 1763 | ||
1755 | static int acpi_video_bus_put_one_device(struct acpi_video_device *device) | 1764 | static int acpi_video_bus_put_one_device(struct acpi_video_device *device) |
1756 | { | 1765 | { |
1757 | acpi_status status; | 1766 | acpi_status status; |
1758 | struct acpi_video_bus *video; | 1767 | struct acpi_video_bus *video; |
1759 | 1768 | ||
1760 | 1769 | ||
1761 | if (!device || !device->video) | 1770 | if (!device || !device->video) |
1762 | return -ENOENT; | 1771 | return -ENOENT; |
1763 | 1772 | ||
1764 | video = device->video; | 1773 | video = device->video; |
1765 | 1774 | ||
1766 | acpi_video_device_remove_fs(device->dev); | 1775 | acpi_video_device_remove_fs(device->dev); |
1767 | 1776 | ||
1768 | status = acpi_remove_notify_handler(device->dev->handle, | 1777 | status = acpi_remove_notify_handler(device->dev->handle, |
1769 | ACPI_DEVICE_NOTIFY, | 1778 | ACPI_DEVICE_NOTIFY, |
1770 | acpi_video_device_notify); | 1779 | acpi_video_device_notify); |
1771 | backlight_device_unregister(device->backlight); | 1780 | backlight_device_unregister(device->backlight); |
1772 | if (device->cdev) { | 1781 | if (device->cdev) { |
1773 | sysfs_remove_link(&device->dev->dev.kobj, | 1782 | sysfs_remove_link(&device->dev->dev.kobj, |
1774 | "thermal_cooling"); | 1783 | "thermal_cooling"); |
1775 | sysfs_remove_link(&device->cdev->device.kobj, | 1784 | sysfs_remove_link(&device->cdev->device.kobj, |
1776 | "device"); | 1785 | "device"); |
1777 | thermal_cooling_device_unregister(device->cdev); | 1786 | thermal_cooling_device_unregister(device->cdev); |
1778 | device->cdev = NULL; | 1787 | device->cdev = NULL; |
1779 | } | 1788 | } |
1780 | video_output_unregister(device->output_dev); | 1789 | video_output_unregister(device->output_dev); |
1781 | 1790 | ||
1782 | return 0; | 1791 | return 0; |
1783 | } | 1792 | } |
1784 | 1793 | ||
1785 | static int acpi_video_bus_put_devices(struct acpi_video_bus *video) | 1794 | static int acpi_video_bus_put_devices(struct acpi_video_bus *video) |
1786 | { | 1795 | { |
1787 | int status; | 1796 | int status; |
1788 | struct acpi_video_device *dev, *next; | 1797 | struct acpi_video_device *dev, *next; |
1789 | 1798 | ||
1790 | mutex_lock(&video->device_list_lock); | 1799 | mutex_lock(&video->device_list_lock); |
1791 | 1800 | ||
1792 | list_for_each_entry_safe(dev, next, &video->video_device_list, entry) { | 1801 | list_for_each_entry_safe(dev, next, &video->video_device_list, entry) { |
1793 | 1802 | ||
1794 | status = acpi_video_bus_put_one_device(dev); | 1803 | status = acpi_video_bus_put_one_device(dev); |
1795 | if (ACPI_FAILURE(status)) | 1804 | if (ACPI_FAILURE(status)) |
1796 | printk(KERN_WARNING PREFIX | 1805 | printk(KERN_WARNING PREFIX |
1797 | "hhuuhhuu bug in acpi video driver.\n"); | 1806 | "hhuuhhuu bug in acpi video driver.\n"); |
1798 | 1807 | ||
1799 | if (dev->brightness) { | 1808 | if (dev->brightness) { |
1800 | kfree(dev->brightness->levels); | 1809 | kfree(dev->brightness->levels); |
1801 | kfree(dev->brightness); | 1810 | kfree(dev->brightness); |
1802 | } | 1811 | } |
1803 | list_del(&dev->entry); | 1812 | list_del(&dev->entry); |
1804 | kfree(dev); | 1813 | kfree(dev); |
1805 | } | 1814 | } |
1806 | 1815 | ||
1807 | mutex_unlock(&video->device_list_lock); | 1816 | mutex_unlock(&video->device_list_lock); |
1808 | 1817 | ||
1809 | return 0; | 1818 | return 0; |
1810 | } | 1819 | } |
1811 | 1820 | ||
1812 | /* acpi_video interface */ | 1821 | /* acpi_video interface */ |
1813 | 1822 | ||
1814 | static int acpi_video_bus_start_devices(struct acpi_video_bus *video) | 1823 | static int acpi_video_bus_start_devices(struct acpi_video_bus *video) |
1815 | { | 1824 | { |
1816 | return acpi_video_bus_DOS(video, 0, 0); | 1825 | return acpi_video_bus_DOS(video, 0, 0); |
1817 | } | 1826 | } |
1818 | 1827 | ||
1819 | static int acpi_video_bus_stop_devices(struct acpi_video_bus *video) | 1828 | static int acpi_video_bus_stop_devices(struct acpi_video_bus *video) |
1820 | { | 1829 | { |
1821 | return acpi_video_bus_DOS(video, 0, 1); | 1830 | return acpi_video_bus_DOS(video, 0, 1); |
1822 | } | 1831 | } |
1823 | 1832 | ||
1824 | static void acpi_video_bus_notify(acpi_handle handle, u32 event, void *data) | 1833 | static void acpi_video_bus_notify(acpi_handle handle, u32 event, void *data) |
1825 | { | 1834 | { |
1826 | struct acpi_video_bus *video = data; | 1835 | struct acpi_video_bus *video = data; |
1827 | struct acpi_device *device = NULL; | 1836 | struct acpi_device *device = NULL; |
1828 | struct input_dev *input; | 1837 | struct input_dev *input; |
1829 | int keycode; | 1838 | int keycode; |
1830 | 1839 | ||
1831 | if (!video) | 1840 | if (!video) |
1832 | return; | 1841 | return; |
1833 | 1842 | ||
1834 | device = video->device; | 1843 | device = video->device; |
1835 | input = video->input; | 1844 | input = video->input; |
1836 | 1845 | ||
1837 | switch (event) { | 1846 | switch (event) { |
1838 | case ACPI_VIDEO_NOTIFY_SWITCH: /* User requested a switch, | 1847 | case ACPI_VIDEO_NOTIFY_SWITCH: /* User requested a switch, |
1839 | * most likely via hotkey. */ | 1848 | * most likely via hotkey. */ |
1840 | acpi_bus_generate_proc_event(device, event, 0); | 1849 | acpi_bus_generate_proc_event(device, event, 0); |
1841 | keycode = KEY_SWITCHVIDEOMODE; | 1850 | keycode = KEY_SWITCHVIDEOMODE; |
1842 | break; | 1851 | break; |
1843 | 1852 | ||
1844 | case ACPI_VIDEO_NOTIFY_PROBE: /* User plugged in or removed a video | 1853 | case ACPI_VIDEO_NOTIFY_PROBE: /* User plugged in or removed a video |
1845 | * connector. */ | 1854 | * connector. */ |
1846 | acpi_video_device_enumerate(video); | 1855 | acpi_video_device_enumerate(video); |
1847 | acpi_video_device_rebind(video); | 1856 | acpi_video_device_rebind(video); |
1848 | acpi_bus_generate_proc_event(device, event, 0); | 1857 | acpi_bus_generate_proc_event(device, event, 0); |
1849 | keycode = KEY_SWITCHVIDEOMODE; | 1858 | keycode = KEY_SWITCHVIDEOMODE; |
1850 | break; | 1859 | break; |
1851 | 1860 | ||
1852 | case ACPI_VIDEO_NOTIFY_CYCLE: /* Cycle Display output hotkey pressed. */ | 1861 | case ACPI_VIDEO_NOTIFY_CYCLE: /* Cycle Display output hotkey pressed. */ |
1853 | acpi_bus_generate_proc_event(device, event, 0); | 1862 | acpi_bus_generate_proc_event(device, event, 0); |
1854 | keycode = KEY_SWITCHVIDEOMODE; | 1863 | keycode = KEY_SWITCHVIDEOMODE; |
1855 | break; | 1864 | break; |
1856 | case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT: /* Next Display output hotkey pressed. */ | 1865 | case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT: /* Next Display output hotkey pressed. */ |
1857 | acpi_bus_generate_proc_event(device, event, 0); | 1866 | acpi_bus_generate_proc_event(device, event, 0); |
1858 | keycode = KEY_VIDEO_NEXT; | 1867 | keycode = KEY_VIDEO_NEXT; |
1859 | break; | 1868 | break; |
1860 | case ACPI_VIDEO_NOTIFY_PREV_OUTPUT: /* previous Display output hotkey pressed. */ | 1869 | case ACPI_VIDEO_NOTIFY_PREV_OUTPUT: /* previous Display output hotkey pressed. */ |
1861 | acpi_bus_generate_proc_event(device, event, 0); | 1870 | acpi_bus_generate_proc_event(device, event, 0); |
1862 | keycode = KEY_VIDEO_PREV; | 1871 | keycode = KEY_VIDEO_PREV; |
1863 | break; | 1872 | break; |
1864 | 1873 | ||
1865 | default: | 1874 | default: |
1866 | keycode = KEY_UNKNOWN; | 1875 | keycode = KEY_UNKNOWN; |
1867 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | 1876 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
1868 | "Unsupported event [0x%x]\n", event)); | 1877 | "Unsupported event [0x%x]\n", event)); |
1869 | break; | 1878 | break; |
1870 | } | 1879 | } |
1871 | 1880 | ||
1872 | acpi_notifier_call_chain(device, event, 0); | 1881 | acpi_notifier_call_chain(device, event, 0); |
1873 | input_report_key(input, keycode, 1); | 1882 | input_report_key(input, keycode, 1); |
1874 | input_sync(input); | 1883 | input_sync(input); |
1875 | input_report_key(input, keycode, 0); | 1884 | input_report_key(input, keycode, 0); |
1876 | input_sync(input); | 1885 | input_sync(input); |
1877 | 1886 | ||
1878 | return; | 1887 | return; |
1879 | } | 1888 | } |
1880 | 1889 | ||
1881 | static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data) | 1890 | static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data) |
1882 | { | 1891 | { |
1883 | struct acpi_video_device *video_device = data; | 1892 | struct acpi_video_device *video_device = data; |
1884 | struct acpi_device *device = NULL; | 1893 | struct acpi_device *device = NULL; |
1885 | struct acpi_video_bus *bus; | 1894 | struct acpi_video_bus *bus; |
1886 | struct input_dev *input; | 1895 | struct input_dev *input; |
1887 | int keycode; | 1896 | int keycode; |
1888 | 1897 | ||
1889 | if (!video_device) | 1898 | if (!video_device) |
1890 | return; | 1899 | return; |
1891 | 1900 | ||
1892 | device = video_device->dev; | 1901 | device = video_device->dev; |
1893 | bus = video_device->video; | 1902 | bus = video_device->video; |
1894 | input = bus->input; | 1903 | input = bus->input; |
1895 | 1904 | ||
1896 | switch (event) { | 1905 | switch (event) { |
1897 | case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS: /* Cycle brightness */ | 1906 | case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS: /* Cycle brightness */ |
1898 | if (brightness_switch_enabled) | 1907 | if (brightness_switch_enabled) |
1899 | acpi_video_switch_brightness(video_device, event); | 1908 | acpi_video_switch_brightness(video_device, event); |
1900 | acpi_bus_generate_proc_event(device, event, 0); | 1909 | acpi_bus_generate_proc_event(device, event, 0); |
1901 | keycode = KEY_BRIGHTNESS_CYCLE; | 1910 | keycode = KEY_BRIGHTNESS_CYCLE; |
1902 | break; | 1911 | break; |
1903 | case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS: /* Increase brightness */ | 1912 | case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS: /* Increase brightness */ |
1904 | if (brightness_switch_enabled) | 1913 | if (brightness_switch_enabled) |
1905 | acpi_video_switch_brightness(video_device, event); | 1914 | acpi_video_switch_brightness(video_device, event); |
1906 | acpi_bus_generate_proc_event(device, event, 0); | 1915 | acpi_bus_generate_proc_event(device, event, 0); |
1907 | keycode = KEY_BRIGHTNESSUP; | 1916 | keycode = KEY_BRIGHTNESSUP; |
1908 | break; | 1917 | break; |
1909 | case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS: /* Decrease brightness */ | 1918 | case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS: /* Decrease brightness */ |
1910 | if (brightness_switch_enabled) | 1919 | if (brightness_switch_enabled) |
1911 | acpi_video_switch_brightness(video_device, event); | 1920 | acpi_video_switch_brightness(video_device, event); |
1912 | acpi_bus_generate_proc_event(device, event, 0); | 1921 | acpi_bus_generate_proc_event(device, event, 0); |
1913 | keycode = KEY_BRIGHTNESSDOWN; | 1922 | keycode = KEY_BRIGHTNESSDOWN; |
1914 | break; | 1923 | break; |
1915 | case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS: /* zero brightnesss */ | 1924 | case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS: /* zero brightnesss */ |
1916 | if (brightness_switch_enabled) | 1925 | if (brightness_switch_enabled) |
1917 | acpi_video_switch_brightness(video_device, event); | 1926 | acpi_video_switch_brightness(video_device, event); |
1918 | acpi_bus_generate_proc_event(device, event, 0); | 1927 | acpi_bus_generate_proc_event(device, event, 0); |
1919 | keycode = KEY_BRIGHTNESS_ZERO; | 1928 | keycode = KEY_BRIGHTNESS_ZERO; |
1920 | break; | 1929 | break; |
1921 | case ACPI_VIDEO_NOTIFY_DISPLAY_OFF: /* display device off */ | 1930 | case ACPI_VIDEO_NOTIFY_DISPLAY_OFF: /* display device off */ |
1922 | if (brightness_switch_enabled) | 1931 | if (brightness_switch_enabled) |
1923 | acpi_video_switch_brightness(video_device, event); | 1932 | acpi_video_switch_brightness(video_device, event); |
1924 | acpi_bus_generate_proc_event(device, event, 0); | 1933 | acpi_bus_generate_proc_event(device, event, 0); |
1925 | keycode = KEY_DISPLAY_OFF; | 1934 | keycode = KEY_DISPLAY_OFF; |
1926 | break; | 1935 | break; |
1927 | default: | 1936 | default: |
1928 | keycode = KEY_UNKNOWN; | 1937 | keycode = KEY_UNKNOWN; |
1929 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | 1938 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
1930 | "Unsupported event [0x%x]\n", event)); | 1939 | "Unsupported event [0x%x]\n", event)); |
1931 | break; | 1940 | break; |
1932 | } | 1941 | } |
1933 | 1942 | ||
1934 | acpi_notifier_call_chain(device, event, 0); | 1943 | acpi_notifier_call_chain(device, event, 0); |
1935 | input_report_key(input, keycode, 1); | 1944 | input_report_key(input, keycode, 1); |
1936 | input_sync(input); | 1945 | input_sync(input); |
1937 | input_report_key(input, keycode, 0); | 1946 | input_report_key(input, keycode, 0); |
1938 | input_sync(input); | 1947 | input_sync(input); |
1939 | 1948 | ||
1940 | return; | 1949 | return; |
1941 | } | 1950 | } |
1942 | 1951 | ||
1943 | static int instance; | 1952 | static int instance; |
1944 | static int acpi_video_resume(struct acpi_device *device) | 1953 | static int acpi_video_resume(struct acpi_device *device) |
1945 | { | 1954 | { |
1946 | struct acpi_video_bus *video; | 1955 | struct acpi_video_bus *video; |
1947 | struct acpi_video_device *video_device; | 1956 | struct acpi_video_device *video_device; |
1948 | int i; | 1957 | int i; |
1949 | 1958 | ||
1950 | if (!device || !acpi_driver_data(device)) | 1959 | if (!device || !acpi_driver_data(device)) |
1951 | return -EINVAL; | 1960 | return -EINVAL; |
1952 | 1961 | ||
1953 | video = acpi_driver_data(device); | 1962 | video = acpi_driver_data(device); |
1954 | 1963 | ||
1955 | for (i = 0; i < video->attached_count; i++) { | 1964 | for (i = 0; i < video->attached_count; i++) { |
1956 | video_device = video->attached_array[i].bind_info; | 1965 | video_device = video->attached_array[i].bind_info; |
1957 | if (video_device && video_device->backlight) | 1966 | if (video_device && video_device->backlight) |
1958 | acpi_video_set_brightness(video_device->backlight); | 1967 | acpi_video_set_brightness(video_device->backlight); |
1959 | } | 1968 | } |
1960 | return AE_OK; | 1969 | return AE_OK; |
1961 | } | 1970 | } |
1962 | 1971 | ||
1963 | static int acpi_video_bus_add(struct acpi_device *device) | 1972 | static int acpi_video_bus_add(struct acpi_device *device) |
1964 | { | 1973 | { |
1965 | acpi_status status; | 1974 | acpi_status status; |
1966 | struct acpi_video_bus *video; | 1975 | struct acpi_video_bus *video; |
1967 | struct input_dev *input; | 1976 | struct input_dev *input; |
1968 | int error; | 1977 | int error; |
1969 | 1978 | ||
1970 | video = kzalloc(sizeof(struct acpi_video_bus), GFP_KERNEL); | 1979 | video = kzalloc(sizeof(struct acpi_video_bus), GFP_KERNEL); |
1971 | if (!video) | 1980 | if (!video) |
1972 | return -ENOMEM; | 1981 | return -ENOMEM; |
1973 | 1982 | ||
1974 | /* a hack to fix the duplicate name "VID" problem on T61 */ | 1983 | /* a hack to fix the duplicate name "VID" problem on T61 */ |
1975 | if (!strcmp(device->pnp.bus_id, "VID")) { | 1984 | if (!strcmp(device->pnp.bus_id, "VID")) { |
1976 | if (instance) | 1985 | if (instance) |
1977 | device->pnp.bus_id[3] = '0' + instance; | 1986 | device->pnp.bus_id[3] = '0' + instance; |
1978 | instance ++; | 1987 | instance ++; |
1979 | } | 1988 | } |
1980 | 1989 | ||
1981 | video->device = device; | 1990 | video->device = device; |
1982 | strcpy(acpi_device_name(device), ACPI_VIDEO_BUS_NAME); | 1991 | strcpy(acpi_device_name(device), ACPI_VIDEO_BUS_NAME); |
1983 | strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS); | 1992 | strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS); |
1984 | device->driver_data = video; | 1993 | device->driver_data = video; |
1985 | 1994 | ||
1986 | acpi_video_bus_find_cap(video); | 1995 | acpi_video_bus_find_cap(video); |
1987 | error = acpi_video_bus_check(video); | 1996 | error = acpi_video_bus_check(video); |
1988 | if (error) | 1997 | if (error) |
1989 | goto err_free_video; | 1998 | goto err_free_video; |
1990 | 1999 | ||
1991 | error = acpi_video_bus_add_fs(device); | 2000 | error = acpi_video_bus_add_fs(device); |
1992 | if (error) | 2001 | if (error) |
1993 | goto err_free_video; | 2002 | goto err_free_video; |
1994 | 2003 | ||
1995 | mutex_init(&video->device_list_lock); | 2004 | mutex_init(&video->device_list_lock); |
1996 | INIT_LIST_HEAD(&video->video_device_list); | 2005 | INIT_LIST_HEAD(&video->video_device_list); |
1997 | 2006 | ||
1998 | acpi_video_bus_get_devices(video, device); | 2007 | acpi_video_bus_get_devices(video, device); |
1999 | acpi_video_bus_start_devices(video); | 2008 | acpi_video_bus_start_devices(video); |
2000 | 2009 | ||
2001 | status = acpi_install_notify_handler(device->handle, | 2010 | status = acpi_install_notify_handler(device->handle, |
2002 | ACPI_DEVICE_NOTIFY, | 2011 | ACPI_DEVICE_NOTIFY, |
2003 | acpi_video_bus_notify, video); | 2012 | acpi_video_bus_notify, video); |
2004 | if (ACPI_FAILURE(status)) { | 2013 | if (ACPI_FAILURE(status)) { |
2005 | printk(KERN_ERR PREFIX | 2014 | printk(KERN_ERR PREFIX |
2006 | "Error installing notify handler\n"); | 2015 | "Error installing notify handler\n"); |
2007 | error = -ENODEV; | 2016 | error = -ENODEV; |
2008 | goto err_stop_video; | 2017 | goto err_stop_video; |
2009 | } | 2018 | } |
2010 | 2019 | ||
2011 | video->input = input = input_allocate_device(); | 2020 | video->input = input = input_allocate_device(); |
2012 | if (!input) { | 2021 | if (!input) { |
2013 | error = -ENOMEM; | 2022 | error = -ENOMEM; |
2014 | goto err_uninstall_notify; | 2023 | goto err_uninstall_notify; |
2015 | } | 2024 | } |
2016 | 2025 | ||
2017 | snprintf(video->phys, sizeof(video->phys), | 2026 | snprintf(video->phys, sizeof(video->phys), |
2018 | "%s/video/input0", acpi_device_hid(video->device)); | 2027 | "%s/video/input0", acpi_device_hid(video->device)); |
2019 | 2028 | ||
2020 | input->name = acpi_device_name(video->device); | 2029 | input->name = acpi_device_name(video->device); |
2021 | input->phys = video->phys; | 2030 | input->phys = video->phys; |
2022 | input->id.bustype = BUS_HOST; | 2031 | input->id.bustype = BUS_HOST; |
2023 | input->id.product = 0x06; | 2032 | input->id.product = 0x06; |
2024 | input->dev.parent = &device->dev; | 2033 | input->dev.parent = &device->dev; |
2025 | input->evbit[0] = BIT(EV_KEY); | 2034 | input->evbit[0] = BIT(EV_KEY); |
2026 | set_bit(KEY_SWITCHVIDEOMODE, input->keybit); | 2035 | set_bit(KEY_SWITCHVIDEOMODE, input->keybit); |
2027 | set_bit(KEY_VIDEO_NEXT, input->keybit); | 2036 | set_bit(KEY_VIDEO_NEXT, input->keybit); |
2028 | set_bit(KEY_VIDEO_PREV, input->keybit); | 2037 | set_bit(KEY_VIDEO_PREV, input->keybit); |
2029 | set_bit(KEY_BRIGHTNESS_CYCLE, input->keybit); | 2038 | set_bit(KEY_BRIGHTNESS_CYCLE, input->keybit); |
2030 | set_bit(KEY_BRIGHTNESSUP, input->keybit); | 2039 | set_bit(KEY_BRIGHTNESSUP, input->keybit); |
2031 | set_bit(KEY_BRIGHTNESSDOWN, input->keybit); | 2040 | set_bit(KEY_BRIGHTNESSDOWN, input->keybit); |
2032 | set_bit(KEY_BRIGHTNESS_ZERO, input->keybit); | 2041 | set_bit(KEY_BRIGHTNESS_ZERO, input->keybit); |
2033 | set_bit(KEY_DISPLAY_OFF, input->keybit); | 2042 | set_bit(KEY_DISPLAY_OFF, input->keybit); |
2034 | set_bit(KEY_UNKNOWN, input->keybit); | 2043 | set_bit(KEY_UNKNOWN, input->keybit); |
2035 | 2044 | ||
2036 | error = input_register_device(input); | 2045 | error = input_register_device(input); |
2037 | if (error) | 2046 | if (error) |
2038 | goto err_free_input_dev; | 2047 | goto err_free_input_dev; |
2039 | 2048 | ||
2040 | printk(KERN_INFO PREFIX "%s [%s] (multi-head: %s rom: %s post: %s)\n", | 2049 | printk(KERN_INFO PREFIX "%s [%s] (multi-head: %s rom: %s post: %s)\n", |
2041 | ACPI_VIDEO_DEVICE_NAME, acpi_device_bid(device), | 2050 | ACPI_VIDEO_DEVICE_NAME, acpi_device_bid(device), |
2042 | video->flags.multihead ? "yes" : "no", | 2051 | video->flags.multihead ? "yes" : "no", |
2043 | video->flags.rom ? "yes" : "no", | 2052 | video->flags.rom ? "yes" : "no", |
2044 | video->flags.post ? "yes" : "no"); | 2053 | video->flags.post ? "yes" : "no"); |
2045 | 2054 | ||
2046 | return 0; | 2055 | return 0; |
2047 | 2056 | ||
2048 | err_free_input_dev: | 2057 | err_free_input_dev: |
2049 | input_free_device(input); | 2058 | input_free_device(input); |
2050 | err_uninstall_notify: | 2059 | err_uninstall_notify: |
2051 | acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY, | 2060 | acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY, |
2052 | acpi_video_bus_notify); | 2061 | acpi_video_bus_notify); |
2053 | err_stop_video: | 2062 | err_stop_video: |
2054 | acpi_video_bus_stop_devices(video); | 2063 | acpi_video_bus_stop_devices(video); |
2055 | acpi_video_bus_put_devices(video); | 2064 | acpi_video_bus_put_devices(video); |
2056 | kfree(video->attached_array); | 2065 | kfree(video->attached_array); |
2057 | acpi_video_bus_remove_fs(device); | 2066 | acpi_video_bus_remove_fs(device); |
2058 | err_free_video: | 2067 | err_free_video: |
2059 | kfree(video); | 2068 | kfree(video); |
2060 | device->driver_data = NULL; | 2069 | device->driver_data = NULL; |
2061 | 2070 | ||
2062 | return error; | 2071 | return error; |
2063 | } | 2072 | } |
2064 | 2073 | ||
2065 | static int acpi_video_bus_remove(struct acpi_device *device, int type) | 2074 | static int acpi_video_bus_remove(struct acpi_device *device, int type) |
2066 | { | 2075 | { |
2067 | acpi_status status = 0; | 2076 | acpi_status status = 0; |
2068 | struct acpi_video_bus *video = NULL; | 2077 | struct acpi_video_bus *video = NULL; |
2069 | 2078 | ||
2070 | 2079 | ||
2071 | if (!device || !acpi_driver_data(device)) | 2080 | if (!device || !acpi_driver_data(device)) |
2072 | return -EINVAL; | 2081 | return -EINVAL; |
2073 | 2082 | ||
2074 | video = acpi_driver_data(device); | 2083 | video = acpi_driver_data(device); |
2075 | 2084 | ||
2076 | acpi_video_bus_stop_devices(video); | 2085 | acpi_video_bus_stop_devices(video); |
2077 | 2086 | ||
2078 | status = acpi_remove_notify_handler(video->device->handle, | 2087 | status = acpi_remove_notify_handler(video->device->handle, |
2079 | ACPI_DEVICE_NOTIFY, | 2088 | ACPI_DEVICE_NOTIFY, |
2080 | acpi_video_bus_notify); | 2089 | acpi_video_bus_notify); |
2081 | 2090 | ||
2082 | acpi_video_bus_put_devices(video); | 2091 | acpi_video_bus_put_devices(video); |
2083 | acpi_video_bus_remove_fs(device); | 2092 | acpi_video_bus_remove_fs(device); |
2084 | 2093 | ||
2085 | input_unregister_device(video->input); | 2094 | input_unregister_device(video->input); |
2086 | kfree(video->attached_array); | 2095 | kfree(video->attached_array); |
2087 | kfree(video); | 2096 | kfree(video); |
2088 | 2097 | ||
2089 | return 0; | 2098 | return 0; |
2090 | } | 2099 | } |
2091 | 2100 | ||
2092 | static int __init acpi_video_init(void) | 2101 | static int __init acpi_video_init(void) |
2093 | { | 2102 | { |
2094 | int result = 0; | 2103 | int result = 0; |
2095 | 2104 | ||
2096 | acpi_video_dir = proc_mkdir(ACPI_VIDEO_CLASS, acpi_root_dir); | 2105 | acpi_video_dir = proc_mkdir(ACPI_VIDEO_CLASS, acpi_root_dir); |
2097 | if (!acpi_video_dir) | 2106 | if (!acpi_video_dir) |
2098 | return -ENODEV; | 2107 | return -ENODEV; |
2099 | acpi_video_dir->owner = THIS_MODULE; | 2108 | acpi_video_dir->owner = THIS_MODULE; |
2100 | 2109 | ||
2101 | result = acpi_bus_register_driver(&acpi_video_bus); | 2110 | result = acpi_bus_register_driver(&acpi_video_bus); |
2102 | if (result < 0) { | 2111 | if (result < 0) { |
2103 | remove_proc_entry(ACPI_VIDEO_CLASS, acpi_root_dir); | 2112 | remove_proc_entry(ACPI_VIDEO_CLASS, acpi_root_dir); |
2104 | return -ENODEV; | 2113 | return -ENODEV; |
2105 | } | 2114 | } |
2106 | 2115 | ||
2107 | return 0; | 2116 | return 0; |
2108 | } | 2117 | } |
2109 | 2118 | ||
2110 | static void __exit acpi_video_exit(void) | 2119 | static void __exit acpi_video_exit(void) |
2111 | { | 2120 | { |
2112 | 2121 | ||
2113 | acpi_bus_unregister_driver(&acpi_video_bus); | 2122 | acpi_bus_unregister_driver(&acpi_video_bus); |
2114 | 2123 | ||
2115 | remove_proc_entry(ACPI_VIDEO_CLASS, acpi_root_dir); | 2124 | remove_proc_entry(ACPI_VIDEO_CLASS, acpi_root_dir); |
2116 | 2125 | ||
2117 | return; | 2126 | return; |
2118 | } | 2127 | } |
2119 | 2128 | ||
2120 | module_init(acpi_video_init); | 2129 | module_init(acpi_video_init); |
drivers/acpi/video_detect.c
File was created | 1 | /* | |
2 | * Copyright (C) 2008 SuSE Linux Products GmbH | ||
3 | * Thomas Renninger <trenn@suse.de> | ||
4 | * | ||
5 | * May be copied or modified under the terms of the GNU General Public License | ||
6 | * | ||
7 | * video_detect.c: | ||
8 | * Provides acpi_is_video_device() for early scanning of ACPI devices in scan.c | ||
9 | * There a Linux specific (Spec does not provide a HID for video devices) is | ||
10 | * assinged | ||
11 | * | ||
12 | * After PCI devices are glued with ACPI devices | ||
13 | * acpi_get_physical_pci_device() can be called to identify ACPI graphics | ||
14 | * devices for which a real graphics card is plugged in | ||
15 | * | ||
16 | * Now acpi_video_get_capabilities() can be called to check which | ||
17 | * capabilities the graphics cards plugged in support. The check for general | ||
18 | * video capabilities will be triggered by the first caller of | ||
19 | * acpi_video_get_capabilities(NULL); which will happen when the first | ||
20 | * backlight (or display output) switching supporting driver calls: | ||
21 | * acpi_video_backlight_support(); | ||
22 | * | ||
23 | * Depending on whether ACPI graphics extensions (cmp. ACPI spec Appendix B) | ||
24 | * are available, video.ko should be used to handle the device. | ||
25 | * | ||
26 | * Otherwise vendor specific drivers like thinkpad_acpi, asus_acpi, | ||
27 | * sony_acpi,... can take care about backlight brightness and display output | ||
28 | * switching. | ||
29 | * | ||
30 | * If CONFIG_ACPI_VIDEO is neither set as "compiled in" (y) nor as a module (m) | ||
31 | * this file will not be compiled, acpi_video_get_capabilities() and | ||
32 | * acpi_video_backlight_support() will always return 0 and vendor specific | ||
33 | * drivers always can handle backlight. | ||
34 | * | ||
35 | */ | ||
36 | |||
37 | #include <linux/acpi.h> | ||
38 | #include <linux/dmi.h> | ||
39 | |||
40 | ACPI_MODULE_NAME("video"); | ||
41 | #define _COMPONENT ACPI_VIDEO_COMPONENT | ||
42 | |||
43 | static long acpi_video_support; | ||
44 | static bool acpi_video_caps_checked; | ||
45 | |||
46 | static acpi_status | ||
47 | acpi_backlight_cap_match(acpi_handle handle, u32 level, void *context, | ||
48 | void **retyurn_value) | ||
49 | { | ||
50 | long *cap = context; | ||
51 | acpi_handle h_dummy; | ||
52 | |||
53 | if (ACPI_SUCCESS(acpi_get_handle(handle, "_BCM", &h_dummy)) && | ||
54 | ACPI_SUCCESS(acpi_get_handle(handle, "_BCL", &h_dummy))) { | ||
55 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found generic backlight " | ||
56 | "support\n")); | ||
57 | *cap |= ACPI_VIDEO_BACKLIGHT; | ||
58 | /* We have backlight support, no need to scan further */ | ||
59 | return AE_CTRL_TERMINATE; | ||
60 | } | ||
61 | return 0; | ||
62 | } | ||
63 | |||
64 | /* Returns true if the device is a video device which can be handled by | ||
65 | * video.ko. | ||
66 | * The device will get a Linux specific CID added in scan.c to | ||
67 | * identify the device as an ACPI graphics device | ||
68 | * Be aware that the graphics device may not be physically present | ||
69 | * Use acpi_video_get_capabilities() to detect general ACPI video | ||
70 | * capabilities of present cards | ||
71 | */ | ||
72 | long acpi_is_video_device(struct acpi_device *device) | ||
73 | { | ||
74 | acpi_handle h_dummy; | ||
75 | long video_caps = 0; | ||
76 | |||
77 | if (!device) | ||
78 | return 0; | ||
79 | |||
80 | /* Does this device able to support video switching ? */ | ||
81 | if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy)) && | ||
82 | ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy))) | ||
83 | video_caps |= ACPI_VIDEO_OUTPUT_SWITCHING; | ||
84 | |||
85 | /* Does this device able to retrieve a video ROM ? */ | ||
86 | if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy))) | ||
87 | video_caps |= ACPI_VIDEO_ROM_AVAILABLE; | ||
88 | |||
89 | /* Does this device able to configure which video head to be POSTed ? */ | ||
90 | if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy)) && | ||
91 | ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy)) && | ||
92 | ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy))) | ||
93 | video_caps |= ACPI_VIDEO_DEVICE_POSTING; | ||
94 | |||
95 | /* Only check for backlight functionality if one of the above hit. */ | ||
96 | if (video_caps) | ||
97 | acpi_walk_namespace(ACPI_TYPE_DEVICE, device->handle, | ||
98 | ACPI_UINT32_MAX, acpi_backlight_cap_match, | ||
99 | &video_caps, NULL); | ||
100 | |||
101 | return video_caps; | ||
102 | } | ||
103 | EXPORT_SYMBOL(acpi_is_video_device); | ||
104 | |||
105 | static acpi_status | ||
106 | find_video(acpi_handle handle, u32 lvl, void *context, void **rv) | ||
107 | { | ||
108 | long *cap = context; | ||
109 | struct device *dev; | ||
110 | struct acpi_device *acpi_dev; | ||
111 | |||
112 | const struct acpi_device_id video_ids[] = { | ||
113 | {ACPI_VIDEO_HID, 0}, | ||
114 | {"", 0}, | ||
115 | }; | ||
116 | if (acpi_bus_get_device(handle, &acpi_dev)) | ||
117 | return AE_OK; | ||
118 | |||
119 | if (!acpi_match_device_ids(acpi_dev, video_ids)) { | ||
120 | dev = acpi_get_physical_pci_device(handle); | ||
121 | if (!dev) | ||
122 | return AE_OK; | ||
123 | put_device(dev); | ||
124 | *cap |= acpi_is_video_device(acpi_dev); | ||
125 | } | ||
126 | return AE_OK; | ||
127 | } | ||
128 | |||
129 | /* | ||
130 | * Returns the video capabilities of a specific ACPI graphics device | ||
131 | * | ||
132 | * if NULL is passed as argument all ACPI devices are enumerated and | ||
133 | * all graphics capabilities of physically present devices are | ||
134 | * summerized and returned. This is cached and done only once. | ||
135 | */ | ||
136 | long acpi_video_get_capabilities(acpi_handle graphics_handle) | ||
137 | { | ||
138 | long caps = 0; | ||
139 | struct acpi_device *tmp_dev; | ||
140 | acpi_status status; | ||
141 | |||
142 | if (acpi_video_caps_checked && graphics_handle == NULL) | ||
143 | return acpi_video_support; | ||
144 | |||
145 | if (!graphics_handle) { | ||
146 | /* Only do the global walk through all graphics devices once */ | ||
147 | acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, | ||
148 | ACPI_UINT32_MAX, find_video, | ||
149 | &caps, NULL); | ||
150 | /* There might be boot param flags set already... */ | ||
151 | acpi_video_support |= caps; | ||
152 | acpi_video_caps_checked = 1; | ||
153 | /* Add blacklists here. Be careful to use the right *DMI* bits | ||
154 | * to still be able to override logic via boot params, e.g.: | ||
155 | * | ||
156 | * if (dmi_name_in_vendors("XY")) { | ||
157 | * acpi_video_support |= | ||
158 | * ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VENDOR; | ||
159 | * acpi_video_support |= | ||
160 | * ACPI_VIDEO_BACKLIGHT_DMI_VENDOR; | ||
161 | *} | ||
162 | */ | ||
163 | } else { | ||
164 | status = acpi_bus_get_device(graphics_handle, &tmp_dev); | ||
165 | if (ACPI_FAILURE(status)) { | ||
166 | ACPI_EXCEPTION((AE_INFO, status, "Invalid device")); | ||
167 | return 0; | ||
168 | } | ||
169 | acpi_walk_namespace(ACPI_TYPE_DEVICE, graphics_handle, | ||
170 | ACPI_UINT32_MAX, find_video, | ||
171 | &caps, NULL); | ||
172 | } | ||
173 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "We have 0x%lX video support %s %s\n", | ||
174 | graphics_handle ? caps : acpi_video_support, | ||
175 | graphics_handle ? "on device " : "in general", | ||
176 | graphics_handle ? acpi_device_bid(tmp_dev) : "")); | ||
177 | return caps; | ||
178 | } | ||
179 | EXPORT_SYMBOL(acpi_video_get_capabilities); | ||
180 | |||
181 | /* Returns true if video.ko can do backlight switching */ | ||
182 | int acpi_video_backlight_support(void) | ||
183 | { | ||
184 | /* | ||
185 | * We must check whether the ACPI graphics device is physically plugged | ||
186 | * in. Therefore this must be called after binding PCI and ACPI devices | ||
187 | */ | ||
188 | if (!acpi_video_caps_checked) | ||
189 | acpi_video_get_capabilities(NULL); | ||
190 | |||
191 | /* First check for boot param -> highest prio */ | ||
192 | if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR) | ||
193 | return 0; | ||
194 | else if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_FORCE_VIDEO) | ||
195 | return 1; | ||
196 | |||
197 | /* Then check for DMI blacklist -> second highest prio */ | ||
198 | if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_DMI_VENDOR) | ||
199 | return 0; | ||
200 | else if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_DMI_VIDEO) | ||
201 | return 1; | ||
202 | |||
203 | /* Then go the default way */ | ||
204 | return acpi_video_support & ACPI_VIDEO_BACKLIGHT; | ||
205 | } | ||
206 | EXPORT_SYMBOL(acpi_video_backlight_support); | ||
207 | |||
208 | /* | ||
209 | * Returns true if video.ko can do display output switching. | ||
210 | * This does not work well/at all with binary graphics drivers | ||
211 | * which disable system io ranges and do it on their own. | ||
212 | */ | ||
213 | int acpi_video_display_switch_support(void) | ||
214 | { | ||
215 | if (!acpi_video_caps_checked) | ||
216 | acpi_video_get_capabilities(NULL); | ||
217 | |||
218 | if (acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VENDOR) | ||
219 | return 0; | ||
220 | else if (acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VIDEO) | ||
221 | return 1; | ||
222 | |||
223 | if (acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VENDOR) | ||
224 | return 0; | ||
225 | else if (acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VIDEO) | ||
226 | return 1; | ||
227 | |||
228 | return acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING; | ||
229 | } | ||
230 | EXPORT_SYMBOL(acpi_video_display_switch_support); | ||
231 | |||
232 | /* | ||
233 | * Use acpi_display_output=vendor/video or acpi_backlight=vendor/video | ||
234 | * To force that backlight or display output switching is processed by vendor | ||
235 | * specific acpi drivers or video.ko driver. | ||
236 | */ | ||
237 | int __init acpi_backlight(char *str) | ||
238 | { | ||
239 | if (str == NULL || *str == '\0') | ||
240 | return 1; | ||
241 | else { | ||
242 | if (!strcmp("vendor", str)) | ||
243 | acpi_video_support |= | ||
244 | ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR; | ||
245 | if (!strcmp("video", str)) | ||
246 | acpi_video_support |= | ||
247 | ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VIDEO; | ||
248 | } | ||
249 | return 1; | ||
250 | } | ||
251 | __setup("acpi_backlight=", acpi_backlight); | ||
252 | |||
253 | int __init acpi_display_output(char *str) | ||
254 | { | ||
255 | if (str == NULL || *str == '\0') | ||
256 | return 1; | ||
257 | else { | ||
258 | if (!strcmp("vendor", str)) | ||
259 | acpi_video_support |= | ||
260 | ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VENDOR; | ||
261 | if (!strcmp("video", str)) | ||
262 | acpi_video_support |= | ||
263 | ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VIDEO; | ||
264 | } | ||
265 | return 1; | ||
266 | } | ||
267 | __setup("acpi_display_output=", acpi_display_output); | ||
268 |
drivers/misc/acer-wmi.c
1 | /* | 1 | /* |
2 | * Acer WMI Laptop Extras | 2 | * Acer WMI Laptop Extras |
3 | * | 3 | * |
4 | * Copyright (C) 2007-2008 Carlos Corbacho <carlos@strangeworlds.co.uk> | 4 | * Copyright (C) 2007-2008 Carlos Corbacho <carlos@strangeworlds.co.uk> |
5 | * | 5 | * |
6 | * Based on acer_acpi: | 6 | * Based on acer_acpi: |
7 | * Copyright (C) 2005-2007 E.M. Smith | 7 | * Copyright (C) 2005-2007 E.M. Smith |
8 | * Copyright (C) 2007-2008 Carlos Corbacho <cathectic@gmail.com> | 8 | * Copyright (C) 2007-2008 Carlos Corbacho <cathectic@gmail.com> |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 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 | 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 | 12 | * the Free Software Foundation; either version 2 of the License, or |
13 | * (at your option) any later version. | 13 | * (at your option) any later version. |
14 | * | 14 | * |
15 | * This program is distributed in the hope that it will be useful, | 15 | * This program is distributed in the hope that it will be useful, |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
18 | * GNU General Public License for more details. | 18 | * GNU General Public License for more details. |
19 | * | 19 | * |
20 | * You should have received a copy of the GNU General Public License | 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 | 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 | 22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <linux/kernel.h> | 25 | #include <linux/kernel.h> |
26 | #include <linux/module.h> | 26 | #include <linux/module.h> |
27 | #include <linux/init.h> | 27 | #include <linux/init.h> |
28 | #include <linux/types.h> | 28 | #include <linux/types.h> |
29 | #include <linux/dmi.h> | 29 | #include <linux/dmi.h> |
30 | #include <linux/fb.h> | 30 | #include <linux/fb.h> |
31 | #include <linux/backlight.h> | 31 | #include <linux/backlight.h> |
32 | #include <linux/leds.h> | 32 | #include <linux/leds.h> |
33 | #include <linux/platform_device.h> | 33 | #include <linux/platform_device.h> |
34 | #include <linux/acpi.h> | 34 | #include <linux/acpi.h> |
35 | #include <linux/i8042.h> | 35 | #include <linux/i8042.h> |
36 | #include <linux/rfkill.h> | 36 | #include <linux/rfkill.h> |
37 | #include <linux/workqueue.h> | 37 | #include <linux/workqueue.h> |
38 | #include <linux/debugfs.h> | 38 | #include <linux/debugfs.h> |
39 | 39 | ||
40 | #include <acpi/acpi_drivers.h> | 40 | #include <acpi/acpi_drivers.h> |
41 | 41 | ||
42 | MODULE_AUTHOR("Carlos Corbacho"); | 42 | MODULE_AUTHOR("Carlos Corbacho"); |
43 | MODULE_DESCRIPTION("Acer Laptop WMI Extras Driver"); | 43 | MODULE_DESCRIPTION("Acer Laptop WMI Extras Driver"); |
44 | MODULE_LICENSE("GPL"); | 44 | MODULE_LICENSE("GPL"); |
45 | 45 | ||
46 | #define ACER_LOGPREFIX "acer-wmi: " | 46 | #define ACER_LOGPREFIX "acer-wmi: " |
47 | #define ACER_ERR KERN_ERR ACER_LOGPREFIX | 47 | #define ACER_ERR KERN_ERR ACER_LOGPREFIX |
48 | #define ACER_NOTICE KERN_NOTICE ACER_LOGPREFIX | 48 | #define ACER_NOTICE KERN_NOTICE ACER_LOGPREFIX |
49 | #define ACER_INFO KERN_INFO ACER_LOGPREFIX | 49 | #define ACER_INFO KERN_INFO ACER_LOGPREFIX |
50 | 50 | ||
51 | /* | 51 | /* |
52 | * The following defines quirks to get some specific functions to work | 52 | * The following defines quirks to get some specific functions to work |
53 | * which are known to not be supported over ACPI-WMI (such as the mail LED | 53 | * which are known to not be supported over ACPI-WMI (such as the mail LED |
54 | * on WMID based Acer's) | 54 | * on WMID based Acer's) |
55 | */ | 55 | */ |
56 | struct acer_quirks { | 56 | struct acer_quirks { |
57 | const char *vendor; | 57 | const char *vendor; |
58 | const char *model; | 58 | const char *model; |
59 | u16 quirks; | 59 | u16 quirks; |
60 | }; | 60 | }; |
61 | 61 | ||
62 | /* | 62 | /* |
63 | * Magic Number | 63 | * Magic Number |
64 | * Meaning is unknown - this number is required for writing to ACPI for AMW0 | 64 | * Meaning is unknown - this number is required for writing to ACPI for AMW0 |
65 | * (it's also used in acerhk when directly accessing the BIOS) | 65 | * (it's also used in acerhk when directly accessing the BIOS) |
66 | */ | 66 | */ |
67 | #define ACER_AMW0_WRITE 0x9610 | 67 | #define ACER_AMW0_WRITE 0x9610 |
68 | 68 | ||
69 | /* | 69 | /* |
70 | * Bit masks for the AMW0 interface | 70 | * Bit masks for the AMW0 interface |
71 | */ | 71 | */ |
72 | #define ACER_AMW0_WIRELESS_MASK 0x35 | 72 | #define ACER_AMW0_WIRELESS_MASK 0x35 |
73 | #define ACER_AMW0_BLUETOOTH_MASK 0x34 | 73 | #define ACER_AMW0_BLUETOOTH_MASK 0x34 |
74 | #define ACER_AMW0_MAILLED_MASK 0x31 | 74 | #define ACER_AMW0_MAILLED_MASK 0x31 |
75 | 75 | ||
76 | /* | 76 | /* |
77 | * Method IDs for WMID interface | 77 | * Method IDs for WMID interface |
78 | */ | 78 | */ |
79 | #define ACER_WMID_GET_WIRELESS_METHODID 1 | 79 | #define ACER_WMID_GET_WIRELESS_METHODID 1 |
80 | #define ACER_WMID_GET_BLUETOOTH_METHODID 2 | 80 | #define ACER_WMID_GET_BLUETOOTH_METHODID 2 |
81 | #define ACER_WMID_GET_BRIGHTNESS_METHODID 3 | 81 | #define ACER_WMID_GET_BRIGHTNESS_METHODID 3 |
82 | #define ACER_WMID_SET_WIRELESS_METHODID 4 | 82 | #define ACER_WMID_SET_WIRELESS_METHODID 4 |
83 | #define ACER_WMID_SET_BLUETOOTH_METHODID 5 | 83 | #define ACER_WMID_SET_BLUETOOTH_METHODID 5 |
84 | #define ACER_WMID_SET_BRIGHTNESS_METHODID 6 | 84 | #define ACER_WMID_SET_BRIGHTNESS_METHODID 6 |
85 | #define ACER_WMID_GET_THREEG_METHODID 10 | 85 | #define ACER_WMID_GET_THREEG_METHODID 10 |
86 | #define ACER_WMID_SET_THREEG_METHODID 11 | 86 | #define ACER_WMID_SET_THREEG_METHODID 11 |
87 | 87 | ||
88 | /* | 88 | /* |
89 | * Acer ACPI method GUIDs | 89 | * Acer ACPI method GUIDs |
90 | */ | 90 | */ |
91 | #define AMW0_GUID1 "67C3371D-95A3-4C37-BB61-DD47B491DAAB" | 91 | #define AMW0_GUID1 "67C3371D-95A3-4C37-BB61-DD47B491DAAB" |
92 | #define AMW0_GUID2 "431F16ED-0C2B-444C-B267-27DEB140CF9C" | 92 | #define AMW0_GUID2 "431F16ED-0C2B-444C-B267-27DEB140CF9C" |
93 | #define WMID_GUID1 "6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3" | 93 | #define WMID_GUID1 "6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3" |
94 | #define WMID_GUID2 "95764E09-FB56-4e83-B31A-37761F60994A" | 94 | #define WMID_GUID2 "95764E09-FB56-4e83-B31A-37761F60994A" |
95 | 95 | ||
96 | MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB"); | 96 | MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB"); |
97 | MODULE_ALIAS("wmi:6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3"); | 97 | MODULE_ALIAS("wmi:6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3"); |
98 | 98 | ||
99 | /* Temporary workaround until the WMI sysfs interface goes in */ | 99 | /* Temporary workaround until the WMI sysfs interface goes in */ |
100 | MODULE_ALIAS("dmi:*:*Acer*:*:"); | 100 | MODULE_ALIAS("dmi:*:*Acer*:*:"); |
101 | 101 | ||
102 | /* | 102 | /* |
103 | * Interface capability flags | 103 | * Interface capability flags |
104 | */ | 104 | */ |
105 | #define ACER_CAP_MAILLED (1<<0) | 105 | #define ACER_CAP_MAILLED (1<<0) |
106 | #define ACER_CAP_WIRELESS (1<<1) | 106 | #define ACER_CAP_WIRELESS (1<<1) |
107 | #define ACER_CAP_BLUETOOTH (1<<2) | 107 | #define ACER_CAP_BLUETOOTH (1<<2) |
108 | #define ACER_CAP_BRIGHTNESS (1<<3) | 108 | #define ACER_CAP_BRIGHTNESS (1<<3) |
109 | #define ACER_CAP_THREEG (1<<4) | 109 | #define ACER_CAP_THREEG (1<<4) |
110 | #define ACER_CAP_ANY (0xFFFFFFFF) | 110 | #define ACER_CAP_ANY (0xFFFFFFFF) |
111 | 111 | ||
112 | /* | 112 | /* |
113 | * Interface type flags | 113 | * Interface type flags |
114 | */ | 114 | */ |
115 | enum interface_flags { | 115 | enum interface_flags { |
116 | ACER_AMW0, | 116 | ACER_AMW0, |
117 | ACER_AMW0_V2, | 117 | ACER_AMW0_V2, |
118 | ACER_WMID, | 118 | ACER_WMID, |
119 | }; | 119 | }; |
120 | 120 | ||
121 | #define ACER_DEFAULT_WIRELESS 0 | 121 | #define ACER_DEFAULT_WIRELESS 0 |
122 | #define ACER_DEFAULT_BLUETOOTH 0 | 122 | #define ACER_DEFAULT_BLUETOOTH 0 |
123 | #define ACER_DEFAULT_MAILLED 0 | 123 | #define ACER_DEFAULT_MAILLED 0 |
124 | #define ACER_DEFAULT_THREEG 0 | 124 | #define ACER_DEFAULT_THREEG 0 |
125 | 125 | ||
126 | static int max_brightness = 0xF; | 126 | static int max_brightness = 0xF; |
127 | 127 | ||
128 | static int mailled = -1; | 128 | static int mailled = -1; |
129 | static int brightness = -1; | 129 | static int brightness = -1; |
130 | static int threeg = -1; | 130 | static int threeg = -1; |
131 | static int force_series; | 131 | static int force_series; |
132 | 132 | ||
133 | module_param(mailled, int, 0444); | 133 | module_param(mailled, int, 0444); |
134 | module_param(brightness, int, 0444); | 134 | module_param(brightness, int, 0444); |
135 | module_param(threeg, int, 0444); | 135 | module_param(threeg, int, 0444); |
136 | module_param(force_series, int, 0444); | 136 | module_param(force_series, int, 0444); |
137 | MODULE_PARM_DESC(mailled, "Set initial state of Mail LED"); | 137 | MODULE_PARM_DESC(mailled, "Set initial state of Mail LED"); |
138 | MODULE_PARM_DESC(brightness, "Set initial LCD backlight brightness"); | 138 | MODULE_PARM_DESC(brightness, "Set initial LCD backlight brightness"); |
139 | MODULE_PARM_DESC(threeg, "Set initial state of 3G hardware"); | 139 | MODULE_PARM_DESC(threeg, "Set initial state of 3G hardware"); |
140 | MODULE_PARM_DESC(force_series, "Force a different laptop series"); | 140 | MODULE_PARM_DESC(force_series, "Force a different laptop series"); |
141 | 141 | ||
142 | struct acer_data { | 142 | struct acer_data { |
143 | int mailled; | 143 | int mailled; |
144 | int threeg; | 144 | int threeg; |
145 | int brightness; | 145 | int brightness; |
146 | }; | 146 | }; |
147 | 147 | ||
148 | struct acer_debug { | 148 | struct acer_debug { |
149 | struct dentry *root; | 149 | struct dentry *root; |
150 | struct dentry *devices; | 150 | struct dentry *devices; |
151 | u32 wmid_devices; | 151 | u32 wmid_devices; |
152 | }; | 152 | }; |
153 | 153 | ||
154 | static struct rfkill *wireless_rfkill; | 154 | static struct rfkill *wireless_rfkill; |
155 | static struct rfkill *bluetooth_rfkill; | 155 | static struct rfkill *bluetooth_rfkill; |
156 | 156 | ||
157 | /* Each low-level interface must define at least some of the following */ | 157 | /* Each low-level interface must define at least some of the following */ |
158 | struct wmi_interface { | 158 | struct wmi_interface { |
159 | /* The WMI device type */ | 159 | /* The WMI device type */ |
160 | u32 type; | 160 | u32 type; |
161 | 161 | ||
162 | /* The capabilities this interface provides */ | 162 | /* The capabilities this interface provides */ |
163 | u32 capability; | 163 | u32 capability; |
164 | 164 | ||
165 | /* Private data for the current interface */ | 165 | /* Private data for the current interface */ |
166 | struct acer_data data; | 166 | struct acer_data data; |
167 | 167 | ||
168 | /* debugfs entries associated with this interface */ | 168 | /* debugfs entries associated with this interface */ |
169 | struct acer_debug debug; | 169 | struct acer_debug debug; |
170 | }; | 170 | }; |
171 | 171 | ||
172 | /* The static interface pointer, points to the currently detected interface */ | 172 | /* The static interface pointer, points to the currently detected interface */ |
173 | static struct wmi_interface *interface; | 173 | static struct wmi_interface *interface; |
174 | 174 | ||
175 | /* | 175 | /* |
176 | * Embedded Controller quirks | 176 | * Embedded Controller quirks |
177 | * Some laptops require us to directly access the EC to either enable or query | 177 | * Some laptops require us to directly access the EC to either enable or query |
178 | * features that are not available through WMI. | 178 | * features that are not available through WMI. |
179 | */ | 179 | */ |
180 | 180 | ||
181 | struct quirk_entry { | 181 | struct quirk_entry { |
182 | u8 wireless; | 182 | u8 wireless; |
183 | u8 mailled; | 183 | u8 mailled; |
184 | s8 brightness; | 184 | s8 brightness; |
185 | u8 bluetooth; | 185 | u8 bluetooth; |
186 | }; | 186 | }; |
187 | 187 | ||
188 | static struct quirk_entry *quirks; | 188 | static struct quirk_entry *quirks; |
189 | 189 | ||
190 | static void set_quirks(void) | 190 | static void set_quirks(void) |
191 | { | 191 | { |
192 | if (!interface) | 192 | if (!interface) |
193 | return; | 193 | return; |
194 | 194 | ||
195 | if (quirks->mailled) | 195 | if (quirks->mailled) |
196 | interface->capability |= ACER_CAP_MAILLED; | 196 | interface->capability |= ACER_CAP_MAILLED; |
197 | 197 | ||
198 | if (quirks->brightness) | 198 | if (quirks->brightness) |
199 | interface->capability |= ACER_CAP_BRIGHTNESS; | 199 | interface->capability |= ACER_CAP_BRIGHTNESS; |
200 | } | 200 | } |
201 | 201 | ||
202 | static int dmi_matched(const struct dmi_system_id *dmi) | 202 | static int dmi_matched(const struct dmi_system_id *dmi) |
203 | { | 203 | { |
204 | quirks = dmi->driver_data; | 204 | quirks = dmi->driver_data; |
205 | return 0; | 205 | return 0; |
206 | } | 206 | } |
207 | 207 | ||
208 | static struct quirk_entry quirk_unknown = { | 208 | static struct quirk_entry quirk_unknown = { |
209 | }; | 209 | }; |
210 | 210 | ||
211 | static struct quirk_entry quirk_acer_aspire_1520 = { | 211 | static struct quirk_entry quirk_acer_aspire_1520 = { |
212 | .brightness = -1, | 212 | .brightness = -1, |
213 | }; | 213 | }; |
214 | 214 | ||
215 | static struct quirk_entry quirk_acer_travelmate_2490 = { | 215 | static struct quirk_entry quirk_acer_travelmate_2490 = { |
216 | .mailled = 1, | 216 | .mailled = 1, |
217 | }; | 217 | }; |
218 | 218 | ||
219 | /* This AMW0 laptop has no bluetooth */ | 219 | /* This AMW0 laptop has no bluetooth */ |
220 | static struct quirk_entry quirk_medion_md_98300 = { | 220 | static struct quirk_entry quirk_medion_md_98300 = { |
221 | .wireless = 1, | 221 | .wireless = 1, |
222 | }; | 222 | }; |
223 | 223 | ||
224 | static struct quirk_entry quirk_fujitsu_amilo_li_1718 = { | 224 | static struct quirk_entry quirk_fujitsu_amilo_li_1718 = { |
225 | .wireless = 2, | 225 | .wireless = 2, |
226 | }; | 226 | }; |
227 | 227 | ||
228 | static struct dmi_system_id acer_quirks[] = { | 228 | static struct dmi_system_id acer_quirks[] = { |
229 | { | 229 | { |
230 | .callback = dmi_matched, | 230 | .callback = dmi_matched, |
231 | .ident = "Acer Aspire 1360", | 231 | .ident = "Acer Aspire 1360", |
232 | .matches = { | 232 | .matches = { |
233 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), | 233 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), |
234 | DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1360"), | 234 | DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1360"), |
235 | }, | 235 | }, |
236 | .driver_data = &quirk_acer_aspire_1520, | 236 | .driver_data = &quirk_acer_aspire_1520, |
237 | }, | 237 | }, |
238 | { | 238 | { |
239 | .callback = dmi_matched, | 239 | .callback = dmi_matched, |
240 | .ident = "Acer Aspire 1520", | 240 | .ident = "Acer Aspire 1520", |
241 | .matches = { | 241 | .matches = { |
242 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), | 242 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), |
243 | DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1520"), | 243 | DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1520"), |
244 | }, | 244 | }, |
245 | .driver_data = &quirk_acer_aspire_1520, | 245 | .driver_data = &quirk_acer_aspire_1520, |
246 | }, | 246 | }, |
247 | { | 247 | { |
248 | .callback = dmi_matched, | 248 | .callback = dmi_matched, |
249 | .ident = "Acer Aspire 3100", | 249 | .ident = "Acer Aspire 3100", |
250 | .matches = { | 250 | .matches = { |
251 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), | 251 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), |
252 | DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3100"), | 252 | DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3100"), |
253 | }, | 253 | }, |
254 | .driver_data = &quirk_acer_travelmate_2490, | 254 | .driver_data = &quirk_acer_travelmate_2490, |
255 | }, | 255 | }, |
256 | { | 256 | { |
257 | .callback = dmi_matched, | 257 | .callback = dmi_matched, |
258 | .ident = "Acer Aspire 3610", | 258 | .ident = "Acer Aspire 3610", |
259 | .matches = { | 259 | .matches = { |
260 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), | 260 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), |
261 | DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3610"), | 261 | DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3610"), |
262 | }, | 262 | }, |
263 | .driver_data = &quirk_acer_travelmate_2490, | 263 | .driver_data = &quirk_acer_travelmate_2490, |
264 | }, | 264 | }, |
265 | { | 265 | { |
266 | .callback = dmi_matched, | 266 | .callback = dmi_matched, |
267 | .ident = "Acer Aspire 5100", | 267 | .ident = "Acer Aspire 5100", |
268 | .matches = { | 268 | .matches = { |
269 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), | 269 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), |
270 | DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"), | 270 | DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"), |
271 | }, | 271 | }, |
272 | .driver_data = &quirk_acer_travelmate_2490, | 272 | .driver_data = &quirk_acer_travelmate_2490, |
273 | }, | 273 | }, |
274 | { | 274 | { |
275 | .callback = dmi_matched, | 275 | .callback = dmi_matched, |
276 | .ident = "Acer Aspire 5610", | 276 | .ident = "Acer Aspire 5610", |
277 | .matches = { | 277 | .matches = { |
278 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), | 278 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), |
279 | DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5610"), | 279 | DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5610"), |
280 | }, | 280 | }, |
281 | .driver_data = &quirk_acer_travelmate_2490, | 281 | .driver_data = &quirk_acer_travelmate_2490, |
282 | }, | 282 | }, |
283 | { | 283 | { |
284 | .callback = dmi_matched, | 284 | .callback = dmi_matched, |
285 | .ident = "Acer Aspire 5630", | 285 | .ident = "Acer Aspire 5630", |
286 | .matches = { | 286 | .matches = { |
287 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), | 287 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), |
288 | DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5630"), | 288 | DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5630"), |
289 | }, | 289 | }, |
290 | .driver_data = &quirk_acer_travelmate_2490, | 290 | .driver_data = &quirk_acer_travelmate_2490, |
291 | }, | 291 | }, |
292 | { | 292 | { |
293 | .callback = dmi_matched, | 293 | .callback = dmi_matched, |
294 | .ident = "Acer Aspire 5650", | 294 | .ident = "Acer Aspire 5650", |
295 | .matches = { | 295 | .matches = { |
296 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), | 296 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), |
297 | DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5650"), | 297 | DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5650"), |
298 | }, | 298 | }, |
299 | .driver_data = &quirk_acer_travelmate_2490, | 299 | .driver_data = &quirk_acer_travelmate_2490, |
300 | }, | 300 | }, |
301 | { | 301 | { |
302 | .callback = dmi_matched, | 302 | .callback = dmi_matched, |
303 | .ident = "Acer Aspire 5680", | 303 | .ident = "Acer Aspire 5680", |
304 | .matches = { | 304 | .matches = { |
305 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), | 305 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), |
306 | DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5680"), | 306 | DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5680"), |
307 | }, | 307 | }, |
308 | .driver_data = &quirk_acer_travelmate_2490, | 308 | .driver_data = &quirk_acer_travelmate_2490, |
309 | }, | 309 | }, |
310 | { | 310 | { |
311 | .callback = dmi_matched, | 311 | .callback = dmi_matched, |
312 | .ident = "Acer Aspire 9110", | 312 | .ident = "Acer Aspire 9110", |
313 | .matches = { | 313 | .matches = { |
314 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), | 314 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), |
315 | DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 9110"), | 315 | DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 9110"), |
316 | }, | 316 | }, |
317 | .driver_data = &quirk_acer_travelmate_2490, | 317 | .driver_data = &quirk_acer_travelmate_2490, |
318 | }, | 318 | }, |
319 | { | 319 | { |
320 | .callback = dmi_matched, | 320 | .callback = dmi_matched, |
321 | .ident = "Acer TravelMate 2490", | 321 | .ident = "Acer TravelMate 2490", |
322 | .matches = { | 322 | .matches = { |
323 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), | 323 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), |
324 | DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2490"), | 324 | DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2490"), |
325 | }, | 325 | }, |
326 | .driver_data = &quirk_acer_travelmate_2490, | 326 | .driver_data = &quirk_acer_travelmate_2490, |
327 | }, | 327 | }, |
328 | { | 328 | { |
329 | .callback = dmi_matched, | 329 | .callback = dmi_matched, |
330 | .ident = "Acer TravelMate 4200", | 330 | .ident = "Acer TravelMate 4200", |
331 | .matches = { | 331 | .matches = { |
332 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), | 332 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), |
333 | DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4200"), | 333 | DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4200"), |
334 | }, | 334 | }, |
335 | .driver_data = &quirk_acer_travelmate_2490, | 335 | .driver_data = &quirk_acer_travelmate_2490, |
336 | }, | 336 | }, |
337 | { | 337 | { |
338 | .callback = dmi_matched, | 338 | .callback = dmi_matched, |
339 | .ident = "Fujitsu Siemens Amilo Li 1718", | 339 | .ident = "Fujitsu Siemens Amilo Li 1718", |
340 | .matches = { | 340 | .matches = { |
341 | DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), | 341 | DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), |
342 | DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Li 1718"), | 342 | DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Li 1718"), |
343 | }, | 343 | }, |
344 | .driver_data = &quirk_fujitsu_amilo_li_1718, | 344 | .driver_data = &quirk_fujitsu_amilo_li_1718, |
345 | }, | 345 | }, |
346 | { | 346 | { |
347 | .callback = dmi_matched, | 347 | .callback = dmi_matched, |
348 | .ident = "Medion MD 98300", | 348 | .ident = "Medion MD 98300", |
349 | .matches = { | 349 | .matches = { |
350 | DMI_MATCH(DMI_SYS_VENDOR, "MEDION"), | 350 | DMI_MATCH(DMI_SYS_VENDOR, "MEDION"), |
351 | DMI_MATCH(DMI_PRODUCT_NAME, "WAM2030"), | 351 | DMI_MATCH(DMI_PRODUCT_NAME, "WAM2030"), |
352 | }, | 352 | }, |
353 | .driver_data = &quirk_medion_md_98300, | 353 | .driver_data = &quirk_medion_md_98300, |
354 | }, | 354 | }, |
355 | {} | 355 | {} |
356 | }; | 356 | }; |
357 | 357 | ||
358 | /* Find which quirks are needed for a particular vendor/ model pair */ | 358 | /* Find which quirks are needed for a particular vendor/ model pair */ |
359 | static void find_quirks(void) | 359 | static void find_quirks(void) |
360 | { | 360 | { |
361 | if (!force_series) { | 361 | if (!force_series) { |
362 | dmi_check_system(acer_quirks); | 362 | dmi_check_system(acer_quirks); |
363 | } else if (force_series == 2490) { | 363 | } else if (force_series == 2490) { |
364 | quirks = &quirk_acer_travelmate_2490; | 364 | quirks = &quirk_acer_travelmate_2490; |
365 | } | 365 | } |
366 | 366 | ||
367 | if (quirks == NULL) | 367 | if (quirks == NULL) |
368 | quirks = &quirk_unknown; | 368 | quirks = &quirk_unknown; |
369 | 369 | ||
370 | set_quirks(); | 370 | set_quirks(); |
371 | } | 371 | } |
372 | 372 | ||
373 | /* | 373 | /* |
374 | * General interface convenience methods | 374 | * General interface convenience methods |
375 | */ | 375 | */ |
376 | 376 | ||
377 | static bool has_cap(u32 cap) | 377 | static bool has_cap(u32 cap) |
378 | { | 378 | { |
379 | if ((interface->capability & cap) != 0) | 379 | if ((interface->capability & cap) != 0) |
380 | return 1; | 380 | return 1; |
381 | 381 | ||
382 | return 0; | 382 | return 0; |
383 | } | 383 | } |
384 | 384 | ||
385 | /* | 385 | /* |
386 | * AMW0 (V1) interface | 386 | * AMW0 (V1) interface |
387 | */ | 387 | */ |
388 | struct wmab_args { | 388 | struct wmab_args { |
389 | u32 eax; | 389 | u32 eax; |
390 | u32 ebx; | 390 | u32 ebx; |
391 | u32 ecx; | 391 | u32 ecx; |
392 | u32 edx; | 392 | u32 edx; |
393 | }; | 393 | }; |
394 | 394 | ||
395 | struct wmab_ret { | 395 | struct wmab_ret { |
396 | u32 eax; | 396 | u32 eax; |
397 | u32 ebx; | 397 | u32 ebx; |
398 | u32 ecx; | 398 | u32 ecx; |
399 | u32 edx; | 399 | u32 edx; |
400 | u32 eex; | 400 | u32 eex; |
401 | }; | 401 | }; |
402 | 402 | ||
403 | static acpi_status wmab_execute(struct wmab_args *regbuf, | 403 | static acpi_status wmab_execute(struct wmab_args *regbuf, |
404 | struct acpi_buffer *result) | 404 | struct acpi_buffer *result) |
405 | { | 405 | { |
406 | struct acpi_buffer input; | 406 | struct acpi_buffer input; |
407 | acpi_status status; | 407 | acpi_status status; |
408 | input.length = sizeof(struct wmab_args); | 408 | input.length = sizeof(struct wmab_args); |
409 | input.pointer = (u8 *)regbuf; | 409 | input.pointer = (u8 *)regbuf; |
410 | 410 | ||
411 | status = wmi_evaluate_method(AMW0_GUID1, 1, 1, &input, result); | 411 | status = wmi_evaluate_method(AMW0_GUID1, 1, 1, &input, result); |
412 | 412 | ||
413 | return status; | 413 | return status; |
414 | } | 414 | } |
415 | 415 | ||
416 | static acpi_status AMW0_get_u32(u32 *value, u32 cap, | 416 | static acpi_status AMW0_get_u32(u32 *value, u32 cap, |
417 | struct wmi_interface *iface) | 417 | struct wmi_interface *iface) |
418 | { | 418 | { |
419 | int err; | 419 | int err; |
420 | u8 result; | 420 | u8 result; |
421 | 421 | ||
422 | switch (cap) { | 422 | switch (cap) { |
423 | case ACER_CAP_MAILLED: | 423 | case ACER_CAP_MAILLED: |
424 | switch (quirks->mailled) { | 424 | switch (quirks->mailled) { |
425 | default: | 425 | default: |
426 | err = ec_read(0xA, &result); | 426 | err = ec_read(0xA, &result); |
427 | if (err) | 427 | if (err) |
428 | return AE_ERROR; | 428 | return AE_ERROR; |
429 | *value = (result >> 7) & 0x1; | 429 | *value = (result >> 7) & 0x1; |
430 | return AE_OK; | 430 | return AE_OK; |
431 | } | 431 | } |
432 | break; | 432 | break; |
433 | case ACER_CAP_WIRELESS: | 433 | case ACER_CAP_WIRELESS: |
434 | switch (quirks->wireless) { | 434 | switch (quirks->wireless) { |
435 | case 1: | 435 | case 1: |
436 | err = ec_read(0x7B, &result); | 436 | err = ec_read(0x7B, &result); |
437 | if (err) | 437 | if (err) |
438 | return AE_ERROR; | 438 | return AE_ERROR; |
439 | *value = result & 0x1; | 439 | *value = result & 0x1; |
440 | return AE_OK; | 440 | return AE_OK; |
441 | case 2: | 441 | case 2: |
442 | err = ec_read(0x71, &result); | 442 | err = ec_read(0x71, &result); |
443 | if (err) | 443 | if (err) |
444 | return AE_ERROR; | 444 | return AE_ERROR; |
445 | *value = result & 0x1; | 445 | *value = result & 0x1; |
446 | return AE_OK; | 446 | return AE_OK; |
447 | default: | 447 | default: |
448 | err = ec_read(0xA, &result); | 448 | err = ec_read(0xA, &result); |
449 | if (err) | 449 | if (err) |
450 | return AE_ERROR; | 450 | return AE_ERROR; |
451 | *value = (result >> 2) & 0x1; | 451 | *value = (result >> 2) & 0x1; |
452 | return AE_OK; | 452 | return AE_OK; |
453 | } | 453 | } |
454 | break; | 454 | break; |
455 | case ACER_CAP_BLUETOOTH: | 455 | case ACER_CAP_BLUETOOTH: |
456 | switch (quirks->bluetooth) { | 456 | switch (quirks->bluetooth) { |
457 | default: | 457 | default: |
458 | err = ec_read(0xA, &result); | 458 | err = ec_read(0xA, &result); |
459 | if (err) | 459 | if (err) |
460 | return AE_ERROR; | 460 | return AE_ERROR; |
461 | *value = (result >> 4) & 0x1; | 461 | *value = (result >> 4) & 0x1; |
462 | return AE_OK; | 462 | return AE_OK; |
463 | } | 463 | } |
464 | break; | 464 | break; |
465 | case ACER_CAP_BRIGHTNESS: | 465 | case ACER_CAP_BRIGHTNESS: |
466 | switch (quirks->brightness) { | 466 | switch (quirks->brightness) { |
467 | default: | 467 | default: |
468 | err = ec_read(0x83, &result); | 468 | err = ec_read(0x83, &result); |
469 | if (err) | 469 | if (err) |
470 | return AE_ERROR; | 470 | return AE_ERROR; |
471 | *value = result; | 471 | *value = result; |
472 | return AE_OK; | 472 | return AE_OK; |
473 | } | 473 | } |
474 | break; | 474 | break; |
475 | default: | 475 | default: |
476 | return AE_ERROR; | 476 | return AE_ERROR; |
477 | } | 477 | } |
478 | return AE_OK; | 478 | return AE_OK; |
479 | } | 479 | } |
480 | 480 | ||
481 | static acpi_status AMW0_set_u32(u32 value, u32 cap, struct wmi_interface *iface) | 481 | static acpi_status AMW0_set_u32(u32 value, u32 cap, struct wmi_interface *iface) |
482 | { | 482 | { |
483 | struct wmab_args args; | 483 | struct wmab_args args; |
484 | 484 | ||
485 | args.eax = ACER_AMW0_WRITE; | 485 | args.eax = ACER_AMW0_WRITE; |
486 | args.ebx = value ? (1<<8) : 0; | 486 | args.ebx = value ? (1<<8) : 0; |
487 | args.ecx = args.edx = 0; | 487 | args.ecx = args.edx = 0; |
488 | 488 | ||
489 | switch (cap) { | 489 | switch (cap) { |
490 | case ACER_CAP_MAILLED: | 490 | case ACER_CAP_MAILLED: |
491 | if (value > 1) | 491 | if (value > 1) |
492 | return AE_BAD_PARAMETER; | 492 | return AE_BAD_PARAMETER; |
493 | args.ebx |= ACER_AMW0_MAILLED_MASK; | 493 | args.ebx |= ACER_AMW0_MAILLED_MASK; |
494 | break; | 494 | break; |
495 | case ACER_CAP_WIRELESS: | 495 | case ACER_CAP_WIRELESS: |
496 | if (value > 1) | 496 | if (value > 1) |
497 | return AE_BAD_PARAMETER; | 497 | return AE_BAD_PARAMETER; |
498 | args.ebx |= ACER_AMW0_WIRELESS_MASK; | 498 | args.ebx |= ACER_AMW0_WIRELESS_MASK; |
499 | break; | 499 | break; |
500 | case ACER_CAP_BLUETOOTH: | 500 | case ACER_CAP_BLUETOOTH: |
501 | if (value > 1) | 501 | if (value > 1) |
502 | return AE_BAD_PARAMETER; | 502 | return AE_BAD_PARAMETER; |
503 | args.ebx |= ACER_AMW0_BLUETOOTH_MASK; | 503 | args.ebx |= ACER_AMW0_BLUETOOTH_MASK; |
504 | break; | 504 | break; |
505 | case ACER_CAP_BRIGHTNESS: | 505 | case ACER_CAP_BRIGHTNESS: |
506 | if (value > max_brightness) | 506 | if (value > max_brightness) |
507 | return AE_BAD_PARAMETER; | 507 | return AE_BAD_PARAMETER; |
508 | switch (quirks->brightness) { | 508 | switch (quirks->brightness) { |
509 | default: | 509 | default: |
510 | return ec_write(0x83, value); | 510 | return ec_write(0x83, value); |
511 | break; | 511 | break; |
512 | } | 512 | } |
513 | default: | 513 | default: |
514 | return AE_ERROR; | 514 | return AE_ERROR; |
515 | } | 515 | } |
516 | 516 | ||
517 | /* Actually do the set */ | 517 | /* Actually do the set */ |
518 | return wmab_execute(&args, NULL); | 518 | return wmab_execute(&args, NULL); |
519 | } | 519 | } |
520 | 520 | ||
521 | static acpi_status AMW0_find_mailled(void) | 521 | static acpi_status AMW0_find_mailled(void) |
522 | { | 522 | { |
523 | struct wmab_args args; | 523 | struct wmab_args args; |
524 | struct wmab_ret ret; | 524 | struct wmab_ret ret; |
525 | acpi_status status = AE_OK; | 525 | acpi_status status = AE_OK; |
526 | struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL }; | 526 | struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL }; |
527 | union acpi_object *obj; | 527 | union acpi_object *obj; |
528 | 528 | ||
529 | args.eax = 0x86; | 529 | args.eax = 0x86; |
530 | args.ebx = args.ecx = args.edx = 0; | 530 | args.ebx = args.ecx = args.edx = 0; |
531 | 531 | ||
532 | status = wmab_execute(&args, &out); | 532 | status = wmab_execute(&args, &out); |
533 | if (ACPI_FAILURE(status)) | 533 | if (ACPI_FAILURE(status)) |
534 | return status; | 534 | return status; |
535 | 535 | ||
536 | obj = (union acpi_object *) out.pointer; | 536 | obj = (union acpi_object *) out.pointer; |
537 | if (obj && obj->type == ACPI_TYPE_BUFFER && | 537 | if (obj && obj->type == ACPI_TYPE_BUFFER && |
538 | obj->buffer.length == sizeof(struct wmab_ret)) { | 538 | obj->buffer.length == sizeof(struct wmab_ret)) { |
539 | ret = *((struct wmab_ret *) obj->buffer.pointer); | 539 | ret = *((struct wmab_ret *) obj->buffer.pointer); |
540 | } else { | 540 | } else { |
541 | return AE_ERROR; | 541 | return AE_ERROR; |
542 | } | 542 | } |
543 | 543 | ||
544 | if (ret.eex & 0x1) | 544 | if (ret.eex & 0x1) |
545 | interface->capability |= ACER_CAP_MAILLED; | 545 | interface->capability |= ACER_CAP_MAILLED; |
546 | 546 | ||
547 | kfree(out.pointer); | 547 | kfree(out.pointer); |
548 | 548 | ||
549 | return AE_OK; | 549 | return AE_OK; |
550 | } | 550 | } |
551 | 551 | ||
552 | static acpi_status AMW0_set_capabilities(void) | 552 | static acpi_status AMW0_set_capabilities(void) |
553 | { | 553 | { |
554 | struct wmab_args args; | 554 | struct wmab_args args; |
555 | struct wmab_ret ret; | 555 | struct wmab_ret ret; |
556 | acpi_status status = AE_OK; | 556 | acpi_status status = AE_OK; |
557 | struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL }; | 557 | struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL }; |
558 | union acpi_object *obj; | 558 | union acpi_object *obj; |
559 | 559 | ||
560 | /* | 560 | /* |
561 | * On laptops with this strange GUID (non Acer), normal probing doesn't | 561 | * On laptops with this strange GUID (non Acer), normal probing doesn't |
562 | * work. | 562 | * work. |
563 | */ | 563 | */ |
564 | if (wmi_has_guid(AMW0_GUID2)) { | 564 | if (wmi_has_guid(AMW0_GUID2)) { |
565 | interface->capability |= ACER_CAP_WIRELESS; | 565 | interface->capability |= ACER_CAP_WIRELESS; |
566 | return AE_OK; | 566 | return AE_OK; |
567 | } | 567 | } |
568 | 568 | ||
569 | args.eax = ACER_AMW0_WRITE; | 569 | args.eax = ACER_AMW0_WRITE; |
570 | args.ecx = args.edx = 0; | 570 | args.ecx = args.edx = 0; |
571 | 571 | ||
572 | args.ebx = 0xa2 << 8; | 572 | args.ebx = 0xa2 << 8; |
573 | args.ebx |= ACER_AMW0_WIRELESS_MASK; | 573 | args.ebx |= ACER_AMW0_WIRELESS_MASK; |
574 | 574 | ||
575 | status = wmab_execute(&args, &out); | 575 | status = wmab_execute(&args, &out); |
576 | if (ACPI_FAILURE(status)) | 576 | if (ACPI_FAILURE(status)) |
577 | return status; | 577 | return status; |
578 | 578 | ||
579 | obj = (union acpi_object *) out.pointer; | 579 | obj = (union acpi_object *) out.pointer; |
580 | if (obj && obj->type == ACPI_TYPE_BUFFER && | 580 | if (obj && obj->type == ACPI_TYPE_BUFFER && |
581 | obj->buffer.length == sizeof(struct wmab_ret)) { | 581 | obj->buffer.length == sizeof(struct wmab_ret)) { |
582 | ret = *((struct wmab_ret *) obj->buffer.pointer); | 582 | ret = *((struct wmab_ret *) obj->buffer.pointer); |
583 | } else { | 583 | } else { |
584 | return AE_ERROR; | 584 | return AE_ERROR; |
585 | } | 585 | } |
586 | 586 | ||
587 | if (ret.eax & 0x1) | 587 | if (ret.eax & 0x1) |
588 | interface->capability |= ACER_CAP_WIRELESS; | 588 | interface->capability |= ACER_CAP_WIRELESS; |
589 | 589 | ||
590 | args.ebx = 2 << 8; | 590 | args.ebx = 2 << 8; |
591 | args.ebx |= ACER_AMW0_BLUETOOTH_MASK; | 591 | args.ebx |= ACER_AMW0_BLUETOOTH_MASK; |
592 | 592 | ||
593 | status = wmab_execute(&args, &out); | 593 | status = wmab_execute(&args, &out); |
594 | if (ACPI_FAILURE(status)) | 594 | if (ACPI_FAILURE(status)) |
595 | return status; | 595 | return status; |
596 | 596 | ||
597 | obj = (union acpi_object *) out.pointer; | 597 | obj = (union acpi_object *) out.pointer; |
598 | if (obj && obj->type == ACPI_TYPE_BUFFER | 598 | if (obj && obj->type == ACPI_TYPE_BUFFER |
599 | && obj->buffer.length == sizeof(struct wmab_ret)) { | 599 | && obj->buffer.length == sizeof(struct wmab_ret)) { |
600 | ret = *((struct wmab_ret *) obj->buffer.pointer); | 600 | ret = *((struct wmab_ret *) obj->buffer.pointer); |
601 | } else { | 601 | } else { |
602 | return AE_ERROR; | 602 | return AE_ERROR; |
603 | } | 603 | } |
604 | 604 | ||
605 | if (ret.eax & 0x1) | 605 | if (ret.eax & 0x1) |
606 | interface->capability |= ACER_CAP_BLUETOOTH; | 606 | interface->capability |= ACER_CAP_BLUETOOTH; |
607 | 607 | ||
608 | kfree(out.pointer); | 608 | kfree(out.pointer); |
609 | 609 | ||
610 | /* | 610 | /* |
611 | * This appears to be safe to enable, since all Wistron based laptops | 611 | * This appears to be safe to enable, since all Wistron based laptops |
612 | * appear to use the same EC register for brightness, even if they | 612 | * appear to use the same EC register for brightness, even if they |
613 | * differ for wireless, etc | 613 | * differ for wireless, etc |
614 | */ | 614 | */ |
615 | if (quirks->brightness >= 0) | 615 | if (quirks->brightness >= 0) |
616 | interface->capability |= ACER_CAP_BRIGHTNESS; | 616 | interface->capability |= ACER_CAP_BRIGHTNESS; |
617 | 617 | ||
618 | return AE_OK; | 618 | return AE_OK; |
619 | } | 619 | } |
620 | 620 | ||
621 | static struct wmi_interface AMW0_interface = { | 621 | static struct wmi_interface AMW0_interface = { |
622 | .type = ACER_AMW0, | 622 | .type = ACER_AMW0, |
623 | }; | 623 | }; |
624 | 624 | ||
625 | static struct wmi_interface AMW0_V2_interface = { | 625 | static struct wmi_interface AMW0_V2_interface = { |
626 | .type = ACER_AMW0_V2, | 626 | .type = ACER_AMW0_V2, |
627 | }; | 627 | }; |
628 | 628 | ||
629 | /* | 629 | /* |
630 | * New interface (The WMID interface) | 630 | * New interface (The WMID interface) |
631 | */ | 631 | */ |
632 | static acpi_status | 632 | static acpi_status |
633 | WMI_execute_u32(u32 method_id, u32 in, u32 *out) | 633 | WMI_execute_u32(u32 method_id, u32 in, u32 *out) |
634 | { | 634 | { |
635 | struct acpi_buffer input = { (acpi_size) sizeof(u32), (void *)(&in) }; | 635 | struct acpi_buffer input = { (acpi_size) sizeof(u32), (void *)(&in) }; |
636 | struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL }; | 636 | struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL }; |
637 | union acpi_object *obj; | 637 | union acpi_object *obj; |
638 | u32 tmp; | 638 | u32 tmp; |
639 | acpi_status status; | 639 | acpi_status status; |
640 | 640 | ||
641 | status = wmi_evaluate_method(WMID_GUID1, 1, method_id, &input, &result); | 641 | status = wmi_evaluate_method(WMID_GUID1, 1, method_id, &input, &result); |
642 | 642 | ||
643 | if (ACPI_FAILURE(status)) | 643 | if (ACPI_FAILURE(status)) |
644 | return status; | 644 | return status; |
645 | 645 | ||
646 | obj = (union acpi_object *) result.pointer; | 646 | obj = (union acpi_object *) result.pointer; |
647 | if (obj && obj->type == ACPI_TYPE_BUFFER && | 647 | if (obj && obj->type == ACPI_TYPE_BUFFER && |
648 | obj->buffer.length == sizeof(u32)) { | 648 | obj->buffer.length == sizeof(u32)) { |
649 | tmp = *((u32 *) obj->buffer.pointer); | 649 | tmp = *((u32 *) obj->buffer.pointer); |
650 | } else { | 650 | } else { |
651 | tmp = 0; | 651 | tmp = 0; |
652 | } | 652 | } |
653 | 653 | ||
654 | if (out) | 654 | if (out) |
655 | *out = tmp; | 655 | *out = tmp; |
656 | 656 | ||
657 | kfree(result.pointer); | 657 | kfree(result.pointer); |
658 | 658 | ||
659 | return status; | 659 | return status; |
660 | } | 660 | } |
661 | 661 | ||
662 | static acpi_status WMID_get_u32(u32 *value, u32 cap, | 662 | static acpi_status WMID_get_u32(u32 *value, u32 cap, |
663 | struct wmi_interface *iface) | 663 | struct wmi_interface *iface) |
664 | { | 664 | { |
665 | acpi_status status; | 665 | acpi_status status; |
666 | u8 tmp; | 666 | u8 tmp; |
667 | u32 result, method_id = 0; | 667 | u32 result, method_id = 0; |
668 | 668 | ||
669 | switch (cap) { | 669 | switch (cap) { |
670 | case ACER_CAP_WIRELESS: | 670 | case ACER_CAP_WIRELESS: |
671 | method_id = ACER_WMID_GET_WIRELESS_METHODID; | 671 | method_id = ACER_WMID_GET_WIRELESS_METHODID; |
672 | break; | 672 | break; |
673 | case ACER_CAP_BLUETOOTH: | 673 | case ACER_CAP_BLUETOOTH: |
674 | method_id = ACER_WMID_GET_BLUETOOTH_METHODID; | 674 | method_id = ACER_WMID_GET_BLUETOOTH_METHODID; |
675 | break; | 675 | break; |
676 | case ACER_CAP_BRIGHTNESS: | 676 | case ACER_CAP_BRIGHTNESS: |
677 | method_id = ACER_WMID_GET_BRIGHTNESS_METHODID; | 677 | method_id = ACER_WMID_GET_BRIGHTNESS_METHODID; |
678 | break; | 678 | break; |
679 | case ACER_CAP_THREEG: | 679 | case ACER_CAP_THREEG: |
680 | method_id = ACER_WMID_GET_THREEG_METHODID; | 680 | method_id = ACER_WMID_GET_THREEG_METHODID; |
681 | break; | 681 | break; |
682 | case ACER_CAP_MAILLED: | 682 | case ACER_CAP_MAILLED: |
683 | if (quirks->mailled == 1) { | 683 | if (quirks->mailled == 1) { |
684 | ec_read(0x9f, &tmp); | 684 | ec_read(0x9f, &tmp); |
685 | *value = tmp & 0x1; | 685 | *value = tmp & 0x1; |
686 | return 0; | 686 | return 0; |
687 | } | 687 | } |
688 | default: | 688 | default: |
689 | return AE_ERROR; | 689 | return AE_ERROR; |
690 | } | 690 | } |
691 | status = WMI_execute_u32(method_id, 0, &result); | 691 | status = WMI_execute_u32(method_id, 0, &result); |
692 | 692 | ||
693 | if (ACPI_SUCCESS(status)) | 693 | if (ACPI_SUCCESS(status)) |
694 | *value = (u8)result; | 694 | *value = (u8)result; |
695 | 695 | ||
696 | return status; | 696 | return status; |
697 | } | 697 | } |
698 | 698 | ||
699 | static acpi_status WMID_set_u32(u32 value, u32 cap, struct wmi_interface *iface) | 699 | static acpi_status WMID_set_u32(u32 value, u32 cap, struct wmi_interface *iface) |
700 | { | 700 | { |
701 | u32 method_id = 0; | 701 | u32 method_id = 0; |
702 | char param; | 702 | char param; |
703 | 703 | ||
704 | switch (cap) { | 704 | switch (cap) { |
705 | case ACER_CAP_BRIGHTNESS: | 705 | case ACER_CAP_BRIGHTNESS: |
706 | if (value > max_brightness) | 706 | if (value > max_brightness) |
707 | return AE_BAD_PARAMETER; | 707 | return AE_BAD_PARAMETER; |
708 | method_id = ACER_WMID_SET_BRIGHTNESS_METHODID; | 708 | method_id = ACER_WMID_SET_BRIGHTNESS_METHODID; |
709 | break; | 709 | break; |
710 | case ACER_CAP_WIRELESS: | 710 | case ACER_CAP_WIRELESS: |
711 | if (value > 1) | 711 | if (value > 1) |
712 | return AE_BAD_PARAMETER; | 712 | return AE_BAD_PARAMETER; |
713 | method_id = ACER_WMID_SET_WIRELESS_METHODID; | 713 | method_id = ACER_WMID_SET_WIRELESS_METHODID; |
714 | break; | 714 | break; |
715 | case ACER_CAP_BLUETOOTH: | 715 | case ACER_CAP_BLUETOOTH: |
716 | if (value > 1) | 716 | if (value > 1) |
717 | return AE_BAD_PARAMETER; | 717 | return AE_BAD_PARAMETER; |
718 | method_id = ACER_WMID_SET_BLUETOOTH_METHODID; | 718 | method_id = ACER_WMID_SET_BLUETOOTH_METHODID; |
719 | break; | 719 | break; |
720 | case ACER_CAP_THREEG: | 720 | case ACER_CAP_THREEG: |
721 | if (value > 1) | 721 | if (value > 1) |
722 | return AE_BAD_PARAMETER; | 722 | return AE_BAD_PARAMETER; |
723 | method_id = ACER_WMID_SET_THREEG_METHODID; | 723 | method_id = ACER_WMID_SET_THREEG_METHODID; |
724 | break; | 724 | break; |
725 | case ACER_CAP_MAILLED: | 725 | case ACER_CAP_MAILLED: |
726 | if (value > 1) | 726 | if (value > 1) |
727 | return AE_BAD_PARAMETER; | 727 | return AE_BAD_PARAMETER; |
728 | if (quirks->mailled == 1) { | 728 | if (quirks->mailled == 1) { |
729 | param = value ? 0x92 : 0x93; | 729 | param = value ? 0x92 : 0x93; |
730 | i8042_command(¶m, 0x1059); | 730 | i8042_command(¶m, 0x1059); |
731 | return 0; | 731 | return 0; |
732 | } | 732 | } |
733 | break; | 733 | break; |
734 | default: | 734 | default: |
735 | return AE_ERROR; | 735 | return AE_ERROR; |
736 | } | 736 | } |
737 | return WMI_execute_u32(method_id, (u32)value, NULL); | 737 | return WMI_execute_u32(method_id, (u32)value, NULL); |
738 | } | 738 | } |
739 | 739 | ||
740 | static acpi_status WMID_set_capabilities(void) | 740 | static acpi_status WMID_set_capabilities(void) |
741 | { | 741 | { |
742 | struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL}; | 742 | struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL}; |
743 | union acpi_object *obj; | 743 | union acpi_object *obj; |
744 | acpi_status status; | 744 | acpi_status status; |
745 | u32 devices; | 745 | u32 devices; |
746 | 746 | ||
747 | status = wmi_query_block(WMID_GUID2, 1, &out); | 747 | status = wmi_query_block(WMID_GUID2, 1, &out); |
748 | if (ACPI_FAILURE(status)) | 748 | if (ACPI_FAILURE(status)) |
749 | return status; | 749 | return status; |
750 | 750 | ||
751 | obj = (union acpi_object *) out.pointer; | 751 | obj = (union acpi_object *) out.pointer; |
752 | if (obj && obj->type == ACPI_TYPE_BUFFER && | 752 | if (obj && obj->type == ACPI_TYPE_BUFFER && |
753 | obj->buffer.length == sizeof(u32)) { | 753 | obj->buffer.length == sizeof(u32)) { |
754 | devices = *((u32 *) obj->buffer.pointer); | 754 | devices = *((u32 *) obj->buffer.pointer); |
755 | } else { | 755 | } else { |
756 | return AE_ERROR; | 756 | return AE_ERROR; |
757 | } | 757 | } |
758 | 758 | ||
759 | /* Not sure on the meaning of the relevant bits yet to detect these */ | 759 | /* Not sure on the meaning of the relevant bits yet to detect these */ |
760 | interface->capability |= ACER_CAP_WIRELESS; | 760 | interface->capability |= ACER_CAP_WIRELESS; |
761 | interface->capability |= ACER_CAP_THREEG; | 761 | interface->capability |= ACER_CAP_THREEG; |
762 | 762 | ||
763 | /* WMID always provides brightness methods */ | 763 | /* WMID always provides brightness methods */ |
764 | interface->capability |= ACER_CAP_BRIGHTNESS; | 764 | interface->capability |= ACER_CAP_BRIGHTNESS; |
765 | 765 | ||
766 | if (devices & 0x10) | 766 | if (devices & 0x10) |
767 | interface->capability |= ACER_CAP_BLUETOOTH; | 767 | interface->capability |= ACER_CAP_BLUETOOTH; |
768 | 768 | ||
769 | if (!(devices & 0x20)) | 769 | if (!(devices & 0x20)) |
770 | max_brightness = 0x9; | 770 | max_brightness = 0x9; |
771 | 771 | ||
772 | return status; | 772 | return status; |
773 | } | 773 | } |
774 | 774 | ||
775 | static struct wmi_interface wmid_interface = { | 775 | static struct wmi_interface wmid_interface = { |
776 | .type = ACER_WMID, | 776 | .type = ACER_WMID, |
777 | }; | 777 | }; |
778 | 778 | ||
779 | /* | 779 | /* |
780 | * Generic Device (interface-independent) | 780 | * Generic Device (interface-independent) |
781 | */ | 781 | */ |
782 | 782 | ||
783 | static acpi_status get_u32(u32 *value, u32 cap) | 783 | static acpi_status get_u32(u32 *value, u32 cap) |
784 | { | 784 | { |
785 | acpi_status status = AE_ERROR; | 785 | acpi_status status = AE_ERROR; |
786 | 786 | ||
787 | switch (interface->type) { | 787 | switch (interface->type) { |
788 | case ACER_AMW0: | 788 | case ACER_AMW0: |
789 | status = AMW0_get_u32(value, cap, interface); | 789 | status = AMW0_get_u32(value, cap, interface); |
790 | break; | 790 | break; |
791 | case ACER_AMW0_V2: | 791 | case ACER_AMW0_V2: |
792 | if (cap == ACER_CAP_MAILLED) { | 792 | if (cap == ACER_CAP_MAILLED) { |
793 | status = AMW0_get_u32(value, cap, interface); | 793 | status = AMW0_get_u32(value, cap, interface); |
794 | break; | 794 | break; |
795 | } | 795 | } |
796 | case ACER_WMID: | 796 | case ACER_WMID: |
797 | status = WMID_get_u32(value, cap, interface); | 797 | status = WMID_get_u32(value, cap, interface); |
798 | break; | 798 | break; |
799 | } | 799 | } |
800 | 800 | ||
801 | return status; | 801 | return status; |
802 | } | 802 | } |
803 | 803 | ||
804 | static acpi_status set_u32(u32 value, u32 cap) | 804 | static acpi_status set_u32(u32 value, u32 cap) |
805 | { | 805 | { |
806 | acpi_status status; | 806 | acpi_status status; |
807 | 807 | ||
808 | if (interface->capability & cap) { | 808 | if (interface->capability & cap) { |
809 | switch (interface->type) { | 809 | switch (interface->type) { |
810 | case ACER_AMW0: | 810 | case ACER_AMW0: |
811 | return AMW0_set_u32(value, cap, interface); | 811 | return AMW0_set_u32(value, cap, interface); |
812 | case ACER_AMW0_V2: | 812 | case ACER_AMW0_V2: |
813 | if (cap == ACER_CAP_MAILLED) | 813 | if (cap == ACER_CAP_MAILLED) |
814 | return AMW0_set_u32(value, cap, interface); | 814 | return AMW0_set_u32(value, cap, interface); |
815 | 815 | ||
816 | /* | 816 | /* |
817 | * On some models, some WMID methods don't toggle | 817 | * On some models, some WMID methods don't toggle |
818 | * properly. For those cases, we want to run the AMW0 | 818 | * properly. For those cases, we want to run the AMW0 |
819 | * method afterwards to be certain we've really toggled | 819 | * method afterwards to be certain we've really toggled |
820 | * the device state. | 820 | * the device state. |
821 | */ | 821 | */ |
822 | if (cap == ACER_CAP_WIRELESS || | 822 | if (cap == ACER_CAP_WIRELESS || |
823 | cap == ACER_CAP_BLUETOOTH) { | 823 | cap == ACER_CAP_BLUETOOTH) { |
824 | status = WMID_set_u32(value, cap, interface); | 824 | status = WMID_set_u32(value, cap, interface); |
825 | if (ACPI_FAILURE(status)) | 825 | if (ACPI_FAILURE(status)) |
826 | return status; | 826 | return status; |
827 | 827 | ||
828 | return AMW0_set_u32(value, cap, interface); | 828 | return AMW0_set_u32(value, cap, interface); |
829 | } | 829 | } |
830 | case ACER_WMID: | 830 | case ACER_WMID: |
831 | return WMID_set_u32(value, cap, interface); | 831 | return WMID_set_u32(value, cap, interface); |
832 | default: | 832 | default: |
833 | return AE_BAD_PARAMETER; | 833 | return AE_BAD_PARAMETER; |
834 | } | 834 | } |
835 | } | 835 | } |
836 | return AE_BAD_PARAMETER; | 836 | return AE_BAD_PARAMETER; |
837 | } | 837 | } |
838 | 838 | ||
839 | static void __init acer_commandline_init(void) | 839 | static void __init acer_commandline_init(void) |
840 | { | 840 | { |
841 | /* | 841 | /* |
842 | * These will all fail silently if the value given is invalid, or the | 842 | * These will all fail silently if the value given is invalid, or the |
843 | * capability isn't available on the given interface | 843 | * capability isn't available on the given interface |
844 | */ | 844 | */ |
845 | set_u32(mailled, ACER_CAP_MAILLED); | 845 | set_u32(mailled, ACER_CAP_MAILLED); |
846 | set_u32(threeg, ACER_CAP_THREEG); | 846 | set_u32(threeg, ACER_CAP_THREEG); |
847 | set_u32(brightness, ACER_CAP_BRIGHTNESS); | 847 | set_u32(brightness, ACER_CAP_BRIGHTNESS); |
848 | } | 848 | } |
849 | 849 | ||
850 | /* | 850 | /* |
851 | * LED device (Mail LED only, no other LEDs known yet) | 851 | * LED device (Mail LED only, no other LEDs known yet) |
852 | */ | 852 | */ |
853 | static void mail_led_set(struct led_classdev *led_cdev, | 853 | static void mail_led_set(struct led_classdev *led_cdev, |
854 | enum led_brightness value) | 854 | enum led_brightness value) |
855 | { | 855 | { |
856 | set_u32(value, ACER_CAP_MAILLED); | 856 | set_u32(value, ACER_CAP_MAILLED); |
857 | } | 857 | } |
858 | 858 | ||
859 | static struct led_classdev mail_led = { | 859 | static struct led_classdev mail_led = { |
860 | .name = "acer-wmi::mail", | 860 | .name = "acer-wmi::mail", |
861 | .brightness_set = mail_led_set, | 861 | .brightness_set = mail_led_set, |
862 | }; | 862 | }; |
863 | 863 | ||
864 | static int __devinit acer_led_init(struct device *dev) | 864 | static int __devinit acer_led_init(struct device *dev) |
865 | { | 865 | { |
866 | return led_classdev_register(dev, &mail_led); | 866 | return led_classdev_register(dev, &mail_led); |
867 | } | 867 | } |
868 | 868 | ||
869 | static void acer_led_exit(void) | 869 | static void acer_led_exit(void) |
870 | { | 870 | { |
871 | led_classdev_unregister(&mail_led); | 871 | led_classdev_unregister(&mail_led); |
872 | } | 872 | } |
873 | 873 | ||
874 | /* | 874 | /* |
875 | * Backlight device | 875 | * Backlight device |
876 | */ | 876 | */ |
877 | static struct backlight_device *acer_backlight_device; | 877 | static struct backlight_device *acer_backlight_device; |
878 | 878 | ||
879 | static int read_brightness(struct backlight_device *bd) | 879 | static int read_brightness(struct backlight_device *bd) |
880 | { | 880 | { |
881 | u32 value; | 881 | u32 value; |
882 | get_u32(&value, ACER_CAP_BRIGHTNESS); | 882 | get_u32(&value, ACER_CAP_BRIGHTNESS); |
883 | return value; | 883 | return value; |
884 | } | 884 | } |
885 | 885 | ||
886 | static int update_bl_status(struct backlight_device *bd) | 886 | static int update_bl_status(struct backlight_device *bd) |
887 | { | 887 | { |
888 | int intensity = bd->props.brightness; | 888 | int intensity = bd->props.brightness; |
889 | 889 | ||
890 | if (bd->props.power != FB_BLANK_UNBLANK) | 890 | if (bd->props.power != FB_BLANK_UNBLANK) |
891 | intensity = 0; | 891 | intensity = 0; |
892 | if (bd->props.fb_blank != FB_BLANK_UNBLANK) | 892 | if (bd->props.fb_blank != FB_BLANK_UNBLANK) |
893 | intensity = 0; | 893 | intensity = 0; |
894 | 894 | ||
895 | set_u32(intensity, ACER_CAP_BRIGHTNESS); | 895 | set_u32(intensity, ACER_CAP_BRIGHTNESS); |
896 | 896 | ||
897 | return 0; | 897 | return 0; |
898 | } | 898 | } |
899 | 899 | ||
900 | static struct backlight_ops acer_bl_ops = { | 900 | static struct backlight_ops acer_bl_ops = { |
901 | .get_brightness = read_brightness, | 901 | .get_brightness = read_brightness, |
902 | .update_status = update_bl_status, | 902 | .update_status = update_bl_status, |
903 | }; | 903 | }; |
904 | 904 | ||
905 | static int __devinit acer_backlight_init(struct device *dev) | 905 | static int __devinit acer_backlight_init(struct device *dev) |
906 | { | 906 | { |
907 | struct backlight_device *bd; | 907 | struct backlight_device *bd; |
908 | 908 | ||
909 | bd = backlight_device_register("acer-wmi", dev, NULL, &acer_bl_ops); | 909 | bd = backlight_device_register("acer-wmi", dev, NULL, &acer_bl_ops); |
910 | if (IS_ERR(bd)) { | 910 | if (IS_ERR(bd)) { |
911 | printk(ACER_ERR "Could not register Acer backlight device\n"); | 911 | printk(ACER_ERR "Could not register Acer backlight device\n"); |
912 | acer_backlight_device = NULL; | 912 | acer_backlight_device = NULL; |
913 | return PTR_ERR(bd); | 913 | return PTR_ERR(bd); |
914 | } | 914 | } |
915 | 915 | ||
916 | acer_backlight_device = bd; | 916 | acer_backlight_device = bd; |
917 | 917 | ||
918 | bd->props.power = FB_BLANK_UNBLANK; | 918 | bd->props.power = FB_BLANK_UNBLANK; |
919 | bd->props.brightness = max_brightness; | 919 | bd->props.brightness = max_brightness; |
920 | bd->props.max_brightness = max_brightness; | 920 | bd->props.max_brightness = max_brightness; |
921 | backlight_update_status(bd); | 921 | backlight_update_status(bd); |
922 | return 0; | 922 | return 0; |
923 | } | 923 | } |
924 | 924 | ||
925 | static void acer_backlight_exit(void) | 925 | static void acer_backlight_exit(void) |
926 | { | 926 | { |
927 | backlight_device_unregister(acer_backlight_device); | 927 | backlight_device_unregister(acer_backlight_device); |
928 | } | 928 | } |
929 | 929 | ||
930 | /* | 930 | /* |
931 | * Rfkill devices | 931 | * Rfkill devices |
932 | */ | 932 | */ |
933 | static void acer_rfkill_update(struct work_struct *ignored); | 933 | static void acer_rfkill_update(struct work_struct *ignored); |
934 | static DECLARE_DELAYED_WORK(acer_rfkill_work, acer_rfkill_update); | 934 | static DECLARE_DELAYED_WORK(acer_rfkill_work, acer_rfkill_update); |
935 | static void acer_rfkill_update(struct work_struct *ignored) | 935 | static void acer_rfkill_update(struct work_struct *ignored) |
936 | { | 936 | { |
937 | u32 state; | 937 | u32 state; |
938 | acpi_status status; | 938 | acpi_status status; |
939 | 939 | ||
940 | status = get_u32(&state, ACER_CAP_WIRELESS); | 940 | status = get_u32(&state, ACER_CAP_WIRELESS); |
941 | if (ACPI_SUCCESS(status)) | 941 | if (ACPI_SUCCESS(status)) |
942 | rfkill_force_state(wireless_rfkill, state ? | 942 | rfkill_force_state(wireless_rfkill, state ? |
943 | RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED); | 943 | RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED); |
944 | 944 | ||
945 | if (has_cap(ACER_CAP_BLUETOOTH)) { | 945 | if (has_cap(ACER_CAP_BLUETOOTH)) { |
946 | status = get_u32(&state, ACER_CAP_BLUETOOTH); | 946 | status = get_u32(&state, ACER_CAP_BLUETOOTH); |
947 | if (ACPI_SUCCESS(status)) | 947 | if (ACPI_SUCCESS(status)) |
948 | rfkill_force_state(bluetooth_rfkill, state ? | 948 | rfkill_force_state(bluetooth_rfkill, state ? |
949 | RFKILL_STATE_UNBLOCKED : | 949 | RFKILL_STATE_UNBLOCKED : |
950 | RFKILL_STATE_SOFT_BLOCKED); | 950 | RFKILL_STATE_SOFT_BLOCKED); |
951 | } | 951 | } |
952 | 952 | ||
953 | schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ)); | 953 | schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ)); |
954 | } | 954 | } |
955 | 955 | ||
956 | static int acer_rfkill_set(void *data, enum rfkill_state state) | 956 | static int acer_rfkill_set(void *data, enum rfkill_state state) |
957 | { | 957 | { |
958 | acpi_status status; | 958 | acpi_status status; |
959 | u32 *cap = data; | 959 | u32 *cap = data; |
960 | status = set_u32((u32) (state == RFKILL_STATE_UNBLOCKED), *cap); | 960 | status = set_u32((u32) (state == RFKILL_STATE_UNBLOCKED), *cap); |
961 | if (ACPI_FAILURE(status)) | 961 | if (ACPI_FAILURE(status)) |
962 | return -ENODEV; | 962 | return -ENODEV; |
963 | return 0; | 963 | return 0; |
964 | } | 964 | } |
965 | 965 | ||
966 | static struct rfkill * acer_rfkill_register(struct device *dev, | 966 | static struct rfkill * acer_rfkill_register(struct device *dev, |
967 | enum rfkill_type type, char *name, u32 cap) | 967 | enum rfkill_type type, char *name, u32 cap) |
968 | { | 968 | { |
969 | int err; | 969 | int err; |
970 | u32 state; | 970 | u32 state; |
971 | u32 *data; | 971 | u32 *data; |
972 | struct rfkill *rfkill_dev; | 972 | struct rfkill *rfkill_dev; |
973 | 973 | ||
974 | rfkill_dev = rfkill_allocate(dev, type); | 974 | rfkill_dev = rfkill_allocate(dev, type); |
975 | if (!rfkill_dev) | 975 | if (!rfkill_dev) |
976 | return ERR_PTR(-ENOMEM); | 976 | return ERR_PTR(-ENOMEM); |
977 | rfkill_dev->name = name; | 977 | rfkill_dev->name = name; |
978 | get_u32(&state, cap); | 978 | get_u32(&state, cap); |
979 | rfkill_dev->state = state ? RFKILL_STATE_UNBLOCKED : | 979 | rfkill_dev->state = state ? RFKILL_STATE_UNBLOCKED : |
980 | RFKILL_STATE_SOFT_BLOCKED; | 980 | RFKILL_STATE_SOFT_BLOCKED; |
981 | data = kzalloc(sizeof(u32), GFP_KERNEL); | 981 | data = kzalloc(sizeof(u32), GFP_KERNEL); |
982 | if (!data) { | 982 | if (!data) { |
983 | rfkill_free(rfkill_dev); | 983 | rfkill_free(rfkill_dev); |
984 | return ERR_PTR(-ENOMEM); | 984 | return ERR_PTR(-ENOMEM); |
985 | } | 985 | } |
986 | *data = cap; | 986 | *data = cap; |
987 | rfkill_dev->data = data; | 987 | rfkill_dev->data = data; |
988 | rfkill_dev->toggle_radio = acer_rfkill_set; | 988 | rfkill_dev->toggle_radio = acer_rfkill_set; |
989 | rfkill_dev->user_claim_unsupported = 1; | 989 | rfkill_dev->user_claim_unsupported = 1; |
990 | 990 | ||
991 | err = rfkill_register(rfkill_dev); | 991 | err = rfkill_register(rfkill_dev); |
992 | if (err) { | 992 | if (err) { |
993 | kfree(rfkill_dev->data); | 993 | kfree(rfkill_dev->data); |
994 | rfkill_free(rfkill_dev); | 994 | rfkill_free(rfkill_dev); |
995 | return ERR_PTR(err); | 995 | return ERR_PTR(err); |
996 | } | 996 | } |
997 | return rfkill_dev; | 997 | return rfkill_dev; |
998 | } | 998 | } |
999 | 999 | ||
1000 | static int acer_rfkill_init(struct device *dev) | 1000 | static int acer_rfkill_init(struct device *dev) |
1001 | { | 1001 | { |
1002 | wireless_rfkill = acer_rfkill_register(dev, RFKILL_TYPE_WLAN, | 1002 | wireless_rfkill = acer_rfkill_register(dev, RFKILL_TYPE_WLAN, |
1003 | "acer-wireless", ACER_CAP_WIRELESS); | 1003 | "acer-wireless", ACER_CAP_WIRELESS); |
1004 | if (IS_ERR(wireless_rfkill)) | 1004 | if (IS_ERR(wireless_rfkill)) |
1005 | return PTR_ERR(wireless_rfkill); | 1005 | return PTR_ERR(wireless_rfkill); |
1006 | 1006 | ||
1007 | if (has_cap(ACER_CAP_BLUETOOTH)) { | 1007 | if (has_cap(ACER_CAP_BLUETOOTH)) { |
1008 | bluetooth_rfkill = acer_rfkill_register(dev, | 1008 | bluetooth_rfkill = acer_rfkill_register(dev, |
1009 | RFKILL_TYPE_BLUETOOTH, "acer-bluetooth", | 1009 | RFKILL_TYPE_BLUETOOTH, "acer-bluetooth", |
1010 | ACER_CAP_BLUETOOTH); | 1010 | ACER_CAP_BLUETOOTH); |
1011 | if (IS_ERR(bluetooth_rfkill)) { | 1011 | if (IS_ERR(bluetooth_rfkill)) { |
1012 | kfree(wireless_rfkill->data); | 1012 | kfree(wireless_rfkill->data); |
1013 | rfkill_unregister(wireless_rfkill); | 1013 | rfkill_unregister(wireless_rfkill); |
1014 | return PTR_ERR(bluetooth_rfkill); | 1014 | return PTR_ERR(bluetooth_rfkill); |
1015 | } | 1015 | } |
1016 | } | 1016 | } |
1017 | 1017 | ||
1018 | schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ)); | 1018 | schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ)); |
1019 | 1019 | ||
1020 | return 0; | 1020 | return 0; |
1021 | } | 1021 | } |
1022 | 1022 | ||
1023 | static void acer_rfkill_exit(void) | 1023 | static void acer_rfkill_exit(void) |
1024 | { | 1024 | { |
1025 | cancel_delayed_work_sync(&acer_rfkill_work); | 1025 | cancel_delayed_work_sync(&acer_rfkill_work); |
1026 | kfree(wireless_rfkill->data); | 1026 | kfree(wireless_rfkill->data); |
1027 | rfkill_unregister(wireless_rfkill); | 1027 | rfkill_unregister(wireless_rfkill); |
1028 | if (has_cap(ACER_CAP_BLUETOOTH)) { | 1028 | if (has_cap(ACER_CAP_BLUETOOTH)) { |
1029 | kfree(wireless_rfkill->data); | 1029 | kfree(wireless_rfkill->data); |
1030 | rfkill_unregister(bluetooth_rfkill); | 1030 | rfkill_unregister(bluetooth_rfkill); |
1031 | } | 1031 | } |
1032 | return; | 1032 | return; |
1033 | } | 1033 | } |
1034 | 1034 | ||
1035 | /* | 1035 | /* |
1036 | * sysfs interface | 1036 | * sysfs interface |
1037 | */ | 1037 | */ |
1038 | static ssize_t show_bool_threeg(struct device *dev, | 1038 | static ssize_t show_bool_threeg(struct device *dev, |
1039 | struct device_attribute *attr, char *buf) | 1039 | struct device_attribute *attr, char *buf) |
1040 | { | 1040 | { |
1041 | u32 result; \ | 1041 | u32 result; \ |
1042 | acpi_status status = get_u32(&result, ACER_CAP_THREEG); | 1042 | acpi_status status = get_u32(&result, ACER_CAP_THREEG); |
1043 | if (ACPI_SUCCESS(status)) | 1043 | if (ACPI_SUCCESS(status)) |
1044 | return sprintf(buf, "%u\n", result); | 1044 | return sprintf(buf, "%u\n", result); |
1045 | return sprintf(buf, "Read error\n"); | 1045 | return sprintf(buf, "Read error\n"); |
1046 | } | 1046 | } |
1047 | 1047 | ||
1048 | static ssize_t set_bool_threeg(struct device *dev, | 1048 | static ssize_t set_bool_threeg(struct device *dev, |
1049 | struct device_attribute *attr, const char *buf, size_t count) | 1049 | struct device_attribute *attr, const char *buf, size_t count) |
1050 | { | 1050 | { |
1051 | u32 tmp = simple_strtoul(buf, NULL, 10); | 1051 | u32 tmp = simple_strtoul(buf, NULL, 10); |
1052 | acpi_status status = set_u32(tmp, ACER_CAP_THREEG); | 1052 | acpi_status status = set_u32(tmp, ACER_CAP_THREEG); |
1053 | if (ACPI_FAILURE(status)) | 1053 | if (ACPI_FAILURE(status)) |
1054 | return -EINVAL; | 1054 | return -EINVAL; |
1055 | return count; | 1055 | return count; |
1056 | } | 1056 | } |
1057 | static DEVICE_ATTR(threeg, S_IWUGO | S_IRUGO | S_IWUSR, show_bool_threeg, | 1057 | static DEVICE_ATTR(threeg, S_IWUGO | S_IRUGO | S_IWUSR, show_bool_threeg, |
1058 | set_bool_threeg); | 1058 | set_bool_threeg); |
1059 | 1059 | ||
1060 | static ssize_t show_interface(struct device *dev, struct device_attribute *attr, | 1060 | static ssize_t show_interface(struct device *dev, struct device_attribute *attr, |
1061 | char *buf) | 1061 | char *buf) |
1062 | { | 1062 | { |
1063 | switch (interface->type) { | 1063 | switch (interface->type) { |
1064 | case ACER_AMW0: | 1064 | case ACER_AMW0: |
1065 | return sprintf(buf, "AMW0\n"); | 1065 | return sprintf(buf, "AMW0\n"); |
1066 | case ACER_AMW0_V2: | 1066 | case ACER_AMW0_V2: |
1067 | return sprintf(buf, "AMW0 v2\n"); | 1067 | return sprintf(buf, "AMW0 v2\n"); |
1068 | case ACER_WMID: | 1068 | case ACER_WMID: |
1069 | return sprintf(buf, "WMID\n"); | 1069 | return sprintf(buf, "WMID\n"); |
1070 | default: | 1070 | default: |
1071 | return sprintf(buf, "Error!\n"); | 1071 | return sprintf(buf, "Error!\n"); |
1072 | } | 1072 | } |
1073 | } | 1073 | } |
1074 | 1074 | ||
1075 | static DEVICE_ATTR(interface, S_IWUGO | S_IRUGO | S_IWUSR, | 1075 | static DEVICE_ATTR(interface, S_IWUGO | S_IRUGO | S_IWUSR, |
1076 | show_interface, NULL); | 1076 | show_interface, NULL); |
1077 | 1077 | ||
1078 | /* | 1078 | /* |
1079 | * debugfs functions | 1079 | * debugfs functions |
1080 | */ | 1080 | */ |
1081 | static u32 get_wmid_devices(void) | 1081 | static u32 get_wmid_devices(void) |
1082 | { | 1082 | { |
1083 | struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL}; | 1083 | struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL}; |
1084 | union acpi_object *obj; | 1084 | union acpi_object *obj; |
1085 | acpi_status status; | 1085 | acpi_status status; |
1086 | 1086 | ||
1087 | status = wmi_query_block(WMID_GUID2, 1, &out); | 1087 | status = wmi_query_block(WMID_GUID2, 1, &out); |
1088 | if (ACPI_FAILURE(status)) | 1088 | if (ACPI_FAILURE(status)) |
1089 | return 0; | 1089 | return 0; |
1090 | 1090 | ||
1091 | obj = (union acpi_object *) out.pointer; | 1091 | obj = (union acpi_object *) out.pointer; |
1092 | if (obj && obj->type == ACPI_TYPE_BUFFER && | 1092 | if (obj && obj->type == ACPI_TYPE_BUFFER && |
1093 | obj->buffer.length == sizeof(u32)) { | 1093 | obj->buffer.length == sizeof(u32)) { |
1094 | return *((u32 *) obj->buffer.pointer); | 1094 | return *((u32 *) obj->buffer.pointer); |
1095 | } else { | 1095 | } else { |
1096 | return 0; | 1096 | return 0; |
1097 | } | 1097 | } |
1098 | } | 1098 | } |
1099 | 1099 | ||
1100 | /* | 1100 | /* |
1101 | * Platform device | 1101 | * Platform device |
1102 | */ | 1102 | */ |
1103 | static int __devinit acer_platform_probe(struct platform_device *device) | 1103 | static int __devinit acer_platform_probe(struct platform_device *device) |
1104 | { | 1104 | { |
1105 | int err; | 1105 | int err; |
1106 | 1106 | ||
1107 | if (has_cap(ACER_CAP_MAILLED)) { | 1107 | if (has_cap(ACER_CAP_MAILLED)) { |
1108 | err = acer_led_init(&device->dev); | 1108 | err = acer_led_init(&device->dev); |
1109 | if (err) | 1109 | if (err) |
1110 | goto error_mailled; | 1110 | goto error_mailled; |
1111 | } | 1111 | } |
1112 | 1112 | ||
1113 | if (has_cap(ACER_CAP_BRIGHTNESS)) { | 1113 | if (has_cap(ACER_CAP_BRIGHTNESS)) { |
1114 | err = acer_backlight_init(&device->dev); | 1114 | err = acer_backlight_init(&device->dev); |
1115 | if (err) | 1115 | if (err) |
1116 | goto error_brightness; | 1116 | goto error_brightness; |
1117 | } | 1117 | } |
1118 | 1118 | ||
1119 | err = acer_rfkill_init(&device->dev); | 1119 | err = acer_rfkill_init(&device->dev); |
1120 | 1120 | ||
1121 | return err; | 1121 | return err; |
1122 | 1122 | ||
1123 | error_brightness: | 1123 | error_brightness: |
1124 | acer_led_exit(); | 1124 | acer_led_exit(); |
1125 | error_mailled: | 1125 | error_mailled: |
1126 | return err; | 1126 | return err; |
1127 | } | 1127 | } |
1128 | 1128 | ||
1129 | static int acer_platform_remove(struct platform_device *device) | 1129 | static int acer_platform_remove(struct platform_device *device) |
1130 | { | 1130 | { |
1131 | if (has_cap(ACER_CAP_MAILLED)) | 1131 | if (has_cap(ACER_CAP_MAILLED)) |
1132 | acer_led_exit(); | 1132 | acer_led_exit(); |
1133 | if (has_cap(ACER_CAP_BRIGHTNESS)) | 1133 | if (has_cap(ACER_CAP_BRIGHTNESS)) |
1134 | acer_backlight_exit(); | 1134 | acer_backlight_exit(); |
1135 | 1135 | ||
1136 | acer_rfkill_exit(); | 1136 | acer_rfkill_exit(); |
1137 | return 0; | 1137 | return 0; |
1138 | } | 1138 | } |
1139 | 1139 | ||
1140 | static int acer_platform_suspend(struct platform_device *dev, | 1140 | static int acer_platform_suspend(struct platform_device *dev, |
1141 | pm_message_t state) | 1141 | pm_message_t state) |
1142 | { | 1142 | { |
1143 | u32 value; | 1143 | u32 value; |
1144 | struct acer_data *data = &interface->data; | 1144 | struct acer_data *data = &interface->data; |
1145 | 1145 | ||
1146 | if (!data) | 1146 | if (!data) |
1147 | return -ENOMEM; | 1147 | return -ENOMEM; |
1148 | 1148 | ||
1149 | if (has_cap(ACER_CAP_MAILLED)) { | 1149 | if (has_cap(ACER_CAP_MAILLED)) { |
1150 | get_u32(&value, ACER_CAP_MAILLED); | 1150 | get_u32(&value, ACER_CAP_MAILLED); |
1151 | data->mailled = value; | 1151 | data->mailled = value; |
1152 | } | 1152 | } |
1153 | 1153 | ||
1154 | if (has_cap(ACER_CAP_BRIGHTNESS)) { | 1154 | if (has_cap(ACER_CAP_BRIGHTNESS)) { |
1155 | get_u32(&value, ACER_CAP_BRIGHTNESS); | 1155 | get_u32(&value, ACER_CAP_BRIGHTNESS); |
1156 | data->brightness = value; | 1156 | data->brightness = value; |
1157 | } | 1157 | } |
1158 | 1158 | ||
1159 | return 0; | 1159 | return 0; |
1160 | } | 1160 | } |
1161 | 1161 | ||
1162 | static int acer_platform_resume(struct platform_device *device) | 1162 | static int acer_platform_resume(struct platform_device *device) |
1163 | { | 1163 | { |
1164 | struct acer_data *data = &interface->data; | 1164 | struct acer_data *data = &interface->data; |
1165 | 1165 | ||
1166 | if (!data) | 1166 | if (!data) |
1167 | return -ENOMEM; | 1167 | return -ENOMEM; |
1168 | 1168 | ||
1169 | if (has_cap(ACER_CAP_MAILLED)) | 1169 | if (has_cap(ACER_CAP_MAILLED)) |
1170 | set_u32(data->mailled, ACER_CAP_MAILLED); | 1170 | set_u32(data->mailled, ACER_CAP_MAILLED); |
1171 | 1171 | ||
1172 | if (has_cap(ACER_CAP_BRIGHTNESS)) | 1172 | if (has_cap(ACER_CAP_BRIGHTNESS)) |
1173 | set_u32(data->brightness, ACER_CAP_BRIGHTNESS); | 1173 | set_u32(data->brightness, ACER_CAP_BRIGHTNESS); |
1174 | 1174 | ||
1175 | return 0; | 1175 | return 0; |
1176 | } | 1176 | } |
1177 | 1177 | ||
1178 | static struct platform_driver acer_platform_driver = { | 1178 | static struct platform_driver acer_platform_driver = { |
1179 | .driver = { | 1179 | .driver = { |
1180 | .name = "acer-wmi", | 1180 | .name = "acer-wmi", |
1181 | .owner = THIS_MODULE, | 1181 | .owner = THIS_MODULE, |
1182 | }, | 1182 | }, |
1183 | .probe = acer_platform_probe, | 1183 | .probe = acer_platform_probe, |
1184 | .remove = acer_platform_remove, | 1184 | .remove = acer_platform_remove, |
1185 | .suspend = acer_platform_suspend, | 1185 | .suspend = acer_platform_suspend, |
1186 | .resume = acer_platform_resume, | 1186 | .resume = acer_platform_resume, |
1187 | }; | 1187 | }; |
1188 | 1188 | ||
1189 | static struct platform_device *acer_platform_device; | 1189 | static struct platform_device *acer_platform_device; |
1190 | 1190 | ||
1191 | static int remove_sysfs(struct platform_device *device) | 1191 | static int remove_sysfs(struct platform_device *device) |
1192 | { | 1192 | { |
1193 | if (has_cap(ACER_CAP_THREEG)) | 1193 | if (has_cap(ACER_CAP_THREEG)) |
1194 | device_remove_file(&device->dev, &dev_attr_threeg); | 1194 | device_remove_file(&device->dev, &dev_attr_threeg); |
1195 | 1195 | ||
1196 | device_remove_file(&device->dev, &dev_attr_interface); | 1196 | device_remove_file(&device->dev, &dev_attr_interface); |
1197 | 1197 | ||
1198 | return 0; | 1198 | return 0; |
1199 | } | 1199 | } |
1200 | 1200 | ||
1201 | static int create_sysfs(void) | 1201 | static int create_sysfs(void) |
1202 | { | 1202 | { |
1203 | int retval = -ENOMEM; | 1203 | int retval = -ENOMEM; |
1204 | 1204 | ||
1205 | if (has_cap(ACER_CAP_THREEG)) { | 1205 | if (has_cap(ACER_CAP_THREEG)) { |
1206 | retval = device_create_file(&acer_platform_device->dev, | 1206 | retval = device_create_file(&acer_platform_device->dev, |
1207 | &dev_attr_threeg); | 1207 | &dev_attr_threeg); |
1208 | if (retval) | 1208 | if (retval) |
1209 | goto error_sysfs; | 1209 | goto error_sysfs; |
1210 | } | 1210 | } |
1211 | 1211 | ||
1212 | retval = device_create_file(&acer_platform_device->dev, | 1212 | retval = device_create_file(&acer_platform_device->dev, |
1213 | &dev_attr_interface); | 1213 | &dev_attr_interface); |
1214 | if (retval) | 1214 | if (retval) |
1215 | goto error_sysfs; | 1215 | goto error_sysfs; |
1216 | 1216 | ||
1217 | return 0; | 1217 | return 0; |
1218 | 1218 | ||
1219 | error_sysfs: | 1219 | error_sysfs: |
1220 | remove_sysfs(acer_platform_device); | 1220 | remove_sysfs(acer_platform_device); |
1221 | return retval; | 1221 | return retval; |
1222 | } | 1222 | } |
1223 | 1223 | ||
1224 | static void remove_debugfs(void) | 1224 | static void remove_debugfs(void) |
1225 | { | 1225 | { |
1226 | debugfs_remove(interface->debug.devices); | 1226 | debugfs_remove(interface->debug.devices); |
1227 | debugfs_remove(interface->debug.root); | 1227 | debugfs_remove(interface->debug.root); |
1228 | } | 1228 | } |
1229 | 1229 | ||
1230 | static int create_debugfs(void) | 1230 | static int create_debugfs(void) |
1231 | { | 1231 | { |
1232 | interface->debug.root = debugfs_create_dir("acer-wmi", NULL); | 1232 | interface->debug.root = debugfs_create_dir("acer-wmi", NULL); |
1233 | if (!interface->debug.root) { | 1233 | if (!interface->debug.root) { |
1234 | printk(ACER_ERR "Failed to create debugfs directory"); | 1234 | printk(ACER_ERR "Failed to create debugfs directory"); |
1235 | return -ENOMEM; | 1235 | return -ENOMEM; |
1236 | } | 1236 | } |
1237 | 1237 | ||
1238 | interface->debug.devices = debugfs_create_u32("devices", S_IRUGO, | 1238 | interface->debug.devices = debugfs_create_u32("devices", S_IRUGO, |
1239 | interface->debug.root, | 1239 | interface->debug.root, |
1240 | &interface->debug.wmid_devices); | 1240 | &interface->debug.wmid_devices); |
1241 | if (!interface->debug.devices) | 1241 | if (!interface->debug.devices) |
1242 | goto error_debugfs; | 1242 | goto error_debugfs; |
1243 | 1243 | ||
1244 | return 0; | 1244 | return 0; |
1245 | 1245 | ||
1246 | error_debugfs: | 1246 | error_debugfs: |
1247 | remove_debugfs(); | 1247 | remove_debugfs(); |
1248 | return -ENOMEM; | 1248 | return -ENOMEM; |
1249 | } | 1249 | } |
1250 | 1250 | ||
1251 | static int __init acer_wmi_init(void) | 1251 | static int __init acer_wmi_init(void) |
1252 | { | 1252 | { |
1253 | int err; | 1253 | int err; |
1254 | 1254 | ||
1255 | printk(ACER_INFO "Acer Laptop ACPI-WMI Extras\n"); | 1255 | printk(ACER_INFO "Acer Laptop ACPI-WMI Extras\n"); |
1256 | 1256 | ||
1257 | find_quirks(); | 1257 | find_quirks(); |
1258 | 1258 | ||
1259 | /* | 1259 | /* |
1260 | * Detect which ACPI-WMI interface we're using. | 1260 | * Detect which ACPI-WMI interface we're using. |
1261 | */ | 1261 | */ |
1262 | if (wmi_has_guid(AMW0_GUID1) && wmi_has_guid(WMID_GUID1)) | 1262 | if (wmi_has_guid(AMW0_GUID1) && wmi_has_guid(WMID_GUID1)) |
1263 | interface = &AMW0_V2_interface; | 1263 | interface = &AMW0_V2_interface; |
1264 | 1264 | ||
1265 | if (!wmi_has_guid(AMW0_GUID1) && wmi_has_guid(WMID_GUID1)) | 1265 | if (!wmi_has_guid(AMW0_GUID1) && wmi_has_guid(WMID_GUID1)) |
1266 | interface = &wmid_interface; | 1266 | interface = &wmid_interface; |
1267 | 1267 | ||
1268 | if (wmi_has_guid(WMID_GUID2) && interface) { | 1268 | if (wmi_has_guid(WMID_GUID2) && interface) { |
1269 | if (ACPI_FAILURE(WMID_set_capabilities())) { | 1269 | if (ACPI_FAILURE(WMID_set_capabilities())) { |
1270 | printk(ACER_ERR "Unable to detect available WMID " | 1270 | printk(ACER_ERR "Unable to detect available WMID " |
1271 | "devices\n"); | 1271 | "devices\n"); |
1272 | return -ENODEV; | 1272 | return -ENODEV; |
1273 | } | 1273 | } |
1274 | } else if (!wmi_has_guid(WMID_GUID2) && interface) { | 1274 | } else if (!wmi_has_guid(WMID_GUID2) && interface) { |
1275 | printk(ACER_ERR "No WMID device detection method found\n"); | 1275 | printk(ACER_ERR "No WMID device detection method found\n"); |
1276 | return -ENODEV; | 1276 | return -ENODEV; |
1277 | } | 1277 | } |
1278 | 1278 | ||
1279 | if (wmi_has_guid(AMW0_GUID1) && !wmi_has_guid(WMID_GUID1)) { | 1279 | if (wmi_has_guid(AMW0_GUID1) && !wmi_has_guid(WMID_GUID1)) { |
1280 | interface = &AMW0_interface; | 1280 | interface = &AMW0_interface; |
1281 | 1281 | ||
1282 | if (ACPI_FAILURE(AMW0_set_capabilities())) { | 1282 | if (ACPI_FAILURE(AMW0_set_capabilities())) { |
1283 | printk(ACER_ERR "Unable to detect available AMW0 " | 1283 | printk(ACER_ERR "Unable to detect available AMW0 " |
1284 | "devices\n"); | 1284 | "devices\n"); |
1285 | return -ENODEV; | 1285 | return -ENODEV; |
1286 | } | 1286 | } |
1287 | } | 1287 | } |
1288 | 1288 | ||
1289 | if (wmi_has_guid(AMW0_GUID1)) | 1289 | if (wmi_has_guid(AMW0_GUID1)) |
1290 | AMW0_find_mailled(); | 1290 | AMW0_find_mailled(); |
1291 | 1291 | ||
1292 | if (!interface) { | 1292 | if (!interface) { |
1293 | printk(ACER_ERR "No or unsupported WMI interface, unable to " | 1293 | printk(ACER_ERR "No or unsupported WMI interface, unable to " |
1294 | "load\n"); | 1294 | "load\n"); |
1295 | return -ENODEV; | 1295 | return -ENODEV; |
1296 | } | 1296 | } |
1297 | 1297 | ||
1298 | set_quirks(); | 1298 | set_quirks(); |
1299 | 1299 | ||
1300 | if (!acpi_video_backlight_support() && has_cap(ACER_CAP_BRIGHTNESS)) { | ||
1301 | interface->capability &= ~ACER_CAP_BRIGHTNESS; | ||
1302 | printk(ACER_INFO "Brightness must be controlled by " | ||
1303 | "generic video driver\n"); | ||
1304 | } | ||
1305 | |||
1300 | if (platform_driver_register(&acer_platform_driver)) { | 1306 | if (platform_driver_register(&acer_platform_driver)) { |
1301 | printk(ACER_ERR "Unable to register platform driver.\n"); | 1307 | printk(ACER_ERR "Unable to register platform driver.\n"); |
1302 | goto error_platform_register; | 1308 | goto error_platform_register; |
1303 | } | 1309 | } |
1304 | acer_platform_device = platform_device_alloc("acer-wmi", -1); | 1310 | acer_platform_device = platform_device_alloc("acer-wmi", -1); |
1305 | platform_device_add(acer_platform_device); | 1311 | platform_device_add(acer_platform_device); |
1306 | 1312 | ||
1307 | err = create_sysfs(); | 1313 | err = create_sysfs(); |
1308 | if (err) | 1314 | if (err) |
1309 | return err; | 1315 | return err; |
1310 | 1316 | ||
1311 | if (wmi_has_guid(WMID_GUID2)) { | 1317 | if (wmi_has_guid(WMID_GUID2)) { |
1312 | interface->debug.wmid_devices = get_wmid_devices(); | 1318 | interface->debug.wmid_devices = get_wmid_devices(); |
1313 | err = create_debugfs(); | 1319 | err = create_debugfs(); |
1314 | if (err) | 1320 | if (err) |
1315 | return err; | 1321 | return err; |
1316 | } | 1322 | } |
1317 | 1323 | ||
1318 | /* Override any initial settings with values from the commandline */ | 1324 | /* Override any initial settings with values from the commandline */ |
1319 | acer_commandline_init(); | 1325 | acer_commandline_init(); |
1320 | 1326 | ||
1321 | return 0; | 1327 | return 0; |
1322 | 1328 | ||
1323 | error_platform_register: | 1329 | error_platform_register: |
1324 | return -ENODEV; | 1330 | return -ENODEV; |
1325 | } | 1331 | } |
1326 | 1332 | ||
1327 | static void __exit acer_wmi_exit(void) | 1333 | static void __exit acer_wmi_exit(void) |
1328 | { | 1334 | { |
1329 | remove_sysfs(acer_platform_device); | 1335 | remove_sysfs(acer_platform_device); |
1330 | remove_debugfs(); | 1336 | remove_debugfs(); |
1331 | platform_device_del(acer_platform_device); | 1337 | platform_device_del(acer_platform_device); |
1332 | platform_driver_unregister(&acer_platform_driver); | 1338 | platform_driver_unregister(&acer_platform_driver); |
1333 | 1339 | ||
1334 | printk(ACER_INFO "Acer Laptop WMI Extras unloaded\n"); | 1340 | printk(ACER_INFO "Acer Laptop WMI Extras unloaded\n"); |
1335 | return; | 1341 | return; |
1336 | } | 1342 | } |
1337 | 1343 | ||
1338 | module_init(acer_wmi_init); | 1344 | module_init(acer_wmi_init); |
1339 | module_exit(acer_wmi_exit); | 1345 | module_exit(acer_wmi_exit); |
1340 | 1346 |
drivers/misc/asus-laptop.c
1 | /* | 1 | /* |
2 | * asus-laptop.c - Asus Laptop Support | 2 | * asus-laptop.c - Asus Laptop Support |
3 | * | 3 | * |
4 | * | 4 | * |
5 | * Copyright (C) 2002-2005 Julien Lerouge, 2003-2006 Karol Kozimor | 5 | * Copyright (C) 2002-2005 Julien Lerouge, 2003-2006 Karol Kozimor |
6 | * Copyright (C) 2006-2007 Corentin Chary | 6 | * Copyright (C) 2006-2007 Corentin Chary |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify | 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 | 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 | 10 | * the Free Software Foundation; either version 2 of the License, or |
11 | * (at your option) any later version. | 11 | * (at your option) any later version. |
12 | * | 12 | * |
13 | * This program is distributed in the hope that it will be useful, | 13 | * This program is distributed in the hope that it will be useful, |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | * GNU General Public License for more details. | 16 | * GNU General Public License for more details. |
17 | * | 17 | * |
18 | * You should have received a copy of the GNU General Public License | 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 | 19 | * along with this program; if not, write to the Free Software |
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 | * The development page for this driver is located at | 23 | * The development page for this driver is located at |
24 | * http://sourceforge.net/projects/acpi4asus/ | 24 | * http://sourceforge.net/projects/acpi4asus/ |
25 | * | 25 | * |
26 | * Credits: | 26 | * Credits: |
27 | * Pontus Fuchs - Helper functions, cleanup | 27 | * Pontus Fuchs - Helper functions, cleanup |
28 | * Johann Wiesner - Small compile fixes | 28 | * Johann Wiesner - Small compile fixes |
29 | * John Belmonte - ACPI code for Toshiba laptop was a good starting point. | 29 | * John Belmonte - ACPI code for Toshiba laptop was a good starting point. |
30 | * Eric Burghard - LED display support for W1N | 30 | * Eric Burghard - LED display support for W1N |
31 | * Josh Green - Light Sens support | 31 | * Josh Green - Light Sens support |
32 | * Thomas Tuttle - His first patch for led support was very helpfull | 32 | * Thomas Tuttle - His first patch for led support was very helpfull |
33 | * Sam Lin - GPS support | 33 | * Sam Lin - GPS support |
34 | */ | 34 | */ |
35 | 35 | ||
36 | #include <linux/kernel.h> | 36 | #include <linux/kernel.h> |
37 | #include <linux/module.h> | 37 | #include <linux/module.h> |
38 | #include <linux/init.h> | 38 | #include <linux/init.h> |
39 | #include <linux/types.h> | 39 | #include <linux/types.h> |
40 | #include <linux/err.h> | 40 | #include <linux/err.h> |
41 | #include <linux/proc_fs.h> | 41 | #include <linux/proc_fs.h> |
42 | #include <linux/backlight.h> | 42 | #include <linux/backlight.h> |
43 | #include <linux/fb.h> | 43 | #include <linux/fb.h> |
44 | #include <linux/leds.h> | 44 | #include <linux/leds.h> |
45 | #include <linux/platform_device.h> | 45 | #include <linux/platform_device.h> |
46 | #include <acpi/acpi_drivers.h> | 46 | #include <acpi/acpi_drivers.h> |
47 | #include <acpi/acpi_bus.h> | 47 | #include <acpi/acpi_bus.h> |
48 | #include <asm/uaccess.h> | 48 | #include <asm/uaccess.h> |
49 | 49 | ||
50 | #define ASUS_LAPTOP_VERSION "0.42" | 50 | #define ASUS_LAPTOP_VERSION "0.42" |
51 | 51 | ||
52 | #define ASUS_HOTK_NAME "Asus Laptop Support" | 52 | #define ASUS_HOTK_NAME "Asus Laptop Support" |
53 | #define ASUS_HOTK_CLASS "hotkey" | 53 | #define ASUS_HOTK_CLASS "hotkey" |
54 | #define ASUS_HOTK_DEVICE_NAME "Hotkey" | 54 | #define ASUS_HOTK_DEVICE_NAME "Hotkey" |
55 | #define ASUS_HOTK_FILE "asus-laptop" | 55 | #define ASUS_HOTK_FILE "asus-laptop" |
56 | #define ASUS_HOTK_PREFIX "\\_SB.ATKD." | 56 | #define ASUS_HOTK_PREFIX "\\_SB.ATKD." |
57 | 57 | ||
58 | /* | 58 | /* |
59 | * Some events we use, same for all Asus | 59 | * Some events we use, same for all Asus |
60 | */ | 60 | */ |
61 | #define ATKD_BR_UP 0x10 | 61 | #define ATKD_BR_UP 0x10 |
62 | #define ATKD_BR_DOWN 0x20 | 62 | #define ATKD_BR_DOWN 0x20 |
63 | #define ATKD_LCD_ON 0x33 | 63 | #define ATKD_LCD_ON 0x33 |
64 | #define ATKD_LCD_OFF 0x34 | 64 | #define ATKD_LCD_OFF 0x34 |
65 | 65 | ||
66 | /* | 66 | /* |
67 | * Known bits returned by \_SB.ATKD.HWRS | 67 | * Known bits returned by \_SB.ATKD.HWRS |
68 | */ | 68 | */ |
69 | #define WL_HWRS 0x80 | 69 | #define WL_HWRS 0x80 |
70 | #define BT_HWRS 0x100 | 70 | #define BT_HWRS 0x100 |
71 | 71 | ||
72 | /* | 72 | /* |
73 | * Flags for hotk status | 73 | * Flags for hotk status |
74 | * WL_ON and BT_ON are also used for wireless_status() | 74 | * WL_ON and BT_ON are also used for wireless_status() |
75 | */ | 75 | */ |
76 | #define WL_ON 0x01 //internal Wifi | 76 | #define WL_ON 0x01 //internal Wifi |
77 | #define BT_ON 0x02 //internal Bluetooth | 77 | #define BT_ON 0x02 //internal Bluetooth |
78 | #define MLED_ON 0x04 //mail LED | 78 | #define MLED_ON 0x04 //mail LED |
79 | #define TLED_ON 0x08 //touchpad LED | 79 | #define TLED_ON 0x08 //touchpad LED |
80 | #define RLED_ON 0x10 //Record LED | 80 | #define RLED_ON 0x10 //Record LED |
81 | #define PLED_ON 0x20 //Phone LED | 81 | #define PLED_ON 0x20 //Phone LED |
82 | #define GLED_ON 0x40 //Gaming LED | 82 | #define GLED_ON 0x40 //Gaming LED |
83 | #define LCD_ON 0x80 //LCD backlight | 83 | #define LCD_ON 0x80 //LCD backlight |
84 | #define GPS_ON 0x100 //GPS | 84 | #define GPS_ON 0x100 //GPS |
85 | 85 | ||
86 | #define ASUS_LOG ASUS_HOTK_FILE ": " | 86 | #define ASUS_LOG ASUS_HOTK_FILE ": " |
87 | #define ASUS_ERR KERN_ERR ASUS_LOG | 87 | #define ASUS_ERR KERN_ERR ASUS_LOG |
88 | #define ASUS_WARNING KERN_WARNING ASUS_LOG | 88 | #define ASUS_WARNING KERN_WARNING ASUS_LOG |
89 | #define ASUS_NOTICE KERN_NOTICE ASUS_LOG | 89 | #define ASUS_NOTICE KERN_NOTICE ASUS_LOG |
90 | #define ASUS_INFO KERN_INFO ASUS_LOG | 90 | #define ASUS_INFO KERN_INFO ASUS_LOG |
91 | #define ASUS_DEBUG KERN_DEBUG ASUS_LOG | 91 | #define ASUS_DEBUG KERN_DEBUG ASUS_LOG |
92 | 92 | ||
93 | MODULE_AUTHOR("Julien Lerouge, Karol Kozimor, Corentin Chary"); | 93 | MODULE_AUTHOR("Julien Lerouge, Karol Kozimor, Corentin Chary"); |
94 | MODULE_DESCRIPTION(ASUS_HOTK_NAME); | 94 | MODULE_DESCRIPTION(ASUS_HOTK_NAME); |
95 | MODULE_LICENSE("GPL"); | 95 | MODULE_LICENSE("GPL"); |
96 | 96 | ||
97 | /* WAPF defines the behavior of the Fn+Fx wlan key | 97 | /* WAPF defines the behavior of the Fn+Fx wlan key |
98 | * The significance of values is yet to be found, but | 98 | * The significance of values is yet to be found, but |
99 | * most of the time: | 99 | * most of the time: |
100 | * 0x0 will do nothing | 100 | * 0x0 will do nothing |
101 | * 0x1 will allow to control the device with Fn+Fx key. | 101 | * 0x1 will allow to control the device with Fn+Fx key. |
102 | * 0x4 will send an ACPI event (0x88) while pressing the Fn+Fx key | 102 | * 0x4 will send an ACPI event (0x88) while pressing the Fn+Fx key |
103 | * 0x5 like 0x1 or 0x4 | 103 | * 0x5 like 0x1 or 0x4 |
104 | * So, if something doesn't work as you want, just try other values =) | 104 | * So, if something doesn't work as you want, just try other values =) |
105 | */ | 105 | */ |
106 | static uint wapf = 1; | 106 | static uint wapf = 1; |
107 | module_param(wapf, uint, 0644); | 107 | module_param(wapf, uint, 0644); |
108 | MODULE_PARM_DESC(wapf, "WAPF value"); | 108 | MODULE_PARM_DESC(wapf, "WAPF value"); |
109 | 109 | ||
110 | #define ASUS_HANDLE(object, paths...) \ | 110 | #define ASUS_HANDLE(object, paths...) \ |
111 | static acpi_handle object##_handle = NULL; \ | 111 | static acpi_handle object##_handle = NULL; \ |
112 | static char *object##_paths[] = { paths } | 112 | static char *object##_paths[] = { paths } |
113 | 113 | ||
114 | /* LED */ | 114 | /* LED */ |
115 | ASUS_HANDLE(mled_set, ASUS_HOTK_PREFIX "MLED"); | 115 | ASUS_HANDLE(mled_set, ASUS_HOTK_PREFIX "MLED"); |
116 | ASUS_HANDLE(tled_set, ASUS_HOTK_PREFIX "TLED"); | 116 | ASUS_HANDLE(tled_set, ASUS_HOTK_PREFIX "TLED"); |
117 | ASUS_HANDLE(rled_set, ASUS_HOTK_PREFIX "RLED"); /* W1JC */ | 117 | ASUS_HANDLE(rled_set, ASUS_HOTK_PREFIX "RLED"); /* W1JC */ |
118 | ASUS_HANDLE(pled_set, ASUS_HOTK_PREFIX "PLED"); /* A7J */ | 118 | ASUS_HANDLE(pled_set, ASUS_HOTK_PREFIX "PLED"); /* A7J */ |
119 | ASUS_HANDLE(gled_set, ASUS_HOTK_PREFIX "GLED"); /* G1, G2 (probably) */ | 119 | ASUS_HANDLE(gled_set, ASUS_HOTK_PREFIX "GLED"); /* G1, G2 (probably) */ |
120 | 120 | ||
121 | /* LEDD */ | 121 | /* LEDD */ |
122 | ASUS_HANDLE(ledd_set, ASUS_HOTK_PREFIX "SLCM"); | 122 | ASUS_HANDLE(ledd_set, ASUS_HOTK_PREFIX "SLCM"); |
123 | 123 | ||
124 | /* Bluetooth and WLAN | 124 | /* Bluetooth and WLAN |
125 | * WLED and BLED are not handled like other XLED, because in some dsdt | 125 | * WLED and BLED are not handled like other XLED, because in some dsdt |
126 | * they also control the WLAN/Bluetooth device. | 126 | * they also control the WLAN/Bluetooth device. |
127 | */ | 127 | */ |
128 | ASUS_HANDLE(wl_switch, ASUS_HOTK_PREFIX "WLED"); | 128 | ASUS_HANDLE(wl_switch, ASUS_HOTK_PREFIX "WLED"); |
129 | ASUS_HANDLE(bt_switch, ASUS_HOTK_PREFIX "BLED"); | 129 | ASUS_HANDLE(bt_switch, ASUS_HOTK_PREFIX "BLED"); |
130 | ASUS_HANDLE(wireless_status, ASUS_HOTK_PREFIX "RSTS"); /* All new models */ | 130 | ASUS_HANDLE(wireless_status, ASUS_HOTK_PREFIX "RSTS"); /* All new models */ |
131 | 131 | ||
132 | /* Brightness */ | 132 | /* Brightness */ |
133 | ASUS_HANDLE(brightness_set, ASUS_HOTK_PREFIX "SPLV"); | 133 | ASUS_HANDLE(brightness_set, ASUS_HOTK_PREFIX "SPLV"); |
134 | ASUS_HANDLE(brightness_get, ASUS_HOTK_PREFIX "GPLV"); | 134 | ASUS_HANDLE(brightness_get, ASUS_HOTK_PREFIX "GPLV"); |
135 | 135 | ||
136 | /* Backlight */ | 136 | /* Backlight */ |
137 | ASUS_HANDLE(lcd_switch, "\\_SB.PCI0.SBRG.EC0._Q10", /* All new models */ | 137 | ASUS_HANDLE(lcd_switch, "\\_SB.PCI0.SBRG.EC0._Q10", /* All new models */ |
138 | "\\_SB.PCI0.ISA.EC0._Q10", /* A1x */ | 138 | "\\_SB.PCI0.ISA.EC0._Q10", /* A1x */ |
139 | "\\_SB.PCI0.PX40.ECD0._Q10", /* L3C */ | 139 | "\\_SB.PCI0.PX40.ECD0._Q10", /* L3C */ |
140 | "\\_SB.PCI0.PX40.EC0.Q10", /* M1A */ | 140 | "\\_SB.PCI0.PX40.EC0.Q10", /* M1A */ |
141 | "\\_SB.PCI0.LPCB.EC0._Q10", /* P30 */ | 141 | "\\_SB.PCI0.LPCB.EC0._Q10", /* P30 */ |
142 | "\\_SB.PCI0.LPCB.EC0._Q0E", /* P30/P35 */ | 142 | "\\_SB.PCI0.LPCB.EC0._Q0E", /* P30/P35 */ |
143 | "\\_SB.PCI0.PX40.Q10", /* S1x */ | 143 | "\\_SB.PCI0.PX40.Q10", /* S1x */ |
144 | "\\Q10"); /* A2x, L2D, L3D, M2E */ | 144 | "\\Q10"); /* A2x, L2D, L3D, M2E */ |
145 | 145 | ||
146 | /* Display */ | 146 | /* Display */ |
147 | ASUS_HANDLE(display_set, ASUS_HOTK_PREFIX "SDSP"); | 147 | ASUS_HANDLE(display_set, ASUS_HOTK_PREFIX "SDSP"); |
148 | ASUS_HANDLE(display_get, "\\_SB.PCI0.P0P1.VGA.GETD", /* A6B, A6K A6R A7D F3JM L4R M6R A3G | 148 | ASUS_HANDLE(display_get, "\\_SB.PCI0.P0P1.VGA.GETD", /* A6B, A6K A6R A7D F3JM L4R M6R A3G |
149 | M6A M6V VX-1 V6J V6V W3Z */ | 149 | M6A M6V VX-1 V6J V6V W3Z */ |
150 | "\\_SB.PCI0.P0P2.VGA.GETD", /* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V | 150 | "\\_SB.PCI0.P0P2.VGA.GETD", /* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V |
151 | S5A M5A z33A W1Jc W2V G1 */ | 151 | S5A M5A z33A W1Jc W2V G1 */ |
152 | "\\_SB.PCI0.P0P3.VGA.GETD", /* A6V A6Q */ | 152 | "\\_SB.PCI0.P0P3.VGA.GETD", /* A6V A6Q */ |
153 | "\\_SB.PCI0.P0PA.VGA.GETD", /* A6T, A6M */ | 153 | "\\_SB.PCI0.P0PA.VGA.GETD", /* A6T, A6M */ |
154 | "\\_SB.PCI0.PCI1.VGAC.NMAP", /* L3C */ | 154 | "\\_SB.PCI0.PCI1.VGAC.NMAP", /* L3C */ |
155 | "\\_SB.PCI0.VGA.GETD", /* Z96F */ | 155 | "\\_SB.PCI0.VGA.GETD", /* Z96F */ |
156 | "\\ACTD", /* A2D */ | 156 | "\\ACTD", /* A2D */ |
157 | "\\ADVG", /* A4G Z71A W1N W5A W5F M2N M3N M5N M6N S1N S5N */ | 157 | "\\ADVG", /* A4G Z71A W1N W5A W5F M2N M3N M5N M6N S1N S5N */ |
158 | "\\DNXT", /* P30 */ | 158 | "\\DNXT", /* P30 */ |
159 | "\\INFB", /* A2H D1 L2D L3D L3H L2E L5D L5C M1A M2E L4L W3V */ | 159 | "\\INFB", /* A2H D1 L2D L3D L3H L2E L5D L5C M1A M2E L4L W3V */ |
160 | "\\SSTE"); /* A3F A6F A3N A3L M6N W3N W6A */ | 160 | "\\SSTE"); /* A3F A6F A3N A3L M6N W3N W6A */ |
161 | 161 | ||
162 | ASUS_HANDLE(ls_switch, ASUS_HOTK_PREFIX "ALSC"); /* Z71A Z71V */ | 162 | ASUS_HANDLE(ls_switch, ASUS_HOTK_PREFIX "ALSC"); /* Z71A Z71V */ |
163 | ASUS_HANDLE(ls_level, ASUS_HOTK_PREFIX "ALSL"); /* Z71A Z71V */ | 163 | ASUS_HANDLE(ls_level, ASUS_HOTK_PREFIX "ALSL"); /* Z71A Z71V */ |
164 | 164 | ||
165 | /* GPS */ | 165 | /* GPS */ |
166 | /* R2H use different handle for GPS on/off */ | 166 | /* R2H use different handle for GPS on/off */ |
167 | ASUS_HANDLE(gps_on, ASUS_HOTK_PREFIX "SDON"); /* R2H */ | 167 | ASUS_HANDLE(gps_on, ASUS_HOTK_PREFIX "SDON"); /* R2H */ |
168 | ASUS_HANDLE(gps_off, ASUS_HOTK_PREFIX "SDOF"); /* R2H */ | 168 | ASUS_HANDLE(gps_off, ASUS_HOTK_PREFIX "SDOF"); /* R2H */ |
169 | ASUS_HANDLE(gps_status, ASUS_HOTK_PREFIX "GPST"); | 169 | ASUS_HANDLE(gps_status, ASUS_HOTK_PREFIX "GPST"); |
170 | 170 | ||
171 | /* | 171 | /* |
172 | * This is the main structure, we can use it to store anything interesting | 172 | * This is the main structure, we can use it to store anything interesting |
173 | * about the hotk device | 173 | * about the hotk device |
174 | */ | 174 | */ |
175 | struct asus_hotk { | 175 | struct asus_hotk { |
176 | char *name; //laptop name | 176 | char *name; //laptop name |
177 | struct acpi_device *device; //the device we are in | 177 | struct acpi_device *device; //the device we are in |
178 | acpi_handle handle; //the handle of the hotk device | 178 | acpi_handle handle; //the handle of the hotk device |
179 | char status; //status of the hotk, for LEDs, ... | 179 | char status; //status of the hotk, for LEDs, ... |
180 | u32 ledd_status; //status of the LED display | 180 | u32 ledd_status; //status of the LED display |
181 | u8 light_level; //light sensor level | 181 | u8 light_level; //light sensor level |
182 | u8 light_switch; //light sensor switch value | 182 | u8 light_switch; //light sensor switch value |
183 | u16 event_count[128]; //count for each event TODO make this better | 183 | u16 event_count[128]; //count for each event TODO make this better |
184 | }; | 184 | }; |
185 | 185 | ||
186 | /* | 186 | /* |
187 | * This header is made available to allow proper configuration given model, | 187 | * This header is made available to allow proper configuration given model, |
188 | * revision number , ... this info cannot go in struct asus_hotk because it is | 188 | * revision number , ... this info cannot go in struct asus_hotk because it is |
189 | * available before the hotk | 189 | * available before the hotk |
190 | */ | 190 | */ |
191 | static struct acpi_table_header *asus_info; | 191 | static struct acpi_table_header *asus_info; |
192 | 192 | ||
193 | /* The actual device the driver binds to */ | 193 | /* The actual device the driver binds to */ |
194 | static struct asus_hotk *hotk; | 194 | static struct asus_hotk *hotk; |
195 | 195 | ||
196 | /* | 196 | /* |
197 | * The hotkey driver declaration | 197 | * The hotkey driver declaration |
198 | */ | 198 | */ |
199 | static const struct acpi_device_id asus_device_ids[] = { | 199 | static const struct acpi_device_id asus_device_ids[] = { |
200 | {"ATK0100", 0}, | 200 | {"ATK0100", 0}, |
201 | {"", 0}, | 201 | {"", 0}, |
202 | }; | 202 | }; |
203 | MODULE_DEVICE_TABLE(acpi, asus_device_ids); | 203 | MODULE_DEVICE_TABLE(acpi, asus_device_ids); |
204 | 204 | ||
205 | static int asus_hotk_add(struct acpi_device *device); | 205 | static int asus_hotk_add(struct acpi_device *device); |
206 | static int asus_hotk_remove(struct acpi_device *device, int type); | 206 | static int asus_hotk_remove(struct acpi_device *device, int type); |
207 | static struct acpi_driver asus_hotk_driver = { | 207 | static struct acpi_driver asus_hotk_driver = { |
208 | .name = ASUS_HOTK_NAME, | 208 | .name = ASUS_HOTK_NAME, |
209 | .class = ASUS_HOTK_CLASS, | 209 | .class = ASUS_HOTK_CLASS, |
210 | .ids = asus_device_ids, | 210 | .ids = asus_device_ids, |
211 | .ops = { | 211 | .ops = { |
212 | .add = asus_hotk_add, | 212 | .add = asus_hotk_add, |
213 | .remove = asus_hotk_remove, | 213 | .remove = asus_hotk_remove, |
214 | }, | 214 | }, |
215 | }; | 215 | }; |
216 | 216 | ||
217 | /* The backlight device /sys/class/backlight */ | 217 | /* The backlight device /sys/class/backlight */ |
218 | static struct backlight_device *asus_backlight_device; | 218 | static struct backlight_device *asus_backlight_device; |
219 | 219 | ||
220 | /* | 220 | /* |
221 | * The backlight class declaration | 221 | * The backlight class declaration |
222 | */ | 222 | */ |
223 | static int read_brightness(struct backlight_device *bd); | 223 | static int read_brightness(struct backlight_device *bd); |
224 | static int update_bl_status(struct backlight_device *bd); | 224 | static int update_bl_status(struct backlight_device *bd); |
225 | static struct backlight_ops asusbl_ops = { | 225 | static struct backlight_ops asusbl_ops = { |
226 | .get_brightness = read_brightness, | 226 | .get_brightness = read_brightness, |
227 | .update_status = update_bl_status, | 227 | .update_status = update_bl_status, |
228 | }; | 228 | }; |
229 | 229 | ||
230 | /* These functions actually update the LED's, and are called from a | 230 | /* These functions actually update the LED's, and are called from a |
231 | * workqueue. By doing this as separate work rather than when the LED | 231 | * workqueue. By doing this as separate work rather than when the LED |
232 | * subsystem asks, we avoid messing with the Asus ACPI stuff during a | 232 | * subsystem asks, we avoid messing with the Asus ACPI stuff during a |
233 | * potentially bad time, such as a timer interrupt. */ | 233 | * potentially bad time, such as a timer interrupt. */ |
234 | static struct workqueue_struct *led_workqueue; | 234 | static struct workqueue_struct *led_workqueue; |
235 | 235 | ||
236 | #define ASUS_LED(object, ledname) \ | 236 | #define ASUS_LED(object, ledname) \ |
237 | static void object##_led_set(struct led_classdev *led_cdev, \ | 237 | static void object##_led_set(struct led_classdev *led_cdev, \ |
238 | enum led_brightness value); \ | 238 | enum led_brightness value); \ |
239 | static void object##_led_update(struct work_struct *ignored); \ | 239 | static void object##_led_update(struct work_struct *ignored); \ |
240 | static int object##_led_wk; \ | 240 | static int object##_led_wk; \ |
241 | static DECLARE_WORK(object##_led_work, object##_led_update); \ | 241 | static DECLARE_WORK(object##_led_work, object##_led_update); \ |
242 | static struct led_classdev object##_led = { \ | 242 | static struct led_classdev object##_led = { \ |
243 | .name = "asus::" ledname, \ | 243 | .name = "asus::" ledname, \ |
244 | .brightness_set = object##_led_set, \ | 244 | .brightness_set = object##_led_set, \ |
245 | } | 245 | } |
246 | 246 | ||
247 | ASUS_LED(mled, "mail"); | 247 | ASUS_LED(mled, "mail"); |
248 | ASUS_LED(tled, "touchpad"); | 248 | ASUS_LED(tled, "touchpad"); |
249 | ASUS_LED(rled, "record"); | 249 | ASUS_LED(rled, "record"); |
250 | ASUS_LED(pled, "phone"); | 250 | ASUS_LED(pled, "phone"); |
251 | ASUS_LED(gled, "gaming"); | 251 | ASUS_LED(gled, "gaming"); |
252 | 252 | ||
253 | /* | 253 | /* |
254 | * This function evaluates an ACPI method, given an int as parameter, the | 254 | * This function evaluates an ACPI method, given an int as parameter, the |
255 | * method is searched within the scope of the handle, can be NULL. The output | 255 | * method is searched within the scope of the handle, can be NULL. The output |
256 | * of the method is written is output, which can also be NULL | 256 | * of the method is written is output, which can also be NULL |
257 | * | 257 | * |
258 | * returns 0 if write is successful, -1 else. | 258 | * returns 0 if write is successful, -1 else. |
259 | */ | 259 | */ |
260 | static int write_acpi_int(acpi_handle handle, const char *method, int val, | 260 | static int write_acpi_int(acpi_handle handle, const char *method, int val, |
261 | struct acpi_buffer *output) | 261 | struct acpi_buffer *output) |
262 | { | 262 | { |
263 | struct acpi_object_list params; //list of input parameters (an int here) | 263 | struct acpi_object_list params; //list of input parameters (an int here) |
264 | union acpi_object in_obj; //the only param we use | 264 | union acpi_object in_obj; //the only param we use |
265 | acpi_status status; | 265 | acpi_status status; |
266 | 266 | ||
267 | if (!handle) | 267 | if (!handle) |
268 | return 0; | 268 | return 0; |
269 | 269 | ||
270 | params.count = 1; | 270 | params.count = 1; |
271 | params.pointer = &in_obj; | 271 | params.pointer = &in_obj; |
272 | in_obj.type = ACPI_TYPE_INTEGER; | 272 | in_obj.type = ACPI_TYPE_INTEGER; |
273 | in_obj.integer.value = val; | 273 | in_obj.integer.value = val; |
274 | 274 | ||
275 | status = acpi_evaluate_object(handle, (char *)method, ¶ms, output); | 275 | status = acpi_evaluate_object(handle, (char *)method, ¶ms, output); |
276 | if (status == AE_OK) | 276 | if (status == AE_OK) |
277 | return 0; | 277 | return 0; |
278 | else | 278 | else |
279 | return -1; | 279 | return -1; |
280 | } | 280 | } |
281 | 281 | ||
282 | static int read_wireless_status(int mask) | 282 | static int read_wireless_status(int mask) |
283 | { | 283 | { |
284 | unsigned long long status; | 284 | unsigned long long status; |
285 | acpi_status rv = AE_OK; | 285 | acpi_status rv = AE_OK; |
286 | 286 | ||
287 | if (!wireless_status_handle) | 287 | if (!wireless_status_handle) |
288 | return (hotk->status & mask) ? 1 : 0; | 288 | return (hotk->status & mask) ? 1 : 0; |
289 | 289 | ||
290 | rv = acpi_evaluate_integer(wireless_status_handle, NULL, NULL, &status); | 290 | rv = acpi_evaluate_integer(wireless_status_handle, NULL, NULL, &status); |
291 | if (ACPI_FAILURE(rv)) | 291 | if (ACPI_FAILURE(rv)) |
292 | printk(ASUS_WARNING "Error reading Wireless status\n"); | 292 | printk(ASUS_WARNING "Error reading Wireless status\n"); |
293 | else | 293 | else |
294 | return (status & mask) ? 1 : 0; | 294 | return (status & mask) ? 1 : 0; |
295 | 295 | ||
296 | return (hotk->status & mask) ? 1 : 0; | 296 | return (hotk->status & mask) ? 1 : 0; |
297 | } | 297 | } |
298 | 298 | ||
299 | static int read_gps_status(void) | 299 | static int read_gps_status(void) |
300 | { | 300 | { |
301 | unsigned long long status; | 301 | unsigned long long status; |
302 | acpi_status rv = AE_OK; | 302 | acpi_status rv = AE_OK; |
303 | 303 | ||
304 | rv = acpi_evaluate_integer(gps_status_handle, NULL, NULL, &status); | 304 | rv = acpi_evaluate_integer(gps_status_handle, NULL, NULL, &status); |
305 | if (ACPI_FAILURE(rv)) | 305 | if (ACPI_FAILURE(rv)) |
306 | printk(ASUS_WARNING "Error reading GPS status\n"); | 306 | printk(ASUS_WARNING "Error reading GPS status\n"); |
307 | else | 307 | else |
308 | return status ? 1 : 0; | 308 | return status ? 1 : 0; |
309 | 309 | ||
310 | return (hotk->status & GPS_ON) ? 1 : 0; | 310 | return (hotk->status & GPS_ON) ? 1 : 0; |
311 | } | 311 | } |
312 | 312 | ||
313 | /* Generic LED functions */ | 313 | /* Generic LED functions */ |
314 | static int read_status(int mask) | 314 | static int read_status(int mask) |
315 | { | 315 | { |
316 | /* There is a special method for both wireless devices */ | 316 | /* There is a special method for both wireless devices */ |
317 | if (mask == BT_ON || mask == WL_ON) | 317 | if (mask == BT_ON || mask == WL_ON) |
318 | return read_wireless_status(mask); | 318 | return read_wireless_status(mask); |
319 | else if (mask == GPS_ON) | 319 | else if (mask == GPS_ON) |
320 | return read_gps_status(); | 320 | return read_gps_status(); |
321 | 321 | ||
322 | return (hotk->status & mask) ? 1 : 0; | 322 | return (hotk->status & mask) ? 1 : 0; |
323 | } | 323 | } |
324 | 324 | ||
325 | static void write_status(acpi_handle handle, int out, int mask) | 325 | static void write_status(acpi_handle handle, int out, int mask) |
326 | { | 326 | { |
327 | hotk->status = (out) ? (hotk->status | mask) : (hotk->status & ~mask); | 327 | hotk->status = (out) ? (hotk->status | mask) : (hotk->status & ~mask); |
328 | 328 | ||
329 | switch (mask) { | 329 | switch (mask) { |
330 | case MLED_ON: | 330 | case MLED_ON: |
331 | out = !(out & 0x1); | 331 | out = !(out & 0x1); |
332 | break; | 332 | break; |
333 | case GLED_ON: | 333 | case GLED_ON: |
334 | out = (out & 0x1) + 1; | 334 | out = (out & 0x1) + 1; |
335 | break; | 335 | break; |
336 | case GPS_ON: | 336 | case GPS_ON: |
337 | handle = (out) ? gps_on_handle : gps_off_handle; | 337 | handle = (out) ? gps_on_handle : gps_off_handle; |
338 | out = 0x02; | 338 | out = 0x02; |
339 | break; | 339 | break; |
340 | default: | 340 | default: |
341 | out &= 0x1; | 341 | out &= 0x1; |
342 | break; | 342 | break; |
343 | } | 343 | } |
344 | 344 | ||
345 | if (write_acpi_int(handle, NULL, out, NULL)) | 345 | if (write_acpi_int(handle, NULL, out, NULL)) |
346 | printk(ASUS_WARNING " write failed %x\n", mask); | 346 | printk(ASUS_WARNING " write failed %x\n", mask); |
347 | } | 347 | } |
348 | 348 | ||
349 | /* /sys/class/led handlers */ | 349 | /* /sys/class/led handlers */ |
350 | #define ASUS_LED_HANDLER(object, mask) \ | 350 | #define ASUS_LED_HANDLER(object, mask) \ |
351 | static void object##_led_set(struct led_classdev *led_cdev, \ | 351 | static void object##_led_set(struct led_classdev *led_cdev, \ |
352 | enum led_brightness value) \ | 352 | enum led_brightness value) \ |
353 | { \ | 353 | { \ |
354 | object##_led_wk = (value > 0) ? 1 : 0; \ | 354 | object##_led_wk = (value > 0) ? 1 : 0; \ |
355 | queue_work(led_workqueue, &object##_led_work); \ | 355 | queue_work(led_workqueue, &object##_led_work); \ |
356 | } \ | 356 | } \ |
357 | static void object##_led_update(struct work_struct *ignored) \ | 357 | static void object##_led_update(struct work_struct *ignored) \ |
358 | { \ | 358 | { \ |
359 | int value = object##_led_wk; \ | 359 | int value = object##_led_wk; \ |
360 | write_status(object##_set_handle, value, (mask)); \ | 360 | write_status(object##_set_handle, value, (mask)); \ |
361 | } | 361 | } |
362 | 362 | ||
363 | ASUS_LED_HANDLER(mled, MLED_ON); | 363 | ASUS_LED_HANDLER(mled, MLED_ON); |
364 | ASUS_LED_HANDLER(pled, PLED_ON); | 364 | ASUS_LED_HANDLER(pled, PLED_ON); |
365 | ASUS_LED_HANDLER(rled, RLED_ON); | 365 | ASUS_LED_HANDLER(rled, RLED_ON); |
366 | ASUS_LED_HANDLER(tled, TLED_ON); | 366 | ASUS_LED_HANDLER(tled, TLED_ON); |
367 | ASUS_LED_HANDLER(gled, GLED_ON); | 367 | ASUS_LED_HANDLER(gled, GLED_ON); |
368 | 368 | ||
369 | static int get_lcd_state(void) | 369 | static int get_lcd_state(void) |
370 | { | 370 | { |
371 | return read_status(LCD_ON); | 371 | return read_status(LCD_ON); |
372 | } | 372 | } |
373 | 373 | ||
374 | static int set_lcd_state(int value) | 374 | static int set_lcd_state(int value) |
375 | { | 375 | { |
376 | int lcd = 0; | 376 | int lcd = 0; |
377 | acpi_status status = 0; | 377 | acpi_status status = 0; |
378 | 378 | ||
379 | lcd = value ? 1 : 0; | 379 | lcd = value ? 1 : 0; |
380 | 380 | ||
381 | if (lcd == get_lcd_state()) | 381 | if (lcd == get_lcd_state()) |
382 | return 0; | 382 | return 0; |
383 | 383 | ||
384 | if (lcd_switch_handle) { | 384 | if (lcd_switch_handle) { |
385 | status = acpi_evaluate_object(lcd_switch_handle, | 385 | status = acpi_evaluate_object(lcd_switch_handle, |
386 | NULL, NULL, NULL); | 386 | NULL, NULL, NULL); |
387 | 387 | ||
388 | if (ACPI_FAILURE(status)) | 388 | if (ACPI_FAILURE(status)) |
389 | printk(ASUS_WARNING "Error switching LCD\n"); | 389 | printk(ASUS_WARNING "Error switching LCD\n"); |
390 | } | 390 | } |
391 | 391 | ||
392 | write_status(NULL, lcd, LCD_ON); | 392 | write_status(NULL, lcd, LCD_ON); |
393 | return 0; | 393 | return 0; |
394 | } | 394 | } |
395 | 395 | ||
396 | static void lcd_blank(int blank) | 396 | static void lcd_blank(int blank) |
397 | { | 397 | { |
398 | struct backlight_device *bd = asus_backlight_device; | 398 | struct backlight_device *bd = asus_backlight_device; |
399 | 399 | ||
400 | if (bd) { | 400 | if (bd) { |
401 | bd->props.power = blank; | 401 | bd->props.power = blank; |
402 | backlight_update_status(bd); | 402 | backlight_update_status(bd); |
403 | } | 403 | } |
404 | } | 404 | } |
405 | 405 | ||
406 | static int read_brightness(struct backlight_device *bd) | 406 | static int read_brightness(struct backlight_device *bd) |
407 | { | 407 | { |
408 | unsigned long long value; | 408 | unsigned long long value; |
409 | acpi_status rv = AE_OK; | 409 | acpi_status rv = AE_OK; |
410 | 410 | ||
411 | rv = acpi_evaluate_integer(brightness_get_handle, NULL, NULL, &value); | 411 | rv = acpi_evaluate_integer(brightness_get_handle, NULL, NULL, &value); |
412 | if (ACPI_FAILURE(rv)) | 412 | if (ACPI_FAILURE(rv)) |
413 | printk(ASUS_WARNING "Error reading brightness\n"); | 413 | printk(ASUS_WARNING "Error reading brightness\n"); |
414 | 414 | ||
415 | return value; | 415 | return value; |
416 | } | 416 | } |
417 | 417 | ||
418 | static int set_brightness(struct backlight_device *bd, int value) | 418 | static int set_brightness(struct backlight_device *bd, int value) |
419 | { | 419 | { |
420 | int ret = 0; | 420 | int ret = 0; |
421 | 421 | ||
422 | value = (0 < value) ? ((15 < value) ? 15 : value) : 0; | 422 | value = (0 < value) ? ((15 < value) ? 15 : value) : 0; |
423 | /* 0 <= value <= 15 */ | 423 | /* 0 <= value <= 15 */ |
424 | 424 | ||
425 | if (write_acpi_int(brightness_set_handle, NULL, value, NULL)) { | 425 | if (write_acpi_int(brightness_set_handle, NULL, value, NULL)) { |
426 | printk(ASUS_WARNING "Error changing brightness\n"); | 426 | printk(ASUS_WARNING "Error changing brightness\n"); |
427 | ret = -EIO; | 427 | ret = -EIO; |
428 | } | 428 | } |
429 | 429 | ||
430 | return ret; | 430 | return ret; |
431 | } | 431 | } |
432 | 432 | ||
433 | static int update_bl_status(struct backlight_device *bd) | 433 | static int update_bl_status(struct backlight_device *bd) |
434 | { | 434 | { |
435 | int rv; | 435 | int rv; |
436 | int value = bd->props.brightness; | 436 | int value = bd->props.brightness; |
437 | 437 | ||
438 | rv = set_brightness(bd, value); | 438 | rv = set_brightness(bd, value); |
439 | if (rv) | 439 | if (rv) |
440 | return rv; | 440 | return rv; |
441 | 441 | ||
442 | value = (bd->props.power == FB_BLANK_UNBLANK) ? 1 : 0; | 442 | value = (bd->props.power == FB_BLANK_UNBLANK) ? 1 : 0; |
443 | return set_lcd_state(value); | 443 | return set_lcd_state(value); |
444 | } | 444 | } |
445 | 445 | ||
446 | /* | 446 | /* |
447 | * Platform device handlers | 447 | * Platform device handlers |
448 | */ | 448 | */ |
449 | 449 | ||
450 | /* | 450 | /* |
451 | * We write our info in page, we begin at offset off and cannot write more | 451 | * We write our info in page, we begin at offset off and cannot write more |
452 | * than count bytes. We set eof to 1 if we handle those 2 values. We return the | 452 | * than count bytes. We set eof to 1 if we handle those 2 values. We return the |
453 | * number of bytes written in page | 453 | * number of bytes written in page |
454 | */ | 454 | */ |
455 | static ssize_t show_infos(struct device *dev, | 455 | static ssize_t show_infos(struct device *dev, |
456 | struct device_attribute *attr, char *page) | 456 | struct device_attribute *attr, char *page) |
457 | { | 457 | { |
458 | int len = 0; | 458 | int len = 0; |
459 | unsigned long long temp; | 459 | unsigned long long temp; |
460 | char buf[16]; //enough for all info | 460 | char buf[16]; //enough for all info |
461 | acpi_status rv = AE_OK; | 461 | acpi_status rv = AE_OK; |
462 | 462 | ||
463 | /* | 463 | /* |
464 | * We use the easy way, we don't care of off and count, so we don't set eof | 464 | * We use the easy way, we don't care of off and count, so we don't set eof |
465 | * to 1 | 465 | * to 1 |
466 | */ | 466 | */ |
467 | 467 | ||
468 | len += sprintf(page, ASUS_HOTK_NAME " " ASUS_LAPTOP_VERSION "\n"); | 468 | len += sprintf(page, ASUS_HOTK_NAME " " ASUS_LAPTOP_VERSION "\n"); |
469 | len += sprintf(page + len, "Model reference : %s\n", hotk->name); | 469 | len += sprintf(page + len, "Model reference : %s\n", hotk->name); |
470 | /* | 470 | /* |
471 | * The SFUN method probably allows the original driver to get the list | 471 | * The SFUN method probably allows the original driver to get the list |
472 | * of features supported by a given model. For now, 0x0100 or 0x0800 | 472 | * of features supported by a given model. For now, 0x0100 or 0x0800 |
473 | * bit signifies that the laptop is equipped with a Wi-Fi MiniPCI card. | 473 | * bit signifies that the laptop is equipped with a Wi-Fi MiniPCI card. |
474 | * The significance of others is yet to be found. | 474 | * The significance of others is yet to be found. |
475 | */ | 475 | */ |
476 | rv = acpi_evaluate_integer(hotk->handle, "SFUN", NULL, &temp); | 476 | rv = acpi_evaluate_integer(hotk->handle, "SFUN", NULL, &temp); |
477 | if (!ACPI_FAILURE(rv)) | 477 | if (!ACPI_FAILURE(rv)) |
478 | len += sprintf(page + len, "SFUN value : 0x%04x\n", | 478 | len += sprintf(page + len, "SFUN value : 0x%04x\n", |
479 | (uint) temp); | 479 | (uint) temp); |
480 | /* | 480 | /* |
481 | * Another value for userspace: the ASYM method returns 0x02 for | 481 | * Another value for userspace: the ASYM method returns 0x02 for |
482 | * battery low and 0x04 for battery critical, its readings tend to be | 482 | * battery low and 0x04 for battery critical, its readings tend to be |
483 | * more accurate than those provided by _BST. | 483 | * more accurate than those provided by _BST. |
484 | * Note: since not all the laptops provide this method, errors are | 484 | * Note: since not all the laptops provide this method, errors are |
485 | * silently ignored. | 485 | * silently ignored. |
486 | */ | 486 | */ |
487 | rv = acpi_evaluate_integer(hotk->handle, "ASYM", NULL, &temp); | 487 | rv = acpi_evaluate_integer(hotk->handle, "ASYM", NULL, &temp); |
488 | if (!ACPI_FAILURE(rv)) | 488 | if (!ACPI_FAILURE(rv)) |
489 | len += sprintf(page + len, "ASYM value : 0x%04x\n", | 489 | len += sprintf(page + len, "ASYM value : 0x%04x\n", |
490 | (uint) temp); | 490 | (uint) temp); |
491 | if (asus_info) { | 491 | if (asus_info) { |
492 | snprintf(buf, 16, "%d", asus_info->length); | 492 | snprintf(buf, 16, "%d", asus_info->length); |
493 | len += sprintf(page + len, "DSDT length : %s\n", buf); | 493 | len += sprintf(page + len, "DSDT length : %s\n", buf); |
494 | snprintf(buf, 16, "%d", asus_info->checksum); | 494 | snprintf(buf, 16, "%d", asus_info->checksum); |
495 | len += sprintf(page + len, "DSDT checksum : %s\n", buf); | 495 | len += sprintf(page + len, "DSDT checksum : %s\n", buf); |
496 | snprintf(buf, 16, "%d", asus_info->revision); | 496 | snprintf(buf, 16, "%d", asus_info->revision); |
497 | len += sprintf(page + len, "DSDT revision : %s\n", buf); | 497 | len += sprintf(page + len, "DSDT revision : %s\n", buf); |
498 | snprintf(buf, 7, "%s", asus_info->oem_id); | 498 | snprintf(buf, 7, "%s", asus_info->oem_id); |
499 | len += sprintf(page + len, "OEM id : %s\n", buf); | 499 | len += sprintf(page + len, "OEM id : %s\n", buf); |
500 | snprintf(buf, 9, "%s", asus_info->oem_table_id); | 500 | snprintf(buf, 9, "%s", asus_info->oem_table_id); |
501 | len += sprintf(page + len, "OEM table id : %s\n", buf); | 501 | len += sprintf(page + len, "OEM table id : %s\n", buf); |
502 | snprintf(buf, 16, "%x", asus_info->oem_revision); | 502 | snprintf(buf, 16, "%x", asus_info->oem_revision); |
503 | len += sprintf(page + len, "OEM revision : 0x%s\n", buf); | 503 | len += sprintf(page + len, "OEM revision : 0x%s\n", buf); |
504 | snprintf(buf, 5, "%s", asus_info->asl_compiler_id); | 504 | snprintf(buf, 5, "%s", asus_info->asl_compiler_id); |
505 | len += sprintf(page + len, "ASL comp vendor id : %s\n", buf); | 505 | len += sprintf(page + len, "ASL comp vendor id : %s\n", buf); |
506 | snprintf(buf, 16, "%x", asus_info->asl_compiler_revision); | 506 | snprintf(buf, 16, "%x", asus_info->asl_compiler_revision); |
507 | len += sprintf(page + len, "ASL comp revision : 0x%s\n", buf); | 507 | len += sprintf(page + len, "ASL comp revision : 0x%s\n", buf); |
508 | } | 508 | } |
509 | 509 | ||
510 | return len; | 510 | return len; |
511 | } | 511 | } |
512 | 512 | ||
513 | static int parse_arg(const char *buf, unsigned long count, int *val) | 513 | static int parse_arg(const char *buf, unsigned long count, int *val) |
514 | { | 514 | { |
515 | if (!count) | 515 | if (!count) |
516 | return 0; | 516 | return 0; |
517 | if (count > 31) | 517 | if (count > 31) |
518 | return -EINVAL; | 518 | return -EINVAL; |
519 | if (sscanf(buf, "%i", val) != 1) | 519 | if (sscanf(buf, "%i", val) != 1) |
520 | return -EINVAL; | 520 | return -EINVAL; |
521 | return count; | 521 | return count; |
522 | } | 522 | } |
523 | 523 | ||
524 | static ssize_t store_status(const char *buf, size_t count, | 524 | static ssize_t store_status(const char *buf, size_t count, |
525 | acpi_handle handle, int mask) | 525 | acpi_handle handle, int mask) |
526 | { | 526 | { |
527 | int rv, value; | 527 | int rv, value; |
528 | int out = 0; | 528 | int out = 0; |
529 | 529 | ||
530 | rv = parse_arg(buf, count, &value); | 530 | rv = parse_arg(buf, count, &value); |
531 | if (rv > 0) | 531 | if (rv > 0) |
532 | out = value ? 1 : 0; | 532 | out = value ? 1 : 0; |
533 | 533 | ||
534 | write_status(handle, out, mask); | 534 | write_status(handle, out, mask); |
535 | 535 | ||
536 | return rv; | 536 | return rv; |
537 | } | 537 | } |
538 | 538 | ||
539 | /* | 539 | /* |
540 | * LEDD display | 540 | * LEDD display |
541 | */ | 541 | */ |
542 | static ssize_t show_ledd(struct device *dev, | 542 | static ssize_t show_ledd(struct device *dev, |
543 | struct device_attribute *attr, char *buf) | 543 | struct device_attribute *attr, char *buf) |
544 | { | 544 | { |
545 | return sprintf(buf, "0x%08x\n", hotk->ledd_status); | 545 | return sprintf(buf, "0x%08x\n", hotk->ledd_status); |
546 | } | 546 | } |
547 | 547 | ||
548 | static ssize_t store_ledd(struct device *dev, struct device_attribute *attr, | 548 | static ssize_t store_ledd(struct device *dev, struct device_attribute *attr, |
549 | const char *buf, size_t count) | 549 | const char *buf, size_t count) |
550 | { | 550 | { |
551 | int rv, value; | 551 | int rv, value; |
552 | 552 | ||
553 | rv = parse_arg(buf, count, &value); | 553 | rv = parse_arg(buf, count, &value); |
554 | if (rv > 0) { | 554 | if (rv > 0) { |
555 | if (write_acpi_int(ledd_set_handle, NULL, value, NULL)) | 555 | if (write_acpi_int(ledd_set_handle, NULL, value, NULL)) |
556 | printk(ASUS_WARNING "LED display write failed\n"); | 556 | printk(ASUS_WARNING "LED display write failed\n"); |
557 | else | 557 | else |
558 | hotk->ledd_status = (u32) value; | 558 | hotk->ledd_status = (u32) value; |
559 | } | 559 | } |
560 | return rv; | 560 | return rv; |
561 | } | 561 | } |
562 | 562 | ||
563 | /* | 563 | /* |
564 | * WLAN | 564 | * WLAN |
565 | */ | 565 | */ |
566 | static ssize_t show_wlan(struct device *dev, | 566 | static ssize_t show_wlan(struct device *dev, |
567 | struct device_attribute *attr, char *buf) | 567 | struct device_attribute *attr, char *buf) |
568 | { | 568 | { |
569 | return sprintf(buf, "%d\n", read_status(WL_ON)); | 569 | return sprintf(buf, "%d\n", read_status(WL_ON)); |
570 | } | 570 | } |
571 | 571 | ||
572 | static ssize_t store_wlan(struct device *dev, struct device_attribute *attr, | 572 | static ssize_t store_wlan(struct device *dev, struct device_attribute *attr, |
573 | const char *buf, size_t count) | 573 | const char *buf, size_t count) |
574 | { | 574 | { |
575 | return store_status(buf, count, wl_switch_handle, WL_ON); | 575 | return store_status(buf, count, wl_switch_handle, WL_ON); |
576 | } | 576 | } |
577 | 577 | ||
578 | /* | 578 | /* |
579 | * Bluetooth | 579 | * Bluetooth |
580 | */ | 580 | */ |
581 | static ssize_t show_bluetooth(struct device *dev, | 581 | static ssize_t show_bluetooth(struct device *dev, |
582 | struct device_attribute *attr, char *buf) | 582 | struct device_attribute *attr, char *buf) |
583 | { | 583 | { |
584 | return sprintf(buf, "%d\n", read_status(BT_ON)); | 584 | return sprintf(buf, "%d\n", read_status(BT_ON)); |
585 | } | 585 | } |
586 | 586 | ||
587 | static ssize_t store_bluetooth(struct device *dev, | 587 | static ssize_t store_bluetooth(struct device *dev, |
588 | struct device_attribute *attr, const char *buf, | 588 | struct device_attribute *attr, const char *buf, |
589 | size_t count) | 589 | size_t count) |
590 | { | 590 | { |
591 | return store_status(buf, count, bt_switch_handle, BT_ON); | 591 | return store_status(buf, count, bt_switch_handle, BT_ON); |
592 | } | 592 | } |
593 | 593 | ||
594 | /* | 594 | /* |
595 | * Display | 595 | * Display |
596 | */ | 596 | */ |
597 | static void set_display(int value) | 597 | static void set_display(int value) |
598 | { | 598 | { |
599 | /* no sanity check needed for now */ | 599 | /* no sanity check needed for now */ |
600 | if (write_acpi_int(display_set_handle, NULL, value, NULL)) | 600 | if (write_acpi_int(display_set_handle, NULL, value, NULL)) |
601 | printk(ASUS_WARNING "Error setting display\n"); | 601 | printk(ASUS_WARNING "Error setting display\n"); |
602 | return; | 602 | return; |
603 | } | 603 | } |
604 | 604 | ||
605 | static int read_display(void) | 605 | static int read_display(void) |
606 | { | 606 | { |
607 | unsigned long long value = 0; | 607 | unsigned long long value = 0; |
608 | acpi_status rv = AE_OK; | 608 | acpi_status rv = AE_OK; |
609 | 609 | ||
610 | /* In most of the case, we know how to set the display, but sometime | 610 | /* In most of the case, we know how to set the display, but sometime |
611 | we can't read it */ | 611 | we can't read it */ |
612 | if (display_get_handle) { | 612 | if (display_get_handle) { |
613 | rv = acpi_evaluate_integer(display_get_handle, NULL, | 613 | rv = acpi_evaluate_integer(display_get_handle, NULL, |
614 | NULL, &value); | 614 | NULL, &value); |
615 | if (ACPI_FAILURE(rv)) | 615 | if (ACPI_FAILURE(rv)) |
616 | printk(ASUS_WARNING "Error reading display status\n"); | 616 | printk(ASUS_WARNING "Error reading display status\n"); |
617 | } | 617 | } |
618 | 618 | ||
619 | value &= 0x0F; /* needed for some models, shouldn't hurt others */ | 619 | value &= 0x0F; /* needed for some models, shouldn't hurt others */ |
620 | 620 | ||
621 | return value; | 621 | return value; |
622 | } | 622 | } |
623 | 623 | ||
624 | /* | 624 | /* |
625 | * Now, *this* one could be more user-friendly, but so far, no-one has | 625 | * Now, *this* one could be more user-friendly, but so far, no-one has |
626 | * complained. The significance of bits is the same as in store_disp() | 626 | * complained. The significance of bits is the same as in store_disp() |
627 | */ | 627 | */ |
628 | static ssize_t show_disp(struct device *dev, | 628 | static ssize_t show_disp(struct device *dev, |
629 | struct device_attribute *attr, char *buf) | 629 | struct device_attribute *attr, char *buf) |
630 | { | 630 | { |
631 | return sprintf(buf, "%d\n", read_display()); | 631 | return sprintf(buf, "%d\n", read_display()); |
632 | } | 632 | } |
633 | 633 | ||
634 | /* | 634 | /* |
635 | * Experimental support for display switching. As of now: 1 should activate | 635 | * Experimental support for display switching. As of now: 1 should activate |
636 | * the LCD output, 2 should do for CRT, 4 for TV-Out and 8 for DVI. | 636 | * the LCD output, 2 should do for CRT, 4 for TV-Out and 8 for DVI. |
637 | * Any combination (bitwise) of these will suffice. I never actually tested 4 | 637 | * Any combination (bitwise) of these will suffice. I never actually tested 4 |
638 | * displays hooked up simultaneously, so be warned. See the acpi4asus README | 638 | * displays hooked up simultaneously, so be warned. See the acpi4asus README |
639 | * for more info. | 639 | * for more info. |
640 | */ | 640 | */ |
641 | static ssize_t store_disp(struct device *dev, struct device_attribute *attr, | 641 | static ssize_t store_disp(struct device *dev, struct device_attribute *attr, |
642 | const char *buf, size_t count) | 642 | const char *buf, size_t count) |
643 | { | 643 | { |
644 | int rv, value; | 644 | int rv, value; |
645 | 645 | ||
646 | rv = parse_arg(buf, count, &value); | 646 | rv = parse_arg(buf, count, &value); |
647 | if (rv > 0) | 647 | if (rv > 0) |
648 | set_display(value); | 648 | set_display(value); |
649 | return rv; | 649 | return rv; |
650 | } | 650 | } |
651 | 651 | ||
652 | /* | 652 | /* |
653 | * Light Sens | 653 | * Light Sens |
654 | */ | 654 | */ |
655 | static void set_light_sens_switch(int value) | 655 | static void set_light_sens_switch(int value) |
656 | { | 656 | { |
657 | if (write_acpi_int(ls_switch_handle, NULL, value, NULL)) | 657 | if (write_acpi_int(ls_switch_handle, NULL, value, NULL)) |
658 | printk(ASUS_WARNING "Error setting light sensor switch\n"); | 658 | printk(ASUS_WARNING "Error setting light sensor switch\n"); |
659 | hotk->light_switch = value; | 659 | hotk->light_switch = value; |
660 | } | 660 | } |
661 | 661 | ||
662 | static ssize_t show_lssw(struct device *dev, | 662 | static ssize_t show_lssw(struct device *dev, |
663 | struct device_attribute *attr, char *buf) | 663 | struct device_attribute *attr, char *buf) |
664 | { | 664 | { |
665 | return sprintf(buf, "%d\n", hotk->light_switch); | 665 | return sprintf(buf, "%d\n", hotk->light_switch); |
666 | } | 666 | } |
667 | 667 | ||
668 | static ssize_t store_lssw(struct device *dev, struct device_attribute *attr, | 668 | static ssize_t store_lssw(struct device *dev, struct device_attribute *attr, |
669 | const char *buf, size_t count) | 669 | const char *buf, size_t count) |
670 | { | 670 | { |
671 | int rv, value; | 671 | int rv, value; |
672 | 672 | ||
673 | rv = parse_arg(buf, count, &value); | 673 | rv = parse_arg(buf, count, &value); |
674 | if (rv > 0) | 674 | if (rv > 0) |
675 | set_light_sens_switch(value ? 1 : 0); | 675 | set_light_sens_switch(value ? 1 : 0); |
676 | 676 | ||
677 | return rv; | 677 | return rv; |
678 | } | 678 | } |
679 | 679 | ||
680 | static void set_light_sens_level(int value) | 680 | static void set_light_sens_level(int value) |
681 | { | 681 | { |
682 | if (write_acpi_int(ls_level_handle, NULL, value, NULL)) | 682 | if (write_acpi_int(ls_level_handle, NULL, value, NULL)) |
683 | printk(ASUS_WARNING "Error setting light sensor level\n"); | 683 | printk(ASUS_WARNING "Error setting light sensor level\n"); |
684 | hotk->light_level = value; | 684 | hotk->light_level = value; |
685 | } | 685 | } |
686 | 686 | ||
687 | static ssize_t show_lslvl(struct device *dev, | 687 | static ssize_t show_lslvl(struct device *dev, |
688 | struct device_attribute *attr, char *buf) | 688 | struct device_attribute *attr, char *buf) |
689 | { | 689 | { |
690 | return sprintf(buf, "%d\n", hotk->light_level); | 690 | return sprintf(buf, "%d\n", hotk->light_level); |
691 | } | 691 | } |
692 | 692 | ||
693 | static ssize_t store_lslvl(struct device *dev, struct device_attribute *attr, | 693 | static ssize_t store_lslvl(struct device *dev, struct device_attribute *attr, |
694 | const char *buf, size_t count) | 694 | const char *buf, size_t count) |
695 | { | 695 | { |
696 | int rv, value; | 696 | int rv, value; |
697 | 697 | ||
698 | rv = parse_arg(buf, count, &value); | 698 | rv = parse_arg(buf, count, &value); |
699 | if (rv > 0) { | 699 | if (rv > 0) { |
700 | value = (0 < value) ? ((15 < value) ? 15 : value) : 0; | 700 | value = (0 < value) ? ((15 < value) ? 15 : value) : 0; |
701 | /* 0 <= value <= 15 */ | 701 | /* 0 <= value <= 15 */ |
702 | set_light_sens_level(value); | 702 | set_light_sens_level(value); |
703 | } | 703 | } |
704 | 704 | ||
705 | return rv; | 705 | return rv; |
706 | } | 706 | } |
707 | 707 | ||
708 | /* | 708 | /* |
709 | * GPS | 709 | * GPS |
710 | */ | 710 | */ |
711 | static ssize_t show_gps(struct device *dev, | 711 | static ssize_t show_gps(struct device *dev, |
712 | struct device_attribute *attr, char *buf) | 712 | struct device_attribute *attr, char *buf) |
713 | { | 713 | { |
714 | return sprintf(buf, "%d\n", read_status(GPS_ON)); | 714 | return sprintf(buf, "%d\n", read_status(GPS_ON)); |
715 | } | 715 | } |
716 | 716 | ||
717 | static ssize_t store_gps(struct device *dev, struct device_attribute *attr, | 717 | static ssize_t store_gps(struct device *dev, struct device_attribute *attr, |
718 | const char *buf, size_t count) | 718 | const char *buf, size_t count) |
719 | { | 719 | { |
720 | return store_status(buf, count, NULL, GPS_ON); | 720 | return store_status(buf, count, NULL, GPS_ON); |
721 | } | 721 | } |
722 | 722 | ||
723 | static void asus_hotk_notify(acpi_handle handle, u32 event, void *data) | 723 | static void asus_hotk_notify(acpi_handle handle, u32 event, void *data) |
724 | { | 724 | { |
725 | /* TODO Find a better way to handle events count. */ | 725 | /* TODO Find a better way to handle events count. */ |
726 | if (!hotk) | 726 | if (!hotk) |
727 | return; | 727 | return; |
728 | 728 | ||
729 | /* | 729 | /* |
730 | * We need to tell the backlight device when the backlight power is | 730 | * We need to tell the backlight device when the backlight power is |
731 | * switched | 731 | * switched |
732 | */ | 732 | */ |
733 | if (event == ATKD_LCD_ON) { | 733 | if (event == ATKD_LCD_ON) { |
734 | write_status(NULL, 1, LCD_ON); | 734 | write_status(NULL, 1, LCD_ON); |
735 | lcd_blank(FB_BLANK_UNBLANK); | 735 | lcd_blank(FB_BLANK_UNBLANK); |
736 | } else if (event == ATKD_LCD_OFF) { | 736 | } else if (event == ATKD_LCD_OFF) { |
737 | write_status(NULL, 0, LCD_ON); | 737 | write_status(NULL, 0, LCD_ON); |
738 | lcd_blank(FB_BLANK_POWERDOWN); | 738 | lcd_blank(FB_BLANK_POWERDOWN); |
739 | } | 739 | } |
740 | 740 | ||
741 | acpi_bus_generate_proc_event(hotk->device, event, | 741 | acpi_bus_generate_proc_event(hotk->device, event, |
742 | hotk->event_count[event % 128]++); | 742 | hotk->event_count[event % 128]++); |
743 | 743 | ||
744 | return; | 744 | return; |
745 | } | 745 | } |
746 | 746 | ||
747 | #define ASUS_CREATE_DEVICE_ATTR(_name) \ | 747 | #define ASUS_CREATE_DEVICE_ATTR(_name) \ |
748 | struct device_attribute dev_attr_##_name = { \ | 748 | struct device_attribute dev_attr_##_name = { \ |
749 | .attr = { \ | 749 | .attr = { \ |
750 | .name = __stringify(_name), \ | 750 | .name = __stringify(_name), \ |
751 | .mode = 0 }, \ | 751 | .mode = 0 }, \ |
752 | .show = NULL, \ | 752 | .show = NULL, \ |
753 | .store = NULL, \ | 753 | .store = NULL, \ |
754 | } | 754 | } |
755 | 755 | ||
756 | #define ASUS_SET_DEVICE_ATTR(_name, _mode, _show, _store) \ | 756 | #define ASUS_SET_DEVICE_ATTR(_name, _mode, _show, _store) \ |
757 | do { \ | 757 | do { \ |
758 | dev_attr_##_name.attr.mode = _mode; \ | 758 | dev_attr_##_name.attr.mode = _mode; \ |
759 | dev_attr_##_name.show = _show; \ | 759 | dev_attr_##_name.show = _show; \ |
760 | dev_attr_##_name.store = _store; \ | 760 | dev_attr_##_name.store = _store; \ |
761 | } while(0) | 761 | } while(0) |
762 | 762 | ||
763 | static ASUS_CREATE_DEVICE_ATTR(infos); | 763 | static ASUS_CREATE_DEVICE_ATTR(infos); |
764 | static ASUS_CREATE_DEVICE_ATTR(wlan); | 764 | static ASUS_CREATE_DEVICE_ATTR(wlan); |
765 | static ASUS_CREATE_DEVICE_ATTR(bluetooth); | 765 | static ASUS_CREATE_DEVICE_ATTR(bluetooth); |
766 | static ASUS_CREATE_DEVICE_ATTR(display); | 766 | static ASUS_CREATE_DEVICE_ATTR(display); |
767 | static ASUS_CREATE_DEVICE_ATTR(ledd); | 767 | static ASUS_CREATE_DEVICE_ATTR(ledd); |
768 | static ASUS_CREATE_DEVICE_ATTR(ls_switch); | 768 | static ASUS_CREATE_DEVICE_ATTR(ls_switch); |
769 | static ASUS_CREATE_DEVICE_ATTR(ls_level); | 769 | static ASUS_CREATE_DEVICE_ATTR(ls_level); |
770 | static ASUS_CREATE_DEVICE_ATTR(gps); | 770 | static ASUS_CREATE_DEVICE_ATTR(gps); |
771 | 771 | ||
772 | static struct attribute *asuspf_attributes[] = { | 772 | static struct attribute *asuspf_attributes[] = { |
773 | &dev_attr_infos.attr, | 773 | &dev_attr_infos.attr, |
774 | &dev_attr_wlan.attr, | 774 | &dev_attr_wlan.attr, |
775 | &dev_attr_bluetooth.attr, | 775 | &dev_attr_bluetooth.attr, |
776 | &dev_attr_display.attr, | 776 | &dev_attr_display.attr, |
777 | &dev_attr_ledd.attr, | 777 | &dev_attr_ledd.attr, |
778 | &dev_attr_ls_switch.attr, | 778 | &dev_attr_ls_switch.attr, |
779 | &dev_attr_ls_level.attr, | 779 | &dev_attr_ls_level.attr, |
780 | &dev_attr_gps.attr, | 780 | &dev_attr_gps.attr, |
781 | NULL | 781 | NULL |
782 | }; | 782 | }; |
783 | 783 | ||
784 | static struct attribute_group asuspf_attribute_group = { | 784 | static struct attribute_group asuspf_attribute_group = { |
785 | .attrs = asuspf_attributes | 785 | .attrs = asuspf_attributes |
786 | }; | 786 | }; |
787 | 787 | ||
788 | static struct platform_driver asuspf_driver = { | 788 | static struct platform_driver asuspf_driver = { |
789 | .driver = { | 789 | .driver = { |
790 | .name = ASUS_HOTK_FILE, | 790 | .name = ASUS_HOTK_FILE, |
791 | .owner = THIS_MODULE, | 791 | .owner = THIS_MODULE, |
792 | } | 792 | } |
793 | }; | 793 | }; |
794 | 794 | ||
795 | static struct platform_device *asuspf_device; | 795 | static struct platform_device *asuspf_device; |
796 | 796 | ||
797 | static void asus_hotk_add_fs(void) | 797 | static void asus_hotk_add_fs(void) |
798 | { | 798 | { |
799 | ASUS_SET_DEVICE_ATTR(infos, 0444, show_infos, NULL); | 799 | ASUS_SET_DEVICE_ATTR(infos, 0444, show_infos, NULL); |
800 | 800 | ||
801 | if (wl_switch_handle) | 801 | if (wl_switch_handle) |
802 | ASUS_SET_DEVICE_ATTR(wlan, 0644, show_wlan, store_wlan); | 802 | ASUS_SET_DEVICE_ATTR(wlan, 0644, show_wlan, store_wlan); |
803 | 803 | ||
804 | if (bt_switch_handle) | 804 | if (bt_switch_handle) |
805 | ASUS_SET_DEVICE_ATTR(bluetooth, 0644, | 805 | ASUS_SET_DEVICE_ATTR(bluetooth, 0644, |
806 | show_bluetooth, store_bluetooth); | 806 | show_bluetooth, store_bluetooth); |
807 | 807 | ||
808 | if (display_set_handle && display_get_handle) | 808 | if (display_set_handle && display_get_handle) |
809 | ASUS_SET_DEVICE_ATTR(display, 0644, show_disp, store_disp); | 809 | ASUS_SET_DEVICE_ATTR(display, 0644, show_disp, store_disp); |
810 | else if (display_set_handle) | 810 | else if (display_set_handle) |
811 | ASUS_SET_DEVICE_ATTR(display, 0200, NULL, store_disp); | 811 | ASUS_SET_DEVICE_ATTR(display, 0200, NULL, store_disp); |
812 | 812 | ||
813 | if (ledd_set_handle) | 813 | if (ledd_set_handle) |
814 | ASUS_SET_DEVICE_ATTR(ledd, 0644, show_ledd, store_ledd); | 814 | ASUS_SET_DEVICE_ATTR(ledd, 0644, show_ledd, store_ledd); |
815 | 815 | ||
816 | if (ls_switch_handle && ls_level_handle) { | 816 | if (ls_switch_handle && ls_level_handle) { |
817 | ASUS_SET_DEVICE_ATTR(ls_level, 0644, show_lslvl, store_lslvl); | 817 | ASUS_SET_DEVICE_ATTR(ls_level, 0644, show_lslvl, store_lslvl); |
818 | ASUS_SET_DEVICE_ATTR(ls_switch, 0644, show_lssw, store_lssw); | 818 | ASUS_SET_DEVICE_ATTR(ls_switch, 0644, show_lssw, store_lssw); |
819 | } | 819 | } |
820 | 820 | ||
821 | if (gps_status_handle && gps_on_handle && gps_off_handle) | 821 | if (gps_status_handle && gps_on_handle && gps_off_handle) |
822 | ASUS_SET_DEVICE_ATTR(gps, 0644, show_gps, store_gps); | 822 | ASUS_SET_DEVICE_ATTR(gps, 0644, show_gps, store_gps); |
823 | } | 823 | } |
824 | 824 | ||
825 | static int asus_handle_init(char *name, acpi_handle * handle, | 825 | static int asus_handle_init(char *name, acpi_handle * handle, |
826 | char **paths, int num_paths) | 826 | char **paths, int num_paths) |
827 | { | 827 | { |
828 | int i; | 828 | int i; |
829 | acpi_status status; | 829 | acpi_status status; |
830 | 830 | ||
831 | for (i = 0; i < num_paths; i++) { | 831 | for (i = 0; i < num_paths; i++) { |
832 | status = acpi_get_handle(NULL, paths[i], handle); | 832 | status = acpi_get_handle(NULL, paths[i], handle); |
833 | if (ACPI_SUCCESS(status)) | 833 | if (ACPI_SUCCESS(status)) |
834 | return 0; | 834 | return 0; |
835 | } | 835 | } |
836 | 836 | ||
837 | *handle = NULL; | 837 | *handle = NULL; |
838 | return -ENODEV; | 838 | return -ENODEV; |
839 | } | 839 | } |
840 | 840 | ||
841 | #define ASUS_HANDLE_INIT(object) \ | 841 | #define ASUS_HANDLE_INIT(object) \ |
842 | asus_handle_init(#object, &object##_handle, object##_paths, \ | 842 | asus_handle_init(#object, &object##_handle, object##_paths, \ |
843 | ARRAY_SIZE(object##_paths)) | 843 | ARRAY_SIZE(object##_paths)) |
844 | 844 | ||
845 | /* | 845 | /* |
846 | * This function is used to initialize the hotk with right values. In this | 846 | * This function is used to initialize the hotk with right values. In this |
847 | * method, we can make all the detection we want, and modify the hotk struct | 847 | * method, we can make all the detection we want, and modify the hotk struct |
848 | */ | 848 | */ |
849 | static int asus_hotk_get_info(void) | 849 | static int asus_hotk_get_info(void) |
850 | { | 850 | { |
851 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | 851 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
852 | union acpi_object *model = NULL; | 852 | union acpi_object *model = NULL; |
853 | unsigned long long bsts_result, hwrs_result; | 853 | unsigned long long bsts_result, hwrs_result; |
854 | char *string = NULL; | 854 | char *string = NULL; |
855 | acpi_status status; | 855 | acpi_status status; |
856 | 856 | ||
857 | /* | 857 | /* |
858 | * Get DSDT headers early enough to allow for differentiating between | 858 | * Get DSDT headers early enough to allow for differentiating between |
859 | * models, but late enough to allow acpi_bus_register_driver() to fail | 859 | * models, but late enough to allow acpi_bus_register_driver() to fail |
860 | * before doing anything ACPI-specific. Should we encounter a machine, | 860 | * before doing anything ACPI-specific. Should we encounter a machine, |
861 | * which needs special handling (i.e. its hotkey device has a different | 861 | * which needs special handling (i.e. its hotkey device has a different |
862 | * HID), this bit will be moved. A global variable asus_info contains | 862 | * HID), this bit will be moved. A global variable asus_info contains |
863 | * the DSDT header. | 863 | * the DSDT header. |
864 | */ | 864 | */ |
865 | status = acpi_get_table(ACPI_SIG_DSDT, 1, &asus_info); | 865 | status = acpi_get_table(ACPI_SIG_DSDT, 1, &asus_info); |
866 | if (ACPI_FAILURE(status)) | 866 | if (ACPI_FAILURE(status)) |
867 | printk(ASUS_WARNING "Couldn't get the DSDT table header\n"); | 867 | printk(ASUS_WARNING "Couldn't get the DSDT table header\n"); |
868 | 868 | ||
869 | /* We have to write 0 on init this far for all ASUS models */ | 869 | /* We have to write 0 on init this far for all ASUS models */ |
870 | if (write_acpi_int(hotk->handle, "INIT", 0, &buffer)) { | 870 | if (write_acpi_int(hotk->handle, "INIT", 0, &buffer)) { |
871 | printk(ASUS_ERR "Hotkey initialization failed\n"); | 871 | printk(ASUS_ERR "Hotkey initialization failed\n"); |
872 | return -ENODEV; | 872 | return -ENODEV; |
873 | } | 873 | } |
874 | 874 | ||
875 | /* This needs to be called for some laptops to init properly */ | 875 | /* This needs to be called for some laptops to init properly */ |
876 | status = | 876 | status = |
877 | acpi_evaluate_integer(hotk->handle, "BSTS", NULL, &bsts_result); | 877 | acpi_evaluate_integer(hotk->handle, "BSTS", NULL, &bsts_result); |
878 | if (ACPI_FAILURE(status)) | 878 | if (ACPI_FAILURE(status)) |
879 | printk(ASUS_WARNING "Error calling BSTS\n"); | 879 | printk(ASUS_WARNING "Error calling BSTS\n"); |
880 | else if (bsts_result) | 880 | else if (bsts_result) |
881 | printk(ASUS_NOTICE "BSTS called, 0x%02x returned\n", | 881 | printk(ASUS_NOTICE "BSTS called, 0x%02x returned\n", |
882 | (uint) bsts_result); | 882 | (uint) bsts_result); |
883 | 883 | ||
884 | /* This too ... */ | 884 | /* This too ... */ |
885 | write_acpi_int(hotk->handle, "CWAP", wapf, NULL); | 885 | write_acpi_int(hotk->handle, "CWAP", wapf, NULL); |
886 | 886 | ||
887 | /* | 887 | /* |
888 | * Try to match the object returned by INIT to the specific model. | 888 | * Try to match the object returned by INIT to the specific model. |
889 | * Handle every possible object (or the lack of thereof) the DSDT | 889 | * Handle every possible object (or the lack of thereof) the DSDT |
890 | * writers might throw at us. When in trouble, we pass NULL to | 890 | * writers might throw at us. When in trouble, we pass NULL to |
891 | * asus_model_match() and try something completely different. | 891 | * asus_model_match() and try something completely different. |
892 | */ | 892 | */ |
893 | if (buffer.pointer) { | 893 | if (buffer.pointer) { |
894 | model = buffer.pointer; | 894 | model = buffer.pointer; |
895 | switch (model->type) { | 895 | switch (model->type) { |
896 | case ACPI_TYPE_STRING: | 896 | case ACPI_TYPE_STRING: |
897 | string = model->string.pointer; | 897 | string = model->string.pointer; |
898 | break; | 898 | break; |
899 | case ACPI_TYPE_BUFFER: | 899 | case ACPI_TYPE_BUFFER: |
900 | string = model->buffer.pointer; | 900 | string = model->buffer.pointer; |
901 | break; | 901 | break; |
902 | default: | 902 | default: |
903 | string = ""; | 903 | string = ""; |
904 | break; | 904 | break; |
905 | } | 905 | } |
906 | } | 906 | } |
907 | hotk->name = kstrdup(string, GFP_KERNEL); | 907 | hotk->name = kstrdup(string, GFP_KERNEL); |
908 | if (!hotk->name) | 908 | if (!hotk->name) |
909 | return -ENOMEM; | 909 | return -ENOMEM; |
910 | 910 | ||
911 | if (*string) | 911 | if (*string) |
912 | printk(ASUS_NOTICE " %s model detected\n", string); | 912 | printk(ASUS_NOTICE " %s model detected\n", string); |
913 | 913 | ||
914 | ASUS_HANDLE_INIT(mled_set); | 914 | ASUS_HANDLE_INIT(mled_set); |
915 | ASUS_HANDLE_INIT(tled_set); | 915 | ASUS_HANDLE_INIT(tled_set); |
916 | ASUS_HANDLE_INIT(rled_set); | 916 | ASUS_HANDLE_INIT(rled_set); |
917 | ASUS_HANDLE_INIT(pled_set); | 917 | ASUS_HANDLE_INIT(pled_set); |
918 | ASUS_HANDLE_INIT(gled_set); | 918 | ASUS_HANDLE_INIT(gled_set); |
919 | 919 | ||
920 | ASUS_HANDLE_INIT(ledd_set); | 920 | ASUS_HANDLE_INIT(ledd_set); |
921 | 921 | ||
922 | /* | 922 | /* |
923 | * The HWRS method return informations about the hardware. | 923 | * The HWRS method return informations about the hardware. |
924 | * 0x80 bit is for WLAN, 0x100 for Bluetooth. | 924 | * 0x80 bit is for WLAN, 0x100 for Bluetooth. |
925 | * The significance of others is yet to be found. | 925 | * The significance of others is yet to be found. |
926 | * If we don't find the method, we assume the device are present. | 926 | * If we don't find the method, we assume the device are present. |
927 | */ | 927 | */ |
928 | status = | 928 | status = |
929 | acpi_evaluate_integer(hotk->handle, "HRWS", NULL, &hwrs_result); | 929 | acpi_evaluate_integer(hotk->handle, "HRWS", NULL, &hwrs_result); |
930 | if (ACPI_FAILURE(status)) | 930 | if (ACPI_FAILURE(status)) |
931 | hwrs_result = WL_HWRS | BT_HWRS; | 931 | hwrs_result = WL_HWRS | BT_HWRS; |
932 | 932 | ||
933 | if (hwrs_result & WL_HWRS) | 933 | if (hwrs_result & WL_HWRS) |
934 | ASUS_HANDLE_INIT(wl_switch); | 934 | ASUS_HANDLE_INIT(wl_switch); |
935 | if (hwrs_result & BT_HWRS) | 935 | if (hwrs_result & BT_HWRS) |
936 | ASUS_HANDLE_INIT(bt_switch); | 936 | ASUS_HANDLE_INIT(bt_switch); |
937 | 937 | ||
938 | ASUS_HANDLE_INIT(wireless_status); | 938 | ASUS_HANDLE_INIT(wireless_status); |
939 | 939 | ||
940 | ASUS_HANDLE_INIT(brightness_set); | 940 | ASUS_HANDLE_INIT(brightness_set); |
941 | ASUS_HANDLE_INIT(brightness_get); | 941 | ASUS_HANDLE_INIT(brightness_get); |
942 | 942 | ||
943 | ASUS_HANDLE_INIT(lcd_switch); | 943 | ASUS_HANDLE_INIT(lcd_switch); |
944 | 944 | ||
945 | ASUS_HANDLE_INIT(display_set); | 945 | ASUS_HANDLE_INIT(display_set); |
946 | ASUS_HANDLE_INIT(display_get); | 946 | ASUS_HANDLE_INIT(display_get); |
947 | 947 | ||
948 | /* There is a lot of models with "ALSL", but a few get | 948 | /* There is a lot of models with "ALSL", but a few get |
949 | a real light sens, so we need to check it. */ | 949 | a real light sens, so we need to check it. */ |
950 | if (!ASUS_HANDLE_INIT(ls_switch)) | 950 | if (!ASUS_HANDLE_INIT(ls_switch)) |
951 | ASUS_HANDLE_INIT(ls_level); | 951 | ASUS_HANDLE_INIT(ls_level); |
952 | 952 | ||
953 | ASUS_HANDLE_INIT(gps_on); | 953 | ASUS_HANDLE_INIT(gps_on); |
954 | ASUS_HANDLE_INIT(gps_off); | 954 | ASUS_HANDLE_INIT(gps_off); |
955 | ASUS_HANDLE_INIT(gps_status); | 955 | ASUS_HANDLE_INIT(gps_status); |
956 | 956 | ||
957 | kfree(model); | 957 | kfree(model); |
958 | 958 | ||
959 | return AE_OK; | 959 | return AE_OK; |
960 | } | 960 | } |
961 | 961 | ||
962 | static int asus_hotk_check(void) | 962 | static int asus_hotk_check(void) |
963 | { | 963 | { |
964 | int result = 0; | 964 | int result = 0; |
965 | 965 | ||
966 | result = acpi_bus_get_status(hotk->device); | 966 | result = acpi_bus_get_status(hotk->device); |
967 | if (result) | 967 | if (result) |
968 | return result; | 968 | return result; |
969 | 969 | ||
970 | if (hotk->device->status.present) { | 970 | if (hotk->device->status.present) { |
971 | result = asus_hotk_get_info(); | 971 | result = asus_hotk_get_info(); |
972 | } else { | 972 | } else { |
973 | printk(ASUS_ERR "Hotkey device not present, aborting\n"); | 973 | printk(ASUS_ERR "Hotkey device not present, aborting\n"); |
974 | return -EINVAL; | 974 | return -EINVAL; |
975 | } | 975 | } |
976 | 976 | ||
977 | return result; | 977 | return result; |
978 | } | 978 | } |
979 | 979 | ||
980 | static int asus_hotk_found; | 980 | static int asus_hotk_found; |
981 | 981 | ||
982 | static int asus_hotk_add(struct acpi_device *device) | 982 | static int asus_hotk_add(struct acpi_device *device) |
983 | { | 983 | { |
984 | acpi_status status = AE_OK; | 984 | acpi_status status = AE_OK; |
985 | int result; | 985 | int result; |
986 | 986 | ||
987 | if (!device) | 987 | if (!device) |
988 | return -EINVAL; | 988 | return -EINVAL; |
989 | 989 | ||
990 | printk(ASUS_NOTICE "Asus Laptop Support version %s\n", | 990 | printk(ASUS_NOTICE "Asus Laptop Support version %s\n", |
991 | ASUS_LAPTOP_VERSION); | 991 | ASUS_LAPTOP_VERSION); |
992 | 992 | ||
993 | hotk = kzalloc(sizeof(struct asus_hotk), GFP_KERNEL); | 993 | hotk = kzalloc(sizeof(struct asus_hotk), GFP_KERNEL); |
994 | if (!hotk) | 994 | if (!hotk) |
995 | return -ENOMEM; | 995 | return -ENOMEM; |
996 | 996 | ||
997 | hotk->handle = device->handle; | 997 | hotk->handle = device->handle; |
998 | strcpy(acpi_device_name(device), ASUS_HOTK_DEVICE_NAME); | 998 | strcpy(acpi_device_name(device), ASUS_HOTK_DEVICE_NAME); |
999 | strcpy(acpi_device_class(device), ASUS_HOTK_CLASS); | 999 | strcpy(acpi_device_class(device), ASUS_HOTK_CLASS); |
1000 | device->driver_data = hotk; | 1000 | device->driver_data = hotk; |
1001 | hotk->device = device; | 1001 | hotk->device = device; |
1002 | 1002 | ||
1003 | result = asus_hotk_check(); | 1003 | result = asus_hotk_check(); |
1004 | if (result) | 1004 | if (result) |
1005 | goto end; | 1005 | goto end; |
1006 | 1006 | ||
1007 | asus_hotk_add_fs(); | 1007 | asus_hotk_add_fs(); |
1008 | 1008 | ||
1009 | /* | 1009 | /* |
1010 | * We install the handler, it will receive the hotk in parameter, so, we | 1010 | * We install the handler, it will receive the hotk in parameter, so, we |
1011 | * could add other data to the hotk struct | 1011 | * could add other data to the hotk struct |
1012 | */ | 1012 | */ |
1013 | status = acpi_install_notify_handler(hotk->handle, ACPI_ALL_NOTIFY, | 1013 | status = acpi_install_notify_handler(hotk->handle, ACPI_ALL_NOTIFY, |
1014 | asus_hotk_notify, hotk); | 1014 | asus_hotk_notify, hotk); |
1015 | if (ACPI_FAILURE(status)) | 1015 | if (ACPI_FAILURE(status)) |
1016 | printk(ASUS_ERR "Error installing notify handler\n"); | 1016 | printk(ASUS_ERR "Error installing notify handler\n"); |
1017 | 1017 | ||
1018 | asus_hotk_found = 1; | 1018 | asus_hotk_found = 1; |
1019 | 1019 | ||
1020 | /* WLED and BLED are on by default */ | 1020 | /* WLED and BLED are on by default */ |
1021 | write_status(bt_switch_handle, 1, BT_ON); | 1021 | write_status(bt_switch_handle, 1, BT_ON); |
1022 | write_status(wl_switch_handle, 1, WL_ON); | 1022 | write_status(wl_switch_handle, 1, WL_ON); |
1023 | 1023 | ||
1024 | /* If the h/w switch is off, we need to check the real status */ | 1024 | /* If the h/w switch is off, we need to check the real status */ |
1025 | write_status(NULL, read_status(BT_ON), BT_ON); | 1025 | write_status(NULL, read_status(BT_ON), BT_ON); |
1026 | write_status(NULL, read_status(WL_ON), WL_ON); | 1026 | write_status(NULL, read_status(WL_ON), WL_ON); |
1027 | 1027 | ||
1028 | /* LCD Backlight is on by default */ | 1028 | /* LCD Backlight is on by default */ |
1029 | write_status(NULL, 1, LCD_ON); | 1029 | write_status(NULL, 1, LCD_ON); |
1030 | 1030 | ||
1031 | /* LED display is off by default */ | 1031 | /* LED display is off by default */ |
1032 | hotk->ledd_status = 0xFFF; | 1032 | hotk->ledd_status = 0xFFF; |
1033 | 1033 | ||
1034 | /* Set initial values of light sensor and level */ | 1034 | /* Set initial values of light sensor and level */ |
1035 | hotk->light_switch = 1; /* Default to light sensor disabled */ | 1035 | hotk->light_switch = 1; /* Default to light sensor disabled */ |
1036 | hotk->light_level = 0; /* level 5 for sensor sensitivity */ | 1036 | hotk->light_level = 0; /* level 5 for sensor sensitivity */ |
1037 | 1037 | ||
1038 | if (ls_switch_handle) | 1038 | if (ls_switch_handle) |
1039 | set_light_sens_switch(hotk->light_switch); | 1039 | set_light_sens_switch(hotk->light_switch); |
1040 | 1040 | ||
1041 | if (ls_level_handle) | 1041 | if (ls_level_handle) |
1042 | set_light_sens_level(hotk->light_level); | 1042 | set_light_sens_level(hotk->light_level); |
1043 | 1043 | ||
1044 | /* GPS is on by default */ | 1044 | /* GPS is on by default */ |
1045 | write_status(NULL, 1, GPS_ON); | 1045 | write_status(NULL, 1, GPS_ON); |
1046 | 1046 | ||
1047 | end: | 1047 | end: |
1048 | if (result) { | 1048 | if (result) { |
1049 | kfree(hotk->name); | 1049 | kfree(hotk->name); |
1050 | kfree(hotk); | 1050 | kfree(hotk); |
1051 | } | 1051 | } |
1052 | 1052 | ||
1053 | return result; | 1053 | return result; |
1054 | } | 1054 | } |
1055 | 1055 | ||
1056 | static int asus_hotk_remove(struct acpi_device *device, int type) | 1056 | static int asus_hotk_remove(struct acpi_device *device, int type) |
1057 | { | 1057 | { |
1058 | acpi_status status = 0; | 1058 | acpi_status status = 0; |
1059 | 1059 | ||
1060 | if (!device || !acpi_driver_data(device)) | 1060 | if (!device || !acpi_driver_data(device)) |
1061 | return -EINVAL; | 1061 | return -EINVAL; |
1062 | 1062 | ||
1063 | status = acpi_remove_notify_handler(hotk->handle, ACPI_ALL_NOTIFY, | 1063 | status = acpi_remove_notify_handler(hotk->handle, ACPI_ALL_NOTIFY, |
1064 | asus_hotk_notify); | 1064 | asus_hotk_notify); |
1065 | if (ACPI_FAILURE(status)) | 1065 | if (ACPI_FAILURE(status)) |
1066 | printk(ASUS_ERR "Error removing notify handler\n"); | 1066 | printk(ASUS_ERR "Error removing notify handler\n"); |
1067 | 1067 | ||
1068 | kfree(hotk->name); | 1068 | kfree(hotk->name); |
1069 | kfree(hotk); | 1069 | kfree(hotk); |
1070 | 1070 | ||
1071 | return 0; | 1071 | return 0; |
1072 | } | 1072 | } |
1073 | 1073 | ||
1074 | static void asus_backlight_exit(void) | 1074 | static void asus_backlight_exit(void) |
1075 | { | 1075 | { |
1076 | if (asus_backlight_device) | 1076 | if (asus_backlight_device) |
1077 | backlight_device_unregister(asus_backlight_device); | 1077 | backlight_device_unregister(asus_backlight_device); |
1078 | } | 1078 | } |
1079 | 1079 | ||
1080 | #define ASUS_LED_UNREGISTER(object) \ | 1080 | #define ASUS_LED_UNREGISTER(object) \ |
1081 | if (object##_led.dev) \ | 1081 | if (object##_led.dev) \ |
1082 | led_classdev_unregister(&object##_led) | 1082 | led_classdev_unregister(&object##_led) |
1083 | 1083 | ||
1084 | static void asus_led_exit(void) | 1084 | static void asus_led_exit(void) |
1085 | { | 1085 | { |
1086 | destroy_workqueue(led_workqueue); | 1086 | destroy_workqueue(led_workqueue); |
1087 | ASUS_LED_UNREGISTER(mled); | 1087 | ASUS_LED_UNREGISTER(mled); |
1088 | ASUS_LED_UNREGISTER(tled); | 1088 | ASUS_LED_UNREGISTER(tled); |
1089 | ASUS_LED_UNREGISTER(pled); | 1089 | ASUS_LED_UNREGISTER(pled); |
1090 | ASUS_LED_UNREGISTER(rled); | 1090 | ASUS_LED_UNREGISTER(rled); |
1091 | ASUS_LED_UNREGISTER(gled); | 1091 | ASUS_LED_UNREGISTER(gled); |
1092 | } | 1092 | } |
1093 | 1093 | ||
1094 | static void __exit asus_laptop_exit(void) | 1094 | static void __exit asus_laptop_exit(void) |
1095 | { | 1095 | { |
1096 | asus_backlight_exit(); | 1096 | asus_backlight_exit(); |
1097 | asus_led_exit(); | 1097 | asus_led_exit(); |
1098 | 1098 | ||
1099 | acpi_bus_unregister_driver(&asus_hotk_driver); | 1099 | acpi_bus_unregister_driver(&asus_hotk_driver); |
1100 | sysfs_remove_group(&asuspf_device->dev.kobj, &asuspf_attribute_group); | 1100 | sysfs_remove_group(&asuspf_device->dev.kobj, &asuspf_attribute_group); |
1101 | platform_device_unregister(asuspf_device); | 1101 | platform_device_unregister(asuspf_device); |
1102 | platform_driver_unregister(&asuspf_driver); | 1102 | platform_driver_unregister(&asuspf_driver); |
1103 | } | 1103 | } |
1104 | 1104 | ||
1105 | static int asus_backlight_init(struct device *dev) | 1105 | static int asus_backlight_init(struct device *dev) |
1106 | { | 1106 | { |
1107 | struct backlight_device *bd; | 1107 | struct backlight_device *bd; |
1108 | 1108 | ||
1109 | if (brightness_set_handle && lcd_switch_handle) { | 1109 | if (brightness_set_handle && lcd_switch_handle) { |
1110 | bd = backlight_device_register(ASUS_HOTK_FILE, dev, | 1110 | bd = backlight_device_register(ASUS_HOTK_FILE, dev, |
1111 | NULL, &asusbl_ops); | 1111 | NULL, &asusbl_ops); |
1112 | if (IS_ERR(bd)) { | 1112 | if (IS_ERR(bd)) { |
1113 | printk(ASUS_ERR | 1113 | printk(ASUS_ERR |
1114 | "Could not register asus backlight device\n"); | 1114 | "Could not register asus backlight device\n"); |
1115 | asus_backlight_device = NULL; | 1115 | asus_backlight_device = NULL; |
1116 | return PTR_ERR(bd); | 1116 | return PTR_ERR(bd); |
1117 | } | 1117 | } |
1118 | 1118 | ||
1119 | asus_backlight_device = bd; | 1119 | asus_backlight_device = bd; |
1120 | 1120 | ||
1121 | bd->props.max_brightness = 15; | 1121 | bd->props.max_brightness = 15; |
1122 | bd->props.brightness = read_brightness(NULL); | 1122 | bd->props.brightness = read_brightness(NULL); |
1123 | bd->props.power = FB_BLANK_UNBLANK; | 1123 | bd->props.power = FB_BLANK_UNBLANK; |
1124 | backlight_update_status(bd); | 1124 | backlight_update_status(bd); |
1125 | } | 1125 | } |
1126 | return 0; | 1126 | return 0; |
1127 | } | 1127 | } |
1128 | 1128 | ||
1129 | static int asus_led_register(acpi_handle handle, | 1129 | static int asus_led_register(acpi_handle handle, |
1130 | struct led_classdev *ldev, struct device *dev) | 1130 | struct led_classdev *ldev, struct device *dev) |
1131 | { | 1131 | { |
1132 | if (!handle) | 1132 | if (!handle) |
1133 | return 0; | 1133 | return 0; |
1134 | 1134 | ||
1135 | return led_classdev_register(dev, ldev); | 1135 | return led_classdev_register(dev, ldev); |
1136 | } | 1136 | } |
1137 | 1137 | ||
1138 | #define ASUS_LED_REGISTER(object, device) \ | 1138 | #define ASUS_LED_REGISTER(object, device) \ |
1139 | asus_led_register(object##_set_handle, &object##_led, device) | 1139 | asus_led_register(object##_set_handle, &object##_led, device) |
1140 | 1140 | ||
1141 | static int asus_led_init(struct device *dev) | 1141 | static int asus_led_init(struct device *dev) |
1142 | { | 1142 | { |
1143 | int rv; | 1143 | int rv; |
1144 | 1144 | ||
1145 | rv = ASUS_LED_REGISTER(mled, dev); | 1145 | rv = ASUS_LED_REGISTER(mled, dev); |
1146 | if (rv) | 1146 | if (rv) |
1147 | goto out; | 1147 | goto out; |
1148 | 1148 | ||
1149 | rv = ASUS_LED_REGISTER(tled, dev); | 1149 | rv = ASUS_LED_REGISTER(tled, dev); |
1150 | if (rv) | 1150 | if (rv) |
1151 | goto out1; | 1151 | goto out1; |
1152 | 1152 | ||
1153 | rv = ASUS_LED_REGISTER(rled, dev); | 1153 | rv = ASUS_LED_REGISTER(rled, dev); |
1154 | if (rv) | 1154 | if (rv) |
1155 | goto out2; | 1155 | goto out2; |
1156 | 1156 | ||
1157 | rv = ASUS_LED_REGISTER(pled, dev); | 1157 | rv = ASUS_LED_REGISTER(pled, dev); |
1158 | if (rv) | 1158 | if (rv) |
1159 | goto out3; | 1159 | goto out3; |
1160 | 1160 | ||
1161 | rv = ASUS_LED_REGISTER(gled, dev); | 1161 | rv = ASUS_LED_REGISTER(gled, dev); |
1162 | if (rv) | 1162 | if (rv) |
1163 | goto out4; | 1163 | goto out4; |
1164 | 1164 | ||
1165 | led_workqueue = create_singlethread_workqueue("led_workqueue"); | 1165 | led_workqueue = create_singlethread_workqueue("led_workqueue"); |
1166 | if (!led_workqueue) | 1166 | if (!led_workqueue) |
1167 | goto out5; | 1167 | goto out5; |
1168 | 1168 | ||
1169 | return 0; | 1169 | return 0; |
1170 | out5: | 1170 | out5: |
1171 | rv = -ENOMEM; | 1171 | rv = -ENOMEM; |
1172 | ASUS_LED_UNREGISTER(gled); | 1172 | ASUS_LED_UNREGISTER(gled); |
1173 | out4: | 1173 | out4: |
1174 | ASUS_LED_UNREGISTER(pled); | 1174 | ASUS_LED_UNREGISTER(pled); |
1175 | out3: | 1175 | out3: |
1176 | ASUS_LED_UNREGISTER(rled); | 1176 | ASUS_LED_UNREGISTER(rled); |
1177 | out2: | 1177 | out2: |
1178 | ASUS_LED_UNREGISTER(tled); | 1178 | ASUS_LED_UNREGISTER(tled); |
1179 | out1: | 1179 | out1: |
1180 | ASUS_LED_UNREGISTER(mled); | 1180 | ASUS_LED_UNREGISTER(mled); |
1181 | out: | 1181 | out: |
1182 | return rv; | 1182 | return rv; |
1183 | } | 1183 | } |
1184 | 1184 | ||
1185 | static int __init asus_laptop_init(void) | 1185 | static int __init asus_laptop_init(void) |
1186 | { | 1186 | { |
1187 | struct device *dev; | 1187 | struct device *dev; |
1188 | int result; | 1188 | int result; |
1189 | 1189 | ||
1190 | if (acpi_disabled) | 1190 | if (acpi_disabled) |
1191 | return -ENODEV; | 1191 | return -ENODEV; |
1192 | 1192 | ||
1193 | result = acpi_bus_register_driver(&asus_hotk_driver); | 1193 | result = acpi_bus_register_driver(&asus_hotk_driver); |
1194 | if (result < 0) | 1194 | if (result < 0) |
1195 | return result; | 1195 | return result; |
1196 | 1196 | ||
1197 | /* | 1197 | /* |
1198 | * This is a bit of a kludge. We only want this module loaded | 1198 | * This is a bit of a kludge. We only want this module loaded |
1199 | * for ASUS systems, but there's currently no way to probe the | 1199 | * for ASUS systems, but there's currently no way to probe the |
1200 | * ACPI namespace for ASUS HIDs. So we just return failure if | 1200 | * ACPI namespace for ASUS HIDs. So we just return failure if |
1201 | * we didn't find one, which will cause the module to be | 1201 | * we didn't find one, which will cause the module to be |
1202 | * unloaded. | 1202 | * unloaded. |
1203 | */ | 1203 | */ |
1204 | if (!asus_hotk_found) { | 1204 | if (!asus_hotk_found) { |
1205 | acpi_bus_unregister_driver(&asus_hotk_driver); | 1205 | acpi_bus_unregister_driver(&asus_hotk_driver); |
1206 | return -ENODEV; | 1206 | return -ENODEV; |
1207 | } | 1207 | } |
1208 | 1208 | ||
1209 | dev = acpi_get_physical_device(hotk->device->handle); | 1209 | dev = acpi_get_physical_device(hotk->device->handle); |
1210 | 1210 | ||
1211 | result = asus_backlight_init(dev); | 1211 | if (!acpi_video_backlight_support()) { |
1212 | if (result) | 1212 | result = asus_backlight_init(dev); |
1213 | goto fail_backlight; | 1213 | if (result) |
1214 | goto fail_backlight; | ||
1215 | } else | ||
1216 | printk(ASUS_INFO "Brightness ignored, must be controlled by " | ||
1217 | "ACPI video driver\n"); | ||
1214 | 1218 | ||
1215 | result = asus_led_init(dev); | 1219 | result = asus_led_init(dev); |
1216 | if (result) | 1220 | if (result) |
1217 | goto fail_led; | 1221 | goto fail_led; |
1218 | 1222 | ||
1219 | /* Register platform stuff */ | 1223 | /* Register platform stuff */ |
1220 | result = platform_driver_register(&asuspf_driver); | 1224 | result = platform_driver_register(&asuspf_driver); |
1221 | if (result) | 1225 | if (result) |
1222 | goto fail_platform_driver; | 1226 | goto fail_platform_driver; |
1223 | 1227 | ||
1224 | asuspf_device = platform_device_alloc(ASUS_HOTK_FILE, -1); | 1228 | asuspf_device = platform_device_alloc(ASUS_HOTK_FILE, -1); |
1225 | if (!asuspf_device) { | 1229 | if (!asuspf_device) { |
1226 | result = -ENOMEM; | 1230 | result = -ENOMEM; |
1227 | goto fail_platform_device1; | 1231 | goto fail_platform_device1; |
1228 | } | 1232 | } |
1229 | 1233 | ||
1230 | result = platform_device_add(asuspf_device); | 1234 | result = platform_device_add(asuspf_device); |
1231 | if (result) | 1235 | if (result) |
1232 | goto fail_platform_device2; | 1236 | goto fail_platform_device2; |
1233 | 1237 | ||
1234 | result = sysfs_create_group(&asuspf_device->dev.kobj, | 1238 | result = sysfs_create_group(&asuspf_device->dev.kobj, |
1235 | &asuspf_attribute_group); | 1239 | &asuspf_attribute_group); |
1236 | if (result) | 1240 | if (result) |
1237 | goto fail_sysfs; | 1241 | goto fail_sysfs; |
1238 | 1242 | ||
1239 | return 0; | 1243 | return 0; |
1240 | 1244 | ||
1241 | fail_sysfs: | 1245 | fail_sysfs: |
1242 | platform_device_del(asuspf_device); | 1246 | platform_device_del(asuspf_device); |
1243 | 1247 | ||
1244 | fail_platform_device2: | 1248 | fail_platform_device2: |
1245 | platform_device_put(asuspf_device); | 1249 | platform_device_put(asuspf_device); |
1246 | 1250 | ||
1247 | fail_platform_device1: | 1251 | fail_platform_device1: |
1248 | platform_driver_unregister(&asuspf_driver); | 1252 | platform_driver_unregister(&asuspf_driver); |
1249 | 1253 | ||
1250 | fail_platform_driver: | 1254 | fail_platform_driver: |
1251 | asus_led_exit(); | 1255 | asus_led_exit(); |
1252 | 1256 | ||
1253 | fail_led: | 1257 | fail_led: |
1254 | asus_backlight_exit(); | 1258 | asus_backlight_exit(); |
1255 | 1259 | ||
1256 | fail_backlight: | 1260 | fail_backlight: |
1257 | 1261 | ||
1258 | return result; | 1262 | return result; |
1259 | } | 1263 | } |
1260 | 1264 | ||
1261 | module_init(asus_laptop_init); | 1265 | module_init(asus_laptop_init); |
1262 | module_exit(asus_laptop_exit); | 1266 | module_exit(asus_laptop_exit); |
1263 | 1267 |
drivers/misc/compal-laptop.c
1 | /*-*-linux-c-*-*/ | 1 | /*-*-linux-c-*-*/ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | Copyright (C) 2008 Cezary Jackiewicz <cezary.jackiewicz (at) gmail.com> | 4 | Copyright (C) 2008 Cezary Jackiewicz <cezary.jackiewicz (at) gmail.com> |
5 | 5 | ||
6 | based on MSI driver | 6 | based on MSI driver |
7 | 7 | ||
8 | Copyright (C) 2006 Lennart Poettering <mzxreary (at) 0pointer (dot) de> | 8 | Copyright (C) 2006 Lennart Poettering <mzxreary (at) 0pointer (dot) de> |
9 | 9 | ||
10 | This program is free software; you can redistribute it and/or modify | 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 | 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 | 12 | the Free Software Foundation; either version 2 of the License, or |
13 | (at your option) any later version. | 13 | (at your option) any later version. |
14 | 14 | ||
15 | This program is distributed in the hope that it will be useful, but | 15 | This program is distributed in the hope that it will be useful, but |
16 | WITHOUT ANY WARRANTY; without even the implied warranty of | 16 | WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
18 | General Public License for more details. | 18 | General Public License for more details. |
19 | 19 | ||
20 | You should have received a copy of the GNU General Public License | 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 | 21 | along with this program; if not, write to the Free Software |
22 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | 22 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
23 | 02110-1301, USA. | 23 | 02110-1301, USA. |
24 | */ | 24 | */ |
25 | 25 | ||
26 | /* | 26 | /* |
27 | * comapl-laptop.c - Compal laptop support. | 27 | * comapl-laptop.c - Compal laptop support. |
28 | * | 28 | * |
29 | * This driver exports a few files in /sys/devices/platform/compal-laptop/: | 29 | * This driver exports a few files in /sys/devices/platform/compal-laptop/: |
30 | * | 30 | * |
31 | * wlan - wlan subsystem state: contains 0 or 1 (rw) | 31 | * wlan - wlan subsystem state: contains 0 or 1 (rw) |
32 | * | 32 | * |
33 | * bluetooth - Bluetooth subsystem state: contains 0 or 1 (rw) | 33 | * bluetooth - Bluetooth subsystem state: contains 0 or 1 (rw) |
34 | * | 34 | * |
35 | * raw - raw value taken from embedded controller register (ro) | 35 | * raw - raw value taken from embedded controller register (ro) |
36 | * | 36 | * |
37 | * In addition to these platform device attributes the driver | 37 | * In addition to these platform device attributes the driver |
38 | * registers itself in the Linux backlight control subsystem and is | 38 | * registers itself in the Linux backlight control subsystem and is |
39 | * available to userspace under /sys/class/backlight/compal-laptop/. | 39 | * available to userspace under /sys/class/backlight/compal-laptop/. |
40 | * | 40 | * |
41 | * This driver might work on other laptops produced by Compal. If you | 41 | * This driver might work on other laptops produced by Compal. If you |
42 | * want to try it you can pass force=1 as argument to the module which | 42 | * want to try it you can pass force=1 as argument to the module which |
43 | * will force it to load even when the DMI data doesn't identify the | 43 | * will force it to load even when the DMI data doesn't identify the |
44 | * laptop as FL9x. | 44 | * laptop as FL9x. |
45 | */ | 45 | */ |
46 | 46 | ||
47 | #include <linux/module.h> | 47 | #include <linux/module.h> |
48 | #include <linux/kernel.h> | 48 | #include <linux/kernel.h> |
49 | #include <linux/init.h> | 49 | #include <linux/init.h> |
50 | #include <linux/acpi.h> | 50 | #include <linux/acpi.h> |
51 | #include <linux/dmi.h> | 51 | #include <linux/dmi.h> |
52 | #include <linux/backlight.h> | 52 | #include <linux/backlight.h> |
53 | #include <linux/platform_device.h> | 53 | #include <linux/platform_device.h> |
54 | #include <linux/autoconf.h> | 54 | #include <linux/autoconf.h> |
55 | 55 | ||
56 | #define COMPAL_DRIVER_VERSION "0.2.6" | 56 | #define COMPAL_DRIVER_VERSION "0.2.6" |
57 | 57 | ||
58 | #define COMPAL_LCD_LEVEL_MAX 8 | 58 | #define COMPAL_LCD_LEVEL_MAX 8 |
59 | 59 | ||
60 | #define COMPAL_EC_COMMAND_WIRELESS 0xBB | 60 | #define COMPAL_EC_COMMAND_WIRELESS 0xBB |
61 | #define COMPAL_EC_COMMAND_LCD_LEVEL 0xB9 | 61 | #define COMPAL_EC_COMMAND_LCD_LEVEL 0xB9 |
62 | 62 | ||
63 | #define KILLSWITCH_MASK 0x10 | 63 | #define KILLSWITCH_MASK 0x10 |
64 | #define WLAN_MASK 0x01 | 64 | #define WLAN_MASK 0x01 |
65 | #define BT_MASK 0x02 | 65 | #define BT_MASK 0x02 |
66 | 66 | ||
67 | static int force; | 67 | static int force; |
68 | module_param(force, bool, 0); | 68 | module_param(force, bool, 0); |
69 | MODULE_PARM_DESC(force, "Force driver load, ignore DMI data"); | 69 | MODULE_PARM_DESC(force, "Force driver load, ignore DMI data"); |
70 | 70 | ||
71 | /* Hardware access */ | 71 | /* Hardware access */ |
72 | 72 | ||
73 | static int set_lcd_level(int level) | 73 | static int set_lcd_level(int level) |
74 | { | 74 | { |
75 | if (level < 0 || level >= COMPAL_LCD_LEVEL_MAX) | 75 | if (level < 0 || level >= COMPAL_LCD_LEVEL_MAX) |
76 | return -EINVAL; | 76 | return -EINVAL; |
77 | 77 | ||
78 | ec_write(COMPAL_EC_COMMAND_LCD_LEVEL, level); | 78 | ec_write(COMPAL_EC_COMMAND_LCD_LEVEL, level); |
79 | 79 | ||
80 | return 0; | 80 | return 0; |
81 | } | 81 | } |
82 | 82 | ||
83 | static int get_lcd_level(void) | 83 | static int get_lcd_level(void) |
84 | { | 84 | { |
85 | u8 result; | 85 | u8 result; |
86 | 86 | ||
87 | ec_read(COMPAL_EC_COMMAND_LCD_LEVEL, &result); | 87 | ec_read(COMPAL_EC_COMMAND_LCD_LEVEL, &result); |
88 | 88 | ||
89 | return (int) result; | 89 | return (int) result; |
90 | } | 90 | } |
91 | 91 | ||
92 | static int set_wlan_state(int state) | 92 | static int set_wlan_state(int state) |
93 | { | 93 | { |
94 | u8 result, value; | 94 | u8 result, value; |
95 | 95 | ||
96 | ec_read(COMPAL_EC_COMMAND_WIRELESS, &result); | 96 | ec_read(COMPAL_EC_COMMAND_WIRELESS, &result); |
97 | 97 | ||
98 | if ((result & KILLSWITCH_MASK) == 0) | 98 | if ((result & KILLSWITCH_MASK) == 0) |
99 | return -EINVAL; | 99 | return -EINVAL; |
100 | else { | 100 | else { |
101 | if (state) | 101 | if (state) |
102 | value = (u8) (result | WLAN_MASK); | 102 | value = (u8) (result | WLAN_MASK); |
103 | else | 103 | else |
104 | value = (u8) (result & ~WLAN_MASK); | 104 | value = (u8) (result & ~WLAN_MASK); |
105 | ec_write(COMPAL_EC_COMMAND_WIRELESS, value); | 105 | ec_write(COMPAL_EC_COMMAND_WIRELESS, value); |
106 | } | 106 | } |
107 | 107 | ||
108 | return 0; | 108 | return 0; |
109 | } | 109 | } |
110 | 110 | ||
111 | static int set_bluetooth_state(int state) | 111 | static int set_bluetooth_state(int state) |
112 | { | 112 | { |
113 | u8 result, value; | 113 | u8 result, value; |
114 | 114 | ||
115 | ec_read(COMPAL_EC_COMMAND_WIRELESS, &result); | 115 | ec_read(COMPAL_EC_COMMAND_WIRELESS, &result); |
116 | 116 | ||
117 | if ((result & KILLSWITCH_MASK) == 0) | 117 | if ((result & KILLSWITCH_MASK) == 0) |
118 | return -EINVAL; | 118 | return -EINVAL; |
119 | else { | 119 | else { |
120 | if (state) | 120 | if (state) |
121 | value = (u8) (result | BT_MASK); | 121 | value = (u8) (result | BT_MASK); |
122 | else | 122 | else |
123 | value = (u8) (result & ~BT_MASK); | 123 | value = (u8) (result & ~BT_MASK); |
124 | ec_write(COMPAL_EC_COMMAND_WIRELESS, value); | 124 | ec_write(COMPAL_EC_COMMAND_WIRELESS, value); |
125 | } | 125 | } |
126 | 126 | ||
127 | return 0; | 127 | return 0; |
128 | } | 128 | } |
129 | 129 | ||
130 | static int get_wireless_state(int *wlan, int *bluetooth) | 130 | static int get_wireless_state(int *wlan, int *bluetooth) |
131 | { | 131 | { |
132 | u8 result; | 132 | u8 result; |
133 | 133 | ||
134 | ec_read(COMPAL_EC_COMMAND_WIRELESS, &result); | 134 | ec_read(COMPAL_EC_COMMAND_WIRELESS, &result); |
135 | 135 | ||
136 | if (wlan) { | 136 | if (wlan) { |
137 | if ((result & KILLSWITCH_MASK) == 0) | 137 | if ((result & KILLSWITCH_MASK) == 0) |
138 | *wlan = 0; | 138 | *wlan = 0; |
139 | else | 139 | else |
140 | *wlan = result & WLAN_MASK; | 140 | *wlan = result & WLAN_MASK; |
141 | } | 141 | } |
142 | 142 | ||
143 | if (bluetooth) { | 143 | if (bluetooth) { |
144 | if ((result & KILLSWITCH_MASK) == 0) | 144 | if ((result & KILLSWITCH_MASK) == 0) |
145 | *bluetooth = 0; | 145 | *bluetooth = 0; |
146 | else | 146 | else |
147 | *bluetooth = (result & BT_MASK) >> 1; | 147 | *bluetooth = (result & BT_MASK) >> 1; |
148 | } | 148 | } |
149 | 149 | ||
150 | return 0; | 150 | return 0; |
151 | } | 151 | } |
152 | 152 | ||
153 | /* Backlight device stuff */ | 153 | /* Backlight device stuff */ |
154 | 154 | ||
155 | static int bl_get_brightness(struct backlight_device *b) | 155 | static int bl_get_brightness(struct backlight_device *b) |
156 | { | 156 | { |
157 | return get_lcd_level(); | 157 | return get_lcd_level(); |
158 | } | 158 | } |
159 | 159 | ||
160 | 160 | ||
161 | static int bl_update_status(struct backlight_device *b) | 161 | static int bl_update_status(struct backlight_device *b) |
162 | { | 162 | { |
163 | return set_lcd_level(b->props.brightness); | 163 | return set_lcd_level(b->props.brightness); |
164 | } | 164 | } |
165 | 165 | ||
166 | static struct backlight_ops compalbl_ops = { | 166 | static struct backlight_ops compalbl_ops = { |
167 | .get_brightness = bl_get_brightness, | 167 | .get_brightness = bl_get_brightness, |
168 | .update_status = bl_update_status, | 168 | .update_status = bl_update_status, |
169 | }; | 169 | }; |
170 | 170 | ||
171 | static struct backlight_device *compalbl_device; | 171 | static struct backlight_device *compalbl_device; |
172 | 172 | ||
173 | /* Platform device */ | 173 | /* Platform device */ |
174 | 174 | ||
175 | static ssize_t show_wlan(struct device *dev, | 175 | static ssize_t show_wlan(struct device *dev, |
176 | struct device_attribute *attr, char *buf) | 176 | struct device_attribute *attr, char *buf) |
177 | { | 177 | { |
178 | int ret, enabled; | 178 | int ret, enabled; |
179 | 179 | ||
180 | ret = get_wireless_state(&enabled, NULL); | 180 | ret = get_wireless_state(&enabled, NULL); |
181 | if (ret < 0) | 181 | if (ret < 0) |
182 | return ret; | 182 | return ret; |
183 | 183 | ||
184 | return sprintf(buf, "%i\n", enabled); | 184 | return sprintf(buf, "%i\n", enabled); |
185 | } | 185 | } |
186 | 186 | ||
187 | static ssize_t show_raw(struct device *dev, | 187 | static ssize_t show_raw(struct device *dev, |
188 | struct device_attribute *attr, char *buf) | 188 | struct device_attribute *attr, char *buf) |
189 | { | 189 | { |
190 | u8 result; | 190 | u8 result; |
191 | 191 | ||
192 | ec_read(COMPAL_EC_COMMAND_WIRELESS, &result); | 192 | ec_read(COMPAL_EC_COMMAND_WIRELESS, &result); |
193 | 193 | ||
194 | return sprintf(buf, "%i\n", result); | 194 | return sprintf(buf, "%i\n", result); |
195 | } | 195 | } |
196 | 196 | ||
197 | static ssize_t show_bluetooth(struct device *dev, | 197 | static ssize_t show_bluetooth(struct device *dev, |
198 | struct device_attribute *attr, char *buf) | 198 | struct device_attribute *attr, char *buf) |
199 | { | 199 | { |
200 | int ret, enabled; | 200 | int ret, enabled; |
201 | 201 | ||
202 | ret = get_wireless_state(NULL, &enabled); | 202 | ret = get_wireless_state(NULL, &enabled); |
203 | if (ret < 0) | 203 | if (ret < 0) |
204 | return ret; | 204 | return ret; |
205 | 205 | ||
206 | return sprintf(buf, "%i\n", enabled); | 206 | return sprintf(buf, "%i\n", enabled); |
207 | } | 207 | } |
208 | 208 | ||
209 | static ssize_t store_wlan_state(struct device *dev, | 209 | static ssize_t store_wlan_state(struct device *dev, |
210 | struct device_attribute *attr, const char *buf, size_t count) | 210 | struct device_attribute *attr, const char *buf, size_t count) |
211 | { | 211 | { |
212 | int state, ret; | 212 | int state, ret; |
213 | 213 | ||
214 | if (sscanf(buf, "%i", &state) != 1 || (state < 0 || state > 1)) | 214 | if (sscanf(buf, "%i", &state) != 1 || (state < 0 || state > 1)) |
215 | return -EINVAL; | 215 | return -EINVAL; |
216 | 216 | ||
217 | ret = set_wlan_state(state); | 217 | ret = set_wlan_state(state); |
218 | if (ret < 0) | 218 | if (ret < 0) |
219 | return ret; | 219 | return ret; |
220 | 220 | ||
221 | return count; | 221 | return count; |
222 | } | 222 | } |
223 | 223 | ||
224 | static ssize_t store_bluetooth_state(struct device *dev, | 224 | static ssize_t store_bluetooth_state(struct device *dev, |
225 | struct device_attribute *attr, const char *buf, size_t count) | 225 | struct device_attribute *attr, const char *buf, size_t count) |
226 | { | 226 | { |
227 | int state, ret; | 227 | int state, ret; |
228 | 228 | ||
229 | if (sscanf(buf, "%i", &state) != 1 || (state < 0 || state > 1)) | 229 | if (sscanf(buf, "%i", &state) != 1 || (state < 0 || state > 1)) |
230 | return -EINVAL; | 230 | return -EINVAL; |
231 | 231 | ||
232 | ret = set_bluetooth_state(state); | 232 | ret = set_bluetooth_state(state); |
233 | if (ret < 0) | 233 | if (ret < 0) |
234 | return ret; | 234 | return ret; |
235 | 235 | ||
236 | return count; | 236 | return count; |
237 | } | 237 | } |
238 | 238 | ||
239 | static DEVICE_ATTR(bluetooth, 0644, show_bluetooth, store_bluetooth_state); | 239 | static DEVICE_ATTR(bluetooth, 0644, show_bluetooth, store_bluetooth_state); |
240 | static DEVICE_ATTR(wlan, 0644, show_wlan, store_wlan_state); | 240 | static DEVICE_ATTR(wlan, 0644, show_wlan, store_wlan_state); |
241 | static DEVICE_ATTR(raw, 0444, show_raw, NULL); | 241 | static DEVICE_ATTR(raw, 0444, show_raw, NULL); |
242 | 242 | ||
243 | static struct attribute *compal_attributes[] = { | 243 | static struct attribute *compal_attributes[] = { |
244 | &dev_attr_bluetooth.attr, | 244 | &dev_attr_bluetooth.attr, |
245 | &dev_attr_wlan.attr, | 245 | &dev_attr_wlan.attr, |
246 | &dev_attr_raw.attr, | 246 | &dev_attr_raw.attr, |
247 | NULL | 247 | NULL |
248 | }; | 248 | }; |
249 | 249 | ||
250 | static struct attribute_group compal_attribute_group = { | 250 | static struct attribute_group compal_attribute_group = { |
251 | .attrs = compal_attributes | 251 | .attrs = compal_attributes |
252 | }; | 252 | }; |
253 | 253 | ||
254 | static struct platform_driver compal_driver = { | 254 | static struct platform_driver compal_driver = { |
255 | .driver = { | 255 | .driver = { |
256 | .name = "compal-laptop", | 256 | .name = "compal-laptop", |
257 | .owner = THIS_MODULE, | 257 | .owner = THIS_MODULE, |
258 | } | 258 | } |
259 | }; | 259 | }; |
260 | 260 | ||
261 | static struct platform_device *compal_device; | 261 | static struct platform_device *compal_device; |
262 | 262 | ||
263 | /* Initialization */ | 263 | /* Initialization */ |
264 | 264 | ||
265 | static int dmi_check_cb(const struct dmi_system_id *id) | 265 | static int dmi_check_cb(const struct dmi_system_id *id) |
266 | { | 266 | { |
267 | printk(KERN_INFO "compal-laptop: Identified laptop model '%s'.\n", | 267 | printk(KERN_INFO "compal-laptop: Identified laptop model '%s'.\n", |
268 | id->ident); | 268 | id->ident); |
269 | 269 | ||
270 | return 0; | 270 | return 0; |
271 | } | 271 | } |
272 | 272 | ||
273 | static struct dmi_system_id __initdata compal_dmi_table[] = { | 273 | static struct dmi_system_id __initdata compal_dmi_table[] = { |
274 | { | 274 | { |
275 | .ident = "FL90/IFL90", | 275 | .ident = "FL90/IFL90", |
276 | .matches = { | 276 | .matches = { |
277 | DMI_MATCH(DMI_BOARD_NAME, "IFL90"), | 277 | DMI_MATCH(DMI_BOARD_NAME, "IFL90"), |
278 | DMI_MATCH(DMI_BOARD_VERSION, "IFT00"), | 278 | DMI_MATCH(DMI_BOARD_VERSION, "IFT00"), |
279 | }, | 279 | }, |
280 | .callback = dmi_check_cb | 280 | .callback = dmi_check_cb |
281 | }, | 281 | }, |
282 | { | 282 | { |
283 | .ident = "FL90/IFL90", | 283 | .ident = "FL90/IFL90", |
284 | .matches = { | 284 | .matches = { |
285 | DMI_MATCH(DMI_BOARD_NAME, "IFL90"), | 285 | DMI_MATCH(DMI_BOARD_NAME, "IFL90"), |
286 | DMI_MATCH(DMI_BOARD_VERSION, "REFERENCE"), | 286 | DMI_MATCH(DMI_BOARD_VERSION, "REFERENCE"), |
287 | }, | 287 | }, |
288 | .callback = dmi_check_cb | 288 | .callback = dmi_check_cb |
289 | }, | 289 | }, |
290 | { | 290 | { |
291 | .ident = "FL91/IFL91", | 291 | .ident = "FL91/IFL91", |
292 | .matches = { | 292 | .matches = { |
293 | DMI_MATCH(DMI_BOARD_NAME, "IFL91"), | 293 | DMI_MATCH(DMI_BOARD_NAME, "IFL91"), |
294 | DMI_MATCH(DMI_BOARD_VERSION, "IFT00"), | 294 | DMI_MATCH(DMI_BOARD_VERSION, "IFT00"), |
295 | }, | 295 | }, |
296 | .callback = dmi_check_cb | 296 | .callback = dmi_check_cb |
297 | }, | 297 | }, |
298 | { | 298 | { |
299 | .ident = "FL92/JFL92", | 299 | .ident = "FL92/JFL92", |
300 | .matches = { | 300 | .matches = { |
301 | DMI_MATCH(DMI_BOARD_NAME, "JFL92"), | 301 | DMI_MATCH(DMI_BOARD_NAME, "JFL92"), |
302 | DMI_MATCH(DMI_BOARD_VERSION, "IFT00"), | 302 | DMI_MATCH(DMI_BOARD_VERSION, "IFT00"), |
303 | }, | 303 | }, |
304 | .callback = dmi_check_cb | 304 | .callback = dmi_check_cb |
305 | }, | 305 | }, |
306 | { | 306 | { |
307 | .ident = "FT00/IFT00", | 307 | .ident = "FT00/IFT00", |
308 | .matches = { | 308 | .matches = { |
309 | DMI_MATCH(DMI_BOARD_NAME, "IFT00"), | 309 | DMI_MATCH(DMI_BOARD_NAME, "IFT00"), |
310 | DMI_MATCH(DMI_BOARD_VERSION, "IFT00"), | 310 | DMI_MATCH(DMI_BOARD_VERSION, "IFT00"), |
311 | }, | 311 | }, |
312 | .callback = dmi_check_cb | 312 | .callback = dmi_check_cb |
313 | }, | 313 | }, |
314 | { } | 314 | { } |
315 | }; | 315 | }; |
316 | 316 | ||
317 | static int __init compal_init(void) | 317 | static int __init compal_init(void) |
318 | { | 318 | { |
319 | int ret; | 319 | int ret; |
320 | 320 | ||
321 | if (acpi_disabled) | 321 | if (acpi_disabled) |
322 | return -ENODEV; | 322 | return -ENODEV; |
323 | 323 | ||
324 | if (!force && !dmi_check_system(compal_dmi_table)) | 324 | if (!force && !dmi_check_system(compal_dmi_table)) |
325 | return -ENODEV; | 325 | return -ENODEV; |
326 | 326 | ||
327 | /* Register backlight stuff */ | 327 | /* Register backlight stuff */ |
328 | 328 | ||
329 | compalbl_device = backlight_device_register("compal-laptop", NULL, NULL, | 329 | if (!acpi_video_backlight_support()) { |
330 | &compalbl_ops); | 330 | compalbl_device = backlight_device_register("compal-laptop", NULL, NULL, |
331 | if (IS_ERR(compalbl_device)) | 331 | &compalbl_ops); |
332 | return PTR_ERR(compalbl_device); | 332 | if (IS_ERR(compalbl_device)) |
333 | return PTR_ERR(compalbl_device); | ||
333 | 334 | ||
334 | compalbl_device->props.max_brightness = COMPAL_LCD_LEVEL_MAX-1; | 335 | compalbl_device->props.max_brightness = COMPAL_LCD_LEVEL_MAX-1; |
336 | } | ||
335 | 337 | ||
336 | ret = platform_driver_register(&compal_driver); | 338 | ret = platform_driver_register(&compal_driver); |
337 | if (ret) | 339 | if (ret) |
338 | goto fail_backlight; | 340 | goto fail_backlight; |
339 | 341 | ||
340 | /* Register platform stuff */ | 342 | /* Register platform stuff */ |
341 | 343 | ||
342 | compal_device = platform_device_alloc("compal-laptop", -1); | 344 | compal_device = platform_device_alloc("compal-laptop", -1); |
343 | if (!compal_device) { | 345 | if (!compal_device) { |
344 | ret = -ENOMEM; | 346 | ret = -ENOMEM; |
345 | goto fail_platform_driver; | 347 | goto fail_platform_driver; |
346 | } | 348 | } |
347 | 349 | ||
348 | ret = platform_device_add(compal_device); | 350 | ret = platform_device_add(compal_device); |
349 | if (ret) | 351 | if (ret) |
350 | goto fail_platform_device1; | 352 | goto fail_platform_device1; |
351 | 353 | ||
352 | ret = sysfs_create_group(&compal_device->dev.kobj, | 354 | ret = sysfs_create_group(&compal_device->dev.kobj, |
353 | &compal_attribute_group); | 355 | &compal_attribute_group); |
354 | if (ret) | 356 | if (ret) |
355 | goto fail_platform_device2; | 357 | goto fail_platform_device2; |
356 | 358 | ||
357 | printk(KERN_INFO "compal-laptop: driver "COMPAL_DRIVER_VERSION | 359 | printk(KERN_INFO "compal-laptop: driver "COMPAL_DRIVER_VERSION |
358 | " successfully loaded.\n"); | 360 | " successfully loaded.\n"); |
359 | 361 | ||
360 | return 0; | 362 | return 0; |
361 | 363 | ||
362 | fail_platform_device2: | 364 | fail_platform_device2: |
363 | 365 | ||
364 | platform_device_del(compal_device); | 366 | platform_device_del(compal_device); |
365 | 367 | ||
366 | fail_platform_device1: | 368 | fail_platform_device1: |
367 | 369 | ||
368 | platform_device_put(compal_device); | 370 | platform_device_put(compal_device); |
369 | 371 | ||
370 | fail_platform_driver: | 372 | fail_platform_driver: |
371 | 373 | ||
372 | platform_driver_unregister(&compal_driver); | 374 | platform_driver_unregister(&compal_driver); |
373 | 375 | ||
374 | fail_backlight: | 376 | fail_backlight: |
375 | 377 | ||
376 | backlight_device_unregister(compalbl_device); | 378 | backlight_device_unregister(compalbl_device); |
377 | 379 | ||
378 | return ret; | 380 | return ret; |
379 | } | 381 | } |
380 | 382 | ||
381 | static void __exit compal_cleanup(void) | 383 | static void __exit compal_cleanup(void) |
382 | { | 384 | { |
383 | 385 | ||
384 | sysfs_remove_group(&compal_device->dev.kobj, &compal_attribute_group); | 386 | sysfs_remove_group(&compal_device->dev.kobj, &compal_attribute_group); |
385 | platform_device_unregister(compal_device); | 387 | platform_device_unregister(compal_device); |
386 | platform_driver_unregister(&compal_driver); | 388 | platform_driver_unregister(&compal_driver); |
387 | backlight_device_unregister(compalbl_device); | 389 | backlight_device_unregister(compalbl_device); |
388 | 390 | ||
389 | printk(KERN_INFO "compal-laptop: driver unloaded.\n"); | 391 | printk(KERN_INFO "compal-laptop: driver unloaded.\n"); |
390 | } | 392 | } |
391 | 393 | ||
392 | module_init(compal_init); | 394 | module_init(compal_init); |
393 | module_exit(compal_cleanup); | 395 | module_exit(compal_cleanup); |
394 | 396 | ||
395 | MODULE_AUTHOR("Cezary Jackiewicz"); | 397 | MODULE_AUTHOR("Cezary Jackiewicz"); |
396 | MODULE_DESCRIPTION("Compal Laptop Support"); | 398 | MODULE_DESCRIPTION("Compal Laptop Support"); |
397 | MODULE_VERSION(COMPAL_DRIVER_VERSION); | 399 | MODULE_VERSION(COMPAL_DRIVER_VERSION); |
398 | MODULE_LICENSE("GPL"); | 400 | MODULE_LICENSE("GPL"); |
399 | 401 | ||
400 | MODULE_ALIAS("dmi:*:rnIFL90:rvrIFT00:*"); | 402 | MODULE_ALIAS("dmi:*:rnIFL90:rvrIFT00:*"); |
401 | MODULE_ALIAS("dmi:*:rnIFL90:rvrREFERENCE:*"); | 403 | MODULE_ALIAS("dmi:*:rnIFL90:rvrREFERENCE:*"); |
402 | MODULE_ALIAS("dmi:*:rnIFL91:rvrIFT00:*"); | 404 | MODULE_ALIAS("dmi:*:rnIFL91:rvrIFT00:*"); |
403 | MODULE_ALIAS("dmi:*:rnJFL92:rvrIFT00:*"); | 405 | MODULE_ALIAS("dmi:*:rnJFL92:rvrIFT00:*"); |
404 | MODULE_ALIAS("dmi:*:rnIFT00:rvrIFT00:*"); | 406 | MODULE_ALIAS("dmi:*:rnIFT00:rvrIFT00:*"); |
405 | 407 |
drivers/misc/eeepc-laptop.c
1 | /* | 1 | /* |
2 | * eepc-laptop.c - Asus Eee PC extras | 2 | * eepc-laptop.c - Asus Eee PC extras |
3 | * | 3 | * |
4 | * Based on asus_acpi.c as patched for the Eee PC by Asus: | 4 | * Based on asus_acpi.c as patched for the Eee PC by Asus: |
5 | * ftp://ftp.asus.com/pub/ASUS/EeePC/701/ASUS_ACPI_071126.rar | 5 | * ftp://ftp.asus.com/pub/ASUS/EeePC/701/ASUS_ACPI_071126.rar |
6 | * Based on eee.c from eeepc-linux | 6 | * Based on eee.c from eeepc-linux |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify | 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 | 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 | 10 | * the Free Software Foundation; either version 2 of the License, or |
11 | * (at your option) any later version. | 11 | * (at your option) any later version. |
12 | * | 12 | * |
13 | * This program is distributed in the hope that it will be useful, | 13 | * This program is distributed in the hope that it will be useful, |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | * GNU General Public License for more details. | 16 | * GNU General Public License for more details. |
17 | */ | 17 | */ |
18 | 18 | ||
19 | #include <linux/kernel.h> | 19 | #include <linux/kernel.h> |
20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
22 | #include <linux/types.h> | 22 | #include <linux/types.h> |
23 | #include <linux/platform_device.h> | 23 | #include <linux/platform_device.h> |
24 | #include <linux/backlight.h> | 24 | #include <linux/backlight.h> |
25 | #include <linux/fb.h> | 25 | #include <linux/fb.h> |
26 | #include <linux/hwmon.h> | 26 | #include <linux/hwmon.h> |
27 | #include <linux/hwmon-sysfs.h> | 27 | #include <linux/hwmon-sysfs.h> |
28 | #include <acpi/acpi_drivers.h> | 28 | #include <acpi/acpi_drivers.h> |
29 | #include <acpi/acpi_bus.h> | 29 | #include <acpi/acpi_bus.h> |
30 | #include <linux/uaccess.h> | 30 | #include <linux/uaccess.h> |
31 | #include <linux/input.h> | 31 | #include <linux/input.h> |
32 | #include <linux/rfkill.h> | 32 | #include <linux/rfkill.h> |
33 | 33 | ||
34 | #define EEEPC_LAPTOP_VERSION "0.1" | 34 | #define EEEPC_LAPTOP_VERSION "0.1" |
35 | 35 | ||
36 | #define EEEPC_HOTK_NAME "Eee PC Hotkey Driver" | 36 | #define EEEPC_HOTK_NAME "Eee PC Hotkey Driver" |
37 | #define EEEPC_HOTK_FILE "eeepc" | 37 | #define EEEPC_HOTK_FILE "eeepc" |
38 | #define EEEPC_HOTK_CLASS "hotkey" | 38 | #define EEEPC_HOTK_CLASS "hotkey" |
39 | #define EEEPC_HOTK_DEVICE_NAME "Hotkey" | 39 | #define EEEPC_HOTK_DEVICE_NAME "Hotkey" |
40 | #define EEEPC_HOTK_HID "ASUS010" | 40 | #define EEEPC_HOTK_HID "ASUS010" |
41 | 41 | ||
42 | #define EEEPC_LOG EEEPC_HOTK_FILE ": " | 42 | #define EEEPC_LOG EEEPC_HOTK_FILE ": " |
43 | #define EEEPC_ERR KERN_ERR EEEPC_LOG | 43 | #define EEEPC_ERR KERN_ERR EEEPC_LOG |
44 | #define EEEPC_WARNING KERN_WARNING EEEPC_LOG | 44 | #define EEEPC_WARNING KERN_WARNING EEEPC_LOG |
45 | #define EEEPC_NOTICE KERN_NOTICE EEEPC_LOG | 45 | #define EEEPC_NOTICE KERN_NOTICE EEEPC_LOG |
46 | #define EEEPC_INFO KERN_INFO EEEPC_LOG | 46 | #define EEEPC_INFO KERN_INFO EEEPC_LOG |
47 | 47 | ||
48 | /* | 48 | /* |
49 | * Definitions for Asus EeePC | 49 | * Definitions for Asus EeePC |
50 | */ | 50 | */ |
51 | #define NOTIFY_WLAN_ON 0x10 | 51 | #define NOTIFY_WLAN_ON 0x10 |
52 | #define NOTIFY_BRN_MIN 0x20 | 52 | #define NOTIFY_BRN_MIN 0x20 |
53 | #define NOTIFY_BRN_MAX 0x2f | 53 | #define NOTIFY_BRN_MAX 0x2f |
54 | 54 | ||
55 | enum { | 55 | enum { |
56 | DISABLE_ASL_WLAN = 0x0001, | 56 | DISABLE_ASL_WLAN = 0x0001, |
57 | DISABLE_ASL_BLUETOOTH = 0x0002, | 57 | DISABLE_ASL_BLUETOOTH = 0x0002, |
58 | DISABLE_ASL_IRDA = 0x0004, | 58 | DISABLE_ASL_IRDA = 0x0004, |
59 | DISABLE_ASL_CAMERA = 0x0008, | 59 | DISABLE_ASL_CAMERA = 0x0008, |
60 | DISABLE_ASL_TV = 0x0010, | 60 | DISABLE_ASL_TV = 0x0010, |
61 | DISABLE_ASL_GPS = 0x0020, | 61 | DISABLE_ASL_GPS = 0x0020, |
62 | DISABLE_ASL_DISPLAYSWITCH = 0x0040, | 62 | DISABLE_ASL_DISPLAYSWITCH = 0x0040, |
63 | DISABLE_ASL_MODEM = 0x0080, | 63 | DISABLE_ASL_MODEM = 0x0080, |
64 | DISABLE_ASL_CARDREADER = 0x0100 | 64 | DISABLE_ASL_CARDREADER = 0x0100 |
65 | }; | 65 | }; |
66 | 66 | ||
67 | enum { | 67 | enum { |
68 | CM_ASL_WLAN = 0, | 68 | CM_ASL_WLAN = 0, |
69 | CM_ASL_BLUETOOTH, | 69 | CM_ASL_BLUETOOTH, |
70 | CM_ASL_IRDA, | 70 | CM_ASL_IRDA, |
71 | CM_ASL_1394, | 71 | CM_ASL_1394, |
72 | CM_ASL_CAMERA, | 72 | CM_ASL_CAMERA, |
73 | CM_ASL_TV, | 73 | CM_ASL_TV, |
74 | CM_ASL_GPS, | 74 | CM_ASL_GPS, |
75 | CM_ASL_DVDROM, | 75 | CM_ASL_DVDROM, |
76 | CM_ASL_DISPLAYSWITCH, | 76 | CM_ASL_DISPLAYSWITCH, |
77 | CM_ASL_PANELBRIGHT, | 77 | CM_ASL_PANELBRIGHT, |
78 | CM_ASL_BIOSFLASH, | 78 | CM_ASL_BIOSFLASH, |
79 | CM_ASL_ACPIFLASH, | 79 | CM_ASL_ACPIFLASH, |
80 | CM_ASL_CPUFV, | 80 | CM_ASL_CPUFV, |
81 | CM_ASL_CPUTEMPERATURE, | 81 | CM_ASL_CPUTEMPERATURE, |
82 | CM_ASL_FANCPU, | 82 | CM_ASL_FANCPU, |
83 | CM_ASL_FANCHASSIS, | 83 | CM_ASL_FANCHASSIS, |
84 | CM_ASL_USBPORT1, | 84 | CM_ASL_USBPORT1, |
85 | CM_ASL_USBPORT2, | 85 | CM_ASL_USBPORT2, |
86 | CM_ASL_USBPORT3, | 86 | CM_ASL_USBPORT3, |
87 | CM_ASL_MODEM, | 87 | CM_ASL_MODEM, |
88 | CM_ASL_CARDREADER, | 88 | CM_ASL_CARDREADER, |
89 | CM_ASL_LID | 89 | CM_ASL_LID |
90 | }; | 90 | }; |
91 | 91 | ||
92 | static const char *cm_getv[] = { | 92 | static const char *cm_getv[] = { |
93 | "WLDG", NULL, NULL, NULL, | 93 | "WLDG", NULL, NULL, NULL, |
94 | "CAMG", NULL, NULL, NULL, | 94 | "CAMG", NULL, NULL, NULL, |
95 | NULL, "PBLG", NULL, NULL, | 95 | NULL, "PBLG", NULL, NULL, |
96 | "CFVG", NULL, NULL, NULL, | 96 | "CFVG", NULL, NULL, NULL, |
97 | "USBG", NULL, NULL, "MODG", | 97 | "USBG", NULL, NULL, "MODG", |
98 | "CRDG", "LIDG" | 98 | "CRDG", "LIDG" |
99 | }; | 99 | }; |
100 | 100 | ||
101 | static const char *cm_setv[] = { | 101 | static const char *cm_setv[] = { |
102 | "WLDS", NULL, NULL, NULL, | 102 | "WLDS", NULL, NULL, NULL, |
103 | "CAMS", NULL, NULL, NULL, | 103 | "CAMS", NULL, NULL, NULL, |
104 | "SDSP", "PBLS", "HDPS", NULL, | 104 | "SDSP", "PBLS", "HDPS", NULL, |
105 | "CFVS", NULL, NULL, NULL, | 105 | "CFVS", NULL, NULL, NULL, |
106 | "USBG", NULL, NULL, "MODS", | 106 | "USBG", NULL, NULL, "MODS", |
107 | "CRDS", NULL | 107 | "CRDS", NULL |
108 | }; | 108 | }; |
109 | 109 | ||
110 | #define EEEPC_EC "\\_SB.PCI0.SBRG.EC0." | 110 | #define EEEPC_EC "\\_SB.PCI0.SBRG.EC0." |
111 | 111 | ||
112 | #define EEEPC_EC_FAN_PWM EEEPC_EC "SC02" /* Fan PWM duty cycle (%) */ | 112 | #define EEEPC_EC_FAN_PWM EEEPC_EC "SC02" /* Fan PWM duty cycle (%) */ |
113 | #define EEEPC_EC_SC02 0x63 | 113 | #define EEEPC_EC_SC02 0x63 |
114 | #define EEEPC_EC_FAN_HRPM EEEPC_EC "SC05" /* High byte, fan speed (RPM) */ | 114 | #define EEEPC_EC_FAN_HRPM EEEPC_EC "SC05" /* High byte, fan speed (RPM) */ |
115 | #define EEEPC_EC_FAN_LRPM EEEPC_EC "SC06" /* Low byte, fan speed (RPM) */ | 115 | #define EEEPC_EC_FAN_LRPM EEEPC_EC "SC06" /* Low byte, fan speed (RPM) */ |
116 | #define EEEPC_EC_FAN_CTRL EEEPC_EC "SFB3" /* Byte containing SF25 */ | 116 | #define EEEPC_EC_FAN_CTRL EEEPC_EC "SFB3" /* Byte containing SF25 */ |
117 | #define EEEPC_EC_SFB3 0xD3 | 117 | #define EEEPC_EC_SFB3 0xD3 |
118 | 118 | ||
119 | /* | 119 | /* |
120 | * This is the main structure, we can use it to store useful information | 120 | * This is the main structure, we can use it to store useful information |
121 | * about the hotk device | 121 | * about the hotk device |
122 | */ | 122 | */ |
123 | struct eeepc_hotk { | 123 | struct eeepc_hotk { |
124 | struct acpi_device *device; /* the device we are in */ | 124 | struct acpi_device *device; /* the device we are in */ |
125 | acpi_handle handle; /* the handle of the hotk device */ | 125 | acpi_handle handle; /* the handle of the hotk device */ |
126 | u32 cm_supported; /* the control methods supported | 126 | u32 cm_supported; /* the control methods supported |
127 | by this BIOS */ | 127 | by this BIOS */ |
128 | uint init_flag; /* Init flags */ | 128 | uint init_flag; /* Init flags */ |
129 | u16 event_count[128]; /* count for each event */ | 129 | u16 event_count[128]; /* count for each event */ |
130 | struct input_dev *inputdev; | 130 | struct input_dev *inputdev; |
131 | u16 *keycode_map; | 131 | u16 *keycode_map; |
132 | struct rfkill *eeepc_wlan_rfkill; | 132 | struct rfkill *eeepc_wlan_rfkill; |
133 | struct rfkill *eeepc_bluetooth_rfkill; | 133 | struct rfkill *eeepc_bluetooth_rfkill; |
134 | }; | 134 | }; |
135 | 135 | ||
136 | /* The actual device the driver binds to */ | 136 | /* The actual device the driver binds to */ |
137 | static struct eeepc_hotk *ehotk; | 137 | static struct eeepc_hotk *ehotk; |
138 | 138 | ||
139 | /* Platform device/driver */ | 139 | /* Platform device/driver */ |
140 | static struct platform_driver platform_driver = { | 140 | static struct platform_driver platform_driver = { |
141 | .driver = { | 141 | .driver = { |
142 | .name = EEEPC_HOTK_FILE, | 142 | .name = EEEPC_HOTK_FILE, |
143 | .owner = THIS_MODULE, | 143 | .owner = THIS_MODULE, |
144 | } | 144 | } |
145 | }; | 145 | }; |
146 | 146 | ||
147 | static struct platform_device *platform_device; | 147 | static struct platform_device *platform_device; |
148 | 148 | ||
149 | struct key_entry { | 149 | struct key_entry { |
150 | char type; | 150 | char type; |
151 | u8 code; | 151 | u8 code; |
152 | u16 keycode; | 152 | u16 keycode; |
153 | }; | 153 | }; |
154 | 154 | ||
155 | enum { KE_KEY, KE_END }; | 155 | enum { KE_KEY, KE_END }; |
156 | 156 | ||
157 | static struct key_entry eeepc_keymap[] = { | 157 | static struct key_entry eeepc_keymap[] = { |
158 | /* Sleep already handled via generic ACPI code */ | 158 | /* Sleep already handled via generic ACPI code */ |
159 | {KE_KEY, 0x10, KEY_WLAN }, | 159 | {KE_KEY, 0x10, KEY_WLAN }, |
160 | {KE_KEY, 0x12, KEY_PROG1 }, | 160 | {KE_KEY, 0x12, KEY_PROG1 }, |
161 | {KE_KEY, 0x13, KEY_MUTE }, | 161 | {KE_KEY, 0x13, KEY_MUTE }, |
162 | {KE_KEY, 0x14, KEY_VOLUMEDOWN }, | 162 | {KE_KEY, 0x14, KEY_VOLUMEDOWN }, |
163 | {KE_KEY, 0x15, KEY_VOLUMEUP }, | 163 | {KE_KEY, 0x15, KEY_VOLUMEUP }, |
164 | {KE_KEY, 0x30, KEY_SWITCHVIDEOMODE }, | 164 | {KE_KEY, 0x30, KEY_SWITCHVIDEOMODE }, |
165 | {KE_KEY, 0x31, KEY_SWITCHVIDEOMODE }, | 165 | {KE_KEY, 0x31, KEY_SWITCHVIDEOMODE }, |
166 | {KE_KEY, 0x32, KEY_SWITCHVIDEOMODE }, | 166 | {KE_KEY, 0x32, KEY_SWITCHVIDEOMODE }, |
167 | {KE_END, 0}, | 167 | {KE_END, 0}, |
168 | }; | 168 | }; |
169 | 169 | ||
170 | /* | 170 | /* |
171 | * The hotkey driver declaration | 171 | * The hotkey driver declaration |
172 | */ | 172 | */ |
173 | static int eeepc_hotk_add(struct acpi_device *device); | 173 | static int eeepc_hotk_add(struct acpi_device *device); |
174 | static int eeepc_hotk_remove(struct acpi_device *device, int type); | 174 | static int eeepc_hotk_remove(struct acpi_device *device, int type); |
175 | 175 | ||
176 | static const struct acpi_device_id eeepc_device_ids[] = { | 176 | static const struct acpi_device_id eeepc_device_ids[] = { |
177 | {EEEPC_HOTK_HID, 0}, | 177 | {EEEPC_HOTK_HID, 0}, |
178 | {"", 0}, | 178 | {"", 0}, |
179 | }; | 179 | }; |
180 | MODULE_DEVICE_TABLE(acpi, eeepc_device_ids); | 180 | MODULE_DEVICE_TABLE(acpi, eeepc_device_ids); |
181 | 181 | ||
182 | static struct acpi_driver eeepc_hotk_driver = { | 182 | static struct acpi_driver eeepc_hotk_driver = { |
183 | .name = EEEPC_HOTK_NAME, | 183 | .name = EEEPC_HOTK_NAME, |
184 | .class = EEEPC_HOTK_CLASS, | 184 | .class = EEEPC_HOTK_CLASS, |
185 | .ids = eeepc_device_ids, | 185 | .ids = eeepc_device_ids, |
186 | .ops = { | 186 | .ops = { |
187 | .add = eeepc_hotk_add, | 187 | .add = eeepc_hotk_add, |
188 | .remove = eeepc_hotk_remove, | 188 | .remove = eeepc_hotk_remove, |
189 | }, | 189 | }, |
190 | }; | 190 | }; |
191 | 191 | ||
192 | /* The backlight device /sys/class/backlight */ | 192 | /* The backlight device /sys/class/backlight */ |
193 | static struct backlight_device *eeepc_backlight_device; | 193 | static struct backlight_device *eeepc_backlight_device; |
194 | 194 | ||
195 | /* The hwmon device */ | 195 | /* The hwmon device */ |
196 | static struct device *eeepc_hwmon_device; | 196 | static struct device *eeepc_hwmon_device; |
197 | 197 | ||
198 | /* | 198 | /* |
199 | * The backlight class declaration | 199 | * The backlight class declaration |
200 | */ | 200 | */ |
201 | static int read_brightness(struct backlight_device *bd); | 201 | static int read_brightness(struct backlight_device *bd); |
202 | static int update_bl_status(struct backlight_device *bd); | 202 | static int update_bl_status(struct backlight_device *bd); |
203 | static struct backlight_ops eeepcbl_ops = { | 203 | static struct backlight_ops eeepcbl_ops = { |
204 | .get_brightness = read_brightness, | 204 | .get_brightness = read_brightness, |
205 | .update_status = update_bl_status, | 205 | .update_status = update_bl_status, |
206 | }; | 206 | }; |
207 | 207 | ||
208 | MODULE_AUTHOR("Corentin Chary, Eric Cooper"); | 208 | MODULE_AUTHOR("Corentin Chary, Eric Cooper"); |
209 | MODULE_DESCRIPTION(EEEPC_HOTK_NAME); | 209 | MODULE_DESCRIPTION(EEEPC_HOTK_NAME); |
210 | MODULE_LICENSE("GPL"); | 210 | MODULE_LICENSE("GPL"); |
211 | 211 | ||
212 | /* | 212 | /* |
213 | * ACPI Helpers | 213 | * ACPI Helpers |
214 | */ | 214 | */ |
215 | static int write_acpi_int(acpi_handle handle, const char *method, int val, | 215 | static int write_acpi_int(acpi_handle handle, const char *method, int val, |
216 | struct acpi_buffer *output) | 216 | struct acpi_buffer *output) |
217 | { | 217 | { |
218 | struct acpi_object_list params; | 218 | struct acpi_object_list params; |
219 | union acpi_object in_obj; | 219 | union acpi_object in_obj; |
220 | acpi_status status; | 220 | acpi_status status; |
221 | 221 | ||
222 | params.count = 1; | 222 | params.count = 1; |
223 | params.pointer = &in_obj; | 223 | params.pointer = &in_obj; |
224 | in_obj.type = ACPI_TYPE_INTEGER; | 224 | in_obj.type = ACPI_TYPE_INTEGER; |
225 | in_obj.integer.value = val; | 225 | in_obj.integer.value = val; |
226 | 226 | ||
227 | status = acpi_evaluate_object(handle, (char *)method, ¶ms, output); | 227 | status = acpi_evaluate_object(handle, (char *)method, ¶ms, output); |
228 | return (status == AE_OK ? 0 : -1); | 228 | return (status == AE_OK ? 0 : -1); |
229 | } | 229 | } |
230 | 230 | ||
231 | static int read_acpi_int(acpi_handle handle, const char *method, int *val) | 231 | static int read_acpi_int(acpi_handle handle, const char *method, int *val) |
232 | { | 232 | { |
233 | acpi_status status; | 233 | acpi_status status; |
234 | unsigned long long result; | 234 | unsigned long long result; |
235 | 235 | ||
236 | status = acpi_evaluate_integer(handle, (char *)method, NULL, &result); | 236 | status = acpi_evaluate_integer(handle, (char *)method, NULL, &result); |
237 | if (ACPI_FAILURE(status)) { | 237 | if (ACPI_FAILURE(status)) { |
238 | *val = -1; | 238 | *val = -1; |
239 | return -1; | 239 | return -1; |
240 | } else { | 240 | } else { |
241 | *val = result; | 241 | *val = result; |
242 | return 0; | 242 | return 0; |
243 | } | 243 | } |
244 | } | 244 | } |
245 | 245 | ||
246 | static int set_acpi(int cm, int value) | 246 | static int set_acpi(int cm, int value) |
247 | { | 247 | { |
248 | if (ehotk->cm_supported & (0x1 << cm)) { | 248 | if (ehotk->cm_supported & (0x1 << cm)) { |
249 | const char *method = cm_setv[cm]; | 249 | const char *method = cm_setv[cm]; |
250 | if (method == NULL) | 250 | if (method == NULL) |
251 | return -ENODEV; | 251 | return -ENODEV; |
252 | if (write_acpi_int(ehotk->handle, method, value, NULL)) | 252 | if (write_acpi_int(ehotk->handle, method, value, NULL)) |
253 | printk(EEEPC_WARNING "Error writing %s\n", method); | 253 | printk(EEEPC_WARNING "Error writing %s\n", method); |
254 | } | 254 | } |
255 | return 0; | 255 | return 0; |
256 | } | 256 | } |
257 | 257 | ||
258 | static int get_acpi(int cm) | 258 | static int get_acpi(int cm) |
259 | { | 259 | { |
260 | int value = -1; | 260 | int value = -1; |
261 | if ((ehotk->cm_supported & (0x1 << cm))) { | 261 | if ((ehotk->cm_supported & (0x1 << cm))) { |
262 | const char *method = cm_getv[cm]; | 262 | const char *method = cm_getv[cm]; |
263 | if (method == NULL) | 263 | if (method == NULL) |
264 | return -ENODEV; | 264 | return -ENODEV; |
265 | if (read_acpi_int(ehotk->handle, method, &value)) | 265 | if (read_acpi_int(ehotk->handle, method, &value)) |
266 | printk(EEEPC_WARNING "Error reading %s\n", method); | 266 | printk(EEEPC_WARNING "Error reading %s\n", method); |
267 | } | 267 | } |
268 | return value; | 268 | return value; |
269 | } | 269 | } |
270 | 270 | ||
271 | /* | 271 | /* |
272 | * Backlight | 272 | * Backlight |
273 | */ | 273 | */ |
274 | static int read_brightness(struct backlight_device *bd) | 274 | static int read_brightness(struct backlight_device *bd) |
275 | { | 275 | { |
276 | return get_acpi(CM_ASL_PANELBRIGHT); | 276 | return get_acpi(CM_ASL_PANELBRIGHT); |
277 | } | 277 | } |
278 | 278 | ||
279 | static int set_brightness(struct backlight_device *bd, int value) | 279 | static int set_brightness(struct backlight_device *bd, int value) |
280 | { | 280 | { |
281 | value = max(0, min(15, value)); | 281 | value = max(0, min(15, value)); |
282 | return set_acpi(CM_ASL_PANELBRIGHT, value); | 282 | return set_acpi(CM_ASL_PANELBRIGHT, value); |
283 | } | 283 | } |
284 | 284 | ||
285 | static int update_bl_status(struct backlight_device *bd) | 285 | static int update_bl_status(struct backlight_device *bd) |
286 | { | 286 | { |
287 | return set_brightness(bd, bd->props.brightness); | 287 | return set_brightness(bd, bd->props.brightness); |
288 | } | 288 | } |
289 | 289 | ||
290 | /* | 290 | /* |
291 | * Rfkill helpers | 291 | * Rfkill helpers |
292 | */ | 292 | */ |
293 | 293 | ||
294 | static int eeepc_wlan_rfkill_set(void *data, enum rfkill_state state) | 294 | static int eeepc_wlan_rfkill_set(void *data, enum rfkill_state state) |
295 | { | 295 | { |
296 | if (state == RFKILL_STATE_SOFT_BLOCKED) | 296 | if (state == RFKILL_STATE_SOFT_BLOCKED) |
297 | return set_acpi(CM_ASL_WLAN, 0); | 297 | return set_acpi(CM_ASL_WLAN, 0); |
298 | else | 298 | else |
299 | return set_acpi(CM_ASL_WLAN, 1); | 299 | return set_acpi(CM_ASL_WLAN, 1); |
300 | } | 300 | } |
301 | 301 | ||
302 | static int eeepc_wlan_rfkill_state(void *data, enum rfkill_state *state) | 302 | static int eeepc_wlan_rfkill_state(void *data, enum rfkill_state *state) |
303 | { | 303 | { |
304 | if (get_acpi(CM_ASL_WLAN) == 1) | 304 | if (get_acpi(CM_ASL_WLAN) == 1) |
305 | *state = RFKILL_STATE_UNBLOCKED; | 305 | *state = RFKILL_STATE_UNBLOCKED; |
306 | else | 306 | else |
307 | *state = RFKILL_STATE_SOFT_BLOCKED; | 307 | *state = RFKILL_STATE_SOFT_BLOCKED; |
308 | return 0; | 308 | return 0; |
309 | } | 309 | } |
310 | 310 | ||
311 | static int eeepc_bluetooth_rfkill_set(void *data, enum rfkill_state state) | 311 | static int eeepc_bluetooth_rfkill_set(void *data, enum rfkill_state state) |
312 | { | 312 | { |
313 | if (state == RFKILL_STATE_SOFT_BLOCKED) | 313 | if (state == RFKILL_STATE_SOFT_BLOCKED) |
314 | return set_acpi(CM_ASL_BLUETOOTH, 0); | 314 | return set_acpi(CM_ASL_BLUETOOTH, 0); |
315 | else | 315 | else |
316 | return set_acpi(CM_ASL_BLUETOOTH, 1); | 316 | return set_acpi(CM_ASL_BLUETOOTH, 1); |
317 | } | 317 | } |
318 | 318 | ||
319 | static int eeepc_bluetooth_rfkill_state(void *data, enum rfkill_state *state) | 319 | static int eeepc_bluetooth_rfkill_state(void *data, enum rfkill_state *state) |
320 | { | 320 | { |
321 | if (get_acpi(CM_ASL_BLUETOOTH) == 1) | 321 | if (get_acpi(CM_ASL_BLUETOOTH) == 1) |
322 | *state = RFKILL_STATE_UNBLOCKED; | 322 | *state = RFKILL_STATE_UNBLOCKED; |
323 | else | 323 | else |
324 | *state = RFKILL_STATE_SOFT_BLOCKED; | 324 | *state = RFKILL_STATE_SOFT_BLOCKED; |
325 | return 0; | 325 | return 0; |
326 | } | 326 | } |
327 | 327 | ||
328 | /* | 328 | /* |
329 | * Sys helpers | 329 | * Sys helpers |
330 | */ | 330 | */ |
331 | static int parse_arg(const char *buf, unsigned long count, int *val) | 331 | static int parse_arg(const char *buf, unsigned long count, int *val) |
332 | { | 332 | { |
333 | if (!count) | 333 | if (!count) |
334 | return 0; | 334 | return 0; |
335 | if (sscanf(buf, "%i", val) != 1) | 335 | if (sscanf(buf, "%i", val) != 1) |
336 | return -EINVAL; | 336 | return -EINVAL; |
337 | return count; | 337 | return count; |
338 | } | 338 | } |
339 | 339 | ||
340 | static ssize_t store_sys_acpi(int cm, const char *buf, size_t count) | 340 | static ssize_t store_sys_acpi(int cm, const char *buf, size_t count) |
341 | { | 341 | { |
342 | int rv, value; | 342 | int rv, value; |
343 | 343 | ||
344 | rv = parse_arg(buf, count, &value); | 344 | rv = parse_arg(buf, count, &value); |
345 | if (rv > 0) | 345 | if (rv > 0) |
346 | set_acpi(cm, value); | 346 | set_acpi(cm, value); |
347 | return rv; | 347 | return rv; |
348 | } | 348 | } |
349 | 349 | ||
350 | static ssize_t show_sys_acpi(int cm, char *buf) | 350 | static ssize_t show_sys_acpi(int cm, char *buf) |
351 | { | 351 | { |
352 | return sprintf(buf, "%d\n", get_acpi(cm)); | 352 | return sprintf(buf, "%d\n", get_acpi(cm)); |
353 | } | 353 | } |
354 | 354 | ||
355 | #define EEEPC_CREATE_DEVICE_ATTR(_name, _cm) \ | 355 | #define EEEPC_CREATE_DEVICE_ATTR(_name, _cm) \ |
356 | static ssize_t show_##_name(struct device *dev, \ | 356 | static ssize_t show_##_name(struct device *dev, \ |
357 | struct device_attribute *attr, \ | 357 | struct device_attribute *attr, \ |
358 | char *buf) \ | 358 | char *buf) \ |
359 | { \ | 359 | { \ |
360 | return show_sys_acpi(_cm, buf); \ | 360 | return show_sys_acpi(_cm, buf); \ |
361 | } \ | 361 | } \ |
362 | static ssize_t store_##_name(struct device *dev, \ | 362 | static ssize_t store_##_name(struct device *dev, \ |
363 | struct device_attribute *attr, \ | 363 | struct device_attribute *attr, \ |
364 | const char *buf, size_t count) \ | 364 | const char *buf, size_t count) \ |
365 | { \ | 365 | { \ |
366 | return store_sys_acpi(_cm, buf, count); \ | 366 | return store_sys_acpi(_cm, buf, count); \ |
367 | } \ | 367 | } \ |
368 | static struct device_attribute dev_attr_##_name = { \ | 368 | static struct device_attribute dev_attr_##_name = { \ |
369 | .attr = { \ | 369 | .attr = { \ |
370 | .name = __stringify(_name), \ | 370 | .name = __stringify(_name), \ |
371 | .mode = 0644 }, \ | 371 | .mode = 0644 }, \ |
372 | .show = show_##_name, \ | 372 | .show = show_##_name, \ |
373 | .store = store_##_name, \ | 373 | .store = store_##_name, \ |
374 | } | 374 | } |
375 | 375 | ||
376 | EEEPC_CREATE_DEVICE_ATTR(camera, CM_ASL_CAMERA); | 376 | EEEPC_CREATE_DEVICE_ATTR(camera, CM_ASL_CAMERA); |
377 | EEEPC_CREATE_DEVICE_ATTR(cardr, CM_ASL_CARDREADER); | 377 | EEEPC_CREATE_DEVICE_ATTR(cardr, CM_ASL_CARDREADER); |
378 | EEEPC_CREATE_DEVICE_ATTR(disp, CM_ASL_DISPLAYSWITCH); | 378 | EEEPC_CREATE_DEVICE_ATTR(disp, CM_ASL_DISPLAYSWITCH); |
379 | 379 | ||
380 | static struct attribute *platform_attributes[] = { | 380 | static struct attribute *platform_attributes[] = { |
381 | &dev_attr_camera.attr, | 381 | &dev_attr_camera.attr, |
382 | &dev_attr_cardr.attr, | 382 | &dev_attr_cardr.attr, |
383 | &dev_attr_disp.attr, | 383 | &dev_attr_disp.attr, |
384 | NULL | 384 | NULL |
385 | }; | 385 | }; |
386 | 386 | ||
387 | static struct attribute_group platform_attribute_group = { | 387 | static struct attribute_group platform_attribute_group = { |
388 | .attrs = platform_attributes | 388 | .attrs = platform_attributes |
389 | }; | 389 | }; |
390 | 390 | ||
391 | /* | 391 | /* |
392 | * Hotkey functions | 392 | * Hotkey functions |
393 | */ | 393 | */ |
394 | static struct key_entry *eepc_get_entry_by_scancode(int code) | 394 | static struct key_entry *eepc_get_entry_by_scancode(int code) |
395 | { | 395 | { |
396 | struct key_entry *key; | 396 | struct key_entry *key; |
397 | 397 | ||
398 | for (key = eeepc_keymap; key->type != KE_END; key++) | 398 | for (key = eeepc_keymap; key->type != KE_END; key++) |
399 | if (code == key->code) | 399 | if (code == key->code) |
400 | return key; | 400 | return key; |
401 | 401 | ||
402 | return NULL; | 402 | return NULL; |
403 | } | 403 | } |
404 | 404 | ||
405 | static struct key_entry *eepc_get_entry_by_keycode(int code) | 405 | static struct key_entry *eepc_get_entry_by_keycode(int code) |
406 | { | 406 | { |
407 | struct key_entry *key; | 407 | struct key_entry *key; |
408 | 408 | ||
409 | for (key = eeepc_keymap; key->type != KE_END; key++) | 409 | for (key = eeepc_keymap; key->type != KE_END; key++) |
410 | if (code == key->keycode && key->type == KE_KEY) | 410 | if (code == key->keycode && key->type == KE_KEY) |
411 | return key; | 411 | return key; |
412 | 412 | ||
413 | return NULL; | 413 | return NULL; |
414 | } | 414 | } |
415 | 415 | ||
416 | static int eeepc_getkeycode(struct input_dev *dev, int scancode, int *keycode) | 416 | static int eeepc_getkeycode(struct input_dev *dev, int scancode, int *keycode) |
417 | { | 417 | { |
418 | struct key_entry *key = eepc_get_entry_by_scancode(scancode); | 418 | struct key_entry *key = eepc_get_entry_by_scancode(scancode); |
419 | 419 | ||
420 | if (key && key->type == KE_KEY) { | 420 | if (key && key->type == KE_KEY) { |
421 | *keycode = key->keycode; | 421 | *keycode = key->keycode; |
422 | return 0; | 422 | return 0; |
423 | } | 423 | } |
424 | 424 | ||
425 | return -EINVAL; | 425 | return -EINVAL; |
426 | } | 426 | } |
427 | 427 | ||
428 | static int eeepc_setkeycode(struct input_dev *dev, int scancode, int keycode) | 428 | static int eeepc_setkeycode(struct input_dev *dev, int scancode, int keycode) |
429 | { | 429 | { |
430 | struct key_entry *key; | 430 | struct key_entry *key; |
431 | int old_keycode; | 431 | int old_keycode; |
432 | 432 | ||
433 | if (keycode < 0 || keycode > KEY_MAX) | 433 | if (keycode < 0 || keycode > KEY_MAX) |
434 | return -EINVAL; | 434 | return -EINVAL; |
435 | 435 | ||
436 | key = eepc_get_entry_by_scancode(scancode); | 436 | key = eepc_get_entry_by_scancode(scancode); |
437 | if (key && key->type == KE_KEY) { | 437 | if (key && key->type == KE_KEY) { |
438 | old_keycode = key->keycode; | 438 | old_keycode = key->keycode; |
439 | key->keycode = keycode; | 439 | key->keycode = keycode; |
440 | set_bit(keycode, dev->keybit); | 440 | set_bit(keycode, dev->keybit); |
441 | if (!eepc_get_entry_by_keycode(old_keycode)) | 441 | if (!eepc_get_entry_by_keycode(old_keycode)) |
442 | clear_bit(old_keycode, dev->keybit); | 442 | clear_bit(old_keycode, dev->keybit); |
443 | return 0; | 443 | return 0; |
444 | } | 444 | } |
445 | 445 | ||
446 | return -EINVAL; | 446 | return -EINVAL; |
447 | } | 447 | } |
448 | 448 | ||
449 | static int eeepc_hotk_check(void) | 449 | static int eeepc_hotk_check(void) |
450 | { | 450 | { |
451 | const struct key_entry *key; | 451 | const struct key_entry *key; |
452 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | 452 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
453 | int result; | 453 | int result; |
454 | 454 | ||
455 | result = acpi_bus_get_status(ehotk->device); | 455 | result = acpi_bus_get_status(ehotk->device); |
456 | if (result) | 456 | if (result) |
457 | return result; | 457 | return result; |
458 | if (ehotk->device->status.present) { | 458 | if (ehotk->device->status.present) { |
459 | if (write_acpi_int(ehotk->handle, "INIT", ehotk->init_flag, | 459 | if (write_acpi_int(ehotk->handle, "INIT", ehotk->init_flag, |
460 | &buffer)) { | 460 | &buffer)) { |
461 | printk(EEEPC_ERR "Hotkey initialization failed\n"); | 461 | printk(EEEPC_ERR "Hotkey initialization failed\n"); |
462 | return -ENODEV; | 462 | return -ENODEV; |
463 | } else { | 463 | } else { |
464 | printk(EEEPC_NOTICE "Hotkey init flags 0x%x\n", | 464 | printk(EEEPC_NOTICE "Hotkey init flags 0x%x\n", |
465 | ehotk->init_flag); | 465 | ehotk->init_flag); |
466 | } | 466 | } |
467 | /* get control methods supported */ | 467 | /* get control methods supported */ |
468 | if (read_acpi_int(ehotk->handle, "CMSG" | 468 | if (read_acpi_int(ehotk->handle, "CMSG" |
469 | , &ehotk->cm_supported)) { | 469 | , &ehotk->cm_supported)) { |
470 | printk(EEEPC_ERR | 470 | printk(EEEPC_ERR |
471 | "Get control methods supported failed\n"); | 471 | "Get control methods supported failed\n"); |
472 | return -ENODEV; | 472 | return -ENODEV; |
473 | } else { | 473 | } else { |
474 | printk(EEEPC_INFO | 474 | printk(EEEPC_INFO |
475 | "Get control methods supported: 0x%x\n", | 475 | "Get control methods supported: 0x%x\n", |
476 | ehotk->cm_supported); | 476 | ehotk->cm_supported); |
477 | } | 477 | } |
478 | ehotk->inputdev = input_allocate_device(); | 478 | ehotk->inputdev = input_allocate_device(); |
479 | if (!ehotk->inputdev) { | 479 | if (!ehotk->inputdev) { |
480 | printk(EEEPC_INFO "Unable to allocate input device\n"); | 480 | printk(EEEPC_INFO "Unable to allocate input device\n"); |
481 | return 0; | 481 | return 0; |
482 | } | 482 | } |
483 | ehotk->inputdev->name = "Asus EeePC extra buttons"; | 483 | ehotk->inputdev->name = "Asus EeePC extra buttons"; |
484 | ehotk->inputdev->phys = EEEPC_HOTK_FILE "/input0"; | 484 | ehotk->inputdev->phys = EEEPC_HOTK_FILE "/input0"; |
485 | ehotk->inputdev->id.bustype = BUS_HOST; | 485 | ehotk->inputdev->id.bustype = BUS_HOST; |
486 | ehotk->inputdev->getkeycode = eeepc_getkeycode; | 486 | ehotk->inputdev->getkeycode = eeepc_getkeycode; |
487 | ehotk->inputdev->setkeycode = eeepc_setkeycode; | 487 | ehotk->inputdev->setkeycode = eeepc_setkeycode; |
488 | 488 | ||
489 | for (key = eeepc_keymap; key->type != KE_END; key++) { | 489 | for (key = eeepc_keymap; key->type != KE_END; key++) { |
490 | switch (key->type) { | 490 | switch (key->type) { |
491 | case KE_KEY: | 491 | case KE_KEY: |
492 | set_bit(EV_KEY, ehotk->inputdev->evbit); | 492 | set_bit(EV_KEY, ehotk->inputdev->evbit); |
493 | set_bit(key->keycode, ehotk->inputdev->keybit); | 493 | set_bit(key->keycode, ehotk->inputdev->keybit); |
494 | break; | 494 | break; |
495 | } | 495 | } |
496 | } | 496 | } |
497 | result = input_register_device(ehotk->inputdev); | 497 | result = input_register_device(ehotk->inputdev); |
498 | if (result) { | 498 | if (result) { |
499 | printk(EEEPC_INFO "Unable to register input device\n"); | 499 | printk(EEEPC_INFO "Unable to register input device\n"); |
500 | input_free_device(ehotk->inputdev); | 500 | input_free_device(ehotk->inputdev); |
501 | return 0; | 501 | return 0; |
502 | } | 502 | } |
503 | } else { | 503 | } else { |
504 | printk(EEEPC_ERR "Hotkey device not present, aborting\n"); | 504 | printk(EEEPC_ERR "Hotkey device not present, aborting\n"); |
505 | return -EINVAL; | 505 | return -EINVAL; |
506 | } | 506 | } |
507 | return 0; | 507 | return 0; |
508 | } | 508 | } |
509 | 509 | ||
510 | static void notify_brn(void) | 510 | static void notify_brn(void) |
511 | { | 511 | { |
512 | struct backlight_device *bd = eeepc_backlight_device; | 512 | struct backlight_device *bd = eeepc_backlight_device; |
513 | bd->props.brightness = read_brightness(bd); | 513 | bd->props.brightness = read_brightness(bd); |
514 | } | 514 | } |
515 | 515 | ||
516 | static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data) | 516 | static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data) |
517 | { | 517 | { |
518 | static struct key_entry *key; | 518 | static struct key_entry *key; |
519 | if (!ehotk) | 519 | if (!ehotk) |
520 | return; | 520 | return; |
521 | if (event >= NOTIFY_BRN_MIN && event <= NOTIFY_BRN_MAX) | 521 | if (event >= NOTIFY_BRN_MIN && event <= NOTIFY_BRN_MAX) |
522 | notify_brn(); | 522 | notify_brn(); |
523 | acpi_bus_generate_proc_event(ehotk->device, event, | 523 | acpi_bus_generate_proc_event(ehotk->device, event, |
524 | ehotk->event_count[event % 128]++); | 524 | ehotk->event_count[event % 128]++); |
525 | if (ehotk->inputdev) { | 525 | if (ehotk->inputdev) { |
526 | key = eepc_get_entry_by_scancode(event); | 526 | key = eepc_get_entry_by_scancode(event); |
527 | if (key) { | 527 | if (key) { |
528 | switch (key->type) { | 528 | switch (key->type) { |
529 | case KE_KEY: | 529 | case KE_KEY: |
530 | input_report_key(ehotk->inputdev, key->keycode, | 530 | input_report_key(ehotk->inputdev, key->keycode, |
531 | 1); | 531 | 1); |
532 | input_sync(ehotk->inputdev); | 532 | input_sync(ehotk->inputdev); |
533 | input_report_key(ehotk->inputdev, key->keycode, | 533 | input_report_key(ehotk->inputdev, key->keycode, |
534 | 0); | 534 | 0); |
535 | input_sync(ehotk->inputdev); | 535 | input_sync(ehotk->inputdev); |
536 | break; | 536 | break; |
537 | } | 537 | } |
538 | } | 538 | } |
539 | } | 539 | } |
540 | } | 540 | } |
541 | 541 | ||
542 | static int eeepc_hotk_add(struct acpi_device *device) | 542 | static int eeepc_hotk_add(struct acpi_device *device) |
543 | { | 543 | { |
544 | acpi_status status = AE_OK; | 544 | acpi_status status = AE_OK; |
545 | int result; | 545 | int result; |
546 | 546 | ||
547 | if (!device) | 547 | if (!device) |
548 | return -EINVAL; | 548 | return -EINVAL; |
549 | printk(EEEPC_NOTICE EEEPC_HOTK_NAME "\n"); | 549 | printk(EEEPC_NOTICE EEEPC_HOTK_NAME "\n"); |
550 | ehotk = kzalloc(sizeof(struct eeepc_hotk), GFP_KERNEL); | 550 | ehotk = kzalloc(sizeof(struct eeepc_hotk), GFP_KERNEL); |
551 | if (!ehotk) | 551 | if (!ehotk) |
552 | return -ENOMEM; | 552 | return -ENOMEM; |
553 | ehotk->init_flag = DISABLE_ASL_WLAN | DISABLE_ASL_DISPLAYSWITCH; | 553 | ehotk->init_flag = DISABLE_ASL_WLAN | DISABLE_ASL_DISPLAYSWITCH; |
554 | ehotk->handle = device->handle; | 554 | ehotk->handle = device->handle; |
555 | strcpy(acpi_device_name(device), EEEPC_HOTK_DEVICE_NAME); | 555 | strcpy(acpi_device_name(device), EEEPC_HOTK_DEVICE_NAME); |
556 | strcpy(acpi_device_class(device), EEEPC_HOTK_CLASS); | 556 | strcpy(acpi_device_class(device), EEEPC_HOTK_CLASS); |
557 | device->driver_data = ehotk; | 557 | device->driver_data = ehotk; |
558 | ehotk->device = device; | 558 | ehotk->device = device; |
559 | result = eeepc_hotk_check(); | 559 | result = eeepc_hotk_check(); |
560 | if (result) | 560 | if (result) |
561 | goto end; | 561 | goto end; |
562 | status = acpi_install_notify_handler(ehotk->handle, ACPI_SYSTEM_NOTIFY, | 562 | status = acpi_install_notify_handler(ehotk->handle, ACPI_SYSTEM_NOTIFY, |
563 | eeepc_hotk_notify, ehotk); | 563 | eeepc_hotk_notify, ehotk); |
564 | if (ACPI_FAILURE(status)) | 564 | if (ACPI_FAILURE(status)) |
565 | printk(EEEPC_ERR "Error installing notify handler\n"); | 565 | printk(EEEPC_ERR "Error installing notify handler\n"); |
566 | 566 | ||
567 | if (get_acpi(CM_ASL_WLAN) != -1) { | 567 | if (get_acpi(CM_ASL_WLAN) != -1) { |
568 | ehotk->eeepc_wlan_rfkill = rfkill_allocate(&device->dev, | 568 | ehotk->eeepc_wlan_rfkill = rfkill_allocate(&device->dev, |
569 | RFKILL_TYPE_WLAN); | 569 | RFKILL_TYPE_WLAN); |
570 | 570 | ||
571 | if (!ehotk->eeepc_wlan_rfkill) | 571 | if (!ehotk->eeepc_wlan_rfkill) |
572 | goto end; | 572 | goto end; |
573 | 573 | ||
574 | ehotk->eeepc_wlan_rfkill->name = "eeepc-wlan"; | 574 | ehotk->eeepc_wlan_rfkill->name = "eeepc-wlan"; |
575 | ehotk->eeepc_wlan_rfkill->toggle_radio = eeepc_wlan_rfkill_set; | 575 | ehotk->eeepc_wlan_rfkill->toggle_radio = eeepc_wlan_rfkill_set; |
576 | ehotk->eeepc_wlan_rfkill->get_state = eeepc_wlan_rfkill_state; | 576 | ehotk->eeepc_wlan_rfkill->get_state = eeepc_wlan_rfkill_state; |
577 | if (get_acpi(CM_ASL_WLAN) == 1) | 577 | if (get_acpi(CM_ASL_WLAN) == 1) |
578 | ehotk->eeepc_wlan_rfkill->state = | 578 | ehotk->eeepc_wlan_rfkill->state = |
579 | RFKILL_STATE_UNBLOCKED; | 579 | RFKILL_STATE_UNBLOCKED; |
580 | else | 580 | else |
581 | ehotk->eeepc_wlan_rfkill->state = | 581 | ehotk->eeepc_wlan_rfkill->state = |
582 | RFKILL_STATE_SOFT_BLOCKED; | 582 | RFKILL_STATE_SOFT_BLOCKED; |
583 | rfkill_register(ehotk->eeepc_wlan_rfkill); | 583 | rfkill_register(ehotk->eeepc_wlan_rfkill); |
584 | } | 584 | } |
585 | 585 | ||
586 | if (get_acpi(CM_ASL_BLUETOOTH) != -1) { | 586 | if (get_acpi(CM_ASL_BLUETOOTH) != -1) { |
587 | ehotk->eeepc_bluetooth_rfkill = | 587 | ehotk->eeepc_bluetooth_rfkill = |
588 | rfkill_allocate(&device->dev, RFKILL_TYPE_BLUETOOTH); | 588 | rfkill_allocate(&device->dev, RFKILL_TYPE_BLUETOOTH); |
589 | 589 | ||
590 | if (!ehotk->eeepc_bluetooth_rfkill) | 590 | if (!ehotk->eeepc_bluetooth_rfkill) |
591 | goto end; | 591 | goto end; |
592 | 592 | ||
593 | ehotk->eeepc_bluetooth_rfkill->name = "eeepc-bluetooth"; | 593 | ehotk->eeepc_bluetooth_rfkill->name = "eeepc-bluetooth"; |
594 | ehotk->eeepc_bluetooth_rfkill->toggle_radio = | 594 | ehotk->eeepc_bluetooth_rfkill->toggle_radio = |
595 | eeepc_bluetooth_rfkill_set; | 595 | eeepc_bluetooth_rfkill_set; |
596 | ehotk->eeepc_bluetooth_rfkill->get_state = | 596 | ehotk->eeepc_bluetooth_rfkill->get_state = |
597 | eeepc_bluetooth_rfkill_state; | 597 | eeepc_bluetooth_rfkill_state; |
598 | if (get_acpi(CM_ASL_BLUETOOTH) == 1) | 598 | if (get_acpi(CM_ASL_BLUETOOTH) == 1) |
599 | ehotk->eeepc_bluetooth_rfkill->state = | 599 | ehotk->eeepc_bluetooth_rfkill->state = |
600 | RFKILL_STATE_UNBLOCKED; | 600 | RFKILL_STATE_UNBLOCKED; |
601 | else | 601 | else |
602 | ehotk->eeepc_bluetooth_rfkill->state = | 602 | ehotk->eeepc_bluetooth_rfkill->state = |
603 | RFKILL_STATE_SOFT_BLOCKED; | 603 | RFKILL_STATE_SOFT_BLOCKED; |
604 | rfkill_register(ehotk->eeepc_bluetooth_rfkill); | 604 | rfkill_register(ehotk->eeepc_bluetooth_rfkill); |
605 | } | 605 | } |
606 | 606 | ||
607 | end: | 607 | end: |
608 | if (result) { | 608 | if (result) { |
609 | kfree(ehotk); | 609 | kfree(ehotk); |
610 | ehotk = NULL; | 610 | ehotk = NULL; |
611 | } | 611 | } |
612 | return result; | 612 | return result; |
613 | } | 613 | } |
614 | 614 | ||
615 | static int eeepc_hotk_remove(struct acpi_device *device, int type) | 615 | static int eeepc_hotk_remove(struct acpi_device *device, int type) |
616 | { | 616 | { |
617 | acpi_status status = 0; | 617 | acpi_status status = 0; |
618 | 618 | ||
619 | if (!device || !acpi_driver_data(device)) | 619 | if (!device || !acpi_driver_data(device)) |
620 | return -EINVAL; | 620 | return -EINVAL; |
621 | status = acpi_remove_notify_handler(ehotk->handle, ACPI_SYSTEM_NOTIFY, | 621 | status = acpi_remove_notify_handler(ehotk->handle, ACPI_SYSTEM_NOTIFY, |
622 | eeepc_hotk_notify); | 622 | eeepc_hotk_notify); |
623 | if (ACPI_FAILURE(status)) | 623 | if (ACPI_FAILURE(status)) |
624 | printk(EEEPC_ERR "Error removing notify handler\n"); | 624 | printk(EEEPC_ERR "Error removing notify handler\n"); |
625 | kfree(ehotk); | 625 | kfree(ehotk); |
626 | return 0; | 626 | return 0; |
627 | } | 627 | } |
628 | 628 | ||
629 | /* | 629 | /* |
630 | * Hwmon | 630 | * Hwmon |
631 | */ | 631 | */ |
632 | static int eeepc_get_fan_pwm(void) | 632 | static int eeepc_get_fan_pwm(void) |
633 | { | 633 | { |
634 | int value = 0; | 634 | int value = 0; |
635 | 635 | ||
636 | read_acpi_int(NULL, EEEPC_EC_FAN_PWM, &value); | 636 | read_acpi_int(NULL, EEEPC_EC_FAN_PWM, &value); |
637 | value = value * 255 / 100; | 637 | value = value * 255 / 100; |
638 | return (value); | 638 | return (value); |
639 | } | 639 | } |
640 | 640 | ||
641 | static void eeepc_set_fan_pwm(int value) | 641 | static void eeepc_set_fan_pwm(int value) |
642 | { | 642 | { |
643 | value = SENSORS_LIMIT(value, 0, 255); | 643 | value = SENSORS_LIMIT(value, 0, 255); |
644 | value = value * 100 / 255; | 644 | value = value * 100 / 255; |
645 | ec_write(EEEPC_EC_SC02, value); | 645 | ec_write(EEEPC_EC_SC02, value); |
646 | } | 646 | } |
647 | 647 | ||
648 | static int eeepc_get_fan_rpm(void) | 648 | static int eeepc_get_fan_rpm(void) |
649 | { | 649 | { |
650 | int high = 0; | 650 | int high = 0; |
651 | int low = 0; | 651 | int low = 0; |
652 | 652 | ||
653 | read_acpi_int(NULL, EEEPC_EC_FAN_HRPM, &high); | 653 | read_acpi_int(NULL, EEEPC_EC_FAN_HRPM, &high); |
654 | read_acpi_int(NULL, EEEPC_EC_FAN_LRPM, &low); | 654 | read_acpi_int(NULL, EEEPC_EC_FAN_LRPM, &low); |
655 | return (high << 8 | low); | 655 | return (high << 8 | low); |
656 | } | 656 | } |
657 | 657 | ||
658 | static int eeepc_get_fan_ctrl(void) | 658 | static int eeepc_get_fan_ctrl(void) |
659 | { | 659 | { |
660 | int value = 0; | 660 | int value = 0; |
661 | 661 | ||
662 | read_acpi_int(NULL, EEEPC_EC_FAN_CTRL, &value); | 662 | read_acpi_int(NULL, EEEPC_EC_FAN_CTRL, &value); |
663 | return ((value & 0x02 ? 1 : 0)); | 663 | return ((value & 0x02 ? 1 : 0)); |
664 | } | 664 | } |
665 | 665 | ||
666 | static void eeepc_set_fan_ctrl(int manual) | 666 | static void eeepc_set_fan_ctrl(int manual) |
667 | { | 667 | { |
668 | int value = 0; | 668 | int value = 0; |
669 | 669 | ||
670 | read_acpi_int(NULL, EEEPC_EC_FAN_CTRL, &value); | 670 | read_acpi_int(NULL, EEEPC_EC_FAN_CTRL, &value); |
671 | if (manual) | 671 | if (manual) |
672 | value |= 0x02; | 672 | value |= 0x02; |
673 | else | 673 | else |
674 | value &= ~0x02; | 674 | value &= ~0x02; |
675 | ec_write(EEEPC_EC_SFB3, value); | 675 | ec_write(EEEPC_EC_SFB3, value); |
676 | } | 676 | } |
677 | 677 | ||
678 | static ssize_t store_sys_hwmon(void (*set)(int), const char *buf, size_t count) | 678 | static ssize_t store_sys_hwmon(void (*set)(int), const char *buf, size_t count) |
679 | { | 679 | { |
680 | int rv, value; | 680 | int rv, value; |
681 | 681 | ||
682 | rv = parse_arg(buf, count, &value); | 682 | rv = parse_arg(buf, count, &value); |
683 | if (rv > 0) | 683 | if (rv > 0) |
684 | set(value); | 684 | set(value); |
685 | return rv; | 685 | return rv; |
686 | } | 686 | } |
687 | 687 | ||
688 | static ssize_t show_sys_hwmon(int (*get)(void), char *buf) | 688 | static ssize_t show_sys_hwmon(int (*get)(void), char *buf) |
689 | { | 689 | { |
690 | return sprintf(buf, "%d\n", get()); | 690 | return sprintf(buf, "%d\n", get()); |
691 | } | 691 | } |
692 | 692 | ||
693 | #define EEEPC_CREATE_SENSOR_ATTR(_name, _mode, _set, _get) \ | 693 | #define EEEPC_CREATE_SENSOR_ATTR(_name, _mode, _set, _get) \ |
694 | static ssize_t show_##_name(struct device *dev, \ | 694 | static ssize_t show_##_name(struct device *dev, \ |
695 | struct device_attribute *attr, \ | 695 | struct device_attribute *attr, \ |
696 | char *buf) \ | 696 | char *buf) \ |
697 | { \ | 697 | { \ |
698 | return show_sys_hwmon(_set, buf); \ | 698 | return show_sys_hwmon(_set, buf); \ |
699 | } \ | 699 | } \ |
700 | static ssize_t store_##_name(struct device *dev, \ | 700 | static ssize_t store_##_name(struct device *dev, \ |
701 | struct device_attribute *attr, \ | 701 | struct device_attribute *attr, \ |
702 | const char *buf, size_t count) \ | 702 | const char *buf, size_t count) \ |
703 | { \ | 703 | { \ |
704 | return store_sys_hwmon(_get, buf, count); \ | 704 | return store_sys_hwmon(_get, buf, count); \ |
705 | } \ | 705 | } \ |
706 | static SENSOR_DEVICE_ATTR(_name, _mode, show_##_name, store_##_name, 0); | 706 | static SENSOR_DEVICE_ATTR(_name, _mode, show_##_name, store_##_name, 0); |
707 | 707 | ||
708 | EEEPC_CREATE_SENSOR_ATTR(fan1_input, S_IRUGO, eeepc_get_fan_rpm, NULL); | 708 | EEEPC_CREATE_SENSOR_ATTR(fan1_input, S_IRUGO, eeepc_get_fan_rpm, NULL); |
709 | EEEPC_CREATE_SENSOR_ATTR(pwm1, S_IRUGO | S_IWUSR, | 709 | EEEPC_CREATE_SENSOR_ATTR(pwm1, S_IRUGO | S_IWUSR, |
710 | eeepc_get_fan_pwm, eeepc_set_fan_pwm); | 710 | eeepc_get_fan_pwm, eeepc_set_fan_pwm); |
711 | EEEPC_CREATE_SENSOR_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, | 711 | EEEPC_CREATE_SENSOR_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, |
712 | eeepc_get_fan_ctrl, eeepc_set_fan_ctrl); | 712 | eeepc_get_fan_ctrl, eeepc_set_fan_ctrl); |
713 | 713 | ||
714 | static ssize_t | 714 | static ssize_t |
715 | show_name(struct device *dev, struct device_attribute *attr, char *buf) | 715 | show_name(struct device *dev, struct device_attribute *attr, char *buf) |
716 | { | 716 | { |
717 | return sprintf(buf, "eeepc\n"); | 717 | return sprintf(buf, "eeepc\n"); |
718 | } | 718 | } |
719 | static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0); | 719 | static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0); |
720 | 720 | ||
721 | static struct attribute *hwmon_attributes[] = { | 721 | static struct attribute *hwmon_attributes[] = { |
722 | &sensor_dev_attr_pwm1.dev_attr.attr, | 722 | &sensor_dev_attr_pwm1.dev_attr.attr, |
723 | &sensor_dev_attr_fan1_input.dev_attr.attr, | 723 | &sensor_dev_attr_fan1_input.dev_attr.attr, |
724 | &sensor_dev_attr_pwm1_enable.dev_attr.attr, | 724 | &sensor_dev_attr_pwm1_enable.dev_attr.attr, |
725 | &sensor_dev_attr_name.dev_attr.attr, | 725 | &sensor_dev_attr_name.dev_attr.attr, |
726 | NULL | 726 | NULL |
727 | }; | 727 | }; |
728 | 728 | ||
729 | static struct attribute_group hwmon_attribute_group = { | 729 | static struct attribute_group hwmon_attribute_group = { |
730 | .attrs = hwmon_attributes | 730 | .attrs = hwmon_attributes |
731 | }; | 731 | }; |
732 | 732 | ||
733 | /* | 733 | /* |
734 | * exit/init | 734 | * exit/init |
735 | */ | 735 | */ |
736 | static void eeepc_backlight_exit(void) | 736 | static void eeepc_backlight_exit(void) |
737 | { | 737 | { |
738 | if (eeepc_backlight_device) | 738 | if (eeepc_backlight_device) |
739 | backlight_device_unregister(eeepc_backlight_device); | 739 | backlight_device_unregister(eeepc_backlight_device); |
740 | if (ehotk->inputdev) | 740 | if (ehotk->inputdev) |
741 | input_unregister_device(ehotk->inputdev); | 741 | input_unregister_device(ehotk->inputdev); |
742 | if (ehotk->eeepc_wlan_rfkill) | 742 | if (ehotk->eeepc_wlan_rfkill) |
743 | rfkill_unregister(ehotk->eeepc_wlan_rfkill); | 743 | rfkill_unregister(ehotk->eeepc_wlan_rfkill); |
744 | if (ehotk->eeepc_bluetooth_rfkill) | 744 | if (ehotk->eeepc_bluetooth_rfkill) |
745 | rfkill_unregister(ehotk->eeepc_bluetooth_rfkill); | 745 | rfkill_unregister(ehotk->eeepc_bluetooth_rfkill); |
746 | eeepc_backlight_device = NULL; | 746 | eeepc_backlight_device = NULL; |
747 | } | 747 | } |
748 | 748 | ||
749 | static void eeepc_hwmon_exit(void) | 749 | static void eeepc_hwmon_exit(void) |
750 | { | 750 | { |
751 | struct device *hwmon; | 751 | struct device *hwmon; |
752 | 752 | ||
753 | hwmon = eeepc_hwmon_device; | 753 | hwmon = eeepc_hwmon_device; |
754 | if (!hwmon) | 754 | if (!hwmon) |
755 | return ; | 755 | return ; |
756 | sysfs_remove_group(&hwmon->kobj, | 756 | sysfs_remove_group(&hwmon->kobj, |
757 | &hwmon_attribute_group); | 757 | &hwmon_attribute_group); |
758 | hwmon_device_unregister(hwmon); | 758 | hwmon_device_unregister(hwmon); |
759 | eeepc_hwmon_device = NULL; | 759 | eeepc_hwmon_device = NULL; |
760 | } | 760 | } |
761 | 761 | ||
762 | static void __exit eeepc_laptop_exit(void) | 762 | static void __exit eeepc_laptop_exit(void) |
763 | { | 763 | { |
764 | eeepc_backlight_exit(); | 764 | eeepc_backlight_exit(); |
765 | eeepc_hwmon_exit(); | 765 | eeepc_hwmon_exit(); |
766 | acpi_bus_unregister_driver(&eeepc_hotk_driver); | 766 | acpi_bus_unregister_driver(&eeepc_hotk_driver); |
767 | sysfs_remove_group(&platform_device->dev.kobj, | 767 | sysfs_remove_group(&platform_device->dev.kobj, |
768 | &platform_attribute_group); | 768 | &platform_attribute_group); |
769 | platform_device_unregister(platform_device); | 769 | platform_device_unregister(platform_device); |
770 | platform_driver_unregister(&platform_driver); | 770 | platform_driver_unregister(&platform_driver); |
771 | } | 771 | } |
772 | 772 | ||
773 | static int eeepc_backlight_init(struct device *dev) | 773 | static int eeepc_backlight_init(struct device *dev) |
774 | { | 774 | { |
775 | struct backlight_device *bd; | 775 | struct backlight_device *bd; |
776 | 776 | ||
777 | bd = backlight_device_register(EEEPC_HOTK_FILE, dev, | 777 | bd = backlight_device_register(EEEPC_HOTK_FILE, dev, |
778 | NULL, &eeepcbl_ops); | 778 | NULL, &eeepcbl_ops); |
779 | if (IS_ERR(bd)) { | 779 | if (IS_ERR(bd)) { |
780 | printk(EEEPC_ERR | 780 | printk(EEEPC_ERR |
781 | "Could not register eeepc backlight device\n"); | 781 | "Could not register eeepc backlight device\n"); |
782 | eeepc_backlight_device = NULL; | 782 | eeepc_backlight_device = NULL; |
783 | return PTR_ERR(bd); | 783 | return PTR_ERR(bd); |
784 | } | 784 | } |
785 | eeepc_backlight_device = bd; | 785 | eeepc_backlight_device = bd; |
786 | bd->props.max_brightness = 15; | 786 | bd->props.max_brightness = 15; |
787 | bd->props.brightness = read_brightness(NULL); | 787 | bd->props.brightness = read_brightness(NULL); |
788 | bd->props.power = FB_BLANK_UNBLANK; | 788 | bd->props.power = FB_BLANK_UNBLANK; |
789 | backlight_update_status(bd); | 789 | backlight_update_status(bd); |
790 | return 0; | 790 | return 0; |
791 | } | 791 | } |
792 | 792 | ||
793 | static int eeepc_hwmon_init(struct device *dev) | 793 | static int eeepc_hwmon_init(struct device *dev) |
794 | { | 794 | { |
795 | struct device *hwmon; | 795 | struct device *hwmon; |
796 | int result; | 796 | int result; |
797 | 797 | ||
798 | hwmon = hwmon_device_register(dev); | 798 | hwmon = hwmon_device_register(dev); |
799 | if (IS_ERR(hwmon)) { | 799 | if (IS_ERR(hwmon)) { |
800 | printk(EEEPC_ERR | 800 | printk(EEEPC_ERR |
801 | "Could not register eeepc hwmon device\n"); | 801 | "Could not register eeepc hwmon device\n"); |
802 | eeepc_hwmon_device = NULL; | 802 | eeepc_hwmon_device = NULL; |
803 | return PTR_ERR(hwmon); | 803 | return PTR_ERR(hwmon); |
804 | } | 804 | } |
805 | eeepc_hwmon_device = hwmon; | 805 | eeepc_hwmon_device = hwmon; |
806 | result = sysfs_create_group(&hwmon->kobj, | 806 | result = sysfs_create_group(&hwmon->kobj, |
807 | &hwmon_attribute_group); | 807 | &hwmon_attribute_group); |
808 | if (result) | 808 | if (result) |
809 | eeepc_hwmon_exit(); | 809 | eeepc_hwmon_exit(); |
810 | return result; | 810 | return result; |
811 | } | 811 | } |
812 | 812 | ||
813 | static int __init eeepc_laptop_init(void) | 813 | static int __init eeepc_laptop_init(void) |
814 | { | 814 | { |
815 | struct device *dev; | 815 | struct device *dev; |
816 | int result; | 816 | int result; |
817 | 817 | ||
818 | if (acpi_disabled) | 818 | if (acpi_disabled) |
819 | return -ENODEV; | 819 | return -ENODEV; |
820 | result = acpi_bus_register_driver(&eeepc_hotk_driver); | 820 | result = acpi_bus_register_driver(&eeepc_hotk_driver); |
821 | if (result < 0) | 821 | if (result < 0) |
822 | return result; | 822 | return result; |
823 | if (!ehotk) { | 823 | if (!ehotk) { |
824 | acpi_bus_unregister_driver(&eeepc_hotk_driver); | 824 | acpi_bus_unregister_driver(&eeepc_hotk_driver); |
825 | return -ENODEV; | 825 | return -ENODEV; |
826 | } | 826 | } |
827 | dev = acpi_get_physical_device(ehotk->device->handle); | 827 | dev = acpi_get_physical_device(ehotk->device->handle); |
828 | result = eeepc_backlight_init(dev); | 828 | |
829 | if (result) | 829 | if (!acpi_video_backlight_support()) { |
830 | goto fail_backlight; | 830 | result = eeepc_backlight_init(dev); |
831 | if (result) | ||
832 | goto fail_backlight; | ||
833 | } else | ||
834 | printk(EEEPC_INFO "Backlight controlled by ACPI video " | ||
835 | "driver\n"); | ||
836 | |||
831 | result = eeepc_hwmon_init(dev); | 837 | result = eeepc_hwmon_init(dev); |
832 | if (result) | 838 | if (result) |
833 | goto fail_hwmon; | 839 | goto fail_hwmon; |
834 | /* Register platform stuff */ | 840 | /* Register platform stuff */ |
835 | result = platform_driver_register(&platform_driver); | 841 | result = platform_driver_register(&platform_driver); |
836 | if (result) | 842 | if (result) |
837 | goto fail_platform_driver; | 843 | goto fail_platform_driver; |
838 | platform_device = platform_device_alloc(EEEPC_HOTK_FILE, -1); | 844 | platform_device = platform_device_alloc(EEEPC_HOTK_FILE, -1); |
839 | if (!platform_device) { | 845 | if (!platform_device) { |
840 | result = -ENOMEM; | 846 | result = -ENOMEM; |
841 | goto fail_platform_device1; | 847 | goto fail_platform_device1; |
842 | } | 848 | } |
843 | result = platform_device_add(platform_device); | 849 | result = platform_device_add(platform_device); |
844 | if (result) | 850 | if (result) |
845 | goto fail_platform_device2; | 851 | goto fail_platform_device2; |
846 | result = sysfs_create_group(&platform_device->dev.kobj, | 852 | result = sysfs_create_group(&platform_device->dev.kobj, |
847 | &platform_attribute_group); | 853 | &platform_attribute_group); |
848 | if (result) | 854 | if (result) |
849 | goto fail_sysfs; | 855 | goto fail_sysfs; |
850 | return 0; | 856 | return 0; |
851 | fail_sysfs: | 857 | fail_sysfs: |
852 | platform_device_del(platform_device); | 858 | platform_device_del(platform_device); |
853 | fail_platform_device2: | 859 | fail_platform_device2: |
854 | platform_device_put(platform_device); | 860 | platform_device_put(platform_device); |
855 | fail_platform_device1: | 861 | fail_platform_device1: |
856 | platform_driver_unregister(&platform_driver); | 862 | platform_driver_unregister(&platform_driver); |
857 | fail_platform_driver: | 863 | fail_platform_driver: |
858 | eeepc_hwmon_exit(); | 864 | eeepc_hwmon_exit(); |
859 | fail_hwmon: | 865 | fail_hwmon: |
860 | eeepc_backlight_exit(); | 866 | eeepc_backlight_exit(); |
861 | fail_backlight: | 867 | fail_backlight: |
862 | return result; | 868 | return result; |
863 | } | 869 | } |
864 | 870 | ||
865 | module_init(eeepc_laptop_init); | 871 | module_init(eeepc_laptop_init); |
866 | module_exit(eeepc_laptop_exit); | 872 | module_exit(eeepc_laptop_exit); |
867 | 873 |
drivers/misc/fujitsu-laptop.c
1 | /*-*-linux-c-*-*/ | 1 | /*-*-linux-c-*-*/ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | Copyright (C) 2007,2008 Jonathan Woithe <jwoithe@physics.adelaide.edu.au> | 4 | Copyright (C) 2007,2008 Jonathan Woithe <jwoithe@physics.adelaide.edu.au> |
5 | Copyright (C) 2008 Peter Gruber <nokos@gmx.net> | 5 | Copyright (C) 2008 Peter Gruber <nokos@gmx.net> |
6 | Based on earlier work: | 6 | Based on earlier work: |
7 | Copyright (C) 2003 Shane Spencer <shane@bogomip.com> | 7 | Copyright (C) 2003 Shane Spencer <shane@bogomip.com> |
8 | Adrian Yee <brewt-fujitsu@brewt.org> | 8 | Adrian Yee <brewt-fujitsu@brewt.org> |
9 | 9 | ||
10 | Templated from msi-laptop.c and thinkpad_acpi.c which is copyright | 10 | Templated from msi-laptop.c and thinkpad_acpi.c which is copyright |
11 | by its respective authors. | 11 | by its respective authors. |
12 | 12 | ||
13 | This program is free software; you can redistribute it and/or modify | 13 | This program is free software; you can redistribute it and/or modify |
14 | it under the terms of the GNU General Public License as published by | 14 | it under the terms of the GNU General Public License as published by |
15 | the Free Software Foundation; either version 2 of the License, or | 15 | the Free Software Foundation; either version 2 of the License, or |
16 | (at your option) any later version. | 16 | (at your option) any later version. |
17 | 17 | ||
18 | This program is distributed in the hope that it will be useful, but | 18 | This program is distributed in the hope that it will be useful, but |
19 | WITHOUT ANY WARRANTY; without even the implied warranty of | 19 | WITHOUT ANY WARRANTY; without even the implied warranty of |
20 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 20 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
21 | General Public License for more details. | 21 | General Public License for more details. |
22 | 22 | ||
23 | You should have received a copy of the GNU General Public License | 23 | You should have received a copy of the GNU General Public License |
24 | along with this program; if not, write to the Free Software | 24 | along with this program; if not, write to the Free Software |
25 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | 25 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
26 | 02110-1301, USA. | 26 | 02110-1301, USA. |
27 | */ | 27 | */ |
28 | 28 | ||
29 | /* | 29 | /* |
30 | * fujitsu-laptop.c - Fujitsu laptop support, providing access to additional | 30 | * fujitsu-laptop.c - Fujitsu laptop support, providing access to additional |
31 | * features made available on a range of Fujitsu laptops including the | 31 | * features made available on a range of Fujitsu laptops including the |
32 | * P2xxx/P5xxx/S6xxx/S7xxx series. | 32 | * P2xxx/P5xxx/S6xxx/S7xxx series. |
33 | * | 33 | * |
34 | * This driver exports a few files in /sys/devices/platform/fujitsu-laptop/; | 34 | * This driver exports a few files in /sys/devices/platform/fujitsu-laptop/; |
35 | * others may be added at a later date. | 35 | * others may be added at a later date. |
36 | * | 36 | * |
37 | * lcd_level - Screen brightness: contains a single integer in the | 37 | * lcd_level - Screen brightness: contains a single integer in the |
38 | * range 0..7. (rw) | 38 | * range 0..7. (rw) |
39 | * | 39 | * |
40 | * In addition to these platform device attributes the driver | 40 | * In addition to these platform device attributes the driver |
41 | * registers itself in the Linux backlight control subsystem and is | 41 | * registers itself in the Linux backlight control subsystem and is |
42 | * available to userspace under /sys/class/backlight/fujitsu-laptop/. | 42 | * available to userspace under /sys/class/backlight/fujitsu-laptop/. |
43 | * | 43 | * |
44 | * Hotkeys present on certain Fujitsu laptops (eg: the S6xxx series) are | 44 | * Hotkeys present on certain Fujitsu laptops (eg: the S6xxx series) are |
45 | * also supported by this driver. | 45 | * also supported by this driver. |
46 | * | 46 | * |
47 | * This driver has been tested on a Fujitsu Lifebook S6410, S7020 and | 47 | * This driver has been tested on a Fujitsu Lifebook S6410, S7020 and |
48 | * P8010. It should work on most P-series and S-series Lifebooks, but | 48 | * P8010. It should work on most P-series and S-series Lifebooks, but |
49 | * YMMV. | 49 | * YMMV. |
50 | * | 50 | * |
51 | * The module parameter use_alt_lcd_levels switches between different ACPI | 51 | * The module parameter use_alt_lcd_levels switches between different ACPI |
52 | * brightness controls which are used by different Fujitsu laptops. In most | 52 | * brightness controls which are used by different Fujitsu laptops. In most |
53 | * cases the correct method is automatically detected. "use_alt_lcd_levels=1" | 53 | * cases the correct method is automatically detected. "use_alt_lcd_levels=1" |
54 | * is applicable for a Fujitsu Lifebook S6410 if autodetection fails. | 54 | * is applicable for a Fujitsu Lifebook S6410 if autodetection fails. |
55 | * | 55 | * |
56 | */ | 56 | */ |
57 | 57 | ||
58 | #include <linux/module.h> | 58 | #include <linux/module.h> |
59 | #include <linux/kernel.h> | 59 | #include <linux/kernel.h> |
60 | #include <linux/init.h> | 60 | #include <linux/init.h> |
61 | #include <linux/acpi.h> | 61 | #include <linux/acpi.h> |
62 | #include <linux/dmi.h> | 62 | #include <linux/dmi.h> |
63 | #include <linux/backlight.h> | 63 | #include <linux/backlight.h> |
64 | #include <linux/input.h> | 64 | #include <linux/input.h> |
65 | #include <linux/kfifo.h> | 65 | #include <linux/kfifo.h> |
66 | #include <linux/video_output.h> | 66 | #include <linux/video_output.h> |
67 | #include <linux/platform_device.h> | 67 | #include <linux/platform_device.h> |
68 | 68 | ||
69 | #define FUJITSU_DRIVER_VERSION "0.4.3" | 69 | #define FUJITSU_DRIVER_VERSION "0.4.3" |
70 | 70 | ||
71 | #define FUJITSU_LCD_N_LEVELS 8 | 71 | #define FUJITSU_LCD_N_LEVELS 8 |
72 | 72 | ||
73 | #define ACPI_FUJITSU_CLASS "fujitsu" | 73 | #define ACPI_FUJITSU_CLASS "fujitsu" |
74 | #define ACPI_FUJITSU_HID "FUJ02B1" | 74 | #define ACPI_FUJITSU_HID "FUJ02B1" |
75 | #define ACPI_FUJITSU_DRIVER_NAME "Fujitsu laptop FUJ02B1 ACPI brightness driver" | 75 | #define ACPI_FUJITSU_DRIVER_NAME "Fujitsu laptop FUJ02B1 ACPI brightness driver" |
76 | #define ACPI_FUJITSU_DEVICE_NAME "Fujitsu FUJ02B1" | 76 | #define ACPI_FUJITSU_DEVICE_NAME "Fujitsu FUJ02B1" |
77 | #define ACPI_FUJITSU_HOTKEY_HID "FUJ02E3" | 77 | #define ACPI_FUJITSU_HOTKEY_HID "FUJ02E3" |
78 | #define ACPI_FUJITSU_HOTKEY_DRIVER_NAME "Fujitsu laptop FUJ02E3 ACPI hotkeys driver" | 78 | #define ACPI_FUJITSU_HOTKEY_DRIVER_NAME "Fujitsu laptop FUJ02E3 ACPI hotkeys driver" |
79 | #define ACPI_FUJITSU_HOTKEY_DEVICE_NAME "Fujitsu FUJ02E3" | 79 | #define ACPI_FUJITSU_HOTKEY_DEVICE_NAME "Fujitsu FUJ02E3" |
80 | 80 | ||
81 | #define ACPI_FUJITSU_NOTIFY_CODE1 0x80 | 81 | #define ACPI_FUJITSU_NOTIFY_CODE1 0x80 |
82 | 82 | ||
83 | #define ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS 0x86 | 83 | #define ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS 0x86 |
84 | #define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS 0x87 | 84 | #define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS 0x87 |
85 | 85 | ||
86 | /* Hotkey details */ | 86 | /* Hotkey details */ |
87 | #define KEY1_CODE 0x410 /* codes for the keys in the GIRB register */ | 87 | #define KEY1_CODE 0x410 /* codes for the keys in the GIRB register */ |
88 | #define KEY2_CODE 0x411 | 88 | #define KEY2_CODE 0x411 |
89 | #define KEY3_CODE 0x412 | 89 | #define KEY3_CODE 0x412 |
90 | #define KEY4_CODE 0x413 | 90 | #define KEY4_CODE 0x413 |
91 | 91 | ||
92 | #define MAX_HOTKEY_RINGBUFFER_SIZE 100 | 92 | #define MAX_HOTKEY_RINGBUFFER_SIZE 100 |
93 | #define RINGBUFFERSIZE 40 | 93 | #define RINGBUFFERSIZE 40 |
94 | 94 | ||
95 | /* Debugging */ | 95 | /* Debugging */ |
96 | #define FUJLAPTOP_LOG ACPI_FUJITSU_HID ": " | 96 | #define FUJLAPTOP_LOG ACPI_FUJITSU_HID ": " |
97 | #define FUJLAPTOP_ERR KERN_ERR FUJLAPTOP_LOG | 97 | #define FUJLAPTOP_ERR KERN_ERR FUJLAPTOP_LOG |
98 | #define FUJLAPTOP_NOTICE KERN_NOTICE FUJLAPTOP_LOG | 98 | #define FUJLAPTOP_NOTICE KERN_NOTICE FUJLAPTOP_LOG |
99 | #define FUJLAPTOP_INFO KERN_INFO FUJLAPTOP_LOG | 99 | #define FUJLAPTOP_INFO KERN_INFO FUJLAPTOP_LOG |
100 | #define FUJLAPTOP_DEBUG KERN_DEBUG FUJLAPTOP_LOG | 100 | #define FUJLAPTOP_DEBUG KERN_DEBUG FUJLAPTOP_LOG |
101 | 101 | ||
102 | #define FUJLAPTOP_DBG_ALL 0xffff | 102 | #define FUJLAPTOP_DBG_ALL 0xffff |
103 | #define FUJLAPTOP_DBG_ERROR 0x0001 | 103 | #define FUJLAPTOP_DBG_ERROR 0x0001 |
104 | #define FUJLAPTOP_DBG_WARN 0x0002 | 104 | #define FUJLAPTOP_DBG_WARN 0x0002 |
105 | #define FUJLAPTOP_DBG_INFO 0x0004 | 105 | #define FUJLAPTOP_DBG_INFO 0x0004 |
106 | #define FUJLAPTOP_DBG_TRACE 0x0008 | 106 | #define FUJLAPTOP_DBG_TRACE 0x0008 |
107 | 107 | ||
108 | #define dbg_printk(a_dbg_level, format, arg...) \ | 108 | #define dbg_printk(a_dbg_level, format, arg...) \ |
109 | do { if (dbg_level & a_dbg_level) \ | 109 | do { if (dbg_level & a_dbg_level) \ |
110 | printk(FUJLAPTOP_DEBUG "%s: " format, __func__ , ## arg); \ | 110 | printk(FUJLAPTOP_DEBUG "%s: " format, __func__ , ## arg); \ |
111 | } while (0) | 111 | } while (0) |
112 | #ifdef CONFIG_FUJITSU_LAPTOP_DEBUG | 112 | #ifdef CONFIG_FUJITSU_LAPTOP_DEBUG |
113 | #define vdbg_printk(a_dbg_level, format, arg...) \ | 113 | #define vdbg_printk(a_dbg_level, format, arg...) \ |
114 | dbg_printk(a_dbg_level, format, ## arg) | 114 | dbg_printk(a_dbg_level, format, ## arg) |
115 | #else | 115 | #else |
116 | #define vdbg_printk(a_dbg_level, format, arg...) | 116 | #define vdbg_printk(a_dbg_level, format, arg...) |
117 | #endif | 117 | #endif |
118 | 118 | ||
119 | /* Device controlling the backlight and associated keys */ | 119 | /* Device controlling the backlight and associated keys */ |
120 | struct fujitsu_t { | 120 | struct fujitsu_t { |
121 | acpi_handle acpi_handle; | 121 | acpi_handle acpi_handle; |
122 | struct acpi_device *dev; | 122 | struct acpi_device *dev; |
123 | struct input_dev *input; | 123 | struct input_dev *input; |
124 | char phys[32]; | 124 | char phys[32]; |
125 | struct backlight_device *bl_device; | 125 | struct backlight_device *bl_device; |
126 | struct platform_device *pf_device; | 126 | struct platform_device *pf_device; |
127 | int keycode1, keycode2, keycode3, keycode4; | 127 | int keycode1, keycode2, keycode3, keycode4; |
128 | 128 | ||
129 | unsigned int max_brightness; | 129 | unsigned int max_brightness; |
130 | unsigned int brightness_changed; | 130 | unsigned int brightness_changed; |
131 | unsigned int brightness_level; | 131 | unsigned int brightness_level; |
132 | }; | 132 | }; |
133 | 133 | ||
134 | static struct fujitsu_t *fujitsu; | 134 | static struct fujitsu_t *fujitsu; |
135 | static int use_alt_lcd_levels = -1; | 135 | static int use_alt_lcd_levels = -1; |
136 | static int disable_brightness_keys = -1; | 136 | static int disable_brightness_keys = -1; |
137 | static int disable_brightness_adjust = -1; | 137 | static int disable_brightness_adjust = -1; |
138 | 138 | ||
139 | /* Device used to access other hotkeys on the laptop */ | 139 | /* Device used to access other hotkeys on the laptop */ |
140 | struct fujitsu_hotkey_t { | 140 | struct fujitsu_hotkey_t { |
141 | acpi_handle acpi_handle; | 141 | acpi_handle acpi_handle; |
142 | struct acpi_device *dev; | 142 | struct acpi_device *dev; |
143 | struct input_dev *input; | 143 | struct input_dev *input; |
144 | char phys[32]; | 144 | char phys[32]; |
145 | struct platform_device *pf_device; | 145 | struct platform_device *pf_device; |
146 | struct kfifo *fifo; | 146 | struct kfifo *fifo; |
147 | spinlock_t fifo_lock; | 147 | spinlock_t fifo_lock; |
148 | 148 | ||
149 | unsigned int irb; /* info about the pressed buttons */ | 149 | unsigned int irb; /* info about the pressed buttons */ |
150 | }; | 150 | }; |
151 | 151 | ||
152 | static struct fujitsu_hotkey_t *fujitsu_hotkey; | 152 | static struct fujitsu_hotkey_t *fujitsu_hotkey; |
153 | 153 | ||
154 | static void acpi_fujitsu_hotkey_notify(acpi_handle handle, u32 event, | 154 | static void acpi_fujitsu_hotkey_notify(acpi_handle handle, u32 event, |
155 | void *data); | 155 | void *data); |
156 | 156 | ||
157 | #ifdef CONFIG_FUJITSU_LAPTOP_DEBUG | 157 | #ifdef CONFIG_FUJITSU_LAPTOP_DEBUG |
158 | static u32 dbg_level = 0x03; | 158 | static u32 dbg_level = 0x03; |
159 | #endif | 159 | #endif |
160 | 160 | ||
161 | static void acpi_fujitsu_notify(acpi_handle handle, u32 event, void *data); | 161 | static void acpi_fujitsu_notify(acpi_handle handle, u32 event, void *data); |
162 | 162 | ||
163 | /* Hardware access for LCD brightness control */ | 163 | /* Hardware access for LCD brightness control */ |
164 | 164 | ||
165 | static int set_lcd_level(int level) | 165 | static int set_lcd_level(int level) |
166 | { | 166 | { |
167 | acpi_status status = AE_OK; | 167 | acpi_status status = AE_OK; |
168 | union acpi_object arg0 = { ACPI_TYPE_INTEGER }; | 168 | union acpi_object arg0 = { ACPI_TYPE_INTEGER }; |
169 | struct acpi_object_list arg_list = { 1, &arg0 }; | 169 | struct acpi_object_list arg_list = { 1, &arg0 }; |
170 | acpi_handle handle = NULL; | 170 | acpi_handle handle = NULL; |
171 | 171 | ||
172 | vdbg_printk(FUJLAPTOP_DBG_TRACE, "set lcd level via SBLL [%d]\n", | 172 | vdbg_printk(FUJLAPTOP_DBG_TRACE, "set lcd level via SBLL [%d]\n", |
173 | level); | 173 | level); |
174 | 174 | ||
175 | if (level < 0 || level >= fujitsu->max_brightness) | 175 | if (level < 0 || level >= fujitsu->max_brightness) |
176 | return -EINVAL; | 176 | return -EINVAL; |
177 | 177 | ||
178 | if (!fujitsu) | 178 | if (!fujitsu) |
179 | return -EINVAL; | 179 | return -EINVAL; |
180 | 180 | ||
181 | status = acpi_get_handle(fujitsu->acpi_handle, "SBLL", &handle); | 181 | status = acpi_get_handle(fujitsu->acpi_handle, "SBLL", &handle); |
182 | if (ACPI_FAILURE(status)) { | 182 | if (ACPI_FAILURE(status)) { |
183 | vdbg_printk(FUJLAPTOP_DBG_ERROR, "SBLL not present\n"); | 183 | vdbg_printk(FUJLAPTOP_DBG_ERROR, "SBLL not present\n"); |
184 | return -ENODEV; | 184 | return -ENODEV; |
185 | } | 185 | } |
186 | 186 | ||
187 | arg0.integer.value = level; | 187 | arg0.integer.value = level; |
188 | 188 | ||
189 | status = acpi_evaluate_object(handle, NULL, &arg_list, NULL); | 189 | status = acpi_evaluate_object(handle, NULL, &arg_list, NULL); |
190 | if (ACPI_FAILURE(status)) | 190 | if (ACPI_FAILURE(status)) |
191 | return -ENODEV; | 191 | return -ENODEV; |
192 | 192 | ||
193 | return 0; | 193 | return 0; |
194 | } | 194 | } |
195 | 195 | ||
196 | static int set_lcd_level_alt(int level) | 196 | static int set_lcd_level_alt(int level) |
197 | { | 197 | { |
198 | acpi_status status = AE_OK; | 198 | acpi_status status = AE_OK; |
199 | union acpi_object arg0 = { ACPI_TYPE_INTEGER }; | 199 | union acpi_object arg0 = { ACPI_TYPE_INTEGER }; |
200 | struct acpi_object_list arg_list = { 1, &arg0 }; | 200 | struct acpi_object_list arg_list = { 1, &arg0 }; |
201 | acpi_handle handle = NULL; | 201 | acpi_handle handle = NULL; |
202 | 202 | ||
203 | vdbg_printk(FUJLAPTOP_DBG_TRACE, "set lcd level via SBL2 [%d]\n", | 203 | vdbg_printk(FUJLAPTOP_DBG_TRACE, "set lcd level via SBL2 [%d]\n", |
204 | level); | 204 | level); |
205 | 205 | ||
206 | if (level < 0 || level >= fujitsu->max_brightness) | 206 | if (level < 0 || level >= fujitsu->max_brightness) |
207 | return -EINVAL; | 207 | return -EINVAL; |
208 | 208 | ||
209 | if (!fujitsu) | 209 | if (!fujitsu) |
210 | return -EINVAL; | 210 | return -EINVAL; |
211 | 211 | ||
212 | status = acpi_get_handle(fujitsu->acpi_handle, "SBL2", &handle); | 212 | status = acpi_get_handle(fujitsu->acpi_handle, "SBL2", &handle); |
213 | if (ACPI_FAILURE(status)) { | 213 | if (ACPI_FAILURE(status)) { |
214 | vdbg_printk(FUJLAPTOP_DBG_ERROR, "SBL2 not present\n"); | 214 | vdbg_printk(FUJLAPTOP_DBG_ERROR, "SBL2 not present\n"); |
215 | return -ENODEV; | 215 | return -ENODEV; |
216 | } | 216 | } |
217 | 217 | ||
218 | arg0.integer.value = level; | 218 | arg0.integer.value = level; |
219 | 219 | ||
220 | status = acpi_evaluate_object(handle, NULL, &arg_list, NULL); | 220 | status = acpi_evaluate_object(handle, NULL, &arg_list, NULL); |
221 | if (ACPI_FAILURE(status)) | 221 | if (ACPI_FAILURE(status)) |
222 | return -ENODEV; | 222 | return -ENODEV; |
223 | 223 | ||
224 | return 0; | 224 | return 0; |
225 | } | 225 | } |
226 | 226 | ||
227 | static int get_lcd_level(void) | 227 | static int get_lcd_level(void) |
228 | { | 228 | { |
229 | unsigned long long state = 0; | 229 | unsigned long long state = 0; |
230 | acpi_status status = AE_OK; | 230 | acpi_status status = AE_OK; |
231 | 231 | ||
232 | vdbg_printk(FUJLAPTOP_DBG_TRACE, "get lcd level via GBLL\n"); | 232 | vdbg_printk(FUJLAPTOP_DBG_TRACE, "get lcd level via GBLL\n"); |
233 | 233 | ||
234 | status = | 234 | status = |
235 | acpi_evaluate_integer(fujitsu->acpi_handle, "GBLL", NULL, &state); | 235 | acpi_evaluate_integer(fujitsu->acpi_handle, "GBLL", NULL, &state); |
236 | if (status < 0) | 236 | if (status < 0) |
237 | return status; | 237 | return status; |
238 | 238 | ||
239 | fujitsu->brightness_level = state & 0x0fffffff; | 239 | fujitsu->brightness_level = state & 0x0fffffff; |
240 | 240 | ||
241 | if (state & 0x80000000) | 241 | if (state & 0x80000000) |
242 | fujitsu->brightness_changed = 1; | 242 | fujitsu->brightness_changed = 1; |
243 | else | 243 | else |
244 | fujitsu->brightness_changed = 0; | 244 | fujitsu->brightness_changed = 0; |
245 | 245 | ||
246 | return fujitsu->brightness_level; | 246 | return fujitsu->brightness_level; |
247 | } | 247 | } |
248 | 248 | ||
249 | static int get_max_brightness(void) | 249 | static int get_max_brightness(void) |
250 | { | 250 | { |
251 | unsigned long long state = 0; | 251 | unsigned long long state = 0; |
252 | acpi_status status = AE_OK; | 252 | acpi_status status = AE_OK; |
253 | 253 | ||
254 | vdbg_printk(FUJLAPTOP_DBG_TRACE, "get max lcd level via RBLL\n"); | 254 | vdbg_printk(FUJLAPTOP_DBG_TRACE, "get max lcd level via RBLL\n"); |
255 | 255 | ||
256 | status = | 256 | status = |
257 | acpi_evaluate_integer(fujitsu->acpi_handle, "RBLL", NULL, &state); | 257 | acpi_evaluate_integer(fujitsu->acpi_handle, "RBLL", NULL, &state); |
258 | if (status < 0) | 258 | if (status < 0) |
259 | return status; | 259 | return status; |
260 | 260 | ||
261 | fujitsu->max_brightness = state; | 261 | fujitsu->max_brightness = state; |
262 | 262 | ||
263 | return fujitsu->max_brightness; | 263 | return fujitsu->max_brightness; |
264 | } | 264 | } |
265 | 265 | ||
266 | static int get_lcd_level_alt(void) | 266 | static int get_lcd_level_alt(void) |
267 | { | 267 | { |
268 | unsigned long long state = 0; | 268 | unsigned long long state = 0; |
269 | acpi_status status = AE_OK; | 269 | acpi_status status = AE_OK; |
270 | 270 | ||
271 | vdbg_printk(FUJLAPTOP_DBG_TRACE, "get lcd level via GBLS\n"); | 271 | vdbg_printk(FUJLAPTOP_DBG_TRACE, "get lcd level via GBLS\n"); |
272 | 272 | ||
273 | status = | 273 | status = |
274 | acpi_evaluate_integer(fujitsu->acpi_handle, "GBLS", NULL, &state); | 274 | acpi_evaluate_integer(fujitsu->acpi_handle, "GBLS", NULL, &state); |
275 | if (status < 0) | 275 | if (status < 0) |
276 | return status; | 276 | return status; |
277 | 277 | ||
278 | fujitsu->brightness_level = state & 0x0fffffff; | 278 | fujitsu->brightness_level = state & 0x0fffffff; |
279 | 279 | ||
280 | if (state & 0x80000000) | 280 | if (state & 0x80000000) |
281 | fujitsu->brightness_changed = 1; | 281 | fujitsu->brightness_changed = 1; |
282 | else | 282 | else |
283 | fujitsu->brightness_changed = 0; | 283 | fujitsu->brightness_changed = 0; |
284 | 284 | ||
285 | return fujitsu->brightness_level; | 285 | return fujitsu->brightness_level; |
286 | } | 286 | } |
287 | 287 | ||
288 | /* Backlight device stuff */ | 288 | /* Backlight device stuff */ |
289 | 289 | ||
290 | static int bl_get_brightness(struct backlight_device *b) | 290 | static int bl_get_brightness(struct backlight_device *b) |
291 | { | 291 | { |
292 | if (use_alt_lcd_levels) | 292 | if (use_alt_lcd_levels) |
293 | return get_lcd_level_alt(); | 293 | return get_lcd_level_alt(); |
294 | else | 294 | else |
295 | return get_lcd_level(); | 295 | return get_lcd_level(); |
296 | } | 296 | } |
297 | 297 | ||
298 | static int bl_update_status(struct backlight_device *b) | 298 | static int bl_update_status(struct backlight_device *b) |
299 | { | 299 | { |
300 | if (use_alt_lcd_levels) | 300 | if (use_alt_lcd_levels) |
301 | return set_lcd_level_alt(b->props.brightness); | 301 | return set_lcd_level_alt(b->props.brightness); |
302 | else | 302 | else |
303 | return set_lcd_level(b->props.brightness); | 303 | return set_lcd_level(b->props.brightness); |
304 | } | 304 | } |
305 | 305 | ||
306 | static struct backlight_ops fujitsubl_ops = { | 306 | static struct backlight_ops fujitsubl_ops = { |
307 | .get_brightness = bl_get_brightness, | 307 | .get_brightness = bl_get_brightness, |
308 | .update_status = bl_update_status, | 308 | .update_status = bl_update_status, |
309 | }; | 309 | }; |
310 | 310 | ||
311 | /* Platform LCD brightness device */ | 311 | /* Platform LCD brightness device */ |
312 | 312 | ||
313 | static ssize_t | 313 | static ssize_t |
314 | show_max_brightness(struct device *dev, | 314 | show_max_brightness(struct device *dev, |
315 | struct device_attribute *attr, char *buf) | 315 | struct device_attribute *attr, char *buf) |
316 | { | 316 | { |
317 | 317 | ||
318 | int ret; | 318 | int ret; |
319 | 319 | ||
320 | ret = get_max_brightness(); | 320 | ret = get_max_brightness(); |
321 | if (ret < 0) | 321 | if (ret < 0) |
322 | return ret; | 322 | return ret; |
323 | 323 | ||
324 | return sprintf(buf, "%i\n", ret); | 324 | return sprintf(buf, "%i\n", ret); |
325 | } | 325 | } |
326 | 326 | ||
327 | static ssize_t | 327 | static ssize_t |
328 | show_brightness_changed(struct device *dev, | 328 | show_brightness_changed(struct device *dev, |
329 | struct device_attribute *attr, char *buf) | 329 | struct device_attribute *attr, char *buf) |
330 | { | 330 | { |
331 | 331 | ||
332 | int ret; | 332 | int ret; |
333 | 333 | ||
334 | ret = fujitsu->brightness_changed; | 334 | ret = fujitsu->brightness_changed; |
335 | if (ret < 0) | 335 | if (ret < 0) |
336 | return ret; | 336 | return ret; |
337 | 337 | ||
338 | return sprintf(buf, "%i\n", ret); | 338 | return sprintf(buf, "%i\n", ret); |
339 | } | 339 | } |
340 | 340 | ||
341 | static ssize_t show_lcd_level(struct device *dev, | 341 | static ssize_t show_lcd_level(struct device *dev, |
342 | struct device_attribute *attr, char *buf) | 342 | struct device_attribute *attr, char *buf) |
343 | { | 343 | { |
344 | 344 | ||
345 | int ret; | 345 | int ret; |
346 | 346 | ||
347 | if (use_alt_lcd_levels) | 347 | if (use_alt_lcd_levels) |
348 | ret = get_lcd_level_alt(); | 348 | ret = get_lcd_level_alt(); |
349 | else | 349 | else |
350 | ret = get_lcd_level(); | 350 | ret = get_lcd_level(); |
351 | if (ret < 0) | 351 | if (ret < 0) |
352 | return ret; | 352 | return ret; |
353 | 353 | ||
354 | return sprintf(buf, "%i\n", ret); | 354 | return sprintf(buf, "%i\n", ret); |
355 | } | 355 | } |
356 | 356 | ||
357 | static ssize_t store_lcd_level(struct device *dev, | 357 | static ssize_t store_lcd_level(struct device *dev, |
358 | struct device_attribute *attr, const char *buf, | 358 | struct device_attribute *attr, const char *buf, |
359 | size_t count) | 359 | size_t count) |
360 | { | 360 | { |
361 | 361 | ||
362 | int level, ret; | 362 | int level, ret; |
363 | 363 | ||
364 | if (sscanf(buf, "%i", &level) != 1 | 364 | if (sscanf(buf, "%i", &level) != 1 |
365 | || (level < 0 || level >= fujitsu->max_brightness)) | 365 | || (level < 0 || level >= fujitsu->max_brightness)) |
366 | return -EINVAL; | 366 | return -EINVAL; |
367 | 367 | ||
368 | if (use_alt_lcd_levels) | 368 | if (use_alt_lcd_levels) |
369 | ret = set_lcd_level_alt(level); | 369 | ret = set_lcd_level_alt(level); |
370 | else | 370 | else |
371 | ret = set_lcd_level(level); | 371 | ret = set_lcd_level(level); |
372 | if (ret < 0) | 372 | if (ret < 0) |
373 | return ret; | 373 | return ret; |
374 | 374 | ||
375 | if (use_alt_lcd_levels) | 375 | if (use_alt_lcd_levels) |
376 | ret = get_lcd_level_alt(); | 376 | ret = get_lcd_level_alt(); |
377 | else | 377 | else |
378 | ret = get_lcd_level(); | 378 | ret = get_lcd_level(); |
379 | if (ret < 0) | 379 | if (ret < 0) |
380 | return ret; | 380 | return ret; |
381 | 381 | ||
382 | return count; | 382 | return count; |
383 | } | 383 | } |
384 | 384 | ||
385 | /* Hardware access for hotkey device */ | 385 | /* Hardware access for hotkey device */ |
386 | 386 | ||
387 | static int get_irb(void) | 387 | static int get_irb(void) |
388 | { | 388 | { |
389 | unsigned long long state = 0; | 389 | unsigned long long state = 0; |
390 | acpi_status status = AE_OK; | 390 | acpi_status status = AE_OK; |
391 | 391 | ||
392 | vdbg_printk(FUJLAPTOP_DBG_TRACE, "Get irb\n"); | 392 | vdbg_printk(FUJLAPTOP_DBG_TRACE, "Get irb\n"); |
393 | 393 | ||
394 | status = | 394 | status = |
395 | acpi_evaluate_integer(fujitsu_hotkey->acpi_handle, "GIRB", NULL, | 395 | acpi_evaluate_integer(fujitsu_hotkey->acpi_handle, "GIRB", NULL, |
396 | &state); | 396 | &state); |
397 | if (status < 0) | 397 | if (status < 0) |
398 | return status; | 398 | return status; |
399 | 399 | ||
400 | fujitsu_hotkey->irb = state; | 400 | fujitsu_hotkey->irb = state; |
401 | 401 | ||
402 | return fujitsu_hotkey->irb; | 402 | return fujitsu_hotkey->irb; |
403 | } | 403 | } |
404 | 404 | ||
405 | static ssize_t | 405 | static ssize_t |
406 | ignore_store(struct device *dev, | 406 | ignore_store(struct device *dev, |
407 | struct device_attribute *attr, const char *buf, size_t count) | 407 | struct device_attribute *attr, const char *buf, size_t count) |
408 | { | 408 | { |
409 | return count; | 409 | return count; |
410 | } | 410 | } |
411 | 411 | ||
412 | static DEVICE_ATTR(max_brightness, 0444, show_max_brightness, ignore_store); | 412 | static DEVICE_ATTR(max_brightness, 0444, show_max_brightness, ignore_store); |
413 | static DEVICE_ATTR(brightness_changed, 0444, show_brightness_changed, | 413 | static DEVICE_ATTR(brightness_changed, 0444, show_brightness_changed, |
414 | ignore_store); | 414 | ignore_store); |
415 | static DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level); | 415 | static DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level); |
416 | 416 | ||
417 | static struct attribute *fujitsupf_attributes[] = { | 417 | static struct attribute *fujitsupf_attributes[] = { |
418 | &dev_attr_brightness_changed.attr, | 418 | &dev_attr_brightness_changed.attr, |
419 | &dev_attr_max_brightness.attr, | 419 | &dev_attr_max_brightness.attr, |
420 | &dev_attr_lcd_level.attr, | 420 | &dev_attr_lcd_level.attr, |
421 | NULL | 421 | NULL |
422 | }; | 422 | }; |
423 | 423 | ||
424 | static struct attribute_group fujitsupf_attribute_group = { | 424 | static struct attribute_group fujitsupf_attribute_group = { |
425 | .attrs = fujitsupf_attributes | 425 | .attrs = fujitsupf_attributes |
426 | }; | 426 | }; |
427 | 427 | ||
428 | static struct platform_driver fujitsupf_driver = { | 428 | static struct platform_driver fujitsupf_driver = { |
429 | .driver = { | 429 | .driver = { |
430 | .name = "fujitsu-laptop", | 430 | .name = "fujitsu-laptop", |
431 | .owner = THIS_MODULE, | 431 | .owner = THIS_MODULE, |
432 | } | 432 | } |
433 | }; | 433 | }; |
434 | 434 | ||
435 | static void dmi_check_cb_common(const struct dmi_system_id *id) | 435 | static void dmi_check_cb_common(const struct dmi_system_id *id) |
436 | { | 436 | { |
437 | acpi_handle handle; | 437 | acpi_handle handle; |
438 | int have_blnf; | 438 | int have_blnf; |
439 | printk(KERN_INFO "fujitsu-laptop: Identified laptop model '%s'.\n", | 439 | printk(KERN_INFO "fujitsu-laptop: Identified laptop model '%s'.\n", |
440 | id->ident); | 440 | id->ident); |
441 | have_blnf = ACPI_SUCCESS | 441 | have_blnf = ACPI_SUCCESS |
442 | (acpi_get_handle(NULL, "\\_SB.PCI0.GFX0.LCD.BLNF", &handle)); | 442 | (acpi_get_handle(NULL, "\\_SB.PCI0.GFX0.LCD.BLNF", &handle)); |
443 | if (use_alt_lcd_levels == -1) { | 443 | if (use_alt_lcd_levels == -1) { |
444 | vdbg_printk(FUJLAPTOP_DBG_TRACE, "auto-detecting usealt\n"); | 444 | vdbg_printk(FUJLAPTOP_DBG_TRACE, "auto-detecting usealt\n"); |
445 | use_alt_lcd_levels = 1; | 445 | use_alt_lcd_levels = 1; |
446 | } | 446 | } |
447 | if (disable_brightness_keys == -1) { | 447 | if (disable_brightness_keys == -1) { |
448 | vdbg_printk(FUJLAPTOP_DBG_TRACE, | 448 | vdbg_printk(FUJLAPTOP_DBG_TRACE, |
449 | "auto-detecting disable_keys\n"); | 449 | "auto-detecting disable_keys\n"); |
450 | disable_brightness_keys = have_blnf ? 1 : 0; | 450 | disable_brightness_keys = have_blnf ? 1 : 0; |
451 | } | 451 | } |
452 | if (disable_brightness_adjust == -1) { | 452 | if (disable_brightness_adjust == -1) { |
453 | vdbg_printk(FUJLAPTOP_DBG_TRACE, | 453 | vdbg_printk(FUJLAPTOP_DBG_TRACE, |
454 | "auto-detecting disable_adjust\n"); | 454 | "auto-detecting disable_adjust\n"); |
455 | disable_brightness_adjust = have_blnf ? 0 : 1; | 455 | disable_brightness_adjust = have_blnf ? 0 : 1; |
456 | } | 456 | } |
457 | } | 457 | } |
458 | 458 | ||
459 | static int dmi_check_cb_s6410(const struct dmi_system_id *id) | 459 | static int dmi_check_cb_s6410(const struct dmi_system_id *id) |
460 | { | 460 | { |
461 | dmi_check_cb_common(id); | 461 | dmi_check_cb_common(id); |
462 | fujitsu->keycode1 = KEY_SCREENLOCK; /* "Lock" */ | 462 | fujitsu->keycode1 = KEY_SCREENLOCK; /* "Lock" */ |
463 | fujitsu->keycode2 = KEY_HELP; /* "Mobility Center" */ | 463 | fujitsu->keycode2 = KEY_HELP; /* "Mobility Center" */ |
464 | return 0; | 464 | return 0; |
465 | } | 465 | } |
466 | 466 | ||
467 | static int dmi_check_cb_s6420(const struct dmi_system_id *id) | 467 | static int dmi_check_cb_s6420(const struct dmi_system_id *id) |
468 | { | 468 | { |
469 | dmi_check_cb_common(id); | 469 | dmi_check_cb_common(id); |
470 | fujitsu->keycode1 = KEY_SCREENLOCK; /* "Lock" */ | 470 | fujitsu->keycode1 = KEY_SCREENLOCK; /* "Lock" */ |
471 | fujitsu->keycode2 = KEY_HELP; /* "Mobility Center" */ | 471 | fujitsu->keycode2 = KEY_HELP; /* "Mobility Center" */ |
472 | return 0; | 472 | return 0; |
473 | } | 473 | } |
474 | 474 | ||
475 | static int dmi_check_cb_p8010(const struct dmi_system_id *id) | 475 | static int dmi_check_cb_p8010(const struct dmi_system_id *id) |
476 | { | 476 | { |
477 | dmi_check_cb_common(id); | 477 | dmi_check_cb_common(id); |
478 | fujitsu->keycode1 = KEY_HELP; /* "Support" */ | 478 | fujitsu->keycode1 = KEY_HELP; /* "Support" */ |
479 | fujitsu->keycode3 = KEY_SWITCHVIDEOMODE; /* "Presentation" */ | 479 | fujitsu->keycode3 = KEY_SWITCHVIDEOMODE; /* "Presentation" */ |
480 | fujitsu->keycode4 = KEY_WWW; /* "Internet" */ | 480 | fujitsu->keycode4 = KEY_WWW; /* "Internet" */ |
481 | return 0; | 481 | return 0; |
482 | } | 482 | } |
483 | 483 | ||
484 | static struct dmi_system_id fujitsu_dmi_table[] = { | 484 | static struct dmi_system_id fujitsu_dmi_table[] = { |
485 | { | 485 | { |
486 | .ident = "Fujitsu Siemens S6410", | 486 | .ident = "Fujitsu Siemens S6410", |
487 | .matches = { | 487 | .matches = { |
488 | DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), | 488 | DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), |
489 | DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S6410"), | 489 | DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S6410"), |
490 | }, | 490 | }, |
491 | .callback = dmi_check_cb_s6410}, | 491 | .callback = dmi_check_cb_s6410}, |
492 | { | 492 | { |
493 | .ident = "Fujitsu Siemens S6420", | 493 | .ident = "Fujitsu Siemens S6420", |
494 | .matches = { | 494 | .matches = { |
495 | DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), | 495 | DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), |
496 | DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S6420"), | 496 | DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S6420"), |
497 | }, | 497 | }, |
498 | .callback = dmi_check_cb_s6420}, | 498 | .callback = dmi_check_cb_s6420}, |
499 | { | 499 | { |
500 | .ident = "Fujitsu LifeBook P8010", | 500 | .ident = "Fujitsu LifeBook P8010", |
501 | .matches = { | 501 | .matches = { |
502 | DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), | 502 | DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), |
503 | DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook P8010"), | 503 | DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook P8010"), |
504 | }, | 504 | }, |
505 | .callback = dmi_check_cb_p8010}, | 505 | .callback = dmi_check_cb_p8010}, |
506 | {} | 506 | {} |
507 | }; | 507 | }; |
508 | 508 | ||
509 | /* ACPI device for LCD brightness control */ | 509 | /* ACPI device for LCD brightness control */ |
510 | 510 | ||
511 | static int acpi_fujitsu_add(struct acpi_device *device) | 511 | static int acpi_fujitsu_add(struct acpi_device *device) |
512 | { | 512 | { |
513 | acpi_status status; | 513 | acpi_status status; |
514 | acpi_handle handle; | 514 | acpi_handle handle; |
515 | int result = 0; | 515 | int result = 0; |
516 | int state = 0; | 516 | int state = 0; |
517 | struct input_dev *input; | 517 | struct input_dev *input; |
518 | int error; | 518 | int error; |
519 | 519 | ||
520 | if (!device) | 520 | if (!device) |
521 | return -EINVAL; | 521 | return -EINVAL; |
522 | 522 | ||
523 | fujitsu->acpi_handle = device->handle; | 523 | fujitsu->acpi_handle = device->handle; |
524 | sprintf(acpi_device_name(device), "%s", ACPI_FUJITSU_DEVICE_NAME); | 524 | sprintf(acpi_device_name(device), "%s", ACPI_FUJITSU_DEVICE_NAME); |
525 | sprintf(acpi_device_class(device), "%s", ACPI_FUJITSU_CLASS); | 525 | sprintf(acpi_device_class(device), "%s", ACPI_FUJITSU_CLASS); |
526 | device->driver_data = fujitsu; | 526 | device->driver_data = fujitsu; |
527 | 527 | ||
528 | status = acpi_install_notify_handler(device->handle, | 528 | status = acpi_install_notify_handler(device->handle, |
529 | ACPI_DEVICE_NOTIFY, | 529 | ACPI_DEVICE_NOTIFY, |
530 | acpi_fujitsu_notify, fujitsu); | 530 | acpi_fujitsu_notify, fujitsu); |
531 | 531 | ||
532 | if (ACPI_FAILURE(status)) { | 532 | if (ACPI_FAILURE(status)) { |
533 | printk(KERN_ERR "Error installing notify handler\n"); | 533 | printk(KERN_ERR "Error installing notify handler\n"); |
534 | error = -ENODEV; | 534 | error = -ENODEV; |
535 | goto err_stop; | 535 | goto err_stop; |
536 | } | 536 | } |
537 | 537 | ||
538 | fujitsu->input = input = input_allocate_device(); | 538 | fujitsu->input = input = input_allocate_device(); |
539 | if (!input) { | 539 | if (!input) { |
540 | error = -ENOMEM; | 540 | error = -ENOMEM; |
541 | goto err_uninstall_notify; | 541 | goto err_uninstall_notify; |
542 | } | 542 | } |
543 | 543 | ||
544 | snprintf(fujitsu->phys, sizeof(fujitsu->phys), | 544 | snprintf(fujitsu->phys, sizeof(fujitsu->phys), |
545 | "%s/video/input0", acpi_device_hid(device)); | 545 | "%s/video/input0", acpi_device_hid(device)); |
546 | 546 | ||
547 | input->name = acpi_device_name(device); | 547 | input->name = acpi_device_name(device); |
548 | input->phys = fujitsu->phys; | 548 | input->phys = fujitsu->phys; |
549 | input->id.bustype = BUS_HOST; | 549 | input->id.bustype = BUS_HOST; |
550 | input->id.product = 0x06; | 550 | input->id.product = 0x06; |
551 | input->dev.parent = &device->dev; | 551 | input->dev.parent = &device->dev; |
552 | input->evbit[0] = BIT(EV_KEY); | 552 | input->evbit[0] = BIT(EV_KEY); |
553 | set_bit(KEY_BRIGHTNESSUP, input->keybit); | 553 | set_bit(KEY_BRIGHTNESSUP, input->keybit); |
554 | set_bit(KEY_BRIGHTNESSDOWN, input->keybit); | 554 | set_bit(KEY_BRIGHTNESSDOWN, input->keybit); |
555 | set_bit(KEY_UNKNOWN, input->keybit); | 555 | set_bit(KEY_UNKNOWN, input->keybit); |
556 | 556 | ||
557 | error = input_register_device(input); | 557 | error = input_register_device(input); |
558 | if (error) | 558 | if (error) |
559 | goto err_free_input_dev; | 559 | goto err_free_input_dev; |
560 | 560 | ||
561 | result = acpi_bus_get_power(fujitsu->acpi_handle, &state); | 561 | result = acpi_bus_get_power(fujitsu->acpi_handle, &state); |
562 | if (result) { | 562 | if (result) { |
563 | printk(KERN_ERR "Error reading power state\n"); | 563 | printk(KERN_ERR "Error reading power state\n"); |
564 | goto end; | 564 | goto end; |
565 | } | 565 | } |
566 | 566 | ||
567 | printk(KERN_INFO PREFIX "%s [%s] (%s)\n", | 567 | printk(KERN_INFO PREFIX "%s [%s] (%s)\n", |
568 | acpi_device_name(device), acpi_device_bid(device), | 568 | acpi_device_name(device), acpi_device_bid(device), |
569 | !device->power.state ? "on" : "off"); | 569 | !device->power.state ? "on" : "off"); |
570 | 570 | ||
571 | fujitsu->dev = device; | 571 | fujitsu->dev = device; |
572 | 572 | ||
573 | if (ACPI_SUCCESS | 573 | if (ACPI_SUCCESS |
574 | (acpi_get_handle(device->handle, METHOD_NAME__INI, &handle))) { | 574 | (acpi_get_handle(device->handle, METHOD_NAME__INI, &handle))) { |
575 | vdbg_printk(FUJLAPTOP_DBG_INFO, "Invoking _INI\n"); | 575 | vdbg_printk(FUJLAPTOP_DBG_INFO, "Invoking _INI\n"); |
576 | if (ACPI_FAILURE | 576 | if (ACPI_FAILURE |
577 | (acpi_evaluate_object | 577 | (acpi_evaluate_object |
578 | (device->handle, METHOD_NAME__INI, NULL, NULL))) | 578 | (device->handle, METHOD_NAME__INI, NULL, NULL))) |
579 | printk(KERN_ERR "_INI Method failed\n"); | 579 | printk(KERN_ERR "_INI Method failed\n"); |
580 | } | 580 | } |
581 | 581 | ||
582 | /* do config (detect defaults) */ | 582 | /* do config (detect defaults) */ |
583 | use_alt_lcd_levels = use_alt_lcd_levels == 1 ? 1 : 0; | 583 | use_alt_lcd_levels = use_alt_lcd_levels == 1 ? 1 : 0; |
584 | disable_brightness_keys = disable_brightness_keys == 1 ? 1 : 0; | 584 | disable_brightness_keys = disable_brightness_keys == 1 ? 1 : 0; |
585 | disable_brightness_adjust = disable_brightness_adjust == 1 ? 1 : 0; | 585 | disable_brightness_adjust = disable_brightness_adjust == 1 ? 1 : 0; |
586 | vdbg_printk(FUJLAPTOP_DBG_INFO, | 586 | vdbg_printk(FUJLAPTOP_DBG_INFO, |
587 | "config: [alt interface: %d], [key disable: %d], [adjust disable: %d]\n", | 587 | "config: [alt interface: %d], [key disable: %d], [adjust disable: %d]\n", |
588 | use_alt_lcd_levels, disable_brightness_keys, | 588 | use_alt_lcd_levels, disable_brightness_keys, |
589 | disable_brightness_adjust); | 589 | disable_brightness_adjust); |
590 | 590 | ||
591 | if (get_max_brightness() <= 0) | 591 | if (get_max_brightness() <= 0) |
592 | fujitsu->max_brightness = FUJITSU_LCD_N_LEVELS; | 592 | fujitsu->max_brightness = FUJITSU_LCD_N_LEVELS; |
593 | if (use_alt_lcd_levels) | 593 | if (use_alt_lcd_levels) |
594 | get_lcd_level_alt(); | 594 | get_lcd_level_alt(); |
595 | else | 595 | else |
596 | get_lcd_level(); | 596 | get_lcd_level(); |
597 | 597 | ||
598 | return result; | 598 | return result; |
599 | 599 | ||
600 | end: | 600 | end: |
601 | err_free_input_dev: | 601 | err_free_input_dev: |
602 | input_free_device(input); | 602 | input_free_device(input); |
603 | err_uninstall_notify: | 603 | err_uninstall_notify: |
604 | acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY, | 604 | acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY, |
605 | acpi_fujitsu_notify); | 605 | acpi_fujitsu_notify); |
606 | err_stop: | 606 | err_stop: |
607 | 607 | ||
608 | return result; | 608 | return result; |
609 | } | 609 | } |
610 | 610 | ||
611 | static int acpi_fujitsu_remove(struct acpi_device *device, int type) | 611 | static int acpi_fujitsu_remove(struct acpi_device *device, int type) |
612 | { | 612 | { |
613 | acpi_status status; | 613 | acpi_status status; |
614 | struct fujitsu_t *fujitsu = NULL; | 614 | struct fujitsu_t *fujitsu = NULL; |
615 | 615 | ||
616 | if (!device || !acpi_driver_data(device)) | 616 | if (!device || !acpi_driver_data(device)) |
617 | return -EINVAL; | 617 | return -EINVAL; |
618 | 618 | ||
619 | fujitsu = acpi_driver_data(device); | 619 | fujitsu = acpi_driver_data(device); |
620 | 620 | ||
621 | status = acpi_remove_notify_handler(fujitsu->acpi_handle, | 621 | status = acpi_remove_notify_handler(fujitsu->acpi_handle, |
622 | ACPI_DEVICE_NOTIFY, | 622 | ACPI_DEVICE_NOTIFY, |
623 | acpi_fujitsu_notify); | 623 | acpi_fujitsu_notify); |
624 | 624 | ||
625 | if (!device || !acpi_driver_data(device)) | 625 | if (!device || !acpi_driver_data(device)) |
626 | return -EINVAL; | 626 | return -EINVAL; |
627 | 627 | ||
628 | fujitsu->acpi_handle = NULL; | 628 | fujitsu->acpi_handle = NULL; |
629 | 629 | ||
630 | return 0; | 630 | return 0; |
631 | } | 631 | } |
632 | 632 | ||
633 | /* Brightness notify */ | 633 | /* Brightness notify */ |
634 | 634 | ||
635 | static void acpi_fujitsu_notify(acpi_handle handle, u32 event, void *data) | 635 | static void acpi_fujitsu_notify(acpi_handle handle, u32 event, void *data) |
636 | { | 636 | { |
637 | struct input_dev *input; | 637 | struct input_dev *input; |
638 | int keycode; | 638 | int keycode; |
639 | int oldb, newb; | 639 | int oldb, newb; |
640 | 640 | ||
641 | input = fujitsu->input; | 641 | input = fujitsu->input; |
642 | 642 | ||
643 | switch (event) { | 643 | switch (event) { |
644 | case ACPI_FUJITSU_NOTIFY_CODE1: | 644 | case ACPI_FUJITSU_NOTIFY_CODE1: |
645 | keycode = 0; | 645 | keycode = 0; |
646 | oldb = fujitsu->brightness_level; | 646 | oldb = fujitsu->brightness_level; |
647 | get_lcd_level(); /* the alt version always yields changed */ | 647 | get_lcd_level(); /* the alt version always yields changed */ |
648 | newb = fujitsu->brightness_level; | 648 | newb = fujitsu->brightness_level; |
649 | 649 | ||
650 | vdbg_printk(FUJLAPTOP_DBG_TRACE, | 650 | vdbg_printk(FUJLAPTOP_DBG_TRACE, |
651 | "brightness button event [%i -> %i (%i)]\n", | 651 | "brightness button event [%i -> %i (%i)]\n", |
652 | oldb, newb, fujitsu->brightness_changed); | 652 | oldb, newb, fujitsu->brightness_changed); |
653 | 653 | ||
654 | if (oldb == newb && fujitsu->brightness_changed) { | 654 | if (oldb == newb && fujitsu->brightness_changed) { |
655 | keycode = 0; | 655 | keycode = 0; |
656 | if (disable_brightness_keys != 1) { | 656 | if (disable_brightness_keys != 1) { |
657 | if (oldb == 0) { | 657 | if (oldb == 0) { |
658 | acpi_bus_generate_proc_event | 658 | acpi_bus_generate_proc_event |
659 | (fujitsu->dev, | 659 | (fujitsu->dev, |
660 | ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS, | 660 | ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS, |
661 | 0); | 661 | 0); |
662 | keycode = KEY_BRIGHTNESSDOWN; | 662 | keycode = KEY_BRIGHTNESSDOWN; |
663 | } else if (oldb == | 663 | } else if (oldb == |
664 | (fujitsu->max_brightness) - 1) { | 664 | (fujitsu->max_brightness) - 1) { |
665 | acpi_bus_generate_proc_event | 665 | acpi_bus_generate_proc_event |
666 | (fujitsu->dev, | 666 | (fujitsu->dev, |
667 | ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS, | 667 | ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS, |
668 | 0); | 668 | 0); |
669 | keycode = KEY_BRIGHTNESSUP; | 669 | keycode = KEY_BRIGHTNESSUP; |
670 | } | 670 | } |
671 | } | 671 | } |
672 | } else if (oldb < newb) { | 672 | } else if (oldb < newb) { |
673 | if (disable_brightness_adjust != 1) { | 673 | if (disable_brightness_adjust != 1) { |
674 | if (use_alt_lcd_levels) | 674 | if (use_alt_lcd_levels) |
675 | set_lcd_level_alt(newb); | 675 | set_lcd_level_alt(newb); |
676 | else | 676 | else |
677 | set_lcd_level(newb); | 677 | set_lcd_level(newb); |
678 | } | 678 | } |
679 | if (disable_brightness_keys != 1) { | 679 | if (disable_brightness_keys != 1) { |
680 | acpi_bus_generate_proc_event(fujitsu->dev, | 680 | acpi_bus_generate_proc_event(fujitsu->dev, |
681 | ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS, 0); | 681 | ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS, 0); |
682 | keycode = KEY_BRIGHTNESSUP; | 682 | keycode = KEY_BRIGHTNESSUP; |
683 | } | 683 | } |
684 | } else if (oldb > newb) { | 684 | } else if (oldb > newb) { |
685 | if (disable_brightness_adjust != 1) { | 685 | if (disable_brightness_adjust != 1) { |
686 | if (use_alt_lcd_levels) | 686 | if (use_alt_lcd_levels) |
687 | set_lcd_level_alt(newb); | 687 | set_lcd_level_alt(newb); |
688 | else | 688 | else |
689 | set_lcd_level(newb); | 689 | set_lcd_level(newb); |
690 | } | 690 | } |
691 | if (disable_brightness_keys != 1) { | 691 | if (disable_brightness_keys != 1) { |
692 | acpi_bus_generate_proc_event(fujitsu->dev, | 692 | acpi_bus_generate_proc_event(fujitsu->dev, |
693 | ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS, 0); | 693 | ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS, 0); |
694 | keycode = KEY_BRIGHTNESSDOWN; | 694 | keycode = KEY_BRIGHTNESSDOWN; |
695 | } | 695 | } |
696 | } else { | 696 | } else { |
697 | keycode = KEY_UNKNOWN; | 697 | keycode = KEY_UNKNOWN; |
698 | } | 698 | } |
699 | break; | 699 | break; |
700 | default: | 700 | default: |
701 | keycode = KEY_UNKNOWN; | 701 | keycode = KEY_UNKNOWN; |
702 | vdbg_printk(FUJLAPTOP_DBG_WARN, | 702 | vdbg_printk(FUJLAPTOP_DBG_WARN, |
703 | "unsupported event [0x%x]\n", event); | 703 | "unsupported event [0x%x]\n", event); |
704 | break; | 704 | break; |
705 | } | 705 | } |
706 | 706 | ||
707 | if (keycode != 0) { | 707 | if (keycode != 0) { |
708 | input_report_key(input, keycode, 1); | 708 | input_report_key(input, keycode, 1); |
709 | input_sync(input); | 709 | input_sync(input); |
710 | input_report_key(input, keycode, 0); | 710 | input_report_key(input, keycode, 0); |
711 | input_sync(input); | 711 | input_sync(input); |
712 | } | 712 | } |
713 | 713 | ||
714 | return; | 714 | return; |
715 | } | 715 | } |
716 | 716 | ||
717 | /* ACPI device for hotkey handling */ | 717 | /* ACPI device for hotkey handling */ |
718 | 718 | ||
719 | static int acpi_fujitsu_hotkey_add(struct acpi_device *device) | 719 | static int acpi_fujitsu_hotkey_add(struct acpi_device *device) |
720 | { | 720 | { |
721 | acpi_status status; | 721 | acpi_status status; |
722 | acpi_handle handle; | 722 | acpi_handle handle; |
723 | int result = 0; | 723 | int result = 0; |
724 | int state = 0; | 724 | int state = 0; |
725 | struct input_dev *input; | 725 | struct input_dev *input; |
726 | int error; | 726 | int error; |
727 | int i; | 727 | int i; |
728 | 728 | ||
729 | if (!device) | 729 | if (!device) |
730 | return -EINVAL; | 730 | return -EINVAL; |
731 | 731 | ||
732 | fujitsu_hotkey->acpi_handle = device->handle; | 732 | fujitsu_hotkey->acpi_handle = device->handle; |
733 | sprintf(acpi_device_name(device), "%s", | 733 | sprintf(acpi_device_name(device), "%s", |
734 | ACPI_FUJITSU_HOTKEY_DEVICE_NAME); | 734 | ACPI_FUJITSU_HOTKEY_DEVICE_NAME); |
735 | sprintf(acpi_device_class(device), "%s", ACPI_FUJITSU_CLASS); | 735 | sprintf(acpi_device_class(device), "%s", ACPI_FUJITSU_CLASS); |
736 | device->driver_data = fujitsu_hotkey; | 736 | device->driver_data = fujitsu_hotkey; |
737 | 737 | ||
738 | status = acpi_install_notify_handler(device->handle, | 738 | status = acpi_install_notify_handler(device->handle, |
739 | ACPI_DEVICE_NOTIFY, | 739 | ACPI_DEVICE_NOTIFY, |
740 | acpi_fujitsu_hotkey_notify, | 740 | acpi_fujitsu_hotkey_notify, |
741 | fujitsu_hotkey); | 741 | fujitsu_hotkey); |
742 | 742 | ||
743 | if (ACPI_FAILURE(status)) { | 743 | if (ACPI_FAILURE(status)) { |
744 | printk(KERN_ERR "Error installing notify handler\n"); | 744 | printk(KERN_ERR "Error installing notify handler\n"); |
745 | error = -ENODEV; | 745 | error = -ENODEV; |
746 | goto err_stop; | 746 | goto err_stop; |
747 | } | 747 | } |
748 | 748 | ||
749 | /* kfifo */ | 749 | /* kfifo */ |
750 | spin_lock_init(&fujitsu_hotkey->fifo_lock); | 750 | spin_lock_init(&fujitsu_hotkey->fifo_lock); |
751 | fujitsu_hotkey->fifo = | 751 | fujitsu_hotkey->fifo = |
752 | kfifo_alloc(RINGBUFFERSIZE * sizeof(int), GFP_KERNEL, | 752 | kfifo_alloc(RINGBUFFERSIZE * sizeof(int), GFP_KERNEL, |
753 | &fujitsu_hotkey->fifo_lock); | 753 | &fujitsu_hotkey->fifo_lock); |
754 | if (IS_ERR(fujitsu_hotkey->fifo)) { | 754 | if (IS_ERR(fujitsu_hotkey->fifo)) { |
755 | printk(KERN_ERR "kfifo_alloc failed\n"); | 755 | printk(KERN_ERR "kfifo_alloc failed\n"); |
756 | error = PTR_ERR(fujitsu_hotkey->fifo); | 756 | error = PTR_ERR(fujitsu_hotkey->fifo); |
757 | goto err_stop; | 757 | goto err_stop; |
758 | } | 758 | } |
759 | 759 | ||
760 | fujitsu_hotkey->input = input = input_allocate_device(); | 760 | fujitsu_hotkey->input = input = input_allocate_device(); |
761 | if (!input) { | 761 | if (!input) { |
762 | error = -ENOMEM; | 762 | error = -ENOMEM; |
763 | goto err_uninstall_notify; | 763 | goto err_uninstall_notify; |
764 | } | 764 | } |
765 | 765 | ||
766 | snprintf(fujitsu_hotkey->phys, sizeof(fujitsu_hotkey->phys), | 766 | snprintf(fujitsu_hotkey->phys, sizeof(fujitsu_hotkey->phys), |
767 | "%s/video/input0", acpi_device_hid(device)); | 767 | "%s/video/input0", acpi_device_hid(device)); |
768 | 768 | ||
769 | input->name = acpi_device_name(device); | 769 | input->name = acpi_device_name(device); |
770 | input->phys = fujitsu_hotkey->phys; | 770 | input->phys = fujitsu_hotkey->phys; |
771 | input->id.bustype = BUS_HOST; | 771 | input->id.bustype = BUS_HOST; |
772 | input->id.product = 0x06; | 772 | input->id.product = 0x06; |
773 | input->dev.parent = &device->dev; | 773 | input->dev.parent = &device->dev; |
774 | input->evbit[0] = BIT(EV_KEY); | 774 | input->evbit[0] = BIT(EV_KEY); |
775 | set_bit(fujitsu->keycode1, input->keybit); | 775 | set_bit(fujitsu->keycode1, input->keybit); |
776 | set_bit(fujitsu->keycode2, input->keybit); | 776 | set_bit(fujitsu->keycode2, input->keybit); |
777 | set_bit(fujitsu->keycode3, input->keybit); | 777 | set_bit(fujitsu->keycode3, input->keybit); |
778 | set_bit(fujitsu->keycode4, input->keybit); | 778 | set_bit(fujitsu->keycode4, input->keybit); |
779 | set_bit(KEY_UNKNOWN, input->keybit); | 779 | set_bit(KEY_UNKNOWN, input->keybit); |
780 | 780 | ||
781 | error = input_register_device(input); | 781 | error = input_register_device(input); |
782 | if (error) | 782 | if (error) |
783 | goto err_free_input_dev; | 783 | goto err_free_input_dev; |
784 | 784 | ||
785 | result = acpi_bus_get_power(fujitsu_hotkey->acpi_handle, &state); | 785 | result = acpi_bus_get_power(fujitsu_hotkey->acpi_handle, &state); |
786 | if (result) { | 786 | if (result) { |
787 | printk(KERN_ERR "Error reading power state\n"); | 787 | printk(KERN_ERR "Error reading power state\n"); |
788 | goto end; | 788 | goto end; |
789 | } | 789 | } |
790 | 790 | ||
791 | printk(KERN_INFO PREFIX "%s [%s] (%s)\n", | 791 | printk(KERN_INFO PREFIX "%s [%s] (%s)\n", |
792 | acpi_device_name(device), acpi_device_bid(device), | 792 | acpi_device_name(device), acpi_device_bid(device), |
793 | !device->power.state ? "on" : "off"); | 793 | !device->power.state ? "on" : "off"); |
794 | 794 | ||
795 | fujitsu_hotkey->dev = device; | 795 | fujitsu_hotkey->dev = device; |
796 | 796 | ||
797 | if (ACPI_SUCCESS | 797 | if (ACPI_SUCCESS |
798 | (acpi_get_handle(device->handle, METHOD_NAME__INI, &handle))) { | 798 | (acpi_get_handle(device->handle, METHOD_NAME__INI, &handle))) { |
799 | vdbg_printk(FUJLAPTOP_DBG_INFO, "Invoking _INI\n"); | 799 | vdbg_printk(FUJLAPTOP_DBG_INFO, "Invoking _INI\n"); |
800 | if (ACPI_FAILURE | 800 | if (ACPI_FAILURE |
801 | (acpi_evaluate_object | 801 | (acpi_evaluate_object |
802 | (device->handle, METHOD_NAME__INI, NULL, NULL))) | 802 | (device->handle, METHOD_NAME__INI, NULL, NULL))) |
803 | printk(KERN_ERR "_INI Method failed\n"); | 803 | printk(KERN_ERR "_INI Method failed\n"); |
804 | } | 804 | } |
805 | 805 | ||
806 | i = 0; /* Discard hotkey ringbuffer */ | 806 | i = 0; /* Discard hotkey ringbuffer */ |
807 | while (get_irb() != 0 && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) ; | 807 | while (get_irb() != 0 && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) ; |
808 | vdbg_printk(FUJLAPTOP_DBG_INFO, "Discarded %i ringbuffer entries\n", i); | 808 | vdbg_printk(FUJLAPTOP_DBG_INFO, "Discarded %i ringbuffer entries\n", i); |
809 | 809 | ||
810 | return result; | 810 | return result; |
811 | 811 | ||
812 | end: | 812 | end: |
813 | err_free_input_dev: | 813 | err_free_input_dev: |
814 | input_free_device(input); | 814 | input_free_device(input); |
815 | err_uninstall_notify: | 815 | err_uninstall_notify: |
816 | acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY, | 816 | acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY, |
817 | acpi_fujitsu_hotkey_notify); | 817 | acpi_fujitsu_hotkey_notify); |
818 | kfifo_free(fujitsu_hotkey->fifo); | 818 | kfifo_free(fujitsu_hotkey->fifo); |
819 | err_stop: | 819 | err_stop: |
820 | 820 | ||
821 | return result; | 821 | return result; |
822 | } | 822 | } |
823 | 823 | ||
824 | static int acpi_fujitsu_hotkey_remove(struct acpi_device *device, int type) | 824 | static int acpi_fujitsu_hotkey_remove(struct acpi_device *device, int type) |
825 | { | 825 | { |
826 | acpi_status status; | 826 | acpi_status status; |
827 | struct fujitsu_hotkey_t *fujitsu_hotkey = NULL; | 827 | struct fujitsu_hotkey_t *fujitsu_hotkey = NULL; |
828 | 828 | ||
829 | if (!device || !acpi_driver_data(device)) | 829 | if (!device || !acpi_driver_data(device)) |
830 | return -EINVAL; | 830 | return -EINVAL; |
831 | 831 | ||
832 | fujitsu_hotkey = acpi_driver_data(device); | 832 | fujitsu_hotkey = acpi_driver_data(device); |
833 | 833 | ||
834 | status = acpi_remove_notify_handler(fujitsu_hotkey->acpi_handle, | 834 | status = acpi_remove_notify_handler(fujitsu_hotkey->acpi_handle, |
835 | ACPI_DEVICE_NOTIFY, | 835 | ACPI_DEVICE_NOTIFY, |
836 | acpi_fujitsu_hotkey_notify); | 836 | acpi_fujitsu_hotkey_notify); |
837 | 837 | ||
838 | fujitsu_hotkey->acpi_handle = NULL; | 838 | fujitsu_hotkey->acpi_handle = NULL; |
839 | 839 | ||
840 | kfifo_free(fujitsu_hotkey->fifo); | 840 | kfifo_free(fujitsu_hotkey->fifo); |
841 | 841 | ||
842 | return 0; | 842 | return 0; |
843 | } | 843 | } |
844 | 844 | ||
845 | static void acpi_fujitsu_hotkey_notify(acpi_handle handle, u32 event, | 845 | static void acpi_fujitsu_hotkey_notify(acpi_handle handle, u32 event, |
846 | void *data) | 846 | void *data) |
847 | { | 847 | { |
848 | struct input_dev *input; | 848 | struct input_dev *input; |
849 | int keycode, keycode_r; | 849 | int keycode, keycode_r; |
850 | unsigned int irb = 1; | 850 | unsigned int irb = 1; |
851 | int i, status; | 851 | int i, status; |
852 | 852 | ||
853 | input = fujitsu_hotkey->input; | 853 | input = fujitsu_hotkey->input; |
854 | 854 | ||
855 | vdbg_printk(FUJLAPTOP_DBG_TRACE, "Hotkey event\n"); | 855 | vdbg_printk(FUJLAPTOP_DBG_TRACE, "Hotkey event\n"); |
856 | 856 | ||
857 | switch (event) { | 857 | switch (event) { |
858 | case ACPI_FUJITSU_NOTIFY_CODE1: | 858 | case ACPI_FUJITSU_NOTIFY_CODE1: |
859 | i = 0; | 859 | i = 0; |
860 | while ((irb = get_irb()) != 0 | 860 | while ((irb = get_irb()) != 0 |
861 | && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) { | 861 | && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) { |
862 | vdbg_printk(FUJLAPTOP_DBG_TRACE, "GIRB result [%x]\n", | 862 | vdbg_printk(FUJLAPTOP_DBG_TRACE, "GIRB result [%x]\n", |
863 | irb); | 863 | irb); |
864 | 864 | ||
865 | switch (irb & 0x4ff) { | 865 | switch (irb & 0x4ff) { |
866 | case KEY1_CODE: | 866 | case KEY1_CODE: |
867 | keycode = fujitsu->keycode1; | 867 | keycode = fujitsu->keycode1; |
868 | break; | 868 | break; |
869 | case KEY2_CODE: | 869 | case KEY2_CODE: |
870 | keycode = fujitsu->keycode2; | 870 | keycode = fujitsu->keycode2; |
871 | break; | 871 | break; |
872 | case KEY3_CODE: | 872 | case KEY3_CODE: |
873 | keycode = fujitsu->keycode3; | 873 | keycode = fujitsu->keycode3; |
874 | break; | 874 | break; |
875 | case KEY4_CODE: | 875 | case KEY4_CODE: |
876 | keycode = fujitsu->keycode4; | 876 | keycode = fujitsu->keycode4; |
877 | break; | 877 | break; |
878 | case 0: | 878 | case 0: |
879 | keycode = 0; | 879 | keycode = 0; |
880 | break; | 880 | break; |
881 | default: | 881 | default: |
882 | vdbg_printk(FUJLAPTOP_DBG_WARN, | 882 | vdbg_printk(FUJLAPTOP_DBG_WARN, |
883 | "Unknown GIRB result [%x]\n", irb); | 883 | "Unknown GIRB result [%x]\n", irb); |
884 | keycode = -1; | 884 | keycode = -1; |
885 | break; | 885 | break; |
886 | } | 886 | } |
887 | if (keycode > 0) { | 887 | if (keycode > 0) { |
888 | vdbg_printk(FUJLAPTOP_DBG_TRACE, | 888 | vdbg_printk(FUJLAPTOP_DBG_TRACE, |
889 | "Push keycode into ringbuffer [%d]\n", | 889 | "Push keycode into ringbuffer [%d]\n", |
890 | keycode); | 890 | keycode); |
891 | status = kfifo_put(fujitsu_hotkey->fifo, | 891 | status = kfifo_put(fujitsu_hotkey->fifo, |
892 | (unsigned char *)&keycode, | 892 | (unsigned char *)&keycode, |
893 | sizeof(keycode)); | 893 | sizeof(keycode)); |
894 | if (status != sizeof(keycode)) { | 894 | if (status != sizeof(keycode)) { |
895 | vdbg_printk(FUJLAPTOP_DBG_WARN, | 895 | vdbg_printk(FUJLAPTOP_DBG_WARN, |
896 | "Could not push keycode [0x%x]\n", | 896 | "Could not push keycode [0x%x]\n", |
897 | keycode); | 897 | keycode); |
898 | } else { | 898 | } else { |
899 | input_report_key(input, keycode, 1); | 899 | input_report_key(input, keycode, 1); |
900 | input_sync(input); | 900 | input_sync(input); |
901 | } | 901 | } |
902 | } else if (keycode == 0) { | 902 | } else if (keycode == 0) { |
903 | while ((status = | 903 | while ((status = |
904 | kfifo_get | 904 | kfifo_get |
905 | (fujitsu_hotkey->fifo, (unsigned char *) | 905 | (fujitsu_hotkey->fifo, (unsigned char *) |
906 | &keycode_r, | 906 | &keycode_r, |
907 | sizeof | 907 | sizeof |
908 | (keycode_r))) == sizeof(keycode_r)) { | 908 | (keycode_r))) == sizeof(keycode_r)) { |
909 | input_report_key(input, keycode_r, 0); | 909 | input_report_key(input, keycode_r, 0); |
910 | input_sync(input); | 910 | input_sync(input); |
911 | vdbg_printk(FUJLAPTOP_DBG_TRACE, | 911 | vdbg_printk(FUJLAPTOP_DBG_TRACE, |
912 | "Pop keycode from ringbuffer [%d]\n", | 912 | "Pop keycode from ringbuffer [%d]\n", |
913 | keycode_r); | 913 | keycode_r); |
914 | } | 914 | } |
915 | } | 915 | } |
916 | } | 916 | } |
917 | 917 | ||
918 | break; | 918 | break; |
919 | default: | 919 | default: |
920 | keycode = KEY_UNKNOWN; | 920 | keycode = KEY_UNKNOWN; |
921 | vdbg_printk(FUJLAPTOP_DBG_WARN, | 921 | vdbg_printk(FUJLAPTOP_DBG_WARN, |
922 | "Unsupported event [0x%x]\n", event); | 922 | "Unsupported event [0x%x]\n", event); |
923 | input_report_key(input, keycode, 1); | 923 | input_report_key(input, keycode, 1); |
924 | input_sync(input); | 924 | input_sync(input); |
925 | input_report_key(input, keycode, 0); | 925 | input_report_key(input, keycode, 0); |
926 | input_sync(input); | 926 | input_sync(input); |
927 | break; | 927 | break; |
928 | } | 928 | } |
929 | 929 | ||
930 | return; | 930 | return; |
931 | } | 931 | } |
932 | 932 | ||
933 | /* Initialization */ | 933 | /* Initialization */ |
934 | 934 | ||
935 | static const struct acpi_device_id fujitsu_device_ids[] = { | 935 | static const struct acpi_device_id fujitsu_device_ids[] = { |
936 | {ACPI_FUJITSU_HID, 0}, | 936 | {ACPI_FUJITSU_HID, 0}, |
937 | {"", 0}, | 937 | {"", 0}, |
938 | }; | 938 | }; |
939 | 939 | ||
940 | static struct acpi_driver acpi_fujitsu_driver = { | 940 | static struct acpi_driver acpi_fujitsu_driver = { |
941 | .name = ACPI_FUJITSU_DRIVER_NAME, | 941 | .name = ACPI_FUJITSU_DRIVER_NAME, |
942 | .class = ACPI_FUJITSU_CLASS, | 942 | .class = ACPI_FUJITSU_CLASS, |
943 | .ids = fujitsu_device_ids, | 943 | .ids = fujitsu_device_ids, |
944 | .ops = { | 944 | .ops = { |
945 | .add = acpi_fujitsu_add, | 945 | .add = acpi_fujitsu_add, |
946 | .remove = acpi_fujitsu_remove, | 946 | .remove = acpi_fujitsu_remove, |
947 | }, | 947 | }, |
948 | }; | 948 | }; |
949 | 949 | ||
950 | static const struct acpi_device_id fujitsu_hotkey_device_ids[] = { | 950 | static const struct acpi_device_id fujitsu_hotkey_device_ids[] = { |
951 | {ACPI_FUJITSU_HOTKEY_HID, 0}, | 951 | {ACPI_FUJITSU_HOTKEY_HID, 0}, |
952 | {"", 0}, | 952 | {"", 0}, |
953 | }; | 953 | }; |
954 | 954 | ||
955 | static struct acpi_driver acpi_fujitsu_hotkey_driver = { | 955 | static struct acpi_driver acpi_fujitsu_hotkey_driver = { |
956 | .name = ACPI_FUJITSU_HOTKEY_DRIVER_NAME, | 956 | .name = ACPI_FUJITSU_HOTKEY_DRIVER_NAME, |
957 | .class = ACPI_FUJITSU_CLASS, | 957 | .class = ACPI_FUJITSU_CLASS, |
958 | .ids = fujitsu_hotkey_device_ids, | 958 | .ids = fujitsu_hotkey_device_ids, |
959 | .ops = { | 959 | .ops = { |
960 | .add = acpi_fujitsu_hotkey_add, | 960 | .add = acpi_fujitsu_hotkey_add, |
961 | .remove = acpi_fujitsu_hotkey_remove, | 961 | .remove = acpi_fujitsu_hotkey_remove, |
962 | }, | 962 | }, |
963 | }; | 963 | }; |
964 | 964 | ||
965 | static int __init fujitsu_init(void) | 965 | static int __init fujitsu_init(void) |
966 | { | 966 | { |
967 | int ret, result, max_brightness; | 967 | int ret, result, max_brightness; |
968 | 968 | ||
969 | if (acpi_disabled) | 969 | if (acpi_disabled) |
970 | return -ENODEV; | 970 | return -ENODEV; |
971 | 971 | ||
972 | fujitsu = kmalloc(sizeof(struct fujitsu_t), GFP_KERNEL); | 972 | fujitsu = kmalloc(sizeof(struct fujitsu_t), GFP_KERNEL); |
973 | if (!fujitsu) | 973 | if (!fujitsu) |
974 | return -ENOMEM; | 974 | return -ENOMEM; |
975 | memset(fujitsu, 0, sizeof(struct fujitsu_t)); | 975 | memset(fujitsu, 0, sizeof(struct fujitsu_t)); |
976 | fujitsu->keycode1 = KEY_PROG1; | 976 | fujitsu->keycode1 = KEY_PROG1; |
977 | fujitsu->keycode2 = KEY_PROG2; | 977 | fujitsu->keycode2 = KEY_PROG2; |
978 | fujitsu->keycode3 = KEY_PROG3; | 978 | fujitsu->keycode3 = KEY_PROG3; |
979 | fujitsu->keycode4 = KEY_PROG4; | 979 | fujitsu->keycode4 = KEY_PROG4; |
980 | dmi_check_system(fujitsu_dmi_table); | 980 | dmi_check_system(fujitsu_dmi_table); |
981 | 981 | ||
982 | result = acpi_bus_register_driver(&acpi_fujitsu_driver); | 982 | result = acpi_bus_register_driver(&acpi_fujitsu_driver); |
983 | if (result < 0) { | 983 | if (result < 0) { |
984 | ret = -ENODEV; | 984 | ret = -ENODEV; |
985 | goto fail_acpi; | 985 | goto fail_acpi; |
986 | } | 986 | } |
987 | 987 | ||
988 | /* Register platform stuff */ | 988 | /* Register platform stuff */ |
989 | 989 | ||
990 | fujitsu->pf_device = platform_device_alloc("fujitsu-laptop", -1); | 990 | fujitsu->pf_device = platform_device_alloc("fujitsu-laptop", -1); |
991 | if (!fujitsu->pf_device) { | 991 | if (!fujitsu->pf_device) { |
992 | ret = -ENOMEM; | 992 | ret = -ENOMEM; |
993 | goto fail_platform_driver; | 993 | goto fail_platform_driver; |
994 | } | 994 | } |
995 | 995 | ||
996 | ret = platform_device_add(fujitsu->pf_device); | 996 | ret = platform_device_add(fujitsu->pf_device); |
997 | if (ret) | 997 | if (ret) |
998 | goto fail_platform_device1; | 998 | goto fail_platform_device1; |
999 | 999 | ||
1000 | ret = | 1000 | ret = |
1001 | sysfs_create_group(&fujitsu->pf_device->dev.kobj, | 1001 | sysfs_create_group(&fujitsu->pf_device->dev.kobj, |
1002 | &fujitsupf_attribute_group); | 1002 | &fujitsupf_attribute_group); |
1003 | if (ret) | 1003 | if (ret) |
1004 | goto fail_platform_device2; | 1004 | goto fail_platform_device2; |
1005 | 1005 | ||
1006 | /* Register backlight stuff */ | 1006 | /* Register backlight stuff */ |
1007 | 1007 | ||
1008 | fujitsu->bl_device = | 1008 | if (!acpi_video_backlight_support()) { |
1009 | backlight_device_register("fujitsu-laptop", NULL, NULL, | 1009 | fujitsu->bl_device = |
1010 | &fujitsubl_ops); | 1010 | backlight_device_register("fujitsu-laptop", NULL, NULL, |
1011 | if (IS_ERR(fujitsu->bl_device)) | 1011 | &fujitsubl_ops); |
1012 | return PTR_ERR(fujitsu->bl_device); | 1012 | if (IS_ERR(fujitsu->bl_device)) |
1013 | return PTR_ERR(fujitsu->bl_device); | ||
1014 | max_brightness = fujitsu->max_brightness; | ||
1015 | fujitsu->bl_device->props.max_brightness = max_brightness - 1; | ||
1016 | fujitsu->bl_device->props.brightness = fujitsu->brightness_level; | ||
1017 | } | ||
1013 | 1018 | ||
1014 | max_brightness = fujitsu->max_brightness; | ||
1015 | |||
1016 | fujitsu->bl_device->props.max_brightness = max_brightness - 1; | ||
1017 | fujitsu->bl_device->props.brightness = fujitsu->brightness_level; | ||
1018 | |||
1019 | ret = platform_driver_register(&fujitsupf_driver); | 1019 | ret = platform_driver_register(&fujitsupf_driver); |
1020 | if (ret) | 1020 | if (ret) |
1021 | goto fail_backlight; | 1021 | goto fail_backlight; |
1022 | 1022 | ||
1023 | /* Register hotkey driver */ | 1023 | /* Register hotkey driver */ |
1024 | 1024 | ||
1025 | fujitsu_hotkey = kmalloc(sizeof(struct fujitsu_hotkey_t), GFP_KERNEL); | 1025 | fujitsu_hotkey = kmalloc(sizeof(struct fujitsu_hotkey_t), GFP_KERNEL); |
1026 | if (!fujitsu_hotkey) { | 1026 | if (!fujitsu_hotkey) { |
1027 | ret = -ENOMEM; | 1027 | ret = -ENOMEM; |
1028 | goto fail_hotkey; | 1028 | goto fail_hotkey; |
1029 | } | 1029 | } |
1030 | memset(fujitsu_hotkey, 0, sizeof(struct fujitsu_hotkey_t)); | 1030 | memset(fujitsu_hotkey, 0, sizeof(struct fujitsu_hotkey_t)); |
1031 | 1031 | ||
1032 | result = acpi_bus_register_driver(&acpi_fujitsu_hotkey_driver); | 1032 | result = acpi_bus_register_driver(&acpi_fujitsu_hotkey_driver); |
1033 | if (result < 0) { | 1033 | if (result < 0) { |
1034 | ret = -ENODEV; | 1034 | ret = -ENODEV; |
1035 | goto fail_hotkey1; | 1035 | goto fail_hotkey1; |
1036 | } | 1036 | } |
1037 | 1037 | ||
1038 | printk(KERN_INFO "fujitsu-laptop: driver " FUJITSU_DRIVER_VERSION | 1038 | printk(KERN_INFO "fujitsu-laptop: driver " FUJITSU_DRIVER_VERSION |
1039 | " successfully loaded.\n"); | 1039 | " successfully loaded.\n"); |
1040 | 1040 | ||
1041 | return 0; | 1041 | return 0; |
1042 | 1042 | ||
1043 | fail_hotkey1: | 1043 | fail_hotkey1: |
1044 | 1044 | ||
1045 | kfree(fujitsu_hotkey); | 1045 | kfree(fujitsu_hotkey); |
1046 | 1046 | ||
1047 | fail_hotkey: | 1047 | fail_hotkey: |
1048 | 1048 | ||
1049 | platform_driver_unregister(&fujitsupf_driver); | 1049 | platform_driver_unregister(&fujitsupf_driver); |
1050 | 1050 | ||
1051 | fail_backlight: | 1051 | fail_backlight: |
1052 | 1052 | ||
1053 | backlight_device_unregister(fujitsu->bl_device); | 1053 | if (fujitsu->bl_device) |
1054 | backlight_device_unregister(fujitsu->bl_device); | ||
1054 | 1055 | ||
1055 | fail_platform_device2: | 1056 | fail_platform_device2: |
1056 | 1057 | ||
1057 | platform_device_del(fujitsu->pf_device); | 1058 | platform_device_del(fujitsu->pf_device); |
1058 | 1059 | ||
1059 | fail_platform_device1: | 1060 | fail_platform_device1: |
1060 | 1061 | ||
1061 | platform_device_put(fujitsu->pf_device); | 1062 | platform_device_put(fujitsu->pf_device); |
1062 | 1063 | ||
1063 | fail_platform_driver: | 1064 | fail_platform_driver: |
1064 | 1065 | ||
1065 | acpi_bus_unregister_driver(&acpi_fujitsu_driver); | 1066 | acpi_bus_unregister_driver(&acpi_fujitsu_driver); |
1066 | 1067 | ||
1067 | fail_acpi: | 1068 | fail_acpi: |
1068 | 1069 | ||
1069 | kfree(fujitsu); | 1070 | kfree(fujitsu); |
1070 | 1071 | ||
1071 | return ret; | 1072 | return ret; |
1072 | } | 1073 | } |
1073 | 1074 | ||
1074 | static void __exit fujitsu_cleanup(void) | 1075 | static void __exit fujitsu_cleanup(void) |
1075 | { | 1076 | { |
1076 | sysfs_remove_group(&fujitsu->pf_device->dev.kobj, | 1077 | sysfs_remove_group(&fujitsu->pf_device->dev.kobj, |
1077 | &fujitsupf_attribute_group); | 1078 | &fujitsupf_attribute_group); |
1078 | platform_device_unregister(fujitsu->pf_device); | 1079 | platform_device_unregister(fujitsu->pf_device); |
1079 | platform_driver_unregister(&fujitsupf_driver); | 1080 | platform_driver_unregister(&fujitsupf_driver); |
1080 | backlight_device_unregister(fujitsu->bl_device); | 1081 | if (fujitsu->bl_device) |
1082 | backlight_device_unregister(fujitsu->bl_device); | ||
1081 | 1083 | ||
1082 | acpi_bus_unregister_driver(&acpi_fujitsu_driver); | 1084 | acpi_bus_unregister_driver(&acpi_fujitsu_driver); |
1083 | 1085 | ||
1084 | kfree(fujitsu); | 1086 | kfree(fujitsu); |
1085 | 1087 | ||
1086 | acpi_bus_unregister_driver(&acpi_fujitsu_hotkey_driver); | 1088 | acpi_bus_unregister_driver(&acpi_fujitsu_hotkey_driver); |
1087 | 1089 | ||
1088 | kfree(fujitsu_hotkey); | 1090 | kfree(fujitsu_hotkey); |
1089 | 1091 | ||
1090 | printk(KERN_INFO "fujitsu-laptop: driver unloaded.\n"); | 1092 | printk(KERN_INFO "fujitsu-laptop: driver unloaded.\n"); |
1091 | } | 1093 | } |
1092 | 1094 | ||
1093 | module_init(fujitsu_init); | 1095 | module_init(fujitsu_init); |
1094 | module_exit(fujitsu_cleanup); | 1096 | module_exit(fujitsu_cleanup); |
1095 | 1097 | ||
1096 | module_param(use_alt_lcd_levels, uint, 0644); | 1098 | module_param(use_alt_lcd_levels, uint, 0644); |
1097 | MODULE_PARM_DESC(use_alt_lcd_levels, | 1099 | MODULE_PARM_DESC(use_alt_lcd_levels, |
1098 | "Use alternative interface for lcd_levels (needed for Lifebook s6410)."); | 1100 | "Use alternative interface for lcd_levels (needed for Lifebook s6410)."); |
1099 | module_param(disable_brightness_keys, uint, 0644); | 1101 | module_param(disable_brightness_keys, uint, 0644); |
1100 | MODULE_PARM_DESC(disable_brightness_keys, | 1102 | MODULE_PARM_DESC(disable_brightness_keys, |
1101 | "Disable brightness keys (eg. if they are already handled by the generic ACPI_VIDEO device)."); | 1103 | "Disable brightness keys (eg. if they are already handled by the generic ACPI_VIDEO device)."); |
1102 | module_param(disable_brightness_adjust, uint, 0644); | 1104 | module_param(disable_brightness_adjust, uint, 0644); |
1103 | MODULE_PARM_DESC(disable_brightness_adjust, "Disable brightness adjustment ."); | 1105 | MODULE_PARM_DESC(disable_brightness_adjust, "Disable brightness adjustment ."); |
1104 | #ifdef CONFIG_FUJITSU_LAPTOP_DEBUG | 1106 | #ifdef CONFIG_FUJITSU_LAPTOP_DEBUG |
1105 | module_param_named(debug, dbg_level, uint, 0644); | 1107 | module_param_named(debug, dbg_level, uint, 0644); |
1106 | MODULE_PARM_DESC(debug, "Sets debug level bit-mask"); | 1108 | MODULE_PARM_DESC(debug, "Sets debug level bit-mask"); |
1107 | #endif | 1109 | #endif |
1108 | 1110 | ||
1109 | MODULE_AUTHOR("Jonathan Woithe, Peter Gruber"); | 1111 | MODULE_AUTHOR("Jonathan Woithe, Peter Gruber"); |
1110 | MODULE_DESCRIPTION("Fujitsu laptop extras support"); | 1112 | MODULE_DESCRIPTION("Fujitsu laptop extras support"); |
1111 | MODULE_VERSION(FUJITSU_DRIVER_VERSION); | 1113 | MODULE_VERSION(FUJITSU_DRIVER_VERSION); |
1112 | MODULE_LICENSE("GPL"); | 1114 | MODULE_LICENSE("GPL"); |
1113 | 1115 | ||
1114 | MODULE_ALIAS("dmi:*:svnFUJITSUSIEMENS:*:pvr:rvnFUJITSU:rnFJNB1D3:*:cvrS6410:*"); | 1116 | MODULE_ALIAS("dmi:*:svnFUJITSUSIEMENS:*:pvr:rvnFUJITSU:rnFJNB1D3:*:cvrS6410:*"); |
1115 | MODULE_ALIAS("dmi:*:svnFUJITSU:*:pvr:rvnFUJITSU:rnFJNB19C:*:cvrS7020:*"); | 1117 | MODULE_ALIAS("dmi:*:svnFUJITSU:*:pvr:rvnFUJITSU:rnFJNB19C:*:cvrS7020:*"); |
1116 | 1118 | ||
1117 | static struct pnp_device_id pnp_ids[] = { | 1119 | static struct pnp_device_id pnp_ids[] = { |
1118 | {.id = "FUJ02bf"}, | 1120 | {.id = "FUJ02bf"}, |
1119 | {.id = "FUJ02B1"}, | 1121 | {.id = "FUJ02B1"}, |
1120 | {.id = "FUJ02E3"}, | 1122 | {.id = "FUJ02E3"}, |
drivers/misc/msi-laptop.c
1 | /*-*-linux-c-*-*/ | 1 | /*-*-linux-c-*-*/ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | Copyright (C) 2006 Lennart Poettering <mzxreary (at) 0pointer (dot) de> | 4 | Copyright (C) 2006 Lennart Poettering <mzxreary (at) 0pointer (dot) de> |
5 | 5 | ||
6 | This program is free software; you can redistribute it and/or modify | 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 | 7 | it under the terms of the GNU General Public License as published by |
8 | the Free Software Foundation; either version 2 of the License, or | 8 | the Free Software Foundation; either version 2 of the License, or |
9 | (at your option) any later version. | 9 | (at your option) any later version. |
10 | 10 | ||
11 | This program is distributed in the hope that it will be useful, but | 11 | This program is distributed in the hope that it will be useful, but |
12 | WITHOUT ANY WARRANTY; without even the implied warranty of | 12 | WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | General Public License for more details. | 14 | General Public License for more details. |
15 | 15 | ||
16 | You should have received a copy of the GNU General Public License | 16 | You should have received a copy of the GNU General Public License |
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., 51 Franklin Street, Fifth Floor, Boston, MA | 18 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
19 | 02110-1301, USA. | 19 | 02110-1301, USA. |
20 | */ | 20 | */ |
21 | 21 | ||
22 | /* | 22 | /* |
23 | * msi-laptop.c - MSI S270 laptop support. This laptop is sold under | 23 | * msi-laptop.c - MSI S270 laptop support. This laptop is sold under |
24 | * various brands, including "Cytron/TCM/Medion/Tchibo MD96100". | 24 | * various brands, including "Cytron/TCM/Medion/Tchibo MD96100". |
25 | * | 25 | * |
26 | * Driver also supports S271, S420 models. | 26 | * Driver also supports S271, S420 models. |
27 | * | 27 | * |
28 | * This driver exports a few files in /sys/devices/platform/msi-laptop-pf/: | 28 | * This driver exports a few files in /sys/devices/platform/msi-laptop-pf/: |
29 | * | 29 | * |
30 | * lcd_level - Screen brightness: contains a single integer in the | 30 | * lcd_level - Screen brightness: contains a single integer in the |
31 | * range 0..8. (rw) | 31 | * range 0..8. (rw) |
32 | * | 32 | * |
33 | * auto_brightness - Enable automatic brightness control: contains | 33 | * auto_brightness - Enable automatic brightness control: contains |
34 | * either 0 or 1. If set to 1 the hardware adjusts the screen | 34 | * either 0 or 1. If set to 1 the hardware adjusts the screen |
35 | * brightness automatically when the power cord is | 35 | * brightness automatically when the power cord is |
36 | * plugged/unplugged. (rw) | 36 | * plugged/unplugged. (rw) |
37 | * | 37 | * |
38 | * wlan - WLAN subsystem enabled: contains either 0 or 1. (ro) | 38 | * wlan - WLAN subsystem enabled: contains either 0 or 1. (ro) |
39 | * | 39 | * |
40 | * bluetooth - Bluetooth subsystem enabled: contains either 0 or 1 | 40 | * bluetooth - Bluetooth subsystem enabled: contains either 0 or 1 |
41 | * Please note that this file is constantly 0 if no Bluetooth | 41 | * Please note that this file is constantly 0 if no Bluetooth |
42 | * hardware is available. (ro) | 42 | * hardware is available. (ro) |
43 | * | 43 | * |
44 | * In addition to these platform device attributes the driver | 44 | * In addition to these platform device attributes the driver |
45 | * registers itself in the Linux backlight control subsystem and is | 45 | * registers itself in the Linux backlight control subsystem and is |
46 | * available to userspace under /sys/class/backlight/msi-laptop-bl/. | 46 | * available to userspace under /sys/class/backlight/msi-laptop-bl/. |
47 | * | 47 | * |
48 | * This driver might work on other laptops produced by MSI. If you | 48 | * This driver might work on other laptops produced by MSI. If you |
49 | * want to try it you can pass force=1 as argument to the module which | 49 | * want to try it you can pass force=1 as argument to the module which |
50 | * will force it to load even when the DMI data doesn't identify the | 50 | * will force it to load even when the DMI data doesn't identify the |
51 | * laptop as MSI S270. YMMV. | 51 | * laptop as MSI S270. YMMV. |
52 | */ | 52 | */ |
53 | 53 | ||
54 | #include <linux/module.h> | 54 | #include <linux/module.h> |
55 | #include <linux/kernel.h> | 55 | #include <linux/kernel.h> |
56 | #include <linux/init.h> | 56 | #include <linux/init.h> |
57 | #include <linux/acpi.h> | 57 | #include <linux/acpi.h> |
58 | #include <linux/dmi.h> | 58 | #include <linux/dmi.h> |
59 | #include <linux/backlight.h> | 59 | #include <linux/backlight.h> |
60 | #include <linux/platform_device.h> | 60 | #include <linux/platform_device.h> |
61 | 61 | ||
62 | #define MSI_DRIVER_VERSION "0.5" | 62 | #define MSI_DRIVER_VERSION "0.5" |
63 | 63 | ||
64 | #define MSI_LCD_LEVEL_MAX 9 | 64 | #define MSI_LCD_LEVEL_MAX 9 |
65 | 65 | ||
66 | #define MSI_EC_COMMAND_WIRELESS 0x10 | 66 | #define MSI_EC_COMMAND_WIRELESS 0x10 |
67 | #define MSI_EC_COMMAND_LCD_LEVEL 0x11 | 67 | #define MSI_EC_COMMAND_LCD_LEVEL 0x11 |
68 | 68 | ||
69 | static int force; | 69 | static int force; |
70 | module_param(force, bool, 0); | 70 | module_param(force, bool, 0); |
71 | MODULE_PARM_DESC(force, "Force driver load, ignore DMI data"); | 71 | MODULE_PARM_DESC(force, "Force driver load, ignore DMI data"); |
72 | 72 | ||
73 | static int auto_brightness; | 73 | static int auto_brightness; |
74 | module_param(auto_brightness, int, 0); | 74 | module_param(auto_brightness, int, 0); |
75 | MODULE_PARM_DESC(auto_brightness, "Enable automatic brightness control (0: disabled; 1: enabled; 2: don't touch)"); | 75 | MODULE_PARM_DESC(auto_brightness, "Enable automatic brightness control (0: disabled; 1: enabled; 2: don't touch)"); |
76 | 76 | ||
77 | /* Hardware access */ | 77 | /* Hardware access */ |
78 | 78 | ||
79 | static int set_lcd_level(int level) | 79 | static int set_lcd_level(int level) |
80 | { | 80 | { |
81 | u8 buf[2]; | 81 | u8 buf[2]; |
82 | 82 | ||
83 | if (level < 0 || level >= MSI_LCD_LEVEL_MAX) | 83 | if (level < 0 || level >= MSI_LCD_LEVEL_MAX) |
84 | return -EINVAL; | 84 | return -EINVAL; |
85 | 85 | ||
86 | buf[0] = 0x80; | 86 | buf[0] = 0x80; |
87 | buf[1] = (u8) (level*31); | 87 | buf[1] = (u8) (level*31); |
88 | 88 | ||
89 | return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, buf, sizeof(buf), NULL, 0, 1); | 89 | return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, buf, sizeof(buf), NULL, 0, 1); |
90 | } | 90 | } |
91 | 91 | ||
92 | static int get_lcd_level(void) | 92 | static int get_lcd_level(void) |
93 | { | 93 | { |
94 | u8 wdata = 0, rdata; | 94 | u8 wdata = 0, rdata; |
95 | int result; | 95 | int result; |
96 | 96 | ||
97 | result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1, &rdata, 1, 1); | 97 | result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1, &rdata, 1, 1); |
98 | if (result < 0) | 98 | if (result < 0) |
99 | return result; | 99 | return result; |
100 | 100 | ||
101 | return (int) rdata / 31; | 101 | return (int) rdata / 31; |
102 | } | 102 | } |
103 | 103 | ||
104 | static int get_auto_brightness(void) | 104 | static int get_auto_brightness(void) |
105 | { | 105 | { |
106 | u8 wdata = 4, rdata; | 106 | u8 wdata = 4, rdata; |
107 | int result; | 107 | int result; |
108 | 108 | ||
109 | result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1, &rdata, 1, 1); | 109 | result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1, &rdata, 1, 1); |
110 | if (result < 0) | 110 | if (result < 0) |
111 | return result; | 111 | return result; |
112 | 112 | ||
113 | return !!(rdata & 8); | 113 | return !!(rdata & 8); |
114 | } | 114 | } |
115 | 115 | ||
116 | static int set_auto_brightness(int enable) | 116 | static int set_auto_brightness(int enable) |
117 | { | 117 | { |
118 | u8 wdata[2], rdata; | 118 | u8 wdata[2], rdata; |
119 | int result; | 119 | int result; |
120 | 120 | ||
121 | wdata[0] = 4; | 121 | wdata[0] = 4; |
122 | 122 | ||
123 | result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 1, &rdata, 1, 1); | 123 | result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 1, &rdata, 1, 1); |
124 | if (result < 0) | 124 | if (result < 0) |
125 | return result; | 125 | return result; |
126 | 126 | ||
127 | wdata[0] = 0x84; | 127 | wdata[0] = 0x84; |
128 | wdata[1] = (rdata & 0xF7) | (enable ? 8 : 0); | 128 | wdata[1] = (rdata & 0xF7) | (enable ? 8 : 0); |
129 | 129 | ||
130 | return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 2, NULL, 0, 1); | 130 | return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 2, NULL, 0, 1); |
131 | } | 131 | } |
132 | 132 | ||
133 | static int get_wireless_state(int *wlan, int *bluetooth) | 133 | static int get_wireless_state(int *wlan, int *bluetooth) |
134 | { | 134 | { |
135 | u8 wdata = 0, rdata; | 135 | u8 wdata = 0, rdata; |
136 | int result; | 136 | int result; |
137 | 137 | ||
138 | result = ec_transaction(MSI_EC_COMMAND_WIRELESS, &wdata, 1, &rdata, 1, 1); | 138 | result = ec_transaction(MSI_EC_COMMAND_WIRELESS, &wdata, 1, &rdata, 1, 1); |
139 | if (result < 0) | 139 | if (result < 0) |
140 | return -1; | 140 | return -1; |
141 | 141 | ||
142 | if (wlan) | 142 | if (wlan) |
143 | *wlan = !!(rdata & 8); | 143 | *wlan = !!(rdata & 8); |
144 | 144 | ||
145 | if (bluetooth) | 145 | if (bluetooth) |
146 | *bluetooth = !!(rdata & 128); | 146 | *bluetooth = !!(rdata & 128); |
147 | 147 | ||
148 | return 0; | 148 | return 0; |
149 | } | 149 | } |
150 | 150 | ||
151 | /* Backlight device stuff */ | 151 | /* Backlight device stuff */ |
152 | 152 | ||
153 | static int bl_get_brightness(struct backlight_device *b) | 153 | static int bl_get_brightness(struct backlight_device *b) |
154 | { | 154 | { |
155 | return get_lcd_level(); | 155 | return get_lcd_level(); |
156 | } | 156 | } |
157 | 157 | ||
158 | 158 | ||
159 | static int bl_update_status(struct backlight_device *b) | 159 | static int bl_update_status(struct backlight_device *b) |
160 | { | 160 | { |
161 | return set_lcd_level(b->props.brightness); | 161 | return set_lcd_level(b->props.brightness); |
162 | } | 162 | } |
163 | 163 | ||
164 | static struct backlight_ops msibl_ops = { | 164 | static struct backlight_ops msibl_ops = { |
165 | .get_brightness = bl_get_brightness, | 165 | .get_brightness = bl_get_brightness, |
166 | .update_status = bl_update_status, | 166 | .update_status = bl_update_status, |
167 | }; | 167 | }; |
168 | 168 | ||
169 | static struct backlight_device *msibl_device; | 169 | static struct backlight_device *msibl_device; |
170 | 170 | ||
171 | /* Platform device */ | 171 | /* Platform device */ |
172 | 172 | ||
173 | static ssize_t show_wlan(struct device *dev, | 173 | static ssize_t show_wlan(struct device *dev, |
174 | struct device_attribute *attr, char *buf) | 174 | struct device_attribute *attr, char *buf) |
175 | { | 175 | { |
176 | 176 | ||
177 | int ret, enabled; | 177 | int ret, enabled; |
178 | 178 | ||
179 | ret = get_wireless_state(&enabled, NULL); | 179 | ret = get_wireless_state(&enabled, NULL); |
180 | if (ret < 0) | 180 | if (ret < 0) |
181 | return ret; | 181 | return ret; |
182 | 182 | ||
183 | return sprintf(buf, "%i\n", enabled); | 183 | return sprintf(buf, "%i\n", enabled); |
184 | } | 184 | } |
185 | 185 | ||
186 | static ssize_t show_bluetooth(struct device *dev, | 186 | static ssize_t show_bluetooth(struct device *dev, |
187 | struct device_attribute *attr, char *buf) | 187 | struct device_attribute *attr, char *buf) |
188 | { | 188 | { |
189 | 189 | ||
190 | int ret, enabled; | 190 | int ret, enabled; |
191 | 191 | ||
192 | ret = get_wireless_state(NULL, &enabled); | 192 | ret = get_wireless_state(NULL, &enabled); |
193 | if (ret < 0) | 193 | if (ret < 0) |
194 | return ret; | 194 | return ret; |
195 | 195 | ||
196 | return sprintf(buf, "%i\n", enabled); | 196 | return sprintf(buf, "%i\n", enabled); |
197 | } | 197 | } |
198 | 198 | ||
199 | static ssize_t show_lcd_level(struct device *dev, | 199 | static ssize_t show_lcd_level(struct device *dev, |
200 | struct device_attribute *attr, char *buf) | 200 | struct device_attribute *attr, char *buf) |
201 | { | 201 | { |
202 | 202 | ||
203 | int ret; | 203 | int ret; |
204 | 204 | ||
205 | ret = get_lcd_level(); | 205 | ret = get_lcd_level(); |
206 | if (ret < 0) | 206 | if (ret < 0) |
207 | return ret; | 207 | return ret; |
208 | 208 | ||
209 | return sprintf(buf, "%i\n", ret); | 209 | return sprintf(buf, "%i\n", ret); |
210 | } | 210 | } |
211 | 211 | ||
212 | static ssize_t store_lcd_level(struct device *dev, | 212 | static ssize_t store_lcd_level(struct device *dev, |
213 | struct device_attribute *attr, const char *buf, size_t count) | 213 | struct device_attribute *attr, const char *buf, size_t count) |
214 | { | 214 | { |
215 | 215 | ||
216 | int level, ret; | 216 | int level, ret; |
217 | 217 | ||
218 | if (sscanf(buf, "%i", &level) != 1 || (level < 0 || level >= MSI_LCD_LEVEL_MAX)) | 218 | if (sscanf(buf, "%i", &level) != 1 || (level < 0 || level >= MSI_LCD_LEVEL_MAX)) |
219 | return -EINVAL; | 219 | return -EINVAL; |
220 | 220 | ||
221 | ret = set_lcd_level(level); | 221 | ret = set_lcd_level(level); |
222 | if (ret < 0) | 222 | if (ret < 0) |
223 | return ret; | 223 | return ret; |
224 | 224 | ||
225 | return count; | 225 | return count; |
226 | } | 226 | } |
227 | 227 | ||
228 | static ssize_t show_auto_brightness(struct device *dev, | 228 | static ssize_t show_auto_brightness(struct device *dev, |
229 | struct device_attribute *attr, char *buf) | 229 | struct device_attribute *attr, char *buf) |
230 | { | 230 | { |
231 | 231 | ||
232 | int ret; | 232 | int ret; |
233 | 233 | ||
234 | ret = get_auto_brightness(); | 234 | ret = get_auto_brightness(); |
235 | if (ret < 0) | 235 | if (ret < 0) |
236 | return ret; | 236 | return ret; |
237 | 237 | ||
238 | return sprintf(buf, "%i\n", ret); | 238 | return sprintf(buf, "%i\n", ret); |
239 | } | 239 | } |
240 | 240 | ||
241 | static ssize_t store_auto_brightness(struct device *dev, | 241 | static ssize_t store_auto_brightness(struct device *dev, |
242 | struct device_attribute *attr, const char *buf, size_t count) | 242 | struct device_attribute *attr, const char *buf, size_t count) |
243 | { | 243 | { |
244 | 244 | ||
245 | int enable, ret; | 245 | int enable, ret; |
246 | 246 | ||
247 | if (sscanf(buf, "%i", &enable) != 1 || (enable != (enable & 1))) | 247 | if (sscanf(buf, "%i", &enable) != 1 || (enable != (enable & 1))) |
248 | return -EINVAL; | 248 | return -EINVAL; |
249 | 249 | ||
250 | ret = set_auto_brightness(enable); | 250 | ret = set_auto_brightness(enable); |
251 | if (ret < 0) | 251 | if (ret < 0) |
252 | return ret; | 252 | return ret; |
253 | 253 | ||
254 | return count; | 254 | return count; |
255 | } | 255 | } |
256 | 256 | ||
257 | static DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level); | 257 | static DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level); |
258 | static DEVICE_ATTR(auto_brightness, 0644, show_auto_brightness, store_auto_brightness); | 258 | static DEVICE_ATTR(auto_brightness, 0644, show_auto_brightness, store_auto_brightness); |
259 | static DEVICE_ATTR(bluetooth, 0444, show_bluetooth, NULL); | 259 | static DEVICE_ATTR(bluetooth, 0444, show_bluetooth, NULL); |
260 | static DEVICE_ATTR(wlan, 0444, show_wlan, NULL); | 260 | static DEVICE_ATTR(wlan, 0444, show_wlan, NULL); |
261 | 261 | ||
262 | static struct attribute *msipf_attributes[] = { | 262 | static struct attribute *msipf_attributes[] = { |
263 | &dev_attr_lcd_level.attr, | 263 | &dev_attr_lcd_level.attr, |
264 | &dev_attr_auto_brightness.attr, | 264 | &dev_attr_auto_brightness.attr, |
265 | &dev_attr_bluetooth.attr, | 265 | &dev_attr_bluetooth.attr, |
266 | &dev_attr_wlan.attr, | 266 | &dev_attr_wlan.attr, |
267 | NULL | 267 | NULL |
268 | }; | 268 | }; |
269 | 269 | ||
270 | static struct attribute_group msipf_attribute_group = { | 270 | static struct attribute_group msipf_attribute_group = { |
271 | .attrs = msipf_attributes | 271 | .attrs = msipf_attributes |
272 | }; | 272 | }; |
273 | 273 | ||
274 | static struct platform_driver msipf_driver = { | 274 | static struct platform_driver msipf_driver = { |
275 | .driver = { | 275 | .driver = { |
276 | .name = "msi-laptop-pf", | 276 | .name = "msi-laptop-pf", |
277 | .owner = THIS_MODULE, | 277 | .owner = THIS_MODULE, |
278 | } | 278 | } |
279 | }; | 279 | }; |
280 | 280 | ||
281 | static struct platform_device *msipf_device; | 281 | static struct platform_device *msipf_device; |
282 | 282 | ||
283 | /* Initialization */ | 283 | /* Initialization */ |
284 | 284 | ||
285 | static int dmi_check_cb(const struct dmi_system_id *id) | 285 | static int dmi_check_cb(const struct dmi_system_id *id) |
286 | { | 286 | { |
287 | printk("msi-laptop: Identified laptop model '%s'.\n", id->ident); | 287 | printk("msi-laptop: Identified laptop model '%s'.\n", id->ident); |
288 | return 0; | 288 | return 0; |
289 | } | 289 | } |
290 | 290 | ||
291 | static struct dmi_system_id __initdata msi_dmi_table[] = { | 291 | static struct dmi_system_id __initdata msi_dmi_table[] = { |
292 | { | 292 | { |
293 | .ident = "MSI S270", | 293 | .ident = "MSI S270", |
294 | .matches = { | 294 | .matches = { |
295 | DMI_MATCH(DMI_SYS_VENDOR, "MICRO-STAR INT'L CO.,LTD"), | 295 | DMI_MATCH(DMI_SYS_VENDOR, "MICRO-STAR INT'L CO.,LTD"), |
296 | DMI_MATCH(DMI_PRODUCT_NAME, "MS-1013"), | 296 | DMI_MATCH(DMI_PRODUCT_NAME, "MS-1013"), |
297 | DMI_MATCH(DMI_PRODUCT_VERSION, "0131"), | 297 | DMI_MATCH(DMI_PRODUCT_VERSION, "0131"), |
298 | DMI_MATCH(DMI_CHASSIS_VENDOR, "MICRO-STAR INT'L CO.,LTD") | 298 | DMI_MATCH(DMI_CHASSIS_VENDOR, "MICRO-STAR INT'L CO.,LTD") |
299 | }, | 299 | }, |
300 | .callback = dmi_check_cb | 300 | .callback = dmi_check_cb |
301 | }, | 301 | }, |
302 | { | 302 | { |
303 | .ident = "MSI S271", | 303 | .ident = "MSI S271", |
304 | .matches = { | 304 | .matches = { |
305 | DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"), | 305 | DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"), |
306 | DMI_MATCH(DMI_PRODUCT_NAME, "MS-1058"), | 306 | DMI_MATCH(DMI_PRODUCT_NAME, "MS-1058"), |
307 | DMI_MATCH(DMI_PRODUCT_VERSION, "0581"), | 307 | DMI_MATCH(DMI_PRODUCT_VERSION, "0581"), |
308 | DMI_MATCH(DMI_BOARD_NAME, "MS-1058") | 308 | DMI_MATCH(DMI_BOARD_NAME, "MS-1058") |
309 | }, | 309 | }, |
310 | .callback = dmi_check_cb | 310 | .callback = dmi_check_cb |
311 | }, | 311 | }, |
312 | { | 312 | { |
313 | .ident = "MSI S420", | 313 | .ident = "MSI S420", |
314 | .matches = { | 314 | .matches = { |
315 | DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"), | 315 | DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"), |
316 | DMI_MATCH(DMI_PRODUCT_NAME, "MS-1412"), | 316 | DMI_MATCH(DMI_PRODUCT_NAME, "MS-1412"), |
317 | DMI_MATCH(DMI_BOARD_VENDOR, "MSI"), | 317 | DMI_MATCH(DMI_BOARD_VENDOR, "MSI"), |
318 | DMI_MATCH(DMI_BOARD_NAME, "MS-1412") | 318 | DMI_MATCH(DMI_BOARD_NAME, "MS-1412") |
319 | }, | 319 | }, |
320 | .callback = dmi_check_cb | 320 | .callback = dmi_check_cb |
321 | }, | 321 | }, |
322 | { | 322 | { |
323 | .ident = "Medion MD96100", | 323 | .ident = "Medion MD96100", |
324 | .matches = { | 324 | .matches = { |
325 | DMI_MATCH(DMI_SYS_VENDOR, "NOTEBOOK"), | 325 | DMI_MATCH(DMI_SYS_VENDOR, "NOTEBOOK"), |
326 | DMI_MATCH(DMI_PRODUCT_NAME, "SAM2000"), | 326 | DMI_MATCH(DMI_PRODUCT_NAME, "SAM2000"), |
327 | DMI_MATCH(DMI_PRODUCT_VERSION, "0131"), | 327 | DMI_MATCH(DMI_PRODUCT_VERSION, "0131"), |
328 | DMI_MATCH(DMI_CHASSIS_VENDOR, "MICRO-STAR INT'L CO.,LTD") | 328 | DMI_MATCH(DMI_CHASSIS_VENDOR, "MICRO-STAR INT'L CO.,LTD") |
329 | }, | 329 | }, |
330 | .callback = dmi_check_cb | 330 | .callback = dmi_check_cb |
331 | }, | 331 | }, |
332 | { } | 332 | { } |
333 | }; | 333 | }; |
334 | 334 | ||
335 | static int __init msi_init(void) | 335 | static int __init msi_init(void) |
336 | { | 336 | { |
337 | int ret; | 337 | int ret; |
338 | 338 | ||
339 | if (acpi_disabled) | 339 | if (acpi_disabled) |
340 | return -ENODEV; | 340 | return -ENODEV; |
341 | 341 | ||
342 | if (!force && !dmi_check_system(msi_dmi_table)) | 342 | if (!force && !dmi_check_system(msi_dmi_table)) |
343 | return -ENODEV; | 343 | return -ENODEV; |
344 | 344 | ||
345 | if (auto_brightness < 0 || auto_brightness > 2) | 345 | if (auto_brightness < 0 || auto_brightness > 2) |
346 | return -EINVAL; | 346 | return -EINVAL; |
347 | 347 | ||
348 | /* Register backlight stuff */ | 348 | /* Register backlight stuff */ |
349 | 349 | ||
350 | msibl_device = backlight_device_register("msi-laptop-bl", NULL, NULL, | 350 | if (acpi_video_backlight_support()) { |
351 | &msibl_ops); | 351 | printk(KERN_INFO "MSI: Brightness ignored, must be controlled " |
352 | if (IS_ERR(msibl_device)) | 352 | "by ACPI video driver\n"); |
353 | return PTR_ERR(msibl_device); | 353 | } else { |
354 | 354 | msibl_device = backlight_device_register("msi-laptop-bl", NULL, | |
355 | msibl_device->props.max_brightness = MSI_LCD_LEVEL_MAX-1; | 355 | NULL, &msibl_ops); |
356 | if (IS_ERR(msibl_device)) | ||
357 | return PTR_ERR(msibl_device); | ||
358 | msibl_device->props.max_brightness = MSI_LCD_LEVEL_MAX-1; | ||
359 | } | ||
356 | 360 | ||
357 | ret = platform_driver_register(&msipf_driver); | 361 | ret = platform_driver_register(&msipf_driver); |
358 | if (ret) | 362 | if (ret) |
359 | goto fail_backlight; | 363 | goto fail_backlight; |
360 | 364 | ||
361 | /* Register platform stuff */ | 365 | /* Register platform stuff */ |
362 | 366 | ||
363 | msipf_device = platform_device_alloc("msi-laptop-pf", -1); | 367 | msipf_device = platform_device_alloc("msi-laptop-pf", -1); |
364 | if (!msipf_device) { | 368 | if (!msipf_device) { |
365 | ret = -ENOMEM; | 369 | ret = -ENOMEM; |
366 | goto fail_platform_driver; | 370 | goto fail_platform_driver; |
367 | } | 371 | } |
368 | 372 | ||
369 | ret = platform_device_add(msipf_device); | 373 | ret = platform_device_add(msipf_device); |
370 | if (ret) | 374 | if (ret) |
371 | goto fail_platform_device1; | 375 | goto fail_platform_device1; |
372 | 376 | ||
373 | ret = sysfs_create_group(&msipf_device->dev.kobj, &msipf_attribute_group); | 377 | ret = sysfs_create_group(&msipf_device->dev.kobj, &msipf_attribute_group); |
374 | if (ret) | 378 | if (ret) |
375 | goto fail_platform_device2; | 379 | goto fail_platform_device2; |
376 | 380 | ||
377 | /* Disable automatic brightness control by default because | 381 | /* Disable automatic brightness control by default because |
378 | * this module was probably loaded to do brightness control in | 382 | * this module was probably loaded to do brightness control in |
379 | * software. */ | 383 | * software. */ |
380 | 384 | ||
381 | if (auto_brightness != 2) | 385 | if (auto_brightness != 2) |
382 | set_auto_brightness(auto_brightness); | 386 | set_auto_brightness(auto_brightness); |
383 | 387 | ||
384 | printk(KERN_INFO "msi-laptop: driver "MSI_DRIVER_VERSION" successfully loaded.\n"); | 388 | printk(KERN_INFO "msi-laptop: driver "MSI_DRIVER_VERSION" successfully loaded.\n"); |
385 | 389 | ||
386 | return 0; | 390 | return 0; |
387 | 391 | ||
388 | fail_platform_device2: | 392 | fail_platform_device2: |
389 | 393 | ||
390 | platform_device_del(msipf_device); | 394 | platform_device_del(msipf_device); |
391 | 395 | ||
392 | fail_platform_device1: | 396 | fail_platform_device1: |
393 | 397 | ||
394 | platform_device_put(msipf_device); | 398 | platform_device_put(msipf_device); |
395 | 399 | ||
396 | fail_platform_driver: | 400 | fail_platform_driver: |
397 | 401 | ||
398 | platform_driver_unregister(&msipf_driver); | 402 | platform_driver_unregister(&msipf_driver); |
399 | 403 | ||
400 | fail_backlight: | 404 | fail_backlight: |
401 | 405 | ||
402 | backlight_device_unregister(msibl_device); | 406 | backlight_device_unregister(msibl_device); |
403 | 407 | ||
404 | return ret; | 408 | return ret; |
405 | } | 409 | } |
406 | 410 | ||
407 | static void __exit msi_cleanup(void) | 411 | static void __exit msi_cleanup(void) |
408 | { | 412 | { |
409 | 413 | ||
410 | sysfs_remove_group(&msipf_device->dev.kobj, &msipf_attribute_group); | 414 | sysfs_remove_group(&msipf_device->dev.kobj, &msipf_attribute_group); |
411 | platform_device_unregister(msipf_device); | 415 | platform_device_unregister(msipf_device); |
412 | platform_driver_unregister(&msipf_driver); | 416 | platform_driver_unregister(&msipf_driver); |
413 | backlight_device_unregister(msibl_device); | 417 | backlight_device_unregister(msibl_device); |
414 | 418 | ||
415 | /* Enable automatic brightness control again */ | 419 | /* Enable automatic brightness control again */ |
416 | if (auto_brightness != 2) | 420 | if (auto_brightness != 2) |
417 | set_auto_brightness(1); | 421 | set_auto_brightness(1); |
418 | 422 | ||
419 | printk(KERN_INFO "msi-laptop: driver unloaded.\n"); | 423 | printk(KERN_INFO "msi-laptop: driver unloaded.\n"); |
420 | } | 424 | } |
421 | 425 | ||
422 | module_init(msi_init); | 426 | module_init(msi_init); |
423 | module_exit(msi_cleanup); | 427 | module_exit(msi_cleanup); |
424 | 428 | ||
425 | MODULE_AUTHOR("Lennart Poettering"); | 429 | MODULE_AUTHOR("Lennart Poettering"); |
426 | MODULE_DESCRIPTION("MSI Laptop Support"); | 430 | MODULE_DESCRIPTION("MSI Laptop Support"); |
427 | MODULE_VERSION(MSI_DRIVER_VERSION); | 431 | MODULE_VERSION(MSI_DRIVER_VERSION); |
428 | MODULE_LICENSE("GPL"); | 432 | MODULE_LICENSE("GPL"); |
429 | 433 | ||
430 | MODULE_ALIAS("dmi:*:svnMICRO-STARINT'LCO.,LTD:pnMS-1013:pvr0131*:cvnMICRO-STARINT'LCO.,LTD:ct10:*"); | 434 | MODULE_ALIAS("dmi:*:svnMICRO-STARINT'LCO.,LTD:pnMS-1013:pvr0131*:cvnMICRO-STARINT'LCO.,LTD:ct10:*"); |
431 | MODULE_ALIAS("dmi:*:svnMicro-StarInternational:pnMS-1058:pvr0581:rvnMSI:rnMS-1058:*:ct10:*"); | 435 | MODULE_ALIAS("dmi:*:svnMicro-StarInternational:pnMS-1058:pvr0581:rvnMSI:rnMS-1058:*:ct10:*"); |
432 | MODULE_ALIAS("dmi:*:svnMicro-StarInternational:pnMS-1412:*:rvnMSI:rnMS-1412:*:cvnMICRO-STARINT'LCO.,LTD:ct10:*"); | 436 | MODULE_ALIAS("dmi:*:svnMicro-StarInternational:pnMS-1412:*:rvnMSI:rnMS-1412:*:cvnMICRO-STARINT'LCO.,LTD:ct10:*"); |
433 | MODULE_ALIAS("dmi:*:svnNOTEBOOK:pnSAM2000:pvr0131*:cvnMICRO-STARINT'LCO.,LTD:ct10:*"); | 437 | MODULE_ALIAS("dmi:*:svnNOTEBOOK:pnSAM2000:pvr0131*:cvnMICRO-STARINT'LCO.,LTD:ct10:*"); |
434 | 438 |
drivers/misc/sony-laptop.c
1 | /* | 1 | /* |
2 | * ACPI Sony Notebook Control Driver (SNC and SPIC) | 2 | * ACPI Sony Notebook Control Driver (SNC and SPIC) |
3 | * | 3 | * |
4 | * Copyright (C) 2004-2005 Stelian Pop <stelian@popies.net> | 4 | * Copyright (C) 2004-2005 Stelian Pop <stelian@popies.net> |
5 | * Copyright (C) 2007 Mattia Dongili <malattia@linux.it> | 5 | * Copyright (C) 2007 Mattia Dongili <malattia@linux.it> |
6 | * | 6 | * |
7 | * Parts of this driver inspired from asus_acpi.c and ibm_acpi.c | 7 | * Parts of this driver inspired from asus_acpi.c and ibm_acpi.c |
8 | * which are copyrighted by their respective authors. | 8 | * which are copyrighted by their respective authors. |
9 | * | 9 | * |
10 | * The SNY6001 driver part is based on the sonypi driver which includes | 10 | * The SNY6001 driver part is based on the sonypi driver which includes |
11 | * material from: | 11 | * material from: |
12 | * | 12 | * |
13 | * Copyright (C) 2001-2005 Stelian Pop <stelian@popies.net> | 13 | * Copyright (C) 2001-2005 Stelian Pop <stelian@popies.net> |
14 | * | 14 | * |
15 | * Copyright (C) 2005 Narayanan R S <nars@kadamba.org> | 15 | * Copyright (C) 2005 Narayanan R S <nars@kadamba.org> |
16 | * | 16 | * |
17 | * Copyright (C) 2001-2002 Alcรดve <www.alcove.com> | 17 | * Copyright (C) 2001-2002 Alcรดve <www.alcove.com> |
18 | * | 18 | * |
19 | * Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au> | 19 | * Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au> |
20 | * | 20 | * |
21 | * Copyright (C) 2001 Junichi Morita <jun1m@mars.dti.ne.jp> | 21 | * Copyright (C) 2001 Junichi Morita <jun1m@mars.dti.ne.jp> |
22 | * | 22 | * |
23 | * Copyright (C) 2000 Takaya Kinjo <t-kinjo@tc4.so-net.ne.jp> | 23 | * Copyright (C) 2000 Takaya Kinjo <t-kinjo@tc4.so-net.ne.jp> |
24 | * | 24 | * |
25 | * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com> | 25 | * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com> |
26 | * | 26 | * |
27 | * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras. | 27 | * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras. |
28 | * | 28 | * |
29 | * This program is free software; you can redistribute it and/or modify | 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 | 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 | 31 | * the Free Software Foundation; either version 2 of the License, or |
32 | * (at your option) any later version. | 32 | * (at your option) any later version. |
33 | * | 33 | * |
34 | * This program is distributed in the hope that it will be useful, | 34 | * This program is distributed in the hope that it will be useful, |
35 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 35 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
36 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 36 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
37 | * GNU General Public License for more details. | 37 | * GNU General Public License for more details. |
38 | * | 38 | * |
39 | * You should have received a copy of the GNU General Public License | 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 | 40 | * along with this program; if not, write to the Free Software |
41 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 41 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
42 | * | 42 | * |
43 | */ | 43 | */ |
44 | 44 | ||
45 | #include <linux/kernel.h> | 45 | #include <linux/kernel.h> |
46 | #include <linux/module.h> | 46 | #include <linux/module.h> |
47 | #include <linux/moduleparam.h> | 47 | #include <linux/moduleparam.h> |
48 | #include <linux/init.h> | 48 | #include <linux/init.h> |
49 | #include <linux/smp_lock.h> | 49 | #include <linux/smp_lock.h> |
50 | #include <linux/types.h> | 50 | #include <linux/types.h> |
51 | #include <linux/backlight.h> | 51 | #include <linux/backlight.h> |
52 | #include <linux/platform_device.h> | 52 | #include <linux/platform_device.h> |
53 | #include <linux/err.h> | 53 | #include <linux/err.h> |
54 | #include <linux/dmi.h> | 54 | #include <linux/dmi.h> |
55 | #include <linux/pci.h> | 55 | #include <linux/pci.h> |
56 | #include <linux/interrupt.h> | 56 | #include <linux/interrupt.h> |
57 | #include <linux/delay.h> | 57 | #include <linux/delay.h> |
58 | #include <linux/input.h> | 58 | #include <linux/input.h> |
59 | #include <linux/kfifo.h> | 59 | #include <linux/kfifo.h> |
60 | #include <linux/workqueue.h> | 60 | #include <linux/workqueue.h> |
61 | #include <linux/acpi.h> | 61 | #include <linux/acpi.h> |
62 | #include <acpi/acpi_drivers.h> | 62 | #include <acpi/acpi_drivers.h> |
63 | #include <acpi/acpi_bus.h> | 63 | #include <acpi/acpi_bus.h> |
64 | #include <asm/uaccess.h> | 64 | #include <asm/uaccess.h> |
65 | #include <linux/sonypi.h> | 65 | #include <linux/sonypi.h> |
66 | #include <linux/sony-laptop.h> | 66 | #include <linux/sony-laptop.h> |
67 | #ifdef CONFIG_SONYPI_COMPAT | 67 | #ifdef CONFIG_SONYPI_COMPAT |
68 | #include <linux/poll.h> | 68 | #include <linux/poll.h> |
69 | #include <linux/miscdevice.h> | 69 | #include <linux/miscdevice.h> |
70 | #endif | 70 | #endif |
71 | 71 | ||
72 | #define DRV_PFX "sony-laptop: " | 72 | #define DRV_PFX "sony-laptop: " |
73 | #define dprintk(msg...) do { \ | 73 | #define dprintk(msg...) do { \ |
74 | if (debug) printk(KERN_WARNING DRV_PFX msg); \ | 74 | if (debug) printk(KERN_WARNING DRV_PFX msg); \ |
75 | } while (0) | 75 | } while (0) |
76 | 76 | ||
77 | #define SONY_LAPTOP_DRIVER_VERSION "0.6" | 77 | #define SONY_LAPTOP_DRIVER_VERSION "0.6" |
78 | 78 | ||
79 | #define SONY_NC_CLASS "sony-nc" | 79 | #define SONY_NC_CLASS "sony-nc" |
80 | #define SONY_NC_HID "SNY5001" | 80 | #define SONY_NC_HID "SNY5001" |
81 | #define SONY_NC_DRIVER_NAME "Sony Notebook Control Driver" | 81 | #define SONY_NC_DRIVER_NAME "Sony Notebook Control Driver" |
82 | 82 | ||
83 | #define SONY_PIC_CLASS "sony-pic" | 83 | #define SONY_PIC_CLASS "sony-pic" |
84 | #define SONY_PIC_HID "SNY6001" | 84 | #define SONY_PIC_HID "SNY6001" |
85 | #define SONY_PIC_DRIVER_NAME "Sony Programmable IO Control Driver" | 85 | #define SONY_PIC_DRIVER_NAME "Sony Programmable IO Control Driver" |
86 | 86 | ||
87 | MODULE_AUTHOR("Stelian Pop, Mattia Dongili"); | 87 | MODULE_AUTHOR("Stelian Pop, Mattia Dongili"); |
88 | MODULE_DESCRIPTION("Sony laptop extras driver (SPIC and SNC ACPI device)"); | 88 | MODULE_DESCRIPTION("Sony laptop extras driver (SPIC and SNC ACPI device)"); |
89 | MODULE_LICENSE("GPL"); | 89 | MODULE_LICENSE("GPL"); |
90 | MODULE_VERSION(SONY_LAPTOP_DRIVER_VERSION); | 90 | MODULE_VERSION(SONY_LAPTOP_DRIVER_VERSION); |
91 | 91 | ||
92 | static int debug; | 92 | static int debug; |
93 | module_param(debug, int, 0); | 93 | module_param(debug, int, 0); |
94 | MODULE_PARM_DESC(debug, "set this to 1 (and RTFM) if you want to help " | 94 | MODULE_PARM_DESC(debug, "set this to 1 (and RTFM) if you want to help " |
95 | "the development of this driver"); | 95 | "the development of this driver"); |
96 | 96 | ||
97 | static int no_spic; /* = 0 */ | 97 | static int no_spic; /* = 0 */ |
98 | module_param(no_spic, int, 0444); | 98 | module_param(no_spic, int, 0444); |
99 | MODULE_PARM_DESC(no_spic, | 99 | MODULE_PARM_DESC(no_spic, |
100 | "set this if you don't want to enable the SPIC device"); | 100 | "set this if you don't want to enable the SPIC device"); |
101 | 101 | ||
102 | static int compat; /* = 0 */ | 102 | static int compat; /* = 0 */ |
103 | module_param(compat, int, 0444); | 103 | module_param(compat, int, 0444); |
104 | MODULE_PARM_DESC(compat, | 104 | MODULE_PARM_DESC(compat, |
105 | "set this if you want to enable backward compatibility mode"); | 105 | "set this if you want to enable backward compatibility mode"); |
106 | 106 | ||
107 | static unsigned long mask = 0xffffffff; | 107 | static unsigned long mask = 0xffffffff; |
108 | module_param(mask, ulong, 0644); | 108 | module_param(mask, ulong, 0644); |
109 | MODULE_PARM_DESC(mask, | 109 | MODULE_PARM_DESC(mask, |
110 | "set this to the mask of event you want to enable (see doc)"); | 110 | "set this to the mask of event you want to enable (see doc)"); |
111 | 111 | ||
112 | static int camera; /* = 0 */ | 112 | static int camera; /* = 0 */ |
113 | module_param(camera, int, 0444); | 113 | module_param(camera, int, 0444); |
114 | MODULE_PARM_DESC(camera, | 114 | MODULE_PARM_DESC(camera, |
115 | "set this to 1 to enable Motion Eye camera controls " | 115 | "set this to 1 to enable Motion Eye camera controls " |
116 | "(only use it if you have a C1VE or C1VN model)"); | 116 | "(only use it if you have a C1VE or C1VN model)"); |
117 | 117 | ||
118 | #ifdef CONFIG_SONYPI_COMPAT | 118 | #ifdef CONFIG_SONYPI_COMPAT |
119 | static int minor = -1; | 119 | static int minor = -1; |
120 | module_param(minor, int, 0); | 120 | module_param(minor, int, 0); |
121 | MODULE_PARM_DESC(minor, | 121 | MODULE_PARM_DESC(minor, |
122 | "minor number of the misc device for the SPIC compatibility code, " | 122 | "minor number of the misc device for the SPIC compatibility code, " |
123 | "default is -1 (automatic)"); | 123 | "default is -1 (automatic)"); |
124 | #endif | 124 | #endif |
125 | 125 | ||
126 | /*********** Input Devices ***********/ | 126 | /*********** Input Devices ***********/ |
127 | 127 | ||
128 | #define SONY_LAPTOP_BUF_SIZE 128 | 128 | #define SONY_LAPTOP_BUF_SIZE 128 |
129 | struct sony_laptop_input_s { | 129 | struct sony_laptop_input_s { |
130 | atomic_t users; | 130 | atomic_t users; |
131 | struct input_dev *jog_dev; | 131 | struct input_dev *jog_dev; |
132 | struct input_dev *key_dev; | 132 | struct input_dev *key_dev; |
133 | struct kfifo *fifo; | 133 | struct kfifo *fifo; |
134 | spinlock_t fifo_lock; | 134 | spinlock_t fifo_lock; |
135 | struct workqueue_struct *wq; | 135 | struct workqueue_struct *wq; |
136 | }; | 136 | }; |
137 | static struct sony_laptop_input_s sony_laptop_input = { | 137 | static struct sony_laptop_input_s sony_laptop_input = { |
138 | .users = ATOMIC_INIT(0), | 138 | .users = ATOMIC_INIT(0), |
139 | }; | 139 | }; |
140 | 140 | ||
141 | struct sony_laptop_keypress { | 141 | struct sony_laptop_keypress { |
142 | struct input_dev *dev; | 142 | struct input_dev *dev; |
143 | int key; | 143 | int key; |
144 | }; | 144 | }; |
145 | 145 | ||
146 | /* Correspondance table between sonypi events | 146 | /* Correspondance table between sonypi events |
147 | * and input layer indexes in the keymap | 147 | * and input layer indexes in the keymap |
148 | */ | 148 | */ |
149 | static int sony_laptop_input_index[] = { | 149 | static int sony_laptop_input_index[] = { |
150 | -1, /* 0 no event */ | 150 | -1, /* 0 no event */ |
151 | -1, /* 1 SONYPI_EVENT_JOGDIAL_DOWN */ | 151 | -1, /* 1 SONYPI_EVENT_JOGDIAL_DOWN */ |
152 | -1, /* 2 SONYPI_EVENT_JOGDIAL_UP */ | 152 | -1, /* 2 SONYPI_EVENT_JOGDIAL_UP */ |
153 | -1, /* 3 SONYPI_EVENT_JOGDIAL_DOWN_PRESSED */ | 153 | -1, /* 3 SONYPI_EVENT_JOGDIAL_DOWN_PRESSED */ |
154 | -1, /* 4 SONYPI_EVENT_JOGDIAL_UP_PRESSED */ | 154 | -1, /* 4 SONYPI_EVENT_JOGDIAL_UP_PRESSED */ |
155 | -1, /* 5 SONYPI_EVENT_JOGDIAL_PRESSED */ | 155 | -1, /* 5 SONYPI_EVENT_JOGDIAL_PRESSED */ |
156 | -1, /* 6 SONYPI_EVENT_JOGDIAL_RELEASED */ | 156 | -1, /* 6 SONYPI_EVENT_JOGDIAL_RELEASED */ |
157 | 0, /* 7 SONYPI_EVENT_CAPTURE_PRESSED */ | 157 | 0, /* 7 SONYPI_EVENT_CAPTURE_PRESSED */ |
158 | 1, /* 8 SONYPI_EVENT_CAPTURE_RELEASED */ | 158 | 1, /* 8 SONYPI_EVENT_CAPTURE_RELEASED */ |
159 | 2, /* 9 SONYPI_EVENT_CAPTURE_PARTIALPRESSED */ | 159 | 2, /* 9 SONYPI_EVENT_CAPTURE_PARTIALPRESSED */ |
160 | 3, /* 10 SONYPI_EVENT_CAPTURE_PARTIALRELEASED */ | 160 | 3, /* 10 SONYPI_EVENT_CAPTURE_PARTIALRELEASED */ |
161 | 4, /* 11 SONYPI_EVENT_FNKEY_ESC */ | 161 | 4, /* 11 SONYPI_EVENT_FNKEY_ESC */ |
162 | 5, /* 12 SONYPI_EVENT_FNKEY_F1 */ | 162 | 5, /* 12 SONYPI_EVENT_FNKEY_F1 */ |
163 | 6, /* 13 SONYPI_EVENT_FNKEY_F2 */ | 163 | 6, /* 13 SONYPI_EVENT_FNKEY_F2 */ |
164 | 7, /* 14 SONYPI_EVENT_FNKEY_F3 */ | 164 | 7, /* 14 SONYPI_EVENT_FNKEY_F3 */ |
165 | 8, /* 15 SONYPI_EVENT_FNKEY_F4 */ | 165 | 8, /* 15 SONYPI_EVENT_FNKEY_F4 */ |
166 | 9, /* 16 SONYPI_EVENT_FNKEY_F5 */ | 166 | 9, /* 16 SONYPI_EVENT_FNKEY_F5 */ |
167 | 10, /* 17 SONYPI_EVENT_FNKEY_F6 */ | 167 | 10, /* 17 SONYPI_EVENT_FNKEY_F6 */ |
168 | 11, /* 18 SONYPI_EVENT_FNKEY_F7 */ | 168 | 11, /* 18 SONYPI_EVENT_FNKEY_F7 */ |
169 | 12, /* 19 SONYPI_EVENT_FNKEY_F8 */ | 169 | 12, /* 19 SONYPI_EVENT_FNKEY_F8 */ |
170 | 13, /* 20 SONYPI_EVENT_FNKEY_F9 */ | 170 | 13, /* 20 SONYPI_EVENT_FNKEY_F9 */ |
171 | 14, /* 21 SONYPI_EVENT_FNKEY_F10 */ | 171 | 14, /* 21 SONYPI_EVENT_FNKEY_F10 */ |
172 | 15, /* 22 SONYPI_EVENT_FNKEY_F11 */ | 172 | 15, /* 22 SONYPI_EVENT_FNKEY_F11 */ |
173 | 16, /* 23 SONYPI_EVENT_FNKEY_F12 */ | 173 | 16, /* 23 SONYPI_EVENT_FNKEY_F12 */ |
174 | 17, /* 24 SONYPI_EVENT_FNKEY_1 */ | 174 | 17, /* 24 SONYPI_EVENT_FNKEY_1 */ |
175 | 18, /* 25 SONYPI_EVENT_FNKEY_2 */ | 175 | 18, /* 25 SONYPI_EVENT_FNKEY_2 */ |
176 | 19, /* 26 SONYPI_EVENT_FNKEY_D */ | 176 | 19, /* 26 SONYPI_EVENT_FNKEY_D */ |
177 | 20, /* 27 SONYPI_EVENT_FNKEY_E */ | 177 | 20, /* 27 SONYPI_EVENT_FNKEY_E */ |
178 | 21, /* 28 SONYPI_EVENT_FNKEY_F */ | 178 | 21, /* 28 SONYPI_EVENT_FNKEY_F */ |
179 | 22, /* 29 SONYPI_EVENT_FNKEY_S */ | 179 | 22, /* 29 SONYPI_EVENT_FNKEY_S */ |
180 | 23, /* 30 SONYPI_EVENT_FNKEY_B */ | 180 | 23, /* 30 SONYPI_EVENT_FNKEY_B */ |
181 | 24, /* 31 SONYPI_EVENT_BLUETOOTH_PRESSED */ | 181 | 24, /* 31 SONYPI_EVENT_BLUETOOTH_PRESSED */ |
182 | 25, /* 32 SONYPI_EVENT_PKEY_P1 */ | 182 | 25, /* 32 SONYPI_EVENT_PKEY_P1 */ |
183 | 26, /* 33 SONYPI_EVENT_PKEY_P2 */ | 183 | 26, /* 33 SONYPI_EVENT_PKEY_P2 */ |
184 | 27, /* 34 SONYPI_EVENT_PKEY_P3 */ | 184 | 27, /* 34 SONYPI_EVENT_PKEY_P3 */ |
185 | 28, /* 35 SONYPI_EVENT_BACK_PRESSED */ | 185 | 28, /* 35 SONYPI_EVENT_BACK_PRESSED */ |
186 | -1, /* 36 SONYPI_EVENT_LID_CLOSED */ | 186 | -1, /* 36 SONYPI_EVENT_LID_CLOSED */ |
187 | -1, /* 37 SONYPI_EVENT_LID_OPENED */ | 187 | -1, /* 37 SONYPI_EVENT_LID_OPENED */ |
188 | 29, /* 38 SONYPI_EVENT_BLUETOOTH_ON */ | 188 | 29, /* 38 SONYPI_EVENT_BLUETOOTH_ON */ |
189 | 30, /* 39 SONYPI_EVENT_BLUETOOTH_OFF */ | 189 | 30, /* 39 SONYPI_EVENT_BLUETOOTH_OFF */ |
190 | 31, /* 40 SONYPI_EVENT_HELP_PRESSED */ | 190 | 31, /* 40 SONYPI_EVENT_HELP_PRESSED */ |
191 | 32, /* 41 SONYPI_EVENT_FNKEY_ONLY */ | 191 | 32, /* 41 SONYPI_EVENT_FNKEY_ONLY */ |
192 | 33, /* 42 SONYPI_EVENT_JOGDIAL_FAST_DOWN */ | 192 | 33, /* 42 SONYPI_EVENT_JOGDIAL_FAST_DOWN */ |
193 | 34, /* 43 SONYPI_EVENT_JOGDIAL_FAST_UP */ | 193 | 34, /* 43 SONYPI_EVENT_JOGDIAL_FAST_UP */ |
194 | 35, /* 44 SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED */ | 194 | 35, /* 44 SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED */ |
195 | 36, /* 45 SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED */ | 195 | 36, /* 45 SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED */ |
196 | 37, /* 46 SONYPI_EVENT_JOGDIAL_VFAST_DOWN */ | 196 | 37, /* 46 SONYPI_EVENT_JOGDIAL_VFAST_DOWN */ |
197 | 38, /* 47 SONYPI_EVENT_JOGDIAL_VFAST_UP */ | 197 | 38, /* 47 SONYPI_EVENT_JOGDIAL_VFAST_UP */ |
198 | 39, /* 48 SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED */ | 198 | 39, /* 48 SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED */ |
199 | 40, /* 49 SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED */ | 199 | 40, /* 49 SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED */ |
200 | 41, /* 50 SONYPI_EVENT_ZOOM_PRESSED */ | 200 | 41, /* 50 SONYPI_EVENT_ZOOM_PRESSED */ |
201 | 42, /* 51 SONYPI_EVENT_THUMBPHRASE_PRESSED */ | 201 | 42, /* 51 SONYPI_EVENT_THUMBPHRASE_PRESSED */ |
202 | 43, /* 52 SONYPI_EVENT_MEYE_FACE */ | 202 | 43, /* 52 SONYPI_EVENT_MEYE_FACE */ |
203 | 44, /* 53 SONYPI_EVENT_MEYE_OPPOSITE */ | 203 | 44, /* 53 SONYPI_EVENT_MEYE_OPPOSITE */ |
204 | 45, /* 54 SONYPI_EVENT_MEMORYSTICK_INSERT */ | 204 | 45, /* 54 SONYPI_EVENT_MEMORYSTICK_INSERT */ |
205 | 46, /* 55 SONYPI_EVENT_MEMORYSTICK_EJECT */ | 205 | 46, /* 55 SONYPI_EVENT_MEMORYSTICK_EJECT */ |
206 | -1, /* 56 SONYPI_EVENT_ANYBUTTON_RELEASED */ | 206 | -1, /* 56 SONYPI_EVENT_ANYBUTTON_RELEASED */ |
207 | -1, /* 57 SONYPI_EVENT_BATTERY_INSERT */ | 207 | -1, /* 57 SONYPI_EVENT_BATTERY_INSERT */ |
208 | -1, /* 58 SONYPI_EVENT_BATTERY_REMOVE */ | 208 | -1, /* 58 SONYPI_EVENT_BATTERY_REMOVE */ |
209 | -1, /* 59 SONYPI_EVENT_FNKEY_RELEASED */ | 209 | -1, /* 59 SONYPI_EVENT_FNKEY_RELEASED */ |
210 | 47, /* 60 SONYPI_EVENT_WIRELESS_ON */ | 210 | 47, /* 60 SONYPI_EVENT_WIRELESS_ON */ |
211 | 48, /* 61 SONYPI_EVENT_WIRELESS_OFF */ | 211 | 48, /* 61 SONYPI_EVENT_WIRELESS_OFF */ |
212 | 49, /* 62 SONYPI_EVENT_ZOOM_IN_PRESSED */ | 212 | 49, /* 62 SONYPI_EVENT_ZOOM_IN_PRESSED */ |
213 | 50, /* 63 SONYPI_EVENT_ZOOM_OUT_PRESSED */ | 213 | 50, /* 63 SONYPI_EVENT_ZOOM_OUT_PRESSED */ |
214 | }; | 214 | }; |
215 | 215 | ||
216 | static int sony_laptop_input_keycode_map[] = { | 216 | static int sony_laptop_input_keycode_map[] = { |
217 | KEY_CAMERA, /* 0 SONYPI_EVENT_CAPTURE_PRESSED */ | 217 | KEY_CAMERA, /* 0 SONYPI_EVENT_CAPTURE_PRESSED */ |
218 | KEY_RESERVED, /* 1 SONYPI_EVENT_CAPTURE_RELEASED */ | 218 | KEY_RESERVED, /* 1 SONYPI_EVENT_CAPTURE_RELEASED */ |
219 | KEY_RESERVED, /* 2 SONYPI_EVENT_CAPTURE_PARTIALPRESSED */ | 219 | KEY_RESERVED, /* 2 SONYPI_EVENT_CAPTURE_PARTIALPRESSED */ |
220 | KEY_RESERVED, /* 3 SONYPI_EVENT_CAPTURE_PARTIALRELEASED */ | 220 | KEY_RESERVED, /* 3 SONYPI_EVENT_CAPTURE_PARTIALRELEASED */ |
221 | KEY_FN_ESC, /* 4 SONYPI_EVENT_FNKEY_ESC */ | 221 | KEY_FN_ESC, /* 4 SONYPI_EVENT_FNKEY_ESC */ |
222 | KEY_FN_F1, /* 5 SONYPI_EVENT_FNKEY_F1 */ | 222 | KEY_FN_F1, /* 5 SONYPI_EVENT_FNKEY_F1 */ |
223 | KEY_FN_F2, /* 6 SONYPI_EVENT_FNKEY_F2 */ | 223 | KEY_FN_F2, /* 6 SONYPI_EVENT_FNKEY_F2 */ |
224 | KEY_FN_F3, /* 7 SONYPI_EVENT_FNKEY_F3 */ | 224 | KEY_FN_F3, /* 7 SONYPI_EVENT_FNKEY_F3 */ |
225 | KEY_FN_F4, /* 8 SONYPI_EVENT_FNKEY_F4 */ | 225 | KEY_FN_F4, /* 8 SONYPI_EVENT_FNKEY_F4 */ |
226 | KEY_FN_F5, /* 9 SONYPI_EVENT_FNKEY_F5 */ | 226 | KEY_FN_F5, /* 9 SONYPI_EVENT_FNKEY_F5 */ |
227 | KEY_FN_F6, /* 10 SONYPI_EVENT_FNKEY_F6 */ | 227 | KEY_FN_F6, /* 10 SONYPI_EVENT_FNKEY_F6 */ |
228 | KEY_FN_F7, /* 11 SONYPI_EVENT_FNKEY_F7 */ | 228 | KEY_FN_F7, /* 11 SONYPI_EVENT_FNKEY_F7 */ |
229 | KEY_FN_F8, /* 12 SONYPI_EVENT_FNKEY_F8 */ | 229 | KEY_FN_F8, /* 12 SONYPI_EVENT_FNKEY_F8 */ |
230 | KEY_FN_F9, /* 13 SONYPI_EVENT_FNKEY_F9 */ | 230 | KEY_FN_F9, /* 13 SONYPI_EVENT_FNKEY_F9 */ |
231 | KEY_FN_F10, /* 14 SONYPI_EVENT_FNKEY_F10 */ | 231 | KEY_FN_F10, /* 14 SONYPI_EVENT_FNKEY_F10 */ |
232 | KEY_FN_F11, /* 15 SONYPI_EVENT_FNKEY_F11 */ | 232 | KEY_FN_F11, /* 15 SONYPI_EVENT_FNKEY_F11 */ |
233 | KEY_FN_F12, /* 16 SONYPI_EVENT_FNKEY_F12 */ | 233 | KEY_FN_F12, /* 16 SONYPI_EVENT_FNKEY_F12 */ |
234 | KEY_FN_F1, /* 17 SONYPI_EVENT_FNKEY_1 */ | 234 | KEY_FN_F1, /* 17 SONYPI_EVENT_FNKEY_1 */ |
235 | KEY_FN_F2, /* 18 SONYPI_EVENT_FNKEY_2 */ | 235 | KEY_FN_F2, /* 18 SONYPI_EVENT_FNKEY_2 */ |
236 | KEY_FN_D, /* 19 SONYPI_EVENT_FNKEY_D */ | 236 | KEY_FN_D, /* 19 SONYPI_EVENT_FNKEY_D */ |
237 | KEY_FN_E, /* 20 SONYPI_EVENT_FNKEY_E */ | 237 | KEY_FN_E, /* 20 SONYPI_EVENT_FNKEY_E */ |
238 | KEY_FN_F, /* 21 SONYPI_EVENT_FNKEY_F */ | 238 | KEY_FN_F, /* 21 SONYPI_EVENT_FNKEY_F */ |
239 | KEY_FN_S, /* 22 SONYPI_EVENT_FNKEY_S */ | 239 | KEY_FN_S, /* 22 SONYPI_EVENT_FNKEY_S */ |
240 | KEY_FN_B, /* 23 SONYPI_EVENT_FNKEY_B */ | 240 | KEY_FN_B, /* 23 SONYPI_EVENT_FNKEY_B */ |
241 | KEY_BLUETOOTH, /* 24 SONYPI_EVENT_BLUETOOTH_PRESSED */ | 241 | KEY_BLUETOOTH, /* 24 SONYPI_EVENT_BLUETOOTH_PRESSED */ |
242 | KEY_PROG1, /* 25 SONYPI_EVENT_PKEY_P1 */ | 242 | KEY_PROG1, /* 25 SONYPI_EVENT_PKEY_P1 */ |
243 | KEY_PROG2, /* 26 SONYPI_EVENT_PKEY_P2 */ | 243 | KEY_PROG2, /* 26 SONYPI_EVENT_PKEY_P2 */ |
244 | KEY_PROG3, /* 27 SONYPI_EVENT_PKEY_P3 */ | 244 | KEY_PROG3, /* 27 SONYPI_EVENT_PKEY_P3 */ |
245 | KEY_BACK, /* 28 SONYPI_EVENT_BACK_PRESSED */ | 245 | KEY_BACK, /* 28 SONYPI_EVENT_BACK_PRESSED */ |
246 | KEY_BLUETOOTH, /* 29 SONYPI_EVENT_BLUETOOTH_ON */ | 246 | KEY_BLUETOOTH, /* 29 SONYPI_EVENT_BLUETOOTH_ON */ |
247 | KEY_BLUETOOTH, /* 30 SONYPI_EVENT_BLUETOOTH_OFF */ | 247 | KEY_BLUETOOTH, /* 30 SONYPI_EVENT_BLUETOOTH_OFF */ |
248 | KEY_HELP, /* 31 SONYPI_EVENT_HELP_PRESSED */ | 248 | KEY_HELP, /* 31 SONYPI_EVENT_HELP_PRESSED */ |
249 | KEY_FN, /* 32 SONYPI_EVENT_FNKEY_ONLY */ | 249 | KEY_FN, /* 32 SONYPI_EVENT_FNKEY_ONLY */ |
250 | KEY_RESERVED, /* 33 SONYPI_EVENT_JOGDIAL_FAST_DOWN */ | 250 | KEY_RESERVED, /* 33 SONYPI_EVENT_JOGDIAL_FAST_DOWN */ |
251 | KEY_RESERVED, /* 34 SONYPI_EVENT_JOGDIAL_FAST_UP */ | 251 | KEY_RESERVED, /* 34 SONYPI_EVENT_JOGDIAL_FAST_UP */ |
252 | KEY_RESERVED, /* 35 SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED */ | 252 | KEY_RESERVED, /* 35 SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED */ |
253 | KEY_RESERVED, /* 36 SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED */ | 253 | KEY_RESERVED, /* 36 SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED */ |
254 | KEY_RESERVED, /* 37 SONYPI_EVENT_JOGDIAL_VFAST_DOWN */ | 254 | KEY_RESERVED, /* 37 SONYPI_EVENT_JOGDIAL_VFAST_DOWN */ |
255 | KEY_RESERVED, /* 38 SONYPI_EVENT_JOGDIAL_VFAST_UP */ | 255 | KEY_RESERVED, /* 38 SONYPI_EVENT_JOGDIAL_VFAST_UP */ |
256 | KEY_RESERVED, /* 39 SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED */ | 256 | KEY_RESERVED, /* 39 SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED */ |
257 | KEY_RESERVED, /* 40 SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED */ | 257 | KEY_RESERVED, /* 40 SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED */ |
258 | KEY_ZOOM, /* 41 SONYPI_EVENT_ZOOM_PRESSED */ | 258 | KEY_ZOOM, /* 41 SONYPI_EVENT_ZOOM_PRESSED */ |
259 | BTN_THUMB, /* 42 SONYPI_EVENT_THUMBPHRASE_PRESSED */ | 259 | BTN_THUMB, /* 42 SONYPI_EVENT_THUMBPHRASE_PRESSED */ |
260 | KEY_RESERVED, /* 43 SONYPI_EVENT_MEYE_FACE */ | 260 | KEY_RESERVED, /* 43 SONYPI_EVENT_MEYE_FACE */ |
261 | KEY_RESERVED, /* 44 SONYPI_EVENT_MEYE_OPPOSITE */ | 261 | KEY_RESERVED, /* 44 SONYPI_EVENT_MEYE_OPPOSITE */ |
262 | KEY_RESERVED, /* 45 SONYPI_EVENT_MEMORYSTICK_INSERT */ | 262 | KEY_RESERVED, /* 45 SONYPI_EVENT_MEMORYSTICK_INSERT */ |
263 | KEY_RESERVED, /* 46 SONYPI_EVENT_MEMORYSTICK_EJECT */ | 263 | KEY_RESERVED, /* 46 SONYPI_EVENT_MEMORYSTICK_EJECT */ |
264 | KEY_WLAN, /* 47 SONYPI_EVENT_WIRELESS_ON */ | 264 | KEY_WLAN, /* 47 SONYPI_EVENT_WIRELESS_ON */ |
265 | KEY_WLAN, /* 48 SONYPI_EVENT_WIRELESS_OFF */ | 265 | KEY_WLAN, /* 48 SONYPI_EVENT_WIRELESS_OFF */ |
266 | KEY_ZOOMIN, /* 49 SONYPI_EVENT_ZOOM_IN_PRESSED */ | 266 | KEY_ZOOMIN, /* 49 SONYPI_EVENT_ZOOM_IN_PRESSED */ |
267 | KEY_ZOOMOUT /* 50 SONYPI_EVENT_ZOOM_OUT_PRESSED */ | 267 | KEY_ZOOMOUT /* 50 SONYPI_EVENT_ZOOM_OUT_PRESSED */ |
268 | }; | 268 | }; |
269 | 269 | ||
270 | /* release buttons after a short delay if pressed */ | 270 | /* release buttons after a short delay if pressed */ |
271 | static void do_sony_laptop_release_key(struct work_struct *work) | 271 | static void do_sony_laptop_release_key(struct work_struct *work) |
272 | { | 272 | { |
273 | struct sony_laptop_keypress kp; | 273 | struct sony_laptop_keypress kp; |
274 | 274 | ||
275 | while (kfifo_get(sony_laptop_input.fifo, (unsigned char *)&kp, | 275 | while (kfifo_get(sony_laptop_input.fifo, (unsigned char *)&kp, |
276 | sizeof(kp)) == sizeof(kp)) { | 276 | sizeof(kp)) == sizeof(kp)) { |
277 | msleep(10); | 277 | msleep(10); |
278 | input_report_key(kp.dev, kp.key, 0); | 278 | input_report_key(kp.dev, kp.key, 0); |
279 | input_sync(kp.dev); | 279 | input_sync(kp.dev); |
280 | } | 280 | } |
281 | } | 281 | } |
282 | static DECLARE_WORK(sony_laptop_release_key_work, | 282 | static DECLARE_WORK(sony_laptop_release_key_work, |
283 | do_sony_laptop_release_key); | 283 | do_sony_laptop_release_key); |
284 | 284 | ||
285 | /* forward event to the input subsystem */ | 285 | /* forward event to the input subsystem */ |
286 | static void sony_laptop_report_input_event(u8 event) | 286 | static void sony_laptop_report_input_event(u8 event) |
287 | { | 287 | { |
288 | struct input_dev *jog_dev = sony_laptop_input.jog_dev; | 288 | struct input_dev *jog_dev = sony_laptop_input.jog_dev; |
289 | struct input_dev *key_dev = sony_laptop_input.key_dev; | 289 | struct input_dev *key_dev = sony_laptop_input.key_dev; |
290 | struct sony_laptop_keypress kp = { NULL }; | 290 | struct sony_laptop_keypress kp = { NULL }; |
291 | 291 | ||
292 | if (event == SONYPI_EVENT_FNKEY_RELEASED) { | 292 | if (event == SONYPI_EVENT_FNKEY_RELEASED) { |
293 | /* Nothing, not all VAIOs generate this event */ | 293 | /* Nothing, not all VAIOs generate this event */ |
294 | return; | 294 | return; |
295 | } | 295 | } |
296 | 296 | ||
297 | /* report events */ | 297 | /* report events */ |
298 | switch (event) { | 298 | switch (event) { |
299 | /* jog_dev events */ | 299 | /* jog_dev events */ |
300 | case SONYPI_EVENT_JOGDIAL_UP: | 300 | case SONYPI_EVENT_JOGDIAL_UP: |
301 | case SONYPI_EVENT_JOGDIAL_UP_PRESSED: | 301 | case SONYPI_EVENT_JOGDIAL_UP_PRESSED: |
302 | input_report_rel(jog_dev, REL_WHEEL, 1); | 302 | input_report_rel(jog_dev, REL_WHEEL, 1); |
303 | input_sync(jog_dev); | 303 | input_sync(jog_dev); |
304 | return; | 304 | return; |
305 | 305 | ||
306 | case SONYPI_EVENT_JOGDIAL_DOWN: | 306 | case SONYPI_EVENT_JOGDIAL_DOWN: |
307 | case SONYPI_EVENT_JOGDIAL_DOWN_PRESSED: | 307 | case SONYPI_EVENT_JOGDIAL_DOWN_PRESSED: |
308 | input_report_rel(jog_dev, REL_WHEEL, -1); | 308 | input_report_rel(jog_dev, REL_WHEEL, -1); |
309 | input_sync(jog_dev); | 309 | input_sync(jog_dev); |
310 | return; | 310 | return; |
311 | 311 | ||
312 | /* key_dev events */ | 312 | /* key_dev events */ |
313 | case SONYPI_EVENT_JOGDIAL_PRESSED: | 313 | case SONYPI_EVENT_JOGDIAL_PRESSED: |
314 | kp.key = BTN_MIDDLE; | 314 | kp.key = BTN_MIDDLE; |
315 | kp.dev = jog_dev; | 315 | kp.dev = jog_dev; |
316 | break; | 316 | break; |
317 | 317 | ||
318 | default: | 318 | default: |
319 | if (event >= ARRAY_SIZE(sony_laptop_input_index)) { | 319 | if (event >= ARRAY_SIZE(sony_laptop_input_index)) { |
320 | dprintk("sony_laptop_report_input_event, event not known: %d\n", event); | 320 | dprintk("sony_laptop_report_input_event, event not known: %d\n", event); |
321 | break; | 321 | break; |
322 | } | 322 | } |
323 | if (sony_laptop_input_index[event] != -1) { | 323 | if (sony_laptop_input_index[event] != -1) { |
324 | kp.key = sony_laptop_input_keycode_map[sony_laptop_input_index[event]]; | 324 | kp.key = sony_laptop_input_keycode_map[sony_laptop_input_index[event]]; |
325 | if (kp.key != KEY_UNKNOWN) | 325 | if (kp.key != KEY_UNKNOWN) |
326 | kp.dev = key_dev; | 326 | kp.dev = key_dev; |
327 | } | 327 | } |
328 | break; | 328 | break; |
329 | } | 329 | } |
330 | 330 | ||
331 | if (kp.dev) { | 331 | if (kp.dev) { |
332 | input_report_key(kp.dev, kp.key, 1); | 332 | input_report_key(kp.dev, kp.key, 1); |
333 | /* we emit the scancode so we can always remap the key */ | 333 | /* we emit the scancode so we can always remap the key */ |
334 | input_event(kp.dev, EV_MSC, MSC_SCAN, event); | 334 | input_event(kp.dev, EV_MSC, MSC_SCAN, event); |
335 | input_sync(kp.dev); | 335 | input_sync(kp.dev); |
336 | kfifo_put(sony_laptop_input.fifo, | 336 | kfifo_put(sony_laptop_input.fifo, |
337 | (unsigned char *)&kp, sizeof(kp)); | 337 | (unsigned char *)&kp, sizeof(kp)); |
338 | 338 | ||
339 | if (!work_pending(&sony_laptop_release_key_work)) | 339 | if (!work_pending(&sony_laptop_release_key_work)) |
340 | queue_work(sony_laptop_input.wq, | 340 | queue_work(sony_laptop_input.wq, |
341 | &sony_laptop_release_key_work); | 341 | &sony_laptop_release_key_work); |
342 | } else | 342 | } else |
343 | dprintk("unknown input event %.2x\n", event); | 343 | dprintk("unknown input event %.2x\n", event); |
344 | } | 344 | } |
345 | 345 | ||
346 | static int sony_laptop_setup_input(struct acpi_device *acpi_device) | 346 | static int sony_laptop_setup_input(struct acpi_device *acpi_device) |
347 | { | 347 | { |
348 | struct input_dev *jog_dev; | 348 | struct input_dev *jog_dev; |
349 | struct input_dev *key_dev; | 349 | struct input_dev *key_dev; |
350 | int i; | 350 | int i; |
351 | int error; | 351 | int error; |
352 | 352 | ||
353 | /* don't run again if already initialized */ | 353 | /* don't run again if already initialized */ |
354 | if (atomic_add_return(1, &sony_laptop_input.users) > 1) | 354 | if (atomic_add_return(1, &sony_laptop_input.users) > 1) |
355 | return 0; | 355 | return 0; |
356 | 356 | ||
357 | /* kfifo */ | 357 | /* kfifo */ |
358 | spin_lock_init(&sony_laptop_input.fifo_lock); | 358 | spin_lock_init(&sony_laptop_input.fifo_lock); |
359 | sony_laptop_input.fifo = | 359 | sony_laptop_input.fifo = |
360 | kfifo_alloc(SONY_LAPTOP_BUF_SIZE, GFP_KERNEL, | 360 | kfifo_alloc(SONY_LAPTOP_BUF_SIZE, GFP_KERNEL, |
361 | &sony_laptop_input.fifo_lock); | 361 | &sony_laptop_input.fifo_lock); |
362 | if (IS_ERR(sony_laptop_input.fifo)) { | 362 | if (IS_ERR(sony_laptop_input.fifo)) { |
363 | printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n"); | 363 | printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n"); |
364 | error = PTR_ERR(sony_laptop_input.fifo); | 364 | error = PTR_ERR(sony_laptop_input.fifo); |
365 | goto err_dec_users; | 365 | goto err_dec_users; |
366 | } | 366 | } |
367 | 367 | ||
368 | /* init workqueue */ | 368 | /* init workqueue */ |
369 | sony_laptop_input.wq = create_singlethread_workqueue("sony-laptop"); | 369 | sony_laptop_input.wq = create_singlethread_workqueue("sony-laptop"); |
370 | if (!sony_laptop_input.wq) { | 370 | if (!sony_laptop_input.wq) { |
371 | printk(KERN_ERR DRV_PFX | 371 | printk(KERN_ERR DRV_PFX |
372 | "Unabe to create workqueue.\n"); | 372 | "Unabe to create workqueue.\n"); |
373 | error = -ENXIO; | 373 | error = -ENXIO; |
374 | goto err_free_kfifo; | 374 | goto err_free_kfifo; |
375 | } | 375 | } |
376 | 376 | ||
377 | /* input keys */ | 377 | /* input keys */ |
378 | key_dev = input_allocate_device(); | 378 | key_dev = input_allocate_device(); |
379 | if (!key_dev) { | 379 | if (!key_dev) { |
380 | error = -ENOMEM; | 380 | error = -ENOMEM; |
381 | goto err_destroy_wq; | 381 | goto err_destroy_wq; |
382 | } | 382 | } |
383 | 383 | ||
384 | key_dev->name = "Sony Vaio Keys"; | 384 | key_dev->name = "Sony Vaio Keys"; |
385 | key_dev->id.bustype = BUS_ISA; | 385 | key_dev->id.bustype = BUS_ISA; |
386 | key_dev->id.vendor = PCI_VENDOR_ID_SONY; | 386 | key_dev->id.vendor = PCI_VENDOR_ID_SONY; |
387 | key_dev->dev.parent = &acpi_device->dev; | 387 | key_dev->dev.parent = &acpi_device->dev; |
388 | 388 | ||
389 | /* Initialize the Input Drivers: special keys */ | 389 | /* Initialize the Input Drivers: special keys */ |
390 | set_bit(EV_KEY, key_dev->evbit); | 390 | set_bit(EV_KEY, key_dev->evbit); |
391 | set_bit(EV_MSC, key_dev->evbit); | 391 | set_bit(EV_MSC, key_dev->evbit); |
392 | set_bit(MSC_SCAN, key_dev->mscbit); | 392 | set_bit(MSC_SCAN, key_dev->mscbit); |
393 | key_dev->keycodesize = sizeof(sony_laptop_input_keycode_map[0]); | 393 | key_dev->keycodesize = sizeof(sony_laptop_input_keycode_map[0]); |
394 | key_dev->keycodemax = ARRAY_SIZE(sony_laptop_input_keycode_map); | 394 | key_dev->keycodemax = ARRAY_SIZE(sony_laptop_input_keycode_map); |
395 | key_dev->keycode = &sony_laptop_input_keycode_map; | 395 | key_dev->keycode = &sony_laptop_input_keycode_map; |
396 | for (i = 0; i < ARRAY_SIZE(sony_laptop_input_keycode_map); i++) { | 396 | for (i = 0; i < ARRAY_SIZE(sony_laptop_input_keycode_map); i++) { |
397 | if (sony_laptop_input_keycode_map[i] != KEY_RESERVED) { | 397 | if (sony_laptop_input_keycode_map[i] != KEY_RESERVED) { |
398 | set_bit(sony_laptop_input_keycode_map[i], | 398 | set_bit(sony_laptop_input_keycode_map[i], |
399 | key_dev->keybit); | 399 | key_dev->keybit); |
400 | } | 400 | } |
401 | } | 401 | } |
402 | 402 | ||
403 | error = input_register_device(key_dev); | 403 | error = input_register_device(key_dev); |
404 | if (error) | 404 | if (error) |
405 | goto err_free_keydev; | 405 | goto err_free_keydev; |
406 | 406 | ||
407 | sony_laptop_input.key_dev = key_dev; | 407 | sony_laptop_input.key_dev = key_dev; |
408 | 408 | ||
409 | /* jogdial */ | 409 | /* jogdial */ |
410 | jog_dev = input_allocate_device(); | 410 | jog_dev = input_allocate_device(); |
411 | if (!jog_dev) { | 411 | if (!jog_dev) { |
412 | error = -ENOMEM; | 412 | error = -ENOMEM; |
413 | goto err_unregister_keydev; | 413 | goto err_unregister_keydev; |
414 | } | 414 | } |
415 | 415 | ||
416 | jog_dev->name = "Sony Vaio Jogdial"; | 416 | jog_dev->name = "Sony Vaio Jogdial"; |
417 | jog_dev->id.bustype = BUS_ISA; | 417 | jog_dev->id.bustype = BUS_ISA; |
418 | jog_dev->id.vendor = PCI_VENDOR_ID_SONY; | 418 | jog_dev->id.vendor = PCI_VENDOR_ID_SONY; |
419 | key_dev->dev.parent = &acpi_device->dev; | 419 | key_dev->dev.parent = &acpi_device->dev; |
420 | 420 | ||
421 | jog_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); | 421 | jog_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); |
422 | jog_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_MIDDLE); | 422 | jog_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_MIDDLE); |
423 | jog_dev->relbit[0] = BIT_MASK(REL_WHEEL); | 423 | jog_dev->relbit[0] = BIT_MASK(REL_WHEEL); |
424 | 424 | ||
425 | error = input_register_device(jog_dev); | 425 | error = input_register_device(jog_dev); |
426 | if (error) | 426 | if (error) |
427 | goto err_free_jogdev; | 427 | goto err_free_jogdev; |
428 | 428 | ||
429 | sony_laptop_input.jog_dev = jog_dev; | 429 | sony_laptop_input.jog_dev = jog_dev; |
430 | 430 | ||
431 | return 0; | 431 | return 0; |
432 | 432 | ||
433 | err_free_jogdev: | 433 | err_free_jogdev: |
434 | input_free_device(jog_dev); | 434 | input_free_device(jog_dev); |
435 | 435 | ||
436 | err_unregister_keydev: | 436 | err_unregister_keydev: |
437 | input_unregister_device(key_dev); | 437 | input_unregister_device(key_dev); |
438 | /* to avoid kref underflow below at input_free_device */ | 438 | /* to avoid kref underflow below at input_free_device */ |
439 | key_dev = NULL; | 439 | key_dev = NULL; |
440 | 440 | ||
441 | err_free_keydev: | 441 | err_free_keydev: |
442 | input_free_device(key_dev); | 442 | input_free_device(key_dev); |
443 | 443 | ||
444 | err_destroy_wq: | 444 | err_destroy_wq: |
445 | destroy_workqueue(sony_laptop_input.wq); | 445 | destroy_workqueue(sony_laptop_input.wq); |
446 | 446 | ||
447 | err_free_kfifo: | 447 | err_free_kfifo: |
448 | kfifo_free(sony_laptop_input.fifo); | 448 | kfifo_free(sony_laptop_input.fifo); |
449 | 449 | ||
450 | err_dec_users: | 450 | err_dec_users: |
451 | atomic_dec(&sony_laptop_input.users); | 451 | atomic_dec(&sony_laptop_input.users); |
452 | return error; | 452 | return error; |
453 | } | 453 | } |
454 | 454 | ||
455 | static void sony_laptop_remove_input(void) | 455 | static void sony_laptop_remove_input(void) |
456 | { | 456 | { |
457 | /* cleanup only after the last user has gone */ | 457 | /* cleanup only after the last user has gone */ |
458 | if (!atomic_dec_and_test(&sony_laptop_input.users)) | 458 | if (!atomic_dec_and_test(&sony_laptop_input.users)) |
459 | return; | 459 | return; |
460 | 460 | ||
461 | /* flush workqueue first */ | 461 | /* flush workqueue first */ |
462 | flush_workqueue(sony_laptop_input.wq); | 462 | flush_workqueue(sony_laptop_input.wq); |
463 | 463 | ||
464 | /* destroy input devs */ | 464 | /* destroy input devs */ |
465 | input_unregister_device(sony_laptop_input.key_dev); | 465 | input_unregister_device(sony_laptop_input.key_dev); |
466 | sony_laptop_input.key_dev = NULL; | 466 | sony_laptop_input.key_dev = NULL; |
467 | 467 | ||
468 | if (sony_laptop_input.jog_dev) { | 468 | if (sony_laptop_input.jog_dev) { |
469 | input_unregister_device(sony_laptop_input.jog_dev); | 469 | input_unregister_device(sony_laptop_input.jog_dev); |
470 | sony_laptop_input.jog_dev = NULL; | 470 | sony_laptop_input.jog_dev = NULL; |
471 | } | 471 | } |
472 | 472 | ||
473 | destroy_workqueue(sony_laptop_input.wq); | 473 | destroy_workqueue(sony_laptop_input.wq); |
474 | kfifo_free(sony_laptop_input.fifo); | 474 | kfifo_free(sony_laptop_input.fifo); |
475 | } | 475 | } |
476 | 476 | ||
477 | /*********** Platform Device ***********/ | 477 | /*********** Platform Device ***********/ |
478 | 478 | ||
479 | static atomic_t sony_pf_users = ATOMIC_INIT(0); | 479 | static atomic_t sony_pf_users = ATOMIC_INIT(0); |
480 | static struct platform_driver sony_pf_driver = { | 480 | static struct platform_driver sony_pf_driver = { |
481 | .driver = { | 481 | .driver = { |
482 | .name = "sony-laptop", | 482 | .name = "sony-laptop", |
483 | .owner = THIS_MODULE, | 483 | .owner = THIS_MODULE, |
484 | } | 484 | } |
485 | }; | 485 | }; |
486 | static struct platform_device *sony_pf_device; | 486 | static struct platform_device *sony_pf_device; |
487 | 487 | ||
488 | static int sony_pf_add(void) | 488 | static int sony_pf_add(void) |
489 | { | 489 | { |
490 | int ret = 0; | 490 | int ret = 0; |
491 | 491 | ||
492 | /* don't run again if already initialized */ | 492 | /* don't run again if already initialized */ |
493 | if (atomic_add_return(1, &sony_pf_users) > 1) | 493 | if (atomic_add_return(1, &sony_pf_users) > 1) |
494 | return 0; | 494 | return 0; |
495 | 495 | ||
496 | ret = platform_driver_register(&sony_pf_driver); | 496 | ret = platform_driver_register(&sony_pf_driver); |
497 | if (ret) | 497 | if (ret) |
498 | goto out; | 498 | goto out; |
499 | 499 | ||
500 | sony_pf_device = platform_device_alloc("sony-laptop", -1); | 500 | sony_pf_device = platform_device_alloc("sony-laptop", -1); |
501 | if (!sony_pf_device) { | 501 | if (!sony_pf_device) { |
502 | ret = -ENOMEM; | 502 | ret = -ENOMEM; |
503 | goto out_platform_registered; | 503 | goto out_platform_registered; |
504 | } | 504 | } |
505 | 505 | ||
506 | ret = platform_device_add(sony_pf_device); | 506 | ret = platform_device_add(sony_pf_device); |
507 | if (ret) | 507 | if (ret) |
508 | goto out_platform_alloced; | 508 | goto out_platform_alloced; |
509 | 509 | ||
510 | return 0; | 510 | return 0; |
511 | 511 | ||
512 | out_platform_alloced: | 512 | out_platform_alloced: |
513 | platform_device_put(sony_pf_device); | 513 | platform_device_put(sony_pf_device); |
514 | sony_pf_device = NULL; | 514 | sony_pf_device = NULL; |
515 | out_platform_registered: | 515 | out_platform_registered: |
516 | platform_driver_unregister(&sony_pf_driver); | 516 | platform_driver_unregister(&sony_pf_driver); |
517 | out: | 517 | out: |
518 | atomic_dec(&sony_pf_users); | 518 | atomic_dec(&sony_pf_users); |
519 | return ret; | 519 | return ret; |
520 | } | 520 | } |
521 | 521 | ||
522 | static void sony_pf_remove(void) | 522 | static void sony_pf_remove(void) |
523 | { | 523 | { |
524 | /* deregister only after the last user has gone */ | 524 | /* deregister only after the last user has gone */ |
525 | if (!atomic_dec_and_test(&sony_pf_users)) | 525 | if (!atomic_dec_and_test(&sony_pf_users)) |
526 | return; | 526 | return; |
527 | 527 | ||
528 | platform_device_del(sony_pf_device); | 528 | platform_device_del(sony_pf_device); |
529 | platform_device_put(sony_pf_device); | 529 | platform_device_put(sony_pf_device); |
530 | platform_driver_unregister(&sony_pf_driver); | 530 | platform_driver_unregister(&sony_pf_driver); |
531 | } | 531 | } |
532 | 532 | ||
533 | /*********** SNC (SNY5001) Device ***********/ | 533 | /*********** SNC (SNY5001) Device ***********/ |
534 | 534 | ||
535 | /* the device uses 1-based values, while the backlight subsystem uses | 535 | /* the device uses 1-based values, while the backlight subsystem uses |
536 | 0-based values */ | 536 | 0-based values */ |
537 | #define SONY_MAX_BRIGHTNESS 8 | 537 | #define SONY_MAX_BRIGHTNESS 8 |
538 | 538 | ||
539 | #define SNC_VALIDATE_IN 0 | 539 | #define SNC_VALIDATE_IN 0 |
540 | #define SNC_VALIDATE_OUT 1 | 540 | #define SNC_VALIDATE_OUT 1 |
541 | 541 | ||
542 | static ssize_t sony_nc_sysfs_show(struct device *, struct device_attribute *, | 542 | static ssize_t sony_nc_sysfs_show(struct device *, struct device_attribute *, |
543 | char *); | 543 | char *); |
544 | static ssize_t sony_nc_sysfs_store(struct device *, struct device_attribute *, | 544 | static ssize_t sony_nc_sysfs_store(struct device *, struct device_attribute *, |
545 | const char *, size_t); | 545 | const char *, size_t); |
546 | static int boolean_validate(const int, const int); | 546 | static int boolean_validate(const int, const int); |
547 | static int brightness_default_validate(const int, const int); | 547 | static int brightness_default_validate(const int, const int); |
548 | 548 | ||
549 | struct sony_nc_value { | 549 | struct sony_nc_value { |
550 | char *name; /* name of the entry */ | 550 | char *name; /* name of the entry */ |
551 | char **acpiget; /* names of the ACPI get function */ | 551 | char **acpiget; /* names of the ACPI get function */ |
552 | char **acpiset; /* names of the ACPI set function */ | 552 | char **acpiset; /* names of the ACPI set function */ |
553 | int (*validate)(const int, const int); /* input/output validation */ | 553 | int (*validate)(const int, const int); /* input/output validation */ |
554 | int value; /* current setting */ | 554 | int value; /* current setting */ |
555 | int valid; /* Has ever been set */ | 555 | int valid; /* Has ever been set */ |
556 | int debug; /* active only in debug mode ? */ | 556 | int debug; /* active only in debug mode ? */ |
557 | struct device_attribute devattr; /* sysfs atribute */ | 557 | struct device_attribute devattr; /* sysfs atribute */ |
558 | }; | 558 | }; |
559 | 559 | ||
560 | #define SNC_HANDLE_NAMES(_name, _values...) \ | 560 | #define SNC_HANDLE_NAMES(_name, _values...) \ |
561 | static char *snc_##_name[] = { _values, NULL } | 561 | static char *snc_##_name[] = { _values, NULL } |
562 | 562 | ||
563 | #define SNC_HANDLE(_name, _getters, _setters, _validate, _debug) \ | 563 | #define SNC_HANDLE(_name, _getters, _setters, _validate, _debug) \ |
564 | { \ | 564 | { \ |
565 | .name = __stringify(_name), \ | 565 | .name = __stringify(_name), \ |
566 | .acpiget = _getters, \ | 566 | .acpiget = _getters, \ |
567 | .acpiset = _setters, \ | 567 | .acpiset = _setters, \ |
568 | .validate = _validate, \ | 568 | .validate = _validate, \ |
569 | .debug = _debug, \ | 569 | .debug = _debug, \ |
570 | .devattr = __ATTR(_name, 0, sony_nc_sysfs_show, sony_nc_sysfs_store), \ | 570 | .devattr = __ATTR(_name, 0, sony_nc_sysfs_show, sony_nc_sysfs_store), \ |
571 | } | 571 | } |
572 | 572 | ||
573 | #define SNC_HANDLE_NULL { .name = NULL } | 573 | #define SNC_HANDLE_NULL { .name = NULL } |
574 | 574 | ||
575 | SNC_HANDLE_NAMES(fnkey_get, "GHKE"); | 575 | SNC_HANDLE_NAMES(fnkey_get, "GHKE"); |
576 | 576 | ||
577 | SNC_HANDLE_NAMES(brightness_def_get, "GPBR"); | 577 | SNC_HANDLE_NAMES(brightness_def_get, "GPBR"); |
578 | SNC_HANDLE_NAMES(brightness_def_set, "SPBR"); | 578 | SNC_HANDLE_NAMES(brightness_def_set, "SPBR"); |
579 | 579 | ||
580 | SNC_HANDLE_NAMES(cdpower_get, "GCDP"); | 580 | SNC_HANDLE_NAMES(cdpower_get, "GCDP"); |
581 | SNC_HANDLE_NAMES(cdpower_set, "SCDP", "CDPW"); | 581 | SNC_HANDLE_NAMES(cdpower_set, "SCDP", "CDPW"); |
582 | 582 | ||
583 | SNC_HANDLE_NAMES(audiopower_get, "GAZP"); | 583 | SNC_HANDLE_NAMES(audiopower_get, "GAZP"); |
584 | SNC_HANDLE_NAMES(audiopower_set, "AZPW"); | 584 | SNC_HANDLE_NAMES(audiopower_set, "AZPW"); |
585 | 585 | ||
586 | SNC_HANDLE_NAMES(lanpower_get, "GLNP"); | 586 | SNC_HANDLE_NAMES(lanpower_get, "GLNP"); |
587 | SNC_HANDLE_NAMES(lanpower_set, "LNPW"); | 587 | SNC_HANDLE_NAMES(lanpower_set, "LNPW"); |
588 | 588 | ||
589 | SNC_HANDLE_NAMES(lidstate_get, "GLID"); | 589 | SNC_HANDLE_NAMES(lidstate_get, "GLID"); |
590 | 590 | ||
591 | SNC_HANDLE_NAMES(indicatorlamp_get, "GILS"); | 591 | SNC_HANDLE_NAMES(indicatorlamp_get, "GILS"); |
592 | SNC_HANDLE_NAMES(indicatorlamp_set, "SILS"); | 592 | SNC_HANDLE_NAMES(indicatorlamp_set, "SILS"); |
593 | 593 | ||
594 | SNC_HANDLE_NAMES(gainbass_get, "GMGB"); | 594 | SNC_HANDLE_NAMES(gainbass_get, "GMGB"); |
595 | SNC_HANDLE_NAMES(gainbass_set, "CMGB"); | 595 | SNC_HANDLE_NAMES(gainbass_set, "CMGB"); |
596 | 596 | ||
597 | SNC_HANDLE_NAMES(PID_get, "GPID"); | 597 | SNC_HANDLE_NAMES(PID_get, "GPID"); |
598 | 598 | ||
599 | SNC_HANDLE_NAMES(CTR_get, "GCTR"); | 599 | SNC_HANDLE_NAMES(CTR_get, "GCTR"); |
600 | SNC_HANDLE_NAMES(CTR_set, "SCTR"); | 600 | SNC_HANDLE_NAMES(CTR_set, "SCTR"); |
601 | 601 | ||
602 | SNC_HANDLE_NAMES(PCR_get, "GPCR"); | 602 | SNC_HANDLE_NAMES(PCR_get, "GPCR"); |
603 | SNC_HANDLE_NAMES(PCR_set, "SPCR"); | 603 | SNC_HANDLE_NAMES(PCR_set, "SPCR"); |
604 | 604 | ||
605 | SNC_HANDLE_NAMES(CMI_get, "GCMI"); | 605 | SNC_HANDLE_NAMES(CMI_get, "GCMI"); |
606 | SNC_HANDLE_NAMES(CMI_set, "SCMI"); | 606 | SNC_HANDLE_NAMES(CMI_set, "SCMI"); |
607 | 607 | ||
608 | static struct sony_nc_value sony_nc_values[] = { | 608 | static struct sony_nc_value sony_nc_values[] = { |
609 | SNC_HANDLE(brightness_default, snc_brightness_def_get, | 609 | SNC_HANDLE(brightness_default, snc_brightness_def_get, |
610 | snc_brightness_def_set, brightness_default_validate, 0), | 610 | snc_brightness_def_set, brightness_default_validate, 0), |
611 | SNC_HANDLE(fnkey, snc_fnkey_get, NULL, NULL, 0), | 611 | SNC_HANDLE(fnkey, snc_fnkey_get, NULL, NULL, 0), |
612 | SNC_HANDLE(cdpower, snc_cdpower_get, snc_cdpower_set, boolean_validate, 0), | 612 | SNC_HANDLE(cdpower, snc_cdpower_get, snc_cdpower_set, boolean_validate, 0), |
613 | SNC_HANDLE(audiopower, snc_audiopower_get, snc_audiopower_set, | 613 | SNC_HANDLE(audiopower, snc_audiopower_get, snc_audiopower_set, |
614 | boolean_validate, 0), | 614 | boolean_validate, 0), |
615 | SNC_HANDLE(lanpower, snc_lanpower_get, snc_lanpower_set, | 615 | SNC_HANDLE(lanpower, snc_lanpower_get, snc_lanpower_set, |
616 | boolean_validate, 1), | 616 | boolean_validate, 1), |
617 | SNC_HANDLE(lidstate, snc_lidstate_get, NULL, | 617 | SNC_HANDLE(lidstate, snc_lidstate_get, NULL, |
618 | boolean_validate, 0), | 618 | boolean_validate, 0), |
619 | SNC_HANDLE(indicatorlamp, snc_indicatorlamp_get, snc_indicatorlamp_set, | 619 | SNC_HANDLE(indicatorlamp, snc_indicatorlamp_get, snc_indicatorlamp_set, |
620 | boolean_validate, 0), | 620 | boolean_validate, 0), |
621 | SNC_HANDLE(gainbass, snc_gainbass_get, snc_gainbass_set, | 621 | SNC_HANDLE(gainbass, snc_gainbass_get, snc_gainbass_set, |
622 | boolean_validate, 0), | 622 | boolean_validate, 0), |
623 | /* unknown methods */ | 623 | /* unknown methods */ |
624 | SNC_HANDLE(PID, snc_PID_get, NULL, NULL, 1), | 624 | SNC_HANDLE(PID, snc_PID_get, NULL, NULL, 1), |
625 | SNC_HANDLE(CTR, snc_CTR_get, snc_CTR_set, NULL, 1), | 625 | SNC_HANDLE(CTR, snc_CTR_get, snc_CTR_set, NULL, 1), |
626 | SNC_HANDLE(PCR, snc_PCR_get, snc_PCR_set, NULL, 1), | 626 | SNC_HANDLE(PCR, snc_PCR_get, snc_PCR_set, NULL, 1), |
627 | SNC_HANDLE(CMI, snc_CMI_get, snc_CMI_set, NULL, 1), | 627 | SNC_HANDLE(CMI, snc_CMI_get, snc_CMI_set, NULL, 1), |
628 | SNC_HANDLE_NULL | 628 | SNC_HANDLE_NULL |
629 | }; | 629 | }; |
630 | 630 | ||
631 | static acpi_handle sony_nc_acpi_handle; | 631 | static acpi_handle sony_nc_acpi_handle; |
632 | static struct acpi_device *sony_nc_acpi_device = NULL; | 632 | static struct acpi_device *sony_nc_acpi_device = NULL; |
633 | 633 | ||
634 | /* | 634 | /* |
635 | * acpi_evaluate_object wrappers | 635 | * acpi_evaluate_object wrappers |
636 | */ | 636 | */ |
637 | static int acpi_callgetfunc(acpi_handle handle, char *name, int *result) | 637 | static int acpi_callgetfunc(acpi_handle handle, char *name, int *result) |
638 | { | 638 | { |
639 | struct acpi_buffer output; | 639 | struct acpi_buffer output; |
640 | union acpi_object out_obj; | 640 | union acpi_object out_obj; |
641 | acpi_status status; | 641 | acpi_status status; |
642 | 642 | ||
643 | output.length = sizeof(out_obj); | 643 | output.length = sizeof(out_obj); |
644 | output.pointer = &out_obj; | 644 | output.pointer = &out_obj; |
645 | 645 | ||
646 | status = acpi_evaluate_object(handle, name, NULL, &output); | 646 | status = acpi_evaluate_object(handle, name, NULL, &output); |
647 | if ((status == AE_OK) && (out_obj.type == ACPI_TYPE_INTEGER)) { | 647 | if ((status == AE_OK) && (out_obj.type == ACPI_TYPE_INTEGER)) { |
648 | *result = out_obj.integer.value; | 648 | *result = out_obj.integer.value; |
649 | return 0; | 649 | return 0; |
650 | } | 650 | } |
651 | 651 | ||
652 | printk(KERN_WARNING DRV_PFX "acpi_callreadfunc failed\n"); | 652 | printk(KERN_WARNING DRV_PFX "acpi_callreadfunc failed\n"); |
653 | 653 | ||
654 | return -1; | 654 | return -1; |
655 | } | 655 | } |
656 | 656 | ||
657 | static int acpi_callsetfunc(acpi_handle handle, char *name, int value, | 657 | static int acpi_callsetfunc(acpi_handle handle, char *name, int value, |
658 | int *result) | 658 | int *result) |
659 | { | 659 | { |
660 | struct acpi_object_list params; | 660 | struct acpi_object_list params; |
661 | union acpi_object in_obj; | 661 | union acpi_object in_obj; |
662 | struct acpi_buffer output; | 662 | struct acpi_buffer output; |
663 | union acpi_object out_obj; | 663 | union acpi_object out_obj; |
664 | acpi_status status; | 664 | acpi_status status; |
665 | 665 | ||
666 | params.count = 1; | 666 | params.count = 1; |
667 | params.pointer = &in_obj; | 667 | params.pointer = &in_obj; |
668 | in_obj.type = ACPI_TYPE_INTEGER; | 668 | in_obj.type = ACPI_TYPE_INTEGER; |
669 | in_obj.integer.value = value; | 669 | in_obj.integer.value = value; |
670 | 670 | ||
671 | output.length = sizeof(out_obj); | 671 | output.length = sizeof(out_obj); |
672 | output.pointer = &out_obj; | 672 | output.pointer = &out_obj; |
673 | 673 | ||
674 | status = acpi_evaluate_object(handle, name, ¶ms, &output); | 674 | status = acpi_evaluate_object(handle, name, ¶ms, &output); |
675 | if (status == AE_OK) { | 675 | if (status == AE_OK) { |
676 | if (result != NULL) { | 676 | if (result != NULL) { |
677 | if (out_obj.type != ACPI_TYPE_INTEGER) { | 677 | if (out_obj.type != ACPI_TYPE_INTEGER) { |
678 | printk(KERN_WARNING DRV_PFX "acpi_evaluate_object bad " | 678 | printk(KERN_WARNING DRV_PFX "acpi_evaluate_object bad " |
679 | "return type\n"); | 679 | "return type\n"); |
680 | return -1; | 680 | return -1; |
681 | } | 681 | } |
682 | *result = out_obj.integer.value; | 682 | *result = out_obj.integer.value; |
683 | } | 683 | } |
684 | return 0; | 684 | return 0; |
685 | } | 685 | } |
686 | 686 | ||
687 | printk(KERN_WARNING DRV_PFX "acpi_evaluate_object failed\n"); | 687 | printk(KERN_WARNING DRV_PFX "acpi_evaluate_object failed\n"); |
688 | 688 | ||
689 | return -1; | 689 | return -1; |
690 | } | 690 | } |
691 | 691 | ||
692 | /* | 692 | /* |
693 | * sony_nc_values input/output validate functions | 693 | * sony_nc_values input/output validate functions |
694 | */ | 694 | */ |
695 | 695 | ||
696 | /* brightness_default_validate: | 696 | /* brightness_default_validate: |
697 | * | 697 | * |
698 | * manipulate input output values to keep consistency with the | 698 | * manipulate input output values to keep consistency with the |
699 | * backlight framework for which brightness values are 0-based. | 699 | * backlight framework for which brightness values are 0-based. |
700 | */ | 700 | */ |
701 | static int brightness_default_validate(const int direction, const int value) | 701 | static int brightness_default_validate(const int direction, const int value) |
702 | { | 702 | { |
703 | switch (direction) { | 703 | switch (direction) { |
704 | case SNC_VALIDATE_OUT: | 704 | case SNC_VALIDATE_OUT: |
705 | return value - 1; | 705 | return value - 1; |
706 | case SNC_VALIDATE_IN: | 706 | case SNC_VALIDATE_IN: |
707 | if (value >= 0 && value < SONY_MAX_BRIGHTNESS) | 707 | if (value >= 0 && value < SONY_MAX_BRIGHTNESS) |
708 | return value + 1; | 708 | return value + 1; |
709 | } | 709 | } |
710 | return -EINVAL; | 710 | return -EINVAL; |
711 | } | 711 | } |
712 | 712 | ||
713 | /* boolean_validate: | 713 | /* boolean_validate: |
714 | * | 714 | * |
715 | * on input validate boolean values 0/1, on output just pass the | 715 | * on input validate boolean values 0/1, on output just pass the |
716 | * received value. | 716 | * received value. |
717 | */ | 717 | */ |
718 | static int boolean_validate(const int direction, const int value) | 718 | static int boolean_validate(const int direction, const int value) |
719 | { | 719 | { |
720 | if (direction == SNC_VALIDATE_IN) { | 720 | if (direction == SNC_VALIDATE_IN) { |
721 | if (value != 0 && value != 1) | 721 | if (value != 0 && value != 1) |
722 | return -EINVAL; | 722 | return -EINVAL; |
723 | } | 723 | } |
724 | return value; | 724 | return value; |
725 | } | 725 | } |
726 | 726 | ||
727 | /* | 727 | /* |
728 | * Sysfs show/store common to all sony_nc_values | 728 | * Sysfs show/store common to all sony_nc_values |
729 | */ | 729 | */ |
730 | static ssize_t sony_nc_sysfs_show(struct device *dev, struct device_attribute *attr, | 730 | static ssize_t sony_nc_sysfs_show(struct device *dev, struct device_attribute *attr, |
731 | char *buffer) | 731 | char *buffer) |
732 | { | 732 | { |
733 | int value; | 733 | int value; |
734 | struct sony_nc_value *item = | 734 | struct sony_nc_value *item = |
735 | container_of(attr, struct sony_nc_value, devattr); | 735 | container_of(attr, struct sony_nc_value, devattr); |
736 | 736 | ||
737 | if (!*item->acpiget) | 737 | if (!*item->acpiget) |
738 | return -EIO; | 738 | return -EIO; |
739 | 739 | ||
740 | if (acpi_callgetfunc(sony_nc_acpi_handle, *item->acpiget, &value) < 0) | 740 | if (acpi_callgetfunc(sony_nc_acpi_handle, *item->acpiget, &value) < 0) |
741 | return -EIO; | 741 | return -EIO; |
742 | 742 | ||
743 | if (item->validate) | 743 | if (item->validate) |
744 | value = item->validate(SNC_VALIDATE_OUT, value); | 744 | value = item->validate(SNC_VALIDATE_OUT, value); |
745 | 745 | ||
746 | return snprintf(buffer, PAGE_SIZE, "%d\n", value); | 746 | return snprintf(buffer, PAGE_SIZE, "%d\n", value); |
747 | } | 747 | } |
748 | 748 | ||
749 | static ssize_t sony_nc_sysfs_store(struct device *dev, | 749 | static ssize_t sony_nc_sysfs_store(struct device *dev, |
750 | struct device_attribute *attr, | 750 | struct device_attribute *attr, |
751 | const char *buffer, size_t count) | 751 | const char *buffer, size_t count) |
752 | { | 752 | { |
753 | int value; | 753 | int value; |
754 | struct sony_nc_value *item = | 754 | struct sony_nc_value *item = |
755 | container_of(attr, struct sony_nc_value, devattr); | 755 | container_of(attr, struct sony_nc_value, devattr); |
756 | 756 | ||
757 | if (!item->acpiset) | 757 | if (!item->acpiset) |
758 | return -EIO; | 758 | return -EIO; |
759 | 759 | ||
760 | if (count > 31) | 760 | if (count > 31) |
761 | return -EINVAL; | 761 | return -EINVAL; |
762 | 762 | ||
763 | value = simple_strtoul(buffer, NULL, 10); | 763 | value = simple_strtoul(buffer, NULL, 10); |
764 | 764 | ||
765 | if (item->validate) | 765 | if (item->validate) |
766 | value = item->validate(SNC_VALIDATE_IN, value); | 766 | value = item->validate(SNC_VALIDATE_IN, value); |
767 | 767 | ||
768 | if (value < 0) | 768 | if (value < 0) |
769 | return value; | 769 | return value; |
770 | 770 | ||
771 | if (acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset, value, NULL) < 0) | 771 | if (acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset, value, NULL) < 0) |
772 | return -EIO; | 772 | return -EIO; |
773 | item->value = value; | 773 | item->value = value; |
774 | item->valid = 1; | 774 | item->valid = 1; |
775 | return count; | 775 | return count; |
776 | } | 776 | } |
777 | 777 | ||
778 | 778 | ||
779 | /* | 779 | /* |
780 | * Backlight device | 780 | * Backlight device |
781 | */ | 781 | */ |
782 | static int sony_backlight_update_status(struct backlight_device *bd) | 782 | static int sony_backlight_update_status(struct backlight_device *bd) |
783 | { | 783 | { |
784 | return acpi_callsetfunc(sony_nc_acpi_handle, "SBRT", | 784 | return acpi_callsetfunc(sony_nc_acpi_handle, "SBRT", |
785 | bd->props.brightness + 1, NULL); | 785 | bd->props.brightness + 1, NULL); |
786 | } | 786 | } |
787 | 787 | ||
788 | static int sony_backlight_get_brightness(struct backlight_device *bd) | 788 | static int sony_backlight_get_brightness(struct backlight_device *bd) |
789 | { | 789 | { |
790 | int value; | 790 | int value; |
791 | 791 | ||
792 | if (acpi_callgetfunc(sony_nc_acpi_handle, "GBRT", &value)) | 792 | if (acpi_callgetfunc(sony_nc_acpi_handle, "GBRT", &value)) |
793 | return 0; | 793 | return 0; |
794 | /* brightness levels are 1-based, while backlight ones are 0-based */ | 794 | /* brightness levels are 1-based, while backlight ones are 0-based */ |
795 | return value - 1; | 795 | return value - 1; |
796 | } | 796 | } |
797 | 797 | ||
798 | static struct backlight_device *sony_backlight_device; | 798 | static struct backlight_device *sony_backlight_device; |
799 | static struct backlight_ops sony_backlight_ops = { | 799 | static struct backlight_ops sony_backlight_ops = { |
800 | .update_status = sony_backlight_update_status, | 800 | .update_status = sony_backlight_update_status, |
801 | .get_brightness = sony_backlight_get_brightness, | 801 | .get_brightness = sony_backlight_get_brightness, |
802 | }; | 802 | }; |
803 | 803 | ||
804 | /* | 804 | /* |
805 | * New SNC-only Vaios event mapping to driver known keys | 805 | * New SNC-only Vaios event mapping to driver known keys |
806 | */ | 806 | */ |
807 | struct sony_nc_event { | 807 | struct sony_nc_event { |
808 | u8 data; | 808 | u8 data; |
809 | u8 event; | 809 | u8 event; |
810 | }; | 810 | }; |
811 | 811 | ||
812 | static struct sony_nc_event *sony_nc_events; | 812 | static struct sony_nc_event *sony_nc_events; |
813 | 813 | ||
814 | /* Vaio C* --maybe also FE*, N* and AR* ?-- special init sequence | 814 | /* Vaio C* --maybe also FE*, N* and AR* ?-- special init sequence |
815 | * for Fn keys | 815 | * for Fn keys |
816 | */ | 816 | */ |
817 | static int sony_nc_C_enable(const struct dmi_system_id *id) | 817 | static int sony_nc_C_enable(const struct dmi_system_id *id) |
818 | { | 818 | { |
819 | int result = 0; | 819 | int result = 0; |
820 | 820 | ||
821 | printk(KERN_NOTICE DRV_PFX "detected %s\n", id->ident); | 821 | printk(KERN_NOTICE DRV_PFX "detected %s\n", id->ident); |
822 | 822 | ||
823 | sony_nc_events = id->driver_data; | 823 | sony_nc_events = id->driver_data; |
824 | 824 | ||
825 | if (acpi_callsetfunc(sony_nc_acpi_handle, "SN02", 0x4, &result) < 0 | 825 | if (acpi_callsetfunc(sony_nc_acpi_handle, "SN02", 0x4, &result) < 0 |
826 | || acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x2, &result) < 0 | 826 | || acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x2, &result) < 0 |
827 | || acpi_callsetfunc(sony_nc_acpi_handle, "SN02", 0x10, &result) < 0 | 827 | || acpi_callsetfunc(sony_nc_acpi_handle, "SN02", 0x10, &result) < 0 |
828 | || acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x0, &result) < 0 | 828 | || acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x0, &result) < 0 |
829 | || acpi_callsetfunc(sony_nc_acpi_handle, "SN03", 0x2, &result) < 0 | 829 | || acpi_callsetfunc(sony_nc_acpi_handle, "SN03", 0x2, &result) < 0 |
830 | || acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x101, &result) < 0) { | 830 | || acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x101, &result) < 0) { |
831 | printk(KERN_WARNING DRV_PFX "failed to initialize SNC, some " | 831 | printk(KERN_WARNING DRV_PFX "failed to initialize SNC, some " |
832 | "functionalities may be missing\n"); | 832 | "functionalities may be missing\n"); |
833 | return 1; | 833 | return 1; |
834 | } | 834 | } |
835 | return 0; | 835 | return 0; |
836 | } | 836 | } |
837 | 837 | ||
838 | static struct sony_nc_event sony_C_events[] = { | 838 | static struct sony_nc_event sony_C_events[] = { |
839 | { 0x81, SONYPI_EVENT_FNKEY_F1 }, | 839 | { 0x81, SONYPI_EVENT_FNKEY_F1 }, |
840 | { 0x01, SONYPI_EVENT_FNKEY_RELEASED }, | 840 | { 0x01, SONYPI_EVENT_FNKEY_RELEASED }, |
841 | { 0x85, SONYPI_EVENT_FNKEY_F5 }, | 841 | { 0x85, SONYPI_EVENT_FNKEY_F5 }, |
842 | { 0x05, SONYPI_EVENT_FNKEY_RELEASED }, | 842 | { 0x05, SONYPI_EVENT_FNKEY_RELEASED }, |
843 | { 0x86, SONYPI_EVENT_FNKEY_F6 }, | 843 | { 0x86, SONYPI_EVENT_FNKEY_F6 }, |
844 | { 0x06, SONYPI_EVENT_FNKEY_RELEASED }, | 844 | { 0x06, SONYPI_EVENT_FNKEY_RELEASED }, |
845 | { 0x87, SONYPI_EVENT_FNKEY_F7 }, | 845 | { 0x87, SONYPI_EVENT_FNKEY_F7 }, |
846 | { 0x07, SONYPI_EVENT_FNKEY_RELEASED }, | 846 | { 0x07, SONYPI_EVENT_FNKEY_RELEASED }, |
847 | { 0x8A, SONYPI_EVENT_FNKEY_F10 }, | 847 | { 0x8A, SONYPI_EVENT_FNKEY_F10 }, |
848 | { 0x0A, SONYPI_EVENT_FNKEY_RELEASED }, | 848 | { 0x0A, SONYPI_EVENT_FNKEY_RELEASED }, |
849 | { 0x8C, SONYPI_EVENT_FNKEY_F12 }, | 849 | { 0x8C, SONYPI_EVENT_FNKEY_F12 }, |
850 | { 0x0C, SONYPI_EVENT_FNKEY_RELEASED }, | 850 | { 0x0C, SONYPI_EVENT_FNKEY_RELEASED }, |
851 | { 0, 0 }, | 851 | { 0, 0 }, |
852 | }; | 852 | }; |
853 | 853 | ||
854 | /* SNC-only model map */ | 854 | /* SNC-only model map */ |
855 | static const struct dmi_system_id sony_nc_ids[] = { | 855 | static const struct dmi_system_id sony_nc_ids[] = { |
856 | { | 856 | { |
857 | .ident = "Sony Vaio FE Series", | 857 | .ident = "Sony Vaio FE Series", |
858 | .callback = sony_nc_C_enable, | 858 | .callback = sony_nc_C_enable, |
859 | .driver_data = sony_C_events, | 859 | .driver_data = sony_C_events, |
860 | .matches = { | 860 | .matches = { |
861 | DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), | 861 | DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), |
862 | DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FE"), | 862 | DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FE"), |
863 | }, | 863 | }, |
864 | }, | 864 | }, |
865 | { | 865 | { |
866 | .ident = "Sony Vaio FZ Series", | 866 | .ident = "Sony Vaio FZ Series", |
867 | .callback = sony_nc_C_enable, | 867 | .callback = sony_nc_C_enable, |
868 | .driver_data = sony_C_events, | 868 | .driver_data = sony_C_events, |
869 | .matches = { | 869 | .matches = { |
870 | DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), | 870 | DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), |
871 | DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FZ"), | 871 | DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FZ"), |
872 | }, | 872 | }, |
873 | }, | 873 | }, |
874 | { | 874 | { |
875 | .ident = "Sony Vaio C Series", | 875 | .ident = "Sony Vaio C Series", |
876 | .callback = sony_nc_C_enable, | 876 | .callback = sony_nc_C_enable, |
877 | .driver_data = sony_C_events, | 877 | .driver_data = sony_C_events, |
878 | .matches = { | 878 | .matches = { |
879 | DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), | 879 | DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), |
880 | DMI_MATCH(DMI_PRODUCT_NAME, "VGN-C"), | 880 | DMI_MATCH(DMI_PRODUCT_NAME, "VGN-C"), |
881 | }, | 881 | }, |
882 | }, | 882 | }, |
883 | { | 883 | { |
884 | .ident = "Sony Vaio N Series", | 884 | .ident = "Sony Vaio N Series", |
885 | .callback = sony_nc_C_enable, | 885 | .callback = sony_nc_C_enable, |
886 | .driver_data = sony_C_events, | 886 | .driver_data = sony_C_events, |
887 | .matches = { | 887 | .matches = { |
888 | DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), | 888 | DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), |
889 | DMI_MATCH(DMI_PRODUCT_NAME, "VGN-N"), | 889 | DMI_MATCH(DMI_PRODUCT_NAME, "VGN-N"), |
890 | }, | 890 | }, |
891 | }, | 891 | }, |
892 | { } | 892 | { } |
893 | }; | 893 | }; |
894 | 894 | ||
895 | /* | 895 | /* |
896 | * ACPI callbacks | 896 | * ACPI callbacks |
897 | */ | 897 | */ |
898 | static void sony_acpi_notify(acpi_handle handle, u32 event, void *data) | 898 | static void sony_acpi_notify(acpi_handle handle, u32 event, void *data) |
899 | { | 899 | { |
900 | struct sony_nc_event *evmap; | 900 | struct sony_nc_event *evmap; |
901 | u32 ev = event; | 901 | u32 ev = event; |
902 | int result; | 902 | int result; |
903 | 903 | ||
904 | if (ev == 0x92) { | 904 | if (ev == 0x92) { |
905 | /* read the key pressed from EC.GECR | 905 | /* read the key pressed from EC.GECR |
906 | * A call to SN07 with 0x0202 will do it as well respecting | 906 | * A call to SN07 with 0x0202 will do it as well respecting |
907 | * the current protocol on different OSes | 907 | * the current protocol on different OSes |
908 | * | 908 | * |
909 | * Note: the path for GECR may be | 909 | * Note: the path for GECR may be |
910 | * \_SB.PCI0.LPCB.EC (C, FE, AR, N and friends) | 910 | * \_SB.PCI0.LPCB.EC (C, FE, AR, N and friends) |
911 | * \_SB.PCI0.PIB.EC0 (VGN-FR notifications are sent directly, no GECR) | 911 | * \_SB.PCI0.PIB.EC0 (VGN-FR notifications are sent directly, no GECR) |
912 | * | 912 | * |
913 | * TODO: we may want to do the same for the older GHKE -need | 913 | * TODO: we may want to do the same for the older GHKE -need |
914 | * dmi list- so this snippet may become one more callback. | 914 | * dmi list- so this snippet may become one more callback. |
915 | */ | 915 | */ |
916 | if (acpi_callsetfunc(handle, "SN07", 0x0202, &result) < 0) | 916 | if (acpi_callsetfunc(handle, "SN07", 0x0202, &result) < 0) |
917 | dprintk("sony_acpi_notify, unable to decode event 0x%.2x\n", ev); | 917 | dprintk("sony_acpi_notify, unable to decode event 0x%.2x\n", ev); |
918 | else | 918 | else |
919 | ev = result & 0xFF; | 919 | ev = result & 0xFF; |
920 | } | 920 | } |
921 | 921 | ||
922 | if (sony_nc_events) | 922 | if (sony_nc_events) |
923 | for (evmap = sony_nc_events; evmap->event; evmap++) { | 923 | for (evmap = sony_nc_events; evmap->event; evmap++) { |
924 | if (evmap->data == ev) { | 924 | if (evmap->data == ev) { |
925 | ev = evmap->event; | 925 | ev = evmap->event; |
926 | break; | 926 | break; |
927 | } | 927 | } |
928 | } | 928 | } |
929 | 929 | ||
930 | dprintk("sony_acpi_notify, event: 0x%.2x\n", ev); | 930 | dprintk("sony_acpi_notify, event: 0x%.2x\n", ev); |
931 | sony_laptop_report_input_event(ev); | 931 | sony_laptop_report_input_event(ev); |
932 | acpi_bus_generate_proc_event(sony_nc_acpi_device, 1, ev); | 932 | acpi_bus_generate_proc_event(sony_nc_acpi_device, 1, ev); |
933 | } | 933 | } |
934 | 934 | ||
935 | static acpi_status sony_walk_callback(acpi_handle handle, u32 level, | 935 | static acpi_status sony_walk_callback(acpi_handle handle, u32 level, |
936 | void *context, void **return_value) | 936 | void *context, void **return_value) |
937 | { | 937 | { |
938 | struct acpi_namespace_node *node; | 938 | struct acpi_namespace_node *node; |
939 | union acpi_operand_object *operand; | 939 | union acpi_operand_object *operand; |
940 | 940 | ||
941 | node = (struct acpi_namespace_node *)handle; | 941 | node = (struct acpi_namespace_node *)handle; |
942 | operand = (union acpi_operand_object *)node->object; | 942 | operand = (union acpi_operand_object *)node->object; |
943 | 943 | ||
944 | printk(KERN_WARNING DRV_PFX "method: name: %4.4s, args %X\n", node->name.ascii, | 944 | printk(KERN_WARNING DRV_PFX "method: name: %4.4s, args %X\n", node->name.ascii, |
945 | (u32) operand->method.param_count); | 945 | (u32) operand->method.param_count); |
946 | 946 | ||
947 | return AE_OK; | 947 | return AE_OK; |
948 | } | 948 | } |
949 | 949 | ||
950 | /* | 950 | /* |
951 | * ACPI device | 951 | * ACPI device |
952 | */ | 952 | */ |
953 | static int sony_nc_resume(struct acpi_device *device) | 953 | static int sony_nc_resume(struct acpi_device *device) |
954 | { | 954 | { |
955 | struct sony_nc_value *item; | 955 | struct sony_nc_value *item; |
956 | 956 | ||
957 | for (item = sony_nc_values; item->name; item++) { | 957 | for (item = sony_nc_values; item->name; item++) { |
958 | int ret; | 958 | int ret; |
959 | 959 | ||
960 | if (!item->valid) | 960 | if (!item->valid) |
961 | continue; | 961 | continue; |
962 | ret = acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset, | 962 | ret = acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset, |
963 | item->value, NULL); | 963 | item->value, NULL); |
964 | if (ret < 0) { | 964 | if (ret < 0) { |
965 | printk("%s: %d\n", __func__, ret); | 965 | printk("%s: %d\n", __func__, ret); |
966 | break; | 966 | break; |
967 | } | 967 | } |
968 | } | 968 | } |
969 | 969 | ||
970 | /* set the last requested brightness level */ | 970 | /* set the last requested brightness level */ |
971 | if (sony_backlight_device && | 971 | if (sony_backlight_device && |
972 | !sony_backlight_update_status(sony_backlight_device)) | 972 | !sony_backlight_update_status(sony_backlight_device)) |
973 | printk(KERN_WARNING DRV_PFX "unable to restore brightness level\n"); | 973 | printk(KERN_WARNING DRV_PFX "unable to restore brightness level\n"); |
974 | 974 | ||
975 | /* re-initialize models with specific requirements */ | 975 | /* re-initialize models with specific requirements */ |
976 | dmi_check_system(sony_nc_ids); | 976 | dmi_check_system(sony_nc_ids); |
977 | 977 | ||
978 | return 0; | 978 | return 0; |
979 | } | 979 | } |
980 | 980 | ||
981 | static int sony_nc_add(struct acpi_device *device) | 981 | static int sony_nc_add(struct acpi_device *device) |
982 | { | 982 | { |
983 | acpi_status status; | 983 | acpi_status status; |
984 | int result = 0; | 984 | int result = 0; |
985 | acpi_handle handle; | 985 | acpi_handle handle; |
986 | struct sony_nc_value *item; | 986 | struct sony_nc_value *item; |
987 | 987 | ||
988 | printk(KERN_INFO DRV_PFX "%s v%s.\n", | 988 | printk(KERN_INFO DRV_PFX "%s v%s.\n", |
989 | SONY_NC_DRIVER_NAME, SONY_LAPTOP_DRIVER_VERSION); | 989 | SONY_NC_DRIVER_NAME, SONY_LAPTOP_DRIVER_VERSION); |
990 | 990 | ||
991 | sony_nc_acpi_device = device; | 991 | sony_nc_acpi_device = device; |
992 | strcpy(acpi_device_class(device), "sony/hotkey"); | 992 | strcpy(acpi_device_class(device), "sony/hotkey"); |
993 | 993 | ||
994 | sony_nc_acpi_handle = device->handle; | 994 | sony_nc_acpi_handle = device->handle; |
995 | 995 | ||
996 | /* read device status */ | 996 | /* read device status */ |
997 | result = acpi_bus_get_status(device); | 997 | result = acpi_bus_get_status(device); |
998 | /* bail IFF the above call was successful and the device is not present */ | 998 | /* bail IFF the above call was successful and the device is not present */ |
999 | if (!result && !device->status.present) { | 999 | if (!result && !device->status.present) { |
1000 | dprintk("Device not present\n"); | 1000 | dprintk("Device not present\n"); |
1001 | result = -ENODEV; | 1001 | result = -ENODEV; |
1002 | goto outwalk; | 1002 | goto outwalk; |
1003 | } | 1003 | } |
1004 | 1004 | ||
1005 | if (debug) { | 1005 | if (debug) { |
1006 | status = acpi_walk_namespace(ACPI_TYPE_METHOD, sony_nc_acpi_handle, | 1006 | status = acpi_walk_namespace(ACPI_TYPE_METHOD, sony_nc_acpi_handle, |
1007 | 1, sony_walk_callback, NULL, NULL); | 1007 | 1, sony_walk_callback, NULL, NULL); |
1008 | if (ACPI_FAILURE(status)) { | 1008 | if (ACPI_FAILURE(status)) { |
1009 | printk(KERN_WARNING DRV_PFX "unable to walk acpi resources\n"); | 1009 | printk(KERN_WARNING DRV_PFX "unable to walk acpi resources\n"); |
1010 | result = -ENODEV; | 1010 | result = -ENODEV; |
1011 | goto outwalk; | 1011 | goto outwalk; |
1012 | } | 1012 | } |
1013 | } | 1013 | } |
1014 | 1014 | ||
1015 | /* try to _INI the device if such method exists (ACPI spec 3.0-6.5.1 | 1015 | /* try to _INI the device if such method exists (ACPI spec 3.0-6.5.1 |
1016 | * should be respected as we already checked for the device presence above */ | 1016 | * should be respected as we already checked for the device presence above */ |
1017 | if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, METHOD_NAME__INI, &handle))) { | 1017 | if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, METHOD_NAME__INI, &handle))) { |
1018 | dprintk("Invoking _INI\n"); | 1018 | dprintk("Invoking _INI\n"); |
1019 | if (ACPI_FAILURE(acpi_evaluate_object(sony_nc_acpi_handle, METHOD_NAME__INI, | 1019 | if (ACPI_FAILURE(acpi_evaluate_object(sony_nc_acpi_handle, METHOD_NAME__INI, |
1020 | NULL, NULL))) | 1020 | NULL, NULL))) |
1021 | dprintk("_INI Method failed\n"); | 1021 | dprintk("_INI Method failed\n"); |
1022 | } | 1022 | } |
1023 | 1023 | ||
1024 | /* setup input devices and helper fifo */ | 1024 | /* setup input devices and helper fifo */ |
1025 | result = sony_laptop_setup_input(device); | 1025 | result = sony_laptop_setup_input(device); |
1026 | if (result) { | 1026 | if (result) { |
1027 | printk(KERN_ERR DRV_PFX | 1027 | printk(KERN_ERR DRV_PFX |
1028 | "Unabe to create input devices.\n"); | 1028 | "Unabe to create input devices.\n"); |
1029 | goto outwalk; | 1029 | goto outwalk; |
1030 | } | 1030 | } |
1031 | 1031 | ||
1032 | status = acpi_install_notify_handler(sony_nc_acpi_handle, | 1032 | status = acpi_install_notify_handler(sony_nc_acpi_handle, |
1033 | ACPI_DEVICE_NOTIFY, | 1033 | ACPI_DEVICE_NOTIFY, |
1034 | sony_acpi_notify, NULL); | 1034 | sony_acpi_notify, NULL); |
1035 | if (ACPI_FAILURE(status)) { | 1035 | if (ACPI_FAILURE(status)) { |
1036 | printk(KERN_WARNING DRV_PFX "unable to install notify handler (%u)\n", status); | 1036 | printk(KERN_WARNING DRV_PFX "unable to install notify handler (%u)\n", status); |
1037 | result = -ENODEV; | 1037 | result = -ENODEV; |
1038 | goto outinput; | 1038 | goto outinput; |
1039 | } | 1039 | } |
1040 | 1040 | ||
1041 | if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT", &handle))) { | 1041 | if (!acpi_video_backlight_support()) { |
1042 | printk(KERN_INFO DRV_PFX "Sony: Brightness ignored, must be " | ||
1043 | "controlled by ACPI video driver\n"); | ||
1044 | } else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT", | ||
1045 | &handle))) { | ||
1042 | sony_backlight_device = backlight_device_register("sony", NULL, | 1046 | sony_backlight_device = backlight_device_register("sony", NULL, |
1043 | NULL, | 1047 | NULL, |
1044 | &sony_backlight_ops); | 1048 | &sony_backlight_ops); |
1045 | 1049 | ||
1046 | if (IS_ERR(sony_backlight_device)) { | 1050 | if (IS_ERR(sony_backlight_device)) { |
1047 | printk(KERN_WARNING DRV_PFX "unable to register backlight device\n"); | 1051 | printk(KERN_WARNING DRV_PFX "unable to register backlight device\n"); |
1048 | sony_backlight_device = NULL; | 1052 | sony_backlight_device = NULL; |
1049 | } else { | 1053 | } else { |
1050 | sony_backlight_device->props.brightness = | 1054 | sony_backlight_device->props.brightness = |
1051 | sony_backlight_get_brightness | 1055 | sony_backlight_get_brightness |
1052 | (sony_backlight_device); | 1056 | (sony_backlight_device); |
1053 | sony_backlight_device->props.max_brightness = | 1057 | sony_backlight_device->props.max_brightness = |
1054 | SONY_MAX_BRIGHTNESS - 1; | 1058 | SONY_MAX_BRIGHTNESS - 1; |
1055 | } | 1059 | } |
1056 | 1060 | ||
1057 | } | 1061 | } |
1058 | 1062 | ||
1059 | /* initialize models with specific requirements */ | 1063 | /* initialize models with specific requirements */ |
1060 | dmi_check_system(sony_nc_ids); | 1064 | dmi_check_system(sony_nc_ids); |
1061 | 1065 | ||
1062 | result = sony_pf_add(); | 1066 | result = sony_pf_add(); |
1063 | if (result) | 1067 | if (result) |
1064 | goto outbacklight; | 1068 | goto outbacklight; |
1065 | 1069 | ||
1066 | /* create sony_pf sysfs attributes related to the SNC device */ | 1070 | /* create sony_pf sysfs attributes related to the SNC device */ |
1067 | for (item = sony_nc_values; item->name; ++item) { | 1071 | for (item = sony_nc_values; item->name; ++item) { |
1068 | 1072 | ||
1069 | if (!debug && item->debug) | 1073 | if (!debug && item->debug) |
1070 | continue; | 1074 | continue; |
1071 | 1075 | ||
1072 | /* find the available acpiget as described in the DSDT */ | 1076 | /* find the available acpiget as described in the DSDT */ |
1073 | for (; item->acpiget && *item->acpiget; ++item->acpiget) { | 1077 | for (; item->acpiget && *item->acpiget; ++item->acpiget) { |
1074 | if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, | 1078 | if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, |
1075 | *item->acpiget, | 1079 | *item->acpiget, |
1076 | &handle))) { | 1080 | &handle))) { |
1077 | dprintk("Found %s getter: %s\n", | 1081 | dprintk("Found %s getter: %s\n", |
1078 | item->name, *item->acpiget); | 1082 | item->name, *item->acpiget); |
1079 | item->devattr.attr.mode |= S_IRUGO; | 1083 | item->devattr.attr.mode |= S_IRUGO; |
1080 | break; | 1084 | break; |
1081 | } | 1085 | } |
1082 | } | 1086 | } |
1083 | 1087 | ||
1084 | /* find the available acpiset as described in the DSDT */ | 1088 | /* find the available acpiset as described in the DSDT */ |
1085 | for (; item->acpiset && *item->acpiset; ++item->acpiset) { | 1089 | for (; item->acpiset && *item->acpiset; ++item->acpiset) { |
1086 | if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, | 1090 | if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, |
1087 | *item->acpiset, | 1091 | *item->acpiset, |
1088 | &handle))) { | 1092 | &handle))) { |
1089 | dprintk("Found %s setter: %s\n", | 1093 | dprintk("Found %s setter: %s\n", |
1090 | item->name, *item->acpiset); | 1094 | item->name, *item->acpiset); |
1091 | item->devattr.attr.mode |= S_IWUSR; | 1095 | item->devattr.attr.mode |= S_IWUSR; |
1092 | break; | 1096 | break; |
1093 | } | 1097 | } |
1094 | } | 1098 | } |
1095 | 1099 | ||
1096 | if (item->devattr.attr.mode != 0) { | 1100 | if (item->devattr.attr.mode != 0) { |
1097 | result = | 1101 | result = |
1098 | device_create_file(&sony_pf_device->dev, | 1102 | device_create_file(&sony_pf_device->dev, |
1099 | &item->devattr); | 1103 | &item->devattr); |
1100 | if (result) | 1104 | if (result) |
1101 | goto out_sysfs; | 1105 | goto out_sysfs; |
1102 | } | 1106 | } |
1103 | } | 1107 | } |
1104 | 1108 | ||
1105 | return 0; | 1109 | return 0; |
1106 | 1110 | ||
1107 | out_sysfs: | 1111 | out_sysfs: |
1108 | for (item = sony_nc_values; item->name; ++item) { | 1112 | for (item = sony_nc_values; item->name; ++item) { |
1109 | device_remove_file(&sony_pf_device->dev, &item->devattr); | 1113 | device_remove_file(&sony_pf_device->dev, &item->devattr); |
1110 | } | 1114 | } |
1111 | sony_pf_remove(); | 1115 | sony_pf_remove(); |
1112 | 1116 | ||
1113 | outbacklight: | 1117 | outbacklight: |
1114 | if (sony_backlight_device) | 1118 | if (sony_backlight_device) |
1115 | backlight_device_unregister(sony_backlight_device); | 1119 | backlight_device_unregister(sony_backlight_device); |
1116 | 1120 | ||
1117 | status = acpi_remove_notify_handler(sony_nc_acpi_handle, | 1121 | status = acpi_remove_notify_handler(sony_nc_acpi_handle, |
1118 | ACPI_DEVICE_NOTIFY, | 1122 | ACPI_DEVICE_NOTIFY, |
1119 | sony_acpi_notify); | 1123 | sony_acpi_notify); |
1120 | if (ACPI_FAILURE(status)) | 1124 | if (ACPI_FAILURE(status)) |
1121 | printk(KERN_WARNING DRV_PFX "unable to remove notify handler\n"); | 1125 | printk(KERN_WARNING DRV_PFX "unable to remove notify handler\n"); |
1122 | 1126 | ||
1123 | outinput: | 1127 | outinput: |
1124 | sony_laptop_remove_input(); | 1128 | sony_laptop_remove_input(); |
1125 | 1129 | ||
1126 | outwalk: | 1130 | outwalk: |
1127 | return result; | 1131 | return result; |
1128 | } | 1132 | } |
1129 | 1133 | ||
1130 | static int sony_nc_remove(struct acpi_device *device, int type) | 1134 | static int sony_nc_remove(struct acpi_device *device, int type) |
1131 | { | 1135 | { |
1132 | acpi_status status; | 1136 | acpi_status status; |
1133 | struct sony_nc_value *item; | 1137 | struct sony_nc_value *item; |
1134 | 1138 | ||
1135 | if (sony_backlight_device) | 1139 | if (sony_backlight_device) |
1136 | backlight_device_unregister(sony_backlight_device); | 1140 | backlight_device_unregister(sony_backlight_device); |
1137 | 1141 | ||
1138 | sony_nc_acpi_device = NULL; | 1142 | sony_nc_acpi_device = NULL; |
1139 | 1143 | ||
1140 | status = acpi_remove_notify_handler(sony_nc_acpi_handle, | 1144 | status = acpi_remove_notify_handler(sony_nc_acpi_handle, |
1141 | ACPI_DEVICE_NOTIFY, | 1145 | ACPI_DEVICE_NOTIFY, |
1142 | sony_acpi_notify); | 1146 | sony_acpi_notify); |
1143 | if (ACPI_FAILURE(status)) | 1147 | if (ACPI_FAILURE(status)) |
1144 | printk(KERN_WARNING DRV_PFX "unable to remove notify handler\n"); | 1148 | printk(KERN_WARNING DRV_PFX "unable to remove notify handler\n"); |
1145 | 1149 | ||
1146 | for (item = sony_nc_values; item->name; ++item) { | 1150 | for (item = sony_nc_values; item->name; ++item) { |
1147 | device_remove_file(&sony_pf_device->dev, &item->devattr); | 1151 | device_remove_file(&sony_pf_device->dev, &item->devattr); |
1148 | } | 1152 | } |
1149 | 1153 | ||
1150 | sony_pf_remove(); | 1154 | sony_pf_remove(); |
1151 | sony_laptop_remove_input(); | 1155 | sony_laptop_remove_input(); |
1152 | dprintk(SONY_NC_DRIVER_NAME " removed.\n"); | 1156 | dprintk(SONY_NC_DRIVER_NAME " removed.\n"); |
1153 | 1157 | ||
1154 | return 0; | 1158 | return 0; |
1155 | } | 1159 | } |
1156 | 1160 | ||
1157 | static const struct acpi_device_id sony_device_ids[] = { | 1161 | static const struct acpi_device_id sony_device_ids[] = { |
1158 | {SONY_NC_HID, 0}, | 1162 | {SONY_NC_HID, 0}, |
1159 | {SONY_PIC_HID, 0}, | 1163 | {SONY_PIC_HID, 0}, |
1160 | {"", 0}, | 1164 | {"", 0}, |
1161 | }; | 1165 | }; |
1162 | MODULE_DEVICE_TABLE(acpi, sony_device_ids); | 1166 | MODULE_DEVICE_TABLE(acpi, sony_device_ids); |
1163 | 1167 | ||
1164 | static const struct acpi_device_id sony_nc_device_ids[] = { | 1168 | static const struct acpi_device_id sony_nc_device_ids[] = { |
1165 | {SONY_NC_HID, 0}, | 1169 | {SONY_NC_HID, 0}, |
1166 | {"", 0}, | 1170 | {"", 0}, |
1167 | }; | 1171 | }; |
1168 | 1172 | ||
1169 | static struct acpi_driver sony_nc_driver = { | 1173 | static struct acpi_driver sony_nc_driver = { |
1170 | .name = SONY_NC_DRIVER_NAME, | 1174 | .name = SONY_NC_DRIVER_NAME, |
1171 | .class = SONY_NC_CLASS, | 1175 | .class = SONY_NC_CLASS, |
1172 | .ids = sony_nc_device_ids, | 1176 | .ids = sony_nc_device_ids, |
1173 | .owner = THIS_MODULE, | 1177 | .owner = THIS_MODULE, |
1174 | .ops = { | 1178 | .ops = { |
1175 | .add = sony_nc_add, | 1179 | .add = sony_nc_add, |
1176 | .remove = sony_nc_remove, | 1180 | .remove = sony_nc_remove, |
1177 | .resume = sony_nc_resume, | 1181 | .resume = sony_nc_resume, |
1178 | }, | 1182 | }, |
1179 | }; | 1183 | }; |
1180 | 1184 | ||
1181 | /*********** SPIC (SNY6001) Device ***********/ | 1185 | /*********** SPIC (SNY6001) Device ***********/ |
1182 | 1186 | ||
1183 | #define SONYPI_DEVICE_TYPE1 0x00000001 | 1187 | #define SONYPI_DEVICE_TYPE1 0x00000001 |
1184 | #define SONYPI_DEVICE_TYPE2 0x00000002 | 1188 | #define SONYPI_DEVICE_TYPE2 0x00000002 |
1185 | #define SONYPI_DEVICE_TYPE3 0x00000004 | 1189 | #define SONYPI_DEVICE_TYPE3 0x00000004 |
1186 | #define SONYPI_DEVICE_TYPE4 0x00000008 | 1190 | #define SONYPI_DEVICE_TYPE4 0x00000008 |
1187 | 1191 | ||
1188 | #define SONYPI_TYPE1_OFFSET 0x04 | 1192 | #define SONYPI_TYPE1_OFFSET 0x04 |
1189 | #define SONYPI_TYPE2_OFFSET 0x12 | 1193 | #define SONYPI_TYPE2_OFFSET 0x12 |
1190 | #define SONYPI_TYPE3_OFFSET 0x12 | 1194 | #define SONYPI_TYPE3_OFFSET 0x12 |
1191 | #define SONYPI_TYPE4_OFFSET 0x12 | 1195 | #define SONYPI_TYPE4_OFFSET 0x12 |
1192 | 1196 | ||
1193 | struct sony_pic_ioport { | 1197 | struct sony_pic_ioport { |
1194 | struct acpi_resource_io io1; | 1198 | struct acpi_resource_io io1; |
1195 | struct acpi_resource_io io2; | 1199 | struct acpi_resource_io io2; |
1196 | struct list_head list; | 1200 | struct list_head list; |
1197 | }; | 1201 | }; |
1198 | 1202 | ||
1199 | struct sony_pic_irq { | 1203 | struct sony_pic_irq { |
1200 | struct acpi_resource_irq irq; | 1204 | struct acpi_resource_irq irq; |
1201 | struct list_head list; | 1205 | struct list_head list; |
1202 | }; | 1206 | }; |
1203 | 1207 | ||
1204 | struct sonypi_eventtypes { | 1208 | struct sonypi_eventtypes { |
1205 | u8 data; | 1209 | u8 data; |
1206 | unsigned long mask; | 1210 | unsigned long mask; |
1207 | struct sonypi_event *events; | 1211 | struct sonypi_event *events; |
1208 | }; | 1212 | }; |
1209 | 1213 | ||
1210 | struct device_ctrl { | 1214 | struct device_ctrl { |
1211 | int model; | 1215 | int model; |
1212 | int (*handle_irq)(const u8, const u8); | 1216 | int (*handle_irq)(const u8, const u8); |
1213 | u16 evport_offset; | 1217 | u16 evport_offset; |
1214 | u8 has_camera; | 1218 | u8 has_camera; |
1215 | u8 has_bluetooth; | 1219 | u8 has_bluetooth; |
1216 | u8 has_wwan; | 1220 | u8 has_wwan; |
1217 | struct sonypi_eventtypes *event_types; | 1221 | struct sonypi_eventtypes *event_types; |
1218 | }; | 1222 | }; |
1219 | 1223 | ||
1220 | struct sony_pic_dev { | 1224 | struct sony_pic_dev { |
1221 | struct device_ctrl *control; | 1225 | struct device_ctrl *control; |
1222 | struct acpi_device *acpi_dev; | 1226 | struct acpi_device *acpi_dev; |
1223 | struct sony_pic_irq *cur_irq; | 1227 | struct sony_pic_irq *cur_irq; |
1224 | struct sony_pic_ioport *cur_ioport; | 1228 | struct sony_pic_ioport *cur_ioport; |
1225 | struct list_head interrupts; | 1229 | struct list_head interrupts; |
1226 | struct list_head ioports; | 1230 | struct list_head ioports; |
1227 | struct mutex lock; | 1231 | struct mutex lock; |
1228 | u8 camera_power; | 1232 | u8 camera_power; |
1229 | u8 bluetooth_power; | 1233 | u8 bluetooth_power; |
1230 | u8 wwan_power; | 1234 | u8 wwan_power; |
1231 | }; | 1235 | }; |
1232 | 1236 | ||
1233 | static struct sony_pic_dev spic_dev = { | 1237 | static struct sony_pic_dev spic_dev = { |
1234 | .interrupts = LIST_HEAD_INIT(spic_dev.interrupts), | 1238 | .interrupts = LIST_HEAD_INIT(spic_dev.interrupts), |
1235 | .ioports = LIST_HEAD_INIT(spic_dev.ioports), | 1239 | .ioports = LIST_HEAD_INIT(spic_dev.ioports), |
1236 | }; | 1240 | }; |
1237 | 1241 | ||
1238 | /* Event masks */ | 1242 | /* Event masks */ |
1239 | #define SONYPI_JOGGER_MASK 0x00000001 | 1243 | #define SONYPI_JOGGER_MASK 0x00000001 |
1240 | #define SONYPI_CAPTURE_MASK 0x00000002 | 1244 | #define SONYPI_CAPTURE_MASK 0x00000002 |
1241 | #define SONYPI_FNKEY_MASK 0x00000004 | 1245 | #define SONYPI_FNKEY_MASK 0x00000004 |
1242 | #define SONYPI_BLUETOOTH_MASK 0x00000008 | 1246 | #define SONYPI_BLUETOOTH_MASK 0x00000008 |
1243 | #define SONYPI_PKEY_MASK 0x00000010 | 1247 | #define SONYPI_PKEY_MASK 0x00000010 |
1244 | #define SONYPI_BACK_MASK 0x00000020 | 1248 | #define SONYPI_BACK_MASK 0x00000020 |
1245 | #define SONYPI_HELP_MASK 0x00000040 | 1249 | #define SONYPI_HELP_MASK 0x00000040 |
1246 | #define SONYPI_LID_MASK 0x00000080 | 1250 | #define SONYPI_LID_MASK 0x00000080 |
1247 | #define SONYPI_ZOOM_MASK 0x00000100 | 1251 | #define SONYPI_ZOOM_MASK 0x00000100 |
1248 | #define SONYPI_THUMBPHRASE_MASK 0x00000200 | 1252 | #define SONYPI_THUMBPHRASE_MASK 0x00000200 |
1249 | #define SONYPI_MEYE_MASK 0x00000400 | 1253 | #define SONYPI_MEYE_MASK 0x00000400 |
1250 | #define SONYPI_MEMORYSTICK_MASK 0x00000800 | 1254 | #define SONYPI_MEMORYSTICK_MASK 0x00000800 |
1251 | #define SONYPI_BATTERY_MASK 0x00001000 | 1255 | #define SONYPI_BATTERY_MASK 0x00001000 |
1252 | #define SONYPI_WIRELESS_MASK 0x00002000 | 1256 | #define SONYPI_WIRELESS_MASK 0x00002000 |
1253 | 1257 | ||
1254 | struct sonypi_event { | 1258 | struct sonypi_event { |
1255 | u8 data; | 1259 | u8 data; |
1256 | u8 event; | 1260 | u8 event; |
1257 | }; | 1261 | }; |
1258 | 1262 | ||
1259 | /* The set of possible button release events */ | 1263 | /* The set of possible button release events */ |
1260 | static struct sonypi_event sonypi_releaseev[] = { | 1264 | static struct sonypi_event sonypi_releaseev[] = { |
1261 | { 0x00, SONYPI_EVENT_ANYBUTTON_RELEASED }, | 1265 | { 0x00, SONYPI_EVENT_ANYBUTTON_RELEASED }, |
1262 | { 0, 0 } | 1266 | { 0, 0 } |
1263 | }; | 1267 | }; |
1264 | 1268 | ||
1265 | /* The set of possible jogger events */ | 1269 | /* The set of possible jogger events */ |
1266 | static struct sonypi_event sonypi_joggerev[] = { | 1270 | static struct sonypi_event sonypi_joggerev[] = { |
1267 | { 0x1f, SONYPI_EVENT_JOGDIAL_UP }, | 1271 | { 0x1f, SONYPI_EVENT_JOGDIAL_UP }, |
1268 | { 0x01, SONYPI_EVENT_JOGDIAL_DOWN }, | 1272 | { 0x01, SONYPI_EVENT_JOGDIAL_DOWN }, |
1269 | { 0x5f, SONYPI_EVENT_JOGDIAL_UP_PRESSED }, | 1273 | { 0x5f, SONYPI_EVENT_JOGDIAL_UP_PRESSED }, |
1270 | { 0x41, SONYPI_EVENT_JOGDIAL_DOWN_PRESSED }, | 1274 | { 0x41, SONYPI_EVENT_JOGDIAL_DOWN_PRESSED }, |
1271 | { 0x1e, SONYPI_EVENT_JOGDIAL_FAST_UP }, | 1275 | { 0x1e, SONYPI_EVENT_JOGDIAL_FAST_UP }, |
1272 | { 0x02, SONYPI_EVENT_JOGDIAL_FAST_DOWN }, | 1276 | { 0x02, SONYPI_EVENT_JOGDIAL_FAST_DOWN }, |
1273 | { 0x5e, SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED }, | 1277 | { 0x5e, SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED }, |
1274 | { 0x42, SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED }, | 1278 | { 0x42, SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED }, |
1275 | { 0x1d, SONYPI_EVENT_JOGDIAL_VFAST_UP }, | 1279 | { 0x1d, SONYPI_EVENT_JOGDIAL_VFAST_UP }, |
1276 | { 0x03, SONYPI_EVENT_JOGDIAL_VFAST_DOWN }, | 1280 | { 0x03, SONYPI_EVENT_JOGDIAL_VFAST_DOWN }, |
1277 | { 0x5d, SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED }, | 1281 | { 0x5d, SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED }, |
1278 | { 0x43, SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED }, | 1282 | { 0x43, SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED }, |
1279 | { 0x40, SONYPI_EVENT_JOGDIAL_PRESSED }, | 1283 | { 0x40, SONYPI_EVENT_JOGDIAL_PRESSED }, |
1280 | { 0, 0 } | 1284 | { 0, 0 } |
1281 | }; | 1285 | }; |
1282 | 1286 | ||
1283 | /* The set of possible capture button events */ | 1287 | /* The set of possible capture button events */ |
1284 | static struct sonypi_event sonypi_captureev[] = { | 1288 | static struct sonypi_event sonypi_captureev[] = { |
1285 | { 0x05, SONYPI_EVENT_CAPTURE_PARTIALPRESSED }, | 1289 | { 0x05, SONYPI_EVENT_CAPTURE_PARTIALPRESSED }, |
1286 | { 0x07, SONYPI_EVENT_CAPTURE_PRESSED }, | 1290 | { 0x07, SONYPI_EVENT_CAPTURE_PRESSED }, |
1287 | { 0x40, SONYPI_EVENT_CAPTURE_PRESSED }, | 1291 | { 0x40, SONYPI_EVENT_CAPTURE_PRESSED }, |
1288 | { 0x01, SONYPI_EVENT_CAPTURE_PARTIALRELEASED }, | 1292 | { 0x01, SONYPI_EVENT_CAPTURE_PARTIALRELEASED }, |
1289 | { 0, 0 } | 1293 | { 0, 0 } |
1290 | }; | 1294 | }; |
1291 | 1295 | ||
1292 | /* The set of possible fnkeys events */ | 1296 | /* The set of possible fnkeys events */ |
1293 | static struct sonypi_event sonypi_fnkeyev[] = { | 1297 | static struct sonypi_event sonypi_fnkeyev[] = { |
1294 | { 0x10, SONYPI_EVENT_FNKEY_ESC }, | 1298 | { 0x10, SONYPI_EVENT_FNKEY_ESC }, |
1295 | { 0x11, SONYPI_EVENT_FNKEY_F1 }, | 1299 | { 0x11, SONYPI_EVENT_FNKEY_F1 }, |
1296 | { 0x12, SONYPI_EVENT_FNKEY_F2 }, | 1300 | { 0x12, SONYPI_EVENT_FNKEY_F2 }, |
1297 | { 0x13, SONYPI_EVENT_FNKEY_F3 }, | 1301 | { 0x13, SONYPI_EVENT_FNKEY_F3 }, |
1298 | { 0x14, SONYPI_EVENT_FNKEY_F4 }, | 1302 | { 0x14, SONYPI_EVENT_FNKEY_F4 }, |
1299 | { 0x15, SONYPI_EVENT_FNKEY_F5 }, | 1303 | { 0x15, SONYPI_EVENT_FNKEY_F5 }, |
1300 | { 0x16, SONYPI_EVENT_FNKEY_F6 }, | 1304 | { 0x16, SONYPI_EVENT_FNKEY_F6 }, |
1301 | { 0x17, SONYPI_EVENT_FNKEY_F7 }, | 1305 | { 0x17, SONYPI_EVENT_FNKEY_F7 }, |
1302 | { 0x18, SONYPI_EVENT_FNKEY_F8 }, | 1306 | { 0x18, SONYPI_EVENT_FNKEY_F8 }, |
1303 | { 0x19, SONYPI_EVENT_FNKEY_F9 }, | 1307 | { 0x19, SONYPI_EVENT_FNKEY_F9 }, |
1304 | { 0x1a, SONYPI_EVENT_FNKEY_F10 }, | 1308 | { 0x1a, SONYPI_EVENT_FNKEY_F10 }, |
1305 | { 0x1b, SONYPI_EVENT_FNKEY_F11 }, | 1309 | { 0x1b, SONYPI_EVENT_FNKEY_F11 }, |
1306 | { 0x1c, SONYPI_EVENT_FNKEY_F12 }, | 1310 | { 0x1c, SONYPI_EVENT_FNKEY_F12 }, |
1307 | { 0x1f, SONYPI_EVENT_FNKEY_RELEASED }, | 1311 | { 0x1f, SONYPI_EVENT_FNKEY_RELEASED }, |
1308 | { 0x21, SONYPI_EVENT_FNKEY_1 }, | 1312 | { 0x21, SONYPI_EVENT_FNKEY_1 }, |
1309 | { 0x22, SONYPI_EVENT_FNKEY_2 }, | 1313 | { 0x22, SONYPI_EVENT_FNKEY_2 }, |
1310 | { 0x31, SONYPI_EVENT_FNKEY_D }, | 1314 | { 0x31, SONYPI_EVENT_FNKEY_D }, |
1311 | { 0x32, SONYPI_EVENT_FNKEY_E }, | 1315 | { 0x32, SONYPI_EVENT_FNKEY_E }, |
1312 | { 0x33, SONYPI_EVENT_FNKEY_F }, | 1316 | { 0x33, SONYPI_EVENT_FNKEY_F }, |
1313 | { 0x34, SONYPI_EVENT_FNKEY_S }, | 1317 | { 0x34, SONYPI_EVENT_FNKEY_S }, |
1314 | { 0x35, SONYPI_EVENT_FNKEY_B }, | 1318 | { 0x35, SONYPI_EVENT_FNKEY_B }, |
1315 | { 0x36, SONYPI_EVENT_FNKEY_ONLY }, | 1319 | { 0x36, SONYPI_EVENT_FNKEY_ONLY }, |
1316 | { 0, 0 } | 1320 | { 0, 0 } |
1317 | }; | 1321 | }; |
1318 | 1322 | ||
1319 | /* The set of possible program key events */ | 1323 | /* The set of possible program key events */ |
1320 | static struct sonypi_event sonypi_pkeyev[] = { | 1324 | static struct sonypi_event sonypi_pkeyev[] = { |
1321 | { 0x01, SONYPI_EVENT_PKEY_P1 }, | 1325 | { 0x01, SONYPI_EVENT_PKEY_P1 }, |
1322 | { 0x02, SONYPI_EVENT_PKEY_P2 }, | 1326 | { 0x02, SONYPI_EVENT_PKEY_P2 }, |
1323 | { 0x04, SONYPI_EVENT_PKEY_P3 }, | 1327 | { 0x04, SONYPI_EVENT_PKEY_P3 }, |
1324 | { 0, 0 } | 1328 | { 0, 0 } |
1325 | }; | 1329 | }; |
1326 | 1330 | ||
1327 | /* The set of possible bluetooth events */ | 1331 | /* The set of possible bluetooth events */ |
1328 | static struct sonypi_event sonypi_blueev[] = { | 1332 | static struct sonypi_event sonypi_blueev[] = { |
1329 | { 0x55, SONYPI_EVENT_BLUETOOTH_PRESSED }, | 1333 | { 0x55, SONYPI_EVENT_BLUETOOTH_PRESSED }, |
1330 | { 0x59, SONYPI_EVENT_BLUETOOTH_ON }, | 1334 | { 0x59, SONYPI_EVENT_BLUETOOTH_ON }, |
1331 | { 0x5a, SONYPI_EVENT_BLUETOOTH_OFF }, | 1335 | { 0x5a, SONYPI_EVENT_BLUETOOTH_OFF }, |
1332 | { 0, 0 } | 1336 | { 0, 0 } |
1333 | }; | 1337 | }; |
1334 | 1338 | ||
1335 | /* The set of possible wireless events */ | 1339 | /* The set of possible wireless events */ |
1336 | static struct sonypi_event sonypi_wlessev[] = { | 1340 | static struct sonypi_event sonypi_wlessev[] = { |
1337 | { 0x59, SONYPI_EVENT_WIRELESS_ON }, | 1341 | { 0x59, SONYPI_EVENT_WIRELESS_ON }, |
1338 | { 0x5a, SONYPI_EVENT_WIRELESS_OFF }, | 1342 | { 0x5a, SONYPI_EVENT_WIRELESS_OFF }, |
1339 | { 0, 0 } | 1343 | { 0, 0 } |
1340 | }; | 1344 | }; |
1341 | 1345 | ||
1342 | /* The set of possible back button events */ | 1346 | /* The set of possible back button events */ |
1343 | static struct sonypi_event sonypi_backev[] = { | 1347 | static struct sonypi_event sonypi_backev[] = { |
1344 | { 0x20, SONYPI_EVENT_BACK_PRESSED }, | 1348 | { 0x20, SONYPI_EVENT_BACK_PRESSED }, |
1345 | { 0, 0 } | 1349 | { 0, 0 } |
1346 | }; | 1350 | }; |
1347 | 1351 | ||
1348 | /* The set of possible help button events */ | 1352 | /* The set of possible help button events */ |
1349 | static struct sonypi_event sonypi_helpev[] = { | 1353 | static struct sonypi_event sonypi_helpev[] = { |
1350 | { 0x3b, SONYPI_EVENT_HELP_PRESSED }, | 1354 | { 0x3b, SONYPI_EVENT_HELP_PRESSED }, |
1351 | { 0, 0 } | 1355 | { 0, 0 } |
1352 | }; | 1356 | }; |
1353 | 1357 | ||
1354 | 1358 | ||
1355 | /* The set of possible lid events */ | 1359 | /* The set of possible lid events */ |
1356 | static struct sonypi_event sonypi_lidev[] = { | 1360 | static struct sonypi_event sonypi_lidev[] = { |
1357 | { 0x51, SONYPI_EVENT_LID_CLOSED }, | 1361 | { 0x51, SONYPI_EVENT_LID_CLOSED }, |
1358 | { 0x50, SONYPI_EVENT_LID_OPENED }, | 1362 | { 0x50, SONYPI_EVENT_LID_OPENED }, |
1359 | { 0, 0 } | 1363 | { 0, 0 } |
1360 | }; | 1364 | }; |
1361 | 1365 | ||
1362 | /* The set of possible zoom events */ | 1366 | /* The set of possible zoom events */ |
1363 | static struct sonypi_event sonypi_zoomev[] = { | 1367 | static struct sonypi_event sonypi_zoomev[] = { |
1364 | { 0x39, SONYPI_EVENT_ZOOM_PRESSED }, | 1368 | { 0x39, SONYPI_EVENT_ZOOM_PRESSED }, |
1365 | { 0x10, SONYPI_EVENT_ZOOM_IN_PRESSED }, | 1369 | { 0x10, SONYPI_EVENT_ZOOM_IN_PRESSED }, |
1366 | { 0x20, SONYPI_EVENT_ZOOM_OUT_PRESSED }, | 1370 | { 0x20, SONYPI_EVENT_ZOOM_OUT_PRESSED }, |
1367 | { 0, 0 } | 1371 | { 0, 0 } |
1368 | }; | 1372 | }; |
1369 | 1373 | ||
1370 | /* The set of possible thumbphrase events */ | 1374 | /* The set of possible thumbphrase events */ |
1371 | static struct sonypi_event sonypi_thumbphraseev[] = { | 1375 | static struct sonypi_event sonypi_thumbphraseev[] = { |
1372 | { 0x3a, SONYPI_EVENT_THUMBPHRASE_PRESSED }, | 1376 | { 0x3a, SONYPI_EVENT_THUMBPHRASE_PRESSED }, |
1373 | { 0, 0 } | 1377 | { 0, 0 } |
1374 | }; | 1378 | }; |
1375 | 1379 | ||
1376 | /* The set of possible motioneye camera events */ | 1380 | /* The set of possible motioneye camera events */ |
1377 | static struct sonypi_event sonypi_meyeev[] = { | 1381 | static struct sonypi_event sonypi_meyeev[] = { |
1378 | { 0x00, SONYPI_EVENT_MEYE_FACE }, | 1382 | { 0x00, SONYPI_EVENT_MEYE_FACE }, |
1379 | { 0x01, SONYPI_EVENT_MEYE_OPPOSITE }, | 1383 | { 0x01, SONYPI_EVENT_MEYE_OPPOSITE }, |
1380 | { 0, 0 } | 1384 | { 0, 0 } |
1381 | }; | 1385 | }; |
1382 | 1386 | ||
1383 | /* The set of possible memorystick events */ | 1387 | /* The set of possible memorystick events */ |
1384 | static struct sonypi_event sonypi_memorystickev[] = { | 1388 | static struct sonypi_event sonypi_memorystickev[] = { |
1385 | { 0x53, SONYPI_EVENT_MEMORYSTICK_INSERT }, | 1389 | { 0x53, SONYPI_EVENT_MEMORYSTICK_INSERT }, |
1386 | { 0x54, SONYPI_EVENT_MEMORYSTICK_EJECT }, | 1390 | { 0x54, SONYPI_EVENT_MEMORYSTICK_EJECT }, |
1387 | { 0, 0 } | 1391 | { 0, 0 } |
1388 | }; | 1392 | }; |
1389 | 1393 | ||
1390 | /* The set of possible battery events */ | 1394 | /* The set of possible battery events */ |
1391 | static struct sonypi_event sonypi_batteryev[] = { | 1395 | static struct sonypi_event sonypi_batteryev[] = { |
1392 | { 0x20, SONYPI_EVENT_BATTERY_INSERT }, | 1396 | { 0x20, SONYPI_EVENT_BATTERY_INSERT }, |
1393 | { 0x30, SONYPI_EVENT_BATTERY_REMOVE }, | 1397 | { 0x30, SONYPI_EVENT_BATTERY_REMOVE }, |
1394 | { 0, 0 } | 1398 | { 0, 0 } |
1395 | }; | 1399 | }; |
1396 | 1400 | ||
1397 | static struct sonypi_eventtypes type1_events[] = { | 1401 | static struct sonypi_eventtypes type1_events[] = { |
1398 | { 0, 0xffffffff, sonypi_releaseev }, | 1402 | { 0, 0xffffffff, sonypi_releaseev }, |
1399 | { 0x70, SONYPI_MEYE_MASK, sonypi_meyeev }, | 1403 | { 0x70, SONYPI_MEYE_MASK, sonypi_meyeev }, |
1400 | { 0x30, SONYPI_LID_MASK, sonypi_lidev }, | 1404 | { 0x30, SONYPI_LID_MASK, sonypi_lidev }, |
1401 | { 0x60, SONYPI_CAPTURE_MASK, sonypi_captureev }, | 1405 | { 0x60, SONYPI_CAPTURE_MASK, sonypi_captureev }, |
1402 | { 0x10, SONYPI_JOGGER_MASK, sonypi_joggerev }, | 1406 | { 0x10, SONYPI_JOGGER_MASK, sonypi_joggerev }, |
1403 | { 0x20, SONYPI_FNKEY_MASK, sonypi_fnkeyev }, | 1407 | { 0x20, SONYPI_FNKEY_MASK, sonypi_fnkeyev }, |
1404 | { 0x30, SONYPI_BLUETOOTH_MASK, sonypi_blueev }, | 1408 | { 0x30, SONYPI_BLUETOOTH_MASK, sonypi_blueev }, |
1405 | { 0x40, SONYPI_PKEY_MASK, sonypi_pkeyev }, | 1409 | { 0x40, SONYPI_PKEY_MASK, sonypi_pkeyev }, |
1406 | { 0x30, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev }, | 1410 | { 0x30, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev }, |
1407 | { 0x40, SONYPI_BATTERY_MASK, sonypi_batteryev }, | 1411 | { 0x40, SONYPI_BATTERY_MASK, sonypi_batteryev }, |
1408 | { 0 }, | 1412 | { 0 }, |
1409 | }; | 1413 | }; |
1410 | static struct sonypi_eventtypes type2_events[] = { | 1414 | static struct sonypi_eventtypes type2_events[] = { |
1411 | { 0, 0xffffffff, sonypi_releaseev }, | 1415 | { 0, 0xffffffff, sonypi_releaseev }, |
1412 | { 0x38, SONYPI_LID_MASK, sonypi_lidev }, | 1416 | { 0x38, SONYPI_LID_MASK, sonypi_lidev }, |
1413 | { 0x11, SONYPI_JOGGER_MASK, sonypi_joggerev }, | 1417 | { 0x11, SONYPI_JOGGER_MASK, sonypi_joggerev }, |
1414 | { 0x61, SONYPI_CAPTURE_MASK, sonypi_captureev }, | 1418 | { 0x61, SONYPI_CAPTURE_MASK, sonypi_captureev }, |
1415 | { 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev }, | 1419 | { 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev }, |
1416 | { 0x31, SONYPI_BLUETOOTH_MASK, sonypi_blueev }, | 1420 | { 0x31, SONYPI_BLUETOOTH_MASK, sonypi_blueev }, |
1417 | { 0x08, SONYPI_PKEY_MASK, sonypi_pkeyev }, | 1421 | { 0x08, SONYPI_PKEY_MASK, sonypi_pkeyev }, |
1418 | { 0x11, SONYPI_BACK_MASK, sonypi_backev }, | 1422 | { 0x11, SONYPI_BACK_MASK, sonypi_backev }, |
1419 | { 0x21, SONYPI_HELP_MASK, sonypi_helpev }, | 1423 | { 0x21, SONYPI_HELP_MASK, sonypi_helpev }, |
1420 | { 0x21, SONYPI_ZOOM_MASK, sonypi_zoomev }, | 1424 | { 0x21, SONYPI_ZOOM_MASK, sonypi_zoomev }, |
1421 | { 0x20, SONYPI_THUMBPHRASE_MASK, sonypi_thumbphraseev }, | 1425 | { 0x20, SONYPI_THUMBPHRASE_MASK, sonypi_thumbphraseev }, |
1422 | { 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev }, | 1426 | { 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev }, |
1423 | { 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev }, | 1427 | { 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev }, |
1424 | { 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev }, | 1428 | { 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev }, |
1425 | { 0 }, | 1429 | { 0 }, |
1426 | }; | 1430 | }; |
1427 | static struct sonypi_eventtypes type3_events[] = { | 1431 | static struct sonypi_eventtypes type3_events[] = { |
1428 | { 0, 0xffffffff, sonypi_releaseev }, | 1432 | { 0, 0xffffffff, sonypi_releaseev }, |
1429 | { 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev }, | 1433 | { 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev }, |
1430 | { 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev }, | 1434 | { 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev }, |
1431 | { 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev }, | 1435 | { 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev }, |
1432 | { 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev }, | 1436 | { 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev }, |
1433 | { 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev }, | 1437 | { 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev }, |
1434 | { 0 }, | 1438 | { 0 }, |
1435 | }; | 1439 | }; |
1436 | static struct sonypi_eventtypes type4_events[] = { | 1440 | static struct sonypi_eventtypes type4_events[] = { |
1437 | { 0, 0xffffffff, sonypi_releaseev }, | 1441 | { 0, 0xffffffff, sonypi_releaseev }, |
1438 | { 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev }, | 1442 | { 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev }, |
1439 | { 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev }, | 1443 | { 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev }, |
1440 | { 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev }, | 1444 | { 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev }, |
1441 | { 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev }, | 1445 | { 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev }, |
1442 | { 0x05, SONYPI_PKEY_MASK, sonypi_pkeyev }, | 1446 | { 0x05, SONYPI_PKEY_MASK, sonypi_pkeyev }, |
1443 | { 0x05, SONYPI_ZOOM_MASK, sonypi_zoomev }, | 1447 | { 0x05, SONYPI_ZOOM_MASK, sonypi_zoomev }, |
1444 | { 0x05, SONYPI_CAPTURE_MASK, sonypi_captureev }, | 1448 | { 0x05, SONYPI_CAPTURE_MASK, sonypi_captureev }, |
1445 | { 0 }, | 1449 | { 0 }, |
1446 | }; | 1450 | }; |
1447 | 1451 | ||
1448 | /* low level spic calls */ | 1452 | /* low level spic calls */ |
1449 | #define ITERATIONS_LONG 10000 | 1453 | #define ITERATIONS_LONG 10000 |
1450 | #define ITERATIONS_SHORT 10 | 1454 | #define ITERATIONS_SHORT 10 |
1451 | #define wait_on_command(command, iterations) { \ | 1455 | #define wait_on_command(command, iterations) { \ |
1452 | unsigned int n = iterations; \ | 1456 | unsigned int n = iterations; \ |
1453 | while (--n && (command)) \ | 1457 | while (--n && (command)) \ |
1454 | udelay(1); \ | 1458 | udelay(1); \ |
1455 | if (!n) \ | 1459 | if (!n) \ |
1456 | dprintk("command failed at %s : %s (line %d)\n", \ | 1460 | dprintk("command failed at %s : %s (line %d)\n", \ |
1457 | __FILE__, __func__, __LINE__); \ | 1461 | __FILE__, __func__, __LINE__); \ |
1458 | } | 1462 | } |
1459 | 1463 | ||
1460 | static u8 sony_pic_call1(u8 dev) | 1464 | static u8 sony_pic_call1(u8 dev) |
1461 | { | 1465 | { |
1462 | u8 v1, v2; | 1466 | u8 v1, v2; |
1463 | 1467 | ||
1464 | wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, | 1468 | wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, |
1465 | ITERATIONS_LONG); | 1469 | ITERATIONS_LONG); |
1466 | outb(dev, spic_dev.cur_ioport->io1.minimum + 4); | 1470 | outb(dev, spic_dev.cur_ioport->io1.minimum + 4); |
1467 | v1 = inb_p(spic_dev.cur_ioport->io1.minimum + 4); | 1471 | v1 = inb_p(spic_dev.cur_ioport->io1.minimum + 4); |
1468 | v2 = inb_p(spic_dev.cur_ioport->io1.minimum); | 1472 | v2 = inb_p(spic_dev.cur_ioport->io1.minimum); |
1469 | dprintk("sony_pic_call1(0x%.2x): 0x%.4x\n", dev, (v2 << 8) | v1); | 1473 | dprintk("sony_pic_call1(0x%.2x): 0x%.4x\n", dev, (v2 << 8) | v1); |
1470 | return v2; | 1474 | return v2; |
1471 | } | 1475 | } |
1472 | 1476 | ||
1473 | static u8 sony_pic_call2(u8 dev, u8 fn) | 1477 | static u8 sony_pic_call2(u8 dev, u8 fn) |
1474 | { | 1478 | { |
1475 | u8 v1; | 1479 | u8 v1; |
1476 | 1480 | ||
1477 | wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, | 1481 | wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, |
1478 | ITERATIONS_LONG); | 1482 | ITERATIONS_LONG); |
1479 | outb(dev, spic_dev.cur_ioport->io1.minimum + 4); | 1483 | outb(dev, spic_dev.cur_ioport->io1.minimum + 4); |
1480 | wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, | 1484 | wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, |
1481 | ITERATIONS_LONG); | 1485 | ITERATIONS_LONG); |
1482 | outb(fn, spic_dev.cur_ioport->io1.minimum); | 1486 | outb(fn, spic_dev.cur_ioport->io1.minimum); |
1483 | v1 = inb_p(spic_dev.cur_ioport->io1.minimum); | 1487 | v1 = inb_p(spic_dev.cur_ioport->io1.minimum); |
1484 | dprintk("sony_pic_call2(0x%.2x - 0x%.2x): 0x%.4x\n", dev, fn, v1); | 1488 | dprintk("sony_pic_call2(0x%.2x - 0x%.2x): 0x%.4x\n", dev, fn, v1); |
1485 | return v1; | 1489 | return v1; |
1486 | } | 1490 | } |
1487 | 1491 | ||
1488 | static u8 sony_pic_call3(u8 dev, u8 fn, u8 v) | 1492 | static u8 sony_pic_call3(u8 dev, u8 fn, u8 v) |
1489 | { | 1493 | { |
1490 | u8 v1; | 1494 | u8 v1; |
1491 | 1495 | ||
1492 | wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG); | 1496 | wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG); |
1493 | outb(dev, spic_dev.cur_ioport->io1.minimum + 4); | 1497 | outb(dev, spic_dev.cur_ioport->io1.minimum + 4); |
1494 | wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG); | 1498 | wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG); |
1495 | outb(fn, spic_dev.cur_ioport->io1.minimum); | 1499 | outb(fn, spic_dev.cur_ioport->io1.minimum); |
1496 | wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG); | 1500 | wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG); |
1497 | outb(v, spic_dev.cur_ioport->io1.minimum); | 1501 | outb(v, spic_dev.cur_ioport->io1.minimum); |
1498 | v1 = inb_p(spic_dev.cur_ioport->io1.minimum); | 1502 | v1 = inb_p(spic_dev.cur_ioport->io1.minimum); |
1499 | dprintk("sony_pic_call3(0x%.2x - 0x%.2x - 0x%.2x): 0x%.4x\n", | 1503 | dprintk("sony_pic_call3(0x%.2x - 0x%.2x - 0x%.2x): 0x%.4x\n", |
1500 | dev, fn, v, v1); | 1504 | dev, fn, v, v1); |
1501 | return v1; | 1505 | return v1; |
1502 | } | 1506 | } |
1503 | 1507 | ||
1504 | /* | 1508 | /* |
1505 | * minidrivers for SPIC models | 1509 | * minidrivers for SPIC models |
1506 | */ | 1510 | */ |
1507 | static int type4_handle_irq(const u8 data_mask, const u8 ev) | 1511 | static int type4_handle_irq(const u8 data_mask, const u8 ev) |
1508 | { | 1512 | { |
1509 | /* | 1513 | /* |
1510 | * 0x31 could mean we have to take some extra action and wait for | 1514 | * 0x31 could mean we have to take some extra action and wait for |
1511 | * the next irq for some Type4 models, it will generate a new | 1515 | * the next irq for some Type4 models, it will generate a new |
1512 | * irq and we can read new data from the device: | 1516 | * irq and we can read new data from the device: |
1513 | * - 0x5c and 0x5f requires 0xA0 | 1517 | * - 0x5c and 0x5f requires 0xA0 |
1514 | * - 0x61 requires 0xB3 | 1518 | * - 0x61 requires 0xB3 |
1515 | */ | 1519 | */ |
1516 | if (data_mask == 0x31) { | 1520 | if (data_mask == 0x31) { |
1517 | if (ev == 0x5c || ev == 0x5f) | 1521 | if (ev == 0x5c || ev == 0x5f) |
1518 | sony_pic_call1(0xA0); | 1522 | sony_pic_call1(0xA0); |
1519 | else if (ev == 0x61) | 1523 | else if (ev == 0x61) |
1520 | sony_pic_call1(0xB3); | 1524 | sony_pic_call1(0xB3); |
1521 | return 0; | 1525 | return 0; |
1522 | } | 1526 | } |
1523 | return 1; | 1527 | return 1; |
1524 | } | 1528 | } |
1525 | 1529 | ||
1526 | static struct device_ctrl spic_types[] = { | 1530 | static struct device_ctrl spic_types[] = { |
1527 | { | 1531 | { |
1528 | .model = SONYPI_DEVICE_TYPE1, | 1532 | .model = SONYPI_DEVICE_TYPE1, |
1529 | .handle_irq = NULL, | 1533 | .handle_irq = NULL, |
1530 | .evport_offset = SONYPI_TYPE1_OFFSET, | 1534 | .evport_offset = SONYPI_TYPE1_OFFSET, |
1531 | .event_types = type1_events, | 1535 | .event_types = type1_events, |
1532 | }, | 1536 | }, |
1533 | { | 1537 | { |
1534 | .model = SONYPI_DEVICE_TYPE2, | 1538 | .model = SONYPI_DEVICE_TYPE2, |
1535 | .handle_irq = NULL, | 1539 | .handle_irq = NULL, |
1536 | .evport_offset = SONYPI_TYPE2_OFFSET, | 1540 | .evport_offset = SONYPI_TYPE2_OFFSET, |
1537 | .event_types = type2_events, | 1541 | .event_types = type2_events, |
1538 | }, | 1542 | }, |
1539 | { | 1543 | { |
1540 | .model = SONYPI_DEVICE_TYPE3, | 1544 | .model = SONYPI_DEVICE_TYPE3, |
1541 | .handle_irq = NULL, | 1545 | .handle_irq = NULL, |
1542 | .evport_offset = SONYPI_TYPE3_OFFSET, | 1546 | .evport_offset = SONYPI_TYPE3_OFFSET, |
1543 | .event_types = type3_events, | 1547 | .event_types = type3_events, |
1544 | }, | 1548 | }, |
1545 | { | 1549 | { |
1546 | .model = SONYPI_DEVICE_TYPE4, | 1550 | .model = SONYPI_DEVICE_TYPE4, |
1547 | .handle_irq = type4_handle_irq, | 1551 | .handle_irq = type4_handle_irq, |
1548 | .evport_offset = SONYPI_TYPE4_OFFSET, | 1552 | .evport_offset = SONYPI_TYPE4_OFFSET, |
1549 | .event_types = type4_events, | 1553 | .event_types = type4_events, |
1550 | }, | 1554 | }, |
1551 | }; | 1555 | }; |
1552 | 1556 | ||
1553 | static void sony_pic_detect_device_type(struct sony_pic_dev *dev) | 1557 | static void sony_pic_detect_device_type(struct sony_pic_dev *dev) |
1554 | { | 1558 | { |
1555 | struct pci_dev *pcidev; | 1559 | struct pci_dev *pcidev; |
1556 | 1560 | ||
1557 | pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, | 1561 | pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, |
1558 | PCI_DEVICE_ID_INTEL_82371AB_3, NULL); | 1562 | PCI_DEVICE_ID_INTEL_82371AB_3, NULL); |
1559 | if (pcidev) { | 1563 | if (pcidev) { |
1560 | dev->control = &spic_types[0]; | 1564 | dev->control = &spic_types[0]; |
1561 | goto out; | 1565 | goto out; |
1562 | } | 1566 | } |
1563 | 1567 | ||
1564 | pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, | 1568 | pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, |
1565 | PCI_DEVICE_ID_INTEL_ICH6_1, NULL); | 1569 | PCI_DEVICE_ID_INTEL_ICH6_1, NULL); |
1566 | if (pcidev) { | 1570 | if (pcidev) { |
1567 | dev->control = &spic_types[2]; | 1571 | dev->control = &spic_types[2]; |
1568 | goto out; | 1572 | goto out; |
1569 | } | 1573 | } |
1570 | 1574 | ||
1571 | pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, | 1575 | pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, |
1572 | PCI_DEVICE_ID_INTEL_ICH7_1, NULL); | 1576 | PCI_DEVICE_ID_INTEL_ICH7_1, NULL); |
1573 | if (pcidev) { | 1577 | if (pcidev) { |
1574 | dev->control = &spic_types[3]; | 1578 | dev->control = &spic_types[3]; |
1575 | goto out; | 1579 | goto out; |
1576 | } | 1580 | } |
1577 | 1581 | ||
1578 | pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, | 1582 | pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, |
1579 | PCI_DEVICE_ID_INTEL_ICH8_4, NULL); | 1583 | PCI_DEVICE_ID_INTEL_ICH8_4, NULL); |
1580 | if (pcidev) { | 1584 | if (pcidev) { |
1581 | dev->control = &spic_types[3]; | 1585 | dev->control = &spic_types[3]; |
1582 | goto out; | 1586 | goto out; |
1583 | } | 1587 | } |
1584 | 1588 | ||
1585 | /* default */ | 1589 | /* default */ |
1586 | dev->control = &spic_types[1]; | 1590 | dev->control = &spic_types[1]; |
1587 | 1591 | ||
1588 | out: | 1592 | out: |
1589 | if (pcidev) | 1593 | if (pcidev) |
1590 | pci_dev_put(pcidev); | 1594 | pci_dev_put(pcidev); |
1591 | 1595 | ||
1592 | printk(KERN_INFO DRV_PFX "detected Type%d model\n", | 1596 | printk(KERN_INFO DRV_PFX "detected Type%d model\n", |
1593 | dev->control->model == SONYPI_DEVICE_TYPE1 ? 1 : | 1597 | dev->control->model == SONYPI_DEVICE_TYPE1 ? 1 : |
1594 | dev->control->model == SONYPI_DEVICE_TYPE2 ? 2 : | 1598 | dev->control->model == SONYPI_DEVICE_TYPE2 ? 2 : |
1595 | dev->control->model == SONYPI_DEVICE_TYPE3 ? 3 : 4); | 1599 | dev->control->model == SONYPI_DEVICE_TYPE3 ? 3 : 4); |
1596 | } | 1600 | } |
1597 | 1601 | ||
1598 | /* camera tests and poweron/poweroff */ | 1602 | /* camera tests and poweron/poweroff */ |
1599 | #define SONYPI_CAMERA_PICTURE 5 | 1603 | #define SONYPI_CAMERA_PICTURE 5 |
1600 | #define SONYPI_CAMERA_CONTROL 0x10 | 1604 | #define SONYPI_CAMERA_CONTROL 0x10 |
1601 | 1605 | ||
1602 | #define SONYPI_CAMERA_BRIGHTNESS 0 | 1606 | #define SONYPI_CAMERA_BRIGHTNESS 0 |
1603 | #define SONYPI_CAMERA_CONTRAST 1 | 1607 | #define SONYPI_CAMERA_CONTRAST 1 |
1604 | #define SONYPI_CAMERA_HUE 2 | 1608 | #define SONYPI_CAMERA_HUE 2 |
1605 | #define SONYPI_CAMERA_COLOR 3 | 1609 | #define SONYPI_CAMERA_COLOR 3 |
1606 | #define SONYPI_CAMERA_SHARPNESS 4 | 1610 | #define SONYPI_CAMERA_SHARPNESS 4 |
1607 | 1611 | ||
1608 | #define SONYPI_CAMERA_EXPOSURE_MASK 0xC | 1612 | #define SONYPI_CAMERA_EXPOSURE_MASK 0xC |
1609 | #define SONYPI_CAMERA_WHITE_BALANCE_MASK 0x3 | 1613 | #define SONYPI_CAMERA_WHITE_BALANCE_MASK 0x3 |
1610 | #define SONYPI_CAMERA_PICTURE_MODE_MASK 0x30 | 1614 | #define SONYPI_CAMERA_PICTURE_MODE_MASK 0x30 |
1611 | #define SONYPI_CAMERA_MUTE_MASK 0x40 | 1615 | #define SONYPI_CAMERA_MUTE_MASK 0x40 |
1612 | 1616 | ||
1613 | /* the rest don't need a loop until not 0xff */ | 1617 | /* the rest don't need a loop until not 0xff */ |
1614 | #define SONYPI_CAMERA_AGC 6 | 1618 | #define SONYPI_CAMERA_AGC 6 |
1615 | #define SONYPI_CAMERA_AGC_MASK 0x30 | 1619 | #define SONYPI_CAMERA_AGC_MASK 0x30 |
1616 | #define SONYPI_CAMERA_SHUTTER_MASK 0x7 | 1620 | #define SONYPI_CAMERA_SHUTTER_MASK 0x7 |
1617 | 1621 | ||
1618 | #define SONYPI_CAMERA_SHUTDOWN_REQUEST 7 | 1622 | #define SONYPI_CAMERA_SHUTDOWN_REQUEST 7 |
1619 | #define SONYPI_CAMERA_CONTROL 0x10 | 1623 | #define SONYPI_CAMERA_CONTROL 0x10 |
1620 | 1624 | ||
1621 | #define SONYPI_CAMERA_STATUS 7 | 1625 | #define SONYPI_CAMERA_STATUS 7 |
1622 | #define SONYPI_CAMERA_STATUS_READY 0x2 | 1626 | #define SONYPI_CAMERA_STATUS_READY 0x2 |
1623 | #define SONYPI_CAMERA_STATUS_POSITION 0x4 | 1627 | #define SONYPI_CAMERA_STATUS_POSITION 0x4 |
1624 | 1628 | ||
1625 | #define SONYPI_DIRECTION_BACKWARDS 0x4 | 1629 | #define SONYPI_DIRECTION_BACKWARDS 0x4 |
1626 | 1630 | ||
1627 | #define SONYPI_CAMERA_REVISION 8 | 1631 | #define SONYPI_CAMERA_REVISION 8 |
1628 | #define SONYPI_CAMERA_ROMVERSION 9 | 1632 | #define SONYPI_CAMERA_ROMVERSION 9 |
1629 | 1633 | ||
1630 | static int __sony_pic_camera_ready(void) | 1634 | static int __sony_pic_camera_ready(void) |
1631 | { | 1635 | { |
1632 | u8 v; | 1636 | u8 v; |
1633 | 1637 | ||
1634 | v = sony_pic_call2(0x8f, SONYPI_CAMERA_STATUS); | 1638 | v = sony_pic_call2(0x8f, SONYPI_CAMERA_STATUS); |
1635 | return (v != 0xff && (v & SONYPI_CAMERA_STATUS_READY)); | 1639 | return (v != 0xff && (v & SONYPI_CAMERA_STATUS_READY)); |
1636 | } | 1640 | } |
1637 | 1641 | ||
1638 | static int __sony_pic_camera_off(void) | 1642 | static int __sony_pic_camera_off(void) |
1639 | { | 1643 | { |
1640 | if (!camera) { | 1644 | if (!camera) { |
1641 | printk(KERN_WARNING DRV_PFX "camera control not enabled\n"); | 1645 | printk(KERN_WARNING DRV_PFX "camera control not enabled\n"); |
1642 | return -ENODEV; | 1646 | return -ENODEV; |
1643 | } | 1647 | } |
1644 | 1648 | ||
1645 | wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_PICTURE, | 1649 | wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_PICTURE, |
1646 | SONYPI_CAMERA_MUTE_MASK), | 1650 | SONYPI_CAMERA_MUTE_MASK), |
1647 | ITERATIONS_SHORT); | 1651 | ITERATIONS_SHORT); |
1648 | 1652 | ||
1649 | if (spic_dev.camera_power) { | 1653 | if (spic_dev.camera_power) { |
1650 | sony_pic_call2(0x91, 0); | 1654 | sony_pic_call2(0x91, 0); |
1651 | spic_dev.camera_power = 0; | 1655 | spic_dev.camera_power = 0; |
1652 | } | 1656 | } |
1653 | return 0; | 1657 | return 0; |
1654 | } | 1658 | } |
1655 | 1659 | ||
1656 | static int __sony_pic_camera_on(void) | 1660 | static int __sony_pic_camera_on(void) |
1657 | { | 1661 | { |
1658 | int i, j, x; | 1662 | int i, j, x; |
1659 | 1663 | ||
1660 | if (!camera) { | 1664 | if (!camera) { |
1661 | printk(KERN_WARNING DRV_PFX "camera control not enabled\n"); | 1665 | printk(KERN_WARNING DRV_PFX "camera control not enabled\n"); |
1662 | return -ENODEV; | 1666 | return -ENODEV; |
1663 | } | 1667 | } |
1664 | 1668 | ||
1665 | if (spic_dev.camera_power) | 1669 | if (spic_dev.camera_power) |
1666 | return 0; | 1670 | return 0; |
1667 | 1671 | ||
1668 | for (j = 5; j > 0; j--) { | 1672 | for (j = 5; j > 0; j--) { |
1669 | 1673 | ||
1670 | for (x = 0; x < 100 && sony_pic_call2(0x91, 0x1); x++) | 1674 | for (x = 0; x < 100 && sony_pic_call2(0x91, 0x1); x++) |
1671 | msleep(10); | 1675 | msleep(10); |
1672 | sony_pic_call1(0x93); | 1676 | sony_pic_call1(0x93); |
1673 | 1677 | ||
1674 | for (i = 400; i > 0; i--) { | 1678 | for (i = 400; i > 0; i--) { |
1675 | if (__sony_pic_camera_ready()) | 1679 | if (__sony_pic_camera_ready()) |
1676 | break; | 1680 | break; |
1677 | msleep(10); | 1681 | msleep(10); |
1678 | } | 1682 | } |
1679 | if (i) | 1683 | if (i) |
1680 | break; | 1684 | break; |
1681 | } | 1685 | } |
1682 | 1686 | ||
1683 | if (j == 0) { | 1687 | if (j == 0) { |
1684 | printk(KERN_WARNING DRV_PFX "failed to power on camera\n"); | 1688 | printk(KERN_WARNING DRV_PFX "failed to power on camera\n"); |
1685 | return -ENODEV; | 1689 | return -ENODEV; |
1686 | } | 1690 | } |
1687 | 1691 | ||
1688 | wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_CONTROL, | 1692 | wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_CONTROL, |
1689 | 0x5a), | 1693 | 0x5a), |
1690 | ITERATIONS_SHORT); | 1694 | ITERATIONS_SHORT); |
1691 | 1695 | ||
1692 | spic_dev.camera_power = 1; | 1696 | spic_dev.camera_power = 1; |
1693 | return 0; | 1697 | return 0; |
1694 | } | 1698 | } |
1695 | 1699 | ||
1696 | /* External camera command (exported to the motion eye v4l driver) */ | 1700 | /* External camera command (exported to the motion eye v4l driver) */ |
1697 | int sony_pic_camera_command(int command, u8 value) | 1701 | int sony_pic_camera_command(int command, u8 value) |
1698 | { | 1702 | { |
1699 | if (!camera) | 1703 | if (!camera) |
1700 | return -EIO; | 1704 | return -EIO; |
1701 | 1705 | ||
1702 | mutex_lock(&spic_dev.lock); | 1706 | mutex_lock(&spic_dev.lock); |
1703 | 1707 | ||
1704 | switch (command) { | 1708 | switch (command) { |
1705 | case SONY_PIC_COMMAND_SETCAMERA: | 1709 | case SONY_PIC_COMMAND_SETCAMERA: |
1706 | if (value) | 1710 | if (value) |
1707 | __sony_pic_camera_on(); | 1711 | __sony_pic_camera_on(); |
1708 | else | 1712 | else |
1709 | __sony_pic_camera_off(); | 1713 | __sony_pic_camera_off(); |
1710 | break; | 1714 | break; |
1711 | case SONY_PIC_COMMAND_SETCAMERABRIGHTNESS: | 1715 | case SONY_PIC_COMMAND_SETCAMERABRIGHTNESS: |
1712 | wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_BRIGHTNESS, value), | 1716 | wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_BRIGHTNESS, value), |
1713 | ITERATIONS_SHORT); | 1717 | ITERATIONS_SHORT); |
1714 | break; | 1718 | break; |
1715 | case SONY_PIC_COMMAND_SETCAMERACONTRAST: | 1719 | case SONY_PIC_COMMAND_SETCAMERACONTRAST: |
1716 | wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_CONTRAST, value), | 1720 | wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_CONTRAST, value), |
1717 | ITERATIONS_SHORT); | 1721 | ITERATIONS_SHORT); |
1718 | break; | 1722 | break; |
1719 | case SONY_PIC_COMMAND_SETCAMERAHUE: | 1723 | case SONY_PIC_COMMAND_SETCAMERAHUE: |
1720 | wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_HUE, value), | 1724 | wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_HUE, value), |
1721 | ITERATIONS_SHORT); | 1725 | ITERATIONS_SHORT); |
1722 | break; | 1726 | break; |
1723 | case SONY_PIC_COMMAND_SETCAMERACOLOR: | 1727 | case SONY_PIC_COMMAND_SETCAMERACOLOR: |
1724 | wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_COLOR, value), | 1728 | wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_COLOR, value), |
1725 | ITERATIONS_SHORT); | 1729 | ITERATIONS_SHORT); |
1726 | break; | 1730 | break; |
1727 | case SONY_PIC_COMMAND_SETCAMERASHARPNESS: | 1731 | case SONY_PIC_COMMAND_SETCAMERASHARPNESS: |
1728 | wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_SHARPNESS, value), | 1732 | wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_SHARPNESS, value), |
1729 | ITERATIONS_SHORT); | 1733 | ITERATIONS_SHORT); |
1730 | break; | 1734 | break; |
1731 | case SONY_PIC_COMMAND_SETCAMERAPICTURE: | 1735 | case SONY_PIC_COMMAND_SETCAMERAPICTURE: |
1732 | wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_PICTURE, value), | 1736 | wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_PICTURE, value), |
1733 | ITERATIONS_SHORT); | 1737 | ITERATIONS_SHORT); |
1734 | break; | 1738 | break; |
1735 | case SONY_PIC_COMMAND_SETCAMERAAGC: | 1739 | case SONY_PIC_COMMAND_SETCAMERAAGC: |
1736 | wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_AGC, value), | 1740 | wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_AGC, value), |
1737 | ITERATIONS_SHORT); | 1741 | ITERATIONS_SHORT); |
1738 | break; | 1742 | break; |
1739 | default: | 1743 | default: |
1740 | printk(KERN_ERR DRV_PFX "sony_pic_camera_command invalid: %d\n", | 1744 | printk(KERN_ERR DRV_PFX "sony_pic_camera_command invalid: %d\n", |
1741 | command); | 1745 | command); |
1742 | break; | 1746 | break; |
1743 | } | 1747 | } |
1744 | mutex_unlock(&spic_dev.lock); | 1748 | mutex_unlock(&spic_dev.lock); |
1745 | return 0; | 1749 | return 0; |
1746 | } | 1750 | } |
1747 | EXPORT_SYMBOL(sony_pic_camera_command); | 1751 | EXPORT_SYMBOL(sony_pic_camera_command); |
1748 | 1752 | ||
1749 | /* gprs/edge modem (SZ460N and SZ210P), thanks to Joshua Wise */ | 1753 | /* gprs/edge modem (SZ460N and SZ210P), thanks to Joshua Wise */ |
1750 | static void sony_pic_set_wwanpower(u8 state) | 1754 | static void sony_pic_set_wwanpower(u8 state) |
1751 | { | 1755 | { |
1752 | state = !!state; | 1756 | state = !!state; |
1753 | mutex_lock(&spic_dev.lock); | 1757 | mutex_lock(&spic_dev.lock); |
1754 | if (spic_dev.wwan_power == state) { | 1758 | if (spic_dev.wwan_power == state) { |
1755 | mutex_unlock(&spic_dev.lock); | 1759 | mutex_unlock(&spic_dev.lock); |
1756 | return; | 1760 | return; |
1757 | } | 1761 | } |
1758 | sony_pic_call2(0xB0, state); | 1762 | sony_pic_call2(0xB0, state); |
1759 | spic_dev.wwan_power = state; | 1763 | spic_dev.wwan_power = state; |
1760 | mutex_unlock(&spic_dev.lock); | 1764 | mutex_unlock(&spic_dev.lock); |
1761 | } | 1765 | } |
1762 | 1766 | ||
1763 | static ssize_t sony_pic_wwanpower_store(struct device *dev, | 1767 | static ssize_t sony_pic_wwanpower_store(struct device *dev, |
1764 | struct device_attribute *attr, | 1768 | struct device_attribute *attr, |
1765 | const char *buffer, size_t count) | 1769 | const char *buffer, size_t count) |
1766 | { | 1770 | { |
1767 | unsigned long value; | 1771 | unsigned long value; |
1768 | if (count > 31) | 1772 | if (count > 31) |
1769 | return -EINVAL; | 1773 | return -EINVAL; |
1770 | 1774 | ||
1771 | value = simple_strtoul(buffer, NULL, 10); | 1775 | value = simple_strtoul(buffer, NULL, 10); |
1772 | sony_pic_set_wwanpower(value); | 1776 | sony_pic_set_wwanpower(value); |
1773 | 1777 | ||
1774 | return count; | 1778 | return count; |
1775 | } | 1779 | } |
1776 | 1780 | ||
1777 | static ssize_t sony_pic_wwanpower_show(struct device *dev, | 1781 | static ssize_t sony_pic_wwanpower_show(struct device *dev, |
1778 | struct device_attribute *attr, char *buffer) | 1782 | struct device_attribute *attr, char *buffer) |
1779 | { | 1783 | { |
1780 | ssize_t count; | 1784 | ssize_t count; |
1781 | mutex_lock(&spic_dev.lock); | 1785 | mutex_lock(&spic_dev.lock); |
1782 | count = snprintf(buffer, PAGE_SIZE, "%d\n", spic_dev.wwan_power); | 1786 | count = snprintf(buffer, PAGE_SIZE, "%d\n", spic_dev.wwan_power); |
1783 | mutex_unlock(&spic_dev.lock); | 1787 | mutex_unlock(&spic_dev.lock); |
1784 | return count; | 1788 | return count; |
1785 | } | 1789 | } |
1786 | 1790 | ||
1787 | /* bluetooth subsystem power state */ | 1791 | /* bluetooth subsystem power state */ |
1788 | static void __sony_pic_set_bluetoothpower(u8 state) | 1792 | static void __sony_pic_set_bluetoothpower(u8 state) |
1789 | { | 1793 | { |
1790 | state = !!state; | 1794 | state = !!state; |
1791 | if (spic_dev.bluetooth_power == state) | 1795 | if (spic_dev.bluetooth_power == state) |
1792 | return; | 1796 | return; |
1793 | sony_pic_call2(0x96, state); | 1797 | sony_pic_call2(0x96, state); |
1794 | sony_pic_call1(0x82); | 1798 | sony_pic_call1(0x82); |
1795 | spic_dev.bluetooth_power = state; | 1799 | spic_dev.bluetooth_power = state; |
1796 | } | 1800 | } |
1797 | 1801 | ||
1798 | static ssize_t sony_pic_bluetoothpower_store(struct device *dev, | 1802 | static ssize_t sony_pic_bluetoothpower_store(struct device *dev, |
1799 | struct device_attribute *attr, | 1803 | struct device_attribute *attr, |
1800 | const char *buffer, size_t count) | 1804 | const char *buffer, size_t count) |
1801 | { | 1805 | { |
1802 | unsigned long value; | 1806 | unsigned long value; |
1803 | if (count > 31) | 1807 | if (count > 31) |
1804 | return -EINVAL; | 1808 | return -EINVAL; |
1805 | 1809 | ||
1806 | value = simple_strtoul(buffer, NULL, 10); | 1810 | value = simple_strtoul(buffer, NULL, 10); |
1807 | mutex_lock(&spic_dev.lock); | 1811 | mutex_lock(&spic_dev.lock); |
1808 | __sony_pic_set_bluetoothpower(value); | 1812 | __sony_pic_set_bluetoothpower(value); |
1809 | mutex_unlock(&spic_dev.lock); | 1813 | mutex_unlock(&spic_dev.lock); |
1810 | 1814 | ||
1811 | return count; | 1815 | return count; |
1812 | } | 1816 | } |
1813 | 1817 | ||
1814 | static ssize_t sony_pic_bluetoothpower_show(struct device *dev, | 1818 | static ssize_t sony_pic_bluetoothpower_show(struct device *dev, |
1815 | struct device_attribute *attr, char *buffer) | 1819 | struct device_attribute *attr, char *buffer) |
1816 | { | 1820 | { |
1817 | ssize_t count = 0; | 1821 | ssize_t count = 0; |
1818 | mutex_lock(&spic_dev.lock); | 1822 | mutex_lock(&spic_dev.lock); |
1819 | count = snprintf(buffer, PAGE_SIZE, "%d\n", spic_dev.bluetooth_power); | 1823 | count = snprintf(buffer, PAGE_SIZE, "%d\n", spic_dev.bluetooth_power); |
1820 | mutex_unlock(&spic_dev.lock); | 1824 | mutex_unlock(&spic_dev.lock); |
1821 | return count; | 1825 | return count; |
1822 | } | 1826 | } |
1823 | 1827 | ||
1824 | /* fan speed */ | 1828 | /* fan speed */ |
1825 | /* FAN0 information (reverse engineered from ACPI tables) */ | 1829 | /* FAN0 information (reverse engineered from ACPI tables) */ |
1826 | #define SONY_PIC_FAN0_STATUS 0x93 | 1830 | #define SONY_PIC_FAN0_STATUS 0x93 |
1827 | static int sony_pic_set_fanspeed(unsigned long value) | 1831 | static int sony_pic_set_fanspeed(unsigned long value) |
1828 | { | 1832 | { |
1829 | return ec_write(SONY_PIC_FAN0_STATUS, value); | 1833 | return ec_write(SONY_PIC_FAN0_STATUS, value); |
1830 | } | 1834 | } |
1831 | 1835 | ||
1832 | static int sony_pic_get_fanspeed(u8 *value) | 1836 | static int sony_pic_get_fanspeed(u8 *value) |
1833 | { | 1837 | { |
1834 | return ec_read(SONY_PIC_FAN0_STATUS, value); | 1838 | return ec_read(SONY_PIC_FAN0_STATUS, value); |
1835 | } | 1839 | } |
1836 | 1840 | ||
1837 | static ssize_t sony_pic_fanspeed_store(struct device *dev, | 1841 | static ssize_t sony_pic_fanspeed_store(struct device *dev, |
1838 | struct device_attribute *attr, | 1842 | struct device_attribute *attr, |
1839 | const char *buffer, size_t count) | 1843 | const char *buffer, size_t count) |
1840 | { | 1844 | { |
1841 | unsigned long value; | 1845 | unsigned long value; |
1842 | if (count > 31) | 1846 | if (count > 31) |
1843 | return -EINVAL; | 1847 | return -EINVAL; |
1844 | 1848 | ||
1845 | value = simple_strtoul(buffer, NULL, 10); | 1849 | value = simple_strtoul(buffer, NULL, 10); |
1846 | if (sony_pic_set_fanspeed(value)) | 1850 | if (sony_pic_set_fanspeed(value)) |
1847 | return -EIO; | 1851 | return -EIO; |
1848 | 1852 | ||
1849 | return count; | 1853 | return count; |
1850 | } | 1854 | } |
1851 | 1855 | ||
1852 | static ssize_t sony_pic_fanspeed_show(struct device *dev, | 1856 | static ssize_t sony_pic_fanspeed_show(struct device *dev, |
1853 | struct device_attribute *attr, char *buffer) | 1857 | struct device_attribute *attr, char *buffer) |
1854 | { | 1858 | { |
1855 | u8 value = 0; | 1859 | u8 value = 0; |
1856 | if (sony_pic_get_fanspeed(&value)) | 1860 | if (sony_pic_get_fanspeed(&value)) |
1857 | return -EIO; | 1861 | return -EIO; |
1858 | 1862 | ||
1859 | return snprintf(buffer, PAGE_SIZE, "%d\n", value); | 1863 | return snprintf(buffer, PAGE_SIZE, "%d\n", value); |
1860 | } | 1864 | } |
1861 | 1865 | ||
1862 | #define SPIC_ATTR(_name, _mode) \ | 1866 | #define SPIC_ATTR(_name, _mode) \ |
1863 | struct device_attribute spic_attr_##_name = __ATTR(_name, \ | 1867 | struct device_attribute spic_attr_##_name = __ATTR(_name, \ |
1864 | _mode, sony_pic_## _name ##_show, \ | 1868 | _mode, sony_pic_## _name ##_show, \ |
1865 | sony_pic_## _name ##_store) | 1869 | sony_pic_## _name ##_store) |
1866 | 1870 | ||
1867 | static SPIC_ATTR(bluetoothpower, 0644); | 1871 | static SPIC_ATTR(bluetoothpower, 0644); |
1868 | static SPIC_ATTR(wwanpower, 0644); | 1872 | static SPIC_ATTR(wwanpower, 0644); |
1869 | static SPIC_ATTR(fanspeed, 0644); | 1873 | static SPIC_ATTR(fanspeed, 0644); |
1870 | 1874 | ||
1871 | static struct attribute *spic_attributes[] = { | 1875 | static struct attribute *spic_attributes[] = { |
1872 | &spic_attr_bluetoothpower.attr, | 1876 | &spic_attr_bluetoothpower.attr, |
1873 | &spic_attr_wwanpower.attr, | 1877 | &spic_attr_wwanpower.attr, |
1874 | &spic_attr_fanspeed.attr, | 1878 | &spic_attr_fanspeed.attr, |
1875 | NULL | 1879 | NULL |
1876 | }; | 1880 | }; |
1877 | 1881 | ||
1878 | static struct attribute_group spic_attribute_group = { | 1882 | static struct attribute_group spic_attribute_group = { |
1879 | .attrs = spic_attributes | 1883 | .attrs = spic_attributes |
1880 | }; | 1884 | }; |
1881 | 1885 | ||
1882 | /******** SONYPI compatibility **********/ | 1886 | /******** SONYPI compatibility **********/ |
1883 | #ifdef CONFIG_SONYPI_COMPAT | 1887 | #ifdef CONFIG_SONYPI_COMPAT |
1884 | 1888 | ||
1885 | /* battery / brightness / temperature addresses */ | 1889 | /* battery / brightness / temperature addresses */ |
1886 | #define SONYPI_BAT_FLAGS 0x81 | 1890 | #define SONYPI_BAT_FLAGS 0x81 |
1887 | #define SONYPI_LCD_LIGHT 0x96 | 1891 | #define SONYPI_LCD_LIGHT 0x96 |
1888 | #define SONYPI_BAT1_PCTRM 0xa0 | 1892 | #define SONYPI_BAT1_PCTRM 0xa0 |
1889 | #define SONYPI_BAT1_LEFT 0xa2 | 1893 | #define SONYPI_BAT1_LEFT 0xa2 |
1890 | #define SONYPI_BAT1_MAXRT 0xa4 | 1894 | #define SONYPI_BAT1_MAXRT 0xa4 |
1891 | #define SONYPI_BAT2_PCTRM 0xa8 | 1895 | #define SONYPI_BAT2_PCTRM 0xa8 |
1892 | #define SONYPI_BAT2_LEFT 0xaa | 1896 | #define SONYPI_BAT2_LEFT 0xaa |
1893 | #define SONYPI_BAT2_MAXRT 0xac | 1897 | #define SONYPI_BAT2_MAXRT 0xac |
1894 | #define SONYPI_BAT1_MAXTK 0xb0 | 1898 | #define SONYPI_BAT1_MAXTK 0xb0 |
1895 | #define SONYPI_BAT1_FULL 0xb2 | 1899 | #define SONYPI_BAT1_FULL 0xb2 |
1896 | #define SONYPI_BAT2_MAXTK 0xb8 | 1900 | #define SONYPI_BAT2_MAXTK 0xb8 |
1897 | #define SONYPI_BAT2_FULL 0xba | 1901 | #define SONYPI_BAT2_FULL 0xba |
1898 | #define SONYPI_TEMP_STATUS 0xC1 | 1902 | #define SONYPI_TEMP_STATUS 0xC1 |
1899 | 1903 | ||
1900 | struct sonypi_compat_s { | 1904 | struct sonypi_compat_s { |
1901 | struct fasync_struct *fifo_async; | 1905 | struct fasync_struct *fifo_async; |
1902 | struct kfifo *fifo; | 1906 | struct kfifo *fifo; |
1903 | spinlock_t fifo_lock; | 1907 | spinlock_t fifo_lock; |
1904 | wait_queue_head_t fifo_proc_list; | 1908 | wait_queue_head_t fifo_proc_list; |
1905 | atomic_t open_count; | 1909 | atomic_t open_count; |
1906 | }; | 1910 | }; |
1907 | static struct sonypi_compat_s sonypi_compat = { | 1911 | static struct sonypi_compat_s sonypi_compat = { |
1908 | .open_count = ATOMIC_INIT(0), | 1912 | .open_count = ATOMIC_INIT(0), |
1909 | }; | 1913 | }; |
1910 | 1914 | ||
1911 | static int sonypi_misc_fasync(int fd, struct file *filp, int on) | 1915 | static int sonypi_misc_fasync(int fd, struct file *filp, int on) |
1912 | { | 1916 | { |
1913 | int retval; | 1917 | int retval; |
1914 | 1918 | ||
1915 | retval = fasync_helper(fd, filp, on, &sonypi_compat.fifo_async); | 1919 | retval = fasync_helper(fd, filp, on, &sonypi_compat.fifo_async); |
1916 | if (retval < 0) | 1920 | if (retval < 0) |
1917 | return retval; | 1921 | return retval; |
1918 | return 0; | 1922 | return 0; |
1919 | } | 1923 | } |
1920 | 1924 | ||
1921 | static int sonypi_misc_release(struct inode *inode, struct file *file) | 1925 | static int sonypi_misc_release(struct inode *inode, struct file *file) |
1922 | { | 1926 | { |
1923 | atomic_dec(&sonypi_compat.open_count); | 1927 | atomic_dec(&sonypi_compat.open_count); |
1924 | return 0; | 1928 | return 0; |
1925 | } | 1929 | } |
1926 | 1930 | ||
1927 | static int sonypi_misc_open(struct inode *inode, struct file *file) | 1931 | static int sonypi_misc_open(struct inode *inode, struct file *file) |
1928 | { | 1932 | { |
1929 | /* Flush input queue on first open */ | 1933 | /* Flush input queue on first open */ |
1930 | lock_kernel(); | 1934 | lock_kernel(); |
1931 | if (atomic_inc_return(&sonypi_compat.open_count) == 1) | 1935 | if (atomic_inc_return(&sonypi_compat.open_count) == 1) |
1932 | kfifo_reset(sonypi_compat.fifo); | 1936 | kfifo_reset(sonypi_compat.fifo); |
1933 | unlock_kernel(); | 1937 | unlock_kernel(); |
1934 | return 0; | 1938 | return 0; |
1935 | } | 1939 | } |
1936 | 1940 | ||
1937 | static ssize_t sonypi_misc_read(struct file *file, char __user *buf, | 1941 | static ssize_t sonypi_misc_read(struct file *file, char __user *buf, |
1938 | size_t count, loff_t *pos) | 1942 | size_t count, loff_t *pos) |
1939 | { | 1943 | { |
1940 | ssize_t ret; | 1944 | ssize_t ret; |
1941 | unsigned char c; | 1945 | unsigned char c; |
1942 | 1946 | ||
1943 | if ((kfifo_len(sonypi_compat.fifo) == 0) && | 1947 | if ((kfifo_len(sonypi_compat.fifo) == 0) && |
1944 | (file->f_flags & O_NONBLOCK)) | 1948 | (file->f_flags & O_NONBLOCK)) |
1945 | return -EAGAIN; | 1949 | return -EAGAIN; |
1946 | 1950 | ||
1947 | ret = wait_event_interruptible(sonypi_compat.fifo_proc_list, | 1951 | ret = wait_event_interruptible(sonypi_compat.fifo_proc_list, |
1948 | kfifo_len(sonypi_compat.fifo) != 0); | 1952 | kfifo_len(sonypi_compat.fifo) != 0); |
1949 | if (ret) | 1953 | if (ret) |
1950 | return ret; | 1954 | return ret; |
1951 | 1955 | ||
1952 | while (ret < count && | 1956 | while (ret < count && |
1953 | (kfifo_get(sonypi_compat.fifo, &c, sizeof(c)) == sizeof(c))) { | 1957 | (kfifo_get(sonypi_compat.fifo, &c, sizeof(c)) == sizeof(c))) { |
1954 | if (put_user(c, buf++)) | 1958 | if (put_user(c, buf++)) |
1955 | return -EFAULT; | 1959 | return -EFAULT; |
1956 | ret++; | 1960 | ret++; |
1957 | } | 1961 | } |
1958 | 1962 | ||
1959 | if (ret > 0) { | 1963 | if (ret > 0) { |
1960 | struct inode *inode = file->f_path.dentry->d_inode; | 1964 | struct inode *inode = file->f_path.dentry->d_inode; |
1961 | inode->i_atime = current_fs_time(inode->i_sb); | 1965 | inode->i_atime = current_fs_time(inode->i_sb); |
1962 | } | 1966 | } |
1963 | 1967 | ||
1964 | return ret; | 1968 | return ret; |
1965 | } | 1969 | } |
1966 | 1970 | ||
1967 | static unsigned int sonypi_misc_poll(struct file *file, poll_table *wait) | 1971 | static unsigned int sonypi_misc_poll(struct file *file, poll_table *wait) |
1968 | { | 1972 | { |
1969 | poll_wait(file, &sonypi_compat.fifo_proc_list, wait); | 1973 | poll_wait(file, &sonypi_compat.fifo_proc_list, wait); |
1970 | if (kfifo_len(sonypi_compat.fifo)) | 1974 | if (kfifo_len(sonypi_compat.fifo)) |
1971 | return POLLIN | POLLRDNORM; | 1975 | return POLLIN | POLLRDNORM; |
1972 | return 0; | 1976 | return 0; |
1973 | } | 1977 | } |
1974 | 1978 | ||
1975 | static int ec_read16(u8 addr, u16 *value) | 1979 | static int ec_read16(u8 addr, u16 *value) |
1976 | { | 1980 | { |
1977 | u8 val_lb, val_hb; | 1981 | u8 val_lb, val_hb; |
1978 | if (ec_read(addr, &val_lb)) | 1982 | if (ec_read(addr, &val_lb)) |
1979 | return -1; | 1983 | return -1; |
1980 | if (ec_read(addr + 1, &val_hb)) | 1984 | if (ec_read(addr + 1, &val_hb)) |
1981 | return -1; | 1985 | return -1; |
1982 | *value = val_lb | (val_hb << 8); | 1986 | *value = val_lb | (val_hb << 8); |
1983 | return 0; | 1987 | return 0; |
1984 | } | 1988 | } |
1985 | 1989 | ||
1986 | static int sonypi_misc_ioctl(struct inode *ip, struct file *fp, | 1990 | static int sonypi_misc_ioctl(struct inode *ip, struct file *fp, |
1987 | unsigned int cmd, unsigned long arg) | 1991 | unsigned int cmd, unsigned long arg) |
1988 | { | 1992 | { |
1989 | int ret = 0; | 1993 | int ret = 0; |
1990 | void __user *argp = (void __user *)arg; | 1994 | void __user *argp = (void __user *)arg; |
1991 | u8 val8; | 1995 | u8 val8; |
1992 | u16 val16; | 1996 | u16 val16; |
1993 | int value; | 1997 | int value; |
1994 | 1998 | ||
1995 | mutex_lock(&spic_dev.lock); | 1999 | mutex_lock(&spic_dev.lock); |
1996 | switch (cmd) { | 2000 | switch (cmd) { |
1997 | case SONYPI_IOCGBRT: | 2001 | case SONYPI_IOCGBRT: |
1998 | if (sony_backlight_device == NULL) { | 2002 | if (sony_backlight_device == NULL) { |
1999 | ret = -EIO; | 2003 | ret = -EIO; |
2000 | break; | 2004 | break; |
2001 | } | 2005 | } |
2002 | if (acpi_callgetfunc(sony_nc_acpi_handle, "GBRT", &value)) { | 2006 | if (acpi_callgetfunc(sony_nc_acpi_handle, "GBRT", &value)) { |
2003 | ret = -EIO; | 2007 | ret = -EIO; |
2004 | break; | 2008 | break; |
2005 | } | 2009 | } |
2006 | val8 = ((value & 0xff) - 1) << 5; | 2010 | val8 = ((value & 0xff) - 1) << 5; |
2007 | if (copy_to_user(argp, &val8, sizeof(val8))) | 2011 | if (copy_to_user(argp, &val8, sizeof(val8))) |
2008 | ret = -EFAULT; | 2012 | ret = -EFAULT; |
2009 | break; | 2013 | break; |
2010 | case SONYPI_IOCSBRT: | 2014 | case SONYPI_IOCSBRT: |
2011 | if (sony_backlight_device == NULL) { | 2015 | if (sony_backlight_device == NULL) { |
2012 | ret = -EIO; | 2016 | ret = -EIO; |
2013 | break; | 2017 | break; |
2014 | } | 2018 | } |
2015 | if (copy_from_user(&val8, argp, sizeof(val8))) { | 2019 | if (copy_from_user(&val8, argp, sizeof(val8))) { |
2016 | ret = -EFAULT; | 2020 | ret = -EFAULT; |
2017 | break; | 2021 | break; |
2018 | } | 2022 | } |
2019 | if (acpi_callsetfunc(sony_nc_acpi_handle, "SBRT", | 2023 | if (acpi_callsetfunc(sony_nc_acpi_handle, "SBRT", |
2020 | (val8 >> 5) + 1, NULL)) { | 2024 | (val8 >> 5) + 1, NULL)) { |
2021 | ret = -EIO; | 2025 | ret = -EIO; |
2022 | break; | 2026 | break; |
2023 | } | 2027 | } |
2024 | /* sync the backlight device status */ | 2028 | /* sync the backlight device status */ |
2025 | sony_backlight_device->props.brightness = | 2029 | sony_backlight_device->props.brightness = |
2026 | sony_backlight_get_brightness(sony_backlight_device); | 2030 | sony_backlight_get_brightness(sony_backlight_device); |
2027 | break; | 2031 | break; |
2028 | case SONYPI_IOCGBAT1CAP: | 2032 | case SONYPI_IOCGBAT1CAP: |
2029 | if (ec_read16(SONYPI_BAT1_FULL, &val16)) { | 2033 | if (ec_read16(SONYPI_BAT1_FULL, &val16)) { |
2030 | ret = -EIO; | 2034 | ret = -EIO; |
2031 | break; | 2035 | break; |
2032 | } | 2036 | } |
2033 | if (copy_to_user(argp, &val16, sizeof(val16))) | 2037 | if (copy_to_user(argp, &val16, sizeof(val16))) |
2034 | ret = -EFAULT; | 2038 | ret = -EFAULT; |
2035 | break; | 2039 | break; |
2036 | case SONYPI_IOCGBAT1REM: | 2040 | case SONYPI_IOCGBAT1REM: |
2037 | if (ec_read16(SONYPI_BAT1_LEFT, &val16)) { | 2041 | if (ec_read16(SONYPI_BAT1_LEFT, &val16)) { |
2038 | ret = -EIO; | 2042 | ret = -EIO; |
2039 | break; | 2043 | break; |
2040 | } | 2044 | } |
2041 | if (copy_to_user(argp, &val16, sizeof(val16))) | 2045 | if (copy_to_user(argp, &val16, sizeof(val16))) |
2042 | ret = -EFAULT; | 2046 | ret = -EFAULT; |
2043 | break; | 2047 | break; |
2044 | case SONYPI_IOCGBAT2CAP: | 2048 | case SONYPI_IOCGBAT2CAP: |
2045 | if (ec_read16(SONYPI_BAT2_FULL, &val16)) { | 2049 | if (ec_read16(SONYPI_BAT2_FULL, &val16)) { |
2046 | ret = -EIO; | 2050 | ret = -EIO; |
2047 | break; | 2051 | break; |
2048 | } | 2052 | } |
2049 | if (copy_to_user(argp, &val16, sizeof(val16))) | 2053 | if (copy_to_user(argp, &val16, sizeof(val16))) |
2050 | ret = -EFAULT; | 2054 | ret = -EFAULT; |
2051 | break; | 2055 | break; |
2052 | case SONYPI_IOCGBAT2REM: | 2056 | case SONYPI_IOCGBAT2REM: |
2053 | if (ec_read16(SONYPI_BAT2_LEFT, &val16)) { | 2057 | if (ec_read16(SONYPI_BAT2_LEFT, &val16)) { |
2054 | ret = -EIO; | 2058 | ret = -EIO; |
2055 | break; | 2059 | break; |
2056 | } | 2060 | } |
2057 | if (copy_to_user(argp, &val16, sizeof(val16))) | 2061 | if (copy_to_user(argp, &val16, sizeof(val16))) |
2058 | ret = -EFAULT; | 2062 | ret = -EFAULT; |
2059 | break; | 2063 | break; |
2060 | case SONYPI_IOCGBATFLAGS: | 2064 | case SONYPI_IOCGBATFLAGS: |
2061 | if (ec_read(SONYPI_BAT_FLAGS, &val8)) { | 2065 | if (ec_read(SONYPI_BAT_FLAGS, &val8)) { |
2062 | ret = -EIO; | 2066 | ret = -EIO; |
2063 | break; | 2067 | break; |
2064 | } | 2068 | } |
2065 | val8 &= 0x07; | 2069 | val8 &= 0x07; |
2066 | if (copy_to_user(argp, &val8, sizeof(val8))) | 2070 | if (copy_to_user(argp, &val8, sizeof(val8))) |
2067 | ret = -EFAULT; | 2071 | ret = -EFAULT; |
2068 | break; | 2072 | break; |
2069 | case SONYPI_IOCGBLUE: | 2073 | case SONYPI_IOCGBLUE: |
2070 | val8 = spic_dev.bluetooth_power; | 2074 | val8 = spic_dev.bluetooth_power; |
2071 | if (copy_to_user(argp, &val8, sizeof(val8))) | 2075 | if (copy_to_user(argp, &val8, sizeof(val8))) |
2072 | ret = -EFAULT; | 2076 | ret = -EFAULT; |
2073 | break; | 2077 | break; |
2074 | case SONYPI_IOCSBLUE: | 2078 | case SONYPI_IOCSBLUE: |
2075 | if (copy_from_user(&val8, argp, sizeof(val8))) { | 2079 | if (copy_from_user(&val8, argp, sizeof(val8))) { |
2076 | ret = -EFAULT; | 2080 | ret = -EFAULT; |
2077 | break; | 2081 | break; |
2078 | } | 2082 | } |
2079 | __sony_pic_set_bluetoothpower(val8); | 2083 | __sony_pic_set_bluetoothpower(val8); |
2080 | break; | 2084 | break; |
2081 | /* FAN Controls */ | 2085 | /* FAN Controls */ |
2082 | case SONYPI_IOCGFAN: | 2086 | case SONYPI_IOCGFAN: |
2083 | if (sony_pic_get_fanspeed(&val8)) { | 2087 | if (sony_pic_get_fanspeed(&val8)) { |
2084 | ret = -EIO; | 2088 | ret = -EIO; |
2085 | break; | 2089 | break; |
2086 | } | 2090 | } |
2087 | if (copy_to_user(argp, &val8, sizeof(val8))) | 2091 | if (copy_to_user(argp, &val8, sizeof(val8))) |
2088 | ret = -EFAULT; | 2092 | ret = -EFAULT; |
2089 | break; | 2093 | break; |
2090 | case SONYPI_IOCSFAN: | 2094 | case SONYPI_IOCSFAN: |
2091 | if (copy_from_user(&val8, argp, sizeof(val8))) { | 2095 | if (copy_from_user(&val8, argp, sizeof(val8))) { |
2092 | ret = -EFAULT; | 2096 | ret = -EFAULT; |
2093 | break; | 2097 | break; |
2094 | } | 2098 | } |
2095 | if (sony_pic_set_fanspeed(val8)) | 2099 | if (sony_pic_set_fanspeed(val8)) |
2096 | ret = -EIO; | 2100 | ret = -EIO; |
2097 | break; | 2101 | break; |
2098 | /* GET Temperature (useful under APM) */ | 2102 | /* GET Temperature (useful under APM) */ |
2099 | case SONYPI_IOCGTEMP: | 2103 | case SONYPI_IOCGTEMP: |
2100 | if (ec_read(SONYPI_TEMP_STATUS, &val8)) { | 2104 | if (ec_read(SONYPI_TEMP_STATUS, &val8)) { |
2101 | ret = -EIO; | 2105 | ret = -EIO; |
2102 | break; | 2106 | break; |
2103 | } | 2107 | } |
2104 | if (copy_to_user(argp, &val8, sizeof(val8))) | 2108 | if (copy_to_user(argp, &val8, sizeof(val8))) |
2105 | ret = -EFAULT; | 2109 | ret = -EFAULT; |
2106 | break; | 2110 | break; |
2107 | default: | 2111 | default: |
2108 | ret = -EINVAL; | 2112 | ret = -EINVAL; |
2109 | } | 2113 | } |
2110 | mutex_unlock(&spic_dev.lock); | 2114 | mutex_unlock(&spic_dev.lock); |
2111 | return ret; | 2115 | return ret; |
2112 | } | 2116 | } |
2113 | 2117 | ||
2114 | static const struct file_operations sonypi_misc_fops = { | 2118 | static const struct file_operations sonypi_misc_fops = { |
2115 | .owner = THIS_MODULE, | 2119 | .owner = THIS_MODULE, |
2116 | .read = sonypi_misc_read, | 2120 | .read = sonypi_misc_read, |
2117 | .poll = sonypi_misc_poll, | 2121 | .poll = sonypi_misc_poll, |
2118 | .open = sonypi_misc_open, | 2122 | .open = sonypi_misc_open, |
2119 | .release = sonypi_misc_release, | 2123 | .release = sonypi_misc_release, |
2120 | .fasync = sonypi_misc_fasync, | 2124 | .fasync = sonypi_misc_fasync, |
2121 | .ioctl = sonypi_misc_ioctl, | 2125 | .ioctl = sonypi_misc_ioctl, |
2122 | }; | 2126 | }; |
2123 | 2127 | ||
2124 | static struct miscdevice sonypi_misc_device = { | 2128 | static struct miscdevice sonypi_misc_device = { |
2125 | .minor = MISC_DYNAMIC_MINOR, | 2129 | .minor = MISC_DYNAMIC_MINOR, |
2126 | .name = "sonypi", | 2130 | .name = "sonypi", |
2127 | .fops = &sonypi_misc_fops, | 2131 | .fops = &sonypi_misc_fops, |
2128 | }; | 2132 | }; |
2129 | 2133 | ||
2130 | static void sonypi_compat_report_event(u8 event) | 2134 | static void sonypi_compat_report_event(u8 event) |
2131 | { | 2135 | { |
2132 | kfifo_put(sonypi_compat.fifo, (unsigned char *)&event, sizeof(event)); | 2136 | kfifo_put(sonypi_compat.fifo, (unsigned char *)&event, sizeof(event)); |
2133 | kill_fasync(&sonypi_compat.fifo_async, SIGIO, POLL_IN); | 2137 | kill_fasync(&sonypi_compat.fifo_async, SIGIO, POLL_IN); |
2134 | wake_up_interruptible(&sonypi_compat.fifo_proc_list); | 2138 | wake_up_interruptible(&sonypi_compat.fifo_proc_list); |
2135 | } | 2139 | } |
2136 | 2140 | ||
2137 | static int sonypi_compat_init(void) | 2141 | static int sonypi_compat_init(void) |
2138 | { | 2142 | { |
2139 | int error; | 2143 | int error; |
2140 | 2144 | ||
2141 | spin_lock_init(&sonypi_compat.fifo_lock); | 2145 | spin_lock_init(&sonypi_compat.fifo_lock); |
2142 | sonypi_compat.fifo = kfifo_alloc(SONY_LAPTOP_BUF_SIZE, GFP_KERNEL, | 2146 | sonypi_compat.fifo = kfifo_alloc(SONY_LAPTOP_BUF_SIZE, GFP_KERNEL, |
2143 | &sonypi_compat.fifo_lock); | 2147 | &sonypi_compat.fifo_lock); |
2144 | if (IS_ERR(sonypi_compat.fifo)) { | 2148 | if (IS_ERR(sonypi_compat.fifo)) { |
2145 | printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n"); | 2149 | printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n"); |
2146 | return PTR_ERR(sonypi_compat.fifo); | 2150 | return PTR_ERR(sonypi_compat.fifo); |
2147 | } | 2151 | } |
2148 | 2152 | ||
2149 | init_waitqueue_head(&sonypi_compat.fifo_proc_list); | 2153 | init_waitqueue_head(&sonypi_compat.fifo_proc_list); |
2150 | 2154 | ||
2151 | if (minor != -1) | 2155 | if (minor != -1) |
2152 | sonypi_misc_device.minor = minor; | 2156 | sonypi_misc_device.minor = minor; |
2153 | error = misc_register(&sonypi_misc_device); | 2157 | error = misc_register(&sonypi_misc_device); |
2154 | if (error) { | 2158 | if (error) { |
2155 | printk(KERN_ERR DRV_PFX "misc_register failed\n"); | 2159 | printk(KERN_ERR DRV_PFX "misc_register failed\n"); |
2156 | goto err_free_kfifo; | 2160 | goto err_free_kfifo; |
2157 | } | 2161 | } |
2158 | if (minor == -1) | 2162 | if (minor == -1) |
2159 | printk(KERN_INFO DRV_PFX "device allocated minor is %d\n", | 2163 | printk(KERN_INFO DRV_PFX "device allocated minor is %d\n", |
2160 | sonypi_misc_device.minor); | 2164 | sonypi_misc_device.minor); |
2161 | 2165 | ||
2162 | return 0; | 2166 | return 0; |
2163 | 2167 | ||
2164 | err_free_kfifo: | 2168 | err_free_kfifo: |
2165 | kfifo_free(sonypi_compat.fifo); | 2169 | kfifo_free(sonypi_compat.fifo); |
2166 | return error; | 2170 | return error; |
2167 | } | 2171 | } |
2168 | 2172 | ||
2169 | static void sonypi_compat_exit(void) | 2173 | static void sonypi_compat_exit(void) |
2170 | { | 2174 | { |
2171 | misc_deregister(&sonypi_misc_device); | 2175 | misc_deregister(&sonypi_misc_device); |
2172 | kfifo_free(sonypi_compat.fifo); | 2176 | kfifo_free(sonypi_compat.fifo); |
2173 | } | 2177 | } |
2174 | #else | 2178 | #else |
2175 | static int sonypi_compat_init(void) { return 0; } | 2179 | static int sonypi_compat_init(void) { return 0; } |
2176 | static void sonypi_compat_exit(void) { } | 2180 | static void sonypi_compat_exit(void) { } |
2177 | static void sonypi_compat_report_event(u8 event) { } | 2181 | static void sonypi_compat_report_event(u8 event) { } |
2178 | #endif /* CONFIG_SONYPI_COMPAT */ | 2182 | #endif /* CONFIG_SONYPI_COMPAT */ |
2179 | 2183 | ||
2180 | /* | 2184 | /* |
2181 | * ACPI callbacks | 2185 | * ACPI callbacks |
2182 | */ | 2186 | */ |
2183 | static acpi_status | 2187 | static acpi_status |
2184 | sony_pic_read_possible_resource(struct acpi_resource *resource, void *context) | 2188 | sony_pic_read_possible_resource(struct acpi_resource *resource, void *context) |
2185 | { | 2189 | { |
2186 | u32 i; | 2190 | u32 i; |
2187 | struct sony_pic_dev *dev = (struct sony_pic_dev *)context; | 2191 | struct sony_pic_dev *dev = (struct sony_pic_dev *)context; |
2188 | 2192 | ||
2189 | switch (resource->type) { | 2193 | switch (resource->type) { |
2190 | case ACPI_RESOURCE_TYPE_START_DEPENDENT: | 2194 | case ACPI_RESOURCE_TYPE_START_DEPENDENT: |
2191 | { | 2195 | { |
2192 | /* start IO enumeration */ | 2196 | /* start IO enumeration */ |
2193 | struct sony_pic_ioport *ioport = kzalloc(sizeof(*ioport), GFP_KERNEL); | 2197 | struct sony_pic_ioport *ioport = kzalloc(sizeof(*ioport), GFP_KERNEL); |
2194 | if (!ioport) | 2198 | if (!ioport) |
2195 | return AE_ERROR; | 2199 | return AE_ERROR; |
2196 | 2200 | ||
2197 | list_add(&ioport->list, &dev->ioports); | 2201 | list_add(&ioport->list, &dev->ioports); |
2198 | return AE_OK; | 2202 | return AE_OK; |
2199 | } | 2203 | } |
2200 | 2204 | ||
2201 | case ACPI_RESOURCE_TYPE_END_DEPENDENT: | 2205 | case ACPI_RESOURCE_TYPE_END_DEPENDENT: |
2202 | /* end IO enumeration */ | 2206 | /* end IO enumeration */ |
2203 | return AE_OK; | 2207 | return AE_OK; |
2204 | 2208 | ||
2205 | case ACPI_RESOURCE_TYPE_IRQ: | 2209 | case ACPI_RESOURCE_TYPE_IRQ: |
2206 | { | 2210 | { |
2207 | struct acpi_resource_irq *p = &resource->data.irq; | 2211 | struct acpi_resource_irq *p = &resource->data.irq; |
2208 | struct sony_pic_irq *interrupt = NULL; | 2212 | struct sony_pic_irq *interrupt = NULL; |
2209 | if (!p || !p->interrupt_count) { | 2213 | if (!p || !p->interrupt_count) { |
2210 | /* | 2214 | /* |
2211 | * IRQ descriptors may have no IRQ# bits set, | 2215 | * IRQ descriptors may have no IRQ# bits set, |
2212 | * particularly those those w/ _STA disabled | 2216 | * particularly those those w/ _STA disabled |
2213 | */ | 2217 | */ |
2214 | dprintk("Blank IRQ resource\n"); | 2218 | dprintk("Blank IRQ resource\n"); |
2215 | return AE_OK; | 2219 | return AE_OK; |
2216 | } | 2220 | } |
2217 | for (i = 0; i < p->interrupt_count; i++) { | 2221 | for (i = 0; i < p->interrupt_count; i++) { |
2218 | if (!p->interrupts[i]) { | 2222 | if (!p->interrupts[i]) { |
2219 | printk(KERN_WARNING DRV_PFX | 2223 | printk(KERN_WARNING DRV_PFX |
2220 | "Invalid IRQ %d\n", | 2224 | "Invalid IRQ %d\n", |
2221 | p->interrupts[i]); | 2225 | p->interrupts[i]); |
2222 | continue; | 2226 | continue; |
2223 | } | 2227 | } |
2224 | interrupt = kzalloc(sizeof(*interrupt), | 2228 | interrupt = kzalloc(sizeof(*interrupt), |
2225 | GFP_KERNEL); | 2229 | GFP_KERNEL); |
2226 | if (!interrupt) | 2230 | if (!interrupt) |
2227 | return AE_ERROR; | 2231 | return AE_ERROR; |
2228 | 2232 | ||
2229 | list_add(&interrupt->list, &dev->interrupts); | 2233 | list_add(&interrupt->list, &dev->interrupts); |
2230 | interrupt->irq.triggering = p->triggering; | 2234 | interrupt->irq.triggering = p->triggering; |
2231 | interrupt->irq.polarity = p->polarity; | 2235 | interrupt->irq.polarity = p->polarity; |
2232 | interrupt->irq.sharable = p->sharable; | 2236 | interrupt->irq.sharable = p->sharable; |
2233 | interrupt->irq.interrupt_count = 1; | 2237 | interrupt->irq.interrupt_count = 1; |
2234 | interrupt->irq.interrupts[0] = p->interrupts[i]; | 2238 | interrupt->irq.interrupts[0] = p->interrupts[i]; |
2235 | } | 2239 | } |
2236 | return AE_OK; | 2240 | return AE_OK; |
2237 | } | 2241 | } |
2238 | case ACPI_RESOURCE_TYPE_IO: | 2242 | case ACPI_RESOURCE_TYPE_IO: |
2239 | { | 2243 | { |
2240 | struct acpi_resource_io *io = &resource->data.io; | 2244 | struct acpi_resource_io *io = &resource->data.io; |
2241 | struct sony_pic_ioport *ioport = | 2245 | struct sony_pic_ioport *ioport = |
2242 | list_first_entry(&dev->ioports, struct sony_pic_ioport, list); | 2246 | list_first_entry(&dev->ioports, struct sony_pic_ioport, list); |
2243 | if (!io) { | 2247 | if (!io) { |
2244 | dprintk("Blank IO resource\n"); | 2248 | dprintk("Blank IO resource\n"); |
2245 | return AE_OK; | 2249 | return AE_OK; |
2246 | } | 2250 | } |
2247 | 2251 | ||
2248 | if (!ioport->io1.minimum) { | 2252 | if (!ioport->io1.minimum) { |
2249 | memcpy(&ioport->io1, io, sizeof(*io)); | 2253 | memcpy(&ioport->io1, io, sizeof(*io)); |
2250 | dprintk("IO1 at 0x%.4x (0x%.2x)\n", ioport->io1.minimum, | 2254 | dprintk("IO1 at 0x%.4x (0x%.2x)\n", ioport->io1.minimum, |
2251 | ioport->io1.address_length); | 2255 | ioport->io1.address_length); |
2252 | } | 2256 | } |
2253 | else if (!ioport->io2.minimum) { | 2257 | else if (!ioport->io2.minimum) { |
2254 | memcpy(&ioport->io2, io, sizeof(*io)); | 2258 | memcpy(&ioport->io2, io, sizeof(*io)); |
2255 | dprintk("IO2 at 0x%.4x (0x%.2x)\n", ioport->io2.minimum, | 2259 | dprintk("IO2 at 0x%.4x (0x%.2x)\n", ioport->io2.minimum, |
2256 | ioport->io2.address_length); | 2260 | ioport->io2.address_length); |
2257 | } | 2261 | } |
2258 | else { | 2262 | else { |
2259 | printk(KERN_ERR DRV_PFX "Unknown SPIC Type, more than 2 IO Ports\n"); | 2263 | printk(KERN_ERR DRV_PFX "Unknown SPIC Type, more than 2 IO Ports\n"); |
2260 | return AE_ERROR; | 2264 | return AE_ERROR; |
2261 | } | 2265 | } |
2262 | return AE_OK; | 2266 | return AE_OK; |
2263 | } | 2267 | } |
2264 | default: | 2268 | default: |
2265 | dprintk("Resource %d isn't an IRQ nor an IO port\n", | 2269 | dprintk("Resource %d isn't an IRQ nor an IO port\n", |
2266 | resource->type); | 2270 | resource->type); |
2267 | 2271 | ||
2268 | case ACPI_RESOURCE_TYPE_END_TAG: | 2272 | case ACPI_RESOURCE_TYPE_END_TAG: |
2269 | return AE_OK; | 2273 | return AE_OK; |
2270 | } | 2274 | } |
2271 | return AE_CTRL_TERMINATE; | 2275 | return AE_CTRL_TERMINATE; |
2272 | } | 2276 | } |
2273 | 2277 | ||
2274 | static int sony_pic_possible_resources(struct acpi_device *device) | 2278 | static int sony_pic_possible_resources(struct acpi_device *device) |
2275 | { | 2279 | { |
2276 | int result = 0; | 2280 | int result = 0; |
2277 | acpi_status status = AE_OK; | 2281 | acpi_status status = AE_OK; |
2278 | 2282 | ||
2279 | if (!device) | 2283 | if (!device) |
2280 | return -EINVAL; | 2284 | return -EINVAL; |
2281 | 2285 | ||
2282 | /* get device status */ | 2286 | /* get device status */ |
2283 | /* see acpi_pci_link_get_current acpi_pci_link_get_possible */ | 2287 | /* see acpi_pci_link_get_current acpi_pci_link_get_possible */ |
2284 | dprintk("Evaluating _STA\n"); | 2288 | dprintk("Evaluating _STA\n"); |
2285 | result = acpi_bus_get_status(device); | 2289 | result = acpi_bus_get_status(device); |
2286 | if (result) { | 2290 | if (result) { |
2287 | printk(KERN_WARNING DRV_PFX "Unable to read status\n"); | 2291 | printk(KERN_WARNING DRV_PFX "Unable to read status\n"); |
2288 | goto end; | 2292 | goto end; |
2289 | } | 2293 | } |
2290 | 2294 | ||
2291 | if (!device->status.enabled) | 2295 | if (!device->status.enabled) |
2292 | dprintk("Device disabled\n"); | 2296 | dprintk("Device disabled\n"); |
2293 | else | 2297 | else |
2294 | dprintk("Device enabled\n"); | 2298 | dprintk("Device enabled\n"); |
2295 | 2299 | ||
2296 | /* | 2300 | /* |
2297 | * Query and parse 'method' | 2301 | * Query and parse 'method' |
2298 | */ | 2302 | */ |
2299 | dprintk("Evaluating %s\n", METHOD_NAME__PRS); | 2303 | dprintk("Evaluating %s\n", METHOD_NAME__PRS); |
2300 | status = acpi_walk_resources(device->handle, METHOD_NAME__PRS, | 2304 | status = acpi_walk_resources(device->handle, METHOD_NAME__PRS, |
2301 | sony_pic_read_possible_resource, &spic_dev); | 2305 | sony_pic_read_possible_resource, &spic_dev); |
2302 | if (ACPI_FAILURE(status)) { | 2306 | if (ACPI_FAILURE(status)) { |
2303 | printk(KERN_WARNING DRV_PFX | 2307 | printk(KERN_WARNING DRV_PFX |
2304 | "Failure evaluating %s\n", | 2308 | "Failure evaluating %s\n", |
2305 | METHOD_NAME__PRS); | 2309 | METHOD_NAME__PRS); |
2306 | result = -ENODEV; | 2310 | result = -ENODEV; |
2307 | } | 2311 | } |
2308 | end: | 2312 | end: |
2309 | return result; | 2313 | return result; |
2310 | } | 2314 | } |
2311 | 2315 | ||
2312 | /* | 2316 | /* |
2313 | * Disable the spic device by calling its _DIS method | 2317 | * Disable the spic device by calling its _DIS method |
2314 | */ | 2318 | */ |
2315 | static int sony_pic_disable(struct acpi_device *device) | 2319 | static int sony_pic_disable(struct acpi_device *device) |
2316 | { | 2320 | { |
2317 | acpi_status ret = acpi_evaluate_object(device->handle, "_DIS", NULL, | 2321 | acpi_status ret = acpi_evaluate_object(device->handle, "_DIS", NULL, |
2318 | NULL); | 2322 | NULL); |
2319 | 2323 | ||
2320 | if (ACPI_FAILURE(ret) && ret != AE_NOT_FOUND) | 2324 | if (ACPI_FAILURE(ret) && ret != AE_NOT_FOUND) |
2321 | return -ENXIO; | 2325 | return -ENXIO; |
2322 | 2326 | ||
2323 | dprintk("Device disabled\n"); | 2327 | dprintk("Device disabled\n"); |
2324 | return 0; | 2328 | return 0; |
2325 | } | 2329 | } |
2326 | 2330 | ||
2327 | 2331 | ||
2328 | /* | 2332 | /* |
2329 | * Based on drivers/acpi/pci_link.c:acpi_pci_link_set | 2333 | * Based on drivers/acpi/pci_link.c:acpi_pci_link_set |
2330 | * | 2334 | * |
2331 | * Call _SRS to set current resources | 2335 | * Call _SRS to set current resources |
2332 | */ | 2336 | */ |
2333 | static int sony_pic_enable(struct acpi_device *device, | 2337 | static int sony_pic_enable(struct acpi_device *device, |
2334 | struct sony_pic_ioport *ioport, struct sony_pic_irq *irq) | 2338 | struct sony_pic_ioport *ioport, struct sony_pic_irq *irq) |
2335 | { | 2339 | { |
2336 | acpi_status status; | 2340 | acpi_status status; |
2337 | int result = 0; | 2341 | int result = 0; |
2338 | /* Type 1 resource layout is: | 2342 | /* Type 1 resource layout is: |
2339 | * IO | 2343 | * IO |
2340 | * IO | 2344 | * IO |
2341 | * IRQNoFlags | 2345 | * IRQNoFlags |
2342 | * End | 2346 | * End |
2343 | * | 2347 | * |
2344 | * Type 2 and 3 resource layout is: | 2348 | * Type 2 and 3 resource layout is: |
2345 | * IO | 2349 | * IO |
2346 | * IRQNoFlags | 2350 | * IRQNoFlags |
2347 | * End | 2351 | * End |
2348 | */ | 2352 | */ |
2349 | struct { | 2353 | struct { |
2350 | struct acpi_resource res1; | 2354 | struct acpi_resource res1; |
2351 | struct acpi_resource res2; | 2355 | struct acpi_resource res2; |
2352 | struct acpi_resource res3; | 2356 | struct acpi_resource res3; |
2353 | struct acpi_resource res4; | 2357 | struct acpi_resource res4; |
2354 | } *resource; | 2358 | } *resource; |
2355 | struct acpi_buffer buffer = { 0, NULL }; | 2359 | struct acpi_buffer buffer = { 0, NULL }; |
2356 | 2360 | ||
2357 | if (!ioport || !irq) | 2361 | if (!ioport || !irq) |
2358 | return -EINVAL; | 2362 | return -EINVAL; |
2359 | 2363 | ||
2360 | /* init acpi_buffer */ | 2364 | /* init acpi_buffer */ |
2361 | resource = kzalloc(sizeof(*resource) + 1, GFP_KERNEL); | 2365 | resource = kzalloc(sizeof(*resource) + 1, GFP_KERNEL); |
2362 | if (!resource) | 2366 | if (!resource) |
2363 | return -ENOMEM; | 2367 | return -ENOMEM; |
2364 | 2368 | ||
2365 | buffer.length = sizeof(*resource) + 1; | 2369 | buffer.length = sizeof(*resource) + 1; |
2366 | buffer.pointer = resource; | 2370 | buffer.pointer = resource; |
2367 | 2371 | ||
2368 | /* setup Type 1 resources */ | 2372 | /* setup Type 1 resources */ |
2369 | if (spic_dev.control->model == SONYPI_DEVICE_TYPE1) { | 2373 | if (spic_dev.control->model == SONYPI_DEVICE_TYPE1) { |
2370 | 2374 | ||
2371 | /* setup io resources */ | 2375 | /* setup io resources */ |
2372 | resource->res1.type = ACPI_RESOURCE_TYPE_IO; | 2376 | resource->res1.type = ACPI_RESOURCE_TYPE_IO; |
2373 | resource->res1.length = sizeof(struct acpi_resource); | 2377 | resource->res1.length = sizeof(struct acpi_resource); |
2374 | memcpy(&resource->res1.data.io, &ioport->io1, | 2378 | memcpy(&resource->res1.data.io, &ioport->io1, |
2375 | sizeof(struct acpi_resource_io)); | 2379 | sizeof(struct acpi_resource_io)); |
2376 | 2380 | ||
2377 | resource->res2.type = ACPI_RESOURCE_TYPE_IO; | 2381 | resource->res2.type = ACPI_RESOURCE_TYPE_IO; |
2378 | resource->res2.length = sizeof(struct acpi_resource); | 2382 | resource->res2.length = sizeof(struct acpi_resource); |
2379 | memcpy(&resource->res2.data.io, &ioport->io2, | 2383 | memcpy(&resource->res2.data.io, &ioport->io2, |
2380 | sizeof(struct acpi_resource_io)); | 2384 | sizeof(struct acpi_resource_io)); |
2381 | 2385 | ||
2382 | /* setup irq resource */ | 2386 | /* setup irq resource */ |
2383 | resource->res3.type = ACPI_RESOURCE_TYPE_IRQ; | 2387 | resource->res3.type = ACPI_RESOURCE_TYPE_IRQ; |
2384 | resource->res3.length = sizeof(struct acpi_resource); | 2388 | resource->res3.length = sizeof(struct acpi_resource); |
2385 | memcpy(&resource->res3.data.irq, &irq->irq, | 2389 | memcpy(&resource->res3.data.irq, &irq->irq, |
2386 | sizeof(struct acpi_resource_irq)); | 2390 | sizeof(struct acpi_resource_irq)); |
2387 | /* we requested a shared irq */ | 2391 | /* we requested a shared irq */ |
2388 | resource->res3.data.irq.sharable = ACPI_SHARED; | 2392 | resource->res3.data.irq.sharable = ACPI_SHARED; |
2389 | 2393 | ||
2390 | resource->res4.type = ACPI_RESOURCE_TYPE_END_TAG; | 2394 | resource->res4.type = ACPI_RESOURCE_TYPE_END_TAG; |
2391 | 2395 | ||
2392 | } | 2396 | } |
2393 | /* setup Type 2/3 resources */ | 2397 | /* setup Type 2/3 resources */ |
2394 | else { | 2398 | else { |
2395 | /* setup io resource */ | 2399 | /* setup io resource */ |
2396 | resource->res1.type = ACPI_RESOURCE_TYPE_IO; | 2400 | resource->res1.type = ACPI_RESOURCE_TYPE_IO; |
2397 | resource->res1.length = sizeof(struct acpi_resource); | 2401 | resource->res1.length = sizeof(struct acpi_resource); |
2398 | memcpy(&resource->res1.data.io, &ioport->io1, | 2402 | memcpy(&resource->res1.data.io, &ioport->io1, |
2399 | sizeof(struct acpi_resource_io)); | 2403 | sizeof(struct acpi_resource_io)); |
2400 | 2404 | ||
2401 | /* setup irq resource */ | 2405 | /* setup irq resource */ |
2402 | resource->res2.type = ACPI_RESOURCE_TYPE_IRQ; | 2406 | resource->res2.type = ACPI_RESOURCE_TYPE_IRQ; |
2403 | resource->res2.length = sizeof(struct acpi_resource); | 2407 | resource->res2.length = sizeof(struct acpi_resource); |
2404 | memcpy(&resource->res2.data.irq, &irq->irq, | 2408 | memcpy(&resource->res2.data.irq, &irq->irq, |
2405 | sizeof(struct acpi_resource_irq)); | 2409 | sizeof(struct acpi_resource_irq)); |
2406 | /* we requested a shared irq */ | 2410 | /* we requested a shared irq */ |
2407 | resource->res2.data.irq.sharable = ACPI_SHARED; | 2411 | resource->res2.data.irq.sharable = ACPI_SHARED; |
2408 | 2412 | ||
2409 | resource->res3.type = ACPI_RESOURCE_TYPE_END_TAG; | 2413 | resource->res3.type = ACPI_RESOURCE_TYPE_END_TAG; |
2410 | } | 2414 | } |
2411 | 2415 | ||
2412 | /* Attempt to set the resource */ | 2416 | /* Attempt to set the resource */ |
2413 | dprintk("Evaluating _SRS\n"); | 2417 | dprintk("Evaluating _SRS\n"); |
2414 | status = acpi_set_current_resources(device->handle, &buffer); | 2418 | status = acpi_set_current_resources(device->handle, &buffer); |
2415 | 2419 | ||
2416 | /* check for total failure */ | 2420 | /* check for total failure */ |
2417 | if (ACPI_FAILURE(status)) { | 2421 | if (ACPI_FAILURE(status)) { |
2418 | printk(KERN_ERR DRV_PFX "Error evaluating _SRS\n"); | 2422 | printk(KERN_ERR DRV_PFX "Error evaluating _SRS\n"); |
2419 | result = -ENODEV; | 2423 | result = -ENODEV; |
2420 | goto end; | 2424 | goto end; |
2421 | } | 2425 | } |
2422 | 2426 | ||
2423 | /* Necessary device initializations calls (from sonypi) */ | 2427 | /* Necessary device initializations calls (from sonypi) */ |
2424 | sony_pic_call1(0x82); | 2428 | sony_pic_call1(0x82); |
2425 | sony_pic_call2(0x81, 0xff); | 2429 | sony_pic_call2(0x81, 0xff); |
2426 | sony_pic_call1(compat ? 0x92 : 0x82); | 2430 | sony_pic_call1(compat ? 0x92 : 0x82); |
2427 | 2431 | ||
2428 | end: | 2432 | end: |
2429 | kfree(resource); | 2433 | kfree(resource); |
2430 | return result; | 2434 | return result; |
2431 | } | 2435 | } |
2432 | 2436 | ||
2433 | /***************** | 2437 | /***************** |
2434 | * | 2438 | * |
2435 | * ISR: some event is available | 2439 | * ISR: some event is available |
2436 | * | 2440 | * |
2437 | *****************/ | 2441 | *****************/ |
2438 | static irqreturn_t sony_pic_irq(int irq, void *dev_id) | 2442 | static irqreturn_t sony_pic_irq(int irq, void *dev_id) |
2439 | { | 2443 | { |
2440 | int i, j; | 2444 | int i, j; |
2441 | u8 ev = 0; | 2445 | u8 ev = 0; |
2442 | u8 data_mask = 0; | 2446 | u8 data_mask = 0; |
2443 | u8 device_event = 0; | 2447 | u8 device_event = 0; |
2444 | 2448 | ||
2445 | struct sony_pic_dev *dev = (struct sony_pic_dev *) dev_id; | 2449 | struct sony_pic_dev *dev = (struct sony_pic_dev *) dev_id; |
2446 | 2450 | ||
2447 | ev = inb_p(dev->cur_ioport->io1.minimum); | 2451 | ev = inb_p(dev->cur_ioport->io1.minimum); |
2448 | if (dev->cur_ioport->io2.minimum) | 2452 | if (dev->cur_ioport->io2.minimum) |
2449 | data_mask = inb_p(dev->cur_ioport->io2.minimum); | 2453 | data_mask = inb_p(dev->cur_ioport->io2.minimum); |
2450 | else | 2454 | else |
2451 | data_mask = inb_p(dev->cur_ioport->io1.minimum + | 2455 | data_mask = inb_p(dev->cur_ioport->io1.minimum + |
2452 | dev->control->evport_offset); | 2456 | dev->control->evport_offset); |
2453 | 2457 | ||
2454 | dprintk("event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n", | 2458 | dprintk("event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n", |
2455 | ev, data_mask, dev->cur_ioport->io1.minimum, | 2459 | ev, data_mask, dev->cur_ioport->io1.minimum, |
2456 | dev->control->evport_offset); | 2460 | dev->control->evport_offset); |
2457 | 2461 | ||
2458 | if (ev == 0x00 || ev == 0xff) | 2462 | if (ev == 0x00 || ev == 0xff) |
2459 | return IRQ_HANDLED; | 2463 | return IRQ_HANDLED; |
2460 | 2464 | ||
2461 | for (i = 0; dev->control->event_types[i].mask; i++) { | 2465 | for (i = 0; dev->control->event_types[i].mask; i++) { |
2462 | 2466 | ||
2463 | if ((data_mask & dev->control->event_types[i].data) != | 2467 | if ((data_mask & dev->control->event_types[i].data) != |
2464 | dev->control->event_types[i].data) | 2468 | dev->control->event_types[i].data) |
2465 | continue; | 2469 | continue; |
2466 | 2470 | ||
2467 | if (!(mask & dev->control->event_types[i].mask)) | 2471 | if (!(mask & dev->control->event_types[i].mask)) |
2468 | continue; | 2472 | continue; |
2469 | 2473 | ||
2470 | for (j = 0; dev->control->event_types[i].events[j].event; j++) { | 2474 | for (j = 0; dev->control->event_types[i].events[j].event; j++) { |
2471 | if (ev == dev->control->event_types[i].events[j].data) { | 2475 | if (ev == dev->control->event_types[i].events[j].data) { |
2472 | device_event = | 2476 | device_event = |
2473 | dev->control-> | 2477 | dev->control-> |
2474 | event_types[i].events[j].event; | 2478 | event_types[i].events[j].event; |
2475 | goto found; | 2479 | goto found; |
2476 | } | 2480 | } |
2477 | } | 2481 | } |
2478 | } | 2482 | } |
2479 | /* Still not able to decode the event try to pass | 2483 | /* Still not able to decode the event try to pass |
2480 | * it over to the minidriver | 2484 | * it over to the minidriver |
2481 | */ | 2485 | */ |
2482 | if (dev->control->handle_irq && | 2486 | if (dev->control->handle_irq && |
2483 | dev->control->handle_irq(data_mask, ev) == 0) | 2487 | dev->control->handle_irq(data_mask, ev) == 0) |
2484 | return IRQ_HANDLED; | 2488 | return IRQ_HANDLED; |
2485 | 2489 | ||
2486 | dprintk("unknown event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n", | 2490 | dprintk("unknown event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n", |
2487 | ev, data_mask, dev->cur_ioport->io1.minimum, | 2491 | ev, data_mask, dev->cur_ioport->io1.minimum, |
2488 | dev->control->evport_offset); | 2492 | dev->control->evport_offset); |
2489 | return IRQ_HANDLED; | 2493 | return IRQ_HANDLED; |
2490 | 2494 | ||
2491 | found: | 2495 | found: |
2492 | sony_laptop_report_input_event(device_event); | 2496 | sony_laptop_report_input_event(device_event); |
2493 | acpi_bus_generate_proc_event(dev->acpi_dev, 1, device_event); | 2497 | acpi_bus_generate_proc_event(dev->acpi_dev, 1, device_event); |
2494 | sonypi_compat_report_event(device_event); | 2498 | sonypi_compat_report_event(device_event); |
2495 | 2499 | ||
2496 | return IRQ_HANDLED; | 2500 | return IRQ_HANDLED; |
2497 | } | 2501 | } |
2498 | 2502 | ||
2499 | /***************** | 2503 | /***************** |
2500 | * | 2504 | * |
2501 | * ACPI driver | 2505 | * ACPI driver |
2502 | * | 2506 | * |
2503 | *****************/ | 2507 | *****************/ |
2504 | static int sony_pic_remove(struct acpi_device *device, int type) | 2508 | static int sony_pic_remove(struct acpi_device *device, int type) |
2505 | { | 2509 | { |
2506 | struct sony_pic_ioport *io, *tmp_io; | 2510 | struct sony_pic_ioport *io, *tmp_io; |
2507 | struct sony_pic_irq *irq, *tmp_irq; | 2511 | struct sony_pic_irq *irq, *tmp_irq; |
2508 | 2512 | ||
2509 | if (sony_pic_disable(device)) { | 2513 | if (sony_pic_disable(device)) { |
2510 | printk(KERN_ERR DRV_PFX "Couldn't disable device.\n"); | 2514 | printk(KERN_ERR DRV_PFX "Couldn't disable device.\n"); |
2511 | return -ENXIO; | 2515 | return -ENXIO; |
2512 | } | 2516 | } |
2513 | 2517 | ||
2514 | free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev); | 2518 | free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev); |
2515 | release_region(spic_dev.cur_ioport->io1.minimum, | 2519 | release_region(spic_dev.cur_ioport->io1.minimum, |
2516 | spic_dev.cur_ioport->io1.address_length); | 2520 | spic_dev.cur_ioport->io1.address_length); |
2517 | if (spic_dev.cur_ioport->io2.minimum) | 2521 | if (spic_dev.cur_ioport->io2.minimum) |
2518 | release_region(spic_dev.cur_ioport->io2.minimum, | 2522 | release_region(spic_dev.cur_ioport->io2.minimum, |
2519 | spic_dev.cur_ioport->io2.address_length); | 2523 | spic_dev.cur_ioport->io2.address_length); |
2520 | 2524 | ||
2521 | sonypi_compat_exit(); | 2525 | sonypi_compat_exit(); |
2522 | 2526 | ||
2523 | sony_laptop_remove_input(); | 2527 | sony_laptop_remove_input(); |
2524 | 2528 | ||
2525 | /* pf attrs */ | 2529 | /* pf attrs */ |
2526 | sysfs_remove_group(&sony_pf_device->dev.kobj, &spic_attribute_group); | 2530 | sysfs_remove_group(&sony_pf_device->dev.kobj, &spic_attribute_group); |
2527 | sony_pf_remove(); | 2531 | sony_pf_remove(); |
2528 | 2532 | ||
2529 | list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) { | 2533 | list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) { |
2530 | list_del(&io->list); | 2534 | list_del(&io->list); |
2531 | kfree(io); | 2535 | kfree(io); |
2532 | } | 2536 | } |
2533 | list_for_each_entry_safe(irq, tmp_irq, &spic_dev.interrupts, list) { | 2537 | list_for_each_entry_safe(irq, tmp_irq, &spic_dev.interrupts, list) { |
2534 | list_del(&irq->list); | 2538 | list_del(&irq->list); |
2535 | kfree(irq); | 2539 | kfree(irq); |
2536 | } | 2540 | } |
2537 | spic_dev.cur_ioport = NULL; | 2541 | spic_dev.cur_ioport = NULL; |
2538 | spic_dev.cur_irq = NULL; | 2542 | spic_dev.cur_irq = NULL; |
2539 | 2543 | ||
2540 | dprintk(SONY_PIC_DRIVER_NAME " removed.\n"); | 2544 | dprintk(SONY_PIC_DRIVER_NAME " removed.\n"); |
2541 | return 0; | 2545 | return 0; |
2542 | } | 2546 | } |
2543 | 2547 | ||
2544 | static int sony_pic_add(struct acpi_device *device) | 2548 | static int sony_pic_add(struct acpi_device *device) |
2545 | { | 2549 | { |
2546 | int result; | 2550 | int result; |
2547 | struct sony_pic_ioport *io, *tmp_io; | 2551 | struct sony_pic_ioport *io, *tmp_io; |
2548 | struct sony_pic_irq *irq, *tmp_irq; | 2552 | struct sony_pic_irq *irq, *tmp_irq; |
2549 | 2553 | ||
2550 | printk(KERN_INFO DRV_PFX "%s v%s.\n", | 2554 | printk(KERN_INFO DRV_PFX "%s v%s.\n", |
2551 | SONY_PIC_DRIVER_NAME, SONY_LAPTOP_DRIVER_VERSION); | 2555 | SONY_PIC_DRIVER_NAME, SONY_LAPTOP_DRIVER_VERSION); |
2552 | 2556 | ||
2553 | spic_dev.acpi_dev = device; | 2557 | spic_dev.acpi_dev = device; |
2554 | strcpy(acpi_device_class(device), "sony/hotkey"); | 2558 | strcpy(acpi_device_class(device), "sony/hotkey"); |
2555 | sony_pic_detect_device_type(&spic_dev); | 2559 | sony_pic_detect_device_type(&spic_dev); |
2556 | mutex_init(&spic_dev.lock); | 2560 | mutex_init(&spic_dev.lock); |
2557 | 2561 | ||
2558 | /* read _PRS resources */ | 2562 | /* read _PRS resources */ |
2559 | result = sony_pic_possible_resources(device); | 2563 | result = sony_pic_possible_resources(device); |
2560 | if (result) { | 2564 | if (result) { |
2561 | printk(KERN_ERR DRV_PFX | 2565 | printk(KERN_ERR DRV_PFX |
2562 | "Unabe to read possible resources.\n"); | 2566 | "Unabe to read possible resources.\n"); |
2563 | goto err_free_resources; | 2567 | goto err_free_resources; |
2564 | } | 2568 | } |
2565 | 2569 | ||
2566 | /* setup input devices and helper fifo */ | 2570 | /* setup input devices and helper fifo */ |
2567 | result = sony_laptop_setup_input(device); | 2571 | result = sony_laptop_setup_input(device); |
2568 | if (result) { | 2572 | if (result) { |
2569 | printk(KERN_ERR DRV_PFX | 2573 | printk(KERN_ERR DRV_PFX |
2570 | "Unabe to create input devices.\n"); | 2574 | "Unabe to create input devices.\n"); |
2571 | goto err_free_resources; | 2575 | goto err_free_resources; |
2572 | } | 2576 | } |
2573 | 2577 | ||
2574 | if (sonypi_compat_init()) | 2578 | if (sonypi_compat_init()) |
2575 | goto err_remove_input; | 2579 | goto err_remove_input; |
2576 | 2580 | ||
2577 | /* request io port */ | 2581 | /* request io port */ |
2578 | list_for_each_entry_reverse(io, &spic_dev.ioports, list) { | 2582 | list_for_each_entry_reverse(io, &spic_dev.ioports, list) { |
2579 | if (request_region(io->io1.minimum, io->io1.address_length, | 2583 | if (request_region(io->io1.minimum, io->io1.address_length, |
2580 | "Sony Programable I/O Device")) { | 2584 | "Sony Programable I/O Device")) { |
2581 | dprintk("I/O port1: 0x%.4x (0x%.4x) + 0x%.2x\n", | 2585 | dprintk("I/O port1: 0x%.4x (0x%.4x) + 0x%.2x\n", |
2582 | io->io1.minimum, io->io1.maximum, | 2586 | io->io1.minimum, io->io1.maximum, |
2583 | io->io1.address_length); | 2587 | io->io1.address_length); |
2584 | /* Type 1 have 2 ioports */ | 2588 | /* Type 1 have 2 ioports */ |
2585 | if (io->io2.minimum) { | 2589 | if (io->io2.minimum) { |
2586 | if (request_region(io->io2.minimum, | 2590 | if (request_region(io->io2.minimum, |
2587 | io->io2.address_length, | 2591 | io->io2.address_length, |
2588 | "Sony Programable I/O Device")) { | 2592 | "Sony Programable I/O Device")) { |
2589 | dprintk("I/O port2: 0x%.4x (0x%.4x) + 0x%.2x\n", | 2593 | dprintk("I/O port2: 0x%.4x (0x%.4x) + 0x%.2x\n", |
2590 | io->io2.minimum, io->io2.maximum, | 2594 | io->io2.minimum, io->io2.maximum, |
2591 | io->io2.address_length); | 2595 | io->io2.address_length); |
2592 | spic_dev.cur_ioport = io; | 2596 | spic_dev.cur_ioport = io; |
2593 | break; | 2597 | break; |
2594 | } | 2598 | } |
2595 | else { | 2599 | else { |
2596 | dprintk("Unable to get I/O port2: " | 2600 | dprintk("Unable to get I/O port2: " |
2597 | "0x%.4x (0x%.4x) + 0x%.2x\n", | 2601 | "0x%.4x (0x%.4x) + 0x%.2x\n", |
2598 | io->io2.minimum, io->io2.maximum, | 2602 | io->io2.minimum, io->io2.maximum, |
2599 | io->io2.address_length); | 2603 | io->io2.address_length); |
2600 | release_region(io->io1.minimum, | 2604 | release_region(io->io1.minimum, |
2601 | io->io1.address_length); | 2605 | io->io1.address_length); |
2602 | } | 2606 | } |
2603 | } | 2607 | } |
2604 | else { | 2608 | else { |
2605 | spic_dev.cur_ioport = io; | 2609 | spic_dev.cur_ioport = io; |
2606 | break; | 2610 | break; |
2607 | } | 2611 | } |
2608 | } | 2612 | } |
2609 | } | 2613 | } |
2610 | if (!spic_dev.cur_ioport) { | 2614 | if (!spic_dev.cur_ioport) { |
2611 | printk(KERN_ERR DRV_PFX "Failed to request_region.\n"); | 2615 | printk(KERN_ERR DRV_PFX "Failed to request_region.\n"); |
2612 | result = -ENODEV; | 2616 | result = -ENODEV; |
2613 | goto err_remove_compat; | 2617 | goto err_remove_compat; |
2614 | } | 2618 | } |
2615 | 2619 | ||
2616 | /* request IRQ */ | 2620 | /* request IRQ */ |
2617 | list_for_each_entry_reverse(irq, &spic_dev.interrupts, list) { | 2621 | list_for_each_entry_reverse(irq, &spic_dev.interrupts, list) { |
2618 | if (!request_irq(irq->irq.interrupts[0], sony_pic_irq, | 2622 | if (!request_irq(irq->irq.interrupts[0], sony_pic_irq, |
2619 | IRQF_SHARED, "sony-laptop", &spic_dev)) { | 2623 | IRQF_SHARED, "sony-laptop", &spic_dev)) { |
2620 | dprintk("IRQ: %d - triggering: %d - " | 2624 | dprintk("IRQ: %d - triggering: %d - " |
2621 | "polarity: %d - shr: %d\n", | 2625 | "polarity: %d - shr: %d\n", |
2622 | irq->irq.interrupts[0], | 2626 | irq->irq.interrupts[0], |
2623 | irq->irq.triggering, | 2627 | irq->irq.triggering, |
2624 | irq->irq.polarity, | 2628 | irq->irq.polarity, |
2625 | irq->irq.sharable); | 2629 | irq->irq.sharable); |
2626 | spic_dev.cur_irq = irq; | 2630 | spic_dev.cur_irq = irq; |
2627 | break; | 2631 | break; |
2628 | } | 2632 | } |
2629 | } | 2633 | } |
2630 | if (!spic_dev.cur_irq) { | 2634 | if (!spic_dev.cur_irq) { |
2631 | printk(KERN_ERR DRV_PFX "Failed to request_irq.\n"); | 2635 | printk(KERN_ERR DRV_PFX "Failed to request_irq.\n"); |
2632 | result = -ENODEV; | 2636 | result = -ENODEV; |
2633 | goto err_release_region; | 2637 | goto err_release_region; |
2634 | } | 2638 | } |
2635 | 2639 | ||
2636 | /* set resource status _SRS */ | 2640 | /* set resource status _SRS */ |
2637 | result = sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq); | 2641 | result = sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq); |
2638 | if (result) { | 2642 | if (result) { |
2639 | printk(KERN_ERR DRV_PFX "Couldn't enable device.\n"); | 2643 | printk(KERN_ERR DRV_PFX "Couldn't enable device.\n"); |
2640 | goto err_free_irq; | 2644 | goto err_free_irq; |
2641 | } | 2645 | } |
2642 | 2646 | ||
2643 | spic_dev.bluetooth_power = -1; | 2647 | spic_dev.bluetooth_power = -1; |
2644 | /* create device attributes */ | 2648 | /* create device attributes */ |
2645 | result = sony_pf_add(); | 2649 | result = sony_pf_add(); |
2646 | if (result) | 2650 | if (result) |
2647 | goto err_disable_device; | 2651 | goto err_disable_device; |
2648 | 2652 | ||
2649 | result = sysfs_create_group(&sony_pf_device->dev.kobj, &spic_attribute_group); | 2653 | result = sysfs_create_group(&sony_pf_device->dev.kobj, &spic_attribute_group); |
2650 | if (result) | 2654 | if (result) |
2651 | goto err_remove_pf; | 2655 | goto err_remove_pf; |
2652 | 2656 | ||
2653 | return 0; | 2657 | return 0; |
2654 | 2658 | ||
2655 | err_remove_pf: | 2659 | err_remove_pf: |
2656 | sony_pf_remove(); | 2660 | sony_pf_remove(); |
2657 | 2661 | ||
2658 | err_disable_device: | 2662 | err_disable_device: |
2659 | sony_pic_disable(device); | 2663 | sony_pic_disable(device); |
2660 | 2664 | ||
2661 | err_free_irq: | 2665 | err_free_irq: |
2662 | free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev); | 2666 | free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev); |
2663 | 2667 | ||
2664 | err_release_region: | 2668 | err_release_region: |
2665 | release_region(spic_dev.cur_ioport->io1.minimum, | 2669 | release_region(spic_dev.cur_ioport->io1.minimum, |
2666 | spic_dev.cur_ioport->io1.address_length); | 2670 | spic_dev.cur_ioport->io1.address_length); |
2667 | if (spic_dev.cur_ioport->io2.minimum) | 2671 | if (spic_dev.cur_ioport->io2.minimum) |
2668 | release_region(spic_dev.cur_ioport->io2.minimum, | 2672 | release_region(spic_dev.cur_ioport->io2.minimum, |
2669 | spic_dev.cur_ioport->io2.address_length); | 2673 | spic_dev.cur_ioport->io2.address_length); |
2670 | 2674 | ||
2671 | err_remove_compat: | 2675 | err_remove_compat: |
2672 | sonypi_compat_exit(); | 2676 | sonypi_compat_exit(); |
2673 | 2677 | ||
2674 | err_remove_input: | 2678 | err_remove_input: |
2675 | sony_laptop_remove_input(); | 2679 | sony_laptop_remove_input(); |
2676 | 2680 | ||
2677 | err_free_resources: | 2681 | err_free_resources: |
2678 | list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) { | 2682 | list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) { |
2679 | list_del(&io->list); | 2683 | list_del(&io->list); |
2680 | kfree(io); | 2684 | kfree(io); |
2681 | } | 2685 | } |
2682 | list_for_each_entry_safe(irq, tmp_irq, &spic_dev.interrupts, list) { | 2686 | list_for_each_entry_safe(irq, tmp_irq, &spic_dev.interrupts, list) { |
2683 | list_del(&irq->list); | 2687 | list_del(&irq->list); |
2684 | kfree(irq); | 2688 | kfree(irq); |
2685 | } | 2689 | } |
2686 | spic_dev.cur_ioport = NULL; | 2690 | spic_dev.cur_ioport = NULL; |
2687 | spic_dev.cur_irq = NULL; | 2691 | spic_dev.cur_irq = NULL; |
2688 | 2692 | ||
2689 | return result; | 2693 | return result; |
2690 | } | 2694 | } |
2691 | 2695 | ||
2692 | static int sony_pic_suspend(struct acpi_device *device, pm_message_t state) | 2696 | static int sony_pic_suspend(struct acpi_device *device, pm_message_t state) |
2693 | { | 2697 | { |
2694 | if (sony_pic_disable(device)) | 2698 | if (sony_pic_disable(device)) |
2695 | return -ENXIO; | 2699 | return -ENXIO; |
2696 | return 0; | 2700 | return 0; |
2697 | } | 2701 | } |
2698 | 2702 | ||
2699 | static int sony_pic_resume(struct acpi_device *device) | 2703 | static int sony_pic_resume(struct acpi_device *device) |
2700 | { | 2704 | { |
2701 | sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq); | 2705 | sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq); |
2702 | return 0; | 2706 | return 0; |
2703 | } | 2707 | } |
2704 | 2708 | ||
2705 | static const struct acpi_device_id sony_pic_device_ids[] = { | 2709 | static const struct acpi_device_id sony_pic_device_ids[] = { |
2706 | {SONY_PIC_HID, 0}, | 2710 | {SONY_PIC_HID, 0}, |
2707 | {"", 0}, | 2711 | {"", 0}, |
2708 | }; | 2712 | }; |
2709 | 2713 | ||
2710 | static struct acpi_driver sony_pic_driver = { | 2714 | static struct acpi_driver sony_pic_driver = { |
2711 | .name = SONY_PIC_DRIVER_NAME, | 2715 | .name = SONY_PIC_DRIVER_NAME, |
2712 | .class = SONY_PIC_CLASS, | 2716 | .class = SONY_PIC_CLASS, |
2713 | .ids = sony_pic_device_ids, | 2717 | .ids = sony_pic_device_ids, |
2714 | .owner = THIS_MODULE, | 2718 | .owner = THIS_MODULE, |
2715 | .ops = { | 2719 | .ops = { |
2716 | .add = sony_pic_add, | 2720 | .add = sony_pic_add, |
2717 | .remove = sony_pic_remove, | 2721 | .remove = sony_pic_remove, |
2718 | .suspend = sony_pic_suspend, | 2722 | .suspend = sony_pic_suspend, |
2719 | .resume = sony_pic_resume, | 2723 | .resume = sony_pic_resume, |
2720 | }, | 2724 | }, |
2721 | }; | 2725 | }; |
2722 | 2726 | ||
2723 | static struct dmi_system_id __initdata sonypi_dmi_table[] = { | 2727 | static struct dmi_system_id __initdata sonypi_dmi_table[] = { |
2724 | { | 2728 | { |
2725 | .ident = "Sony Vaio", | 2729 | .ident = "Sony Vaio", |
2726 | .matches = { | 2730 | .matches = { |
2727 | DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), | 2731 | DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), |
2728 | DMI_MATCH(DMI_PRODUCT_NAME, "PCG-"), | 2732 | DMI_MATCH(DMI_PRODUCT_NAME, "PCG-"), |
2729 | }, | 2733 | }, |
2730 | }, | 2734 | }, |
2731 | { | 2735 | { |
2732 | .ident = "Sony Vaio", | 2736 | .ident = "Sony Vaio", |
2733 | .matches = { | 2737 | .matches = { |
2734 | DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), | 2738 | DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), |
2735 | DMI_MATCH(DMI_PRODUCT_NAME, "VGN-"), | 2739 | DMI_MATCH(DMI_PRODUCT_NAME, "VGN-"), |
2736 | }, | 2740 | }, |
2737 | }, | 2741 | }, |
2738 | { } | 2742 | { } |
2739 | }; | 2743 | }; |
2740 | 2744 | ||
2741 | static int __init sony_laptop_init(void) | 2745 | static int __init sony_laptop_init(void) |
2742 | { | 2746 | { |
2743 | int result; | 2747 | int result; |
2744 | 2748 | ||
2745 | if (!no_spic && dmi_check_system(sonypi_dmi_table)) { | 2749 | if (!no_spic && dmi_check_system(sonypi_dmi_table)) { |
2746 | result = acpi_bus_register_driver(&sony_pic_driver); | 2750 | result = acpi_bus_register_driver(&sony_pic_driver); |
2747 | if (result) { | 2751 | if (result) { |
2748 | printk(KERN_ERR DRV_PFX | 2752 | printk(KERN_ERR DRV_PFX |
2749 | "Unable to register SPIC driver."); | 2753 | "Unable to register SPIC driver."); |
2750 | goto out; | 2754 | goto out; |
2751 | } | 2755 | } |
2752 | } | 2756 | } |
2753 | 2757 | ||
2754 | result = acpi_bus_register_driver(&sony_nc_driver); | 2758 | result = acpi_bus_register_driver(&sony_nc_driver); |
2755 | if (result) { | 2759 | if (result) { |
2756 | printk(KERN_ERR DRV_PFX "Unable to register SNC driver."); | 2760 | printk(KERN_ERR DRV_PFX "Unable to register SNC driver."); |
2757 | goto out_unregister_pic; | 2761 | goto out_unregister_pic; |
2758 | } | 2762 | } |
2759 | 2763 | ||
2760 | return 0; | 2764 | return 0; |
2761 | 2765 | ||
2762 | out_unregister_pic: | 2766 | out_unregister_pic: |
2763 | if (!no_spic) | 2767 | if (!no_spic) |
2764 | acpi_bus_unregister_driver(&sony_pic_driver); | 2768 | acpi_bus_unregister_driver(&sony_pic_driver); |
2765 | out: | 2769 | out: |
2766 | return result; | 2770 | return result; |
2767 | } | 2771 | } |
2768 | 2772 | ||
2769 | static void __exit sony_laptop_exit(void) | 2773 | static void __exit sony_laptop_exit(void) |
2770 | { | 2774 | { |
2771 | acpi_bus_unregister_driver(&sony_nc_driver); | 2775 | acpi_bus_unregister_driver(&sony_nc_driver); |
2772 | if (!no_spic) | 2776 | if (!no_spic) |
2773 | acpi_bus_unregister_driver(&sony_pic_driver); | 2777 | acpi_bus_unregister_driver(&sony_pic_driver); |
2774 | } | 2778 | } |
2775 | 2779 | ||
2776 | module_init(sony_laptop_init); | 2780 | module_init(sony_laptop_init); |
2777 | module_exit(sony_laptop_exit); | 2781 | module_exit(sony_laptop_exit); |
2778 | 2782 |
drivers/misc/thinkpad_acpi.c
1 | /* | 1 | /* |
2 | * thinkpad_acpi.c - ThinkPad ACPI Extras | 2 | * thinkpad_acpi.c - ThinkPad ACPI Extras |
3 | * | 3 | * |
4 | * | 4 | * |
5 | * Copyright (C) 2004-2005 Borislav Deianov <borislav@users.sf.net> | 5 | * Copyright (C) 2004-2005 Borislav Deianov <borislav@users.sf.net> |
6 | * Copyright (C) 2006-2008 Henrique de Moraes Holschuh <hmh@hmh.eng.br> | 6 | * Copyright (C) 2006-2008 Henrique de Moraes Holschuh <hmh@hmh.eng.br> |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify | 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 | 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 | 10 | * the Free Software Foundation; either version 2 of the License, or |
11 | * (at your option) any later version. | 11 | * (at your option) any later version. |
12 | * | 12 | * |
13 | * This program is distributed in the hope that it will be useful, | 13 | * This program is distributed in the hope that it will be useful, |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | * GNU General Public License for more details. | 16 | * GNU General Public License for more details. |
17 | * | 17 | * |
18 | * You should have received a copy of the GNU General Public License | 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 | 19 | * along with this program; if not, write to the Free Software |
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
21 | * 02110-1301, USA. | 21 | * 02110-1301, USA. |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #define TPACPI_VERSION "0.21" | 24 | #define TPACPI_VERSION "0.21" |
25 | #define TPACPI_SYSFS_VERSION 0x020200 | 25 | #define TPACPI_SYSFS_VERSION 0x020200 |
26 | 26 | ||
27 | /* | 27 | /* |
28 | * Changelog: | 28 | * Changelog: |
29 | * 2007-10-20 changelog trimmed down | 29 | * 2007-10-20 changelog trimmed down |
30 | * | 30 | * |
31 | * 2007-03-27 0.14 renamed to thinkpad_acpi and moved to | 31 | * 2007-03-27 0.14 renamed to thinkpad_acpi and moved to |
32 | * drivers/misc. | 32 | * drivers/misc. |
33 | * | 33 | * |
34 | * 2006-11-22 0.13 new maintainer | 34 | * 2006-11-22 0.13 new maintainer |
35 | * changelog now lives in git commit history, and will | 35 | * changelog now lives in git commit history, and will |
36 | * not be updated further in-file. | 36 | * not be updated further in-file. |
37 | * | 37 | * |
38 | * 2005-03-17 0.11 support for 600e, 770x | 38 | * 2005-03-17 0.11 support for 600e, 770x |
39 | * thanks to Jamie Lentin <lentinj@dial.pipex.com> | 39 | * thanks to Jamie Lentin <lentinj@dial.pipex.com> |
40 | * | 40 | * |
41 | * 2005-01-16 0.9 use MODULE_VERSION | 41 | * 2005-01-16 0.9 use MODULE_VERSION |
42 | * thanks to Henrik Brix Andersen <brix@gentoo.org> | 42 | * thanks to Henrik Brix Andersen <brix@gentoo.org> |
43 | * fix parameter passing on module loading | 43 | * fix parameter passing on module loading |
44 | * thanks to Rusty Russell <rusty@rustcorp.com.au> | 44 | * thanks to Rusty Russell <rusty@rustcorp.com.au> |
45 | * thanks to Jim Radford <radford@blackbean.org> | 45 | * thanks to Jim Radford <radford@blackbean.org> |
46 | * 2004-11-08 0.8 fix init error case, don't return from a macro | 46 | * 2004-11-08 0.8 fix init error case, don't return from a macro |
47 | * thanks to Chris Wright <chrisw@osdl.org> | 47 | * thanks to Chris Wright <chrisw@osdl.org> |
48 | */ | 48 | */ |
49 | 49 | ||
50 | #include <linux/kernel.h> | 50 | #include <linux/kernel.h> |
51 | #include <linux/module.h> | 51 | #include <linux/module.h> |
52 | #include <linux/init.h> | 52 | #include <linux/init.h> |
53 | #include <linux/types.h> | 53 | #include <linux/types.h> |
54 | #include <linux/string.h> | 54 | #include <linux/string.h> |
55 | #include <linux/list.h> | 55 | #include <linux/list.h> |
56 | #include <linux/mutex.h> | 56 | #include <linux/mutex.h> |
57 | #include <linux/kthread.h> | 57 | #include <linux/kthread.h> |
58 | #include <linux/freezer.h> | 58 | #include <linux/freezer.h> |
59 | #include <linux/delay.h> | 59 | #include <linux/delay.h> |
60 | 60 | ||
61 | #include <linux/nvram.h> | 61 | #include <linux/nvram.h> |
62 | #include <linux/proc_fs.h> | 62 | #include <linux/proc_fs.h> |
63 | #include <linux/sysfs.h> | 63 | #include <linux/sysfs.h> |
64 | #include <linux/backlight.h> | 64 | #include <linux/backlight.h> |
65 | #include <linux/fb.h> | 65 | #include <linux/fb.h> |
66 | #include <linux/platform_device.h> | 66 | #include <linux/platform_device.h> |
67 | #include <linux/hwmon.h> | 67 | #include <linux/hwmon.h> |
68 | #include <linux/hwmon-sysfs.h> | 68 | #include <linux/hwmon-sysfs.h> |
69 | #include <linux/input.h> | 69 | #include <linux/input.h> |
70 | #include <linux/leds.h> | 70 | #include <linux/leds.h> |
71 | #include <linux/rfkill.h> | 71 | #include <linux/rfkill.h> |
72 | #include <asm/uaccess.h> | 72 | #include <asm/uaccess.h> |
73 | 73 | ||
74 | #include <linux/dmi.h> | 74 | #include <linux/dmi.h> |
75 | #include <linux/jiffies.h> | 75 | #include <linux/jiffies.h> |
76 | #include <linux/workqueue.h> | 76 | #include <linux/workqueue.h> |
77 | 77 | ||
78 | #include <acpi/acpi_drivers.h> | 78 | #include <acpi/acpi_drivers.h> |
79 | #include <acpi/acnamesp.h> | 79 | #include <acpi/acnamesp.h> |
80 | 80 | ||
81 | #include <linux/pci_ids.h> | 81 | #include <linux/pci_ids.h> |
82 | 82 | ||
83 | 83 | ||
84 | /* ThinkPad CMOS commands */ | 84 | /* ThinkPad CMOS commands */ |
85 | #define TP_CMOS_VOLUME_DOWN 0 | 85 | #define TP_CMOS_VOLUME_DOWN 0 |
86 | #define TP_CMOS_VOLUME_UP 1 | 86 | #define TP_CMOS_VOLUME_UP 1 |
87 | #define TP_CMOS_VOLUME_MUTE 2 | 87 | #define TP_CMOS_VOLUME_MUTE 2 |
88 | #define TP_CMOS_BRIGHTNESS_UP 4 | 88 | #define TP_CMOS_BRIGHTNESS_UP 4 |
89 | #define TP_CMOS_BRIGHTNESS_DOWN 5 | 89 | #define TP_CMOS_BRIGHTNESS_DOWN 5 |
90 | #define TP_CMOS_THINKLIGHT_ON 12 | 90 | #define TP_CMOS_THINKLIGHT_ON 12 |
91 | #define TP_CMOS_THINKLIGHT_OFF 13 | 91 | #define TP_CMOS_THINKLIGHT_OFF 13 |
92 | 92 | ||
93 | /* NVRAM Addresses */ | 93 | /* NVRAM Addresses */ |
94 | enum tp_nvram_addr { | 94 | enum tp_nvram_addr { |
95 | TP_NVRAM_ADDR_HK2 = 0x57, | 95 | TP_NVRAM_ADDR_HK2 = 0x57, |
96 | TP_NVRAM_ADDR_THINKLIGHT = 0x58, | 96 | TP_NVRAM_ADDR_THINKLIGHT = 0x58, |
97 | TP_NVRAM_ADDR_VIDEO = 0x59, | 97 | TP_NVRAM_ADDR_VIDEO = 0x59, |
98 | TP_NVRAM_ADDR_BRIGHTNESS = 0x5e, | 98 | TP_NVRAM_ADDR_BRIGHTNESS = 0x5e, |
99 | TP_NVRAM_ADDR_MIXER = 0x60, | 99 | TP_NVRAM_ADDR_MIXER = 0x60, |
100 | }; | 100 | }; |
101 | 101 | ||
102 | /* NVRAM bit masks */ | 102 | /* NVRAM bit masks */ |
103 | enum { | 103 | enum { |
104 | TP_NVRAM_MASK_HKT_THINKPAD = 0x08, | 104 | TP_NVRAM_MASK_HKT_THINKPAD = 0x08, |
105 | TP_NVRAM_MASK_HKT_ZOOM = 0x20, | 105 | TP_NVRAM_MASK_HKT_ZOOM = 0x20, |
106 | TP_NVRAM_MASK_HKT_DISPLAY = 0x40, | 106 | TP_NVRAM_MASK_HKT_DISPLAY = 0x40, |
107 | TP_NVRAM_MASK_HKT_HIBERNATE = 0x80, | 107 | TP_NVRAM_MASK_HKT_HIBERNATE = 0x80, |
108 | TP_NVRAM_MASK_THINKLIGHT = 0x10, | 108 | TP_NVRAM_MASK_THINKLIGHT = 0x10, |
109 | TP_NVRAM_MASK_HKT_DISPEXPND = 0x30, | 109 | TP_NVRAM_MASK_HKT_DISPEXPND = 0x30, |
110 | TP_NVRAM_MASK_HKT_BRIGHTNESS = 0x20, | 110 | TP_NVRAM_MASK_HKT_BRIGHTNESS = 0x20, |
111 | TP_NVRAM_MASK_LEVEL_BRIGHTNESS = 0x0f, | 111 | TP_NVRAM_MASK_LEVEL_BRIGHTNESS = 0x0f, |
112 | TP_NVRAM_POS_LEVEL_BRIGHTNESS = 0, | 112 | TP_NVRAM_POS_LEVEL_BRIGHTNESS = 0, |
113 | TP_NVRAM_MASK_MUTE = 0x40, | 113 | TP_NVRAM_MASK_MUTE = 0x40, |
114 | TP_NVRAM_MASK_HKT_VOLUME = 0x80, | 114 | TP_NVRAM_MASK_HKT_VOLUME = 0x80, |
115 | TP_NVRAM_MASK_LEVEL_VOLUME = 0x0f, | 115 | TP_NVRAM_MASK_LEVEL_VOLUME = 0x0f, |
116 | TP_NVRAM_POS_LEVEL_VOLUME = 0, | 116 | TP_NVRAM_POS_LEVEL_VOLUME = 0, |
117 | }; | 117 | }; |
118 | 118 | ||
119 | /* ACPI HIDs */ | 119 | /* ACPI HIDs */ |
120 | #define TPACPI_ACPI_HKEY_HID "IBM0068" | 120 | #define TPACPI_ACPI_HKEY_HID "IBM0068" |
121 | 121 | ||
122 | /* Input IDs */ | 122 | /* Input IDs */ |
123 | #define TPACPI_HKEY_INPUT_PRODUCT 0x5054 /* "TP" */ | 123 | #define TPACPI_HKEY_INPUT_PRODUCT 0x5054 /* "TP" */ |
124 | #define TPACPI_HKEY_INPUT_VERSION 0x4101 | 124 | #define TPACPI_HKEY_INPUT_VERSION 0x4101 |
125 | 125 | ||
126 | 126 | ||
127 | /**************************************************************************** | 127 | /**************************************************************************** |
128 | * Main driver | 128 | * Main driver |
129 | */ | 129 | */ |
130 | 130 | ||
131 | #define TPACPI_NAME "thinkpad" | 131 | #define TPACPI_NAME "thinkpad" |
132 | #define TPACPI_DESC "ThinkPad ACPI Extras" | 132 | #define TPACPI_DESC "ThinkPad ACPI Extras" |
133 | #define TPACPI_FILE TPACPI_NAME "_acpi" | 133 | #define TPACPI_FILE TPACPI_NAME "_acpi" |
134 | #define TPACPI_URL "http://ibm-acpi.sf.net/" | 134 | #define TPACPI_URL "http://ibm-acpi.sf.net/" |
135 | #define TPACPI_MAIL "ibm-acpi-devel@lists.sourceforge.net" | 135 | #define TPACPI_MAIL "ibm-acpi-devel@lists.sourceforge.net" |
136 | 136 | ||
137 | #define TPACPI_PROC_DIR "ibm" | 137 | #define TPACPI_PROC_DIR "ibm" |
138 | #define TPACPI_ACPI_EVENT_PREFIX "ibm" | 138 | #define TPACPI_ACPI_EVENT_PREFIX "ibm" |
139 | #define TPACPI_DRVR_NAME TPACPI_FILE | 139 | #define TPACPI_DRVR_NAME TPACPI_FILE |
140 | #define TPACPI_DRVR_SHORTNAME "tpacpi" | 140 | #define TPACPI_DRVR_SHORTNAME "tpacpi" |
141 | #define TPACPI_HWMON_DRVR_NAME TPACPI_NAME "_hwmon" | 141 | #define TPACPI_HWMON_DRVR_NAME TPACPI_NAME "_hwmon" |
142 | 142 | ||
143 | #define TPACPI_NVRAM_KTHREAD_NAME "ktpacpi_nvramd" | 143 | #define TPACPI_NVRAM_KTHREAD_NAME "ktpacpi_nvramd" |
144 | #define TPACPI_WORKQUEUE_NAME "ktpacpid" | 144 | #define TPACPI_WORKQUEUE_NAME "ktpacpid" |
145 | 145 | ||
146 | #define TPACPI_MAX_ACPI_ARGS 3 | 146 | #define TPACPI_MAX_ACPI_ARGS 3 |
147 | 147 | ||
148 | /* rfkill switches */ | 148 | /* rfkill switches */ |
149 | enum { | 149 | enum { |
150 | TPACPI_RFK_BLUETOOTH_SW_ID = 0, | 150 | TPACPI_RFK_BLUETOOTH_SW_ID = 0, |
151 | TPACPI_RFK_WWAN_SW_ID, | 151 | TPACPI_RFK_WWAN_SW_ID, |
152 | }; | 152 | }; |
153 | 153 | ||
154 | /* Debugging */ | 154 | /* Debugging */ |
155 | #define TPACPI_LOG TPACPI_FILE ": " | 155 | #define TPACPI_LOG TPACPI_FILE ": " |
156 | #define TPACPI_ERR KERN_ERR TPACPI_LOG | 156 | #define TPACPI_ERR KERN_ERR TPACPI_LOG |
157 | #define TPACPI_NOTICE KERN_NOTICE TPACPI_LOG | 157 | #define TPACPI_NOTICE KERN_NOTICE TPACPI_LOG |
158 | #define TPACPI_INFO KERN_INFO TPACPI_LOG | 158 | #define TPACPI_INFO KERN_INFO TPACPI_LOG |
159 | #define TPACPI_DEBUG KERN_DEBUG TPACPI_LOG | 159 | #define TPACPI_DEBUG KERN_DEBUG TPACPI_LOG |
160 | 160 | ||
161 | #define TPACPI_DBG_ALL 0xffff | 161 | #define TPACPI_DBG_ALL 0xffff |
162 | #define TPACPI_DBG_INIT 0x0001 | 162 | #define TPACPI_DBG_INIT 0x0001 |
163 | #define TPACPI_DBG_EXIT 0x0002 | 163 | #define TPACPI_DBG_EXIT 0x0002 |
164 | #define dbg_printk(a_dbg_level, format, arg...) \ | 164 | #define dbg_printk(a_dbg_level, format, arg...) \ |
165 | do { if (dbg_level & a_dbg_level) \ | 165 | do { if (dbg_level & a_dbg_level) \ |
166 | printk(TPACPI_DEBUG "%s: " format, __func__ , ## arg); \ | 166 | printk(TPACPI_DEBUG "%s: " format, __func__ , ## arg); \ |
167 | } while (0) | 167 | } while (0) |
168 | #ifdef CONFIG_THINKPAD_ACPI_DEBUG | 168 | #ifdef CONFIG_THINKPAD_ACPI_DEBUG |
169 | #define vdbg_printk(a_dbg_level, format, arg...) \ | 169 | #define vdbg_printk(a_dbg_level, format, arg...) \ |
170 | dbg_printk(a_dbg_level, format, ## arg) | 170 | dbg_printk(a_dbg_level, format, ## arg) |
171 | static const char *str_supported(int is_supported); | 171 | static const char *str_supported(int is_supported); |
172 | #else | 172 | #else |
173 | #define vdbg_printk(a_dbg_level, format, arg...) | 173 | #define vdbg_printk(a_dbg_level, format, arg...) |
174 | #endif | 174 | #endif |
175 | 175 | ||
176 | #define onoff(status, bit) ((status) & (1 << (bit)) ? "on" : "off") | 176 | #define onoff(status, bit) ((status) & (1 << (bit)) ? "on" : "off") |
177 | #define enabled(status, bit) ((status) & (1 << (bit)) ? "enabled" : "disabled") | 177 | #define enabled(status, bit) ((status) & (1 << (bit)) ? "enabled" : "disabled") |
178 | #define strlencmp(a, b) (strncmp((a), (b), strlen(b))) | 178 | #define strlencmp(a, b) (strncmp((a), (b), strlen(b))) |
179 | 179 | ||
180 | 180 | ||
181 | /**************************************************************************** | 181 | /**************************************************************************** |
182 | * Driver-wide structs and misc. variables | 182 | * Driver-wide structs and misc. variables |
183 | */ | 183 | */ |
184 | 184 | ||
185 | struct ibm_struct; | 185 | struct ibm_struct; |
186 | 186 | ||
187 | struct tp_acpi_drv_struct { | 187 | struct tp_acpi_drv_struct { |
188 | const struct acpi_device_id *hid; | 188 | const struct acpi_device_id *hid; |
189 | struct acpi_driver *driver; | 189 | struct acpi_driver *driver; |
190 | 190 | ||
191 | void (*notify) (struct ibm_struct *, u32); | 191 | void (*notify) (struct ibm_struct *, u32); |
192 | acpi_handle *handle; | 192 | acpi_handle *handle; |
193 | u32 type; | 193 | u32 type; |
194 | struct acpi_device *device; | 194 | struct acpi_device *device; |
195 | }; | 195 | }; |
196 | 196 | ||
197 | struct ibm_struct { | 197 | struct ibm_struct { |
198 | char *name; | 198 | char *name; |
199 | 199 | ||
200 | int (*read) (char *); | 200 | int (*read) (char *); |
201 | int (*write) (char *); | 201 | int (*write) (char *); |
202 | void (*exit) (void); | 202 | void (*exit) (void); |
203 | void (*resume) (void); | 203 | void (*resume) (void); |
204 | void (*suspend) (pm_message_t state); | 204 | void (*suspend) (pm_message_t state); |
205 | 205 | ||
206 | struct list_head all_drivers; | 206 | struct list_head all_drivers; |
207 | 207 | ||
208 | struct tp_acpi_drv_struct *acpi; | 208 | struct tp_acpi_drv_struct *acpi; |
209 | 209 | ||
210 | struct { | 210 | struct { |
211 | u8 acpi_driver_registered:1; | 211 | u8 acpi_driver_registered:1; |
212 | u8 acpi_notify_installed:1; | 212 | u8 acpi_notify_installed:1; |
213 | u8 proc_created:1; | 213 | u8 proc_created:1; |
214 | u8 init_called:1; | 214 | u8 init_called:1; |
215 | u8 experimental:1; | 215 | u8 experimental:1; |
216 | } flags; | 216 | } flags; |
217 | }; | 217 | }; |
218 | 218 | ||
219 | struct ibm_init_struct { | 219 | struct ibm_init_struct { |
220 | char param[32]; | 220 | char param[32]; |
221 | 221 | ||
222 | int (*init) (struct ibm_init_struct *); | 222 | int (*init) (struct ibm_init_struct *); |
223 | struct ibm_struct *data; | 223 | struct ibm_struct *data; |
224 | }; | 224 | }; |
225 | 225 | ||
226 | static struct { | 226 | static struct { |
227 | #ifdef CONFIG_THINKPAD_ACPI_BAY | 227 | #ifdef CONFIG_THINKPAD_ACPI_BAY |
228 | u32 bay_status:1; | 228 | u32 bay_status:1; |
229 | u32 bay_eject:1; | 229 | u32 bay_eject:1; |
230 | u32 bay_status2:1; | 230 | u32 bay_status2:1; |
231 | u32 bay_eject2:1; | 231 | u32 bay_eject2:1; |
232 | #endif | 232 | #endif |
233 | u32 bluetooth:1; | 233 | u32 bluetooth:1; |
234 | u32 hotkey:1; | 234 | u32 hotkey:1; |
235 | u32 hotkey_mask:1; | 235 | u32 hotkey_mask:1; |
236 | u32 hotkey_wlsw:1; | 236 | u32 hotkey_wlsw:1; |
237 | u32 hotkey_tablet:1; | 237 | u32 hotkey_tablet:1; |
238 | u32 light:1; | 238 | u32 light:1; |
239 | u32 light_status:1; | 239 | u32 light_status:1; |
240 | u32 bright_16levels:1; | 240 | u32 bright_16levels:1; |
241 | u32 bright_acpimode:1; | 241 | u32 bright_acpimode:1; |
242 | u32 wan:1; | 242 | u32 wan:1; |
243 | u32 fan_ctrl_status_undef:1; | 243 | u32 fan_ctrl_status_undef:1; |
244 | u32 input_device_registered:1; | 244 | u32 input_device_registered:1; |
245 | u32 platform_drv_registered:1; | 245 | u32 platform_drv_registered:1; |
246 | u32 platform_drv_attrs_registered:1; | 246 | u32 platform_drv_attrs_registered:1; |
247 | u32 sensors_pdrv_registered:1; | 247 | u32 sensors_pdrv_registered:1; |
248 | u32 sensors_pdrv_attrs_registered:1; | 248 | u32 sensors_pdrv_attrs_registered:1; |
249 | u32 sensors_pdev_attrs_registered:1; | 249 | u32 sensors_pdev_attrs_registered:1; |
250 | u32 hotkey_poll_active:1; | 250 | u32 hotkey_poll_active:1; |
251 | } tp_features; | 251 | } tp_features; |
252 | 252 | ||
253 | static struct { | 253 | static struct { |
254 | u16 hotkey_mask_ff:1; | 254 | u16 hotkey_mask_ff:1; |
255 | u16 bright_cmos_ec_unsync:1; | 255 | u16 bright_cmos_ec_unsync:1; |
256 | } tp_warned; | 256 | } tp_warned; |
257 | 257 | ||
258 | struct thinkpad_id_data { | 258 | struct thinkpad_id_data { |
259 | unsigned int vendor; /* ThinkPad vendor: | 259 | unsigned int vendor; /* ThinkPad vendor: |
260 | * PCI_VENDOR_ID_IBM/PCI_VENDOR_ID_LENOVO */ | 260 | * PCI_VENDOR_ID_IBM/PCI_VENDOR_ID_LENOVO */ |
261 | 261 | ||
262 | char *bios_version_str; /* Something like 1ZET51WW (1.03z) */ | 262 | char *bios_version_str; /* Something like 1ZET51WW (1.03z) */ |
263 | char *ec_version_str; /* Something like 1ZHT51WW-1.04a */ | 263 | char *ec_version_str; /* Something like 1ZHT51WW-1.04a */ |
264 | 264 | ||
265 | u16 bios_model; /* Big Endian, TP-1Y = 0x5931, 0 = unknown */ | 265 | u16 bios_model; /* Big Endian, TP-1Y = 0x5931, 0 = unknown */ |
266 | u16 ec_model; | 266 | u16 ec_model; |
267 | 267 | ||
268 | char *model_str; /* ThinkPad T43 */ | 268 | char *model_str; /* ThinkPad T43 */ |
269 | char *nummodel_str; /* 9384A9C for a 9384-A9C model */ | 269 | char *nummodel_str; /* 9384A9C for a 9384-A9C model */ |
270 | }; | 270 | }; |
271 | static struct thinkpad_id_data thinkpad_id; | 271 | static struct thinkpad_id_data thinkpad_id; |
272 | 272 | ||
273 | static enum { | 273 | static enum { |
274 | TPACPI_LIFE_INIT = 0, | 274 | TPACPI_LIFE_INIT = 0, |
275 | TPACPI_LIFE_RUNNING, | 275 | TPACPI_LIFE_RUNNING, |
276 | TPACPI_LIFE_EXITING, | 276 | TPACPI_LIFE_EXITING, |
277 | } tpacpi_lifecycle; | 277 | } tpacpi_lifecycle; |
278 | 278 | ||
279 | static int experimental; | 279 | static int experimental; |
280 | static u32 dbg_level; | 280 | static u32 dbg_level; |
281 | 281 | ||
282 | static struct workqueue_struct *tpacpi_wq; | 282 | static struct workqueue_struct *tpacpi_wq; |
283 | 283 | ||
284 | /* Special LED class that can defer work */ | 284 | /* Special LED class that can defer work */ |
285 | struct tpacpi_led_classdev { | 285 | struct tpacpi_led_classdev { |
286 | struct led_classdev led_classdev; | 286 | struct led_classdev led_classdev; |
287 | struct work_struct work; | 287 | struct work_struct work; |
288 | enum led_brightness new_brightness; | 288 | enum led_brightness new_brightness; |
289 | unsigned int led; | 289 | unsigned int led; |
290 | }; | 290 | }; |
291 | 291 | ||
292 | /**************************************************************************** | 292 | /**************************************************************************** |
293 | **************************************************************************** | 293 | **************************************************************************** |
294 | * | 294 | * |
295 | * ACPI Helpers and device model | 295 | * ACPI Helpers and device model |
296 | * | 296 | * |
297 | **************************************************************************** | 297 | **************************************************************************** |
298 | ****************************************************************************/ | 298 | ****************************************************************************/ |
299 | 299 | ||
300 | /************************************************************************* | 300 | /************************************************************************* |
301 | * ACPI basic handles | 301 | * ACPI basic handles |
302 | */ | 302 | */ |
303 | 303 | ||
304 | static acpi_handle root_handle; | 304 | static acpi_handle root_handle; |
305 | 305 | ||
306 | #define TPACPI_HANDLE(object, parent, paths...) \ | 306 | #define TPACPI_HANDLE(object, parent, paths...) \ |
307 | static acpi_handle object##_handle; \ | 307 | static acpi_handle object##_handle; \ |
308 | static acpi_handle *object##_parent = &parent##_handle; \ | 308 | static acpi_handle *object##_parent = &parent##_handle; \ |
309 | static char *object##_path; \ | 309 | static char *object##_path; \ |
310 | static char *object##_paths[] = { paths } | 310 | static char *object##_paths[] = { paths } |
311 | 311 | ||
312 | TPACPI_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0", /* 240, 240x */ | 312 | TPACPI_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0", /* 240, 240x */ |
313 | "\\_SB.PCI.ISA.EC", /* 570 */ | 313 | "\\_SB.PCI.ISA.EC", /* 570 */ |
314 | "\\_SB.PCI0.ISA0.EC0", /* 600e/x, 770e, 770x */ | 314 | "\\_SB.PCI0.ISA0.EC0", /* 600e/x, 770e, 770x */ |
315 | "\\_SB.PCI0.ISA.EC", /* A21e, A2xm/p, T20-22, X20-21 */ | 315 | "\\_SB.PCI0.ISA.EC", /* A21e, A2xm/p, T20-22, X20-21 */ |
316 | "\\_SB.PCI0.AD4S.EC0", /* i1400, R30 */ | 316 | "\\_SB.PCI0.AD4S.EC0", /* i1400, R30 */ |
317 | "\\_SB.PCI0.ICH3.EC0", /* R31 */ | 317 | "\\_SB.PCI0.ICH3.EC0", /* R31 */ |
318 | "\\_SB.PCI0.LPC.EC", /* all others */ | 318 | "\\_SB.PCI0.LPC.EC", /* all others */ |
319 | ); | 319 | ); |
320 | 320 | ||
321 | TPACPI_HANDLE(ecrd, ec, "ECRD"); /* 570 */ | 321 | TPACPI_HANDLE(ecrd, ec, "ECRD"); /* 570 */ |
322 | TPACPI_HANDLE(ecwr, ec, "ECWR"); /* 570 */ | 322 | TPACPI_HANDLE(ecwr, ec, "ECWR"); /* 570 */ |
323 | 323 | ||
324 | TPACPI_HANDLE(cmos, root, "\\UCMS", /* R50, R50e, R50p, R51, */ | 324 | TPACPI_HANDLE(cmos, root, "\\UCMS", /* R50, R50e, R50p, R51, */ |
325 | /* T4x, X31, X40 */ | 325 | /* T4x, X31, X40 */ |
326 | "\\CMOS", /* A3x, G4x, R32, T23, T30, X22-24, X30 */ | 326 | "\\CMOS", /* A3x, G4x, R32, T23, T30, X22-24, X30 */ |
327 | "\\CMS", /* R40, R40e */ | 327 | "\\CMS", /* R40, R40e */ |
328 | ); /* all others */ | 328 | ); /* all others */ |
329 | 329 | ||
330 | TPACPI_HANDLE(hkey, ec, "\\_SB.HKEY", /* 600e/x, 770e, 770x */ | 330 | TPACPI_HANDLE(hkey, ec, "\\_SB.HKEY", /* 600e/x, 770e, 770x */ |
331 | "^HKEY", /* R30, R31 */ | 331 | "^HKEY", /* R30, R31 */ |
332 | "HKEY", /* all others */ | 332 | "HKEY", /* all others */ |
333 | ); /* 570 */ | 333 | ); /* 570 */ |
334 | 334 | ||
335 | TPACPI_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA", /* 570 */ | 335 | TPACPI_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA", /* 570 */ |
336 | "\\_SB.PCI0.AGP0.VID0", /* 600e/x, 770x */ | 336 | "\\_SB.PCI0.AGP0.VID0", /* 600e/x, 770x */ |
337 | "\\_SB.PCI0.VID0", /* 770e */ | 337 | "\\_SB.PCI0.VID0", /* 770e */ |
338 | "\\_SB.PCI0.VID", /* A21e, G4x, R50e, X30, X40 */ | 338 | "\\_SB.PCI0.VID", /* A21e, G4x, R50e, X30, X40 */ |
339 | "\\_SB.PCI0.AGP.VID", /* all others */ | 339 | "\\_SB.PCI0.AGP.VID", /* all others */ |
340 | ); /* R30, R31 */ | 340 | ); /* R30, R31 */ |
341 | 341 | ||
342 | 342 | ||
343 | /************************************************************************* | 343 | /************************************************************************* |
344 | * ACPI helpers | 344 | * ACPI helpers |
345 | */ | 345 | */ |
346 | 346 | ||
347 | static int acpi_evalf(acpi_handle handle, | 347 | static int acpi_evalf(acpi_handle handle, |
348 | void *res, char *method, char *fmt, ...) | 348 | void *res, char *method, char *fmt, ...) |
349 | { | 349 | { |
350 | char *fmt0 = fmt; | 350 | char *fmt0 = fmt; |
351 | struct acpi_object_list params; | 351 | struct acpi_object_list params; |
352 | union acpi_object in_objs[TPACPI_MAX_ACPI_ARGS]; | 352 | union acpi_object in_objs[TPACPI_MAX_ACPI_ARGS]; |
353 | struct acpi_buffer result, *resultp; | 353 | struct acpi_buffer result, *resultp; |
354 | union acpi_object out_obj; | 354 | union acpi_object out_obj; |
355 | acpi_status status; | 355 | acpi_status status; |
356 | va_list ap; | 356 | va_list ap; |
357 | char res_type; | 357 | char res_type; |
358 | int success; | 358 | int success; |
359 | int quiet; | 359 | int quiet; |
360 | 360 | ||
361 | if (!*fmt) { | 361 | if (!*fmt) { |
362 | printk(TPACPI_ERR "acpi_evalf() called with empty format\n"); | 362 | printk(TPACPI_ERR "acpi_evalf() called with empty format\n"); |
363 | return 0; | 363 | return 0; |
364 | } | 364 | } |
365 | 365 | ||
366 | if (*fmt == 'q') { | 366 | if (*fmt == 'q') { |
367 | quiet = 1; | 367 | quiet = 1; |
368 | fmt++; | 368 | fmt++; |
369 | } else | 369 | } else |
370 | quiet = 0; | 370 | quiet = 0; |
371 | 371 | ||
372 | res_type = *(fmt++); | 372 | res_type = *(fmt++); |
373 | 373 | ||
374 | params.count = 0; | 374 | params.count = 0; |
375 | params.pointer = &in_objs[0]; | 375 | params.pointer = &in_objs[0]; |
376 | 376 | ||
377 | va_start(ap, fmt); | 377 | va_start(ap, fmt); |
378 | while (*fmt) { | 378 | while (*fmt) { |
379 | char c = *(fmt++); | 379 | char c = *(fmt++); |
380 | switch (c) { | 380 | switch (c) { |
381 | case 'd': /* int */ | 381 | case 'd': /* int */ |
382 | in_objs[params.count].integer.value = va_arg(ap, int); | 382 | in_objs[params.count].integer.value = va_arg(ap, int); |
383 | in_objs[params.count++].type = ACPI_TYPE_INTEGER; | 383 | in_objs[params.count++].type = ACPI_TYPE_INTEGER; |
384 | break; | 384 | break; |
385 | /* add more types as needed */ | 385 | /* add more types as needed */ |
386 | default: | 386 | default: |
387 | printk(TPACPI_ERR "acpi_evalf() called " | 387 | printk(TPACPI_ERR "acpi_evalf() called " |
388 | "with invalid format character '%c'\n", c); | 388 | "with invalid format character '%c'\n", c); |
389 | return 0; | 389 | return 0; |
390 | } | 390 | } |
391 | } | 391 | } |
392 | va_end(ap); | 392 | va_end(ap); |
393 | 393 | ||
394 | if (res_type != 'v') { | 394 | if (res_type != 'v') { |
395 | result.length = sizeof(out_obj); | 395 | result.length = sizeof(out_obj); |
396 | result.pointer = &out_obj; | 396 | result.pointer = &out_obj; |
397 | resultp = &result; | 397 | resultp = &result; |
398 | } else | 398 | } else |
399 | resultp = NULL; | 399 | resultp = NULL; |
400 | 400 | ||
401 | status = acpi_evaluate_object(handle, method, ¶ms, resultp); | 401 | status = acpi_evaluate_object(handle, method, ¶ms, resultp); |
402 | 402 | ||
403 | switch (res_type) { | 403 | switch (res_type) { |
404 | case 'd': /* int */ | 404 | case 'd': /* int */ |
405 | if (res) | 405 | if (res) |
406 | *(int *)res = out_obj.integer.value; | 406 | *(int *)res = out_obj.integer.value; |
407 | success = status == AE_OK && out_obj.type == ACPI_TYPE_INTEGER; | 407 | success = status == AE_OK && out_obj.type == ACPI_TYPE_INTEGER; |
408 | break; | 408 | break; |
409 | case 'v': /* void */ | 409 | case 'v': /* void */ |
410 | success = status == AE_OK; | 410 | success = status == AE_OK; |
411 | break; | 411 | break; |
412 | /* add more types as needed */ | 412 | /* add more types as needed */ |
413 | default: | 413 | default: |
414 | printk(TPACPI_ERR "acpi_evalf() called " | 414 | printk(TPACPI_ERR "acpi_evalf() called " |
415 | "with invalid format character '%c'\n", res_type); | 415 | "with invalid format character '%c'\n", res_type); |
416 | return 0; | 416 | return 0; |
417 | } | 417 | } |
418 | 418 | ||
419 | if (!success && !quiet) | 419 | if (!success && !quiet) |
420 | printk(TPACPI_ERR "acpi_evalf(%s, %s, ...) failed: %d\n", | 420 | printk(TPACPI_ERR "acpi_evalf(%s, %s, ...) failed: %d\n", |
421 | method, fmt0, status); | 421 | method, fmt0, status); |
422 | 422 | ||
423 | return success; | 423 | return success; |
424 | } | 424 | } |
425 | 425 | ||
426 | static int acpi_ec_read(int i, u8 *p) | 426 | static int acpi_ec_read(int i, u8 *p) |
427 | { | 427 | { |
428 | int v; | 428 | int v; |
429 | 429 | ||
430 | if (ecrd_handle) { | 430 | if (ecrd_handle) { |
431 | if (!acpi_evalf(ecrd_handle, &v, NULL, "dd", i)) | 431 | if (!acpi_evalf(ecrd_handle, &v, NULL, "dd", i)) |
432 | return 0; | 432 | return 0; |
433 | *p = v; | 433 | *p = v; |
434 | } else { | 434 | } else { |
435 | if (ec_read(i, p) < 0) | 435 | if (ec_read(i, p) < 0) |
436 | return 0; | 436 | return 0; |
437 | } | 437 | } |
438 | 438 | ||
439 | return 1; | 439 | return 1; |
440 | } | 440 | } |
441 | 441 | ||
442 | static int acpi_ec_write(int i, u8 v) | 442 | static int acpi_ec_write(int i, u8 v) |
443 | { | 443 | { |
444 | if (ecwr_handle) { | 444 | if (ecwr_handle) { |
445 | if (!acpi_evalf(ecwr_handle, NULL, NULL, "vdd", i, v)) | 445 | if (!acpi_evalf(ecwr_handle, NULL, NULL, "vdd", i, v)) |
446 | return 0; | 446 | return 0; |
447 | } else { | 447 | } else { |
448 | if (ec_write(i, v) < 0) | 448 | if (ec_write(i, v) < 0) |
449 | return 0; | 449 | return 0; |
450 | } | 450 | } |
451 | 451 | ||
452 | return 1; | 452 | return 1; |
453 | } | 453 | } |
454 | 454 | ||
455 | #if defined(CONFIG_THINKPAD_ACPI_DOCK) || defined(CONFIG_THINKPAD_ACPI_BAY) | 455 | #if defined(CONFIG_THINKPAD_ACPI_DOCK) || defined(CONFIG_THINKPAD_ACPI_BAY) |
456 | static int _sta(acpi_handle handle) | 456 | static int _sta(acpi_handle handle) |
457 | { | 457 | { |
458 | int status; | 458 | int status; |
459 | 459 | ||
460 | if (!handle || !acpi_evalf(handle, &status, "_STA", "d")) | 460 | if (!handle || !acpi_evalf(handle, &status, "_STA", "d")) |
461 | status = 0; | 461 | status = 0; |
462 | 462 | ||
463 | return status; | 463 | return status; |
464 | } | 464 | } |
465 | #endif | 465 | #endif |
466 | 466 | ||
467 | static int issue_thinkpad_cmos_command(int cmos_cmd) | 467 | static int issue_thinkpad_cmos_command(int cmos_cmd) |
468 | { | 468 | { |
469 | if (!cmos_handle) | 469 | if (!cmos_handle) |
470 | return -ENXIO; | 470 | return -ENXIO; |
471 | 471 | ||
472 | if (!acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd)) | 472 | if (!acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd)) |
473 | return -EIO; | 473 | return -EIO; |
474 | 474 | ||
475 | return 0; | 475 | return 0; |
476 | } | 476 | } |
477 | 477 | ||
478 | /************************************************************************* | 478 | /************************************************************************* |
479 | * ACPI device model | 479 | * ACPI device model |
480 | */ | 480 | */ |
481 | 481 | ||
482 | #define TPACPI_ACPIHANDLE_INIT(object) \ | 482 | #define TPACPI_ACPIHANDLE_INIT(object) \ |
483 | drv_acpi_handle_init(#object, &object##_handle, *object##_parent, \ | 483 | drv_acpi_handle_init(#object, &object##_handle, *object##_parent, \ |
484 | object##_paths, ARRAY_SIZE(object##_paths), &object##_path) | 484 | object##_paths, ARRAY_SIZE(object##_paths), &object##_path) |
485 | 485 | ||
486 | static void drv_acpi_handle_init(char *name, | 486 | static void drv_acpi_handle_init(char *name, |
487 | acpi_handle *handle, acpi_handle parent, | 487 | acpi_handle *handle, acpi_handle parent, |
488 | char **paths, int num_paths, char **path) | 488 | char **paths, int num_paths, char **path) |
489 | { | 489 | { |
490 | int i; | 490 | int i; |
491 | acpi_status status; | 491 | acpi_status status; |
492 | 492 | ||
493 | vdbg_printk(TPACPI_DBG_INIT, "trying to locate ACPI handle for %s\n", | 493 | vdbg_printk(TPACPI_DBG_INIT, "trying to locate ACPI handle for %s\n", |
494 | name); | 494 | name); |
495 | 495 | ||
496 | for (i = 0; i < num_paths; i++) { | 496 | for (i = 0; i < num_paths; i++) { |
497 | status = acpi_get_handle(parent, paths[i], handle); | 497 | status = acpi_get_handle(parent, paths[i], handle); |
498 | if (ACPI_SUCCESS(status)) { | 498 | if (ACPI_SUCCESS(status)) { |
499 | *path = paths[i]; | 499 | *path = paths[i]; |
500 | dbg_printk(TPACPI_DBG_INIT, | 500 | dbg_printk(TPACPI_DBG_INIT, |
501 | "Found ACPI handle %s for %s\n", | 501 | "Found ACPI handle %s for %s\n", |
502 | *path, name); | 502 | *path, name); |
503 | return; | 503 | return; |
504 | } | 504 | } |
505 | } | 505 | } |
506 | 506 | ||
507 | vdbg_printk(TPACPI_DBG_INIT, "ACPI handle for %s not found\n", | 507 | vdbg_printk(TPACPI_DBG_INIT, "ACPI handle for %s not found\n", |
508 | name); | 508 | name); |
509 | *handle = NULL; | 509 | *handle = NULL; |
510 | } | 510 | } |
511 | 511 | ||
512 | static void dispatch_acpi_notify(acpi_handle handle, u32 event, void *data) | 512 | static void dispatch_acpi_notify(acpi_handle handle, u32 event, void *data) |
513 | { | 513 | { |
514 | struct ibm_struct *ibm = data; | 514 | struct ibm_struct *ibm = data; |
515 | 515 | ||
516 | if (tpacpi_lifecycle != TPACPI_LIFE_RUNNING) | 516 | if (tpacpi_lifecycle != TPACPI_LIFE_RUNNING) |
517 | return; | 517 | return; |
518 | 518 | ||
519 | if (!ibm || !ibm->acpi || !ibm->acpi->notify) | 519 | if (!ibm || !ibm->acpi || !ibm->acpi->notify) |
520 | return; | 520 | return; |
521 | 521 | ||
522 | ibm->acpi->notify(ibm, event); | 522 | ibm->acpi->notify(ibm, event); |
523 | } | 523 | } |
524 | 524 | ||
525 | static int __init setup_acpi_notify(struct ibm_struct *ibm) | 525 | static int __init setup_acpi_notify(struct ibm_struct *ibm) |
526 | { | 526 | { |
527 | acpi_status status; | 527 | acpi_status status; |
528 | int rc; | 528 | int rc; |
529 | 529 | ||
530 | BUG_ON(!ibm->acpi); | 530 | BUG_ON(!ibm->acpi); |
531 | 531 | ||
532 | if (!*ibm->acpi->handle) | 532 | if (!*ibm->acpi->handle) |
533 | return 0; | 533 | return 0; |
534 | 534 | ||
535 | vdbg_printk(TPACPI_DBG_INIT, | 535 | vdbg_printk(TPACPI_DBG_INIT, |
536 | "setting up ACPI notify for %s\n", ibm->name); | 536 | "setting up ACPI notify for %s\n", ibm->name); |
537 | 537 | ||
538 | rc = acpi_bus_get_device(*ibm->acpi->handle, &ibm->acpi->device); | 538 | rc = acpi_bus_get_device(*ibm->acpi->handle, &ibm->acpi->device); |
539 | if (rc < 0) { | 539 | if (rc < 0) { |
540 | printk(TPACPI_ERR "acpi_bus_get_device(%s) failed: %d\n", | 540 | printk(TPACPI_ERR "acpi_bus_get_device(%s) failed: %d\n", |
541 | ibm->name, rc); | 541 | ibm->name, rc); |
542 | return -ENODEV; | 542 | return -ENODEV; |
543 | } | 543 | } |
544 | 544 | ||
545 | ibm->acpi->device->driver_data = ibm; | 545 | ibm->acpi->device->driver_data = ibm; |
546 | sprintf(acpi_device_class(ibm->acpi->device), "%s/%s", | 546 | sprintf(acpi_device_class(ibm->acpi->device), "%s/%s", |
547 | TPACPI_ACPI_EVENT_PREFIX, | 547 | TPACPI_ACPI_EVENT_PREFIX, |
548 | ibm->name); | 548 | ibm->name); |
549 | 549 | ||
550 | status = acpi_install_notify_handler(*ibm->acpi->handle, | 550 | status = acpi_install_notify_handler(*ibm->acpi->handle, |
551 | ibm->acpi->type, dispatch_acpi_notify, ibm); | 551 | ibm->acpi->type, dispatch_acpi_notify, ibm); |
552 | if (ACPI_FAILURE(status)) { | 552 | if (ACPI_FAILURE(status)) { |
553 | if (status == AE_ALREADY_EXISTS) { | 553 | if (status == AE_ALREADY_EXISTS) { |
554 | printk(TPACPI_NOTICE | 554 | printk(TPACPI_NOTICE |
555 | "another device driver is already " | 555 | "another device driver is already " |
556 | "handling %s events\n", ibm->name); | 556 | "handling %s events\n", ibm->name); |
557 | } else { | 557 | } else { |
558 | printk(TPACPI_ERR | 558 | printk(TPACPI_ERR |
559 | "acpi_install_notify_handler(%s) failed: %d\n", | 559 | "acpi_install_notify_handler(%s) failed: %d\n", |
560 | ibm->name, status); | 560 | ibm->name, status); |
561 | } | 561 | } |
562 | return -ENODEV; | 562 | return -ENODEV; |
563 | } | 563 | } |
564 | ibm->flags.acpi_notify_installed = 1; | 564 | ibm->flags.acpi_notify_installed = 1; |
565 | return 0; | 565 | return 0; |
566 | } | 566 | } |
567 | 567 | ||
568 | static int __init tpacpi_device_add(struct acpi_device *device) | 568 | static int __init tpacpi_device_add(struct acpi_device *device) |
569 | { | 569 | { |
570 | return 0; | 570 | return 0; |
571 | } | 571 | } |
572 | 572 | ||
573 | static int __init register_tpacpi_subdriver(struct ibm_struct *ibm) | 573 | static int __init register_tpacpi_subdriver(struct ibm_struct *ibm) |
574 | { | 574 | { |
575 | int rc; | 575 | int rc; |
576 | 576 | ||
577 | dbg_printk(TPACPI_DBG_INIT, | 577 | dbg_printk(TPACPI_DBG_INIT, |
578 | "registering %s as an ACPI driver\n", ibm->name); | 578 | "registering %s as an ACPI driver\n", ibm->name); |
579 | 579 | ||
580 | BUG_ON(!ibm->acpi); | 580 | BUG_ON(!ibm->acpi); |
581 | 581 | ||
582 | ibm->acpi->driver = kzalloc(sizeof(struct acpi_driver), GFP_KERNEL); | 582 | ibm->acpi->driver = kzalloc(sizeof(struct acpi_driver), GFP_KERNEL); |
583 | if (!ibm->acpi->driver) { | 583 | if (!ibm->acpi->driver) { |
584 | printk(TPACPI_ERR | 584 | printk(TPACPI_ERR |
585 | "failed to allocate memory for ibm->acpi->driver\n"); | 585 | "failed to allocate memory for ibm->acpi->driver\n"); |
586 | return -ENOMEM; | 586 | return -ENOMEM; |
587 | } | 587 | } |
588 | 588 | ||
589 | sprintf(ibm->acpi->driver->name, "%s_%s", TPACPI_NAME, ibm->name); | 589 | sprintf(ibm->acpi->driver->name, "%s_%s", TPACPI_NAME, ibm->name); |
590 | ibm->acpi->driver->ids = ibm->acpi->hid; | 590 | ibm->acpi->driver->ids = ibm->acpi->hid; |
591 | 591 | ||
592 | ibm->acpi->driver->ops.add = &tpacpi_device_add; | 592 | ibm->acpi->driver->ops.add = &tpacpi_device_add; |
593 | 593 | ||
594 | rc = acpi_bus_register_driver(ibm->acpi->driver); | 594 | rc = acpi_bus_register_driver(ibm->acpi->driver); |
595 | if (rc < 0) { | 595 | if (rc < 0) { |
596 | printk(TPACPI_ERR "acpi_bus_register_driver(%s) failed: %d\n", | 596 | printk(TPACPI_ERR "acpi_bus_register_driver(%s) failed: %d\n", |
597 | ibm->name, rc); | 597 | ibm->name, rc); |
598 | kfree(ibm->acpi->driver); | 598 | kfree(ibm->acpi->driver); |
599 | ibm->acpi->driver = NULL; | 599 | ibm->acpi->driver = NULL; |
600 | } else if (!rc) | 600 | } else if (!rc) |
601 | ibm->flags.acpi_driver_registered = 1; | 601 | ibm->flags.acpi_driver_registered = 1; |
602 | 602 | ||
603 | return rc; | 603 | return rc; |
604 | } | 604 | } |
605 | 605 | ||
606 | 606 | ||
607 | /**************************************************************************** | 607 | /**************************************************************************** |
608 | **************************************************************************** | 608 | **************************************************************************** |
609 | * | 609 | * |
610 | * Procfs Helpers | 610 | * Procfs Helpers |
611 | * | 611 | * |
612 | **************************************************************************** | 612 | **************************************************************************** |
613 | ****************************************************************************/ | 613 | ****************************************************************************/ |
614 | 614 | ||
615 | static int dispatch_procfs_read(char *page, char **start, off_t off, | 615 | static int dispatch_procfs_read(char *page, char **start, off_t off, |
616 | int count, int *eof, void *data) | 616 | int count, int *eof, void *data) |
617 | { | 617 | { |
618 | struct ibm_struct *ibm = data; | 618 | struct ibm_struct *ibm = data; |
619 | int len; | 619 | int len; |
620 | 620 | ||
621 | if (!ibm || !ibm->read) | 621 | if (!ibm || !ibm->read) |
622 | return -EINVAL; | 622 | return -EINVAL; |
623 | 623 | ||
624 | len = ibm->read(page); | 624 | len = ibm->read(page); |
625 | if (len < 0) | 625 | if (len < 0) |
626 | return len; | 626 | return len; |
627 | 627 | ||
628 | if (len <= off + count) | 628 | if (len <= off + count) |
629 | *eof = 1; | 629 | *eof = 1; |
630 | *start = page + off; | 630 | *start = page + off; |
631 | len -= off; | 631 | len -= off; |
632 | if (len > count) | 632 | if (len > count) |
633 | len = count; | 633 | len = count; |
634 | if (len < 0) | 634 | if (len < 0) |
635 | len = 0; | 635 | len = 0; |
636 | 636 | ||
637 | return len; | 637 | return len; |
638 | } | 638 | } |
639 | 639 | ||
640 | static int dispatch_procfs_write(struct file *file, | 640 | static int dispatch_procfs_write(struct file *file, |
641 | const char __user *userbuf, | 641 | const char __user *userbuf, |
642 | unsigned long count, void *data) | 642 | unsigned long count, void *data) |
643 | { | 643 | { |
644 | struct ibm_struct *ibm = data; | 644 | struct ibm_struct *ibm = data; |
645 | char *kernbuf; | 645 | char *kernbuf; |
646 | int ret; | 646 | int ret; |
647 | 647 | ||
648 | if (!ibm || !ibm->write) | 648 | if (!ibm || !ibm->write) |
649 | return -EINVAL; | 649 | return -EINVAL; |
650 | 650 | ||
651 | kernbuf = kmalloc(count + 2, GFP_KERNEL); | 651 | kernbuf = kmalloc(count + 2, GFP_KERNEL); |
652 | if (!kernbuf) | 652 | if (!kernbuf) |
653 | return -ENOMEM; | 653 | return -ENOMEM; |
654 | 654 | ||
655 | if (copy_from_user(kernbuf, userbuf, count)) { | 655 | if (copy_from_user(kernbuf, userbuf, count)) { |
656 | kfree(kernbuf); | 656 | kfree(kernbuf); |
657 | return -EFAULT; | 657 | return -EFAULT; |
658 | } | 658 | } |
659 | 659 | ||
660 | kernbuf[count] = 0; | 660 | kernbuf[count] = 0; |
661 | strcat(kernbuf, ","); | 661 | strcat(kernbuf, ","); |
662 | ret = ibm->write(kernbuf); | 662 | ret = ibm->write(kernbuf); |
663 | if (ret == 0) | 663 | if (ret == 0) |
664 | ret = count; | 664 | ret = count; |
665 | 665 | ||
666 | kfree(kernbuf); | 666 | kfree(kernbuf); |
667 | 667 | ||
668 | return ret; | 668 | return ret; |
669 | } | 669 | } |
670 | 670 | ||
671 | static char *next_cmd(char **cmds) | 671 | static char *next_cmd(char **cmds) |
672 | { | 672 | { |
673 | char *start = *cmds; | 673 | char *start = *cmds; |
674 | char *end; | 674 | char *end; |
675 | 675 | ||
676 | while ((end = strchr(start, ',')) && end == start) | 676 | while ((end = strchr(start, ',')) && end == start) |
677 | start = end + 1; | 677 | start = end + 1; |
678 | 678 | ||
679 | if (!end) | 679 | if (!end) |
680 | return NULL; | 680 | return NULL; |
681 | 681 | ||
682 | *end = 0; | 682 | *end = 0; |
683 | *cmds = end + 1; | 683 | *cmds = end + 1; |
684 | return start; | 684 | return start; |
685 | } | 685 | } |
686 | 686 | ||
687 | 687 | ||
688 | /**************************************************************************** | 688 | /**************************************************************************** |
689 | **************************************************************************** | 689 | **************************************************************************** |
690 | * | 690 | * |
691 | * Device model: input, hwmon and platform | 691 | * Device model: input, hwmon and platform |
692 | * | 692 | * |
693 | **************************************************************************** | 693 | **************************************************************************** |
694 | ****************************************************************************/ | 694 | ****************************************************************************/ |
695 | 695 | ||
696 | static struct platform_device *tpacpi_pdev; | 696 | static struct platform_device *tpacpi_pdev; |
697 | static struct platform_device *tpacpi_sensors_pdev; | 697 | static struct platform_device *tpacpi_sensors_pdev; |
698 | static struct device *tpacpi_hwmon; | 698 | static struct device *tpacpi_hwmon; |
699 | static struct input_dev *tpacpi_inputdev; | 699 | static struct input_dev *tpacpi_inputdev; |
700 | static struct mutex tpacpi_inputdev_send_mutex; | 700 | static struct mutex tpacpi_inputdev_send_mutex; |
701 | static LIST_HEAD(tpacpi_all_drivers); | 701 | static LIST_HEAD(tpacpi_all_drivers); |
702 | 702 | ||
703 | static int tpacpi_suspend_handler(struct platform_device *pdev, | 703 | static int tpacpi_suspend_handler(struct platform_device *pdev, |
704 | pm_message_t state) | 704 | pm_message_t state) |
705 | { | 705 | { |
706 | struct ibm_struct *ibm, *itmp; | 706 | struct ibm_struct *ibm, *itmp; |
707 | 707 | ||
708 | list_for_each_entry_safe(ibm, itmp, | 708 | list_for_each_entry_safe(ibm, itmp, |
709 | &tpacpi_all_drivers, | 709 | &tpacpi_all_drivers, |
710 | all_drivers) { | 710 | all_drivers) { |
711 | if (ibm->suspend) | 711 | if (ibm->suspend) |
712 | (ibm->suspend)(state); | 712 | (ibm->suspend)(state); |
713 | } | 713 | } |
714 | 714 | ||
715 | return 0; | 715 | return 0; |
716 | } | 716 | } |
717 | 717 | ||
718 | static int tpacpi_resume_handler(struct platform_device *pdev) | 718 | static int tpacpi_resume_handler(struct platform_device *pdev) |
719 | { | 719 | { |
720 | struct ibm_struct *ibm, *itmp; | 720 | struct ibm_struct *ibm, *itmp; |
721 | 721 | ||
722 | list_for_each_entry_safe(ibm, itmp, | 722 | list_for_each_entry_safe(ibm, itmp, |
723 | &tpacpi_all_drivers, | 723 | &tpacpi_all_drivers, |
724 | all_drivers) { | 724 | all_drivers) { |
725 | if (ibm->resume) | 725 | if (ibm->resume) |
726 | (ibm->resume)(); | 726 | (ibm->resume)(); |
727 | } | 727 | } |
728 | 728 | ||
729 | return 0; | 729 | return 0; |
730 | } | 730 | } |
731 | 731 | ||
732 | static struct platform_driver tpacpi_pdriver = { | 732 | static struct platform_driver tpacpi_pdriver = { |
733 | .driver = { | 733 | .driver = { |
734 | .name = TPACPI_DRVR_NAME, | 734 | .name = TPACPI_DRVR_NAME, |
735 | .owner = THIS_MODULE, | 735 | .owner = THIS_MODULE, |
736 | }, | 736 | }, |
737 | .suspend = tpacpi_suspend_handler, | 737 | .suspend = tpacpi_suspend_handler, |
738 | .resume = tpacpi_resume_handler, | 738 | .resume = tpacpi_resume_handler, |
739 | }; | 739 | }; |
740 | 740 | ||
741 | static struct platform_driver tpacpi_hwmon_pdriver = { | 741 | static struct platform_driver tpacpi_hwmon_pdriver = { |
742 | .driver = { | 742 | .driver = { |
743 | .name = TPACPI_HWMON_DRVR_NAME, | 743 | .name = TPACPI_HWMON_DRVR_NAME, |
744 | .owner = THIS_MODULE, | 744 | .owner = THIS_MODULE, |
745 | }, | 745 | }, |
746 | }; | 746 | }; |
747 | 747 | ||
748 | /************************************************************************* | 748 | /************************************************************************* |
749 | * sysfs support helpers | 749 | * sysfs support helpers |
750 | */ | 750 | */ |
751 | 751 | ||
752 | struct attribute_set { | 752 | struct attribute_set { |
753 | unsigned int members, max_members; | 753 | unsigned int members, max_members; |
754 | struct attribute_group group; | 754 | struct attribute_group group; |
755 | }; | 755 | }; |
756 | 756 | ||
757 | struct attribute_set_obj { | 757 | struct attribute_set_obj { |
758 | struct attribute_set s; | 758 | struct attribute_set s; |
759 | struct attribute *a; | 759 | struct attribute *a; |
760 | } __attribute__((packed)); | 760 | } __attribute__((packed)); |
761 | 761 | ||
762 | static struct attribute_set *create_attr_set(unsigned int max_members, | 762 | static struct attribute_set *create_attr_set(unsigned int max_members, |
763 | const char *name) | 763 | const char *name) |
764 | { | 764 | { |
765 | struct attribute_set_obj *sobj; | 765 | struct attribute_set_obj *sobj; |
766 | 766 | ||
767 | if (max_members == 0) | 767 | if (max_members == 0) |
768 | return NULL; | 768 | return NULL; |
769 | 769 | ||
770 | /* Allocates space for implicit NULL at the end too */ | 770 | /* Allocates space for implicit NULL at the end too */ |
771 | sobj = kzalloc(sizeof(struct attribute_set_obj) + | 771 | sobj = kzalloc(sizeof(struct attribute_set_obj) + |
772 | max_members * sizeof(struct attribute *), | 772 | max_members * sizeof(struct attribute *), |
773 | GFP_KERNEL); | 773 | GFP_KERNEL); |
774 | if (!sobj) | 774 | if (!sobj) |
775 | return NULL; | 775 | return NULL; |
776 | sobj->s.max_members = max_members; | 776 | sobj->s.max_members = max_members; |
777 | sobj->s.group.attrs = &sobj->a; | 777 | sobj->s.group.attrs = &sobj->a; |
778 | sobj->s.group.name = name; | 778 | sobj->s.group.name = name; |
779 | 779 | ||
780 | return &sobj->s; | 780 | return &sobj->s; |
781 | } | 781 | } |
782 | 782 | ||
783 | #define destroy_attr_set(_set) \ | 783 | #define destroy_attr_set(_set) \ |
784 | kfree(_set); | 784 | kfree(_set); |
785 | 785 | ||
786 | /* not multi-threaded safe, use it in a single thread per set */ | 786 | /* not multi-threaded safe, use it in a single thread per set */ |
787 | static int add_to_attr_set(struct attribute_set *s, struct attribute *attr) | 787 | static int add_to_attr_set(struct attribute_set *s, struct attribute *attr) |
788 | { | 788 | { |
789 | if (!s || !attr) | 789 | if (!s || !attr) |
790 | return -EINVAL; | 790 | return -EINVAL; |
791 | 791 | ||
792 | if (s->members >= s->max_members) | 792 | if (s->members >= s->max_members) |
793 | return -ENOMEM; | 793 | return -ENOMEM; |
794 | 794 | ||
795 | s->group.attrs[s->members] = attr; | 795 | s->group.attrs[s->members] = attr; |
796 | s->members++; | 796 | s->members++; |
797 | 797 | ||
798 | return 0; | 798 | return 0; |
799 | } | 799 | } |
800 | 800 | ||
801 | static int add_many_to_attr_set(struct attribute_set *s, | 801 | static int add_many_to_attr_set(struct attribute_set *s, |
802 | struct attribute **attr, | 802 | struct attribute **attr, |
803 | unsigned int count) | 803 | unsigned int count) |
804 | { | 804 | { |
805 | int i, res; | 805 | int i, res; |
806 | 806 | ||
807 | for (i = 0; i < count; i++) { | 807 | for (i = 0; i < count; i++) { |
808 | res = add_to_attr_set(s, attr[i]); | 808 | res = add_to_attr_set(s, attr[i]); |
809 | if (res) | 809 | if (res) |
810 | return res; | 810 | return res; |
811 | } | 811 | } |
812 | 812 | ||
813 | return 0; | 813 | return 0; |
814 | } | 814 | } |
815 | 815 | ||
816 | static void delete_attr_set(struct attribute_set *s, struct kobject *kobj) | 816 | static void delete_attr_set(struct attribute_set *s, struct kobject *kobj) |
817 | { | 817 | { |
818 | sysfs_remove_group(kobj, &s->group); | 818 | sysfs_remove_group(kobj, &s->group); |
819 | destroy_attr_set(s); | 819 | destroy_attr_set(s); |
820 | } | 820 | } |
821 | 821 | ||
822 | #define register_attr_set_with_sysfs(_attr_set, _kobj) \ | 822 | #define register_attr_set_with_sysfs(_attr_set, _kobj) \ |
823 | sysfs_create_group(_kobj, &_attr_set->group) | 823 | sysfs_create_group(_kobj, &_attr_set->group) |
824 | 824 | ||
825 | static int parse_strtoul(const char *buf, | 825 | static int parse_strtoul(const char *buf, |
826 | unsigned long max, unsigned long *value) | 826 | unsigned long max, unsigned long *value) |
827 | { | 827 | { |
828 | char *endp; | 828 | char *endp; |
829 | 829 | ||
830 | while (*buf && isspace(*buf)) | 830 | while (*buf && isspace(*buf)) |
831 | buf++; | 831 | buf++; |
832 | *value = simple_strtoul(buf, &endp, 0); | 832 | *value = simple_strtoul(buf, &endp, 0); |
833 | while (*endp && isspace(*endp)) | 833 | while (*endp && isspace(*endp)) |
834 | endp++; | 834 | endp++; |
835 | if (*endp || *value > max) | 835 | if (*endp || *value > max) |
836 | return -EINVAL; | 836 | return -EINVAL; |
837 | 837 | ||
838 | return 0; | 838 | return 0; |
839 | } | 839 | } |
840 | 840 | ||
841 | static void tpacpi_disable_brightness_delay(void) | 841 | static void tpacpi_disable_brightness_delay(void) |
842 | { | 842 | { |
843 | if (acpi_evalf(hkey_handle, NULL, "PWMS", "qvd", 0)) | 843 | if (acpi_evalf(hkey_handle, NULL, "PWMS", "qvd", 0)) |
844 | printk(TPACPI_NOTICE | 844 | printk(TPACPI_NOTICE |
845 | "ACPI backlight control delay disabled\n"); | 845 | "ACPI backlight control delay disabled\n"); |
846 | } | 846 | } |
847 | 847 | ||
848 | static int __init tpacpi_query_bcl_levels(acpi_handle handle) | 848 | static int __init tpacpi_query_bcl_levels(acpi_handle handle) |
849 | { | 849 | { |
850 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | 850 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
851 | union acpi_object *obj; | 851 | union acpi_object *obj; |
852 | int rc; | 852 | int rc; |
853 | 853 | ||
854 | if (ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buffer))) { | 854 | if (ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buffer))) { |
855 | obj = (union acpi_object *)buffer.pointer; | 855 | obj = (union acpi_object *)buffer.pointer; |
856 | if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) { | 856 | if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) { |
857 | printk(TPACPI_ERR "Unknown _BCL data, " | 857 | printk(TPACPI_ERR "Unknown _BCL data, " |
858 | "please report this to %s\n", TPACPI_MAIL); | 858 | "please report this to %s\n", TPACPI_MAIL); |
859 | rc = 0; | 859 | rc = 0; |
860 | } else { | 860 | } else { |
861 | rc = obj->package.count; | 861 | rc = obj->package.count; |
862 | } | 862 | } |
863 | } else { | 863 | } else { |
864 | return 0; | 864 | return 0; |
865 | } | 865 | } |
866 | 866 | ||
867 | kfree(buffer.pointer); | 867 | kfree(buffer.pointer); |
868 | return rc; | 868 | return rc; |
869 | } | 869 | } |
870 | 870 | ||
871 | static acpi_status __init tpacpi_acpi_walk_find_bcl(acpi_handle handle, | 871 | static acpi_status __init tpacpi_acpi_walk_find_bcl(acpi_handle handle, |
872 | u32 lvl, void *context, void **rv) | 872 | u32 lvl, void *context, void **rv) |
873 | { | 873 | { |
874 | char name[ACPI_PATH_SEGMENT_LENGTH]; | 874 | char name[ACPI_PATH_SEGMENT_LENGTH]; |
875 | struct acpi_buffer buffer = { sizeof(name), &name }; | 875 | struct acpi_buffer buffer = { sizeof(name), &name }; |
876 | 876 | ||
877 | if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) && | 877 | if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) && |
878 | !strncmp("_BCL", name, sizeof(name) - 1)) { | 878 | !strncmp("_BCL", name, sizeof(name) - 1)) { |
879 | BUG_ON(!rv || !*rv); | 879 | BUG_ON(!rv || !*rv); |
880 | **(int **)rv = tpacpi_query_bcl_levels(handle); | 880 | **(int **)rv = tpacpi_query_bcl_levels(handle); |
881 | return AE_CTRL_TERMINATE; | 881 | return AE_CTRL_TERMINATE; |
882 | } else { | 882 | } else { |
883 | return AE_OK; | 883 | return AE_OK; |
884 | } | 884 | } |
885 | } | 885 | } |
886 | 886 | ||
887 | /* | 887 | /* |
888 | * Returns 0 (no ACPI _BCL or _BCL invalid), or size of brightness map | 888 | * Returns 0 (no ACPI _BCL or _BCL invalid), or size of brightness map |
889 | */ | 889 | */ |
890 | static int __init tpacpi_check_std_acpi_brightness_support(void) | 890 | static int __init tpacpi_check_std_acpi_brightness_support(void) |
891 | { | 891 | { |
892 | int status; | 892 | int status; |
893 | int bcl_levels = 0; | 893 | int bcl_levels = 0; |
894 | void *bcl_ptr = &bcl_levels; | 894 | void *bcl_ptr = &bcl_levels; |
895 | 895 | ||
896 | if (!vid_handle) { | 896 | if (!vid_handle) { |
897 | TPACPI_ACPIHANDLE_INIT(vid); | 897 | TPACPI_ACPIHANDLE_INIT(vid); |
898 | } | 898 | } |
899 | if (!vid_handle) | 899 | if (!vid_handle) |
900 | return 0; | 900 | return 0; |
901 | 901 | ||
902 | /* | 902 | /* |
903 | * Search for a _BCL method, and execute it. This is safe on all | 903 | * Search for a _BCL method, and execute it. This is safe on all |
904 | * ThinkPads, and as a side-effect, _BCL will place a Lenovo Vista | 904 | * ThinkPads, and as a side-effect, _BCL will place a Lenovo Vista |
905 | * BIOS in ACPI backlight control mode. We do NOT have to care | 905 | * BIOS in ACPI backlight control mode. We do NOT have to care |
906 | * about calling the _BCL method in an enabled video device, any | 906 | * about calling the _BCL method in an enabled video device, any |
907 | * will do for our purposes. | 907 | * will do for our purposes. |
908 | */ | 908 | */ |
909 | 909 | ||
910 | status = acpi_walk_namespace(ACPI_TYPE_METHOD, vid_handle, 3, | 910 | status = acpi_walk_namespace(ACPI_TYPE_METHOD, vid_handle, 3, |
911 | tpacpi_acpi_walk_find_bcl, NULL, | 911 | tpacpi_acpi_walk_find_bcl, NULL, |
912 | &bcl_ptr); | 912 | &bcl_ptr); |
913 | 913 | ||
914 | if (ACPI_SUCCESS(status) && bcl_levels > 2) { | 914 | if (ACPI_SUCCESS(status) && bcl_levels > 2) { |
915 | tp_features.bright_acpimode = 1; | 915 | tp_features.bright_acpimode = 1; |
916 | return (bcl_levels - 2); | 916 | return (bcl_levels - 2); |
917 | } | 917 | } |
918 | 918 | ||
919 | return 0; | 919 | return 0; |
920 | } | 920 | } |
921 | 921 | ||
922 | static int __init tpacpi_new_rfkill(const unsigned int id, | 922 | static int __init tpacpi_new_rfkill(const unsigned int id, |
923 | struct rfkill **rfk, | 923 | struct rfkill **rfk, |
924 | const enum rfkill_type rfktype, | 924 | const enum rfkill_type rfktype, |
925 | const char *name, | 925 | const char *name, |
926 | int (*toggle_radio)(void *, enum rfkill_state), | 926 | int (*toggle_radio)(void *, enum rfkill_state), |
927 | int (*get_state)(void *, enum rfkill_state *)) | 927 | int (*get_state)(void *, enum rfkill_state *)) |
928 | { | 928 | { |
929 | int res; | 929 | int res; |
930 | enum rfkill_state initial_state; | 930 | enum rfkill_state initial_state; |
931 | 931 | ||
932 | *rfk = rfkill_allocate(&tpacpi_pdev->dev, rfktype); | 932 | *rfk = rfkill_allocate(&tpacpi_pdev->dev, rfktype); |
933 | if (!*rfk) { | 933 | if (!*rfk) { |
934 | printk(TPACPI_ERR | 934 | printk(TPACPI_ERR |
935 | "failed to allocate memory for rfkill class\n"); | 935 | "failed to allocate memory for rfkill class\n"); |
936 | return -ENOMEM; | 936 | return -ENOMEM; |
937 | } | 937 | } |
938 | 938 | ||
939 | (*rfk)->name = name; | 939 | (*rfk)->name = name; |
940 | (*rfk)->get_state = get_state; | 940 | (*rfk)->get_state = get_state; |
941 | (*rfk)->toggle_radio = toggle_radio; | 941 | (*rfk)->toggle_radio = toggle_radio; |
942 | 942 | ||
943 | if (!get_state(NULL, &initial_state)) | 943 | if (!get_state(NULL, &initial_state)) |
944 | (*rfk)->state = initial_state; | 944 | (*rfk)->state = initial_state; |
945 | 945 | ||
946 | res = rfkill_register(*rfk); | 946 | res = rfkill_register(*rfk); |
947 | if (res < 0) { | 947 | if (res < 0) { |
948 | printk(TPACPI_ERR | 948 | printk(TPACPI_ERR |
949 | "failed to register %s rfkill switch: %d\n", | 949 | "failed to register %s rfkill switch: %d\n", |
950 | name, res); | 950 | name, res); |
951 | rfkill_free(*rfk); | 951 | rfkill_free(*rfk); |
952 | *rfk = NULL; | 952 | *rfk = NULL; |
953 | return res; | 953 | return res; |
954 | } | 954 | } |
955 | 955 | ||
956 | return 0; | 956 | return 0; |
957 | } | 957 | } |
958 | 958 | ||
959 | /************************************************************************* | 959 | /************************************************************************* |
960 | * thinkpad-acpi driver attributes | 960 | * thinkpad-acpi driver attributes |
961 | */ | 961 | */ |
962 | 962 | ||
963 | /* interface_version --------------------------------------------------- */ | 963 | /* interface_version --------------------------------------------------- */ |
964 | static ssize_t tpacpi_driver_interface_version_show( | 964 | static ssize_t tpacpi_driver_interface_version_show( |
965 | struct device_driver *drv, | 965 | struct device_driver *drv, |
966 | char *buf) | 966 | char *buf) |
967 | { | 967 | { |
968 | return snprintf(buf, PAGE_SIZE, "0x%08x\n", TPACPI_SYSFS_VERSION); | 968 | return snprintf(buf, PAGE_SIZE, "0x%08x\n", TPACPI_SYSFS_VERSION); |
969 | } | 969 | } |
970 | 970 | ||
971 | static DRIVER_ATTR(interface_version, S_IRUGO, | 971 | static DRIVER_ATTR(interface_version, S_IRUGO, |
972 | tpacpi_driver_interface_version_show, NULL); | 972 | tpacpi_driver_interface_version_show, NULL); |
973 | 973 | ||
974 | /* debug_level --------------------------------------------------------- */ | 974 | /* debug_level --------------------------------------------------------- */ |
975 | static ssize_t tpacpi_driver_debug_show(struct device_driver *drv, | 975 | static ssize_t tpacpi_driver_debug_show(struct device_driver *drv, |
976 | char *buf) | 976 | char *buf) |
977 | { | 977 | { |
978 | return snprintf(buf, PAGE_SIZE, "0x%04x\n", dbg_level); | 978 | return snprintf(buf, PAGE_SIZE, "0x%04x\n", dbg_level); |
979 | } | 979 | } |
980 | 980 | ||
981 | static ssize_t tpacpi_driver_debug_store(struct device_driver *drv, | 981 | static ssize_t tpacpi_driver_debug_store(struct device_driver *drv, |
982 | const char *buf, size_t count) | 982 | const char *buf, size_t count) |
983 | { | 983 | { |
984 | unsigned long t; | 984 | unsigned long t; |
985 | 985 | ||
986 | if (parse_strtoul(buf, 0xffff, &t)) | 986 | if (parse_strtoul(buf, 0xffff, &t)) |
987 | return -EINVAL; | 987 | return -EINVAL; |
988 | 988 | ||
989 | dbg_level = t; | 989 | dbg_level = t; |
990 | 990 | ||
991 | return count; | 991 | return count; |
992 | } | 992 | } |
993 | 993 | ||
994 | static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, | 994 | static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, |
995 | tpacpi_driver_debug_show, tpacpi_driver_debug_store); | 995 | tpacpi_driver_debug_show, tpacpi_driver_debug_store); |
996 | 996 | ||
997 | /* version ------------------------------------------------------------- */ | 997 | /* version ------------------------------------------------------------- */ |
998 | static ssize_t tpacpi_driver_version_show(struct device_driver *drv, | 998 | static ssize_t tpacpi_driver_version_show(struct device_driver *drv, |
999 | char *buf) | 999 | char *buf) |
1000 | { | 1000 | { |
1001 | return snprintf(buf, PAGE_SIZE, "%s v%s\n", | 1001 | return snprintf(buf, PAGE_SIZE, "%s v%s\n", |
1002 | TPACPI_DESC, TPACPI_VERSION); | 1002 | TPACPI_DESC, TPACPI_VERSION); |
1003 | } | 1003 | } |
1004 | 1004 | ||
1005 | static DRIVER_ATTR(version, S_IRUGO, | 1005 | static DRIVER_ATTR(version, S_IRUGO, |
1006 | tpacpi_driver_version_show, NULL); | 1006 | tpacpi_driver_version_show, NULL); |
1007 | 1007 | ||
1008 | /* --------------------------------------------------------------------- */ | 1008 | /* --------------------------------------------------------------------- */ |
1009 | 1009 | ||
1010 | static struct driver_attribute *tpacpi_driver_attributes[] = { | 1010 | static struct driver_attribute *tpacpi_driver_attributes[] = { |
1011 | &driver_attr_debug_level, &driver_attr_version, | 1011 | &driver_attr_debug_level, &driver_attr_version, |
1012 | &driver_attr_interface_version, | 1012 | &driver_attr_interface_version, |
1013 | }; | 1013 | }; |
1014 | 1014 | ||
1015 | static int __init tpacpi_create_driver_attributes(struct device_driver *drv) | 1015 | static int __init tpacpi_create_driver_attributes(struct device_driver *drv) |
1016 | { | 1016 | { |
1017 | int i, res; | 1017 | int i, res; |
1018 | 1018 | ||
1019 | i = 0; | 1019 | i = 0; |
1020 | res = 0; | 1020 | res = 0; |
1021 | while (!res && i < ARRAY_SIZE(tpacpi_driver_attributes)) { | 1021 | while (!res && i < ARRAY_SIZE(tpacpi_driver_attributes)) { |
1022 | res = driver_create_file(drv, tpacpi_driver_attributes[i]); | 1022 | res = driver_create_file(drv, tpacpi_driver_attributes[i]); |
1023 | i++; | 1023 | i++; |
1024 | } | 1024 | } |
1025 | 1025 | ||
1026 | return res; | 1026 | return res; |
1027 | } | 1027 | } |
1028 | 1028 | ||
1029 | static void tpacpi_remove_driver_attributes(struct device_driver *drv) | 1029 | static void tpacpi_remove_driver_attributes(struct device_driver *drv) |
1030 | { | 1030 | { |
1031 | int i; | 1031 | int i; |
1032 | 1032 | ||
1033 | for (i = 0; i < ARRAY_SIZE(tpacpi_driver_attributes); i++) | 1033 | for (i = 0; i < ARRAY_SIZE(tpacpi_driver_attributes); i++) |
1034 | driver_remove_file(drv, tpacpi_driver_attributes[i]); | 1034 | driver_remove_file(drv, tpacpi_driver_attributes[i]); |
1035 | } | 1035 | } |
1036 | 1036 | ||
1037 | /**************************************************************************** | 1037 | /**************************************************************************** |
1038 | **************************************************************************** | 1038 | **************************************************************************** |
1039 | * | 1039 | * |
1040 | * Subdrivers | 1040 | * Subdrivers |
1041 | * | 1041 | * |
1042 | **************************************************************************** | 1042 | **************************************************************************** |
1043 | ****************************************************************************/ | 1043 | ****************************************************************************/ |
1044 | 1044 | ||
1045 | /************************************************************************* | 1045 | /************************************************************************* |
1046 | * thinkpad-acpi init subdriver | 1046 | * thinkpad-acpi init subdriver |
1047 | */ | 1047 | */ |
1048 | 1048 | ||
1049 | static int __init thinkpad_acpi_driver_init(struct ibm_init_struct *iibm) | 1049 | static int __init thinkpad_acpi_driver_init(struct ibm_init_struct *iibm) |
1050 | { | 1050 | { |
1051 | printk(TPACPI_INFO "%s v%s\n", TPACPI_DESC, TPACPI_VERSION); | 1051 | printk(TPACPI_INFO "%s v%s\n", TPACPI_DESC, TPACPI_VERSION); |
1052 | printk(TPACPI_INFO "%s\n", TPACPI_URL); | 1052 | printk(TPACPI_INFO "%s\n", TPACPI_URL); |
1053 | 1053 | ||
1054 | printk(TPACPI_INFO "ThinkPad BIOS %s, EC %s\n", | 1054 | printk(TPACPI_INFO "ThinkPad BIOS %s, EC %s\n", |
1055 | (thinkpad_id.bios_version_str) ? | 1055 | (thinkpad_id.bios_version_str) ? |
1056 | thinkpad_id.bios_version_str : "unknown", | 1056 | thinkpad_id.bios_version_str : "unknown", |
1057 | (thinkpad_id.ec_version_str) ? | 1057 | (thinkpad_id.ec_version_str) ? |
1058 | thinkpad_id.ec_version_str : "unknown"); | 1058 | thinkpad_id.ec_version_str : "unknown"); |
1059 | 1059 | ||
1060 | if (thinkpad_id.vendor && thinkpad_id.model_str) | 1060 | if (thinkpad_id.vendor && thinkpad_id.model_str) |
1061 | printk(TPACPI_INFO "%s %s, model %s\n", | 1061 | printk(TPACPI_INFO "%s %s, model %s\n", |
1062 | (thinkpad_id.vendor == PCI_VENDOR_ID_IBM) ? | 1062 | (thinkpad_id.vendor == PCI_VENDOR_ID_IBM) ? |
1063 | "IBM" : ((thinkpad_id.vendor == | 1063 | "IBM" : ((thinkpad_id.vendor == |
1064 | PCI_VENDOR_ID_LENOVO) ? | 1064 | PCI_VENDOR_ID_LENOVO) ? |
1065 | "Lenovo" : "Unknown vendor"), | 1065 | "Lenovo" : "Unknown vendor"), |
1066 | thinkpad_id.model_str, | 1066 | thinkpad_id.model_str, |
1067 | (thinkpad_id.nummodel_str) ? | 1067 | (thinkpad_id.nummodel_str) ? |
1068 | thinkpad_id.nummodel_str : "unknown"); | 1068 | thinkpad_id.nummodel_str : "unknown"); |
1069 | 1069 | ||
1070 | return 0; | 1070 | return 0; |
1071 | } | 1071 | } |
1072 | 1072 | ||
1073 | static int thinkpad_acpi_driver_read(char *p) | 1073 | static int thinkpad_acpi_driver_read(char *p) |
1074 | { | 1074 | { |
1075 | int len = 0; | 1075 | int len = 0; |
1076 | 1076 | ||
1077 | len += sprintf(p + len, "driver:\t\t%s\n", TPACPI_DESC); | 1077 | len += sprintf(p + len, "driver:\t\t%s\n", TPACPI_DESC); |
1078 | len += sprintf(p + len, "version:\t%s\n", TPACPI_VERSION); | 1078 | len += sprintf(p + len, "version:\t%s\n", TPACPI_VERSION); |
1079 | 1079 | ||
1080 | return len; | 1080 | return len; |
1081 | } | 1081 | } |
1082 | 1082 | ||
1083 | static struct ibm_struct thinkpad_acpi_driver_data = { | 1083 | static struct ibm_struct thinkpad_acpi_driver_data = { |
1084 | .name = "driver", | 1084 | .name = "driver", |
1085 | .read = thinkpad_acpi_driver_read, | 1085 | .read = thinkpad_acpi_driver_read, |
1086 | }; | 1086 | }; |
1087 | 1087 | ||
1088 | /************************************************************************* | 1088 | /************************************************************************* |
1089 | * Hotkey subdriver | 1089 | * Hotkey subdriver |
1090 | */ | 1090 | */ |
1091 | 1091 | ||
1092 | enum { /* hot key scan codes (derived from ACPI DSDT) */ | 1092 | enum { /* hot key scan codes (derived from ACPI DSDT) */ |
1093 | TP_ACPI_HOTKEYSCAN_FNF1 = 0, | 1093 | TP_ACPI_HOTKEYSCAN_FNF1 = 0, |
1094 | TP_ACPI_HOTKEYSCAN_FNF2, | 1094 | TP_ACPI_HOTKEYSCAN_FNF2, |
1095 | TP_ACPI_HOTKEYSCAN_FNF3, | 1095 | TP_ACPI_HOTKEYSCAN_FNF3, |
1096 | TP_ACPI_HOTKEYSCAN_FNF4, | 1096 | TP_ACPI_HOTKEYSCAN_FNF4, |
1097 | TP_ACPI_HOTKEYSCAN_FNF5, | 1097 | TP_ACPI_HOTKEYSCAN_FNF5, |
1098 | TP_ACPI_HOTKEYSCAN_FNF6, | 1098 | TP_ACPI_HOTKEYSCAN_FNF6, |
1099 | TP_ACPI_HOTKEYSCAN_FNF7, | 1099 | TP_ACPI_HOTKEYSCAN_FNF7, |
1100 | TP_ACPI_HOTKEYSCAN_FNF8, | 1100 | TP_ACPI_HOTKEYSCAN_FNF8, |
1101 | TP_ACPI_HOTKEYSCAN_FNF9, | 1101 | TP_ACPI_HOTKEYSCAN_FNF9, |
1102 | TP_ACPI_HOTKEYSCAN_FNF10, | 1102 | TP_ACPI_HOTKEYSCAN_FNF10, |
1103 | TP_ACPI_HOTKEYSCAN_FNF11, | 1103 | TP_ACPI_HOTKEYSCAN_FNF11, |
1104 | TP_ACPI_HOTKEYSCAN_FNF12, | 1104 | TP_ACPI_HOTKEYSCAN_FNF12, |
1105 | TP_ACPI_HOTKEYSCAN_FNBACKSPACE, | 1105 | TP_ACPI_HOTKEYSCAN_FNBACKSPACE, |
1106 | TP_ACPI_HOTKEYSCAN_FNINSERT, | 1106 | TP_ACPI_HOTKEYSCAN_FNINSERT, |
1107 | TP_ACPI_HOTKEYSCAN_FNDELETE, | 1107 | TP_ACPI_HOTKEYSCAN_FNDELETE, |
1108 | TP_ACPI_HOTKEYSCAN_FNHOME, | 1108 | TP_ACPI_HOTKEYSCAN_FNHOME, |
1109 | TP_ACPI_HOTKEYSCAN_FNEND, | 1109 | TP_ACPI_HOTKEYSCAN_FNEND, |
1110 | TP_ACPI_HOTKEYSCAN_FNPAGEUP, | 1110 | TP_ACPI_HOTKEYSCAN_FNPAGEUP, |
1111 | TP_ACPI_HOTKEYSCAN_FNPAGEDOWN, | 1111 | TP_ACPI_HOTKEYSCAN_FNPAGEDOWN, |
1112 | TP_ACPI_HOTKEYSCAN_FNSPACE, | 1112 | TP_ACPI_HOTKEYSCAN_FNSPACE, |
1113 | TP_ACPI_HOTKEYSCAN_VOLUMEUP, | 1113 | TP_ACPI_HOTKEYSCAN_VOLUMEUP, |
1114 | TP_ACPI_HOTKEYSCAN_VOLUMEDOWN, | 1114 | TP_ACPI_HOTKEYSCAN_VOLUMEDOWN, |
1115 | TP_ACPI_HOTKEYSCAN_MUTE, | 1115 | TP_ACPI_HOTKEYSCAN_MUTE, |
1116 | TP_ACPI_HOTKEYSCAN_THINKPAD, | 1116 | TP_ACPI_HOTKEYSCAN_THINKPAD, |
1117 | }; | 1117 | }; |
1118 | 1118 | ||
1119 | enum { /* Keys available through NVRAM polling */ | 1119 | enum { /* Keys available through NVRAM polling */ |
1120 | TPACPI_HKEY_NVRAM_KNOWN_MASK = 0x00fb88c0U, | 1120 | TPACPI_HKEY_NVRAM_KNOWN_MASK = 0x00fb88c0U, |
1121 | TPACPI_HKEY_NVRAM_GOOD_MASK = 0x00fb8000U, | 1121 | TPACPI_HKEY_NVRAM_GOOD_MASK = 0x00fb8000U, |
1122 | }; | 1122 | }; |
1123 | 1123 | ||
1124 | enum { /* Positions of some of the keys in hotkey masks */ | 1124 | enum { /* Positions of some of the keys in hotkey masks */ |
1125 | TP_ACPI_HKEY_DISPSWTCH_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNF7, | 1125 | TP_ACPI_HKEY_DISPSWTCH_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNF7, |
1126 | TP_ACPI_HKEY_DISPXPAND_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNF8, | 1126 | TP_ACPI_HKEY_DISPXPAND_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNF8, |
1127 | TP_ACPI_HKEY_HIBERNATE_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNF12, | 1127 | TP_ACPI_HKEY_HIBERNATE_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNF12, |
1128 | TP_ACPI_HKEY_BRGHTUP_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNHOME, | 1128 | TP_ACPI_HKEY_BRGHTUP_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNHOME, |
1129 | TP_ACPI_HKEY_BRGHTDWN_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNEND, | 1129 | TP_ACPI_HKEY_BRGHTDWN_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNEND, |
1130 | TP_ACPI_HKEY_THNKLGHT_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNPAGEUP, | 1130 | TP_ACPI_HKEY_THNKLGHT_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNPAGEUP, |
1131 | TP_ACPI_HKEY_ZOOM_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNSPACE, | 1131 | TP_ACPI_HKEY_ZOOM_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNSPACE, |
1132 | TP_ACPI_HKEY_VOLUP_MASK = 1 << TP_ACPI_HOTKEYSCAN_VOLUMEUP, | 1132 | TP_ACPI_HKEY_VOLUP_MASK = 1 << TP_ACPI_HOTKEYSCAN_VOLUMEUP, |
1133 | TP_ACPI_HKEY_VOLDWN_MASK = 1 << TP_ACPI_HOTKEYSCAN_VOLUMEDOWN, | 1133 | TP_ACPI_HKEY_VOLDWN_MASK = 1 << TP_ACPI_HOTKEYSCAN_VOLUMEDOWN, |
1134 | TP_ACPI_HKEY_MUTE_MASK = 1 << TP_ACPI_HOTKEYSCAN_MUTE, | 1134 | TP_ACPI_HKEY_MUTE_MASK = 1 << TP_ACPI_HOTKEYSCAN_MUTE, |
1135 | TP_ACPI_HKEY_THINKPAD_MASK = 1 << TP_ACPI_HOTKEYSCAN_THINKPAD, | 1135 | TP_ACPI_HKEY_THINKPAD_MASK = 1 << TP_ACPI_HOTKEYSCAN_THINKPAD, |
1136 | }; | 1136 | }; |
1137 | 1137 | ||
1138 | enum { /* NVRAM to ACPI HKEY group map */ | 1138 | enum { /* NVRAM to ACPI HKEY group map */ |
1139 | TP_NVRAM_HKEY_GROUP_HK2 = TP_ACPI_HKEY_THINKPAD_MASK | | 1139 | TP_NVRAM_HKEY_GROUP_HK2 = TP_ACPI_HKEY_THINKPAD_MASK | |
1140 | TP_ACPI_HKEY_ZOOM_MASK | | 1140 | TP_ACPI_HKEY_ZOOM_MASK | |
1141 | TP_ACPI_HKEY_DISPSWTCH_MASK | | 1141 | TP_ACPI_HKEY_DISPSWTCH_MASK | |
1142 | TP_ACPI_HKEY_HIBERNATE_MASK, | 1142 | TP_ACPI_HKEY_HIBERNATE_MASK, |
1143 | TP_NVRAM_HKEY_GROUP_BRIGHTNESS = TP_ACPI_HKEY_BRGHTUP_MASK | | 1143 | TP_NVRAM_HKEY_GROUP_BRIGHTNESS = TP_ACPI_HKEY_BRGHTUP_MASK | |
1144 | TP_ACPI_HKEY_BRGHTDWN_MASK, | 1144 | TP_ACPI_HKEY_BRGHTDWN_MASK, |
1145 | TP_NVRAM_HKEY_GROUP_VOLUME = TP_ACPI_HKEY_VOLUP_MASK | | 1145 | TP_NVRAM_HKEY_GROUP_VOLUME = TP_ACPI_HKEY_VOLUP_MASK | |
1146 | TP_ACPI_HKEY_VOLDWN_MASK | | 1146 | TP_ACPI_HKEY_VOLDWN_MASK | |
1147 | TP_ACPI_HKEY_MUTE_MASK, | 1147 | TP_ACPI_HKEY_MUTE_MASK, |
1148 | }; | 1148 | }; |
1149 | 1149 | ||
1150 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL | 1150 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL |
1151 | struct tp_nvram_state { | 1151 | struct tp_nvram_state { |
1152 | u16 thinkpad_toggle:1; | 1152 | u16 thinkpad_toggle:1; |
1153 | u16 zoom_toggle:1; | 1153 | u16 zoom_toggle:1; |
1154 | u16 display_toggle:1; | 1154 | u16 display_toggle:1; |
1155 | u16 thinklight_toggle:1; | 1155 | u16 thinklight_toggle:1; |
1156 | u16 hibernate_toggle:1; | 1156 | u16 hibernate_toggle:1; |
1157 | u16 displayexp_toggle:1; | 1157 | u16 displayexp_toggle:1; |
1158 | u16 display_state:1; | 1158 | u16 display_state:1; |
1159 | u16 brightness_toggle:1; | 1159 | u16 brightness_toggle:1; |
1160 | u16 volume_toggle:1; | 1160 | u16 volume_toggle:1; |
1161 | u16 mute:1; | 1161 | u16 mute:1; |
1162 | 1162 | ||
1163 | u8 brightness_level; | 1163 | u8 brightness_level; |
1164 | u8 volume_level; | 1164 | u8 volume_level; |
1165 | }; | 1165 | }; |
1166 | 1166 | ||
1167 | static struct task_struct *tpacpi_hotkey_task; | 1167 | static struct task_struct *tpacpi_hotkey_task; |
1168 | static u32 hotkey_source_mask; /* bit mask 0=ACPI,1=NVRAM */ | 1168 | static u32 hotkey_source_mask; /* bit mask 0=ACPI,1=NVRAM */ |
1169 | static int hotkey_poll_freq = 10; /* Hz */ | 1169 | static int hotkey_poll_freq = 10; /* Hz */ |
1170 | static struct mutex hotkey_thread_mutex; | 1170 | static struct mutex hotkey_thread_mutex; |
1171 | static struct mutex hotkey_thread_data_mutex; | 1171 | static struct mutex hotkey_thread_data_mutex; |
1172 | static unsigned int hotkey_config_change; | 1172 | static unsigned int hotkey_config_change; |
1173 | 1173 | ||
1174 | #else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ | 1174 | #else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ |
1175 | 1175 | ||
1176 | #define hotkey_source_mask 0U | 1176 | #define hotkey_source_mask 0U |
1177 | 1177 | ||
1178 | #endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ | 1178 | #endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ |
1179 | 1179 | ||
1180 | static struct mutex hotkey_mutex; | 1180 | static struct mutex hotkey_mutex; |
1181 | 1181 | ||
1182 | static enum { /* Reasons for waking up */ | 1182 | static enum { /* Reasons for waking up */ |
1183 | TP_ACPI_WAKEUP_NONE = 0, /* None or unknown */ | 1183 | TP_ACPI_WAKEUP_NONE = 0, /* None or unknown */ |
1184 | TP_ACPI_WAKEUP_BAYEJ, /* Bay ejection request */ | 1184 | TP_ACPI_WAKEUP_BAYEJ, /* Bay ejection request */ |
1185 | TP_ACPI_WAKEUP_UNDOCK, /* Undock request */ | 1185 | TP_ACPI_WAKEUP_UNDOCK, /* Undock request */ |
1186 | } hotkey_wakeup_reason; | 1186 | } hotkey_wakeup_reason; |
1187 | 1187 | ||
1188 | static int hotkey_autosleep_ack; | 1188 | static int hotkey_autosleep_ack; |
1189 | 1189 | ||
1190 | static int hotkey_orig_status; | 1190 | static int hotkey_orig_status; |
1191 | static u32 hotkey_orig_mask; | 1191 | static u32 hotkey_orig_mask; |
1192 | static u32 hotkey_all_mask; | 1192 | static u32 hotkey_all_mask; |
1193 | static u32 hotkey_reserved_mask; | 1193 | static u32 hotkey_reserved_mask; |
1194 | static u32 hotkey_mask; | 1194 | static u32 hotkey_mask; |
1195 | 1195 | ||
1196 | static unsigned int hotkey_report_mode; | 1196 | static unsigned int hotkey_report_mode; |
1197 | 1197 | ||
1198 | static u16 *hotkey_keycode_map; | 1198 | static u16 *hotkey_keycode_map; |
1199 | 1199 | ||
1200 | static struct attribute_set *hotkey_dev_attributes; | 1200 | static struct attribute_set *hotkey_dev_attributes; |
1201 | 1201 | ||
1202 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL | 1202 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL |
1203 | #define HOTKEY_CONFIG_CRITICAL_START \ | 1203 | #define HOTKEY_CONFIG_CRITICAL_START \ |
1204 | do { \ | 1204 | do { \ |
1205 | mutex_lock(&hotkey_thread_data_mutex); \ | 1205 | mutex_lock(&hotkey_thread_data_mutex); \ |
1206 | hotkey_config_change++; \ | 1206 | hotkey_config_change++; \ |
1207 | } while (0); | 1207 | } while (0); |
1208 | #define HOTKEY_CONFIG_CRITICAL_END \ | 1208 | #define HOTKEY_CONFIG_CRITICAL_END \ |
1209 | mutex_unlock(&hotkey_thread_data_mutex); | 1209 | mutex_unlock(&hotkey_thread_data_mutex); |
1210 | #else | 1210 | #else |
1211 | #define HOTKEY_CONFIG_CRITICAL_START | 1211 | #define HOTKEY_CONFIG_CRITICAL_START |
1212 | #define HOTKEY_CONFIG_CRITICAL_END | 1212 | #define HOTKEY_CONFIG_CRITICAL_END |
1213 | #endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ | 1213 | #endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ |
1214 | 1214 | ||
1215 | /* HKEY.MHKG() return bits */ | 1215 | /* HKEY.MHKG() return bits */ |
1216 | #define TP_HOTKEY_TABLET_MASK (1 << 3) | 1216 | #define TP_HOTKEY_TABLET_MASK (1 << 3) |
1217 | 1217 | ||
1218 | static int hotkey_get_wlsw(int *status) | 1218 | static int hotkey_get_wlsw(int *status) |
1219 | { | 1219 | { |
1220 | if (!acpi_evalf(hkey_handle, status, "WLSW", "d")) | 1220 | if (!acpi_evalf(hkey_handle, status, "WLSW", "d")) |
1221 | return -EIO; | 1221 | return -EIO; |
1222 | return 0; | 1222 | return 0; |
1223 | } | 1223 | } |
1224 | 1224 | ||
1225 | static int hotkey_get_tablet_mode(int *status) | 1225 | static int hotkey_get_tablet_mode(int *status) |
1226 | { | 1226 | { |
1227 | int s; | 1227 | int s; |
1228 | 1228 | ||
1229 | if (!acpi_evalf(hkey_handle, &s, "MHKG", "d")) | 1229 | if (!acpi_evalf(hkey_handle, &s, "MHKG", "d")) |
1230 | return -EIO; | 1230 | return -EIO; |
1231 | 1231 | ||
1232 | *status = ((s & TP_HOTKEY_TABLET_MASK) != 0); | 1232 | *status = ((s & TP_HOTKEY_TABLET_MASK) != 0); |
1233 | return 0; | 1233 | return 0; |
1234 | } | 1234 | } |
1235 | 1235 | ||
1236 | /* | 1236 | /* |
1237 | * Call with hotkey_mutex held | 1237 | * Call with hotkey_mutex held |
1238 | */ | 1238 | */ |
1239 | static int hotkey_mask_get(void) | 1239 | static int hotkey_mask_get(void) |
1240 | { | 1240 | { |
1241 | u32 m = 0; | 1241 | u32 m = 0; |
1242 | 1242 | ||
1243 | if (tp_features.hotkey_mask) { | 1243 | if (tp_features.hotkey_mask) { |
1244 | if (!acpi_evalf(hkey_handle, &m, "DHKN", "d")) | 1244 | if (!acpi_evalf(hkey_handle, &m, "DHKN", "d")) |
1245 | return -EIO; | 1245 | return -EIO; |
1246 | } | 1246 | } |
1247 | hotkey_mask = m | (hotkey_source_mask & hotkey_mask); | 1247 | hotkey_mask = m | (hotkey_source_mask & hotkey_mask); |
1248 | 1248 | ||
1249 | return 0; | 1249 | return 0; |
1250 | } | 1250 | } |
1251 | 1251 | ||
1252 | /* | 1252 | /* |
1253 | * Call with hotkey_mutex held | 1253 | * Call with hotkey_mutex held |
1254 | */ | 1254 | */ |
1255 | static int hotkey_mask_set(u32 mask) | 1255 | static int hotkey_mask_set(u32 mask) |
1256 | { | 1256 | { |
1257 | int i; | 1257 | int i; |
1258 | int rc = 0; | 1258 | int rc = 0; |
1259 | 1259 | ||
1260 | if (tp_features.hotkey_mask) { | 1260 | if (tp_features.hotkey_mask) { |
1261 | if (!tp_warned.hotkey_mask_ff && | 1261 | if (!tp_warned.hotkey_mask_ff && |
1262 | (mask == 0xffff || mask == 0xffffff || | 1262 | (mask == 0xffff || mask == 0xffffff || |
1263 | mask == 0xffffffff)) { | 1263 | mask == 0xffffffff)) { |
1264 | tp_warned.hotkey_mask_ff = 1; | 1264 | tp_warned.hotkey_mask_ff = 1; |
1265 | printk(TPACPI_NOTICE | 1265 | printk(TPACPI_NOTICE |
1266 | "setting the hotkey mask to 0x%08x is likely " | 1266 | "setting the hotkey mask to 0x%08x is likely " |
1267 | "not the best way to go about it\n", mask); | 1267 | "not the best way to go about it\n", mask); |
1268 | printk(TPACPI_NOTICE | 1268 | printk(TPACPI_NOTICE |
1269 | "please consider using the driver defaults, " | 1269 | "please consider using the driver defaults, " |
1270 | "and refer to up-to-date thinkpad-acpi " | 1270 | "and refer to up-to-date thinkpad-acpi " |
1271 | "documentation\n"); | 1271 | "documentation\n"); |
1272 | } | 1272 | } |
1273 | 1273 | ||
1274 | HOTKEY_CONFIG_CRITICAL_START | 1274 | HOTKEY_CONFIG_CRITICAL_START |
1275 | for (i = 0; i < 32; i++) { | 1275 | for (i = 0; i < 32; i++) { |
1276 | u32 m = 1 << i; | 1276 | u32 m = 1 << i; |
1277 | /* enable in firmware mask only keys not in NVRAM | 1277 | /* enable in firmware mask only keys not in NVRAM |
1278 | * mode, but enable the key in the cached hotkey_mask | 1278 | * mode, but enable the key in the cached hotkey_mask |
1279 | * regardless of mode, or the key will end up | 1279 | * regardless of mode, or the key will end up |
1280 | * disabled by hotkey_mask_get() */ | 1280 | * disabled by hotkey_mask_get() */ |
1281 | if (!acpi_evalf(hkey_handle, | 1281 | if (!acpi_evalf(hkey_handle, |
1282 | NULL, "MHKM", "vdd", i + 1, | 1282 | NULL, "MHKM", "vdd", i + 1, |
1283 | !!((mask & ~hotkey_source_mask) & m))) { | 1283 | !!((mask & ~hotkey_source_mask) & m))) { |
1284 | rc = -EIO; | 1284 | rc = -EIO; |
1285 | break; | 1285 | break; |
1286 | } else { | 1286 | } else { |
1287 | hotkey_mask = (hotkey_mask & ~m) | (mask & m); | 1287 | hotkey_mask = (hotkey_mask & ~m) | (mask & m); |
1288 | } | 1288 | } |
1289 | } | 1289 | } |
1290 | HOTKEY_CONFIG_CRITICAL_END | 1290 | HOTKEY_CONFIG_CRITICAL_END |
1291 | 1291 | ||
1292 | /* hotkey_mask_get must be called unconditionally below */ | 1292 | /* hotkey_mask_get must be called unconditionally below */ |
1293 | if (!hotkey_mask_get() && !rc && | 1293 | if (!hotkey_mask_get() && !rc && |
1294 | (hotkey_mask & ~hotkey_source_mask) != | 1294 | (hotkey_mask & ~hotkey_source_mask) != |
1295 | (mask & ~hotkey_source_mask)) { | 1295 | (mask & ~hotkey_source_mask)) { |
1296 | printk(TPACPI_NOTICE | 1296 | printk(TPACPI_NOTICE |
1297 | "requested hot key mask 0x%08x, but " | 1297 | "requested hot key mask 0x%08x, but " |
1298 | "firmware forced it to 0x%08x\n", | 1298 | "firmware forced it to 0x%08x\n", |
1299 | mask, hotkey_mask); | 1299 | mask, hotkey_mask); |
1300 | } | 1300 | } |
1301 | } else { | 1301 | } else { |
1302 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL | 1302 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL |
1303 | HOTKEY_CONFIG_CRITICAL_START | 1303 | HOTKEY_CONFIG_CRITICAL_START |
1304 | hotkey_mask = mask & hotkey_source_mask; | 1304 | hotkey_mask = mask & hotkey_source_mask; |
1305 | HOTKEY_CONFIG_CRITICAL_END | 1305 | HOTKEY_CONFIG_CRITICAL_END |
1306 | hotkey_mask_get(); | 1306 | hotkey_mask_get(); |
1307 | if (hotkey_mask != mask) { | 1307 | if (hotkey_mask != mask) { |
1308 | printk(TPACPI_NOTICE | 1308 | printk(TPACPI_NOTICE |
1309 | "requested hot key mask 0x%08x, " | 1309 | "requested hot key mask 0x%08x, " |
1310 | "forced to 0x%08x (NVRAM poll mask is " | 1310 | "forced to 0x%08x (NVRAM poll mask is " |
1311 | "0x%08x): no firmware mask support\n", | 1311 | "0x%08x): no firmware mask support\n", |
1312 | mask, hotkey_mask, hotkey_source_mask); | 1312 | mask, hotkey_mask, hotkey_source_mask); |
1313 | } | 1313 | } |
1314 | #else | 1314 | #else |
1315 | hotkey_mask_get(); | 1315 | hotkey_mask_get(); |
1316 | rc = -ENXIO; | 1316 | rc = -ENXIO; |
1317 | #endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ | 1317 | #endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ |
1318 | } | 1318 | } |
1319 | 1319 | ||
1320 | return rc; | 1320 | return rc; |
1321 | } | 1321 | } |
1322 | 1322 | ||
1323 | static int hotkey_status_get(int *status) | 1323 | static int hotkey_status_get(int *status) |
1324 | { | 1324 | { |
1325 | if (!acpi_evalf(hkey_handle, status, "DHKC", "d")) | 1325 | if (!acpi_evalf(hkey_handle, status, "DHKC", "d")) |
1326 | return -EIO; | 1326 | return -EIO; |
1327 | 1327 | ||
1328 | return 0; | 1328 | return 0; |
1329 | } | 1329 | } |
1330 | 1330 | ||
1331 | static int hotkey_status_set(int status) | 1331 | static int hotkey_status_set(int status) |
1332 | { | 1332 | { |
1333 | if (!acpi_evalf(hkey_handle, NULL, "MHKC", "vd", status)) | 1333 | if (!acpi_evalf(hkey_handle, NULL, "MHKC", "vd", status)) |
1334 | return -EIO; | 1334 | return -EIO; |
1335 | 1335 | ||
1336 | return 0; | 1336 | return 0; |
1337 | } | 1337 | } |
1338 | 1338 | ||
1339 | static void tpacpi_input_send_tabletsw(void) | 1339 | static void tpacpi_input_send_tabletsw(void) |
1340 | { | 1340 | { |
1341 | int state; | 1341 | int state; |
1342 | 1342 | ||
1343 | if (tp_features.hotkey_tablet && | 1343 | if (tp_features.hotkey_tablet && |
1344 | !hotkey_get_tablet_mode(&state)) { | 1344 | !hotkey_get_tablet_mode(&state)) { |
1345 | mutex_lock(&tpacpi_inputdev_send_mutex); | 1345 | mutex_lock(&tpacpi_inputdev_send_mutex); |
1346 | 1346 | ||
1347 | input_report_switch(tpacpi_inputdev, | 1347 | input_report_switch(tpacpi_inputdev, |
1348 | SW_TABLET_MODE, !!state); | 1348 | SW_TABLET_MODE, !!state); |
1349 | input_sync(tpacpi_inputdev); | 1349 | input_sync(tpacpi_inputdev); |
1350 | 1350 | ||
1351 | mutex_unlock(&tpacpi_inputdev_send_mutex); | 1351 | mutex_unlock(&tpacpi_inputdev_send_mutex); |
1352 | } | 1352 | } |
1353 | } | 1353 | } |
1354 | 1354 | ||
1355 | static void tpacpi_input_send_key(unsigned int scancode) | 1355 | static void tpacpi_input_send_key(unsigned int scancode) |
1356 | { | 1356 | { |
1357 | unsigned int keycode; | 1357 | unsigned int keycode; |
1358 | 1358 | ||
1359 | keycode = hotkey_keycode_map[scancode]; | 1359 | keycode = hotkey_keycode_map[scancode]; |
1360 | 1360 | ||
1361 | if (keycode != KEY_RESERVED) { | 1361 | if (keycode != KEY_RESERVED) { |
1362 | mutex_lock(&tpacpi_inputdev_send_mutex); | 1362 | mutex_lock(&tpacpi_inputdev_send_mutex); |
1363 | 1363 | ||
1364 | input_report_key(tpacpi_inputdev, keycode, 1); | 1364 | input_report_key(tpacpi_inputdev, keycode, 1); |
1365 | if (keycode == KEY_UNKNOWN) | 1365 | if (keycode == KEY_UNKNOWN) |
1366 | input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, | 1366 | input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, |
1367 | scancode); | 1367 | scancode); |
1368 | input_sync(tpacpi_inputdev); | 1368 | input_sync(tpacpi_inputdev); |
1369 | 1369 | ||
1370 | input_report_key(tpacpi_inputdev, keycode, 0); | 1370 | input_report_key(tpacpi_inputdev, keycode, 0); |
1371 | if (keycode == KEY_UNKNOWN) | 1371 | if (keycode == KEY_UNKNOWN) |
1372 | input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, | 1372 | input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, |
1373 | scancode); | 1373 | scancode); |
1374 | input_sync(tpacpi_inputdev); | 1374 | input_sync(tpacpi_inputdev); |
1375 | 1375 | ||
1376 | mutex_unlock(&tpacpi_inputdev_send_mutex); | 1376 | mutex_unlock(&tpacpi_inputdev_send_mutex); |
1377 | } | 1377 | } |
1378 | } | 1378 | } |
1379 | 1379 | ||
1380 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL | 1380 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL |
1381 | static struct tp_acpi_drv_struct ibm_hotkey_acpidriver; | 1381 | static struct tp_acpi_drv_struct ibm_hotkey_acpidriver; |
1382 | 1382 | ||
1383 | static void tpacpi_hotkey_send_key(unsigned int scancode) | 1383 | static void tpacpi_hotkey_send_key(unsigned int scancode) |
1384 | { | 1384 | { |
1385 | tpacpi_input_send_key(scancode); | 1385 | tpacpi_input_send_key(scancode); |
1386 | if (hotkey_report_mode < 2) { | 1386 | if (hotkey_report_mode < 2) { |
1387 | acpi_bus_generate_proc_event(ibm_hotkey_acpidriver.device, | 1387 | acpi_bus_generate_proc_event(ibm_hotkey_acpidriver.device, |
1388 | 0x80, 0x1001 + scancode); | 1388 | 0x80, 0x1001 + scancode); |
1389 | } | 1389 | } |
1390 | } | 1390 | } |
1391 | 1391 | ||
1392 | static void hotkey_read_nvram(struct tp_nvram_state *n, u32 m) | 1392 | static void hotkey_read_nvram(struct tp_nvram_state *n, u32 m) |
1393 | { | 1393 | { |
1394 | u8 d; | 1394 | u8 d; |
1395 | 1395 | ||
1396 | if (m & TP_NVRAM_HKEY_GROUP_HK2) { | 1396 | if (m & TP_NVRAM_HKEY_GROUP_HK2) { |
1397 | d = nvram_read_byte(TP_NVRAM_ADDR_HK2); | 1397 | d = nvram_read_byte(TP_NVRAM_ADDR_HK2); |
1398 | n->thinkpad_toggle = !!(d & TP_NVRAM_MASK_HKT_THINKPAD); | 1398 | n->thinkpad_toggle = !!(d & TP_NVRAM_MASK_HKT_THINKPAD); |
1399 | n->zoom_toggle = !!(d & TP_NVRAM_MASK_HKT_ZOOM); | 1399 | n->zoom_toggle = !!(d & TP_NVRAM_MASK_HKT_ZOOM); |
1400 | n->display_toggle = !!(d & TP_NVRAM_MASK_HKT_DISPLAY); | 1400 | n->display_toggle = !!(d & TP_NVRAM_MASK_HKT_DISPLAY); |
1401 | n->hibernate_toggle = !!(d & TP_NVRAM_MASK_HKT_HIBERNATE); | 1401 | n->hibernate_toggle = !!(d & TP_NVRAM_MASK_HKT_HIBERNATE); |
1402 | } | 1402 | } |
1403 | if (m & TP_ACPI_HKEY_THNKLGHT_MASK) { | 1403 | if (m & TP_ACPI_HKEY_THNKLGHT_MASK) { |
1404 | d = nvram_read_byte(TP_NVRAM_ADDR_THINKLIGHT); | 1404 | d = nvram_read_byte(TP_NVRAM_ADDR_THINKLIGHT); |
1405 | n->thinklight_toggle = !!(d & TP_NVRAM_MASK_THINKLIGHT); | 1405 | n->thinklight_toggle = !!(d & TP_NVRAM_MASK_THINKLIGHT); |
1406 | } | 1406 | } |
1407 | if (m & TP_ACPI_HKEY_DISPXPAND_MASK) { | 1407 | if (m & TP_ACPI_HKEY_DISPXPAND_MASK) { |
1408 | d = nvram_read_byte(TP_NVRAM_ADDR_VIDEO); | 1408 | d = nvram_read_byte(TP_NVRAM_ADDR_VIDEO); |
1409 | n->displayexp_toggle = | 1409 | n->displayexp_toggle = |
1410 | !!(d & TP_NVRAM_MASK_HKT_DISPEXPND); | 1410 | !!(d & TP_NVRAM_MASK_HKT_DISPEXPND); |
1411 | } | 1411 | } |
1412 | if (m & TP_NVRAM_HKEY_GROUP_BRIGHTNESS) { | 1412 | if (m & TP_NVRAM_HKEY_GROUP_BRIGHTNESS) { |
1413 | d = nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS); | 1413 | d = nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS); |
1414 | n->brightness_level = (d & TP_NVRAM_MASK_LEVEL_BRIGHTNESS) | 1414 | n->brightness_level = (d & TP_NVRAM_MASK_LEVEL_BRIGHTNESS) |
1415 | >> TP_NVRAM_POS_LEVEL_BRIGHTNESS; | 1415 | >> TP_NVRAM_POS_LEVEL_BRIGHTNESS; |
1416 | n->brightness_toggle = | 1416 | n->brightness_toggle = |
1417 | !!(d & TP_NVRAM_MASK_HKT_BRIGHTNESS); | 1417 | !!(d & TP_NVRAM_MASK_HKT_BRIGHTNESS); |
1418 | } | 1418 | } |
1419 | if (m & TP_NVRAM_HKEY_GROUP_VOLUME) { | 1419 | if (m & TP_NVRAM_HKEY_GROUP_VOLUME) { |
1420 | d = nvram_read_byte(TP_NVRAM_ADDR_MIXER); | 1420 | d = nvram_read_byte(TP_NVRAM_ADDR_MIXER); |
1421 | n->volume_level = (d & TP_NVRAM_MASK_LEVEL_VOLUME) | 1421 | n->volume_level = (d & TP_NVRAM_MASK_LEVEL_VOLUME) |
1422 | >> TP_NVRAM_POS_LEVEL_VOLUME; | 1422 | >> TP_NVRAM_POS_LEVEL_VOLUME; |
1423 | n->mute = !!(d & TP_NVRAM_MASK_MUTE); | 1423 | n->mute = !!(d & TP_NVRAM_MASK_MUTE); |
1424 | n->volume_toggle = !!(d & TP_NVRAM_MASK_HKT_VOLUME); | 1424 | n->volume_toggle = !!(d & TP_NVRAM_MASK_HKT_VOLUME); |
1425 | } | 1425 | } |
1426 | } | 1426 | } |
1427 | 1427 | ||
1428 | #define TPACPI_COMPARE_KEY(__scancode, __member) \ | 1428 | #define TPACPI_COMPARE_KEY(__scancode, __member) \ |
1429 | do { \ | 1429 | do { \ |
1430 | if ((mask & (1 << __scancode)) && \ | 1430 | if ((mask & (1 << __scancode)) && \ |
1431 | oldn->__member != newn->__member) \ | 1431 | oldn->__member != newn->__member) \ |
1432 | tpacpi_hotkey_send_key(__scancode); \ | 1432 | tpacpi_hotkey_send_key(__scancode); \ |
1433 | } while (0) | 1433 | } while (0) |
1434 | 1434 | ||
1435 | #define TPACPI_MAY_SEND_KEY(__scancode) \ | 1435 | #define TPACPI_MAY_SEND_KEY(__scancode) \ |
1436 | do { if (mask & (1 << __scancode)) \ | 1436 | do { if (mask & (1 << __scancode)) \ |
1437 | tpacpi_hotkey_send_key(__scancode); } while (0) | 1437 | tpacpi_hotkey_send_key(__scancode); } while (0) |
1438 | 1438 | ||
1439 | static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn, | 1439 | static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn, |
1440 | struct tp_nvram_state *newn, | 1440 | struct tp_nvram_state *newn, |
1441 | u32 mask) | 1441 | u32 mask) |
1442 | { | 1442 | { |
1443 | TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_THINKPAD, thinkpad_toggle); | 1443 | TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_THINKPAD, thinkpad_toggle); |
1444 | TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNSPACE, zoom_toggle); | 1444 | TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNSPACE, zoom_toggle); |
1445 | TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNF7, display_toggle); | 1445 | TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNF7, display_toggle); |
1446 | TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNF12, hibernate_toggle); | 1446 | TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNF12, hibernate_toggle); |
1447 | 1447 | ||
1448 | TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNPAGEUP, thinklight_toggle); | 1448 | TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNPAGEUP, thinklight_toggle); |
1449 | 1449 | ||
1450 | TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNF8, displayexp_toggle); | 1450 | TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNF8, displayexp_toggle); |
1451 | 1451 | ||
1452 | /* handle volume */ | 1452 | /* handle volume */ |
1453 | if (oldn->volume_toggle != newn->volume_toggle) { | 1453 | if (oldn->volume_toggle != newn->volume_toggle) { |
1454 | if (oldn->mute != newn->mute) { | 1454 | if (oldn->mute != newn->mute) { |
1455 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_MUTE); | 1455 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_MUTE); |
1456 | } | 1456 | } |
1457 | if (oldn->volume_level > newn->volume_level) { | 1457 | if (oldn->volume_level > newn->volume_level) { |
1458 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEDOWN); | 1458 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEDOWN); |
1459 | } else if (oldn->volume_level < newn->volume_level) { | 1459 | } else if (oldn->volume_level < newn->volume_level) { |
1460 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEUP); | 1460 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEUP); |
1461 | } else if (oldn->mute == newn->mute) { | 1461 | } else if (oldn->mute == newn->mute) { |
1462 | /* repeated key presses that didn't change state */ | 1462 | /* repeated key presses that didn't change state */ |
1463 | if (newn->mute) { | 1463 | if (newn->mute) { |
1464 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_MUTE); | 1464 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_MUTE); |
1465 | } else if (newn->volume_level != 0) { | 1465 | } else if (newn->volume_level != 0) { |
1466 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEUP); | 1466 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEUP); |
1467 | } else { | 1467 | } else { |
1468 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEDOWN); | 1468 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEDOWN); |
1469 | } | 1469 | } |
1470 | } | 1470 | } |
1471 | } | 1471 | } |
1472 | 1472 | ||
1473 | /* handle brightness */ | 1473 | /* handle brightness */ |
1474 | if (oldn->brightness_toggle != newn->brightness_toggle) { | 1474 | if (oldn->brightness_toggle != newn->brightness_toggle) { |
1475 | if (oldn->brightness_level < newn->brightness_level) { | 1475 | if (oldn->brightness_level < newn->brightness_level) { |
1476 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNHOME); | 1476 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNHOME); |
1477 | } else if (oldn->brightness_level > newn->brightness_level) { | 1477 | } else if (oldn->brightness_level > newn->brightness_level) { |
1478 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNEND); | 1478 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNEND); |
1479 | } else { | 1479 | } else { |
1480 | /* repeated key presses that didn't change state */ | 1480 | /* repeated key presses that didn't change state */ |
1481 | if (newn->brightness_level != 0) { | 1481 | if (newn->brightness_level != 0) { |
1482 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNHOME); | 1482 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNHOME); |
1483 | } else { | 1483 | } else { |
1484 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNEND); | 1484 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNEND); |
1485 | } | 1485 | } |
1486 | } | 1486 | } |
1487 | } | 1487 | } |
1488 | } | 1488 | } |
1489 | 1489 | ||
1490 | #undef TPACPI_COMPARE_KEY | 1490 | #undef TPACPI_COMPARE_KEY |
1491 | #undef TPACPI_MAY_SEND_KEY | 1491 | #undef TPACPI_MAY_SEND_KEY |
1492 | 1492 | ||
1493 | static int hotkey_kthread(void *data) | 1493 | static int hotkey_kthread(void *data) |
1494 | { | 1494 | { |
1495 | struct tp_nvram_state s[2]; | 1495 | struct tp_nvram_state s[2]; |
1496 | u32 mask; | 1496 | u32 mask; |
1497 | unsigned int si, so; | 1497 | unsigned int si, so; |
1498 | unsigned long t; | 1498 | unsigned long t; |
1499 | unsigned int change_detector, must_reset; | 1499 | unsigned int change_detector, must_reset; |
1500 | 1500 | ||
1501 | mutex_lock(&hotkey_thread_mutex); | 1501 | mutex_lock(&hotkey_thread_mutex); |
1502 | 1502 | ||
1503 | if (tpacpi_lifecycle == TPACPI_LIFE_EXITING) | 1503 | if (tpacpi_lifecycle == TPACPI_LIFE_EXITING) |
1504 | goto exit; | 1504 | goto exit; |
1505 | 1505 | ||
1506 | set_freezable(); | 1506 | set_freezable(); |
1507 | 1507 | ||
1508 | so = 0; | 1508 | so = 0; |
1509 | si = 1; | 1509 | si = 1; |
1510 | t = 0; | 1510 | t = 0; |
1511 | 1511 | ||
1512 | /* Initial state for compares */ | 1512 | /* Initial state for compares */ |
1513 | mutex_lock(&hotkey_thread_data_mutex); | 1513 | mutex_lock(&hotkey_thread_data_mutex); |
1514 | change_detector = hotkey_config_change; | 1514 | change_detector = hotkey_config_change; |
1515 | mask = hotkey_source_mask & hotkey_mask; | 1515 | mask = hotkey_source_mask & hotkey_mask; |
1516 | mutex_unlock(&hotkey_thread_data_mutex); | 1516 | mutex_unlock(&hotkey_thread_data_mutex); |
1517 | hotkey_read_nvram(&s[so], mask); | 1517 | hotkey_read_nvram(&s[so], mask); |
1518 | 1518 | ||
1519 | while (!kthread_should_stop() && hotkey_poll_freq) { | 1519 | while (!kthread_should_stop() && hotkey_poll_freq) { |
1520 | if (t == 0) | 1520 | if (t == 0) |
1521 | t = 1000/hotkey_poll_freq; | 1521 | t = 1000/hotkey_poll_freq; |
1522 | t = msleep_interruptible(t); | 1522 | t = msleep_interruptible(t); |
1523 | if (unlikely(kthread_should_stop())) | 1523 | if (unlikely(kthread_should_stop())) |
1524 | break; | 1524 | break; |
1525 | must_reset = try_to_freeze(); | 1525 | must_reset = try_to_freeze(); |
1526 | if (t > 0 && !must_reset) | 1526 | if (t > 0 && !must_reset) |
1527 | continue; | 1527 | continue; |
1528 | 1528 | ||
1529 | mutex_lock(&hotkey_thread_data_mutex); | 1529 | mutex_lock(&hotkey_thread_data_mutex); |
1530 | if (must_reset || hotkey_config_change != change_detector) { | 1530 | if (must_reset || hotkey_config_change != change_detector) { |
1531 | /* forget old state on thaw or config change */ | 1531 | /* forget old state on thaw or config change */ |
1532 | si = so; | 1532 | si = so; |
1533 | t = 0; | 1533 | t = 0; |
1534 | change_detector = hotkey_config_change; | 1534 | change_detector = hotkey_config_change; |
1535 | } | 1535 | } |
1536 | mask = hotkey_source_mask & hotkey_mask; | 1536 | mask = hotkey_source_mask & hotkey_mask; |
1537 | mutex_unlock(&hotkey_thread_data_mutex); | 1537 | mutex_unlock(&hotkey_thread_data_mutex); |
1538 | 1538 | ||
1539 | if (likely(mask)) { | 1539 | if (likely(mask)) { |
1540 | hotkey_read_nvram(&s[si], mask); | 1540 | hotkey_read_nvram(&s[si], mask); |
1541 | if (likely(si != so)) { | 1541 | if (likely(si != so)) { |
1542 | hotkey_compare_and_issue_event(&s[so], &s[si], | 1542 | hotkey_compare_and_issue_event(&s[so], &s[si], |
1543 | mask); | 1543 | mask); |
1544 | } | 1544 | } |
1545 | } | 1545 | } |
1546 | 1546 | ||
1547 | so = si; | 1547 | so = si; |
1548 | si ^= 1; | 1548 | si ^= 1; |
1549 | } | 1549 | } |
1550 | 1550 | ||
1551 | exit: | 1551 | exit: |
1552 | mutex_unlock(&hotkey_thread_mutex); | 1552 | mutex_unlock(&hotkey_thread_mutex); |
1553 | return 0; | 1553 | return 0; |
1554 | } | 1554 | } |
1555 | 1555 | ||
1556 | static void hotkey_poll_stop_sync(void) | 1556 | static void hotkey_poll_stop_sync(void) |
1557 | { | 1557 | { |
1558 | if (tpacpi_hotkey_task) { | 1558 | if (tpacpi_hotkey_task) { |
1559 | if (frozen(tpacpi_hotkey_task) || | 1559 | if (frozen(tpacpi_hotkey_task) || |
1560 | freezing(tpacpi_hotkey_task)) | 1560 | freezing(tpacpi_hotkey_task)) |
1561 | thaw_process(tpacpi_hotkey_task); | 1561 | thaw_process(tpacpi_hotkey_task); |
1562 | 1562 | ||
1563 | kthread_stop(tpacpi_hotkey_task); | 1563 | kthread_stop(tpacpi_hotkey_task); |
1564 | tpacpi_hotkey_task = NULL; | 1564 | tpacpi_hotkey_task = NULL; |
1565 | mutex_lock(&hotkey_thread_mutex); | 1565 | mutex_lock(&hotkey_thread_mutex); |
1566 | /* at this point, the thread did exit */ | 1566 | /* at this point, the thread did exit */ |
1567 | mutex_unlock(&hotkey_thread_mutex); | 1567 | mutex_unlock(&hotkey_thread_mutex); |
1568 | } | 1568 | } |
1569 | } | 1569 | } |
1570 | 1570 | ||
1571 | /* call with hotkey_mutex held */ | 1571 | /* call with hotkey_mutex held */ |
1572 | static void hotkey_poll_setup(int may_warn) | 1572 | static void hotkey_poll_setup(int may_warn) |
1573 | { | 1573 | { |
1574 | if ((hotkey_source_mask & hotkey_mask) != 0 && | 1574 | if ((hotkey_source_mask & hotkey_mask) != 0 && |
1575 | hotkey_poll_freq > 0 && | 1575 | hotkey_poll_freq > 0 && |
1576 | (tpacpi_inputdev->users > 0 || hotkey_report_mode < 2)) { | 1576 | (tpacpi_inputdev->users > 0 || hotkey_report_mode < 2)) { |
1577 | if (!tpacpi_hotkey_task) { | 1577 | if (!tpacpi_hotkey_task) { |
1578 | tpacpi_hotkey_task = kthread_run(hotkey_kthread, | 1578 | tpacpi_hotkey_task = kthread_run(hotkey_kthread, |
1579 | NULL, TPACPI_NVRAM_KTHREAD_NAME); | 1579 | NULL, TPACPI_NVRAM_KTHREAD_NAME); |
1580 | if (IS_ERR(tpacpi_hotkey_task)) { | 1580 | if (IS_ERR(tpacpi_hotkey_task)) { |
1581 | tpacpi_hotkey_task = NULL; | 1581 | tpacpi_hotkey_task = NULL; |
1582 | printk(TPACPI_ERR | 1582 | printk(TPACPI_ERR |
1583 | "could not create kernel thread " | 1583 | "could not create kernel thread " |
1584 | "for hotkey polling\n"); | 1584 | "for hotkey polling\n"); |
1585 | } | 1585 | } |
1586 | } | 1586 | } |
1587 | } else { | 1587 | } else { |
1588 | hotkey_poll_stop_sync(); | 1588 | hotkey_poll_stop_sync(); |
1589 | if (may_warn && | 1589 | if (may_warn && |
1590 | hotkey_source_mask != 0 && hotkey_poll_freq == 0) { | 1590 | hotkey_source_mask != 0 && hotkey_poll_freq == 0) { |
1591 | printk(TPACPI_NOTICE | 1591 | printk(TPACPI_NOTICE |
1592 | "hot keys 0x%08x require polling, " | 1592 | "hot keys 0x%08x require polling, " |
1593 | "which is currently disabled\n", | 1593 | "which is currently disabled\n", |
1594 | hotkey_source_mask); | 1594 | hotkey_source_mask); |
1595 | } | 1595 | } |
1596 | } | 1596 | } |
1597 | } | 1597 | } |
1598 | 1598 | ||
1599 | static void hotkey_poll_setup_safe(int may_warn) | 1599 | static void hotkey_poll_setup_safe(int may_warn) |
1600 | { | 1600 | { |
1601 | mutex_lock(&hotkey_mutex); | 1601 | mutex_lock(&hotkey_mutex); |
1602 | hotkey_poll_setup(may_warn); | 1602 | hotkey_poll_setup(may_warn); |
1603 | mutex_unlock(&hotkey_mutex); | 1603 | mutex_unlock(&hotkey_mutex); |
1604 | } | 1604 | } |
1605 | 1605 | ||
1606 | #else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ | 1606 | #else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ |
1607 | 1607 | ||
1608 | static void hotkey_poll_setup_safe(int __unused) | 1608 | static void hotkey_poll_setup_safe(int __unused) |
1609 | { | 1609 | { |
1610 | } | 1610 | } |
1611 | 1611 | ||
1612 | #endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ | 1612 | #endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ |
1613 | 1613 | ||
1614 | static int hotkey_inputdev_open(struct input_dev *dev) | 1614 | static int hotkey_inputdev_open(struct input_dev *dev) |
1615 | { | 1615 | { |
1616 | switch (tpacpi_lifecycle) { | 1616 | switch (tpacpi_lifecycle) { |
1617 | case TPACPI_LIFE_INIT: | 1617 | case TPACPI_LIFE_INIT: |
1618 | /* | 1618 | /* |
1619 | * hotkey_init will call hotkey_poll_setup_safe | 1619 | * hotkey_init will call hotkey_poll_setup_safe |
1620 | * at the appropriate moment | 1620 | * at the appropriate moment |
1621 | */ | 1621 | */ |
1622 | return 0; | 1622 | return 0; |
1623 | case TPACPI_LIFE_EXITING: | 1623 | case TPACPI_LIFE_EXITING: |
1624 | return -EBUSY; | 1624 | return -EBUSY; |
1625 | case TPACPI_LIFE_RUNNING: | 1625 | case TPACPI_LIFE_RUNNING: |
1626 | hotkey_poll_setup_safe(0); | 1626 | hotkey_poll_setup_safe(0); |
1627 | return 0; | 1627 | return 0; |
1628 | } | 1628 | } |
1629 | 1629 | ||
1630 | /* Should only happen if tpacpi_lifecycle is corrupt */ | 1630 | /* Should only happen if tpacpi_lifecycle is corrupt */ |
1631 | BUG(); | 1631 | BUG(); |
1632 | return -EBUSY; | 1632 | return -EBUSY; |
1633 | } | 1633 | } |
1634 | 1634 | ||
1635 | static void hotkey_inputdev_close(struct input_dev *dev) | 1635 | static void hotkey_inputdev_close(struct input_dev *dev) |
1636 | { | 1636 | { |
1637 | /* disable hotkey polling when possible */ | 1637 | /* disable hotkey polling when possible */ |
1638 | if (tpacpi_lifecycle == TPACPI_LIFE_RUNNING) | 1638 | if (tpacpi_lifecycle == TPACPI_LIFE_RUNNING) |
1639 | hotkey_poll_setup_safe(0); | 1639 | hotkey_poll_setup_safe(0); |
1640 | } | 1640 | } |
1641 | 1641 | ||
1642 | /* sysfs hotkey enable ------------------------------------------------- */ | 1642 | /* sysfs hotkey enable ------------------------------------------------- */ |
1643 | static ssize_t hotkey_enable_show(struct device *dev, | 1643 | static ssize_t hotkey_enable_show(struct device *dev, |
1644 | struct device_attribute *attr, | 1644 | struct device_attribute *attr, |
1645 | char *buf) | 1645 | char *buf) |
1646 | { | 1646 | { |
1647 | int res, status; | 1647 | int res, status; |
1648 | 1648 | ||
1649 | res = hotkey_status_get(&status); | 1649 | res = hotkey_status_get(&status); |
1650 | if (res) | 1650 | if (res) |
1651 | return res; | 1651 | return res; |
1652 | 1652 | ||
1653 | return snprintf(buf, PAGE_SIZE, "%d\n", status); | 1653 | return snprintf(buf, PAGE_SIZE, "%d\n", status); |
1654 | } | 1654 | } |
1655 | 1655 | ||
1656 | static ssize_t hotkey_enable_store(struct device *dev, | 1656 | static ssize_t hotkey_enable_store(struct device *dev, |
1657 | struct device_attribute *attr, | 1657 | struct device_attribute *attr, |
1658 | const char *buf, size_t count) | 1658 | const char *buf, size_t count) |
1659 | { | 1659 | { |
1660 | unsigned long t; | 1660 | unsigned long t; |
1661 | int res; | 1661 | int res; |
1662 | 1662 | ||
1663 | if (parse_strtoul(buf, 1, &t)) | 1663 | if (parse_strtoul(buf, 1, &t)) |
1664 | return -EINVAL; | 1664 | return -EINVAL; |
1665 | 1665 | ||
1666 | res = hotkey_status_set(t); | 1666 | res = hotkey_status_set(t); |
1667 | 1667 | ||
1668 | return (res) ? res : count; | 1668 | return (res) ? res : count; |
1669 | } | 1669 | } |
1670 | 1670 | ||
1671 | static struct device_attribute dev_attr_hotkey_enable = | 1671 | static struct device_attribute dev_attr_hotkey_enable = |
1672 | __ATTR(hotkey_enable, S_IWUSR | S_IRUGO, | 1672 | __ATTR(hotkey_enable, S_IWUSR | S_IRUGO, |
1673 | hotkey_enable_show, hotkey_enable_store); | 1673 | hotkey_enable_show, hotkey_enable_store); |
1674 | 1674 | ||
1675 | /* sysfs hotkey mask --------------------------------------------------- */ | 1675 | /* sysfs hotkey mask --------------------------------------------------- */ |
1676 | static ssize_t hotkey_mask_show(struct device *dev, | 1676 | static ssize_t hotkey_mask_show(struct device *dev, |
1677 | struct device_attribute *attr, | 1677 | struct device_attribute *attr, |
1678 | char *buf) | 1678 | char *buf) |
1679 | { | 1679 | { |
1680 | int res; | 1680 | int res; |
1681 | 1681 | ||
1682 | if (mutex_lock_interruptible(&hotkey_mutex)) | 1682 | if (mutex_lock_interruptible(&hotkey_mutex)) |
1683 | return -ERESTARTSYS; | 1683 | return -ERESTARTSYS; |
1684 | res = hotkey_mask_get(); | 1684 | res = hotkey_mask_get(); |
1685 | mutex_unlock(&hotkey_mutex); | 1685 | mutex_unlock(&hotkey_mutex); |
1686 | 1686 | ||
1687 | return (res)? | 1687 | return (res)? |
1688 | res : snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_mask); | 1688 | res : snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_mask); |
1689 | } | 1689 | } |
1690 | 1690 | ||
1691 | static ssize_t hotkey_mask_store(struct device *dev, | 1691 | static ssize_t hotkey_mask_store(struct device *dev, |
1692 | struct device_attribute *attr, | 1692 | struct device_attribute *attr, |
1693 | const char *buf, size_t count) | 1693 | const char *buf, size_t count) |
1694 | { | 1694 | { |
1695 | unsigned long t; | 1695 | unsigned long t; |
1696 | int res; | 1696 | int res; |
1697 | 1697 | ||
1698 | if (parse_strtoul(buf, 0xffffffffUL, &t)) | 1698 | if (parse_strtoul(buf, 0xffffffffUL, &t)) |
1699 | return -EINVAL; | 1699 | return -EINVAL; |
1700 | 1700 | ||
1701 | if (mutex_lock_interruptible(&hotkey_mutex)) | 1701 | if (mutex_lock_interruptible(&hotkey_mutex)) |
1702 | return -ERESTARTSYS; | 1702 | return -ERESTARTSYS; |
1703 | 1703 | ||
1704 | res = hotkey_mask_set(t); | 1704 | res = hotkey_mask_set(t); |
1705 | 1705 | ||
1706 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL | 1706 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL |
1707 | hotkey_poll_setup(1); | 1707 | hotkey_poll_setup(1); |
1708 | #endif | 1708 | #endif |
1709 | 1709 | ||
1710 | mutex_unlock(&hotkey_mutex); | 1710 | mutex_unlock(&hotkey_mutex); |
1711 | 1711 | ||
1712 | return (res) ? res : count; | 1712 | return (res) ? res : count; |
1713 | } | 1713 | } |
1714 | 1714 | ||
1715 | static struct device_attribute dev_attr_hotkey_mask = | 1715 | static struct device_attribute dev_attr_hotkey_mask = |
1716 | __ATTR(hotkey_mask, S_IWUSR | S_IRUGO, | 1716 | __ATTR(hotkey_mask, S_IWUSR | S_IRUGO, |
1717 | hotkey_mask_show, hotkey_mask_store); | 1717 | hotkey_mask_show, hotkey_mask_store); |
1718 | 1718 | ||
1719 | /* sysfs hotkey bios_enabled ------------------------------------------- */ | 1719 | /* sysfs hotkey bios_enabled ------------------------------------------- */ |
1720 | static ssize_t hotkey_bios_enabled_show(struct device *dev, | 1720 | static ssize_t hotkey_bios_enabled_show(struct device *dev, |
1721 | struct device_attribute *attr, | 1721 | struct device_attribute *attr, |
1722 | char *buf) | 1722 | char *buf) |
1723 | { | 1723 | { |
1724 | return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_orig_status); | 1724 | return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_orig_status); |
1725 | } | 1725 | } |
1726 | 1726 | ||
1727 | static struct device_attribute dev_attr_hotkey_bios_enabled = | 1727 | static struct device_attribute dev_attr_hotkey_bios_enabled = |
1728 | __ATTR(hotkey_bios_enabled, S_IRUGO, hotkey_bios_enabled_show, NULL); | 1728 | __ATTR(hotkey_bios_enabled, S_IRUGO, hotkey_bios_enabled_show, NULL); |
1729 | 1729 | ||
1730 | /* sysfs hotkey bios_mask ---------------------------------------------- */ | 1730 | /* sysfs hotkey bios_mask ---------------------------------------------- */ |
1731 | static ssize_t hotkey_bios_mask_show(struct device *dev, | 1731 | static ssize_t hotkey_bios_mask_show(struct device *dev, |
1732 | struct device_attribute *attr, | 1732 | struct device_attribute *attr, |
1733 | char *buf) | 1733 | char *buf) |
1734 | { | 1734 | { |
1735 | return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_orig_mask); | 1735 | return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_orig_mask); |
1736 | } | 1736 | } |
1737 | 1737 | ||
1738 | static struct device_attribute dev_attr_hotkey_bios_mask = | 1738 | static struct device_attribute dev_attr_hotkey_bios_mask = |
1739 | __ATTR(hotkey_bios_mask, S_IRUGO, hotkey_bios_mask_show, NULL); | 1739 | __ATTR(hotkey_bios_mask, S_IRUGO, hotkey_bios_mask_show, NULL); |
1740 | 1740 | ||
1741 | /* sysfs hotkey all_mask ----------------------------------------------- */ | 1741 | /* sysfs hotkey all_mask ----------------------------------------------- */ |
1742 | static ssize_t hotkey_all_mask_show(struct device *dev, | 1742 | static ssize_t hotkey_all_mask_show(struct device *dev, |
1743 | struct device_attribute *attr, | 1743 | struct device_attribute *attr, |
1744 | char *buf) | 1744 | char *buf) |
1745 | { | 1745 | { |
1746 | return snprintf(buf, PAGE_SIZE, "0x%08x\n", | 1746 | return snprintf(buf, PAGE_SIZE, "0x%08x\n", |
1747 | hotkey_all_mask | hotkey_source_mask); | 1747 | hotkey_all_mask | hotkey_source_mask); |
1748 | } | 1748 | } |
1749 | 1749 | ||
1750 | static struct device_attribute dev_attr_hotkey_all_mask = | 1750 | static struct device_attribute dev_attr_hotkey_all_mask = |
1751 | __ATTR(hotkey_all_mask, S_IRUGO, hotkey_all_mask_show, NULL); | 1751 | __ATTR(hotkey_all_mask, S_IRUGO, hotkey_all_mask_show, NULL); |
1752 | 1752 | ||
1753 | /* sysfs hotkey recommended_mask --------------------------------------- */ | 1753 | /* sysfs hotkey recommended_mask --------------------------------------- */ |
1754 | static ssize_t hotkey_recommended_mask_show(struct device *dev, | 1754 | static ssize_t hotkey_recommended_mask_show(struct device *dev, |
1755 | struct device_attribute *attr, | 1755 | struct device_attribute *attr, |
1756 | char *buf) | 1756 | char *buf) |
1757 | { | 1757 | { |
1758 | return snprintf(buf, PAGE_SIZE, "0x%08x\n", | 1758 | return snprintf(buf, PAGE_SIZE, "0x%08x\n", |
1759 | (hotkey_all_mask | hotkey_source_mask) | 1759 | (hotkey_all_mask | hotkey_source_mask) |
1760 | & ~hotkey_reserved_mask); | 1760 | & ~hotkey_reserved_mask); |
1761 | } | 1761 | } |
1762 | 1762 | ||
1763 | static struct device_attribute dev_attr_hotkey_recommended_mask = | 1763 | static struct device_attribute dev_attr_hotkey_recommended_mask = |
1764 | __ATTR(hotkey_recommended_mask, S_IRUGO, | 1764 | __ATTR(hotkey_recommended_mask, S_IRUGO, |
1765 | hotkey_recommended_mask_show, NULL); | 1765 | hotkey_recommended_mask_show, NULL); |
1766 | 1766 | ||
1767 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL | 1767 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL |
1768 | 1768 | ||
1769 | /* sysfs hotkey hotkey_source_mask ------------------------------------- */ | 1769 | /* sysfs hotkey hotkey_source_mask ------------------------------------- */ |
1770 | static ssize_t hotkey_source_mask_show(struct device *dev, | 1770 | static ssize_t hotkey_source_mask_show(struct device *dev, |
1771 | struct device_attribute *attr, | 1771 | struct device_attribute *attr, |
1772 | char *buf) | 1772 | char *buf) |
1773 | { | 1773 | { |
1774 | return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_source_mask); | 1774 | return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_source_mask); |
1775 | } | 1775 | } |
1776 | 1776 | ||
1777 | static ssize_t hotkey_source_mask_store(struct device *dev, | 1777 | static ssize_t hotkey_source_mask_store(struct device *dev, |
1778 | struct device_attribute *attr, | 1778 | struct device_attribute *attr, |
1779 | const char *buf, size_t count) | 1779 | const char *buf, size_t count) |
1780 | { | 1780 | { |
1781 | unsigned long t; | 1781 | unsigned long t; |
1782 | 1782 | ||
1783 | if (parse_strtoul(buf, 0xffffffffUL, &t) || | 1783 | if (parse_strtoul(buf, 0xffffffffUL, &t) || |
1784 | ((t & ~TPACPI_HKEY_NVRAM_KNOWN_MASK) != 0)) | 1784 | ((t & ~TPACPI_HKEY_NVRAM_KNOWN_MASK) != 0)) |
1785 | return -EINVAL; | 1785 | return -EINVAL; |
1786 | 1786 | ||
1787 | if (mutex_lock_interruptible(&hotkey_mutex)) | 1787 | if (mutex_lock_interruptible(&hotkey_mutex)) |
1788 | return -ERESTARTSYS; | 1788 | return -ERESTARTSYS; |
1789 | 1789 | ||
1790 | HOTKEY_CONFIG_CRITICAL_START | 1790 | HOTKEY_CONFIG_CRITICAL_START |
1791 | hotkey_source_mask = t; | 1791 | hotkey_source_mask = t; |
1792 | HOTKEY_CONFIG_CRITICAL_END | 1792 | HOTKEY_CONFIG_CRITICAL_END |
1793 | 1793 | ||
1794 | hotkey_poll_setup(1); | 1794 | hotkey_poll_setup(1); |
1795 | 1795 | ||
1796 | mutex_unlock(&hotkey_mutex); | 1796 | mutex_unlock(&hotkey_mutex); |
1797 | 1797 | ||
1798 | return count; | 1798 | return count; |
1799 | } | 1799 | } |
1800 | 1800 | ||
1801 | static struct device_attribute dev_attr_hotkey_source_mask = | 1801 | static struct device_attribute dev_attr_hotkey_source_mask = |
1802 | __ATTR(hotkey_source_mask, S_IWUSR | S_IRUGO, | 1802 | __ATTR(hotkey_source_mask, S_IWUSR | S_IRUGO, |
1803 | hotkey_source_mask_show, hotkey_source_mask_store); | 1803 | hotkey_source_mask_show, hotkey_source_mask_store); |
1804 | 1804 | ||
1805 | /* sysfs hotkey hotkey_poll_freq --------------------------------------- */ | 1805 | /* sysfs hotkey hotkey_poll_freq --------------------------------------- */ |
1806 | static ssize_t hotkey_poll_freq_show(struct device *dev, | 1806 | static ssize_t hotkey_poll_freq_show(struct device *dev, |
1807 | struct device_attribute *attr, | 1807 | struct device_attribute *attr, |
1808 | char *buf) | 1808 | char *buf) |
1809 | { | 1809 | { |
1810 | return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_poll_freq); | 1810 | return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_poll_freq); |
1811 | } | 1811 | } |
1812 | 1812 | ||
1813 | static ssize_t hotkey_poll_freq_store(struct device *dev, | 1813 | static ssize_t hotkey_poll_freq_store(struct device *dev, |
1814 | struct device_attribute *attr, | 1814 | struct device_attribute *attr, |
1815 | const char *buf, size_t count) | 1815 | const char *buf, size_t count) |
1816 | { | 1816 | { |
1817 | unsigned long t; | 1817 | unsigned long t; |
1818 | 1818 | ||
1819 | if (parse_strtoul(buf, 25, &t)) | 1819 | if (parse_strtoul(buf, 25, &t)) |
1820 | return -EINVAL; | 1820 | return -EINVAL; |
1821 | 1821 | ||
1822 | if (mutex_lock_interruptible(&hotkey_mutex)) | 1822 | if (mutex_lock_interruptible(&hotkey_mutex)) |
1823 | return -ERESTARTSYS; | 1823 | return -ERESTARTSYS; |
1824 | 1824 | ||
1825 | hotkey_poll_freq = t; | 1825 | hotkey_poll_freq = t; |
1826 | 1826 | ||
1827 | hotkey_poll_setup(1); | 1827 | hotkey_poll_setup(1); |
1828 | mutex_unlock(&hotkey_mutex); | 1828 | mutex_unlock(&hotkey_mutex); |
1829 | 1829 | ||
1830 | return count; | 1830 | return count; |
1831 | } | 1831 | } |
1832 | 1832 | ||
1833 | static struct device_attribute dev_attr_hotkey_poll_freq = | 1833 | static struct device_attribute dev_attr_hotkey_poll_freq = |
1834 | __ATTR(hotkey_poll_freq, S_IWUSR | S_IRUGO, | 1834 | __ATTR(hotkey_poll_freq, S_IWUSR | S_IRUGO, |
1835 | hotkey_poll_freq_show, hotkey_poll_freq_store); | 1835 | hotkey_poll_freq_show, hotkey_poll_freq_store); |
1836 | 1836 | ||
1837 | #endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ | 1837 | #endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ |
1838 | 1838 | ||
1839 | /* sysfs hotkey radio_sw (pollable) ------------------------------------ */ | 1839 | /* sysfs hotkey radio_sw (pollable) ------------------------------------ */ |
1840 | static ssize_t hotkey_radio_sw_show(struct device *dev, | 1840 | static ssize_t hotkey_radio_sw_show(struct device *dev, |
1841 | struct device_attribute *attr, | 1841 | struct device_attribute *attr, |
1842 | char *buf) | 1842 | char *buf) |
1843 | { | 1843 | { |
1844 | int res, s; | 1844 | int res, s; |
1845 | res = hotkey_get_wlsw(&s); | 1845 | res = hotkey_get_wlsw(&s); |
1846 | if (res < 0) | 1846 | if (res < 0) |
1847 | return res; | 1847 | return res; |
1848 | 1848 | ||
1849 | return snprintf(buf, PAGE_SIZE, "%d\n", !!s); | 1849 | return snprintf(buf, PAGE_SIZE, "%d\n", !!s); |
1850 | } | 1850 | } |
1851 | 1851 | ||
1852 | static struct device_attribute dev_attr_hotkey_radio_sw = | 1852 | static struct device_attribute dev_attr_hotkey_radio_sw = |
1853 | __ATTR(hotkey_radio_sw, S_IRUGO, hotkey_radio_sw_show, NULL); | 1853 | __ATTR(hotkey_radio_sw, S_IRUGO, hotkey_radio_sw_show, NULL); |
1854 | 1854 | ||
1855 | static void hotkey_radio_sw_notify_change(void) | 1855 | static void hotkey_radio_sw_notify_change(void) |
1856 | { | 1856 | { |
1857 | if (tp_features.hotkey_wlsw) | 1857 | if (tp_features.hotkey_wlsw) |
1858 | sysfs_notify(&tpacpi_pdev->dev.kobj, NULL, | 1858 | sysfs_notify(&tpacpi_pdev->dev.kobj, NULL, |
1859 | "hotkey_radio_sw"); | 1859 | "hotkey_radio_sw"); |
1860 | } | 1860 | } |
1861 | 1861 | ||
1862 | /* sysfs hotkey tablet mode (pollable) --------------------------------- */ | 1862 | /* sysfs hotkey tablet mode (pollable) --------------------------------- */ |
1863 | static ssize_t hotkey_tablet_mode_show(struct device *dev, | 1863 | static ssize_t hotkey_tablet_mode_show(struct device *dev, |
1864 | struct device_attribute *attr, | 1864 | struct device_attribute *attr, |
1865 | char *buf) | 1865 | char *buf) |
1866 | { | 1866 | { |
1867 | int res, s; | 1867 | int res, s; |
1868 | res = hotkey_get_tablet_mode(&s); | 1868 | res = hotkey_get_tablet_mode(&s); |
1869 | if (res < 0) | 1869 | if (res < 0) |
1870 | return res; | 1870 | return res; |
1871 | 1871 | ||
1872 | return snprintf(buf, PAGE_SIZE, "%d\n", !!s); | 1872 | return snprintf(buf, PAGE_SIZE, "%d\n", !!s); |
1873 | } | 1873 | } |
1874 | 1874 | ||
1875 | static struct device_attribute dev_attr_hotkey_tablet_mode = | 1875 | static struct device_attribute dev_attr_hotkey_tablet_mode = |
1876 | __ATTR(hotkey_tablet_mode, S_IRUGO, hotkey_tablet_mode_show, NULL); | 1876 | __ATTR(hotkey_tablet_mode, S_IRUGO, hotkey_tablet_mode_show, NULL); |
1877 | 1877 | ||
1878 | static void hotkey_tablet_mode_notify_change(void) | 1878 | static void hotkey_tablet_mode_notify_change(void) |
1879 | { | 1879 | { |
1880 | if (tp_features.hotkey_tablet) | 1880 | if (tp_features.hotkey_tablet) |
1881 | sysfs_notify(&tpacpi_pdev->dev.kobj, NULL, | 1881 | sysfs_notify(&tpacpi_pdev->dev.kobj, NULL, |
1882 | "hotkey_tablet_mode"); | 1882 | "hotkey_tablet_mode"); |
1883 | } | 1883 | } |
1884 | 1884 | ||
1885 | /* sysfs hotkey report_mode -------------------------------------------- */ | 1885 | /* sysfs hotkey report_mode -------------------------------------------- */ |
1886 | static ssize_t hotkey_report_mode_show(struct device *dev, | 1886 | static ssize_t hotkey_report_mode_show(struct device *dev, |
1887 | struct device_attribute *attr, | 1887 | struct device_attribute *attr, |
1888 | char *buf) | 1888 | char *buf) |
1889 | { | 1889 | { |
1890 | return snprintf(buf, PAGE_SIZE, "%d\n", | 1890 | return snprintf(buf, PAGE_SIZE, "%d\n", |
1891 | (hotkey_report_mode != 0) ? hotkey_report_mode : 1); | 1891 | (hotkey_report_mode != 0) ? hotkey_report_mode : 1); |
1892 | } | 1892 | } |
1893 | 1893 | ||
1894 | static struct device_attribute dev_attr_hotkey_report_mode = | 1894 | static struct device_attribute dev_attr_hotkey_report_mode = |
1895 | __ATTR(hotkey_report_mode, S_IRUGO, hotkey_report_mode_show, NULL); | 1895 | __ATTR(hotkey_report_mode, S_IRUGO, hotkey_report_mode_show, NULL); |
1896 | 1896 | ||
1897 | /* sysfs wakeup reason (pollable) -------------------------------------- */ | 1897 | /* sysfs wakeup reason (pollable) -------------------------------------- */ |
1898 | static ssize_t hotkey_wakeup_reason_show(struct device *dev, | 1898 | static ssize_t hotkey_wakeup_reason_show(struct device *dev, |
1899 | struct device_attribute *attr, | 1899 | struct device_attribute *attr, |
1900 | char *buf) | 1900 | char *buf) |
1901 | { | 1901 | { |
1902 | return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_wakeup_reason); | 1902 | return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_wakeup_reason); |
1903 | } | 1903 | } |
1904 | 1904 | ||
1905 | static struct device_attribute dev_attr_hotkey_wakeup_reason = | 1905 | static struct device_attribute dev_attr_hotkey_wakeup_reason = |
1906 | __ATTR(wakeup_reason, S_IRUGO, hotkey_wakeup_reason_show, NULL); | 1906 | __ATTR(wakeup_reason, S_IRUGO, hotkey_wakeup_reason_show, NULL); |
1907 | 1907 | ||
1908 | static void hotkey_wakeup_reason_notify_change(void) | 1908 | static void hotkey_wakeup_reason_notify_change(void) |
1909 | { | 1909 | { |
1910 | if (tp_features.hotkey_mask) | 1910 | if (tp_features.hotkey_mask) |
1911 | sysfs_notify(&tpacpi_pdev->dev.kobj, NULL, | 1911 | sysfs_notify(&tpacpi_pdev->dev.kobj, NULL, |
1912 | "wakeup_reason"); | 1912 | "wakeup_reason"); |
1913 | } | 1913 | } |
1914 | 1914 | ||
1915 | /* sysfs wakeup hotunplug_complete (pollable) -------------------------- */ | 1915 | /* sysfs wakeup hotunplug_complete (pollable) -------------------------- */ |
1916 | static ssize_t hotkey_wakeup_hotunplug_complete_show(struct device *dev, | 1916 | static ssize_t hotkey_wakeup_hotunplug_complete_show(struct device *dev, |
1917 | struct device_attribute *attr, | 1917 | struct device_attribute *attr, |
1918 | char *buf) | 1918 | char *buf) |
1919 | { | 1919 | { |
1920 | return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_autosleep_ack); | 1920 | return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_autosleep_ack); |
1921 | } | 1921 | } |
1922 | 1922 | ||
1923 | static struct device_attribute dev_attr_hotkey_wakeup_hotunplug_complete = | 1923 | static struct device_attribute dev_attr_hotkey_wakeup_hotunplug_complete = |
1924 | __ATTR(wakeup_hotunplug_complete, S_IRUGO, | 1924 | __ATTR(wakeup_hotunplug_complete, S_IRUGO, |
1925 | hotkey_wakeup_hotunplug_complete_show, NULL); | 1925 | hotkey_wakeup_hotunplug_complete_show, NULL); |
1926 | 1926 | ||
1927 | static void hotkey_wakeup_hotunplug_complete_notify_change(void) | 1927 | static void hotkey_wakeup_hotunplug_complete_notify_change(void) |
1928 | { | 1928 | { |
1929 | if (tp_features.hotkey_mask) | 1929 | if (tp_features.hotkey_mask) |
1930 | sysfs_notify(&tpacpi_pdev->dev.kobj, NULL, | 1930 | sysfs_notify(&tpacpi_pdev->dev.kobj, NULL, |
1931 | "wakeup_hotunplug_complete"); | 1931 | "wakeup_hotunplug_complete"); |
1932 | } | 1932 | } |
1933 | 1933 | ||
1934 | /* --------------------------------------------------------------------- */ | 1934 | /* --------------------------------------------------------------------- */ |
1935 | 1935 | ||
1936 | static struct attribute *hotkey_attributes[] __initdata = { | 1936 | static struct attribute *hotkey_attributes[] __initdata = { |
1937 | &dev_attr_hotkey_enable.attr, | 1937 | &dev_attr_hotkey_enable.attr, |
1938 | &dev_attr_hotkey_bios_enabled.attr, | 1938 | &dev_attr_hotkey_bios_enabled.attr, |
1939 | &dev_attr_hotkey_report_mode.attr, | 1939 | &dev_attr_hotkey_report_mode.attr, |
1940 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL | 1940 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL |
1941 | &dev_attr_hotkey_mask.attr, | 1941 | &dev_attr_hotkey_mask.attr, |
1942 | &dev_attr_hotkey_all_mask.attr, | 1942 | &dev_attr_hotkey_all_mask.attr, |
1943 | &dev_attr_hotkey_recommended_mask.attr, | 1943 | &dev_attr_hotkey_recommended_mask.attr, |
1944 | &dev_attr_hotkey_source_mask.attr, | 1944 | &dev_attr_hotkey_source_mask.attr, |
1945 | &dev_attr_hotkey_poll_freq.attr, | 1945 | &dev_attr_hotkey_poll_freq.attr, |
1946 | #endif | 1946 | #endif |
1947 | }; | 1947 | }; |
1948 | 1948 | ||
1949 | static struct attribute *hotkey_mask_attributes[] __initdata = { | 1949 | static struct attribute *hotkey_mask_attributes[] __initdata = { |
1950 | &dev_attr_hotkey_bios_mask.attr, | 1950 | &dev_attr_hotkey_bios_mask.attr, |
1951 | #ifndef CONFIG_THINKPAD_ACPI_HOTKEY_POLL | 1951 | #ifndef CONFIG_THINKPAD_ACPI_HOTKEY_POLL |
1952 | &dev_attr_hotkey_mask.attr, | 1952 | &dev_attr_hotkey_mask.attr, |
1953 | &dev_attr_hotkey_all_mask.attr, | 1953 | &dev_attr_hotkey_all_mask.attr, |
1954 | &dev_attr_hotkey_recommended_mask.attr, | 1954 | &dev_attr_hotkey_recommended_mask.attr, |
1955 | #endif | 1955 | #endif |
1956 | &dev_attr_hotkey_wakeup_reason.attr, | 1956 | &dev_attr_hotkey_wakeup_reason.attr, |
1957 | &dev_attr_hotkey_wakeup_hotunplug_complete.attr, | 1957 | &dev_attr_hotkey_wakeup_hotunplug_complete.attr, |
1958 | }; | 1958 | }; |
1959 | 1959 | ||
1960 | static void bluetooth_update_rfk(void); | 1960 | static void bluetooth_update_rfk(void); |
1961 | static void wan_update_rfk(void); | 1961 | static void wan_update_rfk(void); |
1962 | static void tpacpi_send_radiosw_update(void) | 1962 | static void tpacpi_send_radiosw_update(void) |
1963 | { | 1963 | { |
1964 | int wlsw; | 1964 | int wlsw; |
1965 | 1965 | ||
1966 | /* Sync these BEFORE sending any rfkill events */ | 1966 | /* Sync these BEFORE sending any rfkill events */ |
1967 | if (tp_features.bluetooth) | 1967 | if (tp_features.bluetooth) |
1968 | bluetooth_update_rfk(); | 1968 | bluetooth_update_rfk(); |
1969 | if (tp_features.wan) | 1969 | if (tp_features.wan) |
1970 | wan_update_rfk(); | 1970 | wan_update_rfk(); |
1971 | 1971 | ||
1972 | if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) { | 1972 | if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) { |
1973 | mutex_lock(&tpacpi_inputdev_send_mutex); | 1973 | mutex_lock(&tpacpi_inputdev_send_mutex); |
1974 | 1974 | ||
1975 | input_report_switch(tpacpi_inputdev, | 1975 | input_report_switch(tpacpi_inputdev, |
1976 | SW_RFKILL_ALL, !!wlsw); | 1976 | SW_RFKILL_ALL, !!wlsw); |
1977 | input_sync(tpacpi_inputdev); | 1977 | input_sync(tpacpi_inputdev); |
1978 | 1978 | ||
1979 | mutex_unlock(&tpacpi_inputdev_send_mutex); | 1979 | mutex_unlock(&tpacpi_inputdev_send_mutex); |
1980 | } | 1980 | } |
1981 | hotkey_radio_sw_notify_change(); | 1981 | hotkey_radio_sw_notify_change(); |
1982 | } | 1982 | } |
1983 | 1983 | ||
1984 | static void hotkey_exit(void) | 1984 | static void hotkey_exit(void) |
1985 | { | 1985 | { |
1986 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL | 1986 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL |
1987 | hotkey_poll_stop_sync(); | 1987 | hotkey_poll_stop_sync(); |
1988 | #endif | 1988 | #endif |
1989 | 1989 | ||
1990 | if (hotkey_dev_attributes) | 1990 | if (hotkey_dev_attributes) |
1991 | delete_attr_set(hotkey_dev_attributes, &tpacpi_pdev->dev.kobj); | 1991 | delete_attr_set(hotkey_dev_attributes, &tpacpi_pdev->dev.kobj); |
1992 | 1992 | ||
1993 | kfree(hotkey_keycode_map); | 1993 | kfree(hotkey_keycode_map); |
1994 | 1994 | ||
1995 | if (tp_features.hotkey) { | 1995 | if (tp_features.hotkey) { |
1996 | dbg_printk(TPACPI_DBG_EXIT, | 1996 | dbg_printk(TPACPI_DBG_EXIT, |
1997 | "restoring original hot key mask\n"); | 1997 | "restoring original hot key mask\n"); |
1998 | /* no short-circuit boolean operator below! */ | 1998 | /* no short-circuit boolean operator below! */ |
1999 | if ((hotkey_mask_set(hotkey_orig_mask) | | 1999 | if ((hotkey_mask_set(hotkey_orig_mask) | |
2000 | hotkey_status_set(hotkey_orig_status)) != 0) | 2000 | hotkey_status_set(hotkey_orig_status)) != 0) |
2001 | printk(TPACPI_ERR | 2001 | printk(TPACPI_ERR |
2002 | "failed to restore hot key mask " | 2002 | "failed to restore hot key mask " |
2003 | "to BIOS defaults\n"); | 2003 | "to BIOS defaults\n"); |
2004 | } | 2004 | } |
2005 | } | 2005 | } |
2006 | 2006 | ||
2007 | static int __init hotkey_init(struct ibm_init_struct *iibm) | 2007 | static int __init hotkey_init(struct ibm_init_struct *iibm) |
2008 | { | 2008 | { |
2009 | /* Requirements for changing the default keymaps: | 2009 | /* Requirements for changing the default keymaps: |
2010 | * | 2010 | * |
2011 | * 1. Many of the keys are mapped to KEY_RESERVED for very | 2011 | * 1. Many of the keys are mapped to KEY_RESERVED for very |
2012 | * good reasons. Do not change them unless you have deep | 2012 | * good reasons. Do not change them unless you have deep |
2013 | * knowledge on the IBM and Lenovo ThinkPad firmware for | 2013 | * knowledge on the IBM and Lenovo ThinkPad firmware for |
2014 | * the various ThinkPad models. The driver behaves | 2014 | * the various ThinkPad models. The driver behaves |
2015 | * differently for KEY_RESERVED: such keys have their | 2015 | * differently for KEY_RESERVED: such keys have their |
2016 | * hot key mask *unset* in mask_recommended, and also | 2016 | * hot key mask *unset* in mask_recommended, and also |
2017 | * in the initial hot key mask programmed into the | 2017 | * in the initial hot key mask programmed into the |
2018 | * firmware at driver load time, which means the firm- | 2018 | * firmware at driver load time, which means the firm- |
2019 | * ware may react very differently if you change them to | 2019 | * ware may react very differently if you change them to |
2020 | * something else; | 2020 | * something else; |
2021 | * | 2021 | * |
2022 | * 2. You must be subscribed to the linux-thinkpad and | 2022 | * 2. You must be subscribed to the linux-thinkpad and |
2023 | * ibm-acpi-devel mailing lists, and you should read the | 2023 | * ibm-acpi-devel mailing lists, and you should read the |
2024 | * list archives since 2007 if you want to change the | 2024 | * list archives since 2007 if you want to change the |
2025 | * keymaps. This requirement exists so that you will | 2025 | * keymaps. This requirement exists so that you will |
2026 | * know the past history of problems with the thinkpad- | 2026 | * know the past history of problems with the thinkpad- |
2027 | * acpi driver keymaps, and also that you will be | 2027 | * acpi driver keymaps, and also that you will be |
2028 | * listening to any bug reports; | 2028 | * listening to any bug reports; |
2029 | * | 2029 | * |
2030 | * 3. Do not send thinkpad-acpi specific patches directly to | 2030 | * 3. Do not send thinkpad-acpi specific patches directly to |
2031 | * for merging, *ever*. Send them to the linux-acpi | 2031 | * for merging, *ever*. Send them to the linux-acpi |
2032 | * mailinglist for comments. Merging is to be done only | 2032 | * mailinglist for comments. Merging is to be done only |
2033 | * through acpi-test and the ACPI maintainer. | 2033 | * through acpi-test and the ACPI maintainer. |
2034 | * | 2034 | * |
2035 | * If the above is too much to ask, don't change the keymap. | 2035 | * If the above is too much to ask, don't change the keymap. |
2036 | * Ask the thinkpad-acpi maintainer to do it, instead. | 2036 | * Ask the thinkpad-acpi maintainer to do it, instead. |
2037 | */ | 2037 | */ |
2038 | static u16 ibm_keycode_map[] __initdata = { | 2038 | static u16 ibm_keycode_map[] __initdata = { |
2039 | /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */ | 2039 | /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */ |
2040 | KEY_FN_F1, KEY_FN_F2, KEY_COFFEE, KEY_SLEEP, | 2040 | KEY_FN_F1, KEY_FN_F2, KEY_COFFEE, KEY_SLEEP, |
2041 | KEY_WLAN, KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8, | 2041 | KEY_WLAN, KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8, |
2042 | KEY_FN_F9, KEY_FN_F10, KEY_FN_F11, KEY_SUSPEND, | 2042 | KEY_FN_F9, KEY_FN_F10, KEY_FN_F11, KEY_SUSPEND, |
2043 | 2043 | ||
2044 | /* Scan codes 0x0C to 0x1F: Other ACPI HKEY hot keys */ | 2044 | /* Scan codes 0x0C to 0x1F: Other ACPI HKEY hot keys */ |
2045 | KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */ | 2045 | KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */ |
2046 | KEY_UNKNOWN, /* 0x0D: FN+INSERT */ | 2046 | KEY_UNKNOWN, /* 0x0D: FN+INSERT */ |
2047 | KEY_UNKNOWN, /* 0x0E: FN+DELETE */ | 2047 | KEY_UNKNOWN, /* 0x0E: FN+DELETE */ |
2048 | 2048 | ||
2049 | /* brightness: firmware always reacts to them, unless | 2049 | /* brightness: firmware always reacts to them, unless |
2050 | * X.org did some tricks in the radeon BIOS scratch | 2050 | * X.org did some tricks in the radeon BIOS scratch |
2051 | * registers of *some* models */ | 2051 | * registers of *some* models */ |
2052 | KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */ | 2052 | KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */ |
2053 | KEY_RESERVED, /* 0x10: FN+END (brightness down) */ | 2053 | KEY_RESERVED, /* 0x10: FN+END (brightness down) */ |
2054 | 2054 | ||
2055 | /* Thinklight: firmware always react to it */ | 2055 | /* Thinklight: firmware always react to it */ |
2056 | KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */ | 2056 | KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */ |
2057 | 2057 | ||
2058 | KEY_UNKNOWN, /* 0x12: FN+PGDOWN */ | 2058 | KEY_UNKNOWN, /* 0x12: FN+PGDOWN */ |
2059 | KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */ | 2059 | KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */ |
2060 | 2060 | ||
2061 | /* Volume: firmware always react to it and reprograms | 2061 | /* Volume: firmware always react to it and reprograms |
2062 | * the built-in *extra* mixer. Never map it to control | 2062 | * the built-in *extra* mixer. Never map it to control |
2063 | * another mixer by default. */ | 2063 | * another mixer by default. */ |
2064 | KEY_RESERVED, /* 0x14: VOLUME UP */ | 2064 | KEY_RESERVED, /* 0x14: VOLUME UP */ |
2065 | KEY_RESERVED, /* 0x15: VOLUME DOWN */ | 2065 | KEY_RESERVED, /* 0x15: VOLUME DOWN */ |
2066 | KEY_RESERVED, /* 0x16: MUTE */ | 2066 | KEY_RESERVED, /* 0x16: MUTE */ |
2067 | 2067 | ||
2068 | KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */ | 2068 | KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */ |
2069 | 2069 | ||
2070 | /* (assignments unknown, please report if found) */ | 2070 | /* (assignments unknown, please report if found) */ |
2071 | KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, | 2071 | KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, |
2072 | KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, | 2072 | KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, |
2073 | }; | 2073 | }; |
2074 | static u16 lenovo_keycode_map[] __initdata = { | 2074 | static u16 lenovo_keycode_map[] __initdata = { |
2075 | /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */ | 2075 | /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */ |
2076 | KEY_FN_F1, KEY_COFFEE, KEY_BATTERY, KEY_SLEEP, | 2076 | KEY_FN_F1, KEY_COFFEE, KEY_BATTERY, KEY_SLEEP, |
2077 | KEY_WLAN, KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8, | 2077 | KEY_WLAN, KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8, |
2078 | KEY_FN_F9, KEY_FN_F10, KEY_FN_F11, KEY_SUSPEND, | 2078 | KEY_FN_F9, KEY_FN_F10, KEY_FN_F11, KEY_SUSPEND, |
2079 | 2079 | ||
2080 | /* Scan codes 0x0C to 0x1F: Other ACPI HKEY hot keys */ | 2080 | /* Scan codes 0x0C to 0x1F: Other ACPI HKEY hot keys */ |
2081 | KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */ | 2081 | KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */ |
2082 | KEY_UNKNOWN, /* 0x0D: FN+INSERT */ | 2082 | KEY_UNKNOWN, /* 0x0D: FN+INSERT */ |
2083 | KEY_UNKNOWN, /* 0x0E: FN+DELETE */ | 2083 | KEY_UNKNOWN, /* 0x0E: FN+DELETE */ |
2084 | 2084 | ||
2085 | /* These either have to go through ACPI video, or | 2085 | /* These either have to go through ACPI video, or |
2086 | * act like in the IBM ThinkPads, so don't ever | 2086 | * act like in the IBM ThinkPads, so don't ever |
2087 | * enable them by default */ | 2087 | * enable them by default */ |
2088 | KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */ | 2088 | KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */ |
2089 | KEY_RESERVED, /* 0x10: FN+END (brightness down) */ | 2089 | KEY_RESERVED, /* 0x10: FN+END (brightness down) */ |
2090 | 2090 | ||
2091 | KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */ | 2091 | KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */ |
2092 | 2092 | ||
2093 | KEY_UNKNOWN, /* 0x12: FN+PGDOWN */ | 2093 | KEY_UNKNOWN, /* 0x12: FN+PGDOWN */ |
2094 | KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */ | 2094 | KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */ |
2095 | 2095 | ||
2096 | /* Volume: z60/z61, T60 (BIOS version?): firmware always | 2096 | /* Volume: z60/z61, T60 (BIOS version?): firmware always |
2097 | * react to it and reprograms the built-in *extra* mixer. | 2097 | * react to it and reprograms the built-in *extra* mixer. |
2098 | * Never map it to control another mixer by default. | 2098 | * Never map it to control another mixer by default. |
2099 | * | 2099 | * |
2100 | * T60?, T61, R60?, R61: firmware and EC tries to send | 2100 | * T60?, T61, R60?, R61: firmware and EC tries to send |
2101 | * these over the regular keyboard, so these are no-ops, | 2101 | * these over the regular keyboard, so these are no-ops, |
2102 | * but there are still weird bugs re. MUTE, so do not | 2102 | * but there are still weird bugs re. MUTE, so do not |
2103 | * change unless you get test reports from all Lenovo | 2103 | * change unless you get test reports from all Lenovo |
2104 | * models. May cause the BIOS to interfere with the | 2104 | * models. May cause the BIOS to interfere with the |
2105 | * HDA mixer. | 2105 | * HDA mixer. |
2106 | */ | 2106 | */ |
2107 | KEY_RESERVED, /* 0x14: VOLUME UP */ | 2107 | KEY_RESERVED, /* 0x14: VOLUME UP */ |
2108 | KEY_RESERVED, /* 0x15: VOLUME DOWN */ | 2108 | KEY_RESERVED, /* 0x15: VOLUME DOWN */ |
2109 | KEY_RESERVED, /* 0x16: MUTE */ | 2109 | KEY_RESERVED, /* 0x16: MUTE */ |
2110 | 2110 | ||
2111 | KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */ | 2111 | KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */ |
2112 | 2112 | ||
2113 | /* (assignments unknown, please report if found) */ | 2113 | /* (assignments unknown, please report if found) */ |
2114 | KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, | 2114 | KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, |
2115 | KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, | 2115 | KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, |
2116 | }; | 2116 | }; |
2117 | 2117 | ||
2118 | #define TPACPI_HOTKEY_MAP_LEN ARRAY_SIZE(ibm_keycode_map) | 2118 | #define TPACPI_HOTKEY_MAP_LEN ARRAY_SIZE(ibm_keycode_map) |
2119 | #define TPACPI_HOTKEY_MAP_SIZE sizeof(ibm_keycode_map) | 2119 | #define TPACPI_HOTKEY_MAP_SIZE sizeof(ibm_keycode_map) |
2120 | #define TPACPI_HOTKEY_MAP_TYPESIZE sizeof(ibm_keycode_map[0]) | 2120 | #define TPACPI_HOTKEY_MAP_TYPESIZE sizeof(ibm_keycode_map[0]) |
2121 | 2121 | ||
2122 | int res, i; | 2122 | int res, i; |
2123 | int status; | 2123 | int status; |
2124 | int hkeyv; | 2124 | int hkeyv; |
2125 | 2125 | ||
2126 | vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n"); | 2126 | vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n"); |
2127 | 2127 | ||
2128 | BUG_ON(!tpacpi_inputdev); | 2128 | BUG_ON(!tpacpi_inputdev); |
2129 | BUG_ON(tpacpi_inputdev->open != NULL || | 2129 | BUG_ON(tpacpi_inputdev->open != NULL || |
2130 | tpacpi_inputdev->close != NULL); | 2130 | tpacpi_inputdev->close != NULL); |
2131 | 2131 | ||
2132 | TPACPI_ACPIHANDLE_INIT(hkey); | 2132 | TPACPI_ACPIHANDLE_INIT(hkey); |
2133 | mutex_init(&hotkey_mutex); | 2133 | mutex_init(&hotkey_mutex); |
2134 | 2134 | ||
2135 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL | 2135 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL |
2136 | mutex_init(&hotkey_thread_mutex); | 2136 | mutex_init(&hotkey_thread_mutex); |
2137 | mutex_init(&hotkey_thread_data_mutex); | 2137 | mutex_init(&hotkey_thread_data_mutex); |
2138 | #endif | 2138 | #endif |
2139 | 2139 | ||
2140 | /* hotkey not supported on 570 */ | 2140 | /* hotkey not supported on 570 */ |
2141 | tp_features.hotkey = hkey_handle != NULL; | 2141 | tp_features.hotkey = hkey_handle != NULL; |
2142 | 2142 | ||
2143 | vdbg_printk(TPACPI_DBG_INIT, "hotkeys are %s\n", | 2143 | vdbg_printk(TPACPI_DBG_INIT, "hotkeys are %s\n", |
2144 | str_supported(tp_features.hotkey)); | 2144 | str_supported(tp_features.hotkey)); |
2145 | 2145 | ||
2146 | if (!tp_features.hotkey) | 2146 | if (!tp_features.hotkey) |
2147 | return 1; | 2147 | return 1; |
2148 | 2148 | ||
2149 | tpacpi_disable_brightness_delay(); | 2149 | tpacpi_disable_brightness_delay(); |
2150 | 2150 | ||
2151 | hotkey_dev_attributes = create_attr_set(13, NULL); | 2151 | hotkey_dev_attributes = create_attr_set(13, NULL); |
2152 | if (!hotkey_dev_attributes) | 2152 | if (!hotkey_dev_attributes) |
2153 | return -ENOMEM; | 2153 | return -ENOMEM; |
2154 | res = add_many_to_attr_set(hotkey_dev_attributes, | 2154 | res = add_many_to_attr_set(hotkey_dev_attributes, |
2155 | hotkey_attributes, | 2155 | hotkey_attributes, |
2156 | ARRAY_SIZE(hotkey_attributes)); | 2156 | ARRAY_SIZE(hotkey_attributes)); |
2157 | if (res) | 2157 | if (res) |
2158 | goto err_exit; | 2158 | goto err_exit; |
2159 | 2159 | ||
2160 | /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, | 2160 | /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, |
2161 | A30, R30, R31, T20-22, X20-21, X22-24. Detected by checking | 2161 | A30, R30, R31, T20-22, X20-21, X22-24. Detected by checking |
2162 | for HKEY interface version 0x100 */ | 2162 | for HKEY interface version 0x100 */ |
2163 | if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) { | 2163 | if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) { |
2164 | if ((hkeyv >> 8) != 1) { | 2164 | if ((hkeyv >> 8) != 1) { |
2165 | printk(TPACPI_ERR "unknown version of the " | 2165 | printk(TPACPI_ERR "unknown version of the " |
2166 | "HKEY interface: 0x%x\n", hkeyv); | 2166 | "HKEY interface: 0x%x\n", hkeyv); |
2167 | printk(TPACPI_ERR "please report this to %s\n", | 2167 | printk(TPACPI_ERR "please report this to %s\n", |
2168 | TPACPI_MAIL); | 2168 | TPACPI_MAIL); |
2169 | } else { | 2169 | } else { |
2170 | /* | 2170 | /* |
2171 | * MHKV 0x100 in A31, R40, R40e, | 2171 | * MHKV 0x100 in A31, R40, R40e, |
2172 | * T4x, X31, and later | 2172 | * T4x, X31, and later |
2173 | */ | 2173 | */ |
2174 | tp_features.hotkey_mask = 1; | 2174 | tp_features.hotkey_mask = 1; |
2175 | } | 2175 | } |
2176 | } | 2176 | } |
2177 | 2177 | ||
2178 | vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n", | 2178 | vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n", |
2179 | str_supported(tp_features.hotkey_mask)); | 2179 | str_supported(tp_features.hotkey_mask)); |
2180 | 2180 | ||
2181 | if (tp_features.hotkey_mask) { | 2181 | if (tp_features.hotkey_mask) { |
2182 | if (!acpi_evalf(hkey_handle, &hotkey_all_mask, | 2182 | if (!acpi_evalf(hkey_handle, &hotkey_all_mask, |
2183 | "MHKA", "qd")) { | 2183 | "MHKA", "qd")) { |
2184 | printk(TPACPI_ERR | 2184 | printk(TPACPI_ERR |
2185 | "missing MHKA handler, " | 2185 | "missing MHKA handler, " |
2186 | "please report this to %s\n", | 2186 | "please report this to %s\n", |
2187 | TPACPI_MAIL); | 2187 | TPACPI_MAIL); |
2188 | /* FN+F12, FN+F4, FN+F3 */ | 2188 | /* FN+F12, FN+F4, FN+F3 */ |
2189 | hotkey_all_mask = 0x080cU; | 2189 | hotkey_all_mask = 0x080cU; |
2190 | } | 2190 | } |
2191 | } | 2191 | } |
2192 | 2192 | ||
2193 | /* hotkey_source_mask *must* be zero for | 2193 | /* hotkey_source_mask *must* be zero for |
2194 | * the first hotkey_mask_get */ | 2194 | * the first hotkey_mask_get */ |
2195 | res = hotkey_status_get(&hotkey_orig_status); | 2195 | res = hotkey_status_get(&hotkey_orig_status); |
2196 | if (res) | 2196 | if (res) |
2197 | goto err_exit; | 2197 | goto err_exit; |
2198 | 2198 | ||
2199 | if (tp_features.hotkey_mask) { | 2199 | if (tp_features.hotkey_mask) { |
2200 | res = hotkey_mask_get(); | 2200 | res = hotkey_mask_get(); |
2201 | if (res) | 2201 | if (res) |
2202 | goto err_exit; | 2202 | goto err_exit; |
2203 | 2203 | ||
2204 | hotkey_orig_mask = hotkey_mask; | 2204 | hotkey_orig_mask = hotkey_mask; |
2205 | res = add_many_to_attr_set( | 2205 | res = add_many_to_attr_set( |
2206 | hotkey_dev_attributes, | 2206 | hotkey_dev_attributes, |
2207 | hotkey_mask_attributes, | 2207 | hotkey_mask_attributes, |
2208 | ARRAY_SIZE(hotkey_mask_attributes)); | 2208 | ARRAY_SIZE(hotkey_mask_attributes)); |
2209 | if (res) | 2209 | if (res) |
2210 | goto err_exit; | 2210 | goto err_exit; |
2211 | } | 2211 | } |
2212 | 2212 | ||
2213 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL | 2213 | #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL |
2214 | if (tp_features.hotkey_mask) { | 2214 | if (tp_features.hotkey_mask) { |
2215 | hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK | 2215 | hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK |
2216 | & ~hotkey_all_mask; | 2216 | & ~hotkey_all_mask; |
2217 | } else { | 2217 | } else { |
2218 | hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK; | 2218 | hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK; |
2219 | } | 2219 | } |
2220 | 2220 | ||
2221 | vdbg_printk(TPACPI_DBG_INIT, | 2221 | vdbg_printk(TPACPI_DBG_INIT, |
2222 | "hotkey source mask 0x%08x, polling freq %d\n", | 2222 | "hotkey source mask 0x%08x, polling freq %d\n", |
2223 | hotkey_source_mask, hotkey_poll_freq); | 2223 | hotkey_source_mask, hotkey_poll_freq); |
2224 | #endif | 2224 | #endif |
2225 | 2225 | ||
2226 | /* Not all thinkpads have a hardware radio switch */ | 2226 | /* Not all thinkpads have a hardware radio switch */ |
2227 | if (acpi_evalf(hkey_handle, &status, "WLSW", "qd")) { | 2227 | if (acpi_evalf(hkey_handle, &status, "WLSW", "qd")) { |
2228 | tp_features.hotkey_wlsw = 1; | 2228 | tp_features.hotkey_wlsw = 1; |
2229 | printk(TPACPI_INFO | 2229 | printk(TPACPI_INFO |
2230 | "radio switch found; radios are %s\n", | 2230 | "radio switch found; radios are %s\n", |
2231 | enabled(status, 0)); | 2231 | enabled(status, 0)); |
2232 | } | 2232 | } |
2233 | if (tp_features.hotkey_wlsw) | 2233 | if (tp_features.hotkey_wlsw) |
2234 | res = add_to_attr_set(hotkey_dev_attributes, | 2234 | res = add_to_attr_set(hotkey_dev_attributes, |
2235 | &dev_attr_hotkey_radio_sw.attr); | 2235 | &dev_attr_hotkey_radio_sw.attr); |
2236 | 2236 | ||
2237 | /* For X41t, X60t, X61t Tablets... */ | 2237 | /* For X41t, X60t, X61t Tablets... */ |
2238 | if (!res && acpi_evalf(hkey_handle, &status, "MHKG", "qd")) { | 2238 | if (!res && acpi_evalf(hkey_handle, &status, "MHKG", "qd")) { |
2239 | tp_features.hotkey_tablet = 1; | 2239 | tp_features.hotkey_tablet = 1; |
2240 | printk(TPACPI_INFO | 2240 | printk(TPACPI_INFO |
2241 | "possible tablet mode switch found; " | 2241 | "possible tablet mode switch found; " |
2242 | "ThinkPad in %s mode\n", | 2242 | "ThinkPad in %s mode\n", |
2243 | (status & TP_HOTKEY_TABLET_MASK)? | 2243 | (status & TP_HOTKEY_TABLET_MASK)? |
2244 | "tablet" : "laptop"); | 2244 | "tablet" : "laptop"); |
2245 | res = add_to_attr_set(hotkey_dev_attributes, | 2245 | res = add_to_attr_set(hotkey_dev_attributes, |
2246 | &dev_attr_hotkey_tablet_mode.attr); | 2246 | &dev_attr_hotkey_tablet_mode.attr); |
2247 | } | 2247 | } |
2248 | 2248 | ||
2249 | if (!res) | 2249 | if (!res) |
2250 | res = register_attr_set_with_sysfs( | 2250 | res = register_attr_set_with_sysfs( |
2251 | hotkey_dev_attributes, | 2251 | hotkey_dev_attributes, |
2252 | &tpacpi_pdev->dev.kobj); | 2252 | &tpacpi_pdev->dev.kobj); |
2253 | if (res) | 2253 | if (res) |
2254 | goto err_exit; | 2254 | goto err_exit; |
2255 | 2255 | ||
2256 | /* Set up key map */ | 2256 | /* Set up key map */ |
2257 | 2257 | ||
2258 | hotkey_keycode_map = kmalloc(TPACPI_HOTKEY_MAP_SIZE, | 2258 | hotkey_keycode_map = kmalloc(TPACPI_HOTKEY_MAP_SIZE, |
2259 | GFP_KERNEL); | 2259 | GFP_KERNEL); |
2260 | if (!hotkey_keycode_map) { | 2260 | if (!hotkey_keycode_map) { |
2261 | printk(TPACPI_ERR | 2261 | printk(TPACPI_ERR |
2262 | "failed to allocate memory for key map\n"); | 2262 | "failed to allocate memory for key map\n"); |
2263 | res = -ENOMEM; | 2263 | res = -ENOMEM; |
2264 | goto err_exit; | 2264 | goto err_exit; |
2265 | } | 2265 | } |
2266 | 2266 | ||
2267 | if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) { | 2267 | if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) { |
2268 | dbg_printk(TPACPI_DBG_INIT, | 2268 | dbg_printk(TPACPI_DBG_INIT, |
2269 | "using Lenovo default hot key map\n"); | 2269 | "using Lenovo default hot key map\n"); |
2270 | memcpy(hotkey_keycode_map, &lenovo_keycode_map, | 2270 | memcpy(hotkey_keycode_map, &lenovo_keycode_map, |
2271 | TPACPI_HOTKEY_MAP_SIZE); | 2271 | TPACPI_HOTKEY_MAP_SIZE); |
2272 | } else { | 2272 | } else { |
2273 | dbg_printk(TPACPI_DBG_INIT, | 2273 | dbg_printk(TPACPI_DBG_INIT, |
2274 | "using IBM default hot key map\n"); | 2274 | "using IBM default hot key map\n"); |
2275 | memcpy(hotkey_keycode_map, &ibm_keycode_map, | 2275 | memcpy(hotkey_keycode_map, &ibm_keycode_map, |
2276 | TPACPI_HOTKEY_MAP_SIZE); | 2276 | TPACPI_HOTKEY_MAP_SIZE); |
2277 | } | 2277 | } |
2278 | 2278 | ||
2279 | set_bit(EV_KEY, tpacpi_inputdev->evbit); | 2279 | set_bit(EV_KEY, tpacpi_inputdev->evbit); |
2280 | set_bit(EV_MSC, tpacpi_inputdev->evbit); | 2280 | set_bit(EV_MSC, tpacpi_inputdev->evbit); |
2281 | set_bit(MSC_SCAN, tpacpi_inputdev->mscbit); | 2281 | set_bit(MSC_SCAN, tpacpi_inputdev->mscbit); |
2282 | tpacpi_inputdev->keycodesize = TPACPI_HOTKEY_MAP_TYPESIZE; | 2282 | tpacpi_inputdev->keycodesize = TPACPI_HOTKEY_MAP_TYPESIZE; |
2283 | tpacpi_inputdev->keycodemax = TPACPI_HOTKEY_MAP_LEN; | 2283 | tpacpi_inputdev->keycodemax = TPACPI_HOTKEY_MAP_LEN; |
2284 | tpacpi_inputdev->keycode = hotkey_keycode_map; | 2284 | tpacpi_inputdev->keycode = hotkey_keycode_map; |
2285 | for (i = 0; i < TPACPI_HOTKEY_MAP_LEN; i++) { | 2285 | for (i = 0; i < TPACPI_HOTKEY_MAP_LEN; i++) { |
2286 | if (hotkey_keycode_map[i] != KEY_RESERVED) { | 2286 | if (hotkey_keycode_map[i] != KEY_RESERVED) { |
2287 | set_bit(hotkey_keycode_map[i], | 2287 | set_bit(hotkey_keycode_map[i], |
2288 | tpacpi_inputdev->keybit); | 2288 | tpacpi_inputdev->keybit); |
2289 | } else { | 2289 | } else { |
2290 | if (i < sizeof(hotkey_reserved_mask)*8) | 2290 | if (i < sizeof(hotkey_reserved_mask)*8) |
2291 | hotkey_reserved_mask |= 1 << i; | 2291 | hotkey_reserved_mask |= 1 << i; |
2292 | } | 2292 | } |
2293 | } | 2293 | } |
2294 | 2294 | ||
2295 | if (tp_features.hotkey_wlsw) { | 2295 | if (tp_features.hotkey_wlsw) { |
2296 | set_bit(EV_SW, tpacpi_inputdev->evbit); | 2296 | set_bit(EV_SW, tpacpi_inputdev->evbit); |
2297 | set_bit(SW_RFKILL_ALL, tpacpi_inputdev->swbit); | 2297 | set_bit(SW_RFKILL_ALL, tpacpi_inputdev->swbit); |
2298 | } | 2298 | } |
2299 | if (tp_features.hotkey_tablet) { | 2299 | if (tp_features.hotkey_tablet) { |
2300 | set_bit(EV_SW, tpacpi_inputdev->evbit); | 2300 | set_bit(EV_SW, tpacpi_inputdev->evbit); |
2301 | set_bit(SW_TABLET_MODE, tpacpi_inputdev->swbit); | 2301 | set_bit(SW_TABLET_MODE, tpacpi_inputdev->swbit); |
2302 | } | 2302 | } |
2303 | 2303 | ||
2304 | /* Do not issue duplicate brightness change events to | 2304 | /* Do not issue duplicate brightness change events to |
2305 | * userspace */ | 2305 | * userspace */ |
2306 | if (!tp_features.bright_acpimode) | 2306 | if (!tp_features.bright_acpimode) |
2307 | /* update bright_acpimode... */ | 2307 | /* update bright_acpimode... */ |
2308 | tpacpi_check_std_acpi_brightness_support(); | 2308 | tpacpi_check_std_acpi_brightness_support(); |
2309 | 2309 | ||
2310 | if (tp_features.bright_acpimode) { | 2310 | if (tp_features.bright_acpimode) { |
2311 | printk(TPACPI_INFO | 2311 | printk(TPACPI_INFO |
2312 | "This ThinkPad has standard ACPI backlight " | 2312 | "This ThinkPad has standard ACPI backlight " |
2313 | "brightness control, supported by the ACPI " | 2313 | "brightness control, supported by the ACPI " |
2314 | "video driver\n"); | 2314 | "video driver\n"); |
2315 | printk(TPACPI_NOTICE | 2315 | printk(TPACPI_NOTICE |
2316 | "Disabling thinkpad-acpi brightness events " | 2316 | "Disabling thinkpad-acpi brightness events " |
2317 | "by default...\n"); | 2317 | "by default...\n"); |
2318 | 2318 | ||
2319 | /* The hotkey_reserved_mask change below is not | 2319 | /* The hotkey_reserved_mask change below is not |
2320 | * necessary while the keys are at KEY_RESERVED in the | 2320 | * necessary while the keys are at KEY_RESERVED in the |
2321 | * default map, but better safe than sorry, leave it | 2321 | * default map, but better safe than sorry, leave it |
2322 | * here as a marker of what we have to do, especially | 2322 | * here as a marker of what we have to do, especially |
2323 | * when we finally become able to set this at runtime | 2323 | * when we finally become able to set this at runtime |
2324 | * on response to X.org requests */ | 2324 | * on response to X.org requests */ |
2325 | hotkey_reserved_mask |= | 2325 | hotkey_reserved_mask |= |
2326 | (1 << TP_ACPI_HOTKEYSCAN_FNHOME) | 2326 | (1 << TP_ACPI_HOTKEYSCAN_FNHOME) |
2327 | | (1 << TP_ACPI_HOTKEYSCAN_FNEND); | 2327 | | (1 << TP_ACPI_HOTKEYSCAN_FNEND); |
2328 | } | 2328 | } |
2329 | 2329 | ||
2330 | dbg_printk(TPACPI_DBG_INIT, "enabling hot key handling\n"); | 2330 | dbg_printk(TPACPI_DBG_INIT, "enabling hot key handling\n"); |
2331 | res = hotkey_status_set(1); | 2331 | res = hotkey_status_set(1); |
2332 | if (res) { | 2332 | if (res) { |
2333 | hotkey_exit(); | 2333 | hotkey_exit(); |
2334 | return res; | 2334 | return res; |
2335 | } | 2335 | } |
2336 | res = hotkey_mask_set(((hotkey_all_mask | hotkey_source_mask) | 2336 | res = hotkey_mask_set(((hotkey_all_mask | hotkey_source_mask) |
2337 | & ~hotkey_reserved_mask) | 2337 | & ~hotkey_reserved_mask) |
2338 | | hotkey_orig_mask); | 2338 | | hotkey_orig_mask); |
2339 | if (res < 0 && res != -ENXIO) { | 2339 | if (res < 0 && res != -ENXIO) { |
2340 | hotkey_exit(); | 2340 | hotkey_exit(); |
2341 | return res; | 2341 | return res; |
2342 | } | 2342 | } |
2343 | 2343 | ||
2344 | dbg_printk(TPACPI_DBG_INIT, | 2344 | dbg_printk(TPACPI_DBG_INIT, |
2345 | "legacy hot key reporting over procfs %s\n", | 2345 | "legacy hot key reporting over procfs %s\n", |
2346 | (hotkey_report_mode < 2) ? | 2346 | (hotkey_report_mode < 2) ? |
2347 | "enabled" : "disabled"); | 2347 | "enabled" : "disabled"); |
2348 | 2348 | ||
2349 | tpacpi_inputdev->open = &hotkey_inputdev_open; | 2349 | tpacpi_inputdev->open = &hotkey_inputdev_open; |
2350 | tpacpi_inputdev->close = &hotkey_inputdev_close; | 2350 | tpacpi_inputdev->close = &hotkey_inputdev_close; |
2351 | 2351 | ||
2352 | hotkey_poll_setup_safe(1); | 2352 | hotkey_poll_setup_safe(1); |
2353 | tpacpi_send_radiosw_update(); | 2353 | tpacpi_send_radiosw_update(); |
2354 | tpacpi_input_send_tabletsw(); | 2354 | tpacpi_input_send_tabletsw(); |
2355 | 2355 | ||
2356 | return 0; | 2356 | return 0; |
2357 | 2357 | ||
2358 | err_exit: | 2358 | err_exit: |
2359 | delete_attr_set(hotkey_dev_attributes, &tpacpi_pdev->dev.kobj); | 2359 | delete_attr_set(hotkey_dev_attributes, &tpacpi_pdev->dev.kobj); |
2360 | hotkey_dev_attributes = NULL; | 2360 | hotkey_dev_attributes = NULL; |
2361 | 2361 | ||
2362 | return (res < 0)? res : 1; | 2362 | return (res < 0)? res : 1; |
2363 | } | 2363 | } |
2364 | 2364 | ||
2365 | static void hotkey_notify(struct ibm_struct *ibm, u32 event) | 2365 | static void hotkey_notify(struct ibm_struct *ibm, u32 event) |
2366 | { | 2366 | { |
2367 | u32 hkey; | 2367 | u32 hkey; |
2368 | unsigned int scancode; | 2368 | unsigned int scancode; |
2369 | int send_acpi_ev; | 2369 | int send_acpi_ev; |
2370 | int ignore_acpi_ev; | 2370 | int ignore_acpi_ev; |
2371 | int unk_ev; | 2371 | int unk_ev; |
2372 | 2372 | ||
2373 | if (event != 0x80) { | 2373 | if (event != 0x80) { |
2374 | printk(TPACPI_ERR | 2374 | printk(TPACPI_ERR |
2375 | "unknown HKEY notification event %d\n", event); | 2375 | "unknown HKEY notification event %d\n", event); |
2376 | /* forward it to userspace, maybe it knows how to handle it */ | 2376 | /* forward it to userspace, maybe it knows how to handle it */ |
2377 | acpi_bus_generate_netlink_event( | 2377 | acpi_bus_generate_netlink_event( |
2378 | ibm->acpi->device->pnp.device_class, | 2378 | ibm->acpi->device->pnp.device_class, |
2379 | ibm->acpi->device->dev.bus_id, | 2379 | ibm->acpi->device->dev.bus_id, |
2380 | event, 0); | 2380 | event, 0); |
2381 | return; | 2381 | return; |
2382 | } | 2382 | } |
2383 | 2383 | ||
2384 | while (1) { | 2384 | while (1) { |
2385 | if (!acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) { | 2385 | if (!acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) { |
2386 | printk(TPACPI_ERR "failed to retrieve HKEY event\n"); | 2386 | printk(TPACPI_ERR "failed to retrieve HKEY event\n"); |
2387 | return; | 2387 | return; |
2388 | } | 2388 | } |
2389 | 2389 | ||
2390 | if (hkey == 0) { | 2390 | if (hkey == 0) { |
2391 | /* queue empty */ | 2391 | /* queue empty */ |
2392 | return; | 2392 | return; |
2393 | } | 2393 | } |
2394 | 2394 | ||
2395 | send_acpi_ev = 1; | 2395 | send_acpi_ev = 1; |
2396 | ignore_acpi_ev = 0; | 2396 | ignore_acpi_ev = 0; |
2397 | unk_ev = 0; | 2397 | unk_ev = 0; |
2398 | 2398 | ||
2399 | switch (hkey >> 12) { | 2399 | switch (hkey >> 12) { |
2400 | case 1: | 2400 | case 1: |
2401 | /* 0x1000-0x1FFF: key presses */ | 2401 | /* 0x1000-0x1FFF: key presses */ |
2402 | scancode = hkey & 0xfff; | 2402 | scancode = hkey & 0xfff; |
2403 | if (scancode > 0 && scancode < 0x21) { | 2403 | if (scancode > 0 && scancode < 0x21) { |
2404 | scancode--; | 2404 | scancode--; |
2405 | if (!(hotkey_source_mask & (1 << scancode))) { | 2405 | if (!(hotkey_source_mask & (1 << scancode))) { |
2406 | tpacpi_input_send_key(scancode); | 2406 | tpacpi_input_send_key(scancode); |
2407 | send_acpi_ev = 0; | 2407 | send_acpi_ev = 0; |
2408 | } else { | 2408 | } else { |
2409 | ignore_acpi_ev = 1; | 2409 | ignore_acpi_ev = 1; |
2410 | } | 2410 | } |
2411 | } else { | 2411 | } else { |
2412 | unk_ev = 1; | 2412 | unk_ev = 1; |
2413 | } | 2413 | } |
2414 | break; | 2414 | break; |
2415 | case 2: | 2415 | case 2: |
2416 | /* Wakeup reason */ | 2416 | /* Wakeup reason */ |
2417 | switch (hkey) { | 2417 | switch (hkey) { |
2418 | case 0x2304: /* suspend, undock */ | 2418 | case 0x2304: /* suspend, undock */ |
2419 | case 0x2404: /* hibernation, undock */ | 2419 | case 0x2404: /* hibernation, undock */ |
2420 | hotkey_wakeup_reason = TP_ACPI_WAKEUP_UNDOCK; | 2420 | hotkey_wakeup_reason = TP_ACPI_WAKEUP_UNDOCK; |
2421 | ignore_acpi_ev = 1; | 2421 | ignore_acpi_ev = 1; |
2422 | break; | 2422 | break; |
2423 | case 0x2305: /* suspend, bay eject */ | 2423 | case 0x2305: /* suspend, bay eject */ |
2424 | case 0x2405: /* hibernation, bay eject */ | 2424 | case 0x2405: /* hibernation, bay eject */ |
2425 | hotkey_wakeup_reason = TP_ACPI_WAKEUP_BAYEJ; | 2425 | hotkey_wakeup_reason = TP_ACPI_WAKEUP_BAYEJ; |
2426 | ignore_acpi_ev = 1; | 2426 | ignore_acpi_ev = 1; |
2427 | break; | 2427 | break; |
2428 | default: | 2428 | default: |
2429 | unk_ev = 1; | 2429 | unk_ev = 1; |
2430 | } | 2430 | } |
2431 | if (hotkey_wakeup_reason != TP_ACPI_WAKEUP_NONE) { | 2431 | if (hotkey_wakeup_reason != TP_ACPI_WAKEUP_NONE) { |
2432 | printk(TPACPI_INFO | 2432 | printk(TPACPI_INFO |
2433 | "woke up due to a hot-unplug " | 2433 | "woke up due to a hot-unplug " |
2434 | "request...\n"); | 2434 | "request...\n"); |
2435 | hotkey_wakeup_reason_notify_change(); | 2435 | hotkey_wakeup_reason_notify_change(); |
2436 | } | 2436 | } |
2437 | break; | 2437 | break; |
2438 | case 3: | 2438 | case 3: |
2439 | /* bay-related wakeups */ | 2439 | /* bay-related wakeups */ |
2440 | if (hkey == 0x3003) { | 2440 | if (hkey == 0x3003) { |
2441 | hotkey_autosleep_ack = 1; | 2441 | hotkey_autosleep_ack = 1; |
2442 | printk(TPACPI_INFO | 2442 | printk(TPACPI_INFO |
2443 | "bay ejected\n"); | 2443 | "bay ejected\n"); |
2444 | hotkey_wakeup_hotunplug_complete_notify_change(); | 2444 | hotkey_wakeup_hotunplug_complete_notify_change(); |
2445 | } else { | 2445 | } else { |
2446 | unk_ev = 1; | 2446 | unk_ev = 1; |
2447 | } | 2447 | } |
2448 | break; | 2448 | break; |
2449 | case 4: | 2449 | case 4: |
2450 | /* dock-related wakeups */ | 2450 | /* dock-related wakeups */ |
2451 | if (hkey == 0x4003) { | 2451 | if (hkey == 0x4003) { |
2452 | hotkey_autosleep_ack = 1; | 2452 | hotkey_autosleep_ack = 1; |
2453 | printk(TPACPI_INFO | 2453 | printk(TPACPI_INFO |
2454 | "undocked\n"); | 2454 | "undocked\n"); |
2455 | hotkey_wakeup_hotunplug_complete_notify_change(); | 2455 | hotkey_wakeup_hotunplug_complete_notify_change(); |
2456 | } else { | 2456 | } else { |
2457 | unk_ev = 1; | 2457 | unk_ev = 1; |
2458 | } | 2458 | } |
2459 | break; | 2459 | break; |
2460 | case 5: | 2460 | case 5: |
2461 | /* 0x5000-0x5FFF: human interface helpers */ | 2461 | /* 0x5000-0x5FFF: human interface helpers */ |
2462 | switch (hkey) { | 2462 | switch (hkey) { |
2463 | case 0x5010: /* Lenovo new BIOS: brightness changed */ | 2463 | case 0x5010: /* Lenovo new BIOS: brightness changed */ |
2464 | case 0x500b: /* X61t: tablet pen inserted into bay */ | 2464 | case 0x500b: /* X61t: tablet pen inserted into bay */ |
2465 | case 0x500c: /* X61t: tablet pen removed from bay */ | 2465 | case 0x500c: /* X61t: tablet pen removed from bay */ |
2466 | break; | 2466 | break; |
2467 | case 0x5009: /* X41t-X61t: swivel up (tablet mode) */ | 2467 | case 0x5009: /* X41t-X61t: swivel up (tablet mode) */ |
2468 | case 0x500a: /* X41t-X61t: swivel down (normal mode) */ | 2468 | case 0x500a: /* X41t-X61t: swivel down (normal mode) */ |
2469 | tpacpi_input_send_tabletsw(); | 2469 | tpacpi_input_send_tabletsw(); |
2470 | hotkey_tablet_mode_notify_change(); | 2470 | hotkey_tablet_mode_notify_change(); |
2471 | send_acpi_ev = 0; | 2471 | send_acpi_ev = 0; |
2472 | break; | 2472 | break; |
2473 | case 0x5001: | 2473 | case 0x5001: |
2474 | case 0x5002: | 2474 | case 0x5002: |
2475 | /* LID switch events. Do not propagate */ | 2475 | /* LID switch events. Do not propagate */ |
2476 | ignore_acpi_ev = 1; | 2476 | ignore_acpi_ev = 1; |
2477 | break; | 2477 | break; |
2478 | default: | 2478 | default: |
2479 | unk_ev = 1; | 2479 | unk_ev = 1; |
2480 | } | 2480 | } |
2481 | break; | 2481 | break; |
2482 | case 7: | 2482 | case 7: |
2483 | /* 0x7000-0x7FFF: misc */ | 2483 | /* 0x7000-0x7FFF: misc */ |
2484 | if (tp_features.hotkey_wlsw && hkey == 0x7000) { | 2484 | if (tp_features.hotkey_wlsw && hkey == 0x7000) { |
2485 | tpacpi_send_radiosw_update(); | 2485 | tpacpi_send_radiosw_update(); |
2486 | send_acpi_ev = 0; | 2486 | send_acpi_ev = 0; |
2487 | break; | 2487 | break; |
2488 | } | 2488 | } |
2489 | /* fallthrough to default */ | 2489 | /* fallthrough to default */ |
2490 | default: | 2490 | default: |
2491 | unk_ev = 1; | 2491 | unk_ev = 1; |
2492 | } | 2492 | } |
2493 | if (unk_ev) { | 2493 | if (unk_ev) { |
2494 | printk(TPACPI_NOTICE | 2494 | printk(TPACPI_NOTICE |
2495 | "unhandled HKEY event 0x%04x\n", hkey); | 2495 | "unhandled HKEY event 0x%04x\n", hkey); |
2496 | } | 2496 | } |
2497 | 2497 | ||
2498 | /* Legacy events */ | 2498 | /* Legacy events */ |
2499 | if (!ignore_acpi_ev && | 2499 | if (!ignore_acpi_ev && |
2500 | (send_acpi_ev || hotkey_report_mode < 2)) { | 2500 | (send_acpi_ev || hotkey_report_mode < 2)) { |
2501 | acpi_bus_generate_proc_event(ibm->acpi->device, | 2501 | acpi_bus_generate_proc_event(ibm->acpi->device, |
2502 | event, hkey); | 2502 | event, hkey); |
2503 | } | 2503 | } |
2504 | 2504 | ||
2505 | /* netlink events */ | 2505 | /* netlink events */ |
2506 | if (!ignore_acpi_ev && send_acpi_ev) { | 2506 | if (!ignore_acpi_ev && send_acpi_ev) { |
2507 | acpi_bus_generate_netlink_event( | 2507 | acpi_bus_generate_netlink_event( |
2508 | ibm->acpi->device->pnp.device_class, | 2508 | ibm->acpi->device->pnp.device_class, |
2509 | ibm->acpi->device->dev.bus_id, | 2509 | ibm->acpi->device->dev.bus_id, |
2510 | event, hkey); | 2510 | event, hkey); |
2511 | } | 2511 | } |
2512 | } | 2512 | } |
2513 | } | 2513 | } |
2514 | 2514 | ||
2515 | static void hotkey_suspend(pm_message_t state) | 2515 | static void hotkey_suspend(pm_message_t state) |
2516 | { | 2516 | { |
2517 | /* Do these on suspend, we get the events on early resume! */ | 2517 | /* Do these on suspend, we get the events on early resume! */ |
2518 | hotkey_wakeup_reason = TP_ACPI_WAKEUP_NONE; | 2518 | hotkey_wakeup_reason = TP_ACPI_WAKEUP_NONE; |
2519 | hotkey_autosleep_ack = 0; | 2519 | hotkey_autosleep_ack = 0; |
2520 | } | 2520 | } |
2521 | 2521 | ||
2522 | static void hotkey_resume(void) | 2522 | static void hotkey_resume(void) |
2523 | { | 2523 | { |
2524 | tpacpi_disable_brightness_delay(); | 2524 | tpacpi_disable_brightness_delay(); |
2525 | 2525 | ||
2526 | if (hotkey_mask_get()) | 2526 | if (hotkey_mask_get()) |
2527 | printk(TPACPI_ERR | 2527 | printk(TPACPI_ERR |
2528 | "error while trying to read hot key mask " | 2528 | "error while trying to read hot key mask " |
2529 | "from firmware\n"); | 2529 | "from firmware\n"); |
2530 | tpacpi_send_radiosw_update(); | 2530 | tpacpi_send_radiosw_update(); |
2531 | hotkey_tablet_mode_notify_change(); | 2531 | hotkey_tablet_mode_notify_change(); |
2532 | hotkey_wakeup_reason_notify_change(); | 2532 | hotkey_wakeup_reason_notify_change(); |
2533 | hotkey_wakeup_hotunplug_complete_notify_change(); | 2533 | hotkey_wakeup_hotunplug_complete_notify_change(); |
2534 | hotkey_poll_setup_safe(0); | 2534 | hotkey_poll_setup_safe(0); |
2535 | } | 2535 | } |
2536 | 2536 | ||
2537 | /* procfs -------------------------------------------------------------- */ | 2537 | /* procfs -------------------------------------------------------------- */ |
2538 | static int hotkey_read(char *p) | 2538 | static int hotkey_read(char *p) |
2539 | { | 2539 | { |
2540 | int res, status; | 2540 | int res, status; |
2541 | int len = 0; | 2541 | int len = 0; |
2542 | 2542 | ||
2543 | if (!tp_features.hotkey) { | 2543 | if (!tp_features.hotkey) { |
2544 | len += sprintf(p + len, "status:\t\tnot supported\n"); | 2544 | len += sprintf(p + len, "status:\t\tnot supported\n"); |
2545 | return len; | 2545 | return len; |
2546 | } | 2546 | } |
2547 | 2547 | ||
2548 | if (mutex_lock_interruptible(&hotkey_mutex)) | 2548 | if (mutex_lock_interruptible(&hotkey_mutex)) |
2549 | return -ERESTARTSYS; | 2549 | return -ERESTARTSYS; |
2550 | res = hotkey_status_get(&status); | 2550 | res = hotkey_status_get(&status); |
2551 | if (!res) | 2551 | if (!res) |
2552 | res = hotkey_mask_get(); | 2552 | res = hotkey_mask_get(); |
2553 | mutex_unlock(&hotkey_mutex); | 2553 | mutex_unlock(&hotkey_mutex); |
2554 | if (res) | 2554 | if (res) |
2555 | return res; | 2555 | return res; |
2556 | 2556 | ||
2557 | len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0)); | 2557 | len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0)); |
2558 | if (tp_features.hotkey_mask) { | 2558 | if (tp_features.hotkey_mask) { |
2559 | len += sprintf(p + len, "mask:\t\t0x%08x\n", hotkey_mask); | 2559 | len += sprintf(p + len, "mask:\t\t0x%08x\n", hotkey_mask); |
2560 | len += sprintf(p + len, | 2560 | len += sprintf(p + len, |
2561 | "commands:\tenable, disable, reset, <mask>\n"); | 2561 | "commands:\tenable, disable, reset, <mask>\n"); |
2562 | } else { | 2562 | } else { |
2563 | len += sprintf(p + len, "mask:\t\tnot supported\n"); | 2563 | len += sprintf(p + len, "mask:\t\tnot supported\n"); |
2564 | len += sprintf(p + len, "commands:\tenable, disable, reset\n"); | 2564 | len += sprintf(p + len, "commands:\tenable, disable, reset\n"); |
2565 | } | 2565 | } |
2566 | 2566 | ||
2567 | return len; | 2567 | return len; |
2568 | } | 2568 | } |
2569 | 2569 | ||
2570 | static int hotkey_write(char *buf) | 2570 | static int hotkey_write(char *buf) |
2571 | { | 2571 | { |
2572 | int res, status; | 2572 | int res, status; |
2573 | u32 mask; | 2573 | u32 mask; |
2574 | char *cmd; | 2574 | char *cmd; |
2575 | 2575 | ||
2576 | if (!tp_features.hotkey) | 2576 | if (!tp_features.hotkey) |
2577 | return -ENODEV; | 2577 | return -ENODEV; |
2578 | 2578 | ||
2579 | if (mutex_lock_interruptible(&hotkey_mutex)) | 2579 | if (mutex_lock_interruptible(&hotkey_mutex)) |
2580 | return -ERESTARTSYS; | 2580 | return -ERESTARTSYS; |
2581 | 2581 | ||
2582 | status = -1; | 2582 | status = -1; |
2583 | mask = hotkey_mask; | 2583 | mask = hotkey_mask; |
2584 | 2584 | ||
2585 | res = 0; | 2585 | res = 0; |
2586 | while ((cmd = next_cmd(&buf))) { | 2586 | while ((cmd = next_cmd(&buf))) { |
2587 | if (strlencmp(cmd, "enable") == 0) { | 2587 | if (strlencmp(cmd, "enable") == 0) { |
2588 | status = 1; | 2588 | status = 1; |
2589 | } else if (strlencmp(cmd, "disable") == 0) { | 2589 | } else if (strlencmp(cmd, "disable") == 0) { |
2590 | status = 0; | 2590 | status = 0; |
2591 | } else if (strlencmp(cmd, "reset") == 0) { | 2591 | } else if (strlencmp(cmd, "reset") == 0) { |
2592 | status = hotkey_orig_status; | 2592 | status = hotkey_orig_status; |
2593 | mask = hotkey_orig_mask; | 2593 | mask = hotkey_orig_mask; |
2594 | } else if (sscanf(cmd, "0x%x", &mask) == 1) { | 2594 | } else if (sscanf(cmd, "0x%x", &mask) == 1) { |
2595 | /* mask set */ | 2595 | /* mask set */ |
2596 | } else if (sscanf(cmd, "%x", &mask) == 1) { | 2596 | } else if (sscanf(cmd, "%x", &mask) == 1) { |
2597 | /* mask set */ | 2597 | /* mask set */ |
2598 | } else { | 2598 | } else { |
2599 | res = -EINVAL; | 2599 | res = -EINVAL; |
2600 | goto errexit; | 2600 | goto errexit; |
2601 | } | 2601 | } |
2602 | } | 2602 | } |
2603 | if (status != -1) | 2603 | if (status != -1) |
2604 | res = hotkey_status_set(status); | 2604 | res = hotkey_status_set(status); |
2605 | 2605 | ||
2606 | if (!res && mask != hotkey_mask) | 2606 | if (!res && mask != hotkey_mask) |
2607 | res = hotkey_mask_set(mask); | 2607 | res = hotkey_mask_set(mask); |
2608 | 2608 | ||
2609 | errexit: | 2609 | errexit: |
2610 | mutex_unlock(&hotkey_mutex); | 2610 | mutex_unlock(&hotkey_mutex); |
2611 | return res; | 2611 | return res; |
2612 | } | 2612 | } |
2613 | 2613 | ||
2614 | static const struct acpi_device_id ibm_htk_device_ids[] = { | 2614 | static const struct acpi_device_id ibm_htk_device_ids[] = { |
2615 | {TPACPI_ACPI_HKEY_HID, 0}, | 2615 | {TPACPI_ACPI_HKEY_HID, 0}, |
2616 | {"", 0}, | 2616 | {"", 0}, |
2617 | }; | 2617 | }; |
2618 | 2618 | ||
2619 | static struct tp_acpi_drv_struct ibm_hotkey_acpidriver = { | 2619 | static struct tp_acpi_drv_struct ibm_hotkey_acpidriver = { |
2620 | .hid = ibm_htk_device_ids, | 2620 | .hid = ibm_htk_device_ids, |
2621 | .notify = hotkey_notify, | 2621 | .notify = hotkey_notify, |
2622 | .handle = &hkey_handle, | 2622 | .handle = &hkey_handle, |
2623 | .type = ACPI_DEVICE_NOTIFY, | 2623 | .type = ACPI_DEVICE_NOTIFY, |
2624 | }; | 2624 | }; |
2625 | 2625 | ||
2626 | static struct ibm_struct hotkey_driver_data = { | 2626 | static struct ibm_struct hotkey_driver_data = { |
2627 | .name = "hotkey", | 2627 | .name = "hotkey", |
2628 | .read = hotkey_read, | 2628 | .read = hotkey_read, |
2629 | .write = hotkey_write, | 2629 | .write = hotkey_write, |
2630 | .exit = hotkey_exit, | 2630 | .exit = hotkey_exit, |
2631 | .resume = hotkey_resume, | 2631 | .resume = hotkey_resume, |
2632 | .suspend = hotkey_suspend, | 2632 | .suspend = hotkey_suspend, |
2633 | .acpi = &ibm_hotkey_acpidriver, | 2633 | .acpi = &ibm_hotkey_acpidriver, |
2634 | }; | 2634 | }; |
2635 | 2635 | ||
2636 | /************************************************************************* | 2636 | /************************************************************************* |
2637 | * Bluetooth subdriver | 2637 | * Bluetooth subdriver |
2638 | */ | 2638 | */ |
2639 | 2639 | ||
2640 | enum { | 2640 | enum { |
2641 | /* ACPI GBDC/SBDC bits */ | 2641 | /* ACPI GBDC/SBDC bits */ |
2642 | TP_ACPI_BLUETOOTH_HWPRESENT = 0x01, /* Bluetooth hw available */ | 2642 | TP_ACPI_BLUETOOTH_HWPRESENT = 0x01, /* Bluetooth hw available */ |
2643 | TP_ACPI_BLUETOOTH_RADIOSSW = 0x02, /* Bluetooth radio enabled */ | 2643 | TP_ACPI_BLUETOOTH_RADIOSSW = 0x02, /* Bluetooth radio enabled */ |
2644 | TP_ACPI_BLUETOOTH_UNK = 0x04, /* unknown function */ | 2644 | TP_ACPI_BLUETOOTH_UNK = 0x04, /* unknown function */ |
2645 | }; | 2645 | }; |
2646 | 2646 | ||
2647 | static struct rfkill *tpacpi_bluetooth_rfkill; | 2647 | static struct rfkill *tpacpi_bluetooth_rfkill; |
2648 | 2648 | ||
2649 | static int bluetooth_get_radiosw(void) | 2649 | static int bluetooth_get_radiosw(void) |
2650 | { | 2650 | { |
2651 | int status; | 2651 | int status; |
2652 | 2652 | ||
2653 | if (!tp_features.bluetooth) | 2653 | if (!tp_features.bluetooth) |
2654 | return -ENODEV; | 2654 | return -ENODEV; |
2655 | 2655 | ||
2656 | /* WLSW overrides bluetooth in firmware/hardware, reflect that */ | 2656 | /* WLSW overrides bluetooth in firmware/hardware, reflect that */ |
2657 | if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status) | 2657 | if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status) |
2658 | return RFKILL_STATE_HARD_BLOCKED; | 2658 | return RFKILL_STATE_HARD_BLOCKED; |
2659 | 2659 | ||
2660 | if (!acpi_evalf(hkey_handle, &status, "GBDC", "d")) | 2660 | if (!acpi_evalf(hkey_handle, &status, "GBDC", "d")) |
2661 | return -EIO; | 2661 | return -EIO; |
2662 | 2662 | ||
2663 | return ((status & TP_ACPI_BLUETOOTH_RADIOSSW) != 0) ? | 2663 | return ((status & TP_ACPI_BLUETOOTH_RADIOSSW) != 0) ? |
2664 | RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; | 2664 | RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; |
2665 | } | 2665 | } |
2666 | 2666 | ||
2667 | static void bluetooth_update_rfk(void) | 2667 | static void bluetooth_update_rfk(void) |
2668 | { | 2668 | { |
2669 | int status; | 2669 | int status; |
2670 | 2670 | ||
2671 | if (!tpacpi_bluetooth_rfkill) | 2671 | if (!tpacpi_bluetooth_rfkill) |
2672 | return; | 2672 | return; |
2673 | 2673 | ||
2674 | status = bluetooth_get_radiosw(); | 2674 | status = bluetooth_get_radiosw(); |
2675 | if (status < 0) | 2675 | if (status < 0) |
2676 | return; | 2676 | return; |
2677 | rfkill_force_state(tpacpi_bluetooth_rfkill, status); | 2677 | rfkill_force_state(tpacpi_bluetooth_rfkill, status); |
2678 | } | 2678 | } |
2679 | 2679 | ||
2680 | static int bluetooth_set_radiosw(int radio_on, int update_rfk) | 2680 | static int bluetooth_set_radiosw(int radio_on, int update_rfk) |
2681 | { | 2681 | { |
2682 | int status; | 2682 | int status; |
2683 | 2683 | ||
2684 | if (!tp_features.bluetooth) | 2684 | if (!tp_features.bluetooth) |
2685 | return -ENODEV; | 2685 | return -ENODEV; |
2686 | 2686 | ||
2687 | /* WLSW overrides bluetooth in firmware/hardware, but there is no | 2687 | /* WLSW overrides bluetooth in firmware/hardware, but there is no |
2688 | * reason to risk weird behaviour. */ | 2688 | * reason to risk weird behaviour. */ |
2689 | if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status | 2689 | if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status |
2690 | && radio_on) | 2690 | && radio_on) |
2691 | return -EPERM; | 2691 | return -EPERM; |
2692 | 2692 | ||
2693 | if (!acpi_evalf(hkey_handle, &status, "GBDC", "d")) | 2693 | if (!acpi_evalf(hkey_handle, &status, "GBDC", "d")) |
2694 | return -EIO; | 2694 | return -EIO; |
2695 | if (radio_on) | 2695 | if (radio_on) |
2696 | status |= TP_ACPI_BLUETOOTH_RADIOSSW; | 2696 | status |= TP_ACPI_BLUETOOTH_RADIOSSW; |
2697 | else | 2697 | else |
2698 | status &= ~TP_ACPI_BLUETOOTH_RADIOSSW; | 2698 | status &= ~TP_ACPI_BLUETOOTH_RADIOSSW; |
2699 | if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status)) | 2699 | if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status)) |
2700 | return -EIO; | 2700 | return -EIO; |
2701 | 2701 | ||
2702 | if (update_rfk) | 2702 | if (update_rfk) |
2703 | bluetooth_update_rfk(); | 2703 | bluetooth_update_rfk(); |
2704 | 2704 | ||
2705 | return 0; | 2705 | return 0; |
2706 | } | 2706 | } |
2707 | 2707 | ||
2708 | /* sysfs bluetooth enable ---------------------------------------------- */ | 2708 | /* sysfs bluetooth enable ---------------------------------------------- */ |
2709 | static ssize_t bluetooth_enable_show(struct device *dev, | 2709 | static ssize_t bluetooth_enable_show(struct device *dev, |
2710 | struct device_attribute *attr, | 2710 | struct device_attribute *attr, |
2711 | char *buf) | 2711 | char *buf) |
2712 | { | 2712 | { |
2713 | int status; | 2713 | int status; |
2714 | 2714 | ||
2715 | status = bluetooth_get_radiosw(); | 2715 | status = bluetooth_get_radiosw(); |
2716 | if (status < 0) | 2716 | if (status < 0) |
2717 | return status; | 2717 | return status; |
2718 | 2718 | ||
2719 | return snprintf(buf, PAGE_SIZE, "%d\n", | 2719 | return snprintf(buf, PAGE_SIZE, "%d\n", |
2720 | (status == RFKILL_STATE_UNBLOCKED) ? 1 : 0); | 2720 | (status == RFKILL_STATE_UNBLOCKED) ? 1 : 0); |
2721 | } | 2721 | } |
2722 | 2722 | ||
2723 | static ssize_t bluetooth_enable_store(struct device *dev, | 2723 | static ssize_t bluetooth_enable_store(struct device *dev, |
2724 | struct device_attribute *attr, | 2724 | struct device_attribute *attr, |
2725 | const char *buf, size_t count) | 2725 | const char *buf, size_t count) |
2726 | { | 2726 | { |
2727 | unsigned long t; | 2727 | unsigned long t; |
2728 | int res; | 2728 | int res; |
2729 | 2729 | ||
2730 | if (parse_strtoul(buf, 1, &t)) | 2730 | if (parse_strtoul(buf, 1, &t)) |
2731 | return -EINVAL; | 2731 | return -EINVAL; |
2732 | 2732 | ||
2733 | res = bluetooth_set_radiosw(t, 1); | 2733 | res = bluetooth_set_radiosw(t, 1); |
2734 | 2734 | ||
2735 | return (res) ? res : count; | 2735 | return (res) ? res : count; |
2736 | } | 2736 | } |
2737 | 2737 | ||
2738 | static struct device_attribute dev_attr_bluetooth_enable = | 2738 | static struct device_attribute dev_attr_bluetooth_enable = |
2739 | __ATTR(bluetooth_enable, S_IWUSR | S_IRUGO, | 2739 | __ATTR(bluetooth_enable, S_IWUSR | S_IRUGO, |
2740 | bluetooth_enable_show, bluetooth_enable_store); | 2740 | bluetooth_enable_show, bluetooth_enable_store); |
2741 | 2741 | ||
2742 | /* --------------------------------------------------------------------- */ | 2742 | /* --------------------------------------------------------------------- */ |
2743 | 2743 | ||
2744 | static struct attribute *bluetooth_attributes[] = { | 2744 | static struct attribute *bluetooth_attributes[] = { |
2745 | &dev_attr_bluetooth_enable.attr, | 2745 | &dev_attr_bluetooth_enable.attr, |
2746 | NULL | 2746 | NULL |
2747 | }; | 2747 | }; |
2748 | 2748 | ||
2749 | static const struct attribute_group bluetooth_attr_group = { | 2749 | static const struct attribute_group bluetooth_attr_group = { |
2750 | .attrs = bluetooth_attributes, | 2750 | .attrs = bluetooth_attributes, |
2751 | }; | 2751 | }; |
2752 | 2752 | ||
2753 | static int tpacpi_bluetooth_rfk_get(void *data, enum rfkill_state *state) | 2753 | static int tpacpi_bluetooth_rfk_get(void *data, enum rfkill_state *state) |
2754 | { | 2754 | { |
2755 | int bts = bluetooth_get_radiosw(); | 2755 | int bts = bluetooth_get_radiosw(); |
2756 | 2756 | ||
2757 | if (bts < 0) | 2757 | if (bts < 0) |
2758 | return bts; | 2758 | return bts; |
2759 | 2759 | ||
2760 | *state = bts; | 2760 | *state = bts; |
2761 | return 0; | 2761 | return 0; |
2762 | } | 2762 | } |
2763 | 2763 | ||
2764 | static int tpacpi_bluetooth_rfk_set(void *data, enum rfkill_state state) | 2764 | static int tpacpi_bluetooth_rfk_set(void *data, enum rfkill_state state) |
2765 | { | 2765 | { |
2766 | return bluetooth_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0); | 2766 | return bluetooth_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0); |
2767 | } | 2767 | } |
2768 | 2768 | ||
2769 | static void bluetooth_exit(void) | 2769 | static void bluetooth_exit(void) |
2770 | { | 2770 | { |
2771 | if (tpacpi_bluetooth_rfkill) | 2771 | if (tpacpi_bluetooth_rfkill) |
2772 | rfkill_unregister(tpacpi_bluetooth_rfkill); | 2772 | rfkill_unregister(tpacpi_bluetooth_rfkill); |
2773 | 2773 | ||
2774 | sysfs_remove_group(&tpacpi_pdev->dev.kobj, | 2774 | sysfs_remove_group(&tpacpi_pdev->dev.kobj, |
2775 | &bluetooth_attr_group); | 2775 | &bluetooth_attr_group); |
2776 | } | 2776 | } |
2777 | 2777 | ||
2778 | static int __init bluetooth_init(struct ibm_init_struct *iibm) | 2778 | static int __init bluetooth_init(struct ibm_init_struct *iibm) |
2779 | { | 2779 | { |
2780 | int res; | 2780 | int res; |
2781 | int status = 0; | 2781 | int status = 0; |
2782 | 2782 | ||
2783 | vdbg_printk(TPACPI_DBG_INIT, "initializing bluetooth subdriver\n"); | 2783 | vdbg_printk(TPACPI_DBG_INIT, "initializing bluetooth subdriver\n"); |
2784 | 2784 | ||
2785 | TPACPI_ACPIHANDLE_INIT(hkey); | 2785 | TPACPI_ACPIHANDLE_INIT(hkey); |
2786 | 2786 | ||
2787 | /* bluetooth not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, | 2787 | /* bluetooth not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, |
2788 | G4x, R30, R31, R40e, R50e, T20-22, X20-21 */ | 2788 | G4x, R30, R31, R40e, R50e, T20-22, X20-21 */ |
2789 | tp_features.bluetooth = hkey_handle && | 2789 | tp_features.bluetooth = hkey_handle && |
2790 | acpi_evalf(hkey_handle, &status, "GBDC", "qd"); | 2790 | acpi_evalf(hkey_handle, &status, "GBDC", "qd"); |
2791 | 2791 | ||
2792 | vdbg_printk(TPACPI_DBG_INIT, "bluetooth is %s, status 0x%02x\n", | 2792 | vdbg_printk(TPACPI_DBG_INIT, "bluetooth is %s, status 0x%02x\n", |
2793 | str_supported(tp_features.bluetooth), | 2793 | str_supported(tp_features.bluetooth), |
2794 | status); | 2794 | status); |
2795 | 2795 | ||
2796 | if (tp_features.bluetooth && | 2796 | if (tp_features.bluetooth && |
2797 | !(status & TP_ACPI_BLUETOOTH_HWPRESENT)) { | 2797 | !(status & TP_ACPI_BLUETOOTH_HWPRESENT)) { |
2798 | /* no bluetooth hardware present in system */ | 2798 | /* no bluetooth hardware present in system */ |
2799 | tp_features.bluetooth = 0; | 2799 | tp_features.bluetooth = 0; |
2800 | dbg_printk(TPACPI_DBG_INIT, | 2800 | dbg_printk(TPACPI_DBG_INIT, |
2801 | "bluetooth hardware not installed\n"); | 2801 | "bluetooth hardware not installed\n"); |
2802 | } | 2802 | } |
2803 | 2803 | ||
2804 | if (!tp_features.bluetooth) | 2804 | if (!tp_features.bluetooth) |
2805 | return 1; | 2805 | return 1; |
2806 | 2806 | ||
2807 | res = sysfs_create_group(&tpacpi_pdev->dev.kobj, | 2807 | res = sysfs_create_group(&tpacpi_pdev->dev.kobj, |
2808 | &bluetooth_attr_group); | 2808 | &bluetooth_attr_group); |
2809 | if (res) | 2809 | if (res) |
2810 | return res; | 2810 | return res; |
2811 | 2811 | ||
2812 | res = tpacpi_new_rfkill(TPACPI_RFK_BLUETOOTH_SW_ID, | 2812 | res = tpacpi_new_rfkill(TPACPI_RFK_BLUETOOTH_SW_ID, |
2813 | &tpacpi_bluetooth_rfkill, | 2813 | &tpacpi_bluetooth_rfkill, |
2814 | RFKILL_TYPE_BLUETOOTH, | 2814 | RFKILL_TYPE_BLUETOOTH, |
2815 | "tpacpi_bluetooth_sw", | 2815 | "tpacpi_bluetooth_sw", |
2816 | tpacpi_bluetooth_rfk_set, | 2816 | tpacpi_bluetooth_rfk_set, |
2817 | tpacpi_bluetooth_rfk_get); | 2817 | tpacpi_bluetooth_rfk_get); |
2818 | if (res) { | 2818 | if (res) { |
2819 | bluetooth_exit(); | 2819 | bluetooth_exit(); |
2820 | return res; | 2820 | return res; |
2821 | } | 2821 | } |
2822 | 2822 | ||
2823 | return 0; | 2823 | return 0; |
2824 | } | 2824 | } |
2825 | 2825 | ||
2826 | /* procfs -------------------------------------------------------------- */ | 2826 | /* procfs -------------------------------------------------------------- */ |
2827 | static int bluetooth_read(char *p) | 2827 | static int bluetooth_read(char *p) |
2828 | { | 2828 | { |
2829 | int len = 0; | 2829 | int len = 0; |
2830 | int status = bluetooth_get_radiosw(); | 2830 | int status = bluetooth_get_radiosw(); |
2831 | 2831 | ||
2832 | if (!tp_features.bluetooth) | 2832 | if (!tp_features.bluetooth) |
2833 | len += sprintf(p + len, "status:\t\tnot supported\n"); | 2833 | len += sprintf(p + len, "status:\t\tnot supported\n"); |
2834 | else { | 2834 | else { |
2835 | len += sprintf(p + len, "status:\t\t%s\n", | 2835 | len += sprintf(p + len, "status:\t\t%s\n", |
2836 | (status == RFKILL_STATE_UNBLOCKED) ? | 2836 | (status == RFKILL_STATE_UNBLOCKED) ? |
2837 | "enabled" : "disabled"); | 2837 | "enabled" : "disabled"); |
2838 | len += sprintf(p + len, "commands:\tenable, disable\n"); | 2838 | len += sprintf(p + len, "commands:\tenable, disable\n"); |
2839 | } | 2839 | } |
2840 | 2840 | ||
2841 | return len; | 2841 | return len; |
2842 | } | 2842 | } |
2843 | 2843 | ||
2844 | static int bluetooth_write(char *buf) | 2844 | static int bluetooth_write(char *buf) |
2845 | { | 2845 | { |
2846 | char *cmd; | 2846 | char *cmd; |
2847 | 2847 | ||
2848 | if (!tp_features.bluetooth) | 2848 | if (!tp_features.bluetooth) |
2849 | return -ENODEV; | 2849 | return -ENODEV; |
2850 | 2850 | ||
2851 | while ((cmd = next_cmd(&buf))) { | 2851 | while ((cmd = next_cmd(&buf))) { |
2852 | if (strlencmp(cmd, "enable") == 0) { | 2852 | if (strlencmp(cmd, "enable") == 0) { |
2853 | bluetooth_set_radiosw(1, 1); | 2853 | bluetooth_set_radiosw(1, 1); |
2854 | } else if (strlencmp(cmd, "disable") == 0) { | 2854 | } else if (strlencmp(cmd, "disable") == 0) { |
2855 | bluetooth_set_radiosw(0, 1); | 2855 | bluetooth_set_radiosw(0, 1); |
2856 | } else | 2856 | } else |
2857 | return -EINVAL; | 2857 | return -EINVAL; |
2858 | } | 2858 | } |
2859 | 2859 | ||
2860 | return 0; | 2860 | return 0; |
2861 | } | 2861 | } |
2862 | 2862 | ||
2863 | static struct ibm_struct bluetooth_driver_data = { | 2863 | static struct ibm_struct bluetooth_driver_data = { |
2864 | .name = "bluetooth", | 2864 | .name = "bluetooth", |
2865 | .read = bluetooth_read, | 2865 | .read = bluetooth_read, |
2866 | .write = bluetooth_write, | 2866 | .write = bluetooth_write, |
2867 | .exit = bluetooth_exit, | 2867 | .exit = bluetooth_exit, |
2868 | }; | 2868 | }; |
2869 | 2869 | ||
2870 | /************************************************************************* | 2870 | /************************************************************************* |
2871 | * Wan subdriver | 2871 | * Wan subdriver |
2872 | */ | 2872 | */ |
2873 | 2873 | ||
2874 | enum { | 2874 | enum { |
2875 | /* ACPI GWAN/SWAN bits */ | 2875 | /* ACPI GWAN/SWAN bits */ |
2876 | TP_ACPI_WANCARD_HWPRESENT = 0x01, /* Wan hw available */ | 2876 | TP_ACPI_WANCARD_HWPRESENT = 0x01, /* Wan hw available */ |
2877 | TP_ACPI_WANCARD_RADIOSSW = 0x02, /* Wan radio enabled */ | 2877 | TP_ACPI_WANCARD_RADIOSSW = 0x02, /* Wan radio enabled */ |
2878 | TP_ACPI_WANCARD_UNK = 0x04, /* unknown function */ | 2878 | TP_ACPI_WANCARD_UNK = 0x04, /* unknown function */ |
2879 | }; | 2879 | }; |
2880 | 2880 | ||
2881 | static struct rfkill *tpacpi_wan_rfkill; | 2881 | static struct rfkill *tpacpi_wan_rfkill; |
2882 | 2882 | ||
2883 | static int wan_get_radiosw(void) | 2883 | static int wan_get_radiosw(void) |
2884 | { | 2884 | { |
2885 | int status; | 2885 | int status; |
2886 | 2886 | ||
2887 | if (!tp_features.wan) | 2887 | if (!tp_features.wan) |
2888 | return -ENODEV; | 2888 | return -ENODEV; |
2889 | 2889 | ||
2890 | /* WLSW overrides WWAN in firmware/hardware, reflect that */ | 2890 | /* WLSW overrides WWAN in firmware/hardware, reflect that */ |
2891 | if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status) | 2891 | if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status) |
2892 | return RFKILL_STATE_HARD_BLOCKED; | 2892 | return RFKILL_STATE_HARD_BLOCKED; |
2893 | 2893 | ||
2894 | if (!acpi_evalf(hkey_handle, &status, "GWAN", "d")) | 2894 | if (!acpi_evalf(hkey_handle, &status, "GWAN", "d")) |
2895 | return -EIO; | 2895 | return -EIO; |
2896 | 2896 | ||
2897 | return ((status & TP_ACPI_WANCARD_RADIOSSW) != 0) ? | 2897 | return ((status & TP_ACPI_WANCARD_RADIOSSW) != 0) ? |
2898 | RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; | 2898 | RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; |
2899 | } | 2899 | } |
2900 | 2900 | ||
2901 | static void wan_update_rfk(void) | 2901 | static void wan_update_rfk(void) |
2902 | { | 2902 | { |
2903 | int status; | 2903 | int status; |
2904 | 2904 | ||
2905 | if (!tpacpi_wan_rfkill) | 2905 | if (!tpacpi_wan_rfkill) |
2906 | return; | 2906 | return; |
2907 | 2907 | ||
2908 | status = wan_get_radiosw(); | 2908 | status = wan_get_radiosw(); |
2909 | if (status < 0) | 2909 | if (status < 0) |
2910 | return; | 2910 | return; |
2911 | rfkill_force_state(tpacpi_wan_rfkill, status); | 2911 | rfkill_force_state(tpacpi_wan_rfkill, status); |
2912 | } | 2912 | } |
2913 | 2913 | ||
2914 | static int wan_set_radiosw(int radio_on, int update_rfk) | 2914 | static int wan_set_radiosw(int radio_on, int update_rfk) |
2915 | { | 2915 | { |
2916 | int status; | 2916 | int status; |
2917 | 2917 | ||
2918 | if (!tp_features.wan) | 2918 | if (!tp_features.wan) |
2919 | return -ENODEV; | 2919 | return -ENODEV; |
2920 | 2920 | ||
2921 | /* WLSW overrides bluetooth in firmware/hardware, but there is no | 2921 | /* WLSW overrides bluetooth in firmware/hardware, but there is no |
2922 | * reason to risk weird behaviour. */ | 2922 | * reason to risk weird behaviour. */ |
2923 | if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status | 2923 | if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status |
2924 | && radio_on) | 2924 | && radio_on) |
2925 | return -EPERM; | 2925 | return -EPERM; |
2926 | 2926 | ||
2927 | if (!acpi_evalf(hkey_handle, &status, "GWAN", "d")) | 2927 | if (!acpi_evalf(hkey_handle, &status, "GWAN", "d")) |
2928 | return -EIO; | 2928 | return -EIO; |
2929 | if (radio_on) | 2929 | if (radio_on) |
2930 | status |= TP_ACPI_WANCARD_RADIOSSW; | 2930 | status |= TP_ACPI_WANCARD_RADIOSSW; |
2931 | else | 2931 | else |
2932 | status &= ~TP_ACPI_WANCARD_RADIOSSW; | 2932 | status &= ~TP_ACPI_WANCARD_RADIOSSW; |
2933 | if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status)) | 2933 | if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status)) |
2934 | return -EIO; | 2934 | return -EIO; |
2935 | 2935 | ||
2936 | if (update_rfk) | 2936 | if (update_rfk) |
2937 | wan_update_rfk(); | 2937 | wan_update_rfk(); |
2938 | 2938 | ||
2939 | return 0; | 2939 | return 0; |
2940 | } | 2940 | } |
2941 | 2941 | ||
2942 | /* sysfs wan enable ---------------------------------------------------- */ | 2942 | /* sysfs wan enable ---------------------------------------------------- */ |
2943 | static ssize_t wan_enable_show(struct device *dev, | 2943 | static ssize_t wan_enable_show(struct device *dev, |
2944 | struct device_attribute *attr, | 2944 | struct device_attribute *attr, |
2945 | char *buf) | 2945 | char *buf) |
2946 | { | 2946 | { |
2947 | int status; | 2947 | int status; |
2948 | 2948 | ||
2949 | status = wan_get_radiosw(); | 2949 | status = wan_get_radiosw(); |
2950 | if (status < 0) | 2950 | if (status < 0) |
2951 | return status; | 2951 | return status; |
2952 | 2952 | ||
2953 | return snprintf(buf, PAGE_SIZE, "%d\n", | 2953 | return snprintf(buf, PAGE_SIZE, "%d\n", |
2954 | (status == RFKILL_STATE_UNBLOCKED) ? 1 : 0); | 2954 | (status == RFKILL_STATE_UNBLOCKED) ? 1 : 0); |
2955 | } | 2955 | } |
2956 | 2956 | ||
2957 | static ssize_t wan_enable_store(struct device *dev, | 2957 | static ssize_t wan_enable_store(struct device *dev, |
2958 | struct device_attribute *attr, | 2958 | struct device_attribute *attr, |
2959 | const char *buf, size_t count) | 2959 | const char *buf, size_t count) |
2960 | { | 2960 | { |
2961 | unsigned long t; | 2961 | unsigned long t; |
2962 | int res; | 2962 | int res; |
2963 | 2963 | ||
2964 | if (parse_strtoul(buf, 1, &t)) | 2964 | if (parse_strtoul(buf, 1, &t)) |
2965 | return -EINVAL; | 2965 | return -EINVAL; |
2966 | 2966 | ||
2967 | res = wan_set_radiosw(t, 1); | 2967 | res = wan_set_radiosw(t, 1); |
2968 | 2968 | ||
2969 | return (res) ? res : count; | 2969 | return (res) ? res : count; |
2970 | } | 2970 | } |
2971 | 2971 | ||
2972 | static struct device_attribute dev_attr_wan_enable = | 2972 | static struct device_attribute dev_attr_wan_enable = |
2973 | __ATTR(wwan_enable, S_IWUSR | S_IRUGO, | 2973 | __ATTR(wwan_enable, S_IWUSR | S_IRUGO, |
2974 | wan_enable_show, wan_enable_store); | 2974 | wan_enable_show, wan_enable_store); |
2975 | 2975 | ||
2976 | /* --------------------------------------------------------------------- */ | 2976 | /* --------------------------------------------------------------------- */ |
2977 | 2977 | ||
2978 | static struct attribute *wan_attributes[] = { | 2978 | static struct attribute *wan_attributes[] = { |
2979 | &dev_attr_wan_enable.attr, | 2979 | &dev_attr_wan_enable.attr, |
2980 | NULL | 2980 | NULL |
2981 | }; | 2981 | }; |
2982 | 2982 | ||
2983 | static const struct attribute_group wan_attr_group = { | 2983 | static const struct attribute_group wan_attr_group = { |
2984 | .attrs = wan_attributes, | 2984 | .attrs = wan_attributes, |
2985 | }; | 2985 | }; |
2986 | 2986 | ||
2987 | static int tpacpi_wan_rfk_get(void *data, enum rfkill_state *state) | 2987 | static int tpacpi_wan_rfk_get(void *data, enum rfkill_state *state) |
2988 | { | 2988 | { |
2989 | int wans = wan_get_radiosw(); | 2989 | int wans = wan_get_radiosw(); |
2990 | 2990 | ||
2991 | if (wans < 0) | 2991 | if (wans < 0) |
2992 | return wans; | 2992 | return wans; |
2993 | 2993 | ||
2994 | *state = wans; | 2994 | *state = wans; |
2995 | return 0; | 2995 | return 0; |
2996 | } | 2996 | } |
2997 | 2997 | ||
2998 | static int tpacpi_wan_rfk_set(void *data, enum rfkill_state state) | 2998 | static int tpacpi_wan_rfk_set(void *data, enum rfkill_state state) |
2999 | { | 2999 | { |
3000 | return wan_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0); | 3000 | return wan_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0); |
3001 | } | 3001 | } |
3002 | 3002 | ||
3003 | static void wan_exit(void) | 3003 | static void wan_exit(void) |
3004 | { | 3004 | { |
3005 | if (tpacpi_wan_rfkill) | 3005 | if (tpacpi_wan_rfkill) |
3006 | rfkill_unregister(tpacpi_wan_rfkill); | 3006 | rfkill_unregister(tpacpi_wan_rfkill); |
3007 | 3007 | ||
3008 | sysfs_remove_group(&tpacpi_pdev->dev.kobj, | 3008 | sysfs_remove_group(&tpacpi_pdev->dev.kobj, |
3009 | &wan_attr_group); | 3009 | &wan_attr_group); |
3010 | } | 3010 | } |
3011 | 3011 | ||
3012 | static int __init wan_init(struct ibm_init_struct *iibm) | 3012 | static int __init wan_init(struct ibm_init_struct *iibm) |
3013 | { | 3013 | { |
3014 | int res; | 3014 | int res; |
3015 | int status = 0; | 3015 | int status = 0; |
3016 | 3016 | ||
3017 | vdbg_printk(TPACPI_DBG_INIT, "initializing wan subdriver\n"); | 3017 | vdbg_printk(TPACPI_DBG_INIT, "initializing wan subdriver\n"); |
3018 | 3018 | ||
3019 | TPACPI_ACPIHANDLE_INIT(hkey); | 3019 | TPACPI_ACPIHANDLE_INIT(hkey); |
3020 | 3020 | ||
3021 | tp_features.wan = hkey_handle && | 3021 | tp_features.wan = hkey_handle && |
3022 | acpi_evalf(hkey_handle, &status, "GWAN", "qd"); | 3022 | acpi_evalf(hkey_handle, &status, "GWAN", "qd"); |
3023 | 3023 | ||
3024 | vdbg_printk(TPACPI_DBG_INIT, "wan is %s, status 0x%02x\n", | 3024 | vdbg_printk(TPACPI_DBG_INIT, "wan is %s, status 0x%02x\n", |
3025 | str_supported(tp_features.wan), | 3025 | str_supported(tp_features.wan), |
3026 | status); | 3026 | status); |
3027 | 3027 | ||
3028 | if (tp_features.wan && | 3028 | if (tp_features.wan && |
3029 | !(status & TP_ACPI_WANCARD_HWPRESENT)) { | 3029 | !(status & TP_ACPI_WANCARD_HWPRESENT)) { |
3030 | /* no wan hardware present in system */ | 3030 | /* no wan hardware present in system */ |
3031 | tp_features.wan = 0; | 3031 | tp_features.wan = 0; |
3032 | dbg_printk(TPACPI_DBG_INIT, | 3032 | dbg_printk(TPACPI_DBG_INIT, |
3033 | "wan hardware not installed\n"); | 3033 | "wan hardware not installed\n"); |
3034 | } | 3034 | } |
3035 | 3035 | ||
3036 | if (!tp_features.wan) | 3036 | if (!tp_features.wan) |
3037 | return 1; | 3037 | return 1; |
3038 | 3038 | ||
3039 | res = sysfs_create_group(&tpacpi_pdev->dev.kobj, | 3039 | res = sysfs_create_group(&tpacpi_pdev->dev.kobj, |
3040 | &wan_attr_group); | 3040 | &wan_attr_group); |
3041 | if (res) | 3041 | if (res) |
3042 | return res; | 3042 | return res; |
3043 | 3043 | ||
3044 | res = tpacpi_new_rfkill(TPACPI_RFK_WWAN_SW_ID, | 3044 | res = tpacpi_new_rfkill(TPACPI_RFK_WWAN_SW_ID, |
3045 | &tpacpi_wan_rfkill, | 3045 | &tpacpi_wan_rfkill, |
3046 | RFKILL_TYPE_WWAN, | 3046 | RFKILL_TYPE_WWAN, |
3047 | "tpacpi_wwan_sw", | 3047 | "tpacpi_wwan_sw", |
3048 | tpacpi_wan_rfk_set, | 3048 | tpacpi_wan_rfk_set, |
3049 | tpacpi_wan_rfk_get); | 3049 | tpacpi_wan_rfk_get); |
3050 | if (res) { | 3050 | if (res) { |
3051 | wan_exit(); | 3051 | wan_exit(); |
3052 | return res; | 3052 | return res; |
3053 | } | 3053 | } |
3054 | 3054 | ||
3055 | return 0; | 3055 | return 0; |
3056 | } | 3056 | } |
3057 | 3057 | ||
3058 | /* procfs -------------------------------------------------------------- */ | 3058 | /* procfs -------------------------------------------------------------- */ |
3059 | static int wan_read(char *p) | 3059 | static int wan_read(char *p) |
3060 | { | 3060 | { |
3061 | int len = 0; | 3061 | int len = 0; |
3062 | int status = wan_get_radiosw(); | 3062 | int status = wan_get_radiosw(); |
3063 | 3063 | ||
3064 | if (!tp_features.wan) | 3064 | if (!tp_features.wan) |
3065 | len += sprintf(p + len, "status:\t\tnot supported\n"); | 3065 | len += sprintf(p + len, "status:\t\tnot supported\n"); |
3066 | else { | 3066 | else { |
3067 | len += sprintf(p + len, "status:\t\t%s\n", | 3067 | len += sprintf(p + len, "status:\t\t%s\n", |
3068 | (status == RFKILL_STATE_UNBLOCKED) ? | 3068 | (status == RFKILL_STATE_UNBLOCKED) ? |
3069 | "enabled" : "disabled"); | 3069 | "enabled" : "disabled"); |
3070 | len += sprintf(p + len, "commands:\tenable, disable\n"); | 3070 | len += sprintf(p + len, "commands:\tenable, disable\n"); |
3071 | } | 3071 | } |
3072 | 3072 | ||
3073 | return len; | 3073 | return len; |
3074 | } | 3074 | } |
3075 | 3075 | ||
3076 | static int wan_write(char *buf) | 3076 | static int wan_write(char *buf) |
3077 | { | 3077 | { |
3078 | char *cmd; | 3078 | char *cmd; |
3079 | 3079 | ||
3080 | if (!tp_features.wan) | 3080 | if (!tp_features.wan) |
3081 | return -ENODEV; | 3081 | return -ENODEV; |
3082 | 3082 | ||
3083 | while ((cmd = next_cmd(&buf))) { | 3083 | while ((cmd = next_cmd(&buf))) { |
3084 | if (strlencmp(cmd, "enable") == 0) { | 3084 | if (strlencmp(cmd, "enable") == 0) { |
3085 | wan_set_radiosw(1, 1); | 3085 | wan_set_radiosw(1, 1); |
3086 | } else if (strlencmp(cmd, "disable") == 0) { | 3086 | } else if (strlencmp(cmd, "disable") == 0) { |
3087 | wan_set_radiosw(0, 1); | 3087 | wan_set_radiosw(0, 1); |
3088 | } else | 3088 | } else |
3089 | return -EINVAL; | 3089 | return -EINVAL; |
3090 | } | 3090 | } |
3091 | 3091 | ||
3092 | return 0; | 3092 | return 0; |
3093 | } | 3093 | } |
3094 | 3094 | ||
3095 | static struct ibm_struct wan_driver_data = { | 3095 | static struct ibm_struct wan_driver_data = { |
3096 | .name = "wan", | 3096 | .name = "wan", |
3097 | .read = wan_read, | 3097 | .read = wan_read, |
3098 | .write = wan_write, | 3098 | .write = wan_write, |
3099 | .exit = wan_exit, | 3099 | .exit = wan_exit, |
3100 | }; | 3100 | }; |
3101 | 3101 | ||
3102 | /************************************************************************* | 3102 | /************************************************************************* |
3103 | * Video subdriver | 3103 | * Video subdriver |
3104 | */ | 3104 | */ |
3105 | 3105 | ||
3106 | #ifdef CONFIG_THINKPAD_ACPI_VIDEO | 3106 | #ifdef CONFIG_THINKPAD_ACPI_VIDEO |
3107 | 3107 | ||
3108 | enum video_access_mode { | 3108 | enum video_access_mode { |
3109 | TPACPI_VIDEO_NONE = 0, | 3109 | TPACPI_VIDEO_NONE = 0, |
3110 | TPACPI_VIDEO_570, /* 570 */ | 3110 | TPACPI_VIDEO_570, /* 570 */ |
3111 | TPACPI_VIDEO_770, /* 600e/x, 770e, 770x */ | 3111 | TPACPI_VIDEO_770, /* 600e/x, 770e, 770x */ |
3112 | TPACPI_VIDEO_NEW, /* all others */ | 3112 | TPACPI_VIDEO_NEW, /* all others */ |
3113 | }; | 3113 | }; |
3114 | 3114 | ||
3115 | enum { /* video status flags, based on VIDEO_570 */ | 3115 | enum { /* video status flags, based on VIDEO_570 */ |
3116 | TP_ACPI_VIDEO_S_LCD = 0x01, /* LCD output enabled */ | 3116 | TP_ACPI_VIDEO_S_LCD = 0x01, /* LCD output enabled */ |
3117 | TP_ACPI_VIDEO_S_CRT = 0x02, /* CRT output enabled */ | 3117 | TP_ACPI_VIDEO_S_CRT = 0x02, /* CRT output enabled */ |
3118 | TP_ACPI_VIDEO_S_DVI = 0x08, /* DVI output enabled */ | 3118 | TP_ACPI_VIDEO_S_DVI = 0x08, /* DVI output enabled */ |
3119 | }; | 3119 | }; |
3120 | 3120 | ||
3121 | enum { /* TPACPI_VIDEO_570 constants */ | 3121 | enum { /* TPACPI_VIDEO_570 constants */ |
3122 | TP_ACPI_VIDEO_570_PHSCMD = 0x87, /* unknown magic constant :( */ | 3122 | TP_ACPI_VIDEO_570_PHSCMD = 0x87, /* unknown magic constant :( */ |
3123 | TP_ACPI_VIDEO_570_PHSMASK = 0x03, /* PHS bits that map to | 3123 | TP_ACPI_VIDEO_570_PHSMASK = 0x03, /* PHS bits that map to |
3124 | * video_status_flags */ | 3124 | * video_status_flags */ |
3125 | TP_ACPI_VIDEO_570_PHS2CMD = 0x8b, /* unknown magic constant :( */ | 3125 | TP_ACPI_VIDEO_570_PHS2CMD = 0x8b, /* unknown magic constant :( */ |
3126 | TP_ACPI_VIDEO_570_PHS2SET = 0x80, /* unknown magic constant :( */ | 3126 | TP_ACPI_VIDEO_570_PHS2SET = 0x80, /* unknown magic constant :( */ |
3127 | }; | 3127 | }; |
3128 | 3128 | ||
3129 | static enum video_access_mode video_supported; | 3129 | static enum video_access_mode video_supported; |
3130 | static int video_orig_autosw; | 3130 | static int video_orig_autosw; |
3131 | 3131 | ||
3132 | static int video_autosw_get(void); | 3132 | static int video_autosw_get(void); |
3133 | static int video_autosw_set(int enable); | 3133 | static int video_autosw_set(int enable); |
3134 | 3134 | ||
3135 | TPACPI_HANDLE(vid2, root, "\\_SB.PCI0.AGPB.VID"); /* G41 */ | 3135 | TPACPI_HANDLE(vid2, root, "\\_SB.PCI0.AGPB.VID"); /* G41 */ |
3136 | 3136 | ||
3137 | static int __init video_init(struct ibm_init_struct *iibm) | 3137 | static int __init video_init(struct ibm_init_struct *iibm) |
3138 | { | 3138 | { |
3139 | int ivga; | 3139 | int ivga; |
3140 | 3140 | ||
3141 | vdbg_printk(TPACPI_DBG_INIT, "initializing video subdriver\n"); | 3141 | vdbg_printk(TPACPI_DBG_INIT, "initializing video subdriver\n"); |
3142 | 3142 | ||
3143 | TPACPI_ACPIHANDLE_INIT(vid); | 3143 | TPACPI_ACPIHANDLE_INIT(vid); |
3144 | TPACPI_ACPIHANDLE_INIT(vid2); | 3144 | TPACPI_ACPIHANDLE_INIT(vid2); |
3145 | 3145 | ||
3146 | if (vid2_handle && acpi_evalf(NULL, &ivga, "\\IVGA", "d") && ivga) | 3146 | if (vid2_handle && acpi_evalf(NULL, &ivga, "\\IVGA", "d") && ivga) |
3147 | /* G41, assume IVGA doesn't change */ | 3147 | /* G41, assume IVGA doesn't change */ |
3148 | vid_handle = vid2_handle; | 3148 | vid_handle = vid2_handle; |
3149 | 3149 | ||
3150 | if (!vid_handle) | 3150 | if (!vid_handle) |
3151 | /* video switching not supported on R30, R31 */ | 3151 | /* video switching not supported on R30, R31 */ |
3152 | video_supported = TPACPI_VIDEO_NONE; | 3152 | video_supported = TPACPI_VIDEO_NONE; |
3153 | else if (acpi_evalf(vid_handle, &video_orig_autosw, "SWIT", "qd")) | 3153 | else if (acpi_evalf(vid_handle, &video_orig_autosw, "SWIT", "qd")) |
3154 | /* 570 */ | 3154 | /* 570 */ |
3155 | video_supported = TPACPI_VIDEO_570; | 3155 | video_supported = TPACPI_VIDEO_570; |
3156 | else if (acpi_evalf(vid_handle, &video_orig_autosw, "^VADL", "qd")) | 3156 | else if (acpi_evalf(vid_handle, &video_orig_autosw, "^VADL", "qd")) |
3157 | /* 600e/x, 770e, 770x */ | 3157 | /* 600e/x, 770e, 770x */ |
3158 | video_supported = TPACPI_VIDEO_770; | 3158 | video_supported = TPACPI_VIDEO_770; |
3159 | else | 3159 | else |
3160 | /* all others */ | 3160 | /* all others */ |
3161 | video_supported = TPACPI_VIDEO_NEW; | 3161 | video_supported = TPACPI_VIDEO_NEW; |
3162 | 3162 | ||
3163 | vdbg_printk(TPACPI_DBG_INIT, "video is %s, mode %d\n", | 3163 | vdbg_printk(TPACPI_DBG_INIT, "video is %s, mode %d\n", |
3164 | str_supported(video_supported != TPACPI_VIDEO_NONE), | 3164 | str_supported(video_supported != TPACPI_VIDEO_NONE), |
3165 | video_supported); | 3165 | video_supported); |
3166 | 3166 | ||
3167 | return (video_supported != TPACPI_VIDEO_NONE)? 0 : 1; | 3167 | return (video_supported != TPACPI_VIDEO_NONE)? 0 : 1; |
3168 | } | 3168 | } |
3169 | 3169 | ||
3170 | static void video_exit(void) | 3170 | static void video_exit(void) |
3171 | { | 3171 | { |
3172 | dbg_printk(TPACPI_DBG_EXIT, | 3172 | dbg_printk(TPACPI_DBG_EXIT, |
3173 | "restoring original video autoswitch mode\n"); | 3173 | "restoring original video autoswitch mode\n"); |
3174 | if (video_autosw_set(video_orig_autosw)) | 3174 | if (video_autosw_set(video_orig_autosw)) |
3175 | printk(TPACPI_ERR "error while trying to restore original " | 3175 | printk(TPACPI_ERR "error while trying to restore original " |
3176 | "video autoswitch mode\n"); | 3176 | "video autoswitch mode\n"); |
3177 | } | 3177 | } |
3178 | 3178 | ||
3179 | static int video_outputsw_get(void) | 3179 | static int video_outputsw_get(void) |
3180 | { | 3180 | { |
3181 | int status = 0; | 3181 | int status = 0; |
3182 | int i; | 3182 | int i; |
3183 | 3183 | ||
3184 | switch (video_supported) { | 3184 | switch (video_supported) { |
3185 | case TPACPI_VIDEO_570: | 3185 | case TPACPI_VIDEO_570: |
3186 | if (!acpi_evalf(NULL, &i, "\\_SB.PHS", "dd", | 3186 | if (!acpi_evalf(NULL, &i, "\\_SB.PHS", "dd", |
3187 | TP_ACPI_VIDEO_570_PHSCMD)) | 3187 | TP_ACPI_VIDEO_570_PHSCMD)) |
3188 | return -EIO; | 3188 | return -EIO; |
3189 | status = i & TP_ACPI_VIDEO_570_PHSMASK; | 3189 | status = i & TP_ACPI_VIDEO_570_PHSMASK; |
3190 | break; | 3190 | break; |
3191 | case TPACPI_VIDEO_770: | 3191 | case TPACPI_VIDEO_770: |
3192 | if (!acpi_evalf(NULL, &i, "\\VCDL", "d")) | 3192 | if (!acpi_evalf(NULL, &i, "\\VCDL", "d")) |
3193 | return -EIO; | 3193 | return -EIO; |
3194 | if (i) | 3194 | if (i) |
3195 | status |= TP_ACPI_VIDEO_S_LCD; | 3195 | status |= TP_ACPI_VIDEO_S_LCD; |
3196 | if (!acpi_evalf(NULL, &i, "\\VCDC", "d")) | 3196 | if (!acpi_evalf(NULL, &i, "\\VCDC", "d")) |
3197 | return -EIO; | 3197 | return -EIO; |
3198 | if (i) | 3198 | if (i) |
3199 | status |= TP_ACPI_VIDEO_S_CRT; | 3199 | status |= TP_ACPI_VIDEO_S_CRT; |
3200 | break; | 3200 | break; |
3201 | case TPACPI_VIDEO_NEW: | 3201 | case TPACPI_VIDEO_NEW: |
3202 | if (!acpi_evalf(NULL, NULL, "\\VUPS", "vd", 1) || | 3202 | if (!acpi_evalf(NULL, NULL, "\\VUPS", "vd", 1) || |
3203 | !acpi_evalf(NULL, &i, "\\VCDC", "d")) | 3203 | !acpi_evalf(NULL, &i, "\\VCDC", "d")) |
3204 | return -EIO; | 3204 | return -EIO; |
3205 | if (i) | 3205 | if (i) |
3206 | status |= TP_ACPI_VIDEO_S_CRT; | 3206 | status |= TP_ACPI_VIDEO_S_CRT; |
3207 | 3207 | ||
3208 | if (!acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0) || | 3208 | if (!acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0) || |
3209 | !acpi_evalf(NULL, &i, "\\VCDL", "d")) | 3209 | !acpi_evalf(NULL, &i, "\\VCDL", "d")) |
3210 | return -EIO; | 3210 | return -EIO; |
3211 | if (i) | 3211 | if (i) |
3212 | status |= TP_ACPI_VIDEO_S_LCD; | 3212 | status |= TP_ACPI_VIDEO_S_LCD; |
3213 | if (!acpi_evalf(NULL, &i, "\\VCDD", "d")) | 3213 | if (!acpi_evalf(NULL, &i, "\\VCDD", "d")) |
3214 | return -EIO; | 3214 | return -EIO; |
3215 | if (i) | 3215 | if (i) |
3216 | status |= TP_ACPI_VIDEO_S_DVI; | 3216 | status |= TP_ACPI_VIDEO_S_DVI; |
3217 | break; | 3217 | break; |
3218 | default: | 3218 | default: |
3219 | return -ENOSYS; | 3219 | return -ENOSYS; |
3220 | } | 3220 | } |
3221 | 3221 | ||
3222 | return status; | 3222 | return status; |
3223 | } | 3223 | } |
3224 | 3224 | ||
3225 | static int video_outputsw_set(int status) | 3225 | static int video_outputsw_set(int status) |
3226 | { | 3226 | { |
3227 | int autosw; | 3227 | int autosw; |
3228 | int res = 0; | 3228 | int res = 0; |
3229 | 3229 | ||
3230 | switch (video_supported) { | 3230 | switch (video_supported) { |
3231 | case TPACPI_VIDEO_570: | 3231 | case TPACPI_VIDEO_570: |
3232 | res = acpi_evalf(NULL, NULL, | 3232 | res = acpi_evalf(NULL, NULL, |
3233 | "\\_SB.PHS2", "vdd", | 3233 | "\\_SB.PHS2", "vdd", |
3234 | TP_ACPI_VIDEO_570_PHS2CMD, | 3234 | TP_ACPI_VIDEO_570_PHS2CMD, |
3235 | status | TP_ACPI_VIDEO_570_PHS2SET); | 3235 | status | TP_ACPI_VIDEO_570_PHS2SET); |
3236 | break; | 3236 | break; |
3237 | case TPACPI_VIDEO_770: | 3237 | case TPACPI_VIDEO_770: |
3238 | autosw = video_autosw_get(); | 3238 | autosw = video_autosw_get(); |
3239 | if (autosw < 0) | 3239 | if (autosw < 0) |
3240 | return autosw; | 3240 | return autosw; |
3241 | 3241 | ||
3242 | res = video_autosw_set(1); | 3242 | res = video_autosw_set(1); |
3243 | if (res) | 3243 | if (res) |
3244 | return res; | 3244 | return res; |
3245 | res = acpi_evalf(vid_handle, NULL, | 3245 | res = acpi_evalf(vid_handle, NULL, |
3246 | "ASWT", "vdd", status * 0x100, 0); | 3246 | "ASWT", "vdd", status * 0x100, 0); |
3247 | if (!autosw && video_autosw_set(autosw)) { | 3247 | if (!autosw && video_autosw_set(autosw)) { |
3248 | printk(TPACPI_ERR | 3248 | printk(TPACPI_ERR |
3249 | "video auto-switch left enabled due to error\n"); | 3249 | "video auto-switch left enabled due to error\n"); |
3250 | return -EIO; | 3250 | return -EIO; |
3251 | } | 3251 | } |
3252 | break; | 3252 | break; |
3253 | case TPACPI_VIDEO_NEW: | 3253 | case TPACPI_VIDEO_NEW: |
3254 | res = acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0x80) && | 3254 | res = acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0x80) && |
3255 | acpi_evalf(NULL, NULL, "\\VSDS", "vdd", status, 1); | 3255 | acpi_evalf(NULL, NULL, "\\VSDS", "vdd", status, 1); |
3256 | break; | 3256 | break; |
3257 | default: | 3257 | default: |
3258 | return -ENOSYS; | 3258 | return -ENOSYS; |
3259 | } | 3259 | } |
3260 | 3260 | ||
3261 | return (res)? 0 : -EIO; | 3261 | return (res)? 0 : -EIO; |
3262 | } | 3262 | } |
3263 | 3263 | ||
3264 | static int video_autosw_get(void) | 3264 | static int video_autosw_get(void) |
3265 | { | 3265 | { |
3266 | int autosw = 0; | 3266 | int autosw = 0; |
3267 | 3267 | ||
3268 | switch (video_supported) { | 3268 | switch (video_supported) { |
3269 | case TPACPI_VIDEO_570: | 3269 | case TPACPI_VIDEO_570: |
3270 | if (!acpi_evalf(vid_handle, &autosw, "SWIT", "d")) | 3270 | if (!acpi_evalf(vid_handle, &autosw, "SWIT", "d")) |
3271 | return -EIO; | 3271 | return -EIO; |
3272 | break; | 3272 | break; |
3273 | case TPACPI_VIDEO_770: | 3273 | case TPACPI_VIDEO_770: |
3274 | case TPACPI_VIDEO_NEW: | 3274 | case TPACPI_VIDEO_NEW: |
3275 | if (!acpi_evalf(vid_handle, &autosw, "^VDEE", "d")) | 3275 | if (!acpi_evalf(vid_handle, &autosw, "^VDEE", "d")) |
3276 | return -EIO; | 3276 | return -EIO; |
3277 | break; | 3277 | break; |
3278 | default: | 3278 | default: |
3279 | return -ENOSYS; | 3279 | return -ENOSYS; |
3280 | } | 3280 | } |
3281 | 3281 | ||
3282 | return autosw & 1; | 3282 | return autosw & 1; |
3283 | } | 3283 | } |
3284 | 3284 | ||
3285 | static int video_autosw_set(int enable) | 3285 | static int video_autosw_set(int enable) |
3286 | { | 3286 | { |
3287 | if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", (enable)? 1 : 0)) | 3287 | if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", (enable)? 1 : 0)) |
3288 | return -EIO; | 3288 | return -EIO; |
3289 | return 0; | 3289 | return 0; |
3290 | } | 3290 | } |
3291 | 3291 | ||
3292 | static int video_outputsw_cycle(void) | 3292 | static int video_outputsw_cycle(void) |
3293 | { | 3293 | { |
3294 | int autosw = video_autosw_get(); | 3294 | int autosw = video_autosw_get(); |
3295 | int res; | 3295 | int res; |
3296 | 3296 | ||
3297 | if (autosw < 0) | 3297 | if (autosw < 0) |
3298 | return autosw; | 3298 | return autosw; |
3299 | 3299 | ||
3300 | switch (video_supported) { | 3300 | switch (video_supported) { |
3301 | case TPACPI_VIDEO_570: | 3301 | case TPACPI_VIDEO_570: |
3302 | res = video_autosw_set(1); | 3302 | res = video_autosw_set(1); |
3303 | if (res) | 3303 | if (res) |
3304 | return res; | 3304 | return res; |
3305 | res = acpi_evalf(ec_handle, NULL, "_Q16", "v"); | 3305 | res = acpi_evalf(ec_handle, NULL, "_Q16", "v"); |
3306 | break; | 3306 | break; |
3307 | case TPACPI_VIDEO_770: | 3307 | case TPACPI_VIDEO_770: |
3308 | case TPACPI_VIDEO_NEW: | 3308 | case TPACPI_VIDEO_NEW: |
3309 | res = video_autosw_set(1); | 3309 | res = video_autosw_set(1); |
3310 | if (res) | 3310 | if (res) |
3311 | return res; | 3311 | return res; |
3312 | res = acpi_evalf(vid_handle, NULL, "VSWT", "v"); | 3312 | res = acpi_evalf(vid_handle, NULL, "VSWT", "v"); |
3313 | break; | 3313 | break; |
3314 | default: | 3314 | default: |
3315 | return -ENOSYS; | 3315 | return -ENOSYS; |
3316 | } | 3316 | } |
3317 | if (!autosw && video_autosw_set(autosw)) { | 3317 | if (!autosw && video_autosw_set(autosw)) { |
3318 | printk(TPACPI_ERR | 3318 | printk(TPACPI_ERR |
3319 | "video auto-switch left enabled due to error\n"); | 3319 | "video auto-switch left enabled due to error\n"); |
3320 | return -EIO; | 3320 | return -EIO; |
3321 | } | 3321 | } |
3322 | 3322 | ||
3323 | return (res)? 0 : -EIO; | 3323 | return (res)? 0 : -EIO; |
3324 | } | 3324 | } |
3325 | 3325 | ||
3326 | static int video_expand_toggle(void) | 3326 | static int video_expand_toggle(void) |
3327 | { | 3327 | { |
3328 | switch (video_supported) { | 3328 | switch (video_supported) { |
3329 | case TPACPI_VIDEO_570: | 3329 | case TPACPI_VIDEO_570: |
3330 | return acpi_evalf(ec_handle, NULL, "_Q17", "v")? | 3330 | return acpi_evalf(ec_handle, NULL, "_Q17", "v")? |
3331 | 0 : -EIO; | 3331 | 0 : -EIO; |
3332 | case TPACPI_VIDEO_770: | 3332 | case TPACPI_VIDEO_770: |
3333 | return acpi_evalf(vid_handle, NULL, "VEXP", "v")? | 3333 | return acpi_evalf(vid_handle, NULL, "VEXP", "v")? |
3334 | 0 : -EIO; | 3334 | 0 : -EIO; |
3335 | case TPACPI_VIDEO_NEW: | 3335 | case TPACPI_VIDEO_NEW: |
3336 | return acpi_evalf(NULL, NULL, "\\VEXP", "v")? | 3336 | return acpi_evalf(NULL, NULL, "\\VEXP", "v")? |
3337 | 0 : -EIO; | 3337 | 0 : -EIO; |
3338 | default: | 3338 | default: |
3339 | return -ENOSYS; | 3339 | return -ENOSYS; |
3340 | } | 3340 | } |
3341 | /* not reached */ | 3341 | /* not reached */ |
3342 | } | 3342 | } |
3343 | 3343 | ||
3344 | static int video_read(char *p) | 3344 | static int video_read(char *p) |
3345 | { | 3345 | { |
3346 | int status, autosw; | 3346 | int status, autosw; |
3347 | int len = 0; | 3347 | int len = 0; |
3348 | 3348 | ||
3349 | if (video_supported == TPACPI_VIDEO_NONE) { | 3349 | if (video_supported == TPACPI_VIDEO_NONE) { |
3350 | len += sprintf(p + len, "status:\t\tnot supported\n"); | 3350 | len += sprintf(p + len, "status:\t\tnot supported\n"); |
3351 | return len; | 3351 | return len; |
3352 | } | 3352 | } |
3353 | 3353 | ||
3354 | status = video_outputsw_get(); | 3354 | status = video_outputsw_get(); |
3355 | if (status < 0) | 3355 | if (status < 0) |
3356 | return status; | 3356 | return status; |
3357 | 3357 | ||
3358 | autosw = video_autosw_get(); | 3358 | autosw = video_autosw_get(); |
3359 | if (autosw < 0) | 3359 | if (autosw < 0) |
3360 | return autosw; | 3360 | return autosw; |
3361 | 3361 | ||
3362 | len += sprintf(p + len, "status:\t\tsupported\n"); | 3362 | len += sprintf(p + len, "status:\t\tsupported\n"); |
3363 | len += sprintf(p + len, "lcd:\t\t%s\n", enabled(status, 0)); | 3363 | len += sprintf(p + len, "lcd:\t\t%s\n", enabled(status, 0)); |
3364 | len += sprintf(p + len, "crt:\t\t%s\n", enabled(status, 1)); | 3364 | len += sprintf(p + len, "crt:\t\t%s\n", enabled(status, 1)); |
3365 | if (video_supported == TPACPI_VIDEO_NEW) | 3365 | if (video_supported == TPACPI_VIDEO_NEW) |
3366 | len += sprintf(p + len, "dvi:\t\t%s\n", enabled(status, 3)); | 3366 | len += sprintf(p + len, "dvi:\t\t%s\n", enabled(status, 3)); |
3367 | len += sprintf(p + len, "auto:\t\t%s\n", enabled(autosw, 0)); | 3367 | len += sprintf(p + len, "auto:\t\t%s\n", enabled(autosw, 0)); |
3368 | len += sprintf(p + len, "commands:\tlcd_enable, lcd_disable\n"); | 3368 | len += sprintf(p + len, "commands:\tlcd_enable, lcd_disable\n"); |
3369 | len += sprintf(p + len, "commands:\tcrt_enable, crt_disable\n"); | 3369 | len += sprintf(p + len, "commands:\tcrt_enable, crt_disable\n"); |
3370 | if (video_supported == TPACPI_VIDEO_NEW) | 3370 | if (video_supported == TPACPI_VIDEO_NEW) |
3371 | len += sprintf(p + len, "commands:\tdvi_enable, dvi_disable\n"); | 3371 | len += sprintf(p + len, "commands:\tdvi_enable, dvi_disable\n"); |
3372 | len += sprintf(p + len, "commands:\tauto_enable, auto_disable\n"); | 3372 | len += sprintf(p + len, "commands:\tauto_enable, auto_disable\n"); |
3373 | len += sprintf(p + len, "commands:\tvideo_switch, expand_toggle\n"); | 3373 | len += sprintf(p + len, "commands:\tvideo_switch, expand_toggle\n"); |
3374 | 3374 | ||
3375 | return len; | 3375 | return len; |
3376 | } | 3376 | } |
3377 | 3377 | ||
3378 | static int video_write(char *buf) | 3378 | static int video_write(char *buf) |
3379 | { | 3379 | { |
3380 | char *cmd; | 3380 | char *cmd; |
3381 | int enable, disable, status; | 3381 | int enable, disable, status; |
3382 | int res; | 3382 | int res; |
3383 | 3383 | ||
3384 | if (video_supported == TPACPI_VIDEO_NONE) | 3384 | if (video_supported == TPACPI_VIDEO_NONE) |
3385 | return -ENODEV; | 3385 | return -ENODEV; |
3386 | 3386 | ||
3387 | enable = 0; | 3387 | enable = 0; |
3388 | disable = 0; | 3388 | disable = 0; |
3389 | 3389 | ||
3390 | while ((cmd = next_cmd(&buf))) { | 3390 | while ((cmd = next_cmd(&buf))) { |
3391 | if (strlencmp(cmd, "lcd_enable") == 0) { | 3391 | if (strlencmp(cmd, "lcd_enable") == 0) { |
3392 | enable |= TP_ACPI_VIDEO_S_LCD; | 3392 | enable |= TP_ACPI_VIDEO_S_LCD; |
3393 | } else if (strlencmp(cmd, "lcd_disable") == 0) { | 3393 | } else if (strlencmp(cmd, "lcd_disable") == 0) { |
3394 | disable |= TP_ACPI_VIDEO_S_LCD; | 3394 | disable |= TP_ACPI_VIDEO_S_LCD; |
3395 | } else if (strlencmp(cmd, "crt_enable") == 0) { | 3395 | } else if (strlencmp(cmd, "crt_enable") == 0) { |
3396 | enable |= TP_ACPI_VIDEO_S_CRT; | 3396 | enable |= TP_ACPI_VIDEO_S_CRT; |
3397 | } else if (strlencmp(cmd, "crt_disable") == 0) { | 3397 | } else if (strlencmp(cmd, "crt_disable") == 0) { |
3398 | disable |= TP_ACPI_VIDEO_S_CRT; | 3398 | disable |= TP_ACPI_VIDEO_S_CRT; |
3399 | } else if (video_supported == TPACPI_VIDEO_NEW && | 3399 | } else if (video_supported == TPACPI_VIDEO_NEW && |
3400 | strlencmp(cmd, "dvi_enable") == 0) { | 3400 | strlencmp(cmd, "dvi_enable") == 0) { |
3401 | enable |= TP_ACPI_VIDEO_S_DVI; | 3401 | enable |= TP_ACPI_VIDEO_S_DVI; |
3402 | } else if (video_supported == TPACPI_VIDEO_NEW && | 3402 | } else if (video_supported == TPACPI_VIDEO_NEW && |
3403 | strlencmp(cmd, "dvi_disable") == 0) { | 3403 | strlencmp(cmd, "dvi_disable") == 0) { |
3404 | disable |= TP_ACPI_VIDEO_S_DVI; | 3404 | disable |= TP_ACPI_VIDEO_S_DVI; |
3405 | } else if (strlencmp(cmd, "auto_enable") == 0) { | 3405 | } else if (strlencmp(cmd, "auto_enable") == 0) { |
3406 | res = video_autosw_set(1); | 3406 | res = video_autosw_set(1); |
3407 | if (res) | 3407 | if (res) |
3408 | return res; | 3408 | return res; |
3409 | } else if (strlencmp(cmd, "auto_disable") == 0) { | 3409 | } else if (strlencmp(cmd, "auto_disable") == 0) { |
3410 | res = video_autosw_set(0); | 3410 | res = video_autosw_set(0); |
3411 | if (res) | 3411 | if (res) |
3412 | return res; | 3412 | return res; |
3413 | } else if (strlencmp(cmd, "video_switch") == 0) { | 3413 | } else if (strlencmp(cmd, "video_switch") == 0) { |
3414 | res = video_outputsw_cycle(); | 3414 | res = video_outputsw_cycle(); |
3415 | if (res) | 3415 | if (res) |
3416 | return res; | 3416 | return res; |
3417 | } else if (strlencmp(cmd, "expand_toggle") == 0) { | 3417 | } else if (strlencmp(cmd, "expand_toggle") == 0) { |
3418 | res = video_expand_toggle(); | 3418 | res = video_expand_toggle(); |
3419 | if (res) | 3419 | if (res) |
3420 | return res; | 3420 | return res; |
3421 | } else | 3421 | } else |
3422 | return -EINVAL; | 3422 | return -EINVAL; |
3423 | } | 3423 | } |
3424 | 3424 | ||
3425 | if (enable || disable) { | 3425 | if (enable || disable) { |
3426 | status = video_outputsw_get(); | 3426 | status = video_outputsw_get(); |
3427 | if (status < 0) | 3427 | if (status < 0) |
3428 | return status; | 3428 | return status; |
3429 | res = video_outputsw_set((status & ~disable) | enable); | 3429 | res = video_outputsw_set((status & ~disable) | enable); |
3430 | if (res) | 3430 | if (res) |
3431 | return res; | 3431 | return res; |
3432 | } | 3432 | } |
3433 | 3433 | ||
3434 | return 0; | 3434 | return 0; |
3435 | } | 3435 | } |
3436 | 3436 | ||
3437 | static struct ibm_struct video_driver_data = { | 3437 | static struct ibm_struct video_driver_data = { |
3438 | .name = "video", | 3438 | .name = "video", |
3439 | .read = video_read, | 3439 | .read = video_read, |
3440 | .write = video_write, | 3440 | .write = video_write, |
3441 | .exit = video_exit, | 3441 | .exit = video_exit, |
3442 | }; | 3442 | }; |
3443 | 3443 | ||
3444 | #endif /* CONFIG_THINKPAD_ACPI_VIDEO */ | 3444 | #endif /* CONFIG_THINKPAD_ACPI_VIDEO */ |
3445 | 3445 | ||
3446 | /************************************************************************* | 3446 | /************************************************************************* |
3447 | * Light (thinklight) subdriver | 3447 | * Light (thinklight) subdriver |
3448 | */ | 3448 | */ |
3449 | 3449 | ||
3450 | TPACPI_HANDLE(lght, root, "\\LGHT"); /* A21e, A2xm/p, T20-22, X20-21 */ | 3450 | TPACPI_HANDLE(lght, root, "\\LGHT"); /* A21e, A2xm/p, T20-22, X20-21 */ |
3451 | TPACPI_HANDLE(ledb, ec, "LEDB"); /* G4x */ | 3451 | TPACPI_HANDLE(ledb, ec, "LEDB"); /* G4x */ |
3452 | 3452 | ||
3453 | static int light_get_status(void) | 3453 | static int light_get_status(void) |
3454 | { | 3454 | { |
3455 | int status = 0; | 3455 | int status = 0; |
3456 | 3456 | ||
3457 | if (tp_features.light_status) { | 3457 | if (tp_features.light_status) { |
3458 | if (!acpi_evalf(ec_handle, &status, "KBLT", "d")) | 3458 | if (!acpi_evalf(ec_handle, &status, "KBLT", "d")) |
3459 | return -EIO; | 3459 | return -EIO; |
3460 | return (!!status); | 3460 | return (!!status); |
3461 | } | 3461 | } |
3462 | 3462 | ||
3463 | return -ENXIO; | 3463 | return -ENXIO; |
3464 | } | 3464 | } |
3465 | 3465 | ||
3466 | static int light_set_status(int status) | 3466 | static int light_set_status(int status) |
3467 | { | 3467 | { |
3468 | int rc; | 3468 | int rc; |
3469 | 3469 | ||
3470 | if (tp_features.light) { | 3470 | if (tp_features.light) { |
3471 | if (cmos_handle) { | 3471 | if (cmos_handle) { |
3472 | rc = acpi_evalf(cmos_handle, NULL, NULL, "vd", | 3472 | rc = acpi_evalf(cmos_handle, NULL, NULL, "vd", |
3473 | (status)? | 3473 | (status)? |
3474 | TP_CMOS_THINKLIGHT_ON : | 3474 | TP_CMOS_THINKLIGHT_ON : |
3475 | TP_CMOS_THINKLIGHT_OFF); | 3475 | TP_CMOS_THINKLIGHT_OFF); |
3476 | } else { | 3476 | } else { |
3477 | rc = acpi_evalf(lght_handle, NULL, NULL, "vd", | 3477 | rc = acpi_evalf(lght_handle, NULL, NULL, "vd", |
3478 | (status)? 1 : 0); | 3478 | (status)? 1 : 0); |
3479 | } | 3479 | } |
3480 | return (rc)? 0 : -EIO; | 3480 | return (rc)? 0 : -EIO; |
3481 | } | 3481 | } |
3482 | 3482 | ||
3483 | return -ENXIO; | 3483 | return -ENXIO; |
3484 | } | 3484 | } |
3485 | 3485 | ||
3486 | static void light_set_status_worker(struct work_struct *work) | 3486 | static void light_set_status_worker(struct work_struct *work) |
3487 | { | 3487 | { |
3488 | struct tpacpi_led_classdev *data = | 3488 | struct tpacpi_led_classdev *data = |
3489 | container_of(work, struct tpacpi_led_classdev, work); | 3489 | container_of(work, struct tpacpi_led_classdev, work); |
3490 | 3490 | ||
3491 | if (likely(tpacpi_lifecycle == TPACPI_LIFE_RUNNING)) | 3491 | if (likely(tpacpi_lifecycle == TPACPI_LIFE_RUNNING)) |
3492 | light_set_status((data->new_brightness != LED_OFF)); | 3492 | light_set_status((data->new_brightness != LED_OFF)); |
3493 | } | 3493 | } |
3494 | 3494 | ||
3495 | static void light_sysfs_set(struct led_classdev *led_cdev, | 3495 | static void light_sysfs_set(struct led_classdev *led_cdev, |
3496 | enum led_brightness brightness) | 3496 | enum led_brightness brightness) |
3497 | { | 3497 | { |
3498 | struct tpacpi_led_classdev *data = | 3498 | struct tpacpi_led_classdev *data = |
3499 | container_of(led_cdev, | 3499 | container_of(led_cdev, |
3500 | struct tpacpi_led_classdev, | 3500 | struct tpacpi_led_classdev, |
3501 | led_classdev); | 3501 | led_classdev); |
3502 | data->new_brightness = brightness; | 3502 | data->new_brightness = brightness; |
3503 | queue_work(tpacpi_wq, &data->work); | 3503 | queue_work(tpacpi_wq, &data->work); |
3504 | } | 3504 | } |
3505 | 3505 | ||
3506 | static enum led_brightness light_sysfs_get(struct led_classdev *led_cdev) | 3506 | static enum led_brightness light_sysfs_get(struct led_classdev *led_cdev) |
3507 | { | 3507 | { |
3508 | return (light_get_status() == 1)? LED_FULL : LED_OFF; | 3508 | return (light_get_status() == 1)? LED_FULL : LED_OFF; |
3509 | } | 3509 | } |
3510 | 3510 | ||
3511 | static struct tpacpi_led_classdev tpacpi_led_thinklight = { | 3511 | static struct tpacpi_led_classdev tpacpi_led_thinklight = { |
3512 | .led_classdev = { | 3512 | .led_classdev = { |
3513 | .name = "tpacpi::thinklight", | 3513 | .name = "tpacpi::thinklight", |
3514 | .brightness_set = &light_sysfs_set, | 3514 | .brightness_set = &light_sysfs_set, |
3515 | .brightness_get = &light_sysfs_get, | 3515 | .brightness_get = &light_sysfs_get, |
3516 | } | 3516 | } |
3517 | }; | 3517 | }; |
3518 | 3518 | ||
3519 | static int __init light_init(struct ibm_init_struct *iibm) | 3519 | static int __init light_init(struct ibm_init_struct *iibm) |
3520 | { | 3520 | { |
3521 | int rc; | 3521 | int rc; |
3522 | 3522 | ||
3523 | vdbg_printk(TPACPI_DBG_INIT, "initializing light subdriver\n"); | 3523 | vdbg_printk(TPACPI_DBG_INIT, "initializing light subdriver\n"); |
3524 | 3524 | ||
3525 | TPACPI_ACPIHANDLE_INIT(ledb); | 3525 | TPACPI_ACPIHANDLE_INIT(ledb); |
3526 | TPACPI_ACPIHANDLE_INIT(lght); | 3526 | TPACPI_ACPIHANDLE_INIT(lght); |
3527 | TPACPI_ACPIHANDLE_INIT(cmos); | 3527 | TPACPI_ACPIHANDLE_INIT(cmos); |
3528 | INIT_WORK(&tpacpi_led_thinklight.work, light_set_status_worker); | 3528 | INIT_WORK(&tpacpi_led_thinklight.work, light_set_status_worker); |
3529 | 3529 | ||
3530 | /* light not supported on 570, 600e/x, 770e, 770x, G4x, R30, R31 */ | 3530 | /* light not supported on 570, 600e/x, 770e, 770x, G4x, R30, R31 */ |
3531 | tp_features.light = (cmos_handle || lght_handle) && !ledb_handle; | 3531 | tp_features.light = (cmos_handle || lght_handle) && !ledb_handle; |
3532 | 3532 | ||
3533 | if (tp_features.light) | 3533 | if (tp_features.light) |
3534 | /* light status not supported on | 3534 | /* light status not supported on |
3535 | 570, 600e/x, 770e, 770x, G4x, R30, R31, R32, X20 */ | 3535 | 570, 600e/x, 770e, 770x, G4x, R30, R31, R32, X20 */ |
3536 | tp_features.light_status = | 3536 | tp_features.light_status = |
3537 | acpi_evalf(ec_handle, NULL, "KBLT", "qv"); | 3537 | acpi_evalf(ec_handle, NULL, "KBLT", "qv"); |
3538 | 3538 | ||
3539 | vdbg_printk(TPACPI_DBG_INIT, "light is %s, light status is %s\n", | 3539 | vdbg_printk(TPACPI_DBG_INIT, "light is %s, light status is %s\n", |
3540 | str_supported(tp_features.light), | 3540 | str_supported(tp_features.light), |
3541 | str_supported(tp_features.light_status)); | 3541 | str_supported(tp_features.light_status)); |
3542 | 3542 | ||
3543 | if (!tp_features.light) | 3543 | if (!tp_features.light) |
3544 | return 1; | 3544 | return 1; |
3545 | 3545 | ||
3546 | rc = led_classdev_register(&tpacpi_pdev->dev, | 3546 | rc = led_classdev_register(&tpacpi_pdev->dev, |
3547 | &tpacpi_led_thinklight.led_classdev); | 3547 | &tpacpi_led_thinklight.led_classdev); |
3548 | 3548 | ||
3549 | if (rc < 0) { | 3549 | if (rc < 0) { |
3550 | tp_features.light = 0; | 3550 | tp_features.light = 0; |
3551 | tp_features.light_status = 0; | 3551 | tp_features.light_status = 0; |
3552 | } else { | 3552 | } else { |
3553 | rc = 0; | 3553 | rc = 0; |
3554 | } | 3554 | } |
3555 | 3555 | ||
3556 | return rc; | 3556 | return rc; |
3557 | } | 3557 | } |
3558 | 3558 | ||
3559 | static void light_exit(void) | 3559 | static void light_exit(void) |
3560 | { | 3560 | { |
3561 | led_classdev_unregister(&tpacpi_led_thinklight.led_classdev); | 3561 | led_classdev_unregister(&tpacpi_led_thinklight.led_classdev); |
3562 | if (work_pending(&tpacpi_led_thinklight.work)) | 3562 | if (work_pending(&tpacpi_led_thinklight.work)) |
3563 | flush_workqueue(tpacpi_wq); | 3563 | flush_workqueue(tpacpi_wq); |
3564 | } | 3564 | } |
3565 | 3565 | ||
3566 | static int light_read(char *p) | 3566 | static int light_read(char *p) |
3567 | { | 3567 | { |
3568 | int len = 0; | 3568 | int len = 0; |
3569 | int status; | 3569 | int status; |
3570 | 3570 | ||
3571 | if (!tp_features.light) { | 3571 | if (!tp_features.light) { |
3572 | len += sprintf(p + len, "status:\t\tnot supported\n"); | 3572 | len += sprintf(p + len, "status:\t\tnot supported\n"); |
3573 | } else if (!tp_features.light_status) { | 3573 | } else if (!tp_features.light_status) { |
3574 | len += sprintf(p + len, "status:\t\tunknown\n"); | 3574 | len += sprintf(p + len, "status:\t\tunknown\n"); |
3575 | len += sprintf(p + len, "commands:\ton, off\n"); | 3575 | len += sprintf(p + len, "commands:\ton, off\n"); |
3576 | } else { | 3576 | } else { |
3577 | status = light_get_status(); | 3577 | status = light_get_status(); |
3578 | if (status < 0) | 3578 | if (status < 0) |
3579 | return status; | 3579 | return status; |
3580 | len += sprintf(p + len, "status:\t\t%s\n", onoff(status, 0)); | 3580 | len += sprintf(p + len, "status:\t\t%s\n", onoff(status, 0)); |
3581 | len += sprintf(p + len, "commands:\ton, off\n"); | 3581 | len += sprintf(p + len, "commands:\ton, off\n"); |
3582 | } | 3582 | } |
3583 | 3583 | ||
3584 | return len; | 3584 | return len; |
3585 | } | 3585 | } |
3586 | 3586 | ||
3587 | static int light_write(char *buf) | 3587 | static int light_write(char *buf) |
3588 | { | 3588 | { |
3589 | char *cmd; | 3589 | char *cmd; |
3590 | int newstatus = 0; | 3590 | int newstatus = 0; |
3591 | 3591 | ||
3592 | if (!tp_features.light) | 3592 | if (!tp_features.light) |
3593 | return -ENODEV; | 3593 | return -ENODEV; |
3594 | 3594 | ||
3595 | while ((cmd = next_cmd(&buf))) { | 3595 | while ((cmd = next_cmd(&buf))) { |
3596 | if (strlencmp(cmd, "on") == 0) { | 3596 | if (strlencmp(cmd, "on") == 0) { |
3597 | newstatus = 1; | 3597 | newstatus = 1; |
3598 | } else if (strlencmp(cmd, "off") == 0) { | 3598 | } else if (strlencmp(cmd, "off") == 0) { |
3599 | newstatus = 0; | 3599 | newstatus = 0; |
3600 | } else | 3600 | } else |
3601 | return -EINVAL; | 3601 | return -EINVAL; |
3602 | } | 3602 | } |
3603 | 3603 | ||
3604 | return light_set_status(newstatus); | 3604 | return light_set_status(newstatus); |
3605 | } | 3605 | } |
3606 | 3606 | ||
3607 | static struct ibm_struct light_driver_data = { | 3607 | static struct ibm_struct light_driver_data = { |
3608 | .name = "light", | 3608 | .name = "light", |
3609 | .read = light_read, | 3609 | .read = light_read, |
3610 | .write = light_write, | 3610 | .write = light_write, |
3611 | .exit = light_exit, | 3611 | .exit = light_exit, |
3612 | }; | 3612 | }; |
3613 | 3613 | ||
3614 | /************************************************************************* | 3614 | /************************************************************************* |
3615 | * Dock subdriver | 3615 | * Dock subdriver |
3616 | */ | 3616 | */ |
3617 | 3617 | ||
3618 | #ifdef CONFIG_THINKPAD_ACPI_DOCK | 3618 | #ifdef CONFIG_THINKPAD_ACPI_DOCK |
3619 | 3619 | ||
3620 | static void dock_notify(struct ibm_struct *ibm, u32 event); | 3620 | static void dock_notify(struct ibm_struct *ibm, u32 event); |
3621 | static int dock_read(char *p); | 3621 | static int dock_read(char *p); |
3622 | static int dock_write(char *buf); | 3622 | static int dock_write(char *buf); |
3623 | 3623 | ||
3624 | TPACPI_HANDLE(dock, root, "\\_SB.GDCK", /* X30, X31, X40 */ | 3624 | TPACPI_HANDLE(dock, root, "\\_SB.GDCK", /* X30, X31, X40 */ |
3625 | "\\_SB.PCI0.DOCK", /* 600e/x,770e,770x,A2xm/p,T20-22,X20-21 */ | 3625 | "\\_SB.PCI0.DOCK", /* 600e/x,770e,770x,A2xm/p,T20-22,X20-21 */ |
3626 | "\\_SB.PCI0.PCI1.DOCK", /* all others */ | 3626 | "\\_SB.PCI0.PCI1.DOCK", /* all others */ |
3627 | "\\_SB.PCI.ISA.SLCE", /* 570 */ | 3627 | "\\_SB.PCI.ISA.SLCE", /* 570 */ |
3628 | ); /* A21e,G4x,R30,R31,R32,R40,R40e,R50e */ | 3628 | ); /* A21e,G4x,R30,R31,R32,R40,R40e,R50e */ |
3629 | 3629 | ||
3630 | /* don't list other alternatives as we install a notify handler on the 570 */ | 3630 | /* don't list other alternatives as we install a notify handler on the 570 */ |
3631 | TPACPI_HANDLE(pci, root, "\\_SB.PCI"); /* 570 */ | 3631 | TPACPI_HANDLE(pci, root, "\\_SB.PCI"); /* 570 */ |
3632 | 3632 | ||
3633 | static const struct acpi_device_id ibm_pci_device_ids[] = { | 3633 | static const struct acpi_device_id ibm_pci_device_ids[] = { |
3634 | {PCI_ROOT_HID_STRING, 0}, | 3634 | {PCI_ROOT_HID_STRING, 0}, |
3635 | {"", 0}, | 3635 | {"", 0}, |
3636 | }; | 3636 | }; |
3637 | 3637 | ||
3638 | static struct tp_acpi_drv_struct ibm_dock_acpidriver[2] = { | 3638 | static struct tp_acpi_drv_struct ibm_dock_acpidriver[2] = { |
3639 | { | 3639 | { |
3640 | .notify = dock_notify, | 3640 | .notify = dock_notify, |
3641 | .handle = &dock_handle, | 3641 | .handle = &dock_handle, |
3642 | .type = ACPI_SYSTEM_NOTIFY, | 3642 | .type = ACPI_SYSTEM_NOTIFY, |
3643 | }, | 3643 | }, |
3644 | { | 3644 | { |
3645 | /* THIS ONE MUST NEVER BE USED FOR DRIVER AUTOLOADING. | 3645 | /* THIS ONE MUST NEVER BE USED FOR DRIVER AUTOLOADING. |
3646 | * We just use it to get notifications of dock hotplug | 3646 | * We just use it to get notifications of dock hotplug |
3647 | * in very old thinkpads */ | 3647 | * in very old thinkpads */ |
3648 | .hid = ibm_pci_device_ids, | 3648 | .hid = ibm_pci_device_ids, |
3649 | .notify = dock_notify, | 3649 | .notify = dock_notify, |
3650 | .handle = &pci_handle, | 3650 | .handle = &pci_handle, |
3651 | .type = ACPI_SYSTEM_NOTIFY, | 3651 | .type = ACPI_SYSTEM_NOTIFY, |
3652 | }, | 3652 | }, |
3653 | }; | 3653 | }; |
3654 | 3654 | ||
3655 | static struct ibm_struct dock_driver_data[2] = { | 3655 | static struct ibm_struct dock_driver_data[2] = { |
3656 | { | 3656 | { |
3657 | .name = "dock", | 3657 | .name = "dock", |
3658 | .read = dock_read, | 3658 | .read = dock_read, |
3659 | .write = dock_write, | 3659 | .write = dock_write, |
3660 | .acpi = &ibm_dock_acpidriver[0], | 3660 | .acpi = &ibm_dock_acpidriver[0], |
3661 | }, | 3661 | }, |
3662 | { | 3662 | { |
3663 | .name = "dock", | 3663 | .name = "dock", |
3664 | .acpi = &ibm_dock_acpidriver[1], | 3664 | .acpi = &ibm_dock_acpidriver[1], |
3665 | }, | 3665 | }, |
3666 | }; | 3666 | }; |
3667 | 3667 | ||
3668 | #define dock_docked() (_sta(dock_handle) & 1) | 3668 | #define dock_docked() (_sta(dock_handle) & 1) |
3669 | 3669 | ||
3670 | static int __init dock_init(struct ibm_init_struct *iibm) | 3670 | static int __init dock_init(struct ibm_init_struct *iibm) |
3671 | { | 3671 | { |
3672 | vdbg_printk(TPACPI_DBG_INIT, "initializing dock subdriver\n"); | 3672 | vdbg_printk(TPACPI_DBG_INIT, "initializing dock subdriver\n"); |
3673 | 3673 | ||
3674 | TPACPI_ACPIHANDLE_INIT(dock); | 3674 | TPACPI_ACPIHANDLE_INIT(dock); |
3675 | 3675 | ||
3676 | vdbg_printk(TPACPI_DBG_INIT, "dock is %s\n", | 3676 | vdbg_printk(TPACPI_DBG_INIT, "dock is %s\n", |
3677 | str_supported(dock_handle != NULL)); | 3677 | str_supported(dock_handle != NULL)); |
3678 | 3678 | ||
3679 | return (dock_handle)? 0 : 1; | 3679 | return (dock_handle)? 0 : 1; |
3680 | } | 3680 | } |
3681 | 3681 | ||
3682 | static int __init dock_init2(struct ibm_init_struct *iibm) | 3682 | static int __init dock_init2(struct ibm_init_struct *iibm) |
3683 | { | 3683 | { |
3684 | int dock2_needed; | 3684 | int dock2_needed; |
3685 | 3685 | ||
3686 | vdbg_printk(TPACPI_DBG_INIT, "initializing dock subdriver part 2\n"); | 3686 | vdbg_printk(TPACPI_DBG_INIT, "initializing dock subdriver part 2\n"); |
3687 | 3687 | ||
3688 | if (dock_driver_data[0].flags.acpi_driver_registered && | 3688 | if (dock_driver_data[0].flags.acpi_driver_registered && |
3689 | dock_driver_data[0].flags.acpi_notify_installed) { | 3689 | dock_driver_data[0].flags.acpi_notify_installed) { |
3690 | TPACPI_ACPIHANDLE_INIT(pci); | 3690 | TPACPI_ACPIHANDLE_INIT(pci); |
3691 | dock2_needed = (pci_handle != NULL); | 3691 | dock2_needed = (pci_handle != NULL); |
3692 | vdbg_printk(TPACPI_DBG_INIT, | 3692 | vdbg_printk(TPACPI_DBG_INIT, |
3693 | "dock PCI handler for the TP 570 is %s\n", | 3693 | "dock PCI handler for the TP 570 is %s\n", |
3694 | str_supported(dock2_needed)); | 3694 | str_supported(dock2_needed)); |
3695 | } else { | 3695 | } else { |
3696 | vdbg_printk(TPACPI_DBG_INIT, | 3696 | vdbg_printk(TPACPI_DBG_INIT, |
3697 | "dock subdriver part 2 not required\n"); | 3697 | "dock subdriver part 2 not required\n"); |
3698 | dock2_needed = 0; | 3698 | dock2_needed = 0; |
3699 | } | 3699 | } |
3700 | 3700 | ||
3701 | return (dock2_needed)? 0 : 1; | 3701 | return (dock2_needed)? 0 : 1; |
3702 | } | 3702 | } |
3703 | 3703 | ||
3704 | static void dock_notify(struct ibm_struct *ibm, u32 event) | 3704 | static void dock_notify(struct ibm_struct *ibm, u32 event) |
3705 | { | 3705 | { |
3706 | int docked = dock_docked(); | 3706 | int docked = dock_docked(); |
3707 | int pci = ibm->acpi->hid && ibm->acpi->device && | 3707 | int pci = ibm->acpi->hid && ibm->acpi->device && |
3708 | acpi_match_device_ids(ibm->acpi->device, ibm_pci_device_ids); | 3708 | acpi_match_device_ids(ibm->acpi->device, ibm_pci_device_ids); |
3709 | int data; | 3709 | int data; |
3710 | 3710 | ||
3711 | if (event == 1 && !pci) /* 570 */ | 3711 | if (event == 1 && !pci) /* 570 */ |
3712 | data = 1; /* button */ | 3712 | data = 1; /* button */ |
3713 | else if (event == 1 && pci) /* 570 */ | 3713 | else if (event == 1 && pci) /* 570 */ |
3714 | data = 3; /* dock */ | 3714 | data = 3; /* dock */ |
3715 | else if (event == 3 && docked) | 3715 | else if (event == 3 && docked) |
3716 | data = 1; /* button */ | 3716 | data = 1; /* button */ |
3717 | else if (event == 3 && !docked) | 3717 | else if (event == 3 && !docked) |
3718 | data = 2; /* undock */ | 3718 | data = 2; /* undock */ |
3719 | else if (event == 0 && docked) | 3719 | else if (event == 0 && docked) |
3720 | data = 3; /* dock */ | 3720 | data = 3; /* dock */ |
3721 | else { | 3721 | else { |
3722 | printk(TPACPI_ERR "unknown dock event %d, status %d\n", | 3722 | printk(TPACPI_ERR "unknown dock event %d, status %d\n", |
3723 | event, _sta(dock_handle)); | 3723 | event, _sta(dock_handle)); |
3724 | data = 0; /* unknown */ | 3724 | data = 0; /* unknown */ |
3725 | } | 3725 | } |
3726 | acpi_bus_generate_proc_event(ibm->acpi->device, event, data); | 3726 | acpi_bus_generate_proc_event(ibm->acpi->device, event, data); |
3727 | acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class, | 3727 | acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class, |
3728 | ibm->acpi->device->dev.bus_id, | 3728 | ibm->acpi->device->dev.bus_id, |
3729 | event, data); | 3729 | event, data); |
3730 | } | 3730 | } |
3731 | 3731 | ||
3732 | static int dock_read(char *p) | 3732 | static int dock_read(char *p) |
3733 | { | 3733 | { |
3734 | int len = 0; | 3734 | int len = 0; |
3735 | int docked = dock_docked(); | 3735 | int docked = dock_docked(); |
3736 | 3736 | ||
3737 | if (!dock_handle) | 3737 | if (!dock_handle) |
3738 | len += sprintf(p + len, "status:\t\tnot supported\n"); | 3738 | len += sprintf(p + len, "status:\t\tnot supported\n"); |
3739 | else if (!docked) | 3739 | else if (!docked) |
3740 | len += sprintf(p + len, "status:\t\tundocked\n"); | 3740 | len += sprintf(p + len, "status:\t\tundocked\n"); |
3741 | else { | 3741 | else { |
3742 | len += sprintf(p + len, "status:\t\tdocked\n"); | 3742 | len += sprintf(p + len, "status:\t\tdocked\n"); |
3743 | len += sprintf(p + len, "commands:\tdock, undock\n"); | 3743 | len += sprintf(p + len, "commands:\tdock, undock\n"); |
3744 | } | 3744 | } |
3745 | 3745 | ||
3746 | return len; | 3746 | return len; |
3747 | } | 3747 | } |
3748 | 3748 | ||
3749 | static int dock_write(char *buf) | 3749 | static int dock_write(char *buf) |
3750 | { | 3750 | { |
3751 | char *cmd; | 3751 | char *cmd; |
3752 | 3752 | ||
3753 | if (!dock_docked()) | 3753 | if (!dock_docked()) |
3754 | return -ENODEV; | 3754 | return -ENODEV; |
3755 | 3755 | ||
3756 | while ((cmd = next_cmd(&buf))) { | 3756 | while ((cmd = next_cmd(&buf))) { |
3757 | if (strlencmp(cmd, "undock") == 0) { | 3757 | if (strlencmp(cmd, "undock") == 0) { |
3758 | if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 0) || | 3758 | if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 0) || |
3759 | !acpi_evalf(dock_handle, NULL, "_EJ0", "vd", 1)) | 3759 | !acpi_evalf(dock_handle, NULL, "_EJ0", "vd", 1)) |
3760 | return -EIO; | 3760 | return -EIO; |
3761 | } else if (strlencmp(cmd, "dock") == 0) { | 3761 | } else if (strlencmp(cmd, "dock") == 0) { |
3762 | if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 1)) | 3762 | if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 1)) |
3763 | return -EIO; | 3763 | return -EIO; |
3764 | } else | 3764 | } else |
3765 | return -EINVAL; | 3765 | return -EINVAL; |
3766 | } | 3766 | } |
3767 | 3767 | ||
3768 | return 0; | 3768 | return 0; |
3769 | } | 3769 | } |
3770 | 3770 | ||
3771 | #endif /* CONFIG_THINKPAD_ACPI_DOCK */ | 3771 | #endif /* CONFIG_THINKPAD_ACPI_DOCK */ |
3772 | 3772 | ||
3773 | /************************************************************************* | 3773 | /************************************************************************* |
3774 | * Bay subdriver | 3774 | * Bay subdriver |
3775 | */ | 3775 | */ |
3776 | 3776 | ||
3777 | #ifdef CONFIG_THINKPAD_ACPI_BAY | 3777 | #ifdef CONFIG_THINKPAD_ACPI_BAY |
3778 | 3778 | ||
3779 | TPACPI_HANDLE(bay, root, "\\_SB.PCI.IDE.SECN.MAST", /* 570 */ | 3779 | TPACPI_HANDLE(bay, root, "\\_SB.PCI.IDE.SECN.MAST", /* 570 */ |
3780 | "\\_SB.PCI0.IDE0.IDES.IDSM", /* 600e/x, 770e, 770x */ | 3780 | "\\_SB.PCI0.IDE0.IDES.IDSM", /* 600e/x, 770e, 770x */ |
3781 | "\\_SB.PCI0.SATA.SCND.MSTR", /* T60, X60, Z60 */ | 3781 | "\\_SB.PCI0.SATA.SCND.MSTR", /* T60, X60, Z60 */ |
3782 | "\\_SB.PCI0.IDE0.SCND.MSTR", /* all others */ | 3782 | "\\_SB.PCI0.IDE0.SCND.MSTR", /* all others */ |
3783 | ); /* A21e, R30, R31 */ | 3783 | ); /* A21e, R30, R31 */ |
3784 | TPACPI_HANDLE(bay_ej, bay, "_EJ3", /* 600e/x, A2xm/p, A3x */ | 3784 | TPACPI_HANDLE(bay_ej, bay, "_EJ3", /* 600e/x, A2xm/p, A3x */ |
3785 | "_EJ0", /* all others */ | 3785 | "_EJ0", /* all others */ |
3786 | ); /* 570,A21e,G4x,R30,R31,R32,R40e,R50e */ | 3786 | ); /* 570,A21e,G4x,R30,R31,R32,R40e,R50e */ |
3787 | TPACPI_HANDLE(bay2, root, "\\_SB.PCI0.IDE0.PRIM.SLAV", /* A3x, R32 */ | 3787 | TPACPI_HANDLE(bay2, root, "\\_SB.PCI0.IDE0.PRIM.SLAV", /* A3x, R32 */ |
3788 | "\\_SB.PCI0.IDE0.IDEP.IDPS", /* 600e/x, 770e, 770x */ | 3788 | "\\_SB.PCI0.IDE0.IDEP.IDPS", /* 600e/x, 770e, 770x */ |
3789 | ); /* all others */ | 3789 | ); /* all others */ |
3790 | TPACPI_HANDLE(bay2_ej, bay2, "_EJ3", /* 600e/x, 770e, A3x */ | 3790 | TPACPI_HANDLE(bay2_ej, bay2, "_EJ3", /* 600e/x, 770e, A3x */ |
3791 | "_EJ0", /* 770x */ | 3791 | "_EJ0", /* 770x */ |
3792 | ); /* all others */ | 3792 | ); /* all others */ |
3793 | 3793 | ||
3794 | static int __init bay_init(struct ibm_init_struct *iibm) | 3794 | static int __init bay_init(struct ibm_init_struct *iibm) |
3795 | { | 3795 | { |
3796 | vdbg_printk(TPACPI_DBG_INIT, "initializing bay subdriver\n"); | 3796 | vdbg_printk(TPACPI_DBG_INIT, "initializing bay subdriver\n"); |
3797 | 3797 | ||
3798 | TPACPI_ACPIHANDLE_INIT(bay); | 3798 | TPACPI_ACPIHANDLE_INIT(bay); |
3799 | if (bay_handle) | 3799 | if (bay_handle) |
3800 | TPACPI_ACPIHANDLE_INIT(bay_ej); | 3800 | TPACPI_ACPIHANDLE_INIT(bay_ej); |
3801 | TPACPI_ACPIHANDLE_INIT(bay2); | 3801 | TPACPI_ACPIHANDLE_INIT(bay2); |
3802 | if (bay2_handle) | 3802 | if (bay2_handle) |
3803 | TPACPI_ACPIHANDLE_INIT(bay2_ej); | 3803 | TPACPI_ACPIHANDLE_INIT(bay2_ej); |
3804 | 3804 | ||
3805 | tp_features.bay_status = bay_handle && | 3805 | tp_features.bay_status = bay_handle && |
3806 | acpi_evalf(bay_handle, NULL, "_STA", "qv"); | 3806 | acpi_evalf(bay_handle, NULL, "_STA", "qv"); |
3807 | tp_features.bay_status2 = bay2_handle && | 3807 | tp_features.bay_status2 = bay2_handle && |
3808 | acpi_evalf(bay2_handle, NULL, "_STA", "qv"); | 3808 | acpi_evalf(bay2_handle, NULL, "_STA", "qv"); |
3809 | 3809 | ||
3810 | tp_features.bay_eject = bay_handle && bay_ej_handle && | 3810 | tp_features.bay_eject = bay_handle && bay_ej_handle && |
3811 | (strlencmp(bay_ej_path, "_EJ0") == 0 || experimental); | 3811 | (strlencmp(bay_ej_path, "_EJ0") == 0 || experimental); |
3812 | tp_features.bay_eject2 = bay2_handle && bay2_ej_handle && | 3812 | tp_features.bay_eject2 = bay2_handle && bay2_ej_handle && |
3813 | (strlencmp(bay2_ej_path, "_EJ0") == 0 || experimental); | 3813 | (strlencmp(bay2_ej_path, "_EJ0") == 0 || experimental); |
3814 | 3814 | ||
3815 | vdbg_printk(TPACPI_DBG_INIT, | 3815 | vdbg_printk(TPACPI_DBG_INIT, |
3816 | "bay 1: status %s, eject %s; bay 2: status %s, eject %s\n", | 3816 | "bay 1: status %s, eject %s; bay 2: status %s, eject %s\n", |
3817 | str_supported(tp_features.bay_status), | 3817 | str_supported(tp_features.bay_status), |
3818 | str_supported(tp_features.bay_eject), | 3818 | str_supported(tp_features.bay_eject), |
3819 | str_supported(tp_features.bay_status2), | 3819 | str_supported(tp_features.bay_status2), |
3820 | str_supported(tp_features.bay_eject2)); | 3820 | str_supported(tp_features.bay_eject2)); |
3821 | 3821 | ||
3822 | return (tp_features.bay_status || tp_features.bay_eject || | 3822 | return (tp_features.bay_status || tp_features.bay_eject || |
3823 | tp_features.bay_status2 || tp_features.bay_eject2)? 0 : 1; | 3823 | tp_features.bay_status2 || tp_features.bay_eject2)? 0 : 1; |
3824 | } | 3824 | } |
3825 | 3825 | ||
3826 | static void bay_notify(struct ibm_struct *ibm, u32 event) | 3826 | static void bay_notify(struct ibm_struct *ibm, u32 event) |
3827 | { | 3827 | { |
3828 | acpi_bus_generate_proc_event(ibm->acpi->device, event, 0); | 3828 | acpi_bus_generate_proc_event(ibm->acpi->device, event, 0); |
3829 | acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class, | 3829 | acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class, |
3830 | ibm->acpi->device->dev.bus_id, | 3830 | ibm->acpi->device->dev.bus_id, |
3831 | event, 0); | 3831 | event, 0); |
3832 | } | 3832 | } |
3833 | 3833 | ||
3834 | #define bay_occupied(b) (_sta(b##_handle) & 1) | 3834 | #define bay_occupied(b) (_sta(b##_handle) & 1) |
3835 | 3835 | ||
3836 | static int bay_read(char *p) | 3836 | static int bay_read(char *p) |
3837 | { | 3837 | { |
3838 | int len = 0; | 3838 | int len = 0; |
3839 | int occupied = bay_occupied(bay); | 3839 | int occupied = bay_occupied(bay); |
3840 | int occupied2 = bay_occupied(bay2); | 3840 | int occupied2 = bay_occupied(bay2); |
3841 | int eject, eject2; | 3841 | int eject, eject2; |
3842 | 3842 | ||
3843 | len += sprintf(p + len, "status:\t\t%s\n", | 3843 | len += sprintf(p + len, "status:\t\t%s\n", |
3844 | tp_features.bay_status ? | 3844 | tp_features.bay_status ? |
3845 | (occupied ? "occupied" : "unoccupied") : | 3845 | (occupied ? "occupied" : "unoccupied") : |
3846 | "not supported"); | 3846 | "not supported"); |
3847 | if (tp_features.bay_status2) | 3847 | if (tp_features.bay_status2) |
3848 | len += sprintf(p + len, "status2:\t%s\n", occupied2 ? | 3848 | len += sprintf(p + len, "status2:\t%s\n", occupied2 ? |
3849 | "occupied" : "unoccupied"); | 3849 | "occupied" : "unoccupied"); |
3850 | 3850 | ||
3851 | eject = tp_features.bay_eject && occupied; | 3851 | eject = tp_features.bay_eject && occupied; |
3852 | eject2 = tp_features.bay_eject2 && occupied2; | 3852 | eject2 = tp_features.bay_eject2 && occupied2; |
3853 | 3853 | ||
3854 | if (eject && eject2) | 3854 | if (eject && eject2) |
3855 | len += sprintf(p + len, "commands:\teject, eject2\n"); | 3855 | len += sprintf(p + len, "commands:\teject, eject2\n"); |
3856 | else if (eject) | 3856 | else if (eject) |
3857 | len += sprintf(p + len, "commands:\teject\n"); | 3857 | len += sprintf(p + len, "commands:\teject\n"); |
3858 | else if (eject2) | 3858 | else if (eject2) |
3859 | len += sprintf(p + len, "commands:\teject2\n"); | 3859 | len += sprintf(p + len, "commands:\teject2\n"); |
3860 | 3860 | ||
3861 | return len; | 3861 | return len; |
3862 | } | 3862 | } |
3863 | 3863 | ||
3864 | static int bay_write(char *buf) | 3864 | static int bay_write(char *buf) |
3865 | { | 3865 | { |
3866 | char *cmd; | 3866 | char *cmd; |
3867 | 3867 | ||
3868 | if (!tp_features.bay_eject && !tp_features.bay_eject2) | 3868 | if (!tp_features.bay_eject && !tp_features.bay_eject2) |
3869 | return -ENODEV; | 3869 | return -ENODEV; |
3870 | 3870 | ||
3871 | while ((cmd = next_cmd(&buf))) { | 3871 | while ((cmd = next_cmd(&buf))) { |
3872 | if (tp_features.bay_eject && strlencmp(cmd, "eject") == 0) { | 3872 | if (tp_features.bay_eject && strlencmp(cmd, "eject") == 0) { |
3873 | if (!acpi_evalf(bay_ej_handle, NULL, NULL, "vd", 1)) | 3873 | if (!acpi_evalf(bay_ej_handle, NULL, NULL, "vd", 1)) |
3874 | return -EIO; | 3874 | return -EIO; |
3875 | } else if (tp_features.bay_eject2 && | 3875 | } else if (tp_features.bay_eject2 && |
3876 | strlencmp(cmd, "eject2") == 0) { | 3876 | strlencmp(cmd, "eject2") == 0) { |
3877 | if (!acpi_evalf(bay2_ej_handle, NULL, NULL, "vd", 1)) | 3877 | if (!acpi_evalf(bay2_ej_handle, NULL, NULL, "vd", 1)) |
3878 | return -EIO; | 3878 | return -EIO; |
3879 | } else | 3879 | } else |
3880 | return -EINVAL; | 3880 | return -EINVAL; |
3881 | } | 3881 | } |
3882 | 3882 | ||
3883 | return 0; | 3883 | return 0; |
3884 | } | 3884 | } |
3885 | 3885 | ||
3886 | static struct tp_acpi_drv_struct ibm_bay_acpidriver = { | 3886 | static struct tp_acpi_drv_struct ibm_bay_acpidriver = { |
3887 | .notify = bay_notify, | 3887 | .notify = bay_notify, |
3888 | .handle = &bay_handle, | 3888 | .handle = &bay_handle, |
3889 | .type = ACPI_SYSTEM_NOTIFY, | 3889 | .type = ACPI_SYSTEM_NOTIFY, |
3890 | }; | 3890 | }; |
3891 | 3891 | ||
3892 | static struct ibm_struct bay_driver_data = { | 3892 | static struct ibm_struct bay_driver_data = { |
3893 | .name = "bay", | 3893 | .name = "bay", |
3894 | .read = bay_read, | 3894 | .read = bay_read, |
3895 | .write = bay_write, | 3895 | .write = bay_write, |
3896 | .acpi = &ibm_bay_acpidriver, | 3896 | .acpi = &ibm_bay_acpidriver, |
3897 | }; | 3897 | }; |
3898 | 3898 | ||
3899 | #endif /* CONFIG_THINKPAD_ACPI_BAY */ | 3899 | #endif /* CONFIG_THINKPAD_ACPI_BAY */ |
3900 | 3900 | ||
3901 | /************************************************************************* | 3901 | /************************************************************************* |
3902 | * CMOS subdriver | 3902 | * CMOS subdriver |
3903 | */ | 3903 | */ |
3904 | 3904 | ||
3905 | /* sysfs cmos_command -------------------------------------------------- */ | 3905 | /* sysfs cmos_command -------------------------------------------------- */ |
3906 | static ssize_t cmos_command_store(struct device *dev, | 3906 | static ssize_t cmos_command_store(struct device *dev, |
3907 | struct device_attribute *attr, | 3907 | struct device_attribute *attr, |
3908 | const char *buf, size_t count) | 3908 | const char *buf, size_t count) |
3909 | { | 3909 | { |
3910 | unsigned long cmos_cmd; | 3910 | unsigned long cmos_cmd; |
3911 | int res; | 3911 | int res; |
3912 | 3912 | ||
3913 | if (parse_strtoul(buf, 21, &cmos_cmd)) | 3913 | if (parse_strtoul(buf, 21, &cmos_cmd)) |
3914 | return -EINVAL; | 3914 | return -EINVAL; |
3915 | 3915 | ||
3916 | res = issue_thinkpad_cmos_command(cmos_cmd); | 3916 | res = issue_thinkpad_cmos_command(cmos_cmd); |
3917 | return (res)? res : count; | 3917 | return (res)? res : count; |
3918 | } | 3918 | } |
3919 | 3919 | ||
3920 | static struct device_attribute dev_attr_cmos_command = | 3920 | static struct device_attribute dev_attr_cmos_command = |
3921 | __ATTR(cmos_command, S_IWUSR, NULL, cmos_command_store); | 3921 | __ATTR(cmos_command, S_IWUSR, NULL, cmos_command_store); |
3922 | 3922 | ||
3923 | /* --------------------------------------------------------------------- */ | 3923 | /* --------------------------------------------------------------------- */ |
3924 | 3924 | ||
3925 | static int __init cmos_init(struct ibm_init_struct *iibm) | 3925 | static int __init cmos_init(struct ibm_init_struct *iibm) |
3926 | { | 3926 | { |
3927 | int res; | 3927 | int res; |
3928 | 3928 | ||
3929 | vdbg_printk(TPACPI_DBG_INIT, | 3929 | vdbg_printk(TPACPI_DBG_INIT, |
3930 | "initializing cmos commands subdriver\n"); | 3930 | "initializing cmos commands subdriver\n"); |
3931 | 3931 | ||
3932 | TPACPI_ACPIHANDLE_INIT(cmos); | 3932 | TPACPI_ACPIHANDLE_INIT(cmos); |
3933 | 3933 | ||
3934 | vdbg_printk(TPACPI_DBG_INIT, "cmos commands are %s\n", | 3934 | vdbg_printk(TPACPI_DBG_INIT, "cmos commands are %s\n", |
3935 | str_supported(cmos_handle != NULL)); | 3935 | str_supported(cmos_handle != NULL)); |
3936 | 3936 | ||
3937 | res = device_create_file(&tpacpi_pdev->dev, &dev_attr_cmos_command); | 3937 | res = device_create_file(&tpacpi_pdev->dev, &dev_attr_cmos_command); |
3938 | if (res) | 3938 | if (res) |
3939 | return res; | 3939 | return res; |
3940 | 3940 | ||
3941 | return (cmos_handle)? 0 : 1; | 3941 | return (cmos_handle)? 0 : 1; |
3942 | } | 3942 | } |
3943 | 3943 | ||
3944 | static void cmos_exit(void) | 3944 | static void cmos_exit(void) |
3945 | { | 3945 | { |
3946 | device_remove_file(&tpacpi_pdev->dev, &dev_attr_cmos_command); | 3946 | device_remove_file(&tpacpi_pdev->dev, &dev_attr_cmos_command); |
3947 | } | 3947 | } |
3948 | 3948 | ||
3949 | static int cmos_read(char *p) | 3949 | static int cmos_read(char *p) |
3950 | { | 3950 | { |
3951 | int len = 0; | 3951 | int len = 0; |
3952 | 3952 | ||
3953 | /* cmos not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, | 3953 | /* cmos not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, |
3954 | R30, R31, T20-22, X20-21 */ | 3954 | R30, R31, T20-22, X20-21 */ |
3955 | if (!cmos_handle) | 3955 | if (!cmos_handle) |
3956 | len += sprintf(p + len, "status:\t\tnot supported\n"); | 3956 | len += sprintf(p + len, "status:\t\tnot supported\n"); |
3957 | else { | 3957 | else { |
3958 | len += sprintf(p + len, "status:\t\tsupported\n"); | 3958 | len += sprintf(p + len, "status:\t\tsupported\n"); |
3959 | len += sprintf(p + len, "commands:\t<cmd> (<cmd> is 0-21)\n"); | 3959 | len += sprintf(p + len, "commands:\t<cmd> (<cmd> is 0-21)\n"); |
3960 | } | 3960 | } |
3961 | 3961 | ||
3962 | return len; | 3962 | return len; |
3963 | } | 3963 | } |
3964 | 3964 | ||
3965 | static int cmos_write(char *buf) | 3965 | static int cmos_write(char *buf) |
3966 | { | 3966 | { |
3967 | char *cmd; | 3967 | char *cmd; |
3968 | int cmos_cmd, res; | 3968 | int cmos_cmd, res; |
3969 | 3969 | ||
3970 | while ((cmd = next_cmd(&buf))) { | 3970 | while ((cmd = next_cmd(&buf))) { |
3971 | if (sscanf(cmd, "%u", &cmos_cmd) == 1 && | 3971 | if (sscanf(cmd, "%u", &cmos_cmd) == 1 && |
3972 | cmos_cmd >= 0 && cmos_cmd <= 21) { | 3972 | cmos_cmd >= 0 && cmos_cmd <= 21) { |
3973 | /* cmos_cmd set */ | 3973 | /* cmos_cmd set */ |
3974 | } else | 3974 | } else |
3975 | return -EINVAL; | 3975 | return -EINVAL; |
3976 | 3976 | ||
3977 | res = issue_thinkpad_cmos_command(cmos_cmd); | 3977 | res = issue_thinkpad_cmos_command(cmos_cmd); |
3978 | if (res) | 3978 | if (res) |
3979 | return res; | 3979 | return res; |
3980 | } | 3980 | } |
3981 | 3981 | ||
3982 | return 0; | 3982 | return 0; |
3983 | } | 3983 | } |
3984 | 3984 | ||
3985 | static struct ibm_struct cmos_driver_data = { | 3985 | static struct ibm_struct cmos_driver_data = { |
3986 | .name = "cmos", | 3986 | .name = "cmos", |
3987 | .read = cmos_read, | 3987 | .read = cmos_read, |
3988 | .write = cmos_write, | 3988 | .write = cmos_write, |
3989 | .exit = cmos_exit, | 3989 | .exit = cmos_exit, |
3990 | }; | 3990 | }; |
3991 | 3991 | ||
3992 | /************************************************************************* | 3992 | /************************************************************************* |
3993 | * LED subdriver | 3993 | * LED subdriver |
3994 | */ | 3994 | */ |
3995 | 3995 | ||
3996 | enum led_access_mode { | 3996 | enum led_access_mode { |
3997 | TPACPI_LED_NONE = 0, | 3997 | TPACPI_LED_NONE = 0, |
3998 | TPACPI_LED_570, /* 570 */ | 3998 | TPACPI_LED_570, /* 570 */ |
3999 | TPACPI_LED_OLD, /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */ | 3999 | TPACPI_LED_OLD, /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */ |
4000 | TPACPI_LED_NEW, /* all others */ | 4000 | TPACPI_LED_NEW, /* all others */ |
4001 | }; | 4001 | }; |
4002 | 4002 | ||
4003 | enum { /* For TPACPI_LED_OLD */ | 4003 | enum { /* For TPACPI_LED_OLD */ |
4004 | TPACPI_LED_EC_HLCL = 0x0c, /* EC reg to get led to power on */ | 4004 | TPACPI_LED_EC_HLCL = 0x0c, /* EC reg to get led to power on */ |
4005 | TPACPI_LED_EC_HLBL = 0x0d, /* EC reg to blink a lit led */ | 4005 | TPACPI_LED_EC_HLBL = 0x0d, /* EC reg to blink a lit led */ |
4006 | TPACPI_LED_EC_HLMS = 0x0e, /* EC reg to select led to command */ | 4006 | TPACPI_LED_EC_HLMS = 0x0e, /* EC reg to select led to command */ |
4007 | }; | 4007 | }; |
4008 | 4008 | ||
4009 | enum led_status_t { | 4009 | enum led_status_t { |
4010 | TPACPI_LED_OFF = 0, | 4010 | TPACPI_LED_OFF = 0, |
4011 | TPACPI_LED_ON, | 4011 | TPACPI_LED_ON, |
4012 | TPACPI_LED_BLINK, | 4012 | TPACPI_LED_BLINK, |
4013 | }; | 4013 | }; |
4014 | 4014 | ||
4015 | static enum led_access_mode led_supported; | 4015 | static enum led_access_mode led_supported; |
4016 | 4016 | ||
4017 | TPACPI_HANDLE(led, ec, "SLED", /* 570 */ | 4017 | TPACPI_HANDLE(led, ec, "SLED", /* 570 */ |
4018 | "SYSL", /* 600e/x, 770e, 770x, A21e, A2xm/p, */ | 4018 | "SYSL", /* 600e/x, 770e, 770x, A21e, A2xm/p, */ |
4019 | /* T20-22, X20-21 */ | 4019 | /* T20-22, X20-21 */ |
4020 | "LED", /* all others */ | 4020 | "LED", /* all others */ |
4021 | ); /* R30, R31 */ | 4021 | ); /* R30, R31 */ |
4022 | 4022 | ||
4023 | #define TPACPI_LED_NUMLEDS 8 | 4023 | #define TPACPI_LED_NUMLEDS 8 |
4024 | static struct tpacpi_led_classdev *tpacpi_leds; | 4024 | static struct tpacpi_led_classdev *tpacpi_leds; |
4025 | static enum led_status_t tpacpi_led_state_cache[TPACPI_LED_NUMLEDS]; | 4025 | static enum led_status_t tpacpi_led_state_cache[TPACPI_LED_NUMLEDS]; |
4026 | static const char * const tpacpi_led_names[TPACPI_LED_NUMLEDS] = { | 4026 | static const char * const tpacpi_led_names[TPACPI_LED_NUMLEDS] = { |
4027 | /* there's a limit of 19 chars + NULL before 2.6.26 */ | 4027 | /* there's a limit of 19 chars + NULL before 2.6.26 */ |
4028 | "tpacpi::power", | 4028 | "tpacpi::power", |
4029 | "tpacpi:orange:batt", | 4029 | "tpacpi:orange:batt", |
4030 | "tpacpi:green:batt", | 4030 | "tpacpi:green:batt", |
4031 | "tpacpi::dock_active", | 4031 | "tpacpi::dock_active", |
4032 | "tpacpi::bay_active", | 4032 | "tpacpi::bay_active", |
4033 | "tpacpi::dock_batt", | 4033 | "tpacpi::dock_batt", |
4034 | "tpacpi::unknown_led", | 4034 | "tpacpi::unknown_led", |
4035 | "tpacpi::standby", | 4035 | "tpacpi::standby", |
4036 | }; | 4036 | }; |
4037 | 4037 | ||
4038 | static int led_get_status(const unsigned int led) | 4038 | static int led_get_status(const unsigned int led) |
4039 | { | 4039 | { |
4040 | int status; | 4040 | int status; |
4041 | enum led_status_t led_s; | 4041 | enum led_status_t led_s; |
4042 | 4042 | ||
4043 | switch (led_supported) { | 4043 | switch (led_supported) { |
4044 | case TPACPI_LED_570: | 4044 | case TPACPI_LED_570: |
4045 | if (!acpi_evalf(ec_handle, | 4045 | if (!acpi_evalf(ec_handle, |
4046 | &status, "GLED", "dd", 1 << led)) | 4046 | &status, "GLED", "dd", 1 << led)) |
4047 | return -EIO; | 4047 | return -EIO; |
4048 | led_s = (status == 0)? | 4048 | led_s = (status == 0)? |
4049 | TPACPI_LED_OFF : | 4049 | TPACPI_LED_OFF : |
4050 | ((status == 1)? | 4050 | ((status == 1)? |
4051 | TPACPI_LED_ON : | 4051 | TPACPI_LED_ON : |
4052 | TPACPI_LED_BLINK); | 4052 | TPACPI_LED_BLINK); |
4053 | tpacpi_led_state_cache[led] = led_s; | 4053 | tpacpi_led_state_cache[led] = led_s; |
4054 | return led_s; | 4054 | return led_s; |
4055 | default: | 4055 | default: |
4056 | return -ENXIO; | 4056 | return -ENXIO; |
4057 | } | 4057 | } |
4058 | 4058 | ||
4059 | /* not reached */ | 4059 | /* not reached */ |
4060 | } | 4060 | } |
4061 | 4061 | ||
4062 | static int led_set_status(const unsigned int led, | 4062 | static int led_set_status(const unsigned int led, |
4063 | const enum led_status_t ledstatus) | 4063 | const enum led_status_t ledstatus) |
4064 | { | 4064 | { |
4065 | /* off, on, blink. Index is led_status_t */ | 4065 | /* off, on, blink. Index is led_status_t */ |
4066 | static const unsigned int led_sled_arg1[] = { 0, 1, 3 }; | 4066 | static const unsigned int led_sled_arg1[] = { 0, 1, 3 }; |
4067 | static const unsigned int led_led_arg1[] = { 0, 0x80, 0xc0 }; | 4067 | static const unsigned int led_led_arg1[] = { 0, 0x80, 0xc0 }; |
4068 | 4068 | ||
4069 | int rc = 0; | 4069 | int rc = 0; |
4070 | 4070 | ||
4071 | switch (led_supported) { | 4071 | switch (led_supported) { |
4072 | case TPACPI_LED_570: | 4072 | case TPACPI_LED_570: |
4073 | /* 570 */ | 4073 | /* 570 */ |
4074 | if (led > 7) | 4074 | if (led > 7) |
4075 | return -EINVAL; | 4075 | return -EINVAL; |
4076 | if (!acpi_evalf(led_handle, NULL, NULL, "vdd", | 4076 | if (!acpi_evalf(led_handle, NULL, NULL, "vdd", |
4077 | (1 << led), led_sled_arg1[ledstatus])) | 4077 | (1 << led), led_sled_arg1[ledstatus])) |
4078 | rc = -EIO; | 4078 | rc = -EIO; |
4079 | break; | 4079 | break; |
4080 | case TPACPI_LED_OLD: | 4080 | case TPACPI_LED_OLD: |
4081 | /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */ | 4081 | /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */ |
4082 | if (led > 7) | 4082 | if (led > 7) |
4083 | return -EINVAL; | 4083 | return -EINVAL; |
4084 | rc = ec_write(TPACPI_LED_EC_HLMS, (1 << led)); | 4084 | rc = ec_write(TPACPI_LED_EC_HLMS, (1 << led)); |
4085 | if (rc >= 0) | 4085 | if (rc >= 0) |
4086 | rc = ec_write(TPACPI_LED_EC_HLBL, | 4086 | rc = ec_write(TPACPI_LED_EC_HLBL, |
4087 | (ledstatus == TPACPI_LED_BLINK) << led); | 4087 | (ledstatus == TPACPI_LED_BLINK) << led); |
4088 | if (rc >= 0) | 4088 | if (rc >= 0) |
4089 | rc = ec_write(TPACPI_LED_EC_HLCL, | 4089 | rc = ec_write(TPACPI_LED_EC_HLCL, |
4090 | (ledstatus != TPACPI_LED_OFF) << led); | 4090 | (ledstatus != TPACPI_LED_OFF) << led); |
4091 | break; | 4091 | break; |
4092 | case TPACPI_LED_NEW: | 4092 | case TPACPI_LED_NEW: |
4093 | /* all others */ | 4093 | /* all others */ |
4094 | if (!acpi_evalf(led_handle, NULL, NULL, "vdd", | 4094 | if (!acpi_evalf(led_handle, NULL, NULL, "vdd", |
4095 | led, led_led_arg1[ledstatus])) | 4095 | led, led_led_arg1[ledstatus])) |
4096 | rc = -EIO; | 4096 | rc = -EIO; |
4097 | break; | 4097 | break; |
4098 | default: | 4098 | default: |
4099 | rc = -ENXIO; | 4099 | rc = -ENXIO; |
4100 | } | 4100 | } |
4101 | 4101 | ||
4102 | if (!rc) | 4102 | if (!rc) |
4103 | tpacpi_led_state_cache[led] = ledstatus; | 4103 | tpacpi_led_state_cache[led] = ledstatus; |
4104 | 4104 | ||
4105 | return rc; | 4105 | return rc; |
4106 | } | 4106 | } |
4107 | 4107 | ||
4108 | static void led_sysfs_set_status(unsigned int led, | 4108 | static void led_sysfs_set_status(unsigned int led, |
4109 | enum led_brightness brightness) | 4109 | enum led_brightness brightness) |
4110 | { | 4110 | { |
4111 | led_set_status(led, | 4111 | led_set_status(led, |
4112 | (brightness == LED_OFF) ? | 4112 | (brightness == LED_OFF) ? |
4113 | TPACPI_LED_OFF : | 4113 | TPACPI_LED_OFF : |
4114 | (tpacpi_led_state_cache[led] == TPACPI_LED_BLINK) ? | 4114 | (tpacpi_led_state_cache[led] == TPACPI_LED_BLINK) ? |
4115 | TPACPI_LED_BLINK : TPACPI_LED_ON); | 4115 | TPACPI_LED_BLINK : TPACPI_LED_ON); |
4116 | } | 4116 | } |
4117 | 4117 | ||
4118 | static void led_set_status_worker(struct work_struct *work) | 4118 | static void led_set_status_worker(struct work_struct *work) |
4119 | { | 4119 | { |
4120 | struct tpacpi_led_classdev *data = | 4120 | struct tpacpi_led_classdev *data = |
4121 | container_of(work, struct tpacpi_led_classdev, work); | 4121 | container_of(work, struct tpacpi_led_classdev, work); |
4122 | 4122 | ||
4123 | if (likely(tpacpi_lifecycle == TPACPI_LIFE_RUNNING)) | 4123 | if (likely(tpacpi_lifecycle == TPACPI_LIFE_RUNNING)) |
4124 | led_sysfs_set_status(data->led, data->new_brightness); | 4124 | led_sysfs_set_status(data->led, data->new_brightness); |
4125 | } | 4125 | } |
4126 | 4126 | ||
4127 | static void led_sysfs_set(struct led_classdev *led_cdev, | 4127 | static void led_sysfs_set(struct led_classdev *led_cdev, |
4128 | enum led_brightness brightness) | 4128 | enum led_brightness brightness) |
4129 | { | 4129 | { |
4130 | struct tpacpi_led_classdev *data = container_of(led_cdev, | 4130 | struct tpacpi_led_classdev *data = container_of(led_cdev, |
4131 | struct tpacpi_led_classdev, led_classdev); | 4131 | struct tpacpi_led_classdev, led_classdev); |
4132 | 4132 | ||
4133 | data->new_brightness = brightness; | 4133 | data->new_brightness = brightness; |
4134 | queue_work(tpacpi_wq, &data->work); | 4134 | queue_work(tpacpi_wq, &data->work); |
4135 | } | 4135 | } |
4136 | 4136 | ||
4137 | static int led_sysfs_blink_set(struct led_classdev *led_cdev, | 4137 | static int led_sysfs_blink_set(struct led_classdev *led_cdev, |
4138 | unsigned long *delay_on, unsigned long *delay_off) | 4138 | unsigned long *delay_on, unsigned long *delay_off) |
4139 | { | 4139 | { |
4140 | struct tpacpi_led_classdev *data = container_of(led_cdev, | 4140 | struct tpacpi_led_classdev *data = container_of(led_cdev, |
4141 | struct tpacpi_led_classdev, led_classdev); | 4141 | struct tpacpi_led_classdev, led_classdev); |
4142 | 4142 | ||
4143 | /* Can we choose the flash rate? */ | 4143 | /* Can we choose the flash rate? */ |
4144 | if (*delay_on == 0 && *delay_off == 0) { | 4144 | if (*delay_on == 0 && *delay_off == 0) { |
4145 | /* yes. set them to the hardware blink rate (1 Hz) */ | 4145 | /* yes. set them to the hardware blink rate (1 Hz) */ |
4146 | *delay_on = 500; /* ms */ | 4146 | *delay_on = 500; /* ms */ |
4147 | *delay_off = 500; /* ms */ | 4147 | *delay_off = 500; /* ms */ |
4148 | } else if ((*delay_on != 500) || (*delay_off != 500)) | 4148 | } else if ((*delay_on != 500) || (*delay_off != 500)) |
4149 | return -EINVAL; | 4149 | return -EINVAL; |
4150 | 4150 | ||
4151 | data->new_brightness = TPACPI_LED_BLINK; | 4151 | data->new_brightness = TPACPI_LED_BLINK; |
4152 | queue_work(tpacpi_wq, &data->work); | 4152 | queue_work(tpacpi_wq, &data->work); |
4153 | 4153 | ||
4154 | return 0; | 4154 | return 0; |
4155 | } | 4155 | } |
4156 | 4156 | ||
4157 | static enum led_brightness led_sysfs_get(struct led_classdev *led_cdev) | 4157 | static enum led_brightness led_sysfs_get(struct led_classdev *led_cdev) |
4158 | { | 4158 | { |
4159 | int rc; | 4159 | int rc; |
4160 | 4160 | ||
4161 | struct tpacpi_led_classdev *data = container_of(led_cdev, | 4161 | struct tpacpi_led_classdev *data = container_of(led_cdev, |
4162 | struct tpacpi_led_classdev, led_classdev); | 4162 | struct tpacpi_led_classdev, led_classdev); |
4163 | 4163 | ||
4164 | rc = led_get_status(data->led); | 4164 | rc = led_get_status(data->led); |
4165 | 4165 | ||
4166 | if (rc == TPACPI_LED_OFF || rc < 0) | 4166 | if (rc == TPACPI_LED_OFF || rc < 0) |
4167 | rc = LED_OFF; /* no error handling in led class :( */ | 4167 | rc = LED_OFF; /* no error handling in led class :( */ |
4168 | else | 4168 | else |
4169 | rc = LED_FULL; | 4169 | rc = LED_FULL; |
4170 | 4170 | ||
4171 | return rc; | 4171 | return rc; |
4172 | } | 4172 | } |
4173 | 4173 | ||
4174 | static void led_exit(void) | 4174 | static void led_exit(void) |
4175 | { | 4175 | { |
4176 | unsigned int i; | 4176 | unsigned int i; |
4177 | 4177 | ||
4178 | for (i = 0; i < TPACPI_LED_NUMLEDS; i++) { | 4178 | for (i = 0; i < TPACPI_LED_NUMLEDS; i++) { |
4179 | if (tpacpi_leds[i].led_classdev.name) | 4179 | if (tpacpi_leds[i].led_classdev.name) |
4180 | led_classdev_unregister(&tpacpi_leds[i].led_classdev); | 4180 | led_classdev_unregister(&tpacpi_leds[i].led_classdev); |
4181 | } | 4181 | } |
4182 | 4182 | ||
4183 | kfree(tpacpi_leds); | 4183 | kfree(tpacpi_leds); |
4184 | } | 4184 | } |
4185 | 4185 | ||
4186 | static int __init led_init(struct ibm_init_struct *iibm) | 4186 | static int __init led_init(struct ibm_init_struct *iibm) |
4187 | { | 4187 | { |
4188 | unsigned int i; | 4188 | unsigned int i; |
4189 | int rc; | 4189 | int rc; |
4190 | 4190 | ||
4191 | vdbg_printk(TPACPI_DBG_INIT, "initializing LED subdriver\n"); | 4191 | vdbg_printk(TPACPI_DBG_INIT, "initializing LED subdriver\n"); |
4192 | 4192 | ||
4193 | TPACPI_ACPIHANDLE_INIT(led); | 4193 | TPACPI_ACPIHANDLE_INIT(led); |
4194 | 4194 | ||
4195 | if (!led_handle) | 4195 | if (!led_handle) |
4196 | /* led not supported on R30, R31 */ | 4196 | /* led not supported on R30, R31 */ |
4197 | led_supported = TPACPI_LED_NONE; | 4197 | led_supported = TPACPI_LED_NONE; |
4198 | else if (strlencmp(led_path, "SLED") == 0) | 4198 | else if (strlencmp(led_path, "SLED") == 0) |
4199 | /* 570 */ | 4199 | /* 570 */ |
4200 | led_supported = TPACPI_LED_570; | 4200 | led_supported = TPACPI_LED_570; |
4201 | else if (strlencmp(led_path, "SYSL") == 0) | 4201 | else if (strlencmp(led_path, "SYSL") == 0) |
4202 | /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */ | 4202 | /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */ |
4203 | led_supported = TPACPI_LED_OLD; | 4203 | led_supported = TPACPI_LED_OLD; |
4204 | else | 4204 | else |
4205 | /* all others */ | 4205 | /* all others */ |
4206 | led_supported = TPACPI_LED_NEW; | 4206 | led_supported = TPACPI_LED_NEW; |
4207 | 4207 | ||
4208 | vdbg_printk(TPACPI_DBG_INIT, "LED commands are %s, mode %d\n", | 4208 | vdbg_printk(TPACPI_DBG_INIT, "LED commands are %s, mode %d\n", |
4209 | str_supported(led_supported), led_supported); | 4209 | str_supported(led_supported), led_supported); |
4210 | 4210 | ||
4211 | tpacpi_leds = kzalloc(sizeof(*tpacpi_leds) * TPACPI_LED_NUMLEDS, | 4211 | tpacpi_leds = kzalloc(sizeof(*tpacpi_leds) * TPACPI_LED_NUMLEDS, |
4212 | GFP_KERNEL); | 4212 | GFP_KERNEL); |
4213 | if (!tpacpi_leds) { | 4213 | if (!tpacpi_leds) { |
4214 | printk(TPACPI_ERR "Out of memory for LED data\n"); | 4214 | printk(TPACPI_ERR "Out of memory for LED data\n"); |
4215 | return -ENOMEM; | 4215 | return -ENOMEM; |
4216 | } | 4216 | } |
4217 | 4217 | ||
4218 | for (i = 0; i < TPACPI_LED_NUMLEDS; i++) { | 4218 | for (i = 0; i < TPACPI_LED_NUMLEDS; i++) { |
4219 | tpacpi_leds[i].led = i; | 4219 | tpacpi_leds[i].led = i; |
4220 | 4220 | ||
4221 | tpacpi_leds[i].led_classdev.brightness_set = &led_sysfs_set; | 4221 | tpacpi_leds[i].led_classdev.brightness_set = &led_sysfs_set; |
4222 | tpacpi_leds[i].led_classdev.blink_set = &led_sysfs_blink_set; | 4222 | tpacpi_leds[i].led_classdev.blink_set = &led_sysfs_blink_set; |
4223 | if (led_supported == TPACPI_LED_570) | 4223 | if (led_supported == TPACPI_LED_570) |
4224 | tpacpi_leds[i].led_classdev.brightness_get = | 4224 | tpacpi_leds[i].led_classdev.brightness_get = |
4225 | &led_sysfs_get; | 4225 | &led_sysfs_get; |
4226 | 4226 | ||
4227 | tpacpi_leds[i].led_classdev.name = tpacpi_led_names[i]; | 4227 | tpacpi_leds[i].led_classdev.name = tpacpi_led_names[i]; |
4228 | 4228 | ||
4229 | INIT_WORK(&tpacpi_leds[i].work, led_set_status_worker); | 4229 | INIT_WORK(&tpacpi_leds[i].work, led_set_status_worker); |
4230 | 4230 | ||
4231 | rc = led_classdev_register(&tpacpi_pdev->dev, | 4231 | rc = led_classdev_register(&tpacpi_pdev->dev, |
4232 | &tpacpi_leds[i].led_classdev); | 4232 | &tpacpi_leds[i].led_classdev); |
4233 | if (rc < 0) { | 4233 | if (rc < 0) { |
4234 | tpacpi_leds[i].led_classdev.name = NULL; | 4234 | tpacpi_leds[i].led_classdev.name = NULL; |
4235 | led_exit(); | 4235 | led_exit(); |
4236 | return rc; | 4236 | return rc; |
4237 | } | 4237 | } |
4238 | } | 4238 | } |
4239 | 4239 | ||
4240 | return (led_supported != TPACPI_LED_NONE)? 0 : 1; | 4240 | return (led_supported != TPACPI_LED_NONE)? 0 : 1; |
4241 | } | 4241 | } |
4242 | 4242 | ||
4243 | #define str_led_status(s) \ | 4243 | #define str_led_status(s) \ |
4244 | ((s) == TPACPI_LED_OFF ? "off" : \ | 4244 | ((s) == TPACPI_LED_OFF ? "off" : \ |
4245 | ((s) == TPACPI_LED_ON ? "on" : "blinking")) | 4245 | ((s) == TPACPI_LED_ON ? "on" : "blinking")) |
4246 | 4246 | ||
4247 | static int led_read(char *p) | 4247 | static int led_read(char *p) |
4248 | { | 4248 | { |
4249 | int len = 0; | 4249 | int len = 0; |
4250 | 4250 | ||
4251 | if (!led_supported) { | 4251 | if (!led_supported) { |
4252 | len += sprintf(p + len, "status:\t\tnot supported\n"); | 4252 | len += sprintf(p + len, "status:\t\tnot supported\n"); |
4253 | return len; | 4253 | return len; |
4254 | } | 4254 | } |
4255 | len += sprintf(p + len, "status:\t\tsupported\n"); | 4255 | len += sprintf(p + len, "status:\t\tsupported\n"); |
4256 | 4256 | ||
4257 | if (led_supported == TPACPI_LED_570) { | 4257 | if (led_supported == TPACPI_LED_570) { |
4258 | /* 570 */ | 4258 | /* 570 */ |
4259 | int i, status; | 4259 | int i, status; |
4260 | for (i = 0; i < 8; i++) { | 4260 | for (i = 0; i < 8; i++) { |
4261 | status = led_get_status(i); | 4261 | status = led_get_status(i); |
4262 | if (status < 0) | 4262 | if (status < 0) |
4263 | return -EIO; | 4263 | return -EIO; |
4264 | len += sprintf(p + len, "%d:\t\t%s\n", | 4264 | len += sprintf(p + len, "%d:\t\t%s\n", |
4265 | i, str_led_status(status)); | 4265 | i, str_led_status(status)); |
4266 | } | 4266 | } |
4267 | } | 4267 | } |
4268 | 4268 | ||
4269 | len += sprintf(p + len, "commands:\t" | 4269 | len += sprintf(p + len, "commands:\t" |
4270 | "<led> on, <led> off, <led> blink (<led> is 0-7)\n"); | 4270 | "<led> on, <led> off, <led> blink (<led> is 0-7)\n"); |
4271 | 4271 | ||
4272 | return len; | 4272 | return len; |
4273 | } | 4273 | } |
4274 | 4274 | ||
4275 | static int led_write(char *buf) | 4275 | static int led_write(char *buf) |
4276 | { | 4276 | { |
4277 | char *cmd; | 4277 | char *cmd; |
4278 | int led, rc; | 4278 | int led, rc; |
4279 | enum led_status_t s; | 4279 | enum led_status_t s; |
4280 | 4280 | ||
4281 | if (!led_supported) | 4281 | if (!led_supported) |
4282 | return -ENODEV; | 4282 | return -ENODEV; |
4283 | 4283 | ||
4284 | while ((cmd = next_cmd(&buf))) { | 4284 | while ((cmd = next_cmd(&buf))) { |
4285 | if (sscanf(cmd, "%d", &led) != 1 || led < 0 || led > 7) | 4285 | if (sscanf(cmd, "%d", &led) != 1 || led < 0 || led > 7) |
4286 | return -EINVAL; | 4286 | return -EINVAL; |
4287 | 4287 | ||
4288 | if (strstr(cmd, "off")) { | 4288 | if (strstr(cmd, "off")) { |
4289 | s = TPACPI_LED_OFF; | 4289 | s = TPACPI_LED_OFF; |
4290 | } else if (strstr(cmd, "on")) { | 4290 | } else if (strstr(cmd, "on")) { |
4291 | s = TPACPI_LED_ON; | 4291 | s = TPACPI_LED_ON; |
4292 | } else if (strstr(cmd, "blink")) { | 4292 | } else if (strstr(cmd, "blink")) { |
4293 | s = TPACPI_LED_BLINK; | 4293 | s = TPACPI_LED_BLINK; |
4294 | } else { | 4294 | } else { |
4295 | return -EINVAL; | 4295 | return -EINVAL; |
4296 | } | 4296 | } |
4297 | 4297 | ||
4298 | rc = led_set_status(led, s); | 4298 | rc = led_set_status(led, s); |
4299 | if (rc < 0) | 4299 | if (rc < 0) |
4300 | return rc; | 4300 | return rc; |
4301 | } | 4301 | } |
4302 | 4302 | ||
4303 | return 0; | 4303 | return 0; |
4304 | } | 4304 | } |
4305 | 4305 | ||
4306 | static struct ibm_struct led_driver_data = { | 4306 | static struct ibm_struct led_driver_data = { |
4307 | .name = "led", | 4307 | .name = "led", |
4308 | .read = led_read, | 4308 | .read = led_read, |
4309 | .write = led_write, | 4309 | .write = led_write, |
4310 | .exit = led_exit, | 4310 | .exit = led_exit, |
4311 | }; | 4311 | }; |
4312 | 4312 | ||
4313 | /************************************************************************* | 4313 | /************************************************************************* |
4314 | * Beep subdriver | 4314 | * Beep subdriver |
4315 | */ | 4315 | */ |
4316 | 4316 | ||
4317 | TPACPI_HANDLE(beep, ec, "BEEP"); /* all except R30, R31 */ | 4317 | TPACPI_HANDLE(beep, ec, "BEEP"); /* all except R30, R31 */ |
4318 | 4318 | ||
4319 | static int __init beep_init(struct ibm_init_struct *iibm) | 4319 | static int __init beep_init(struct ibm_init_struct *iibm) |
4320 | { | 4320 | { |
4321 | vdbg_printk(TPACPI_DBG_INIT, "initializing beep subdriver\n"); | 4321 | vdbg_printk(TPACPI_DBG_INIT, "initializing beep subdriver\n"); |
4322 | 4322 | ||
4323 | TPACPI_ACPIHANDLE_INIT(beep); | 4323 | TPACPI_ACPIHANDLE_INIT(beep); |
4324 | 4324 | ||
4325 | vdbg_printk(TPACPI_DBG_INIT, "beep is %s\n", | 4325 | vdbg_printk(TPACPI_DBG_INIT, "beep is %s\n", |
4326 | str_supported(beep_handle != NULL)); | 4326 | str_supported(beep_handle != NULL)); |
4327 | 4327 | ||
4328 | return (beep_handle)? 0 : 1; | 4328 | return (beep_handle)? 0 : 1; |
4329 | } | 4329 | } |
4330 | 4330 | ||
4331 | static int beep_read(char *p) | 4331 | static int beep_read(char *p) |
4332 | { | 4332 | { |
4333 | int len = 0; | 4333 | int len = 0; |
4334 | 4334 | ||
4335 | if (!beep_handle) | 4335 | if (!beep_handle) |
4336 | len += sprintf(p + len, "status:\t\tnot supported\n"); | 4336 | len += sprintf(p + len, "status:\t\tnot supported\n"); |
4337 | else { | 4337 | else { |
4338 | len += sprintf(p + len, "status:\t\tsupported\n"); | 4338 | len += sprintf(p + len, "status:\t\tsupported\n"); |
4339 | len += sprintf(p + len, "commands:\t<cmd> (<cmd> is 0-17)\n"); | 4339 | len += sprintf(p + len, "commands:\t<cmd> (<cmd> is 0-17)\n"); |
4340 | } | 4340 | } |
4341 | 4341 | ||
4342 | return len; | 4342 | return len; |
4343 | } | 4343 | } |
4344 | 4344 | ||
4345 | static int beep_write(char *buf) | 4345 | static int beep_write(char *buf) |
4346 | { | 4346 | { |
4347 | char *cmd; | 4347 | char *cmd; |
4348 | int beep_cmd; | 4348 | int beep_cmd; |
4349 | 4349 | ||
4350 | if (!beep_handle) | 4350 | if (!beep_handle) |
4351 | return -ENODEV; | 4351 | return -ENODEV; |
4352 | 4352 | ||
4353 | while ((cmd = next_cmd(&buf))) { | 4353 | while ((cmd = next_cmd(&buf))) { |
4354 | if (sscanf(cmd, "%u", &beep_cmd) == 1 && | 4354 | if (sscanf(cmd, "%u", &beep_cmd) == 1 && |
4355 | beep_cmd >= 0 && beep_cmd <= 17) { | 4355 | beep_cmd >= 0 && beep_cmd <= 17) { |
4356 | /* beep_cmd set */ | 4356 | /* beep_cmd set */ |
4357 | } else | 4357 | } else |
4358 | return -EINVAL; | 4358 | return -EINVAL; |
4359 | if (!acpi_evalf(beep_handle, NULL, NULL, "vdd", beep_cmd, 0)) | 4359 | if (!acpi_evalf(beep_handle, NULL, NULL, "vdd", beep_cmd, 0)) |
4360 | return -EIO; | 4360 | return -EIO; |
4361 | } | 4361 | } |
4362 | 4362 | ||
4363 | return 0; | 4363 | return 0; |
4364 | } | 4364 | } |
4365 | 4365 | ||
4366 | static struct ibm_struct beep_driver_data = { | 4366 | static struct ibm_struct beep_driver_data = { |
4367 | .name = "beep", | 4367 | .name = "beep", |
4368 | .read = beep_read, | 4368 | .read = beep_read, |
4369 | .write = beep_write, | 4369 | .write = beep_write, |
4370 | }; | 4370 | }; |
4371 | 4371 | ||
4372 | /************************************************************************* | 4372 | /************************************************************************* |
4373 | * Thermal subdriver | 4373 | * Thermal subdriver |
4374 | */ | 4374 | */ |
4375 | 4375 | ||
4376 | enum thermal_access_mode { | 4376 | enum thermal_access_mode { |
4377 | TPACPI_THERMAL_NONE = 0, /* No thermal support */ | 4377 | TPACPI_THERMAL_NONE = 0, /* No thermal support */ |
4378 | TPACPI_THERMAL_ACPI_TMP07, /* Use ACPI TMP0-7 */ | 4378 | TPACPI_THERMAL_ACPI_TMP07, /* Use ACPI TMP0-7 */ |
4379 | TPACPI_THERMAL_ACPI_UPDT, /* Use ACPI TMP0-7 with UPDT */ | 4379 | TPACPI_THERMAL_ACPI_UPDT, /* Use ACPI TMP0-7 with UPDT */ |
4380 | TPACPI_THERMAL_TPEC_8, /* Use ACPI EC regs, 8 sensors */ | 4380 | TPACPI_THERMAL_TPEC_8, /* Use ACPI EC regs, 8 sensors */ |
4381 | TPACPI_THERMAL_TPEC_16, /* Use ACPI EC regs, 16 sensors */ | 4381 | TPACPI_THERMAL_TPEC_16, /* Use ACPI EC regs, 16 sensors */ |
4382 | }; | 4382 | }; |
4383 | 4383 | ||
4384 | enum { /* TPACPI_THERMAL_TPEC_* */ | 4384 | enum { /* TPACPI_THERMAL_TPEC_* */ |
4385 | TP_EC_THERMAL_TMP0 = 0x78, /* ACPI EC regs TMP 0..7 */ | 4385 | TP_EC_THERMAL_TMP0 = 0x78, /* ACPI EC regs TMP 0..7 */ |
4386 | TP_EC_THERMAL_TMP8 = 0xC0, /* ACPI EC regs TMP 8..15 */ | 4386 | TP_EC_THERMAL_TMP8 = 0xC0, /* ACPI EC regs TMP 8..15 */ |
4387 | TP_EC_THERMAL_TMP_NA = -128, /* ACPI EC sensor not available */ | 4387 | TP_EC_THERMAL_TMP_NA = -128, /* ACPI EC sensor not available */ |
4388 | }; | 4388 | }; |
4389 | 4389 | ||
4390 | #define TPACPI_MAX_THERMAL_SENSORS 16 /* Max thermal sensors supported */ | 4390 | #define TPACPI_MAX_THERMAL_SENSORS 16 /* Max thermal sensors supported */ |
4391 | struct ibm_thermal_sensors_struct { | 4391 | struct ibm_thermal_sensors_struct { |
4392 | s32 temp[TPACPI_MAX_THERMAL_SENSORS]; | 4392 | s32 temp[TPACPI_MAX_THERMAL_SENSORS]; |
4393 | }; | 4393 | }; |
4394 | 4394 | ||
4395 | static enum thermal_access_mode thermal_read_mode; | 4395 | static enum thermal_access_mode thermal_read_mode; |
4396 | 4396 | ||
4397 | /* idx is zero-based */ | 4397 | /* idx is zero-based */ |
4398 | static int thermal_get_sensor(int idx, s32 *value) | 4398 | static int thermal_get_sensor(int idx, s32 *value) |
4399 | { | 4399 | { |
4400 | int t; | 4400 | int t; |
4401 | s8 tmp; | 4401 | s8 tmp; |
4402 | char tmpi[5]; | 4402 | char tmpi[5]; |
4403 | 4403 | ||
4404 | t = TP_EC_THERMAL_TMP0; | 4404 | t = TP_EC_THERMAL_TMP0; |
4405 | 4405 | ||
4406 | switch (thermal_read_mode) { | 4406 | switch (thermal_read_mode) { |
4407 | #if TPACPI_MAX_THERMAL_SENSORS >= 16 | 4407 | #if TPACPI_MAX_THERMAL_SENSORS >= 16 |
4408 | case TPACPI_THERMAL_TPEC_16: | 4408 | case TPACPI_THERMAL_TPEC_16: |
4409 | if (idx >= 8 && idx <= 15) { | 4409 | if (idx >= 8 && idx <= 15) { |
4410 | t = TP_EC_THERMAL_TMP8; | 4410 | t = TP_EC_THERMAL_TMP8; |
4411 | idx -= 8; | 4411 | idx -= 8; |
4412 | } | 4412 | } |
4413 | /* fallthrough */ | 4413 | /* fallthrough */ |
4414 | #endif | 4414 | #endif |
4415 | case TPACPI_THERMAL_TPEC_8: | 4415 | case TPACPI_THERMAL_TPEC_8: |
4416 | if (idx <= 7) { | 4416 | if (idx <= 7) { |
4417 | if (!acpi_ec_read(t + idx, &tmp)) | 4417 | if (!acpi_ec_read(t + idx, &tmp)) |
4418 | return -EIO; | 4418 | return -EIO; |
4419 | *value = tmp * 1000; | 4419 | *value = tmp * 1000; |
4420 | return 0; | 4420 | return 0; |
4421 | } | 4421 | } |
4422 | break; | 4422 | break; |
4423 | 4423 | ||
4424 | case TPACPI_THERMAL_ACPI_UPDT: | 4424 | case TPACPI_THERMAL_ACPI_UPDT: |
4425 | if (idx <= 7) { | 4425 | if (idx <= 7) { |
4426 | snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx); | 4426 | snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx); |
4427 | if (!acpi_evalf(ec_handle, NULL, "UPDT", "v")) | 4427 | if (!acpi_evalf(ec_handle, NULL, "UPDT", "v")) |
4428 | return -EIO; | 4428 | return -EIO; |
4429 | if (!acpi_evalf(ec_handle, &t, tmpi, "d")) | 4429 | if (!acpi_evalf(ec_handle, &t, tmpi, "d")) |
4430 | return -EIO; | 4430 | return -EIO; |
4431 | *value = (t - 2732) * 100; | 4431 | *value = (t - 2732) * 100; |
4432 | return 0; | 4432 | return 0; |
4433 | } | 4433 | } |
4434 | break; | 4434 | break; |
4435 | 4435 | ||
4436 | case TPACPI_THERMAL_ACPI_TMP07: | 4436 | case TPACPI_THERMAL_ACPI_TMP07: |
4437 | if (idx <= 7) { | 4437 | if (idx <= 7) { |
4438 | snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx); | 4438 | snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx); |
4439 | if (!acpi_evalf(ec_handle, &t, tmpi, "d")) | 4439 | if (!acpi_evalf(ec_handle, &t, tmpi, "d")) |
4440 | return -EIO; | 4440 | return -EIO; |
4441 | if (t > 127 || t < -127) | 4441 | if (t > 127 || t < -127) |
4442 | t = TP_EC_THERMAL_TMP_NA; | 4442 | t = TP_EC_THERMAL_TMP_NA; |
4443 | *value = t * 1000; | 4443 | *value = t * 1000; |
4444 | return 0; | 4444 | return 0; |
4445 | } | 4445 | } |
4446 | break; | 4446 | break; |
4447 | 4447 | ||
4448 | case TPACPI_THERMAL_NONE: | 4448 | case TPACPI_THERMAL_NONE: |
4449 | default: | 4449 | default: |
4450 | return -ENOSYS; | 4450 | return -ENOSYS; |
4451 | } | 4451 | } |
4452 | 4452 | ||
4453 | return -EINVAL; | 4453 | return -EINVAL; |
4454 | } | 4454 | } |
4455 | 4455 | ||
4456 | static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s) | 4456 | static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s) |
4457 | { | 4457 | { |
4458 | int res, i; | 4458 | int res, i; |
4459 | int n; | 4459 | int n; |
4460 | 4460 | ||
4461 | n = 8; | 4461 | n = 8; |
4462 | i = 0; | 4462 | i = 0; |
4463 | 4463 | ||
4464 | if (!s) | 4464 | if (!s) |
4465 | return -EINVAL; | 4465 | return -EINVAL; |
4466 | 4466 | ||
4467 | if (thermal_read_mode == TPACPI_THERMAL_TPEC_16) | 4467 | if (thermal_read_mode == TPACPI_THERMAL_TPEC_16) |
4468 | n = 16; | 4468 | n = 16; |
4469 | 4469 | ||
4470 | for (i = 0 ; i < n; i++) { | 4470 | for (i = 0 ; i < n; i++) { |
4471 | res = thermal_get_sensor(i, &s->temp[i]); | 4471 | res = thermal_get_sensor(i, &s->temp[i]); |
4472 | if (res) | 4472 | if (res) |
4473 | return res; | 4473 | return res; |
4474 | } | 4474 | } |
4475 | 4475 | ||
4476 | return n; | 4476 | return n; |
4477 | } | 4477 | } |
4478 | 4478 | ||
4479 | /* sysfs temp##_input -------------------------------------------------- */ | 4479 | /* sysfs temp##_input -------------------------------------------------- */ |
4480 | 4480 | ||
4481 | static ssize_t thermal_temp_input_show(struct device *dev, | 4481 | static ssize_t thermal_temp_input_show(struct device *dev, |
4482 | struct device_attribute *attr, | 4482 | struct device_attribute *attr, |
4483 | char *buf) | 4483 | char *buf) |
4484 | { | 4484 | { |
4485 | struct sensor_device_attribute *sensor_attr = | 4485 | struct sensor_device_attribute *sensor_attr = |
4486 | to_sensor_dev_attr(attr); | 4486 | to_sensor_dev_attr(attr); |
4487 | int idx = sensor_attr->index; | 4487 | int idx = sensor_attr->index; |
4488 | s32 value; | 4488 | s32 value; |
4489 | int res; | 4489 | int res; |
4490 | 4490 | ||
4491 | res = thermal_get_sensor(idx, &value); | 4491 | res = thermal_get_sensor(idx, &value); |
4492 | if (res) | 4492 | if (res) |
4493 | return res; | 4493 | return res; |
4494 | if (value == TP_EC_THERMAL_TMP_NA * 1000) | 4494 | if (value == TP_EC_THERMAL_TMP_NA * 1000) |
4495 | return -ENXIO; | 4495 | return -ENXIO; |
4496 | 4496 | ||
4497 | return snprintf(buf, PAGE_SIZE, "%d\n", value); | 4497 | return snprintf(buf, PAGE_SIZE, "%d\n", value); |
4498 | } | 4498 | } |
4499 | 4499 | ||
4500 | #define THERMAL_SENSOR_ATTR_TEMP(_idxA, _idxB) \ | 4500 | #define THERMAL_SENSOR_ATTR_TEMP(_idxA, _idxB) \ |
4501 | SENSOR_ATTR(temp##_idxA##_input, S_IRUGO, \ | 4501 | SENSOR_ATTR(temp##_idxA##_input, S_IRUGO, \ |
4502 | thermal_temp_input_show, NULL, _idxB) | 4502 | thermal_temp_input_show, NULL, _idxB) |
4503 | 4503 | ||
4504 | static struct sensor_device_attribute sensor_dev_attr_thermal_temp_input[] = { | 4504 | static struct sensor_device_attribute sensor_dev_attr_thermal_temp_input[] = { |
4505 | THERMAL_SENSOR_ATTR_TEMP(1, 0), | 4505 | THERMAL_SENSOR_ATTR_TEMP(1, 0), |
4506 | THERMAL_SENSOR_ATTR_TEMP(2, 1), | 4506 | THERMAL_SENSOR_ATTR_TEMP(2, 1), |
4507 | THERMAL_SENSOR_ATTR_TEMP(3, 2), | 4507 | THERMAL_SENSOR_ATTR_TEMP(3, 2), |
4508 | THERMAL_SENSOR_ATTR_TEMP(4, 3), | 4508 | THERMAL_SENSOR_ATTR_TEMP(4, 3), |
4509 | THERMAL_SENSOR_ATTR_TEMP(5, 4), | 4509 | THERMAL_SENSOR_ATTR_TEMP(5, 4), |
4510 | THERMAL_SENSOR_ATTR_TEMP(6, 5), | 4510 | THERMAL_SENSOR_ATTR_TEMP(6, 5), |
4511 | THERMAL_SENSOR_ATTR_TEMP(7, 6), | 4511 | THERMAL_SENSOR_ATTR_TEMP(7, 6), |
4512 | THERMAL_SENSOR_ATTR_TEMP(8, 7), | 4512 | THERMAL_SENSOR_ATTR_TEMP(8, 7), |
4513 | THERMAL_SENSOR_ATTR_TEMP(9, 8), | 4513 | THERMAL_SENSOR_ATTR_TEMP(9, 8), |
4514 | THERMAL_SENSOR_ATTR_TEMP(10, 9), | 4514 | THERMAL_SENSOR_ATTR_TEMP(10, 9), |
4515 | THERMAL_SENSOR_ATTR_TEMP(11, 10), | 4515 | THERMAL_SENSOR_ATTR_TEMP(11, 10), |
4516 | THERMAL_SENSOR_ATTR_TEMP(12, 11), | 4516 | THERMAL_SENSOR_ATTR_TEMP(12, 11), |
4517 | THERMAL_SENSOR_ATTR_TEMP(13, 12), | 4517 | THERMAL_SENSOR_ATTR_TEMP(13, 12), |
4518 | THERMAL_SENSOR_ATTR_TEMP(14, 13), | 4518 | THERMAL_SENSOR_ATTR_TEMP(14, 13), |
4519 | THERMAL_SENSOR_ATTR_TEMP(15, 14), | 4519 | THERMAL_SENSOR_ATTR_TEMP(15, 14), |
4520 | THERMAL_SENSOR_ATTR_TEMP(16, 15), | 4520 | THERMAL_SENSOR_ATTR_TEMP(16, 15), |
4521 | }; | 4521 | }; |
4522 | 4522 | ||
4523 | #define THERMAL_ATTRS(X) \ | 4523 | #define THERMAL_ATTRS(X) \ |
4524 | &sensor_dev_attr_thermal_temp_input[X].dev_attr.attr | 4524 | &sensor_dev_attr_thermal_temp_input[X].dev_attr.attr |
4525 | 4525 | ||
4526 | static struct attribute *thermal_temp_input_attr[] = { | 4526 | static struct attribute *thermal_temp_input_attr[] = { |
4527 | THERMAL_ATTRS(8), | 4527 | THERMAL_ATTRS(8), |
4528 | THERMAL_ATTRS(9), | 4528 | THERMAL_ATTRS(9), |
4529 | THERMAL_ATTRS(10), | 4529 | THERMAL_ATTRS(10), |
4530 | THERMAL_ATTRS(11), | 4530 | THERMAL_ATTRS(11), |
4531 | THERMAL_ATTRS(12), | 4531 | THERMAL_ATTRS(12), |
4532 | THERMAL_ATTRS(13), | 4532 | THERMAL_ATTRS(13), |
4533 | THERMAL_ATTRS(14), | 4533 | THERMAL_ATTRS(14), |
4534 | THERMAL_ATTRS(15), | 4534 | THERMAL_ATTRS(15), |
4535 | THERMAL_ATTRS(0), | 4535 | THERMAL_ATTRS(0), |
4536 | THERMAL_ATTRS(1), | 4536 | THERMAL_ATTRS(1), |
4537 | THERMAL_ATTRS(2), | 4537 | THERMAL_ATTRS(2), |
4538 | THERMAL_ATTRS(3), | 4538 | THERMAL_ATTRS(3), |
4539 | THERMAL_ATTRS(4), | 4539 | THERMAL_ATTRS(4), |
4540 | THERMAL_ATTRS(5), | 4540 | THERMAL_ATTRS(5), |
4541 | THERMAL_ATTRS(6), | 4541 | THERMAL_ATTRS(6), |
4542 | THERMAL_ATTRS(7), | 4542 | THERMAL_ATTRS(7), |
4543 | NULL | 4543 | NULL |
4544 | }; | 4544 | }; |
4545 | 4545 | ||
4546 | static const struct attribute_group thermal_temp_input16_group = { | 4546 | static const struct attribute_group thermal_temp_input16_group = { |
4547 | .attrs = thermal_temp_input_attr | 4547 | .attrs = thermal_temp_input_attr |
4548 | }; | 4548 | }; |
4549 | 4549 | ||
4550 | static const struct attribute_group thermal_temp_input8_group = { | 4550 | static const struct attribute_group thermal_temp_input8_group = { |
4551 | .attrs = &thermal_temp_input_attr[8] | 4551 | .attrs = &thermal_temp_input_attr[8] |
4552 | }; | 4552 | }; |
4553 | 4553 | ||
4554 | #undef THERMAL_SENSOR_ATTR_TEMP | 4554 | #undef THERMAL_SENSOR_ATTR_TEMP |
4555 | #undef THERMAL_ATTRS | 4555 | #undef THERMAL_ATTRS |
4556 | 4556 | ||
4557 | /* --------------------------------------------------------------------- */ | 4557 | /* --------------------------------------------------------------------- */ |
4558 | 4558 | ||
4559 | static int __init thermal_init(struct ibm_init_struct *iibm) | 4559 | static int __init thermal_init(struct ibm_init_struct *iibm) |
4560 | { | 4560 | { |
4561 | u8 t, ta1, ta2; | 4561 | u8 t, ta1, ta2; |
4562 | int i; | 4562 | int i; |
4563 | int acpi_tmp7; | 4563 | int acpi_tmp7; |
4564 | int res; | 4564 | int res; |
4565 | 4565 | ||
4566 | vdbg_printk(TPACPI_DBG_INIT, "initializing thermal subdriver\n"); | 4566 | vdbg_printk(TPACPI_DBG_INIT, "initializing thermal subdriver\n"); |
4567 | 4567 | ||
4568 | acpi_tmp7 = acpi_evalf(ec_handle, NULL, "TMP7", "qv"); | 4568 | acpi_tmp7 = acpi_evalf(ec_handle, NULL, "TMP7", "qv"); |
4569 | 4569 | ||
4570 | if (thinkpad_id.ec_model) { | 4570 | if (thinkpad_id.ec_model) { |
4571 | /* | 4571 | /* |
4572 | * Direct EC access mode: sensors at registers | 4572 | * Direct EC access mode: sensors at registers |
4573 | * 0x78-0x7F, 0xC0-0xC7. Registers return 0x00 for | 4573 | * 0x78-0x7F, 0xC0-0xC7. Registers return 0x00 for |
4574 | * non-implemented, thermal sensors return 0x80 when | 4574 | * non-implemented, thermal sensors return 0x80 when |
4575 | * not available | 4575 | * not available |
4576 | */ | 4576 | */ |
4577 | 4577 | ||
4578 | ta1 = ta2 = 0; | 4578 | ta1 = ta2 = 0; |
4579 | for (i = 0; i < 8; i++) { | 4579 | for (i = 0; i < 8; i++) { |
4580 | if (acpi_ec_read(TP_EC_THERMAL_TMP0 + i, &t)) { | 4580 | if (acpi_ec_read(TP_EC_THERMAL_TMP0 + i, &t)) { |
4581 | ta1 |= t; | 4581 | ta1 |= t; |
4582 | } else { | 4582 | } else { |
4583 | ta1 = 0; | 4583 | ta1 = 0; |
4584 | break; | 4584 | break; |
4585 | } | 4585 | } |
4586 | if (acpi_ec_read(TP_EC_THERMAL_TMP8 + i, &t)) { | 4586 | if (acpi_ec_read(TP_EC_THERMAL_TMP8 + i, &t)) { |
4587 | ta2 |= t; | 4587 | ta2 |= t; |
4588 | } else { | 4588 | } else { |
4589 | ta1 = 0; | 4589 | ta1 = 0; |
4590 | break; | 4590 | break; |
4591 | } | 4591 | } |
4592 | } | 4592 | } |
4593 | if (ta1 == 0) { | 4593 | if (ta1 == 0) { |
4594 | /* This is sheer paranoia, but we handle it anyway */ | 4594 | /* This is sheer paranoia, but we handle it anyway */ |
4595 | if (acpi_tmp7) { | 4595 | if (acpi_tmp7) { |
4596 | printk(TPACPI_ERR | 4596 | printk(TPACPI_ERR |
4597 | "ThinkPad ACPI EC access misbehaving, " | 4597 | "ThinkPad ACPI EC access misbehaving, " |
4598 | "falling back to ACPI TMPx access " | 4598 | "falling back to ACPI TMPx access " |
4599 | "mode\n"); | 4599 | "mode\n"); |
4600 | thermal_read_mode = TPACPI_THERMAL_ACPI_TMP07; | 4600 | thermal_read_mode = TPACPI_THERMAL_ACPI_TMP07; |
4601 | } else { | 4601 | } else { |
4602 | printk(TPACPI_ERR | 4602 | printk(TPACPI_ERR |
4603 | "ThinkPad ACPI EC access misbehaving, " | 4603 | "ThinkPad ACPI EC access misbehaving, " |
4604 | "disabling thermal sensors access\n"); | 4604 | "disabling thermal sensors access\n"); |
4605 | thermal_read_mode = TPACPI_THERMAL_NONE; | 4605 | thermal_read_mode = TPACPI_THERMAL_NONE; |
4606 | } | 4606 | } |
4607 | } else { | 4607 | } else { |
4608 | thermal_read_mode = | 4608 | thermal_read_mode = |
4609 | (ta2 != 0) ? | 4609 | (ta2 != 0) ? |
4610 | TPACPI_THERMAL_TPEC_16 : TPACPI_THERMAL_TPEC_8; | 4610 | TPACPI_THERMAL_TPEC_16 : TPACPI_THERMAL_TPEC_8; |
4611 | } | 4611 | } |
4612 | } else if (acpi_tmp7) { | 4612 | } else if (acpi_tmp7) { |
4613 | if (acpi_evalf(ec_handle, NULL, "UPDT", "qv")) { | 4613 | if (acpi_evalf(ec_handle, NULL, "UPDT", "qv")) { |
4614 | /* 600e/x, 770e, 770x */ | 4614 | /* 600e/x, 770e, 770x */ |
4615 | thermal_read_mode = TPACPI_THERMAL_ACPI_UPDT; | 4615 | thermal_read_mode = TPACPI_THERMAL_ACPI_UPDT; |
4616 | } else { | 4616 | } else { |
4617 | /* Standard ACPI TMPx access, max 8 sensors */ | 4617 | /* Standard ACPI TMPx access, max 8 sensors */ |
4618 | thermal_read_mode = TPACPI_THERMAL_ACPI_TMP07; | 4618 | thermal_read_mode = TPACPI_THERMAL_ACPI_TMP07; |
4619 | } | 4619 | } |
4620 | } else { | 4620 | } else { |
4621 | /* temperatures not supported on 570, G4x, R30, R31, R32 */ | 4621 | /* temperatures not supported on 570, G4x, R30, R31, R32 */ |
4622 | thermal_read_mode = TPACPI_THERMAL_NONE; | 4622 | thermal_read_mode = TPACPI_THERMAL_NONE; |
4623 | } | 4623 | } |
4624 | 4624 | ||
4625 | vdbg_printk(TPACPI_DBG_INIT, "thermal is %s, mode %d\n", | 4625 | vdbg_printk(TPACPI_DBG_INIT, "thermal is %s, mode %d\n", |
4626 | str_supported(thermal_read_mode != TPACPI_THERMAL_NONE), | 4626 | str_supported(thermal_read_mode != TPACPI_THERMAL_NONE), |
4627 | thermal_read_mode); | 4627 | thermal_read_mode); |
4628 | 4628 | ||
4629 | switch (thermal_read_mode) { | 4629 | switch (thermal_read_mode) { |
4630 | case TPACPI_THERMAL_TPEC_16: | 4630 | case TPACPI_THERMAL_TPEC_16: |
4631 | res = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj, | 4631 | res = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj, |
4632 | &thermal_temp_input16_group); | 4632 | &thermal_temp_input16_group); |
4633 | if (res) | 4633 | if (res) |
4634 | return res; | 4634 | return res; |
4635 | break; | 4635 | break; |
4636 | case TPACPI_THERMAL_TPEC_8: | 4636 | case TPACPI_THERMAL_TPEC_8: |
4637 | case TPACPI_THERMAL_ACPI_TMP07: | 4637 | case TPACPI_THERMAL_ACPI_TMP07: |
4638 | case TPACPI_THERMAL_ACPI_UPDT: | 4638 | case TPACPI_THERMAL_ACPI_UPDT: |
4639 | res = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj, | 4639 | res = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj, |
4640 | &thermal_temp_input8_group); | 4640 | &thermal_temp_input8_group); |
4641 | if (res) | 4641 | if (res) |
4642 | return res; | 4642 | return res; |
4643 | break; | 4643 | break; |
4644 | case TPACPI_THERMAL_NONE: | 4644 | case TPACPI_THERMAL_NONE: |
4645 | default: | 4645 | default: |
4646 | return 1; | 4646 | return 1; |
4647 | } | 4647 | } |
4648 | 4648 | ||
4649 | return 0; | 4649 | return 0; |
4650 | } | 4650 | } |
4651 | 4651 | ||
4652 | static void thermal_exit(void) | 4652 | static void thermal_exit(void) |
4653 | { | 4653 | { |
4654 | switch (thermal_read_mode) { | 4654 | switch (thermal_read_mode) { |
4655 | case TPACPI_THERMAL_TPEC_16: | 4655 | case TPACPI_THERMAL_TPEC_16: |
4656 | sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, | 4656 | sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, |
4657 | &thermal_temp_input16_group); | 4657 | &thermal_temp_input16_group); |
4658 | break; | 4658 | break; |
4659 | case TPACPI_THERMAL_TPEC_8: | 4659 | case TPACPI_THERMAL_TPEC_8: |
4660 | case TPACPI_THERMAL_ACPI_TMP07: | 4660 | case TPACPI_THERMAL_ACPI_TMP07: |
4661 | case TPACPI_THERMAL_ACPI_UPDT: | 4661 | case TPACPI_THERMAL_ACPI_UPDT: |
4662 | sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, | 4662 | sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, |
4663 | &thermal_temp_input16_group); | 4663 | &thermal_temp_input16_group); |
4664 | break; | 4664 | break; |
4665 | case TPACPI_THERMAL_NONE: | 4665 | case TPACPI_THERMAL_NONE: |
4666 | default: | 4666 | default: |
4667 | break; | 4667 | break; |
4668 | } | 4668 | } |
4669 | } | 4669 | } |
4670 | 4670 | ||
4671 | static int thermal_read(char *p) | 4671 | static int thermal_read(char *p) |
4672 | { | 4672 | { |
4673 | int len = 0; | 4673 | int len = 0; |
4674 | int n, i; | 4674 | int n, i; |
4675 | struct ibm_thermal_sensors_struct t; | 4675 | struct ibm_thermal_sensors_struct t; |
4676 | 4676 | ||
4677 | n = thermal_get_sensors(&t); | 4677 | n = thermal_get_sensors(&t); |
4678 | if (unlikely(n < 0)) | 4678 | if (unlikely(n < 0)) |
4679 | return n; | 4679 | return n; |
4680 | 4680 | ||
4681 | len += sprintf(p + len, "temperatures:\t"); | 4681 | len += sprintf(p + len, "temperatures:\t"); |
4682 | 4682 | ||
4683 | if (n > 0) { | 4683 | if (n > 0) { |
4684 | for (i = 0; i < (n - 1); i++) | 4684 | for (i = 0; i < (n - 1); i++) |
4685 | len += sprintf(p + len, "%d ", t.temp[i] / 1000); | 4685 | len += sprintf(p + len, "%d ", t.temp[i] / 1000); |
4686 | len += sprintf(p + len, "%d\n", t.temp[i] / 1000); | 4686 | len += sprintf(p + len, "%d\n", t.temp[i] / 1000); |
4687 | } else | 4687 | } else |
4688 | len += sprintf(p + len, "not supported\n"); | 4688 | len += sprintf(p + len, "not supported\n"); |
4689 | 4689 | ||
4690 | return len; | 4690 | return len; |
4691 | } | 4691 | } |
4692 | 4692 | ||
4693 | static struct ibm_struct thermal_driver_data = { | 4693 | static struct ibm_struct thermal_driver_data = { |
4694 | .name = "thermal", | 4694 | .name = "thermal", |
4695 | .read = thermal_read, | 4695 | .read = thermal_read, |
4696 | .exit = thermal_exit, | 4696 | .exit = thermal_exit, |
4697 | }; | 4697 | }; |
4698 | 4698 | ||
4699 | /************************************************************************* | 4699 | /************************************************************************* |
4700 | * EC Dump subdriver | 4700 | * EC Dump subdriver |
4701 | */ | 4701 | */ |
4702 | 4702 | ||
4703 | static u8 ecdump_regs[256]; | 4703 | static u8 ecdump_regs[256]; |
4704 | 4704 | ||
4705 | static int ecdump_read(char *p) | 4705 | static int ecdump_read(char *p) |
4706 | { | 4706 | { |
4707 | int len = 0; | 4707 | int len = 0; |
4708 | int i, j; | 4708 | int i, j; |
4709 | u8 v; | 4709 | u8 v; |
4710 | 4710 | ||
4711 | len += sprintf(p + len, "EC " | 4711 | len += sprintf(p + len, "EC " |
4712 | " +00 +01 +02 +03 +04 +05 +06 +07" | 4712 | " +00 +01 +02 +03 +04 +05 +06 +07" |
4713 | " +08 +09 +0a +0b +0c +0d +0e +0f\n"); | 4713 | " +08 +09 +0a +0b +0c +0d +0e +0f\n"); |
4714 | for (i = 0; i < 256; i += 16) { | 4714 | for (i = 0; i < 256; i += 16) { |
4715 | len += sprintf(p + len, "EC 0x%02x:", i); | 4715 | len += sprintf(p + len, "EC 0x%02x:", i); |
4716 | for (j = 0; j < 16; j++) { | 4716 | for (j = 0; j < 16; j++) { |
4717 | if (!acpi_ec_read(i + j, &v)) | 4717 | if (!acpi_ec_read(i + j, &v)) |
4718 | break; | 4718 | break; |
4719 | if (v != ecdump_regs[i + j]) | 4719 | if (v != ecdump_regs[i + j]) |
4720 | len += sprintf(p + len, " *%02x", v); | 4720 | len += sprintf(p + len, " *%02x", v); |
4721 | else | 4721 | else |
4722 | len += sprintf(p + len, " %02x", v); | 4722 | len += sprintf(p + len, " %02x", v); |
4723 | ecdump_regs[i + j] = v; | 4723 | ecdump_regs[i + j] = v; |
4724 | } | 4724 | } |
4725 | len += sprintf(p + len, "\n"); | 4725 | len += sprintf(p + len, "\n"); |
4726 | if (j != 16) | 4726 | if (j != 16) |
4727 | break; | 4727 | break; |
4728 | } | 4728 | } |
4729 | 4729 | ||
4730 | /* These are way too dangerous to advertise openly... */ | 4730 | /* These are way too dangerous to advertise openly... */ |
4731 | #if 0 | 4731 | #if 0 |
4732 | len += sprintf(p + len, "commands:\t0x<offset> 0x<value>" | 4732 | len += sprintf(p + len, "commands:\t0x<offset> 0x<value>" |
4733 | " (<offset> is 00-ff, <value> is 00-ff)\n"); | 4733 | " (<offset> is 00-ff, <value> is 00-ff)\n"); |
4734 | len += sprintf(p + len, "commands:\t0x<offset> <value> " | 4734 | len += sprintf(p + len, "commands:\t0x<offset> <value> " |
4735 | " (<offset> is 00-ff, <value> is 0-255)\n"); | 4735 | " (<offset> is 00-ff, <value> is 0-255)\n"); |
4736 | #endif | 4736 | #endif |
4737 | return len; | 4737 | return len; |
4738 | } | 4738 | } |
4739 | 4739 | ||
4740 | static int ecdump_write(char *buf) | 4740 | static int ecdump_write(char *buf) |
4741 | { | 4741 | { |
4742 | char *cmd; | 4742 | char *cmd; |
4743 | int i, v; | 4743 | int i, v; |
4744 | 4744 | ||
4745 | while ((cmd = next_cmd(&buf))) { | 4745 | while ((cmd = next_cmd(&buf))) { |
4746 | if (sscanf(cmd, "0x%x 0x%x", &i, &v) == 2) { | 4746 | if (sscanf(cmd, "0x%x 0x%x", &i, &v) == 2) { |
4747 | /* i and v set */ | 4747 | /* i and v set */ |
4748 | } else if (sscanf(cmd, "0x%x %u", &i, &v) == 2) { | 4748 | } else if (sscanf(cmd, "0x%x %u", &i, &v) == 2) { |
4749 | /* i and v set */ | 4749 | /* i and v set */ |
4750 | } else | 4750 | } else |
4751 | return -EINVAL; | 4751 | return -EINVAL; |
4752 | if (i >= 0 && i < 256 && v >= 0 && v < 256) { | 4752 | if (i >= 0 && i < 256 && v >= 0 && v < 256) { |
4753 | if (!acpi_ec_write(i, v)) | 4753 | if (!acpi_ec_write(i, v)) |
4754 | return -EIO; | 4754 | return -EIO; |
4755 | } else | 4755 | } else |
4756 | return -EINVAL; | 4756 | return -EINVAL; |
4757 | } | 4757 | } |
4758 | 4758 | ||
4759 | return 0; | 4759 | return 0; |
4760 | } | 4760 | } |
4761 | 4761 | ||
4762 | static struct ibm_struct ecdump_driver_data = { | 4762 | static struct ibm_struct ecdump_driver_data = { |
4763 | .name = "ecdump", | 4763 | .name = "ecdump", |
4764 | .read = ecdump_read, | 4764 | .read = ecdump_read, |
4765 | .write = ecdump_write, | 4765 | .write = ecdump_write, |
4766 | .flags.experimental = 1, | 4766 | .flags.experimental = 1, |
4767 | }; | 4767 | }; |
4768 | 4768 | ||
4769 | /************************************************************************* | 4769 | /************************************************************************* |
4770 | * Backlight/brightness subdriver | 4770 | * Backlight/brightness subdriver |
4771 | */ | 4771 | */ |
4772 | 4772 | ||
4773 | #define TPACPI_BACKLIGHT_DEV_NAME "thinkpad_screen" | 4773 | #define TPACPI_BACKLIGHT_DEV_NAME "thinkpad_screen" |
4774 | 4774 | ||
4775 | enum { | 4775 | enum { |
4776 | TP_EC_BACKLIGHT = 0x31, | 4776 | TP_EC_BACKLIGHT = 0x31, |
4777 | 4777 | ||
4778 | /* TP_EC_BACKLIGHT bitmasks */ | 4778 | /* TP_EC_BACKLIGHT bitmasks */ |
4779 | TP_EC_BACKLIGHT_LVLMSK = 0x1F, | 4779 | TP_EC_BACKLIGHT_LVLMSK = 0x1F, |
4780 | TP_EC_BACKLIGHT_CMDMSK = 0xE0, | 4780 | TP_EC_BACKLIGHT_CMDMSK = 0xE0, |
4781 | TP_EC_BACKLIGHT_MAPSW = 0x20, | 4781 | TP_EC_BACKLIGHT_MAPSW = 0x20, |
4782 | }; | 4782 | }; |
4783 | 4783 | ||
4784 | static struct backlight_device *ibm_backlight_device; | 4784 | static struct backlight_device *ibm_backlight_device; |
4785 | static int brightness_mode; | 4785 | static int brightness_mode; |
4786 | static unsigned int brightness_enable = 2; /* 2 = auto, 0 = no, 1 = yes */ | 4786 | static unsigned int brightness_enable = 2; /* 2 = auto, 0 = no, 1 = yes */ |
4787 | 4787 | ||
4788 | static struct mutex brightness_mutex; | 4788 | static struct mutex brightness_mutex; |
4789 | 4789 | ||
4790 | /* | 4790 | /* |
4791 | * ThinkPads can read brightness from two places: EC 0x31, or | 4791 | * ThinkPads can read brightness from two places: EC 0x31, or |
4792 | * CMOS NVRAM byte 0x5E, bits 0-3. | 4792 | * CMOS NVRAM byte 0x5E, bits 0-3. |
4793 | * | 4793 | * |
4794 | * EC 0x31 has the following layout | 4794 | * EC 0x31 has the following layout |
4795 | * Bit 7: unknown function | 4795 | * Bit 7: unknown function |
4796 | * Bit 6: unknown function | 4796 | * Bit 6: unknown function |
4797 | * Bit 5: Z: honour scale changes, NZ: ignore scale changes | 4797 | * Bit 5: Z: honour scale changes, NZ: ignore scale changes |
4798 | * Bit 4: must be set to zero to avoid problems | 4798 | * Bit 4: must be set to zero to avoid problems |
4799 | * Bit 3-0: backlight brightness level | 4799 | * Bit 3-0: backlight brightness level |
4800 | * | 4800 | * |
4801 | * brightness_get_raw returns status data in the EC 0x31 layout | 4801 | * brightness_get_raw returns status data in the EC 0x31 layout |
4802 | */ | 4802 | */ |
4803 | static int brightness_get_raw(int *status) | 4803 | static int brightness_get_raw(int *status) |
4804 | { | 4804 | { |
4805 | u8 lec = 0, lcmos = 0, level = 0; | 4805 | u8 lec = 0, lcmos = 0, level = 0; |
4806 | 4806 | ||
4807 | if (brightness_mode & 1) { | 4807 | if (brightness_mode & 1) { |
4808 | if (!acpi_ec_read(TP_EC_BACKLIGHT, &lec)) | 4808 | if (!acpi_ec_read(TP_EC_BACKLIGHT, &lec)) |
4809 | return -EIO; | 4809 | return -EIO; |
4810 | level = lec & TP_EC_BACKLIGHT_LVLMSK; | 4810 | level = lec & TP_EC_BACKLIGHT_LVLMSK; |
4811 | }; | 4811 | }; |
4812 | if (brightness_mode & 2) { | 4812 | if (brightness_mode & 2) { |
4813 | lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS) | 4813 | lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS) |
4814 | & TP_NVRAM_MASK_LEVEL_BRIGHTNESS) | 4814 | & TP_NVRAM_MASK_LEVEL_BRIGHTNESS) |
4815 | >> TP_NVRAM_POS_LEVEL_BRIGHTNESS; | 4815 | >> TP_NVRAM_POS_LEVEL_BRIGHTNESS; |
4816 | lcmos &= (tp_features.bright_16levels)? 0x0f : 0x07; | 4816 | lcmos &= (tp_features.bright_16levels)? 0x0f : 0x07; |
4817 | level = lcmos; | 4817 | level = lcmos; |
4818 | } | 4818 | } |
4819 | 4819 | ||
4820 | if (brightness_mode == 3) { | 4820 | if (brightness_mode == 3) { |
4821 | *status = lec; /* Prefer EC, CMOS is just a backing store */ | 4821 | *status = lec; /* Prefer EC, CMOS is just a backing store */ |
4822 | lec &= TP_EC_BACKLIGHT_LVLMSK; | 4822 | lec &= TP_EC_BACKLIGHT_LVLMSK; |
4823 | if (lec == lcmos) | 4823 | if (lec == lcmos) |
4824 | tp_warned.bright_cmos_ec_unsync = 0; | 4824 | tp_warned.bright_cmos_ec_unsync = 0; |
4825 | else { | 4825 | else { |
4826 | if (!tp_warned.bright_cmos_ec_unsync) { | 4826 | if (!tp_warned.bright_cmos_ec_unsync) { |
4827 | printk(TPACPI_ERR | 4827 | printk(TPACPI_ERR |
4828 | "CMOS NVRAM (%u) and EC (%u) do not " | 4828 | "CMOS NVRAM (%u) and EC (%u) do not " |
4829 | "agree on display brightness level\n", | 4829 | "agree on display brightness level\n", |
4830 | (unsigned int) lcmos, | 4830 | (unsigned int) lcmos, |
4831 | (unsigned int) lec); | 4831 | (unsigned int) lec); |
4832 | tp_warned.bright_cmos_ec_unsync = 1; | 4832 | tp_warned.bright_cmos_ec_unsync = 1; |
4833 | } | 4833 | } |
4834 | return -EIO; | 4834 | return -EIO; |
4835 | } | 4835 | } |
4836 | } else { | 4836 | } else { |
4837 | *status = level; | 4837 | *status = level; |
4838 | } | 4838 | } |
4839 | 4839 | ||
4840 | return 0; | 4840 | return 0; |
4841 | } | 4841 | } |
4842 | 4842 | ||
4843 | /* May return EINTR which can always be mapped to ERESTARTSYS */ | 4843 | /* May return EINTR which can always be mapped to ERESTARTSYS */ |
4844 | static int brightness_set(int value) | 4844 | static int brightness_set(int value) |
4845 | { | 4845 | { |
4846 | int cmos_cmd, inc, i, res; | 4846 | int cmos_cmd, inc, i, res; |
4847 | int current_value; | 4847 | int current_value; |
4848 | int command_bits; | 4848 | int command_bits; |
4849 | 4849 | ||
4850 | if (value > ((tp_features.bright_16levels)? 15 : 7) || | 4850 | if (value > ((tp_features.bright_16levels)? 15 : 7) || |
4851 | value < 0) | 4851 | value < 0) |
4852 | return -EINVAL; | 4852 | return -EINVAL; |
4853 | 4853 | ||
4854 | res = mutex_lock_interruptible(&brightness_mutex); | 4854 | res = mutex_lock_interruptible(&brightness_mutex); |
4855 | if (res < 0) | 4855 | if (res < 0) |
4856 | return res; | 4856 | return res; |
4857 | 4857 | ||
4858 | res = brightness_get_raw(¤t_value); | 4858 | res = brightness_get_raw(¤t_value); |
4859 | if (res < 0) | 4859 | if (res < 0) |
4860 | goto errout; | 4860 | goto errout; |
4861 | 4861 | ||
4862 | command_bits = current_value & TP_EC_BACKLIGHT_CMDMSK; | 4862 | command_bits = current_value & TP_EC_BACKLIGHT_CMDMSK; |
4863 | current_value &= TP_EC_BACKLIGHT_LVLMSK; | 4863 | current_value &= TP_EC_BACKLIGHT_LVLMSK; |
4864 | 4864 | ||
4865 | cmos_cmd = value > current_value ? | 4865 | cmos_cmd = value > current_value ? |
4866 | TP_CMOS_BRIGHTNESS_UP : | 4866 | TP_CMOS_BRIGHTNESS_UP : |
4867 | TP_CMOS_BRIGHTNESS_DOWN; | 4867 | TP_CMOS_BRIGHTNESS_DOWN; |
4868 | inc = (value > current_value)? 1 : -1; | 4868 | inc = (value > current_value)? 1 : -1; |
4869 | 4869 | ||
4870 | res = 0; | 4870 | res = 0; |
4871 | for (i = current_value; i != value; i += inc) { | 4871 | for (i = current_value; i != value; i += inc) { |
4872 | if ((brightness_mode & 2) && | 4872 | if ((brightness_mode & 2) && |
4873 | issue_thinkpad_cmos_command(cmos_cmd)) { | 4873 | issue_thinkpad_cmos_command(cmos_cmd)) { |
4874 | res = -EIO; | 4874 | res = -EIO; |
4875 | goto errout; | 4875 | goto errout; |
4876 | } | 4876 | } |
4877 | if ((brightness_mode & 1) && | 4877 | if ((brightness_mode & 1) && |
4878 | !acpi_ec_write(TP_EC_BACKLIGHT, | 4878 | !acpi_ec_write(TP_EC_BACKLIGHT, |
4879 | (i + inc) | command_bits)) { | 4879 | (i + inc) | command_bits)) { |
4880 | res = -EIO; | 4880 | res = -EIO; |
4881 | goto errout;; | 4881 | goto errout;; |
4882 | } | 4882 | } |
4883 | } | 4883 | } |
4884 | 4884 | ||
4885 | errout: | 4885 | errout: |
4886 | mutex_unlock(&brightness_mutex); | 4886 | mutex_unlock(&brightness_mutex); |
4887 | return res; | 4887 | return res; |
4888 | } | 4888 | } |
4889 | 4889 | ||
4890 | /* sysfs backlight class ----------------------------------------------- */ | 4890 | /* sysfs backlight class ----------------------------------------------- */ |
4891 | 4891 | ||
4892 | static int brightness_update_status(struct backlight_device *bd) | 4892 | static int brightness_update_status(struct backlight_device *bd) |
4893 | { | 4893 | { |
4894 | /* it is the backlight class's job (caller) to handle | 4894 | /* it is the backlight class's job (caller) to handle |
4895 | * EINTR and other errors properly */ | 4895 | * EINTR and other errors properly */ |
4896 | return brightness_set( | 4896 | return brightness_set( |
4897 | (bd->props.fb_blank == FB_BLANK_UNBLANK && | 4897 | (bd->props.fb_blank == FB_BLANK_UNBLANK && |
4898 | bd->props.power == FB_BLANK_UNBLANK) ? | 4898 | bd->props.power == FB_BLANK_UNBLANK) ? |
4899 | bd->props.brightness : 0); | 4899 | bd->props.brightness : 0); |
4900 | } | 4900 | } |
4901 | 4901 | ||
4902 | static int brightness_get(struct backlight_device *bd) | 4902 | static int brightness_get(struct backlight_device *bd) |
4903 | { | 4903 | { |
4904 | int status, res; | 4904 | int status, res; |
4905 | 4905 | ||
4906 | res = brightness_get_raw(&status); | 4906 | res = brightness_get_raw(&status); |
4907 | if (res < 0) | 4907 | if (res < 0) |
4908 | return 0; /* FIXME: teach backlight about error handling */ | 4908 | return 0; /* FIXME: teach backlight about error handling */ |
4909 | 4909 | ||
4910 | return status & TP_EC_BACKLIGHT_LVLMSK; | 4910 | return status & TP_EC_BACKLIGHT_LVLMSK; |
4911 | } | 4911 | } |
4912 | 4912 | ||
4913 | static struct backlight_ops ibm_backlight_data = { | 4913 | static struct backlight_ops ibm_backlight_data = { |
4914 | .get_brightness = brightness_get, | 4914 | .get_brightness = brightness_get, |
4915 | .update_status = brightness_update_status, | 4915 | .update_status = brightness_update_status, |
4916 | }; | 4916 | }; |
4917 | 4917 | ||
4918 | /* --------------------------------------------------------------------- */ | 4918 | /* --------------------------------------------------------------------- */ |
4919 | 4919 | ||
4920 | static int __init brightness_init(struct ibm_init_struct *iibm) | 4920 | static int __init brightness_init(struct ibm_init_struct *iibm) |
4921 | { | 4921 | { |
4922 | int b; | 4922 | int b; |
4923 | 4923 | ||
4924 | vdbg_printk(TPACPI_DBG_INIT, "initializing brightness subdriver\n"); | 4924 | vdbg_printk(TPACPI_DBG_INIT, "initializing brightness subdriver\n"); |
4925 | 4925 | ||
4926 | mutex_init(&brightness_mutex); | 4926 | mutex_init(&brightness_mutex); |
4927 | 4927 | ||
4928 | /* | 4928 | /* |
4929 | * We always attempt to detect acpi support, so as to switch | 4929 | * We always attempt to detect acpi support, so as to switch |
4930 | * Lenovo Vista BIOS to ACPI brightness mode even if we are not | 4930 | * Lenovo Vista BIOS to ACPI brightness mode even if we are not |
4931 | * going to publish a backlight interface | 4931 | * going to publish a backlight interface |
4932 | */ | 4932 | */ |
4933 | b = tpacpi_check_std_acpi_brightness_support(); | 4933 | b = tpacpi_check_std_acpi_brightness_support(); |
4934 | if (b > 0) { | 4934 | if (b > 0) { |
4935 | if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) { | 4935 | |
4936 | printk(TPACPI_NOTICE | 4936 | if (acpi_video_backlight_support()) { |
4937 | "Lenovo BIOS switched to ACPI backlight " | 4937 | if (brightness_enable > 1) { |
4938 | "control mode\n"); | 4938 | printk(TPACPI_NOTICE |
4939 | } | 4939 | "Standard ACPI backlight interface " |
4940 | if (brightness_enable > 1) { | 4940 | "available, not loading native one.\n"); |
4941 | printk(TPACPI_NOTICE | 4941 | return 1; |
4942 | "standard ACPI backlight interface " | 4942 | } else if (brightness_enable == 1) { |
4943 | "available, not loading native one...\n"); | 4943 | printk(TPACPI_NOTICE |
4944 | return 1; | 4944 | "Backlight control force enabled, even if standard " |
4945 | "ACPI backlight interface is available\n"); | ||
4946 | } | ||
4947 | } else { | ||
4948 | if (brightness_enable > 1) { | ||
4949 | printk(TPACPI_NOTICE | ||
4950 | "Standard ACPI backlight interface not " | ||
4951 | "available, thinkpad_acpi native " | ||
4952 | "brightness control enabled\n"); | ||
4953 | } | ||
4945 | } | 4954 | } |
4946 | } | 4955 | } |
4947 | 4956 | ||
4948 | if (!brightness_enable) { | 4957 | if (!brightness_enable) { |
4949 | dbg_printk(TPACPI_DBG_INIT, | 4958 | dbg_printk(TPACPI_DBG_INIT, |
4950 | "brightness support disabled by " | 4959 | "brightness support disabled by " |
4951 | "module parameter\n"); | 4960 | "module parameter\n"); |
4952 | return 1; | 4961 | return 1; |
4953 | } | 4962 | } |
4954 | 4963 | ||
4955 | if (b > 16) { | 4964 | if (b > 16) { |
4956 | printk(TPACPI_ERR | 4965 | printk(TPACPI_ERR |
4957 | "Unsupported brightness interface, " | 4966 | "Unsupported brightness interface, " |
4958 | "please contact %s\n", TPACPI_MAIL); | 4967 | "please contact %s\n", TPACPI_MAIL); |
4959 | return 1; | 4968 | return 1; |
4960 | } | 4969 | } |
4961 | if (b == 16) | 4970 | if (b == 16) |
4962 | tp_features.bright_16levels = 1; | 4971 | tp_features.bright_16levels = 1; |
4963 | 4972 | ||
4964 | if (!brightness_mode) { | 4973 | if (!brightness_mode) { |
4965 | if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) | 4974 | if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) |
4966 | brightness_mode = 2; | 4975 | brightness_mode = 2; |
4967 | else | 4976 | else |
4968 | brightness_mode = 3; | 4977 | brightness_mode = 3; |
4969 | 4978 | ||
4970 | dbg_printk(TPACPI_DBG_INIT, "selected brightness_mode=%d\n", | 4979 | dbg_printk(TPACPI_DBG_INIT, "selected brightness_mode=%d\n", |
4971 | brightness_mode); | 4980 | brightness_mode); |
4972 | } | 4981 | } |
4973 | 4982 | ||
4974 | if (brightness_mode > 3) | 4983 | if (brightness_mode > 3) |
4975 | return -EINVAL; | 4984 | return -EINVAL; |
4976 | 4985 | ||
4977 | if (brightness_get_raw(&b) < 0) | 4986 | if (brightness_get_raw(&b) < 0) |
4978 | return 1; | 4987 | return 1; |
4979 | 4988 | ||
4980 | if (tp_features.bright_16levels) | 4989 | if (tp_features.bright_16levels) |
4981 | printk(TPACPI_INFO | 4990 | printk(TPACPI_INFO |
4982 | "detected a 16-level brightness capable ThinkPad\n"); | 4991 | "detected a 16-level brightness capable ThinkPad\n"); |
4983 | 4992 | ||
4984 | ibm_backlight_device = backlight_device_register( | 4993 | ibm_backlight_device = backlight_device_register( |
4985 | TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL, | 4994 | TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL, |
4986 | &ibm_backlight_data); | 4995 | &ibm_backlight_data); |
4987 | if (IS_ERR(ibm_backlight_device)) { | 4996 | if (IS_ERR(ibm_backlight_device)) { |
4988 | printk(TPACPI_ERR "Could not register backlight device\n"); | 4997 | printk(TPACPI_ERR "Could not register backlight device\n"); |
4989 | return PTR_ERR(ibm_backlight_device); | 4998 | return PTR_ERR(ibm_backlight_device); |
4990 | } | 4999 | } |
4991 | vdbg_printk(TPACPI_DBG_INIT, "brightness is supported\n"); | 5000 | vdbg_printk(TPACPI_DBG_INIT, "brightness is supported\n"); |
4992 | 5001 | ||
4993 | ibm_backlight_device->props.max_brightness = | 5002 | ibm_backlight_device->props.max_brightness = |
4994 | (tp_features.bright_16levels)? 15 : 7; | 5003 | (tp_features.bright_16levels)? 15 : 7; |
4995 | ibm_backlight_device->props.brightness = b & TP_EC_BACKLIGHT_LVLMSK; | 5004 | ibm_backlight_device->props.brightness = b & TP_EC_BACKLIGHT_LVLMSK; |
4996 | backlight_update_status(ibm_backlight_device); | 5005 | backlight_update_status(ibm_backlight_device); |
4997 | 5006 | ||
4998 | return 0; | 5007 | return 0; |
4999 | } | 5008 | } |
5000 | 5009 | ||
5001 | static void brightness_exit(void) | 5010 | static void brightness_exit(void) |
5002 | { | 5011 | { |
5003 | if (ibm_backlight_device) { | 5012 | if (ibm_backlight_device) { |
5004 | vdbg_printk(TPACPI_DBG_EXIT, | 5013 | vdbg_printk(TPACPI_DBG_EXIT, |
5005 | "calling backlight_device_unregister()\n"); | 5014 | "calling backlight_device_unregister()\n"); |
5006 | backlight_device_unregister(ibm_backlight_device); | 5015 | backlight_device_unregister(ibm_backlight_device); |
5007 | } | 5016 | } |
5008 | } | 5017 | } |
5009 | 5018 | ||
5010 | static int brightness_read(char *p) | 5019 | static int brightness_read(char *p) |
5011 | { | 5020 | { |
5012 | int len = 0; | 5021 | int len = 0; |
5013 | int level; | 5022 | int level; |
5014 | 5023 | ||
5015 | level = brightness_get(NULL); | 5024 | level = brightness_get(NULL); |
5016 | if (level < 0) { | 5025 | if (level < 0) { |
5017 | len += sprintf(p + len, "level:\t\tunreadable\n"); | 5026 | len += sprintf(p + len, "level:\t\tunreadable\n"); |
5018 | } else { | 5027 | } else { |
5019 | len += sprintf(p + len, "level:\t\t%d\n", level); | 5028 | len += sprintf(p + len, "level:\t\t%d\n", level); |
5020 | len += sprintf(p + len, "commands:\tup, down\n"); | 5029 | len += sprintf(p + len, "commands:\tup, down\n"); |
5021 | len += sprintf(p + len, "commands:\tlevel <level>" | 5030 | len += sprintf(p + len, "commands:\tlevel <level>" |
5022 | " (<level> is 0-%d)\n", | 5031 | " (<level> is 0-%d)\n", |
5023 | (tp_features.bright_16levels) ? 15 : 7); | 5032 | (tp_features.bright_16levels) ? 15 : 7); |
5024 | } | 5033 | } |
5025 | 5034 | ||
5026 | return len; | 5035 | return len; |
5027 | } | 5036 | } |
5028 | 5037 | ||
5029 | static int brightness_write(char *buf) | 5038 | static int brightness_write(char *buf) |
5030 | { | 5039 | { |
5031 | int level; | 5040 | int level; |
5032 | int rc; | 5041 | int rc; |
5033 | char *cmd; | 5042 | char *cmd; |
5034 | int max_level = (tp_features.bright_16levels) ? 15 : 7; | 5043 | int max_level = (tp_features.bright_16levels) ? 15 : 7; |
5035 | 5044 | ||
5036 | level = brightness_get(NULL); | 5045 | level = brightness_get(NULL); |
5037 | if (level < 0) | 5046 | if (level < 0) |
5038 | return level; | 5047 | return level; |
5039 | 5048 | ||
5040 | while ((cmd = next_cmd(&buf))) { | 5049 | while ((cmd = next_cmd(&buf))) { |
5041 | if (strlencmp(cmd, "up") == 0) { | 5050 | if (strlencmp(cmd, "up") == 0) { |
5042 | if (level < max_level) | 5051 | if (level < max_level) |
5043 | level++; | 5052 | level++; |
5044 | } else if (strlencmp(cmd, "down") == 0) { | 5053 | } else if (strlencmp(cmd, "down") == 0) { |
5045 | if (level > 0) | 5054 | if (level > 0) |
5046 | level--; | 5055 | level--; |
5047 | } else if (sscanf(cmd, "level %d", &level) == 1 && | 5056 | } else if (sscanf(cmd, "level %d", &level) == 1 && |
5048 | level >= 0 && level <= max_level) { | 5057 | level >= 0 && level <= max_level) { |
5049 | /* new level set */ | 5058 | /* new level set */ |
5050 | } else | 5059 | } else |
5051 | return -EINVAL; | 5060 | return -EINVAL; |
5052 | } | 5061 | } |
5053 | 5062 | ||
5054 | /* | 5063 | /* |
5055 | * Now we know what the final level should be, so we try to set it. | 5064 | * Now we know what the final level should be, so we try to set it. |
5056 | * Doing it this way makes the syscall restartable in case of EINTR | 5065 | * Doing it this way makes the syscall restartable in case of EINTR |
5057 | */ | 5066 | */ |
5058 | rc = brightness_set(level); | 5067 | rc = brightness_set(level); |
5059 | return (rc == -EINTR)? ERESTARTSYS : rc; | 5068 | return (rc == -EINTR)? ERESTARTSYS : rc; |
5060 | } | 5069 | } |
5061 | 5070 | ||
5062 | static struct ibm_struct brightness_driver_data = { | 5071 | static struct ibm_struct brightness_driver_data = { |
5063 | .name = "brightness", | 5072 | .name = "brightness", |
5064 | .read = brightness_read, | 5073 | .read = brightness_read, |
5065 | .write = brightness_write, | 5074 | .write = brightness_write, |
5066 | .exit = brightness_exit, | 5075 | .exit = brightness_exit, |
5067 | }; | 5076 | }; |
5068 | 5077 | ||
5069 | /************************************************************************* | 5078 | /************************************************************************* |
5070 | * Volume subdriver | 5079 | * Volume subdriver |
5071 | */ | 5080 | */ |
5072 | 5081 | ||
5073 | static int volume_offset = 0x30; | 5082 | static int volume_offset = 0x30; |
5074 | 5083 | ||
5075 | static int volume_read(char *p) | 5084 | static int volume_read(char *p) |
5076 | { | 5085 | { |
5077 | int len = 0; | 5086 | int len = 0; |
5078 | u8 level; | 5087 | u8 level; |
5079 | 5088 | ||
5080 | if (!acpi_ec_read(volume_offset, &level)) { | 5089 | if (!acpi_ec_read(volume_offset, &level)) { |
5081 | len += sprintf(p + len, "level:\t\tunreadable\n"); | 5090 | len += sprintf(p + len, "level:\t\tunreadable\n"); |
5082 | } else { | 5091 | } else { |
5083 | len += sprintf(p + len, "level:\t\t%d\n", level & 0xf); | 5092 | len += sprintf(p + len, "level:\t\t%d\n", level & 0xf); |
5084 | len += sprintf(p + len, "mute:\t\t%s\n", onoff(level, 6)); | 5093 | len += sprintf(p + len, "mute:\t\t%s\n", onoff(level, 6)); |
5085 | len += sprintf(p + len, "commands:\tup, down, mute\n"); | 5094 | len += sprintf(p + len, "commands:\tup, down, mute\n"); |
5086 | len += sprintf(p + len, "commands:\tlevel <level>" | 5095 | len += sprintf(p + len, "commands:\tlevel <level>" |
5087 | " (<level> is 0-15)\n"); | 5096 | " (<level> is 0-15)\n"); |
5088 | } | 5097 | } |
5089 | 5098 | ||
5090 | return len; | 5099 | return len; |
5091 | } | 5100 | } |
5092 | 5101 | ||
5093 | static int volume_write(char *buf) | 5102 | static int volume_write(char *buf) |
5094 | { | 5103 | { |
5095 | int cmos_cmd, inc, i; | 5104 | int cmos_cmd, inc, i; |
5096 | u8 level, mute; | 5105 | u8 level, mute; |
5097 | int new_level, new_mute; | 5106 | int new_level, new_mute; |
5098 | char *cmd; | 5107 | char *cmd; |
5099 | 5108 | ||
5100 | while ((cmd = next_cmd(&buf))) { | 5109 | while ((cmd = next_cmd(&buf))) { |
5101 | if (!acpi_ec_read(volume_offset, &level)) | 5110 | if (!acpi_ec_read(volume_offset, &level)) |
5102 | return -EIO; | 5111 | return -EIO; |
5103 | new_mute = mute = level & 0x40; | 5112 | new_mute = mute = level & 0x40; |
5104 | new_level = level = level & 0xf; | 5113 | new_level = level = level & 0xf; |
5105 | 5114 | ||
5106 | if (strlencmp(cmd, "up") == 0) { | 5115 | if (strlencmp(cmd, "up") == 0) { |
5107 | if (mute) | 5116 | if (mute) |
5108 | new_mute = 0; | 5117 | new_mute = 0; |
5109 | else | 5118 | else |
5110 | new_level = level == 15 ? 15 : level + 1; | 5119 | new_level = level == 15 ? 15 : level + 1; |
5111 | } else if (strlencmp(cmd, "down") == 0) { | 5120 | } else if (strlencmp(cmd, "down") == 0) { |
5112 | if (mute) | 5121 | if (mute) |
5113 | new_mute = 0; | 5122 | new_mute = 0; |
5114 | else | 5123 | else |
5115 | new_level = level == 0 ? 0 : level - 1; | 5124 | new_level = level == 0 ? 0 : level - 1; |
5116 | } else if (sscanf(cmd, "level %d", &new_level) == 1 && | 5125 | } else if (sscanf(cmd, "level %d", &new_level) == 1 && |
5117 | new_level >= 0 && new_level <= 15) { | 5126 | new_level >= 0 && new_level <= 15) { |
5118 | /* new_level set */ | 5127 | /* new_level set */ |
5119 | } else if (strlencmp(cmd, "mute") == 0) { | 5128 | } else if (strlencmp(cmd, "mute") == 0) { |
5120 | new_mute = 0x40; | 5129 | new_mute = 0x40; |
5121 | } else | 5130 | } else |
5122 | return -EINVAL; | 5131 | return -EINVAL; |
5123 | 5132 | ||
5124 | if (new_level != level) { | 5133 | if (new_level != level) { |
5125 | /* mute doesn't change */ | 5134 | /* mute doesn't change */ |
5126 | 5135 | ||
5127 | cmos_cmd = (new_level > level) ? | 5136 | cmos_cmd = (new_level > level) ? |
5128 | TP_CMOS_VOLUME_UP : TP_CMOS_VOLUME_DOWN; | 5137 | TP_CMOS_VOLUME_UP : TP_CMOS_VOLUME_DOWN; |
5129 | inc = new_level > level ? 1 : -1; | 5138 | inc = new_level > level ? 1 : -1; |
5130 | 5139 | ||
5131 | if (mute && (issue_thinkpad_cmos_command(cmos_cmd) || | 5140 | if (mute && (issue_thinkpad_cmos_command(cmos_cmd) || |
5132 | !acpi_ec_write(volume_offset, level))) | 5141 | !acpi_ec_write(volume_offset, level))) |
5133 | return -EIO; | 5142 | return -EIO; |
5134 | 5143 | ||
5135 | for (i = level; i != new_level; i += inc) | 5144 | for (i = level; i != new_level; i += inc) |
5136 | if (issue_thinkpad_cmos_command(cmos_cmd) || | 5145 | if (issue_thinkpad_cmos_command(cmos_cmd) || |
5137 | !acpi_ec_write(volume_offset, i + inc)) | 5146 | !acpi_ec_write(volume_offset, i + inc)) |
5138 | return -EIO; | 5147 | return -EIO; |
5139 | 5148 | ||
5140 | if (mute && | 5149 | if (mute && |
5141 | (issue_thinkpad_cmos_command(TP_CMOS_VOLUME_MUTE) || | 5150 | (issue_thinkpad_cmos_command(TP_CMOS_VOLUME_MUTE) || |
5142 | !acpi_ec_write(volume_offset, new_level + mute))) { | 5151 | !acpi_ec_write(volume_offset, new_level + mute))) { |
5143 | return -EIO; | 5152 | return -EIO; |
5144 | } | 5153 | } |
5145 | } | 5154 | } |
5146 | 5155 | ||
5147 | if (new_mute != mute) { | 5156 | if (new_mute != mute) { |
5148 | /* level doesn't change */ | 5157 | /* level doesn't change */ |
5149 | 5158 | ||
5150 | cmos_cmd = (new_mute) ? | 5159 | cmos_cmd = (new_mute) ? |
5151 | TP_CMOS_VOLUME_MUTE : TP_CMOS_VOLUME_UP; | 5160 | TP_CMOS_VOLUME_MUTE : TP_CMOS_VOLUME_UP; |
5152 | 5161 | ||
5153 | if (issue_thinkpad_cmos_command(cmos_cmd) || | 5162 | if (issue_thinkpad_cmos_command(cmos_cmd) || |
5154 | !acpi_ec_write(volume_offset, level + new_mute)) | 5163 | !acpi_ec_write(volume_offset, level + new_mute)) |
5155 | return -EIO; | 5164 | return -EIO; |
5156 | } | 5165 | } |
5157 | } | 5166 | } |
5158 | 5167 | ||
5159 | return 0; | 5168 | return 0; |
5160 | } | 5169 | } |
5161 | 5170 | ||
5162 | static struct ibm_struct volume_driver_data = { | 5171 | static struct ibm_struct volume_driver_data = { |
5163 | .name = "volume", | 5172 | .name = "volume", |
5164 | .read = volume_read, | 5173 | .read = volume_read, |
5165 | .write = volume_write, | 5174 | .write = volume_write, |
5166 | }; | 5175 | }; |
5167 | 5176 | ||
5168 | /************************************************************************* | 5177 | /************************************************************************* |
5169 | * Fan subdriver | 5178 | * Fan subdriver |
5170 | */ | 5179 | */ |
5171 | 5180 | ||
5172 | /* | 5181 | /* |
5173 | * FAN ACCESS MODES | 5182 | * FAN ACCESS MODES |
5174 | * | 5183 | * |
5175 | * TPACPI_FAN_RD_ACPI_GFAN: | 5184 | * TPACPI_FAN_RD_ACPI_GFAN: |
5176 | * ACPI GFAN method: returns fan level | 5185 | * ACPI GFAN method: returns fan level |
5177 | * | 5186 | * |
5178 | * see TPACPI_FAN_WR_ACPI_SFAN | 5187 | * see TPACPI_FAN_WR_ACPI_SFAN |
5179 | * EC 0x2f (HFSP) not available if GFAN exists | 5188 | * EC 0x2f (HFSP) not available if GFAN exists |
5180 | * | 5189 | * |
5181 | * TPACPI_FAN_WR_ACPI_SFAN: | 5190 | * TPACPI_FAN_WR_ACPI_SFAN: |
5182 | * ACPI SFAN method: sets fan level, 0 (stop) to 7 (max) | 5191 | * ACPI SFAN method: sets fan level, 0 (stop) to 7 (max) |
5183 | * | 5192 | * |
5184 | * EC 0x2f (HFSP) might be available *for reading*, but do not use | 5193 | * EC 0x2f (HFSP) might be available *for reading*, but do not use |
5185 | * it for writing. | 5194 | * it for writing. |
5186 | * | 5195 | * |
5187 | * TPACPI_FAN_WR_TPEC: | 5196 | * TPACPI_FAN_WR_TPEC: |
5188 | * ThinkPad EC register 0x2f (HFSP): fan control loop mode | 5197 | * ThinkPad EC register 0x2f (HFSP): fan control loop mode |
5189 | * Supported on almost all ThinkPads | 5198 | * Supported on almost all ThinkPads |
5190 | * | 5199 | * |
5191 | * Fan speed changes of any sort (including those caused by the | 5200 | * Fan speed changes of any sort (including those caused by the |
5192 | * disengaged mode) are usually done slowly by the firmware as the | 5201 | * disengaged mode) are usually done slowly by the firmware as the |
5193 | * maximum ammount of fan duty cycle change per second seems to be | 5202 | * maximum ammount of fan duty cycle change per second seems to be |
5194 | * limited. | 5203 | * limited. |
5195 | * | 5204 | * |
5196 | * Reading is not available if GFAN exists. | 5205 | * Reading is not available if GFAN exists. |
5197 | * Writing is not available if SFAN exists. | 5206 | * Writing is not available if SFAN exists. |
5198 | * | 5207 | * |
5199 | * Bits | 5208 | * Bits |
5200 | * 7 automatic mode engaged; | 5209 | * 7 automatic mode engaged; |
5201 | * (default operation mode of the ThinkPad) | 5210 | * (default operation mode of the ThinkPad) |
5202 | * fan level is ignored in this mode. | 5211 | * fan level is ignored in this mode. |
5203 | * 6 full speed mode (takes precedence over bit 7); | 5212 | * 6 full speed mode (takes precedence over bit 7); |
5204 | * not available on all thinkpads. May disable | 5213 | * not available on all thinkpads. May disable |
5205 | * the tachometer while the fan controller ramps up | 5214 | * the tachometer while the fan controller ramps up |
5206 | * the speed (which can take up to a few *minutes*). | 5215 | * the speed (which can take up to a few *minutes*). |
5207 | * Speeds up fan to 100% duty-cycle, which is far above | 5216 | * Speeds up fan to 100% duty-cycle, which is far above |
5208 | * the standard RPM levels. It is not impossible that | 5217 | * the standard RPM levels. It is not impossible that |
5209 | * it could cause hardware damage. | 5218 | * it could cause hardware damage. |
5210 | * 5-3 unused in some models. Extra bits for fan level | 5219 | * 5-3 unused in some models. Extra bits for fan level |
5211 | * in others, but still useless as all values above | 5220 | * in others, but still useless as all values above |
5212 | * 7 map to the same speed as level 7 in these models. | 5221 | * 7 map to the same speed as level 7 in these models. |
5213 | * 2-0 fan level (0..7 usually) | 5222 | * 2-0 fan level (0..7 usually) |
5214 | * 0x00 = stop | 5223 | * 0x00 = stop |
5215 | * 0x07 = max (set when temperatures critical) | 5224 | * 0x07 = max (set when temperatures critical) |
5216 | * Some ThinkPads may have other levels, see | 5225 | * Some ThinkPads may have other levels, see |
5217 | * TPACPI_FAN_WR_ACPI_FANS (X31/X40/X41) | 5226 | * TPACPI_FAN_WR_ACPI_FANS (X31/X40/X41) |
5218 | * | 5227 | * |
5219 | * FIRMWARE BUG: on some models, EC 0x2f might not be initialized at | 5228 | * FIRMWARE BUG: on some models, EC 0x2f might not be initialized at |
5220 | * boot. Apparently the EC does not intialize it, so unless ACPI DSDT | 5229 | * boot. Apparently the EC does not intialize it, so unless ACPI DSDT |
5221 | * does so, its initial value is meaningless (0x07). | 5230 | * does so, its initial value is meaningless (0x07). |
5222 | * | 5231 | * |
5223 | * For firmware bugs, refer to: | 5232 | * For firmware bugs, refer to: |
5224 | * http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues | 5233 | * http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues |
5225 | * | 5234 | * |
5226 | * ---- | 5235 | * ---- |
5227 | * | 5236 | * |
5228 | * ThinkPad EC register 0x84 (LSB), 0x85 (MSB): | 5237 | * ThinkPad EC register 0x84 (LSB), 0x85 (MSB): |
5229 | * Main fan tachometer reading (in RPM) | 5238 | * Main fan tachometer reading (in RPM) |
5230 | * | 5239 | * |
5231 | * This register is present on all ThinkPads with a new-style EC, and | 5240 | * This register is present on all ThinkPads with a new-style EC, and |
5232 | * it is known not to be present on the A21m/e, and T22, as there is | 5241 | * it is known not to be present on the A21m/e, and T22, as there is |
5233 | * something else in offset 0x84 according to the ACPI DSDT. Other | 5242 | * something else in offset 0x84 according to the ACPI DSDT. Other |
5234 | * ThinkPads from this same time period (and earlier) probably lack the | 5243 | * ThinkPads from this same time period (and earlier) probably lack the |
5235 | * tachometer as well. | 5244 | * tachometer as well. |
5236 | * | 5245 | * |
5237 | * Unfortunately a lot of ThinkPads with new-style ECs but whose firwmare | 5246 | * Unfortunately a lot of ThinkPads with new-style ECs but whose firwmare |
5238 | * was never fixed by IBM to report the EC firmware version string | 5247 | * was never fixed by IBM to report the EC firmware version string |
5239 | * probably support the tachometer (like the early X models), so | 5248 | * probably support the tachometer (like the early X models), so |
5240 | * detecting it is quite hard. We need more data to know for sure. | 5249 | * detecting it is quite hard. We need more data to know for sure. |
5241 | * | 5250 | * |
5242 | * FIRMWARE BUG: always read 0x84 first, otherwise incorrect readings | 5251 | * FIRMWARE BUG: always read 0x84 first, otherwise incorrect readings |
5243 | * might result. | 5252 | * might result. |
5244 | * | 5253 | * |
5245 | * FIRMWARE BUG: may go stale while the EC is switching to full speed | 5254 | * FIRMWARE BUG: may go stale while the EC is switching to full speed |
5246 | * mode. | 5255 | * mode. |
5247 | * | 5256 | * |
5248 | * For firmware bugs, refer to: | 5257 | * For firmware bugs, refer to: |
5249 | * http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues | 5258 | * http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues |
5250 | * | 5259 | * |
5251 | * TPACPI_FAN_WR_ACPI_FANS: | 5260 | * TPACPI_FAN_WR_ACPI_FANS: |
5252 | * ThinkPad X31, X40, X41. Not available in the X60. | 5261 | * ThinkPad X31, X40, X41. Not available in the X60. |
5253 | * | 5262 | * |
5254 | * FANS ACPI handle: takes three arguments: low speed, medium speed, | 5263 | * FANS ACPI handle: takes three arguments: low speed, medium speed, |
5255 | * high speed. ACPI DSDT seems to map these three speeds to levels | 5264 | * high speed. ACPI DSDT seems to map these three speeds to levels |
5256 | * as follows: STOP LOW LOW MED MED HIGH HIGH HIGH HIGH | 5265 | * as follows: STOP LOW LOW MED MED HIGH HIGH HIGH HIGH |
5257 | * (this map is stored on FAN0..FAN8 as "0,1,1,2,2,3,3,3,3") | 5266 | * (this map is stored on FAN0..FAN8 as "0,1,1,2,2,3,3,3,3") |
5258 | * | 5267 | * |
5259 | * The speeds are stored on handles | 5268 | * The speeds are stored on handles |
5260 | * (FANA:FAN9), (FANC:FANB), (FANE:FAND). | 5269 | * (FANA:FAN9), (FANC:FANB), (FANE:FAND). |
5261 | * | 5270 | * |
5262 | * There are three default speed sets, acessible as handles: | 5271 | * There are three default speed sets, acessible as handles: |
5263 | * FS1L,FS1M,FS1H; FS2L,FS2M,FS2H; FS3L,FS3M,FS3H | 5272 | * FS1L,FS1M,FS1H; FS2L,FS2M,FS2H; FS3L,FS3M,FS3H |
5264 | * | 5273 | * |
5265 | * ACPI DSDT switches which set is in use depending on various | 5274 | * ACPI DSDT switches which set is in use depending on various |
5266 | * factors. | 5275 | * factors. |
5267 | * | 5276 | * |
5268 | * TPACPI_FAN_WR_TPEC is also available and should be used to | 5277 | * TPACPI_FAN_WR_TPEC is also available and should be used to |
5269 | * command the fan. The X31/X40/X41 seems to have 8 fan levels, | 5278 | * command the fan. The X31/X40/X41 seems to have 8 fan levels, |
5270 | * but the ACPI tables just mention level 7. | 5279 | * but the ACPI tables just mention level 7. |
5271 | */ | 5280 | */ |
5272 | 5281 | ||
5273 | enum { /* Fan control constants */ | 5282 | enum { /* Fan control constants */ |
5274 | fan_status_offset = 0x2f, /* EC register 0x2f */ | 5283 | fan_status_offset = 0x2f, /* EC register 0x2f */ |
5275 | fan_rpm_offset = 0x84, /* EC register 0x84: LSB, 0x85 MSB (RPM) | 5284 | fan_rpm_offset = 0x84, /* EC register 0x84: LSB, 0x85 MSB (RPM) |
5276 | * 0x84 must be read before 0x85 */ | 5285 | * 0x84 must be read before 0x85 */ |
5277 | 5286 | ||
5278 | TP_EC_FAN_FULLSPEED = 0x40, /* EC fan mode: full speed */ | 5287 | TP_EC_FAN_FULLSPEED = 0x40, /* EC fan mode: full speed */ |
5279 | TP_EC_FAN_AUTO = 0x80, /* EC fan mode: auto fan control */ | 5288 | TP_EC_FAN_AUTO = 0x80, /* EC fan mode: auto fan control */ |
5280 | 5289 | ||
5281 | TPACPI_FAN_LAST_LEVEL = 0x100, /* Use cached last-seen fan level */ | 5290 | TPACPI_FAN_LAST_LEVEL = 0x100, /* Use cached last-seen fan level */ |
5282 | }; | 5291 | }; |
5283 | 5292 | ||
5284 | enum fan_status_access_mode { | 5293 | enum fan_status_access_mode { |
5285 | TPACPI_FAN_NONE = 0, /* No fan status or control */ | 5294 | TPACPI_FAN_NONE = 0, /* No fan status or control */ |
5286 | TPACPI_FAN_RD_ACPI_GFAN, /* Use ACPI GFAN */ | 5295 | TPACPI_FAN_RD_ACPI_GFAN, /* Use ACPI GFAN */ |
5287 | TPACPI_FAN_RD_TPEC, /* Use ACPI EC regs 0x2f, 0x84-0x85 */ | 5296 | TPACPI_FAN_RD_TPEC, /* Use ACPI EC regs 0x2f, 0x84-0x85 */ |
5288 | }; | 5297 | }; |
5289 | 5298 | ||
5290 | enum fan_control_access_mode { | 5299 | enum fan_control_access_mode { |
5291 | TPACPI_FAN_WR_NONE = 0, /* No fan control */ | 5300 | TPACPI_FAN_WR_NONE = 0, /* No fan control */ |
5292 | TPACPI_FAN_WR_ACPI_SFAN, /* Use ACPI SFAN */ | 5301 | TPACPI_FAN_WR_ACPI_SFAN, /* Use ACPI SFAN */ |
5293 | TPACPI_FAN_WR_TPEC, /* Use ACPI EC reg 0x2f */ | 5302 | TPACPI_FAN_WR_TPEC, /* Use ACPI EC reg 0x2f */ |
5294 | TPACPI_FAN_WR_ACPI_FANS, /* Use ACPI FANS and EC reg 0x2f */ | 5303 | TPACPI_FAN_WR_ACPI_FANS, /* Use ACPI FANS and EC reg 0x2f */ |
5295 | }; | 5304 | }; |
5296 | 5305 | ||
5297 | enum fan_control_commands { | 5306 | enum fan_control_commands { |
5298 | TPACPI_FAN_CMD_SPEED = 0x0001, /* speed command */ | 5307 | TPACPI_FAN_CMD_SPEED = 0x0001, /* speed command */ |
5299 | TPACPI_FAN_CMD_LEVEL = 0x0002, /* level command */ | 5308 | TPACPI_FAN_CMD_LEVEL = 0x0002, /* level command */ |
5300 | TPACPI_FAN_CMD_ENABLE = 0x0004, /* enable/disable cmd, | 5309 | TPACPI_FAN_CMD_ENABLE = 0x0004, /* enable/disable cmd, |
5301 | * and also watchdog cmd */ | 5310 | * and also watchdog cmd */ |
5302 | }; | 5311 | }; |
5303 | 5312 | ||
5304 | static int fan_control_allowed; | 5313 | static int fan_control_allowed; |
5305 | 5314 | ||
5306 | static enum fan_status_access_mode fan_status_access_mode; | 5315 | static enum fan_status_access_mode fan_status_access_mode; |
5307 | static enum fan_control_access_mode fan_control_access_mode; | 5316 | static enum fan_control_access_mode fan_control_access_mode; |
5308 | static enum fan_control_commands fan_control_commands; | 5317 | static enum fan_control_commands fan_control_commands; |
5309 | 5318 | ||
5310 | static u8 fan_control_initial_status; | 5319 | static u8 fan_control_initial_status; |
5311 | static u8 fan_control_desired_level; | 5320 | static u8 fan_control_desired_level; |
5312 | static int fan_watchdog_maxinterval; | 5321 | static int fan_watchdog_maxinterval; |
5313 | 5322 | ||
5314 | static struct mutex fan_mutex; | 5323 | static struct mutex fan_mutex; |
5315 | 5324 | ||
5316 | static void fan_watchdog_fire(struct work_struct *ignored); | 5325 | static void fan_watchdog_fire(struct work_struct *ignored); |
5317 | static DECLARE_DELAYED_WORK(fan_watchdog_task, fan_watchdog_fire); | 5326 | static DECLARE_DELAYED_WORK(fan_watchdog_task, fan_watchdog_fire); |
5318 | 5327 | ||
5319 | TPACPI_HANDLE(fans, ec, "FANS"); /* X31, X40, X41 */ | 5328 | TPACPI_HANDLE(fans, ec, "FANS"); /* X31, X40, X41 */ |
5320 | TPACPI_HANDLE(gfan, ec, "GFAN", /* 570 */ | 5329 | TPACPI_HANDLE(gfan, ec, "GFAN", /* 570 */ |
5321 | "\\FSPD", /* 600e/x, 770e, 770x */ | 5330 | "\\FSPD", /* 600e/x, 770e, 770x */ |
5322 | ); /* all others */ | 5331 | ); /* all others */ |
5323 | TPACPI_HANDLE(sfan, ec, "SFAN", /* 570 */ | 5332 | TPACPI_HANDLE(sfan, ec, "SFAN", /* 570 */ |
5324 | "JFNS", /* 770x-JL */ | 5333 | "JFNS", /* 770x-JL */ |
5325 | ); /* all others */ | 5334 | ); /* all others */ |
5326 | 5335 | ||
5327 | /* | 5336 | /* |
5328 | * Call with fan_mutex held | 5337 | * Call with fan_mutex held |
5329 | */ | 5338 | */ |
5330 | static void fan_update_desired_level(u8 status) | 5339 | static void fan_update_desired_level(u8 status) |
5331 | { | 5340 | { |
5332 | if ((status & | 5341 | if ((status & |
5333 | (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) == 0) { | 5342 | (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) == 0) { |
5334 | if (status > 7) | 5343 | if (status > 7) |
5335 | fan_control_desired_level = 7; | 5344 | fan_control_desired_level = 7; |
5336 | else | 5345 | else |
5337 | fan_control_desired_level = status; | 5346 | fan_control_desired_level = status; |
5338 | } | 5347 | } |
5339 | } | 5348 | } |
5340 | 5349 | ||
5341 | static int fan_get_status(u8 *status) | 5350 | static int fan_get_status(u8 *status) |
5342 | { | 5351 | { |
5343 | u8 s; | 5352 | u8 s; |
5344 | 5353 | ||
5345 | /* TODO: | 5354 | /* TODO: |
5346 | * Add TPACPI_FAN_RD_ACPI_FANS ? */ | 5355 | * Add TPACPI_FAN_RD_ACPI_FANS ? */ |
5347 | 5356 | ||
5348 | switch (fan_status_access_mode) { | 5357 | switch (fan_status_access_mode) { |
5349 | case TPACPI_FAN_RD_ACPI_GFAN: | 5358 | case TPACPI_FAN_RD_ACPI_GFAN: |
5350 | /* 570, 600e/x, 770e, 770x */ | 5359 | /* 570, 600e/x, 770e, 770x */ |
5351 | 5360 | ||
5352 | if (unlikely(!acpi_evalf(gfan_handle, &s, NULL, "d"))) | 5361 | if (unlikely(!acpi_evalf(gfan_handle, &s, NULL, "d"))) |
5353 | return -EIO; | 5362 | return -EIO; |
5354 | 5363 | ||
5355 | if (likely(status)) | 5364 | if (likely(status)) |
5356 | *status = s & 0x07; | 5365 | *status = s & 0x07; |
5357 | 5366 | ||
5358 | break; | 5367 | break; |
5359 | 5368 | ||
5360 | case TPACPI_FAN_RD_TPEC: | 5369 | case TPACPI_FAN_RD_TPEC: |
5361 | /* all except 570, 600e/x, 770e, 770x */ | 5370 | /* all except 570, 600e/x, 770e, 770x */ |
5362 | if (unlikely(!acpi_ec_read(fan_status_offset, &s))) | 5371 | if (unlikely(!acpi_ec_read(fan_status_offset, &s))) |
5363 | return -EIO; | 5372 | return -EIO; |
5364 | 5373 | ||
5365 | if (likely(status)) | 5374 | if (likely(status)) |
5366 | *status = s; | 5375 | *status = s; |
5367 | 5376 | ||
5368 | break; | 5377 | break; |
5369 | 5378 | ||
5370 | default: | 5379 | default: |
5371 | return -ENXIO; | 5380 | return -ENXIO; |
5372 | } | 5381 | } |
5373 | 5382 | ||
5374 | return 0; | 5383 | return 0; |
5375 | } | 5384 | } |
5376 | 5385 | ||
5377 | static int fan_get_status_safe(u8 *status) | 5386 | static int fan_get_status_safe(u8 *status) |
5378 | { | 5387 | { |
5379 | int rc; | 5388 | int rc; |
5380 | u8 s; | 5389 | u8 s; |
5381 | 5390 | ||
5382 | if (mutex_lock_interruptible(&fan_mutex)) | 5391 | if (mutex_lock_interruptible(&fan_mutex)) |
5383 | return -ERESTARTSYS; | 5392 | return -ERESTARTSYS; |
5384 | rc = fan_get_status(&s); | 5393 | rc = fan_get_status(&s); |
5385 | if (!rc) | 5394 | if (!rc) |
5386 | fan_update_desired_level(s); | 5395 | fan_update_desired_level(s); |
5387 | mutex_unlock(&fan_mutex); | 5396 | mutex_unlock(&fan_mutex); |
5388 | 5397 | ||
5389 | if (status) | 5398 | if (status) |
5390 | *status = s; | 5399 | *status = s; |
5391 | 5400 | ||
5392 | return rc; | 5401 | return rc; |
5393 | } | 5402 | } |
5394 | 5403 | ||
5395 | static int fan_get_speed(unsigned int *speed) | 5404 | static int fan_get_speed(unsigned int *speed) |
5396 | { | 5405 | { |
5397 | u8 hi, lo; | 5406 | u8 hi, lo; |
5398 | 5407 | ||
5399 | switch (fan_status_access_mode) { | 5408 | switch (fan_status_access_mode) { |
5400 | case TPACPI_FAN_RD_TPEC: | 5409 | case TPACPI_FAN_RD_TPEC: |
5401 | /* all except 570, 600e/x, 770e, 770x */ | 5410 | /* all except 570, 600e/x, 770e, 770x */ |
5402 | if (unlikely(!acpi_ec_read(fan_rpm_offset, &lo) || | 5411 | if (unlikely(!acpi_ec_read(fan_rpm_offset, &lo) || |
5403 | !acpi_ec_read(fan_rpm_offset + 1, &hi))) | 5412 | !acpi_ec_read(fan_rpm_offset + 1, &hi))) |
5404 | return -EIO; | 5413 | return -EIO; |
5405 | 5414 | ||
5406 | if (likely(speed)) | 5415 | if (likely(speed)) |
5407 | *speed = (hi << 8) | lo; | 5416 | *speed = (hi << 8) | lo; |
5408 | 5417 | ||
5409 | break; | 5418 | break; |
5410 | 5419 | ||
5411 | default: | 5420 | default: |
5412 | return -ENXIO; | 5421 | return -ENXIO; |
5413 | } | 5422 | } |
5414 | 5423 | ||
5415 | return 0; | 5424 | return 0; |
5416 | } | 5425 | } |
5417 | 5426 | ||
5418 | static int fan_set_level(int level) | 5427 | static int fan_set_level(int level) |
5419 | { | 5428 | { |
5420 | if (!fan_control_allowed) | 5429 | if (!fan_control_allowed) |
5421 | return -EPERM; | 5430 | return -EPERM; |
5422 | 5431 | ||
5423 | switch (fan_control_access_mode) { | 5432 | switch (fan_control_access_mode) { |
5424 | case TPACPI_FAN_WR_ACPI_SFAN: | 5433 | case TPACPI_FAN_WR_ACPI_SFAN: |
5425 | if (level >= 0 && level <= 7) { | 5434 | if (level >= 0 && level <= 7) { |
5426 | if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level)) | 5435 | if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level)) |
5427 | return -EIO; | 5436 | return -EIO; |
5428 | } else | 5437 | } else |
5429 | return -EINVAL; | 5438 | return -EINVAL; |
5430 | break; | 5439 | break; |
5431 | 5440 | ||
5432 | case TPACPI_FAN_WR_ACPI_FANS: | 5441 | case TPACPI_FAN_WR_ACPI_FANS: |
5433 | case TPACPI_FAN_WR_TPEC: | 5442 | case TPACPI_FAN_WR_TPEC: |
5434 | if ((level != TP_EC_FAN_AUTO) && | 5443 | if ((level != TP_EC_FAN_AUTO) && |
5435 | (level != TP_EC_FAN_FULLSPEED) && | 5444 | (level != TP_EC_FAN_FULLSPEED) && |
5436 | ((level < 0) || (level > 7))) | 5445 | ((level < 0) || (level > 7))) |
5437 | return -EINVAL; | 5446 | return -EINVAL; |
5438 | 5447 | ||
5439 | /* safety net should the EC not support AUTO | 5448 | /* safety net should the EC not support AUTO |
5440 | * or FULLSPEED mode bits and just ignore them */ | 5449 | * or FULLSPEED mode bits and just ignore them */ |
5441 | if (level & TP_EC_FAN_FULLSPEED) | 5450 | if (level & TP_EC_FAN_FULLSPEED) |
5442 | level |= 7; /* safety min speed 7 */ | 5451 | level |= 7; /* safety min speed 7 */ |
5443 | else if (level & TP_EC_FAN_AUTO) | 5452 | else if (level & TP_EC_FAN_AUTO) |
5444 | level |= 4; /* safety min speed 4 */ | 5453 | level |= 4; /* safety min speed 4 */ |
5445 | 5454 | ||
5446 | if (!acpi_ec_write(fan_status_offset, level)) | 5455 | if (!acpi_ec_write(fan_status_offset, level)) |
5447 | return -EIO; | 5456 | return -EIO; |
5448 | else | 5457 | else |
5449 | tp_features.fan_ctrl_status_undef = 0; | 5458 | tp_features.fan_ctrl_status_undef = 0; |
5450 | break; | 5459 | break; |
5451 | 5460 | ||
5452 | default: | 5461 | default: |
5453 | return -ENXIO; | 5462 | return -ENXIO; |
5454 | } | 5463 | } |
5455 | return 0; | 5464 | return 0; |
5456 | } | 5465 | } |
5457 | 5466 | ||
5458 | static int fan_set_level_safe(int level) | 5467 | static int fan_set_level_safe(int level) |
5459 | { | 5468 | { |
5460 | int rc; | 5469 | int rc; |
5461 | 5470 | ||
5462 | if (!fan_control_allowed) | 5471 | if (!fan_control_allowed) |
5463 | return -EPERM; | 5472 | return -EPERM; |
5464 | 5473 | ||
5465 | if (mutex_lock_interruptible(&fan_mutex)) | 5474 | if (mutex_lock_interruptible(&fan_mutex)) |
5466 | return -ERESTARTSYS; | 5475 | return -ERESTARTSYS; |
5467 | 5476 | ||
5468 | if (level == TPACPI_FAN_LAST_LEVEL) | 5477 | if (level == TPACPI_FAN_LAST_LEVEL) |
5469 | level = fan_control_desired_level; | 5478 | level = fan_control_desired_level; |
5470 | 5479 | ||
5471 | rc = fan_set_level(level); | 5480 | rc = fan_set_level(level); |
5472 | if (!rc) | 5481 | if (!rc) |
5473 | fan_update_desired_level(level); | 5482 | fan_update_desired_level(level); |
5474 | 5483 | ||
5475 | mutex_unlock(&fan_mutex); | 5484 | mutex_unlock(&fan_mutex); |
5476 | return rc; | 5485 | return rc; |
5477 | } | 5486 | } |
5478 | 5487 | ||
5479 | static int fan_set_enable(void) | 5488 | static int fan_set_enable(void) |
5480 | { | 5489 | { |
5481 | u8 s; | 5490 | u8 s; |
5482 | int rc; | 5491 | int rc; |
5483 | 5492 | ||
5484 | if (!fan_control_allowed) | 5493 | if (!fan_control_allowed) |
5485 | return -EPERM; | 5494 | return -EPERM; |
5486 | 5495 | ||
5487 | if (mutex_lock_interruptible(&fan_mutex)) | 5496 | if (mutex_lock_interruptible(&fan_mutex)) |
5488 | return -ERESTARTSYS; | 5497 | return -ERESTARTSYS; |
5489 | 5498 | ||
5490 | switch (fan_control_access_mode) { | 5499 | switch (fan_control_access_mode) { |
5491 | case TPACPI_FAN_WR_ACPI_FANS: | 5500 | case TPACPI_FAN_WR_ACPI_FANS: |
5492 | case TPACPI_FAN_WR_TPEC: | 5501 | case TPACPI_FAN_WR_TPEC: |
5493 | rc = fan_get_status(&s); | 5502 | rc = fan_get_status(&s); |
5494 | if (rc < 0) | 5503 | if (rc < 0) |
5495 | break; | 5504 | break; |
5496 | 5505 | ||
5497 | /* Don't go out of emergency fan mode */ | 5506 | /* Don't go out of emergency fan mode */ |
5498 | if (s != 7) { | 5507 | if (s != 7) { |
5499 | s &= 0x07; | 5508 | s &= 0x07; |
5500 | s |= TP_EC_FAN_AUTO | 4; /* min fan speed 4 */ | 5509 | s |= TP_EC_FAN_AUTO | 4; /* min fan speed 4 */ |
5501 | } | 5510 | } |
5502 | 5511 | ||
5503 | if (!acpi_ec_write(fan_status_offset, s)) | 5512 | if (!acpi_ec_write(fan_status_offset, s)) |
5504 | rc = -EIO; | 5513 | rc = -EIO; |
5505 | else { | 5514 | else { |
5506 | tp_features.fan_ctrl_status_undef = 0; | 5515 | tp_features.fan_ctrl_status_undef = 0; |
5507 | rc = 0; | 5516 | rc = 0; |
5508 | } | 5517 | } |
5509 | break; | 5518 | break; |
5510 | 5519 | ||
5511 | case TPACPI_FAN_WR_ACPI_SFAN: | 5520 | case TPACPI_FAN_WR_ACPI_SFAN: |
5512 | rc = fan_get_status(&s); | 5521 | rc = fan_get_status(&s); |
5513 | if (rc < 0) | 5522 | if (rc < 0) |
5514 | break; | 5523 | break; |
5515 | 5524 | ||
5516 | s &= 0x07; | 5525 | s &= 0x07; |
5517 | 5526 | ||
5518 | /* Set fan to at least level 4 */ | 5527 | /* Set fan to at least level 4 */ |
5519 | s |= 4; | 5528 | s |= 4; |
5520 | 5529 | ||
5521 | if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", s)) | 5530 | if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", s)) |
5522 | rc = -EIO; | 5531 | rc = -EIO; |
5523 | else | 5532 | else |
5524 | rc = 0; | 5533 | rc = 0; |
5525 | break; | 5534 | break; |
5526 | 5535 | ||
5527 | default: | 5536 | default: |
5528 | rc = -ENXIO; | 5537 | rc = -ENXIO; |
5529 | } | 5538 | } |
5530 | 5539 | ||
5531 | mutex_unlock(&fan_mutex); | 5540 | mutex_unlock(&fan_mutex); |
5532 | return rc; | 5541 | return rc; |
5533 | } | 5542 | } |
5534 | 5543 | ||
5535 | static int fan_set_disable(void) | 5544 | static int fan_set_disable(void) |
5536 | { | 5545 | { |
5537 | int rc; | 5546 | int rc; |
5538 | 5547 | ||
5539 | if (!fan_control_allowed) | 5548 | if (!fan_control_allowed) |
5540 | return -EPERM; | 5549 | return -EPERM; |
5541 | 5550 | ||
5542 | if (mutex_lock_interruptible(&fan_mutex)) | 5551 | if (mutex_lock_interruptible(&fan_mutex)) |
5543 | return -ERESTARTSYS; | 5552 | return -ERESTARTSYS; |
5544 | 5553 | ||
5545 | rc = 0; | 5554 | rc = 0; |
5546 | switch (fan_control_access_mode) { | 5555 | switch (fan_control_access_mode) { |
5547 | case TPACPI_FAN_WR_ACPI_FANS: | 5556 | case TPACPI_FAN_WR_ACPI_FANS: |
5548 | case TPACPI_FAN_WR_TPEC: | 5557 | case TPACPI_FAN_WR_TPEC: |
5549 | if (!acpi_ec_write(fan_status_offset, 0x00)) | 5558 | if (!acpi_ec_write(fan_status_offset, 0x00)) |
5550 | rc = -EIO; | 5559 | rc = -EIO; |
5551 | else { | 5560 | else { |
5552 | fan_control_desired_level = 0; | 5561 | fan_control_desired_level = 0; |
5553 | tp_features.fan_ctrl_status_undef = 0; | 5562 | tp_features.fan_ctrl_status_undef = 0; |
5554 | } | 5563 | } |
5555 | break; | 5564 | break; |
5556 | 5565 | ||
5557 | case TPACPI_FAN_WR_ACPI_SFAN: | 5566 | case TPACPI_FAN_WR_ACPI_SFAN: |
5558 | if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", 0x00)) | 5567 | if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", 0x00)) |
5559 | rc = -EIO; | 5568 | rc = -EIO; |
5560 | else | 5569 | else |
5561 | fan_control_desired_level = 0; | 5570 | fan_control_desired_level = 0; |
5562 | break; | 5571 | break; |
5563 | 5572 | ||
5564 | default: | 5573 | default: |
5565 | rc = -ENXIO; | 5574 | rc = -ENXIO; |
5566 | } | 5575 | } |
5567 | 5576 | ||
5568 | 5577 | ||
5569 | mutex_unlock(&fan_mutex); | 5578 | mutex_unlock(&fan_mutex); |
5570 | return rc; | 5579 | return rc; |
5571 | } | 5580 | } |
5572 | 5581 | ||
5573 | static int fan_set_speed(int speed) | 5582 | static int fan_set_speed(int speed) |
5574 | { | 5583 | { |
5575 | int rc; | 5584 | int rc; |
5576 | 5585 | ||
5577 | if (!fan_control_allowed) | 5586 | if (!fan_control_allowed) |
5578 | return -EPERM; | 5587 | return -EPERM; |
5579 | 5588 | ||
5580 | if (mutex_lock_interruptible(&fan_mutex)) | 5589 | if (mutex_lock_interruptible(&fan_mutex)) |
5581 | return -ERESTARTSYS; | 5590 | return -ERESTARTSYS; |
5582 | 5591 | ||
5583 | rc = 0; | 5592 | rc = 0; |
5584 | switch (fan_control_access_mode) { | 5593 | switch (fan_control_access_mode) { |
5585 | case TPACPI_FAN_WR_ACPI_FANS: | 5594 | case TPACPI_FAN_WR_ACPI_FANS: |
5586 | if (speed >= 0 && speed <= 65535) { | 5595 | if (speed >= 0 && speed <= 65535) { |
5587 | if (!acpi_evalf(fans_handle, NULL, NULL, "vddd", | 5596 | if (!acpi_evalf(fans_handle, NULL, NULL, "vddd", |
5588 | speed, speed, speed)) | 5597 | speed, speed, speed)) |
5589 | rc = -EIO; | 5598 | rc = -EIO; |
5590 | } else | 5599 | } else |
5591 | rc = -EINVAL; | 5600 | rc = -EINVAL; |
5592 | break; | 5601 | break; |
5593 | 5602 | ||
5594 | default: | 5603 | default: |
5595 | rc = -ENXIO; | 5604 | rc = -ENXIO; |
5596 | } | 5605 | } |
5597 | 5606 | ||
5598 | mutex_unlock(&fan_mutex); | 5607 | mutex_unlock(&fan_mutex); |
5599 | return rc; | 5608 | return rc; |
5600 | } | 5609 | } |
5601 | 5610 | ||
5602 | static void fan_watchdog_reset(void) | 5611 | static void fan_watchdog_reset(void) |
5603 | { | 5612 | { |
5604 | static int fan_watchdog_active; | 5613 | static int fan_watchdog_active; |
5605 | 5614 | ||
5606 | if (fan_control_access_mode == TPACPI_FAN_WR_NONE) | 5615 | if (fan_control_access_mode == TPACPI_FAN_WR_NONE) |
5607 | return; | 5616 | return; |
5608 | 5617 | ||
5609 | if (fan_watchdog_active) | 5618 | if (fan_watchdog_active) |
5610 | cancel_delayed_work(&fan_watchdog_task); | 5619 | cancel_delayed_work(&fan_watchdog_task); |
5611 | 5620 | ||
5612 | if (fan_watchdog_maxinterval > 0 && | 5621 | if (fan_watchdog_maxinterval > 0 && |
5613 | tpacpi_lifecycle != TPACPI_LIFE_EXITING) { | 5622 | tpacpi_lifecycle != TPACPI_LIFE_EXITING) { |
5614 | fan_watchdog_active = 1; | 5623 | fan_watchdog_active = 1; |
5615 | if (!queue_delayed_work(tpacpi_wq, &fan_watchdog_task, | 5624 | if (!queue_delayed_work(tpacpi_wq, &fan_watchdog_task, |
5616 | msecs_to_jiffies(fan_watchdog_maxinterval | 5625 | msecs_to_jiffies(fan_watchdog_maxinterval |
5617 | * 1000))) { | 5626 | * 1000))) { |
5618 | printk(TPACPI_ERR | 5627 | printk(TPACPI_ERR |
5619 | "failed to queue the fan watchdog, " | 5628 | "failed to queue the fan watchdog, " |
5620 | "watchdog will not trigger\n"); | 5629 | "watchdog will not trigger\n"); |
5621 | } | 5630 | } |
5622 | } else | 5631 | } else |
5623 | fan_watchdog_active = 0; | 5632 | fan_watchdog_active = 0; |
5624 | } | 5633 | } |
5625 | 5634 | ||
5626 | static void fan_watchdog_fire(struct work_struct *ignored) | 5635 | static void fan_watchdog_fire(struct work_struct *ignored) |
5627 | { | 5636 | { |
5628 | int rc; | 5637 | int rc; |
5629 | 5638 | ||
5630 | if (tpacpi_lifecycle != TPACPI_LIFE_RUNNING) | 5639 | if (tpacpi_lifecycle != TPACPI_LIFE_RUNNING) |
5631 | return; | 5640 | return; |
5632 | 5641 | ||
5633 | printk(TPACPI_NOTICE "fan watchdog: enabling fan\n"); | 5642 | printk(TPACPI_NOTICE "fan watchdog: enabling fan\n"); |
5634 | rc = fan_set_enable(); | 5643 | rc = fan_set_enable(); |
5635 | if (rc < 0) { | 5644 | if (rc < 0) { |
5636 | printk(TPACPI_ERR "fan watchdog: error %d while enabling fan, " | 5645 | printk(TPACPI_ERR "fan watchdog: error %d while enabling fan, " |
5637 | "will try again later...\n", -rc); | 5646 | "will try again later...\n", -rc); |
5638 | /* reschedule for later */ | 5647 | /* reschedule for later */ |
5639 | fan_watchdog_reset(); | 5648 | fan_watchdog_reset(); |
5640 | } | 5649 | } |
5641 | } | 5650 | } |
5642 | 5651 | ||
5643 | /* | 5652 | /* |
5644 | * SYSFS fan layout: hwmon compatible (device) | 5653 | * SYSFS fan layout: hwmon compatible (device) |
5645 | * | 5654 | * |
5646 | * pwm*_enable: | 5655 | * pwm*_enable: |
5647 | * 0: "disengaged" mode | 5656 | * 0: "disengaged" mode |
5648 | * 1: manual mode | 5657 | * 1: manual mode |
5649 | * 2: native EC "auto" mode (recommended, hardware default) | 5658 | * 2: native EC "auto" mode (recommended, hardware default) |
5650 | * | 5659 | * |
5651 | * pwm*: set speed in manual mode, ignored otherwise. | 5660 | * pwm*: set speed in manual mode, ignored otherwise. |
5652 | * 0 is level 0; 255 is level 7. Intermediate points done with linear | 5661 | * 0 is level 0; 255 is level 7. Intermediate points done with linear |
5653 | * interpolation. | 5662 | * interpolation. |
5654 | * | 5663 | * |
5655 | * fan*_input: tachometer reading, RPM | 5664 | * fan*_input: tachometer reading, RPM |
5656 | * | 5665 | * |
5657 | * | 5666 | * |
5658 | * SYSFS fan layout: extensions | 5667 | * SYSFS fan layout: extensions |
5659 | * | 5668 | * |
5660 | * fan_watchdog (driver): | 5669 | * fan_watchdog (driver): |
5661 | * fan watchdog interval in seconds, 0 disables (default), max 120 | 5670 | * fan watchdog interval in seconds, 0 disables (default), max 120 |
5662 | */ | 5671 | */ |
5663 | 5672 | ||
5664 | /* sysfs fan pwm1_enable ----------------------------------------------- */ | 5673 | /* sysfs fan pwm1_enable ----------------------------------------------- */ |
5665 | static ssize_t fan_pwm1_enable_show(struct device *dev, | 5674 | static ssize_t fan_pwm1_enable_show(struct device *dev, |
5666 | struct device_attribute *attr, | 5675 | struct device_attribute *attr, |
5667 | char *buf) | 5676 | char *buf) |
5668 | { | 5677 | { |
5669 | int res, mode; | 5678 | int res, mode; |
5670 | u8 status; | 5679 | u8 status; |
5671 | 5680 | ||
5672 | res = fan_get_status_safe(&status); | 5681 | res = fan_get_status_safe(&status); |
5673 | if (res) | 5682 | if (res) |
5674 | return res; | 5683 | return res; |
5675 | 5684 | ||
5676 | if (unlikely(tp_features.fan_ctrl_status_undef)) { | 5685 | if (unlikely(tp_features.fan_ctrl_status_undef)) { |
5677 | if (status != fan_control_initial_status) { | 5686 | if (status != fan_control_initial_status) { |
5678 | tp_features.fan_ctrl_status_undef = 0; | 5687 | tp_features.fan_ctrl_status_undef = 0; |
5679 | } else { | 5688 | } else { |
5680 | /* Return most likely status. In fact, it | 5689 | /* Return most likely status. In fact, it |
5681 | * might be the only possible status */ | 5690 | * might be the only possible status */ |
5682 | status = TP_EC_FAN_AUTO; | 5691 | status = TP_EC_FAN_AUTO; |
5683 | } | 5692 | } |
5684 | } | 5693 | } |
5685 | 5694 | ||
5686 | if (status & TP_EC_FAN_FULLSPEED) { | 5695 | if (status & TP_EC_FAN_FULLSPEED) { |
5687 | mode = 0; | 5696 | mode = 0; |
5688 | } else if (status & TP_EC_FAN_AUTO) { | 5697 | } else if (status & TP_EC_FAN_AUTO) { |
5689 | mode = 2; | 5698 | mode = 2; |
5690 | } else | 5699 | } else |
5691 | mode = 1; | 5700 | mode = 1; |
5692 | 5701 | ||
5693 | return snprintf(buf, PAGE_SIZE, "%d\n", mode); | 5702 | return snprintf(buf, PAGE_SIZE, "%d\n", mode); |
5694 | } | 5703 | } |
5695 | 5704 | ||
5696 | static ssize_t fan_pwm1_enable_store(struct device *dev, | 5705 | static ssize_t fan_pwm1_enable_store(struct device *dev, |
5697 | struct device_attribute *attr, | 5706 | struct device_attribute *attr, |
5698 | const char *buf, size_t count) | 5707 | const char *buf, size_t count) |
5699 | { | 5708 | { |
5700 | unsigned long t; | 5709 | unsigned long t; |
5701 | int res, level; | 5710 | int res, level; |
5702 | 5711 | ||
5703 | if (parse_strtoul(buf, 2, &t)) | 5712 | if (parse_strtoul(buf, 2, &t)) |
5704 | return -EINVAL; | 5713 | return -EINVAL; |
5705 | 5714 | ||
5706 | switch (t) { | 5715 | switch (t) { |
5707 | case 0: | 5716 | case 0: |
5708 | level = TP_EC_FAN_FULLSPEED; | 5717 | level = TP_EC_FAN_FULLSPEED; |
5709 | break; | 5718 | break; |
5710 | case 1: | 5719 | case 1: |
5711 | level = TPACPI_FAN_LAST_LEVEL; | 5720 | level = TPACPI_FAN_LAST_LEVEL; |
5712 | break; | 5721 | break; |
5713 | case 2: | 5722 | case 2: |
5714 | level = TP_EC_FAN_AUTO; | 5723 | level = TP_EC_FAN_AUTO; |
5715 | break; | 5724 | break; |
5716 | case 3: | 5725 | case 3: |
5717 | /* reserved for software-controlled auto mode */ | 5726 | /* reserved for software-controlled auto mode */ |
5718 | return -ENOSYS; | 5727 | return -ENOSYS; |
5719 | default: | 5728 | default: |
5720 | return -EINVAL; | 5729 | return -EINVAL; |
5721 | } | 5730 | } |
5722 | 5731 | ||
5723 | res = fan_set_level_safe(level); | 5732 | res = fan_set_level_safe(level); |
5724 | if (res == -ENXIO) | 5733 | if (res == -ENXIO) |
5725 | return -EINVAL; | 5734 | return -EINVAL; |
5726 | else if (res < 0) | 5735 | else if (res < 0) |
5727 | return res; | 5736 | return res; |
5728 | 5737 | ||
5729 | fan_watchdog_reset(); | 5738 | fan_watchdog_reset(); |
5730 | 5739 | ||
5731 | return count; | 5740 | return count; |
5732 | } | 5741 | } |
5733 | 5742 | ||
5734 | static struct device_attribute dev_attr_fan_pwm1_enable = | 5743 | static struct device_attribute dev_attr_fan_pwm1_enable = |
5735 | __ATTR(pwm1_enable, S_IWUSR | S_IRUGO, | 5744 | __ATTR(pwm1_enable, S_IWUSR | S_IRUGO, |
5736 | fan_pwm1_enable_show, fan_pwm1_enable_store); | 5745 | fan_pwm1_enable_show, fan_pwm1_enable_store); |
5737 | 5746 | ||
5738 | /* sysfs fan pwm1 ------------------------------------------------------ */ | 5747 | /* sysfs fan pwm1 ------------------------------------------------------ */ |
5739 | static ssize_t fan_pwm1_show(struct device *dev, | 5748 | static ssize_t fan_pwm1_show(struct device *dev, |
5740 | struct device_attribute *attr, | 5749 | struct device_attribute *attr, |
5741 | char *buf) | 5750 | char *buf) |
5742 | { | 5751 | { |
5743 | int res; | 5752 | int res; |
5744 | u8 status; | 5753 | u8 status; |
5745 | 5754 | ||
5746 | res = fan_get_status_safe(&status); | 5755 | res = fan_get_status_safe(&status); |
5747 | if (res) | 5756 | if (res) |
5748 | return res; | 5757 | return res; |
5749 | 5758 | ||
5750 | if (unlikely(tp_features.fan_ctrl_status_undef)) { | 5759 | if (unlikely(tp_features.fan_ctrl_status_undef)) { |
5751 | if (status != fan_control_initial_status) { | 5760 | if (status != fan_control_initial_status) { |
5752 | tp_features.fan_ctrl_status_undef = 0; | 5761 | tp_features.fan_ctrl_status_undef = 0; |
5753 | } else { | 5762 | } else { |
5754 | status = TP_EC_FAN_AUTO; | 5763 | status = TP_EC_FAN_AUTO; |
5755 | } | 5764 | } |
5756 | } | 5765 | } |
5757 | 5766 | ||
5758 | if ((status & | 5767 | if ((status & |
5759 | (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) != 0) | 5768 | (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) != 0) |
5760 | status = fan_control_desired_level; | 5769 | status = fan_control_desired_level; |
5761 | 5770 | ||
5762 | if (status > 7) | 5771 | if (status > 7) |
5763 | status = 7; | 5772 | status = 7; |
5764 | 5773 | ||
5765 | return snprintf(buf, PAGE_SIZE, "%u\n", (status * 255) / 7); | 5774 | return snprintf(buf, PAGE_SIZE, "%u\n", (status * 255) / 7); |
5766 | } | 5775 | } |
5767 | 5776 | ||
5768 | static ssize_t fan_pwm1_store(struct device *dev, | 5777 | static ssize_t fan_pwm1_store(struct device *dev, |
5769 | struct device_attribute *attr, | 5778 | struct device_attribute *attr, |
5770 | const char *buf, size_t count) | 5779 | const char *buf, size_t count) |
5771 | { | 5780 | { |
5772 | unsigned long s; | 5781 | unsigned long s; |
5773 | int rc; | 5782 | int rc; |
5774 | u8 status, newlevel; | 5783 | u8 status, newlevel; |
5775 | 5784 | ||
5776 | if (parse_strtoul(buf, 255, &s)) | 5785 | if (parse_strtoul(buf, 255, &s)) |
5777 | return -EINVAL; | 5786 | return -EINVAL; |
5778 | 5787 | ||
5779 | /* scale down from 0-255 to 0-7 */ | 5788 | /* scale down from 0-255 to 0-7 */ |
5780 | newlevel = (s >> 5) & 0x07; | 5789 | newlevel = (s >> 5) & 0x07; |
5781 | 5790 | ||
5782 | if (mutex_lock_interruptible(&fan_mutex)) | 5791 | if (mutex_lock_interruptible(&fan_mutex)) |
5783 | return -ERESTARTSYS; | 5792 | return -ERESTARTSYS; |
5784 | 5793 | ||
5785 | rc = fan_get_status(&status); | 5794 | rc = fan_get_status(&status); |
5786 | if (!rc && (status & | 5795 | if (!rc && (status & |
5787 | (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) == 0) { | 5796 | (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) == 0) { |
5788 | rc = fan_set_level(newlevel); | 5797 | rc = fan_set_level(newlevel); |
5789 | if (rc == -ENXIO) | 5798 | if (rc == -ENXIO) |
5790 | rc = -EINVAL; | 5799 | rc = -EINVAL; |
5791 | else if (!rc) { | 5800 | else if (!rc) { |
5792 | fan_update_desired_level(newlevel); | 5801 | fan_update_desired_level(newlevel); |
5793 | fan_watchdog_reset(); | 5802 | fan_watchdog_reset(); |
5794 | } | 5803 | } |
5795 | } | 5804 | } |
5796 | 5805 | ||
5797 | mutex_unlock(&fan_mutex); | 5806 | mutex_unlock(&fan_mutex); |
5798 | return (rc)? rc : count; | 5807 | return (rc)? rc : count; |
5799 | } | 5808 | } |
5800 | 5809 | ||
5801 | static struct device_attribute dev_attr_fan_pwm1 = | 5810 | static struct device_attribute dev_attr_fan_pwm1 = |
5802 | __ATTR(pwm1, S_IWUSR | S_IRUGO, | 5811 | __ATTR(pwm1, S_IWUSR | S_IRUGO, |
5803 | fan_pwm1_show, fan_pwm1_store); | 5812 | fan_pwm1_show, fan_pwm1_store); |
5804 | 5813 | ||
5805 | /* sysfs fan fan1_input ------------------------------------------------ */ | 5814 | /* sysfs fan fan1_input ------------------------------------------------ */ |
5806 | static ssize_t fan_fan1_input_show(struct device *dev, | 5815 | static ssize_t fan_fan1_input_show(struct device *dev, |
5807 | struct device_attribute *attr, | 5816 | struct device_attribute *attr, |
5808 | char *buf) | 5817 | char *buf) |
5809 | { | 5818 | { |
5810 | int res; | 5819 | int res; |
5811 | unsigned int speed; | 5820 | unsigned int speed; |
5812 | 5821 | ||
5813 | res = fan_get_speed(&speed); | 5822 | res = fan_get_speed(&speed); |
5814 | if (res < 0) | 5823 | if (res < 0) |
5815 | return res; | 5824 | return res; |
5816 | 5825 | ||
5817 | return snprintf(buf, PAGE_SIZE, "%u\n", speed); | 5826 | return snprintf(buf, PAGE_SIZE, "%u\n", speed); |
5818 | } | 5827 | } |
5819 | 5828 | ||
5820 | static struct device_attribute dev_attr_fan_fan1_input = | 5829 | static struct device_attribute dev_attr_fan_fan1_input = |
5821 | __ATTR(fan1_input, S_IRUGO, | 5830 | __ATTR(fan1_input, S_IRUGO, |
5822 | fan_fan1_input_show, NULL); | 5831 | fan_fan1_input_show, NULL); |
5823 | 5832 | ||
5824 | /* sysfs fan fan_watchdog (hwmon driver) ------------------------------- */ | 5833 | /* sysfs fan fan_watchdog (hwmon driver) ------------------------------- */ |
5825 | static ssize_t fan_fan_watchdog_show(struct device_driver *drv, | 5834 | static ssize_t fan_fan_watchdog_show(struct device_driver *drv, |
5826 | char *buf) | 5835 | char *buf) |
5827 | { | 5836 | { |
5828 | return snprintf(buf, PAGE_SIZE, "%u\n", fan_watchdog_maxinterval); | 5837 | return snprintf(buf, PAGE_SIZE, "%u\n", fan_watchdog_maxinterval); |
5829 | } | 5838 | } |
5830 | 5839 | ||
5831 | static ssize_t fan_fan_watchdog_store(struct device_driver *drv, | 5840 | static ssize_t fan_fan_watchdog_store(struct device_driver *drv, |
5832 | const char *buf, size_t count) | 5841 | const char *buf, size_t count) |
5833 | { | 5842 | { |
5834 | unsigned long t; | 5843 | unsigned long t; |
5835 | 5844 | ||
5836 | if (parse_strtoul(buf, 120, &t)) | 5845 | if (parse_strtoul(buf, 120, &t)) |
5837 | return -EINVAL; | 5846 | return -EINVAL; |
5838 | 5847 | ||
5839 | if (!fan_control_allowed) | 5848 | if (!fan_control_allowed) |
5840 | return -EPERM; | 5849 | return -EPERM; |
5841 | 5850 | ||
5842 | fan_watchdog_maxinterval = t; | 5851 | fan_watchdog_maxinterval = t; |
5843 | fan_watchdog_reset(); | 5852 | fan_watchdog_reset(); |
5844 | 5853 | ||
5845 | return count; | 5854 | return count; |
5846 | } | 5855 | } |
5847 | 5856 | ||
5848 | static DRIVER_ATTR(fan_watchdog, S_IWUSR | S_IRUGO, | 5857 | static DRIVER_ATTR(fan_watchdog, S_IWUSR | S_IRUGO, |
5849 | fan_fan_watchdog_show, fan_fan_watchdog_store); | 5858 | fan_fan_watchdog_show, fan_fan_watchdog_store); |
5850 | 5859 | ||
5851 | /* --------------------------------------------------------------------- */ | 5860 | /* --------------------------------------------------------------------- */ |
5852 | static struct attribute *fan_attributes[] = { | 5861 | static struct attribute *fan_attributes[] = { |
5853 | &dev_attr_fan_pwm1_enable.attr, &dev_attr_fan_pwm1.attr, | 5862 | &dev_attr_fan_pwm1_enable.attr, &dev_attr_fan_pwm1.attr, |
5854 | &dev_attr_fan_fan1_input.attr, | 5863 | &dev_attr_fan_fan1_input.attr, |
5855 | NULL | 5864 | NULL |
5856 | }; | 5865 | }; |
5857 | 5866 | ||
5858 | static const struct attribute_group fan_attr_group = { | 5867 | static const struct attribute_group fan_attr_group = { |
5859 | .attrs = fan_attributes, | 5868 | .attrs = fan_attributes, |
5860 | }; | 5869 | }; |
5861 | 5870 | ||
5862 | static int __init fan_init(struct ibm_init_struct *iibm) | 5871 | static int __init fan_init(struct ibm_init_struct *iibm) |
5863 | { | 5872 | { |
5864 | int rc; | 5873 | int rc; |
5865 | 5874 | ||
5866 | vdbg_printk(TPACPI_DBG_INIT, "initializing fan subdriver\n"); | 5875 | vdbg_printk(TPACPI_DBG_INIT, "initializing fan subdriver\n"); |
5867 | 5876 | ||
5868 | mutex_init(&fan_mutex); | 5877 | mutex_init(&fan_mutex); |
5869 | fan_status_access_mode = TPACPI_FAN_NONE; | 5878 | fan_status_access_mode = TPACPI_FAN_NONE; |
5870 | fan_control_access_mode = TPACPI_FAN_WR_NONE; | 5879 | fan_control_access_mode = TPACPI_FAN_WR_NONE; |
5871 | fan_control_commands = 0; | 5880 | fan_control_commands = 0; |
5872 | fan_watchdog_maxinterval = 0; | 5881 | fan_watchdog_maxinterval = 0; |
5873 | tp_features.fan_ctrl_status_undef = 0; | 5882 | tp_features.fan_ctrl_status_undef = 0; |
5874 | fan_control_desired_level = 7; | 5883 | fan_control_desired_level = 7; |
5875 | 5884 | ||
5876 | TPACPI_ACPIHANDLE_INIT(fans); | 5885 | TPACPI_ACPIHANDLE_INIT(fans); |
5877 | TPACPI_ACPIHANDLE_INIT(gfan); | 5886 | TPACPI_ACPIHANDLE_INIT(gfan); |
5878 | TPACPI_ACPIHANDLE_INIT(sfan); | 5887 | TPACPI_ACPIHANDLE_INIT(sfan); |
5879 | 5888 | ||
5880 | if (gfan_handle) { | 5889 | if (gfan_handle) { |
5881 | /* 570, 600e/x, 770e, 770x */ | 5890 | /* 570, 600e/x, 770e, 770x */ |
5882 | fan_status_access_mode = TPACPI_FAN_RD_ACPI_GFAN; | 5891 | fan_status_access_mode = TPACPI_FAN_RD_ACPI_GFAN; |
5883 | } else { | 5892 | } else { |
5884 | /* all other ThinkPads: note that even old-style | 5893 | /* all other ThinkPads: note that even old-style |
5885 | * ThinkPad ECs supports the fan control register */ | 5894 | * ThinkPad ECs supports the fan control register */ |
5886 | if (likely(acpi_ec_read(fan_status_offset, | 5895 | if (likely(acpi_ec_read(fan_status_offset, |
5887 | &fan_control_initial_status))) { | 5896 | &fan_control_initial_status))) { |
5888 | fan_status_access_mode = TPACPI_FAN_RD_TPEC; | 5897 | fan_status_access_mode = TPACPI_FAN_RD_TPEC; |
5889 | 5898 | ||
5890 | /* In some ThinkPads, neither the EC nor the ACPI | 5899 | /* In some ThinkPads, neither the EC nor the ACPI |
5891 | * DSDT initialize the fan status, and it ends up | 5900 | * DSDT initialize the fan status, and it ends up |
5892 | * being set to 0x07 when it *could* be either | 5901 | * being set to 0x07 when it *could* be either |
5893 | * 0x07 or 0x80. | 5902 | * 0x07 or 0x80. |
5894 | * | 5903 | * |
5895 | * Enable for TP-1Y (T43), TP-78 (R51e), | 5904 | * Enable for TP-1Y (T43), TP-78 (R51e), |
5896 | * TP-76 (R52), TP-70 (T43, R52), which are known | 5905 | * TP-76 (R52), TP-70 (T43, R52), which are known |
5897 | * to be buggy. */ | 5906 | * to be buggy. */ |
5898 | if (fan_control_initial_status == 0x07) { | 5907 | if (fan_control_initial_status == 0x07) { |
5899 | switch (thinkpad_id.ec_model) { | 5908 | switch (thinkpad_id.ec_model) { |
5900 | case 0x5931: /* TP-1Y */ | 5909 | case 0x5931: /* TP-1Y */ |
5901 | case 0x3837: /* TP-78 */ | 5910 | case 0x3837: /* TP-78 */ |
5902 | case 0x3637: /* TP-76 */ | 5911 | case 0x3637: /* TP-76 */ |
5903 | case 0x3037: /* TP-70 */ | 5912 | case 0x3037: /* TP-70 */ |
5904 | printk(TPACPI_NOTICE | 5913 | printk(TPACPI_NOTICE |
5905 | "fan_init: initial fan status " | 5914 | "fan_init: initial fan status " |
5906 | "is unknown, assuming it is " | 5915 | "is unknown, assuming it is " |
5907 | "in auto mode\n"); | 5916 | "in auto mode\n"); |
5908 | tp_features.fan_ctrl_status_undef = 1; | 5917 | tp_features.fan_ctrl_status_undef = 1; |
5909 | ;; | 5918 | ;; |
5910 | } | 5919 | } |
5911 | } | 5920 | } |
5912 | } else { | 5921 | } else { |
5913 | printk(TPACPI_ERR | 5922 | printk(TPACPI_ERR |
5914 | "ThinkPad ACPI EC access misbehaving, " | 5923 | "ThinkPad ACPI EC access misbehaving, " |
5915 | "fan status and control unavailable\n"); | 5924 | "fan status and control unavailable\n"); |
5916 | return 1; | 5925 | return 1; |
5917 | } | 5926 | } |
5918 | } | 5927 | } |
5919 | 5928 | ||
5920 | if (sfan_handle) { | 5929 | if (sfan_handle) { |
5921 | /* 570, 770x-JL */ | 5930 | /* 570, 770x-JL */ |
5922 | fan_control_access_mode = TPACPI_FAN_WR_ACPI_SFAN; | 5931 | fan_control_access_mode = TPACPI_FAN_WR_ACPI_SFAN; |
5923 | fan_control_commands |= | 5932 | fan_control_commands |= |
5924 | TPACPI_FAN_CMD_LEVEL | TPACPI_FAN_CMD_ENABLE; | 5933 | TPACPI_FAN_CMD_LEVEL | TPACPI_FAN_CMD_ENABLE; |
5925 | } else { | 5934 | } else { |
5926 | if (!gfan_handle) { | 5935 | if (!gfan_handle) { |
5927 | /* gfan without sfan means no fan control */ | 5936 | /* gfan without sfan means no fan control */ |
5928 | /* all other models implement TP EC 0x2f control */ | 5937 | /* all other models implement TP EC 0x2f control */ |
5929 | 5938 | ||
5930 | if (fans_handle) { | 5939 | if (fans_handle) { |
5931 | /* X31, X40, X41 */ | 5940 | /* X31, X40, X41 */ |
5932 | fan_control_access_mode = | 5941 | fan_control_access_mode = |
5933 | TPACPI_FAN_WR_ACPI_FANS; | 5942 | TPACPI_FAN_WR_ACPI_FANS; |
5934 | fan_control_commands |= | 5943 | fan_control_commands |= |
5935 | TPACPI_FAN_CMD_SPEED | | 5944 | TPACPI_FAN_CMD_SPEED | |
5936 | TPACPI_FAN_CMD_LEVEL | | 5945 | TPACPI_FAN_CMD_LEVEL | |
5937 | TPACPI_FAN_CMD_ENABLE; | 5946 | TPACPI_FAN_CMD_ENABLE; |
5938 | } else { | 5947 | } else { |
5939 | fan_control_access_mode = TPACPI_FAN_WR_TPEC; | 5948 | fan_control_access_mode = TPACPI_FAN_WR_TPEC; |
5940 | fan_control_commands |= | 5949 | fan_control_commands |= |
5941 | TPACPI_FAN_CMD_LEVEL | | 5950 | TPACPI_FAN_CMD_LEVEL | |
5942 | TPACPI_FAN_CMD_ENABLE; | 5951 | TPACPI_FAN_CMD_ENABLE; |
5943 | } | 5952 | } |
5944 | } | 5953 | } |
5945 | } | 5954 | } |
5946 | 5955 | ||
5947 | vdbg_printk(TPACPI_DBG_INIT, "fan is %s, modes %d, %d\n", | 5956 | vdbg_printk(TPACPI_DBG_INIT, "fan is %s, modes %d, %d\n", |
5948 | str_supported(fan_status_access_mode != TPACPI_FAN_NONE || | 5957 | str_supported(fan_status_access_mode != TPACPI_FAN_NONE || |
5949 | fan_control_access_mode != TPACPI_FAN_WR_NONE), | 5958 | fan_control_access_mode != TPACPI_FAN_WR_NONE), |
5950 | fan_status_access_mode, fan_control_access_mode); | 5959 | fan_status_access_mode, fan_control_access_mode); |
5951 | 5960 | ||
5952 | /* fan control master switch */ | 5961 | /* fan control master switch */ |
5953 | if (!fan_control_allowed) { | 5962 | if (!fan_control_allowed) { |
5954 | fan_control_access_mode = TPACPI_FAN_WR_NONE; | 5963 | fan_control_access_mode = TPACPI_FAN_WR_NONE; |
5955 | fan_control_commands = 0; | 5964 | fan_control_commands = 0; |
5956 | dbg_printk(TPACPI_DBG_INIT, | 5965 | dbg_printk(TPACPI_DBG_INIT, |
5957 | "fan control features disabled by parameter\n"); | 5966 | "fan control features disabled by parameter\n"); |
5958 | } | 5967 | } |
5959 | 5968 | ||
5960 | /* update fan_control_desired_level */ | 5969 | /* update fan_control_desired_level */ |
5961 | if (fan_status_access_mode != TPACPI_FAN_NONE) | 5970 | if (fan_status_access_mode != TPACPI_FAN_NONE) |
5962 | fan_get_status_safe(NULL); | 5971 | fan_get_status_safe(NULL); |
5963 | 5972 | ||
5964 | if (fan_status_access_mode != TPACPI_FAN_NONE || | 5973 | if (fan_status_access_mode != TPACPI_FAN_NONE || |
5965 | fan_control_access_mode != TPACPI_FAN_WR_NONE) { | 5974 | fan_control_access_mode != TPACPI_FAN_WR_NONE) { |
5966 | rc = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj, | 5975 | rc = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj, |
5967 | &fan_attr_group); | 5976 | &fan_attr_group); |
5968 | if (rc < 0) | 5977 | if (rc < 0) |
5969 | return rc; | 5978 | return rc; |
5970 | 5979 | ||
5971 | rc = driver_create_file(&tpacpi_hwmon_pdriver.driver, | 5980 | rc = driver_create_file(&tpacpi_hwmon_pdriver.driver, |
5972 | &driver_attr_fan_watchdog); | 5981 | &driver_attr_fan_watchdog); |
5973 | if (rc < 0) { | 5982 | if (rc < 0) { |
5974 | sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, | 5983 | sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, |
5975 | &fan_attr_group); | 5984 | &fan_attr_group); |
5976 | return rc; | 5985 | return rc; |
5977 | } | 5986 | } |
5978 | return 0; | 5987 | return 0; |
5979 | } else | 5988 | } else |
5980 | return 1; | 5989 | return 1; |
5981 | } | 5990 | } |
5982 | 5991 | ||
5983 | static void fan_exit(void) | 5992 | static void fan_exit(void) |
5984 | { | 5993 | { |
5985 | vdbg_printk(TPACPI_DBG_EXIT, | 5994 | vdbg_printk(TPACPI_DBG_EXIT, |
5986 | "cancelling any pending fan watchdog tasks\n"); | 5995 | "cancelling any pending fan watchdog tasks\n"); |
5987 | 5996 | ||
5988 | /* FIXME: can we really do this unconditionally? */ | 5997 | /* FIXME: can we really do this unconditionally? */ |
5989 | sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, &fan_attr_group); | 5998 | sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, &fan_attr_group); |
5990 | driver_remove_file(&tpacpi_hwmon_pdriver.driver, | 5999 | driver_remove_file(&tpacpi_hwmon_pdriver.driver, |
5991 | &driver_attr_fan_watchdog); | 6000 | &driver_attr_fan_watchdog); |
5992 | 6001 | ||
5993 | cancel_delayed_work(&fan_watchdog_task); | 6002 | cancel_delayed_work(&fan_watchdog_task); |
5994 | flush_workqueue(tpacpi_wq); | 6003 | flush_workqueue(tpacpi_wq); |
5995 | } | 6004 | } |
5996 | 6005 | ||
5997 | static void fan_suspend(pm_message_t state) | 6006 | static void fan_suspend(pm_message_t state) |
5998 | { | 6007 | { |
5999 | if (!fan_control_allowed) | 6008 | if (!fan_control_allowed) |
6000 | return; | 6009 | return; |
6001 | 6010 | ||
6002 | /* Store fan status in cache */ | 6011 | /* Store fan status in cache */ |
6003 | fan_get_status_safe(NULL); | 6012 | fan_get_status_safe(NULL); |
6004 | if (tp_features.fan_ctrl_status_undef) | 6013 | if (tp_features.fan_ctrl_status_undef) |
6005 | fan_control_desired_level = TP_EC_FAN_AUTO; | 6014 | fan_control_desired_level = TP_EC_FAN_AUTO; |
6006 | } | 6015 | } |
6007 | 6016 | ||
6008 | static void fan_resume(void) | 6017 | static void fan_resume(void) |
6009 | { | 6018 | { |
6010 | u8 saved_fan_level; | 6019 | u8 saved_fan_level; |
6011 | u8 current_level = 7; | 6020 | u8 current_level = 7; |
6012 | bool do_set = false; | 6021 | bool do_set = false; |
6013 | 6022 | ||
6014 | /* DSDT *always* updates status on resume */ | 6023 | /* DSDT *always* updates status on resume */ |
6015 | tp_features.fan_ctrl_status_undef = 0; | 6024 | tp_features.fan_ctrl_status_undef = 0; |
6016 | 6025 | ||
6017 | saved_fan_level = fan_control_desired_level; | 6026 | saved_fan_level = fan_control_desired_level; |
6018 | if (!fan_control_allowed || | 6027 | if (!fan_control_allowed || |
6019 | (fan_get_status_safe(¤t_level) < 0)) | 6028 | (fan_get_status_safe(¤t_level) < 0)) |
6020 | return; | 6029 | return; |
6021 | 6030 | ||
6022 | switch (fan_control_access_mode) { | 6031 | switch (fan_control_access_mode) { |
6023 | case TPACPI_FAN_WR_ACPI_SFAN: | 6032 | case TPACPI_FAN_WR_ACPI_SFAN: |
6024 | do_set = (saved_fan_level > current_level); | 6033 | do_set = (saved_fan_level > current_level); |
6025 | break; | 6034 | break; |
6026 | case TPACPI_FAN_WR_ACPI_FANS: | 6035 | case TPACPI_FAN_WR_ACPI_FANS: |
6027 | case TPACPI_FAN_WR_TPEC: | 6036 | case TPACPI_FAN_WR_TPEC: |
6028 | do_set = ((saved_fan_level & TP_EC_FAN_FULLSPEED) || | 6037 | do_set = ((saved_fan_level & TP_EC_FAN_FULLSPEED) || |
6029 | (saved_fan_level == 7 && | 6038 | (saved_fan_level == 7 && |
6030 | !(current_level & TP_EC_FAN_FULLSPEED))); | 6039 | !(current_level & TP_EC_FAN_FULLSPEED))); |
6031 | break; | 6040 | break; |
6032 | default: | 6041 | default: |
6033 | return; | 6042 | return; |
6034 | } | 6043 | } |
6035 | if (do_set) { | 6044 | if (do_set) { |
6036 | printk(TPACPI_NOTICE | 6045 | printk(TPACPI_NOTICE |
6037 | "restoring fan level to 0x%02x\n", | 6046 | "restoring fan level to 0x%02x\n", |
6038 | saved_fan_level); | 6047 | saved_fan_level); |
6039 | fan_set_level_safe(saved_fan_level); | 6048 | fan_set_level_safe(saved_fan_level); |
6040 | } | 6049 | } |
6041 | } | 6050 | } |
6042 | 6051 | ||
6043 | static int fan_read(char *p) | 6052 | static int fan_read(char *p) |
6044 | { | 6053 | { |
6045 | int len = 0; | 6054 | int len = 0; |
6046 | int rc; | 6055 | int rc; |
6047 | u8 status; | 6056 | u8 status; |
6048 | unsigned int speed = 0; | 6057 | unsigned int speed = 0; |
6049 | 6058 | ||
6050 | switch (fan_status_access_mode) { | 6059 | switch (fan_status_access_mode) { |
6051 | case TPACPI_FAN_RD_ACPI_GFAN: | 6060 | case TPACPI_FAN_RD_ACPI_GFAN: |
6052 | /* 570, 600e/x, 770e, 770x */ | 6061 | /* 570, 600e/x, 770e, 770x */ |
6053 | rc = fan_get_status_safe(&status); | 6062 | rc = fan_get_status_safe(&status); |
6054 | if (rc < 0) | 6063 | if (rc < 0) |
6055 | return rc; | 6064 | return rc; |
6056 | 6065 | ||
6057 | len += sprintf(p + len, "status:\t\t%s\n" | 6066 | len += sprintf(p + len, "status:\t\t%s\n" |
6058 | "level:\t\t%d\n", | 6067 | "level:\t\t%d\n", |
6059 | (status != 0) ? "enabled" : "disabled", status); | 6068 | (status != 0) ? "enabled" : "disabled", status); |
6060 | break; | 6069 | break; |
6061 | 6070 | ||
6062 | case TPACPI_FAN_RD_TPEC: | 6071 | case TPACPI_FAN_RD_TPEC: |
6063 | /* all except 570, 600e/x, 770e, 770x */ | 6072 | /* all except 570, 600e/x, 770e, 770x */ |
6064 | rc = fan_get_status_safe(&status); | 6073 | rc = fan_get_status_safe(&status); |
6065 | if (rc < 0) | 6074 | if (rc < 0) |
6066 | return rc; | 6075 | return rc; |
6067 | 6076 | ||
6068 | if (unlikely(tp_features.fan_ctrl_status_undef)) { | 6077 | if (unlikely(tp_features.fan_ctrl_status_undef)) { |
6069 | if (status != fan_control_initial_status) | 6078 | if (status != fan_control_initial_status) |
6070 | tp_features.fan_ctrl_status_undef = 0; | 6079 | tp_features.fan_ctrl_status_undef = 0; |
6071 | else | 6080 | else |
6072 | /* Return most likely status. In fact, it | 6081 | /* Return most likely status. In fact, it |
6073 | * might be the only possible status */ | 6082 | * might be the only possible status */ |
6074 | status = TP_EC_FAN_AUTO; | 6083 | status = TP_EC_FAN_AUTO; |
6075 | } | 6084 | } |
6076 | 6085 | ||
6077 | len += sprintf(p + len, "status:\t\t%s\n", | 6086 | len += sprintf(p + len, "status:\t\t%s\n", |
6078 | (status != 0) ? "enabled" : "disabled"); | 6087 | (status != 0) ? "enabled" : "disabled"); |
6079 | 6088 | ||
6080 | rc = fan_get_speed(&speed); | 6089 | rc = fan_get_speed(&speed); |
6081 | if (rc < 0) | 6090 | if (rc < 0) |
6082 | return rc; | 6091 | return rc; |
6083 | 6092 | ||
6084 | len += sprintf(p + len, "speed:\t\t%d\n", speed); | 6093 | len += sprintf(p + len, "speed:\t\t%d\n", speed); |
6085 | 6094 | ||
6086 | if (status & TP_EC_FAN_FULLSPEED) | 6095 | if (status & TP_EC_FAN_FULLSPEED) |
6087 | /* Disengaged mode takes precedence */ | 6096 | /* Disengaged mode takes precedence */ |
6088 | len += sprintf(p + len, "level:\t\tdisengaged\n"); | 6097 | len += sprintf(p + len, "level:\t\tdisengaged\n"); |
6089 | else if (status & TP_EC_FAN_AUTO) | 6098 | else if (status & TP_EC_FAN_AUTO) |
6090 | len += sprintf(p + len, "level:\t\tauto\n"); | 6099 | len += sprintf(p + len, "level:\t\tauto\n"); |
6091 | else | 6100 | else |
6092 | len += sprintf(p + len, "level:\t\t%d\n", status); | 6101 | len += sprintf(p + len, "level:\t\t%d\n", status); |
6093 | break; | 6102 | break; |
6094 | 6103 | ||
6095 | case TPACPI_FAN_NONE: | 6104 | case TPACPI_FAN_NONE: |
6096 | default: | 6105 | default: |
6097 | len += sprintf(p + len, "status:\t\tnot supported\n"); | 6106 | len += sprintf(p + len, "status:\t\tnot supported\n"); |
6098 | } | 6107 | } |
6099 | 6108 | ||
6100 | if (fan_control_commands & TPACPI_FAN_CMD_LEVEL) { | 6109 | if (fan_control_commands & TPACPI_FAN_CMD_LEVEL) { |
6101 | len += sprintf(p + len, "commands:\tlevel <level>"); | 6110 | len += sprintf(p + len, "commands:\tlevel <level>"); |
6102 | 6111 | ||
6103 | switch (fan_control_access_mode) { | 6112 | switch (fan_control_access_mode) { |
6104 | case TPACPI_FAN_WR_ACPI_SFAN: | 6113 | case TPACPI_FAN_WR_ACPI_SFAN: |
6105 | len += sprintf(p + len, " (<level> is 0-7)\n"); | 6114 | len += sprintf(p + len, " (<level> is 0-7)\n"); |
6106 | break; | 6115 | break; |
6107 | 6116 | ||
6108 | default: | 6117 | default: |
6109 | len += sprintf(p + len, " (<level> is 0-7, " | 6118 | len += sprintf(p + len, " (<level> is 0-7, " |
6110 | "auto, disengaged, full-speed)\n"); | 6119 | "auto, disengaged, full-speed)\n"); |
6111 | break; | 6120 | break; |
6112 | } | 6121 | } |
6113 | } | 6122 | } |
6114 | 6123 | ||
6115 | if (fan_control_commands & TPACPI_FAN_CMD_ENABLE) | 6124 | if (fan_control_commands & TPACPI_FAN_CMD_ENABLE) |
6116 | len += sprintf(p + len, "commands:\tenable, disable\n" | 6125 | len += sprintf(p + len, "commands:\tenable, disable\n" |
6117 | "commands:\twatchdog <timeout> (<timeout> " | 6126 | "commands:\twatchdog <timeout> (<timeout> " |
6118 | "is 0 (off), 1-120 (seconds))\n"); | 6127 | "is 0 (off), 1-120 (seconds))\n"); |
6119 | 6128 | ||
6120 | if (fan_control_commands & TPACPI_FAN_CMD_SPEED) | 6129 | if (fan_control_commands & TPACPI_FAN_CMD_SPEED) |
6121 | len += sprintf(p + len, "commands:\tspeed <speed>" | 6130 | len += sprintf(p + len, "commands:\tspeed <speed>" |
6122 | " (<speed> is 0-65535)\n"); | 6131 | " (<speed> is 0-65535)\n"); |
6123 | 6132 | ||
6124 | return len; | 6133 | return len; |
6125 | } | 6134 | } |
6126 | 6135 | ||
6127 | static int fan_write_cmd_level(const char *cmd, int *rc) | 6136 | static int fan_write_cmd_level(const char *cmd, int *rc) |
6128 | { | 6137 | { |
6129 | int level; | 6138 | int level; |
6130 | 6139 | ||
6131 | if (strlencmp(cmd, "level auto") == 0) | 6140 | if (strlencmp(cmd, "level auto") == 0) |
6132 | level = TP_EC_FAN_AUTO; | 6141 | level = TP_EC_FAN_AUTO; |
6133 | else if ((strlencmp(cmd, "level disengaged") == 0) | | 6142 | else if ((strlencmp(cmd, "level disengaged") == 0) | |
6134 | (strlencmp(cmd, "level full-speed") == 0)) | 6143 | (strlencmp(cmd, "level full-speed") == 0)) |
6135 | level = TP_EC_FAN_FULLSPEED; | 6144 | level = TP_EC_FAN_FULLSPEED; |
6136 | else if (sscanf(cmd, "level %d", &level) != 1) | 6145 | else if (sscanf(cmd, "level %d", &level) != 1) |
6137 | return 0; | 6146 | return 0; |
6138 | 6147 | ||
6139 | *rc = fan_set_level_safe(level); | 6148 | *rc = fan_set_level_safe(level); |
6140 | if (*rc == -ENXIO) | 6149 | if (*rc == -ENXIO) |
6141 | printk(TPACPI_ERR "level command accepted for unsupported " | 6150 | printk(TPACPI_ERR "level command accepted for unsupported " |
6142 | "access mode %d", fan_control_access_mode); | 6151 | "access mode %d", fan_control_access_mode); |
6143 | 6152 | ||
6144 | return 1; | 6153 | return 1; |
6145 | } | 6154 | } |
6146 | 6155 | ||
6147 | static int fan_write_cmd_enable(const char *cmd, int *rc) | 6156 | static int fan_write_cmd_enable(const char *cmd, int *rc) |
6148 | { | 6157 | { |
6149 | if (strlencmp(cmd, "enable") != 0) | 6158 | if (strlencmp(cmd, "enable") != 0) |
6150 | return 0; | 6159 | return 0; |
6151 | 6160 | ||
6152 | *rc = fan_set_enable(); | 6161 | *rc = fan_set_enable(); |
6153 | if (*rc == -ENXIO) | 6162 | if (*rc == -ENXIO) |
6154 | printk(TPACPI_ERR "enable command accepted for unsupported " | 6163 | printk(TPACPI_ERR "enable command accepted for unsupported " |
6155 | "access mode %d", fan_control_access_mode); | 6164 | "access mode %d", fan_control_access_mode); |
6156 | 6165 | ||
6157 | return 1; | 6166 | return 1; |
6158 | } | 6167 | } |
6159 | 6168 | ||
6160 | static int fan_write_cmd_disable(const char *cmd, int *rc) | 6169 | static int fan_write_cmd_disable(const char *cmd, int *rc) |
6161 | { | 6170 | { |
6162 | if (strlencmp(cmd, "disable") != 0) | 6171 | if (strlencmp(cmd, "disable") != 0) |
6163 | return 0; | 6172 | return 0; |
6164 | 6173 | ||
6165 | *rc = fan_set_disable(); | 6174 | *rc = fan_set_disable(); |
6166 | if (*rc == -ENXIO) | 6175 | if (*rc == -ENXIO) |
6167 | printk(TPACPI_ERR "disable command accepted for unsupported " | 6176 | printk(TPACPI_ERR "disable command accepted for unsupported " |
6168 | "access mode %d", fan_control_access_mode); | 6177 | "access mode %d", fan_control_access_mode); |
6169 | 6178 | ||
6170 | return 1; | 6179 | return 1; |
6171 | } | 6180 | } |
6172 | 6181 | ||
6173 | static int fan_write_cmd_speed(const char *cmd, int *rc) | 6182 | static int fan_write_cmd_speed(const char *cmd, int *rc) |
6174 | { | 6183 | { |
6175 | int speed; | 6184 | int speed; |
6176 | 6185 | ||
6177 | /* TODO: | 6186 | /* TODO: |
6178 | * Support speed <low> <medium> <high> ? */ | 6187 | * Support speed <low> <medium> <high> ? */ |
6179 | 6188 | ||
6180 | if (sscanf(cmd, "speed %d", &speed) != 1) | 6189 | if (sscanf(cmd, "speed %d", &speed) != 1) |
6181 | return 0; | 6190 | return 0; |
6182 | 6191 | ||
6183 | *rc = fan_set_speed(speed); | 6192 | *rc = fan_set_speed(speed); |
6184 | if (*rc == -ENXIO) | 6193 | if (*rc == -ENXIO) |
6185 | printk(TPACPI_ERR "speed command accepted for unsupported " | 6194 | printk(TPACPI_ERR "speed command accepted for unsupported " |
6186 | "access mode %d", fan_control_access_mode); | 6195 | "access mode %d", fan_control_access_mode); |
6187 | 6196 | ||
6188 | return 1; | 6197 | return 1; |
6189 | } | 6198 | } |
6190 | 6199 | ||
6191 | static int fan_write_cmd_watchdog(const char *cmd, int *rc) | 6200 | static int fan_write_cmd_watchdog(const char *cmd, int *rc) |
6192 | { | 6201 | { |
6193 | int interval; | 6202 | int interval; |
6194 | 6203 | ||
6195 | if (sscanf(cmd, "watchdog %d", &interval) != 1) | 6204 | if (sscanf(cmd, "watchdog %d", &interval) != 1) |
6196 | return 0; | 6205 | return 0; |
6197 | 6206 | ||
6198 | if (interval < 0 || interval > 120) | 6207 | if (interval < 0 || interval > 120) |
6199 | *rc = -EINVAL; | 6208 | *rc = -EINVAL; |
6200 | else | 6209 | else |
6201 | fan_watchdog_maxinterval = interval; | 6210 | fan_watchdog_maxinterval = interval; |
6202 | 6211 | ||
6203 | return 1; | 6212 | return 1; |
6204 | } | 6213 | } |
6205 | 6214 | ||
6206 | static int fan_write(char *buf) | 6215 | static int fan_write(char *buf) |
6207 | { | 6216 | { |
6208 | char *cmd; | 6217 | char *cmd; |
6209 | int rc = 0; | 6218 | int rc = 0; |
6210 | 6219 | ||
6211 | while (!rc && (cmd = next_cmd(&buf))) { | 6220 | while (!rc && (cmd = next_cmd(&buf))) { |
6212 | if (!((fan_control_commands & TPACPI_FAN_CMD_LEVEL) && | 6221 | if (!((fan_control_commands & TPACPI_FAN_CMD_LEVEL) && |
6213 | fan_write_cmd_level(cmd, &rc)) && | 6222 | fan_write_cmd_level(cmd, &rc)) && |
6214 | !((fan_control_commands & TPACPI_FAN_CMD_ENABLE) && | 6223 | !((fan_control_commands & TPACPI_FAN_CMD_ENABLE) && |
6215 | (fan_write_cmd_enable(cmd, &rc) || | 6224 | (fan_write_cmd_enable(cmd, &rc) || |
6216 | fan_write_cmd_disable(cmd, &rc) || | 6225 | fan_write_cmd_disable(cmd, &rc) || |
6217 | fan_write_cmd_watchdog(cmd, &rc))) && | 6226 | fan_write_cmd_watchdog(cmd, &rc))) && |
6218 | !((fan_control_commands & TPACPI_FAN_CMD_SPEED) && | 6227 | !((fan_control_commands & TPACPI_FAN_CMD_SPEED) && |
6219 | fan_write_cmd_speed(cmd, &rc)) | 6228 | fan_write_cmd_speed(cmd, &rc)) |
6220 | ) | 6229 | ) |
6221 | rc = -EINVAL; | 6230 | rc = -EINVAL; |
6222 | else if (!rc) | 6231 | else if (!rc) |
6223 | fan_watchdog_reset(); | 6232 | fan_watchdog_reset(); |
6224 | } | 6233 | } |
6225 | 6234 | ||
6226 | return rc; | 6235 | return rc; |
6227 | } | 6236 | } |
6228 | 6237 | ||
6229 | static struct ibm_struct fan_driver_data = { | 6238 | static struct ibm_struct fan_driver_data = { |
6230 | .name = "fan", | 6239 | .name = "fan", |
6231 | .read = fan_read, | 6240 | .read = fan_read, |
6232 | .write = fan_write, | 6241 | .write = fan_write, |
6233 | .exit = fan_exit, | 6242 | .exit = fan_exit, |
6234 | .suspend = fan_suspend, | 6243 | .suspend = fan_suspend, |
6235 | .resume = fan_resume, | 6244 | .resume = fan_resume, |
6236 | }; | 6245 | }; |
6237 | 6246 | ||
6238 | /**************************************************************************** | 6247 | /**************************************************************************** |
6239 | **************************************************************************** | 6248 | **************************************************************************** |
6240 | * | 6249 | * |
6241 | * Infrastructure | 6250 | * Infrastructure |
6242 | * | 6251 | * |
6243 | **************************************************************************** | 6252 | **************************************************************************** |
6244 | ****************************************************************************/ | 6253 | ****************************************************************************/ |
6245 | 6254 | ||
6246 | /* sysfs name ---------------------------------------------------------- */ | 6255 | /* sysfs name ---------------------------------------------------------- */ |
6247 | static ssize_t thinkpad_acpi_pdev_name_show(struct device *dev, | 6256 | static ssize_t thinkpad_acpi_pdev_name_show(struct device *dev, |
6248 | struct device_attribute *attr, | 6257 | struct device_attribute *attr, |
6249 | char *buf) | 6258 | char *buf) |
6250 | { | 6259 | { |
6251 | return snprintf(buf, PAGE_SIZE, "%s\n", TPACPI_NAME); | 6260 | return snprintf(buf, PAGE_SIZE, "%s\n", TPACPI_NAME); |
6252 | } | 6261 | } |
6253 | 6262 | ||
6254 | static struct device_attribute dev_attr_thinkpad_acpi_pdev_name = | 6263 | static struct device_attribute dev_attr_thinkpad_acpi_pdev_name = |
6255 | __ATTR(name, S_IRUGO, thinkpad_acpi_pdev_name_show, NULL); | 6264 | __ATTR(name, S_IRUGO, thinkpad_acpi_pdev_name_show, NULL); |
6256 | 6265 | ||
6257 | /* --------------------------------------------------------------------- */ | 6266 | /* --------------------------------------------------------------------- */ |
6258 | 6267 | ||
6259 | /* /proc support */ | 6268 | /* /proc support */ |
6260 | static struct proc_dir_entry *proc_dir; | 6269 | static struct proc_dir_entry *proc_dir; |
6261 | 6270 | ||
6262 | /* | 6271 | /* |
6263 | * Module and infrastructure proble, init and exit handling | 6272 | * Module and infrastructure proble, init and exit handling |
6264 | */ | 6273 | */ |
6265 | 6274 | ||
6266 | static int force_load; | 6275 | static int force_load; |
6267 | 6276 | ||
6268 | #ifdef CONFIG_THINKPAD_ACPI_DEBUG | 6277 | #ifdef CONFIG_THINKPAD_ACPI_DEBUG |
6269 | static const char * __init str_supported(int is_supported) | 6278 | static const char * __init str_supported(int is_supported) |
6270 | { | 6279 | { |
6271 | static char text_unsupported[] __initdata = "not supported"; | 6280 | static char text_unsupported[] __initdata = "not supported"; |
6272 | 6281 | ||
6273 | return (is_supported)? &text_unsupported[4] : &text_unsupported[0]; | 6282 | return (is_supported)? &text_unsupported[4] : &text_unsupported[0]; |
6274 | } | 6283 | } |
6275 | #endif /* CONFIG_THINKPAD_ACPI_DEBUG */ | 6284 | #endif /* CONFIG_THINKPAD_ACPI_DEBUG */ |
6276 | 6285 | ||
6277 | static void ibm_exit(struct ibm_struct *ibm) | 6286 | static void ibm_exit(struct ibm_struct *ibm) |
6278 | { | 6287 | { |
6279 | dbg_printk(TPACPI_DBG_EXIT, "removing %s\n", ibm->name); | 6288 | dbg_printk(TPACPI_DBG_EXIT, "removing %s\n", ibm->name); |
6280 | 6289 | ||
6281 | list_del_init(&ibm->all_drivers); | 6290 | list_del_init(&ibm->all_drivers); |
6282 | 6291 | ||
6283 | if (ibm->flags.acpi_notify_installed) { | 6292 | if (ibm->flags.acpi_notify_installed) { |
6284 | dbg_printk(TPACPI_DBG_EXIT, | 6293 | dbg_printk(TPACPI_DBG_EXIT, |
6285 | "%s: acpi_remove_notify_handler\n", ibm->name); | 6294 | "%s: acpi_remove_notify_handler\n", ibm->name); |
6286 | BUG_ON(!ibm->acpi); | 6295 | BUG_ON(!ibm->acpi); |
6287 | acpi_remove_notify_handler(*ibm->acpi->handle, | 6296 | acpi_remove_notify_handler(*ibm->acpi->handle, |
6288 | ibm->acpi->type, | 6297 | ibm->acpi->type, |
6289 | dispatch_acpi_notify); | 6298 | dispatch_acpi_notify); |
6290 | ibm->flags.acpi_notify_installed = 0; | 6299 | ibm->flags.acpi_notify_installed = 0; |
6291 | ibm->flags.acpi_notify_installed = 0; | 6300 | ibm->flags.acpi_notify_installed = 0; |
6292 | } | 6301 | } |
6293 | 6302 | ||
6294 | if (ibm->flags.proc_created) { | 6303 | if (ibm->flags.proc_created) { |
6295 | dbg_printk(TPACPI_DBG_EXIT, | 6304 | dbg_printk(TPACPI_DBG_EXIT, |
6296 | "%s: remove_proc_entry\n", ibm->name); | 6305 | "%s: remove_proc_entry\n", ibm->name); |
6297 | remove_proc_entry(ibm->name, proc_dir); | 6306 | remove_proc_entry(ibm->name, proc_dir); |
6298 | ibm->flags.proc_created = 0; | 6307 | ibm->flags.proc_created = 0; |
6299 | } | 6308 | } |
6300 | 6309 | ||
6301 | if (ibm->flags.acpi_driver_registered) { | 6310 | if (ibm->flags.acpi_driver_registered) { |
6302 | dbg_printk(TPACPI_DBG_EXIT, | 6311 | dbg_printk(TPACPI_DBG_EXIT, |
6303 | "%s: acpi_bus_unregister_driver\n", ibm->name); | 6312 | "%s: acpi_bus_unregister_driver\n", ibm->name); |
6304 | BUG_ON(!ibm->acpi); | 6313 | BUG_ON(!ibm->acpi); |
6305 | acpi_bus_unregister_driver(ibm->acpi->driver); | 6314 | acpi_bus_unregister_driver(ibm->acpi->driver); |
6306 | kfree(ibm->acpi->driver); | 6315 | kfree(ibm->acpi->driver); |
6307 | ibm->acpi->driver = NULL; | 6316 | ibm->acpi->driver = NULL; |
6308 | ibm->flags.acpi_driver_registered = 0; | 6317 | ibm->flags.acpi_driver_registered = 0; |
6309 | } | 6318 | } |
6310 | 6319 | ||
6311 | if (ibm->flags.init_called && ibm->exit) { | 6320 | if (ibm->flags.init_called && ibm->exit) { |
6312 | ibm->exit(); | 6321 | ibm->exit(); |
6313 | ibm->flags.init_called = 0; | 6322 | ibm->flags.init_called = 0; |
6314 | } | 6323 | } |
6315 | 6324 | ||
6316 | dbg_printk(TPACPI_DBG_INIT, "finished removing %s\n", ibm->name); | 6325 | dbg_printk(TPACPI_DBG_INIT, "finished removing %s\n", ibm->name); |
6317 | } | 6326 | } |
6318 | 6327 | ||
6319 | static int __init ibm_init(struct ibm_init_struct *iibm) | 6328 | static int __init ibm_init(struct ibm_init_struct *iibm) |
6320 | { | 6329 | { |
6321 | int ret; | 6330 | int ret; |
6322 | struct ibm_struct *ibm = iibm->data; | 6331 | struct ibm_struct *ibm = iibm->data; |
6323 | struct proc_dir_entry *entry; | 6332 | struct proc_dir_entry *entry; |
6324 | 6333 | ||
6325 | BUG_ON(ibm == NULL); | 6334 | BUG_ON(ibm == NULL); |
6326 | 6335 | ||
6327 | INIT_LIST_HEAD(&ibm->all_drivers); | 6336 | INIT_LIST_HEAD(&ibm->all_drivers); |
6328 | 6337 | ||
6329 | if (ibm->flags.experimental && !experimental) | 6338 | if (ibm->flags.experimental && !experimental) |
6330 | return 0; | 6339 | return 0; |
6331 | 6340 | ||
6332 | dbg_printk(TPACPI_DBG_INIT, | 6341 | dbg_printk(TPACPI_DBG_INIT, |
6333 | "probing for %s\n", ibm->name); | 6342 | "probing for %s\n", ibm->name); |
6334 | 6343 | ||
6335 | if (iibm->init) { | 6344 | if (iibm->init) { |
6336 | ret = iibm->init(iibm); | 6345 | ret = iibm->init(iibm); |
6337 | if (ret > 0) | 6346 | if (ret > 0) |
6338 | return 0; /* probe failed */ | 6347 | return 0; /* probe failed */ |
6339 | if (ret) | 6348 | if (ret) |
6340 | return ret; | 6349 | return ret; |
6341 | 6350 | ||
6342 | ibm->flags.init_called = 1; | 6351 | ibm->flags.init_called = 1; |
6343 | } | 6352 | } |
6344 | 6353 | ||
6345 | if (ibm->acpi) { | 6354 | if (ibm->acpi) { |
6346 | if (ibm->acpi->hid) { | 6355 | if (ibm->acpi->hid) { |
6347 | ret = register_tpacpi_subdriver(ibm); | 6356 | ret = register_tpacpi_subdriver(ibm); |
6348 | if (ret) | 6357 | if (ret) |
6349 | goto err_out; | 6358 | goto err_out; |
6350 | } | 6359 | } |
6351 | 6360 | ||
6352 | if (ibm->acpi->notify) { | 6361 | if (ibm->acpi->notify) { |
6353 | ret = setup_acpi_notify(ibm); | 6362 | ret = setup_acpi_notify(ibm); |
6354 | if (ret == -ENODEV) { | 6363 | if (ret == -ENODEV) { |
6355 | printk(TPACPI_NOTICE "disabling subdriver %s\n", | 6364 | printk(TPACPI_NOTICE "disabling subdriver %s\n", |
6356 | ibm->name); | 6365 | ibm->name); |
6357 | ret = 0; | 6366 | ret = 0; |
6358 | goto err_out; | 6367 | goto err_out; |
6359 | } | 6368 | } |
6360 | if (ret < 0) | 6369 | if (ret < 0) |
6361 | goto err_out; | 6370 | goto err_out; |
6362 | } | 6371 | } |
6363 | } | 6372 | } |
6364 | 6373 | ||
6365 | dbg_printk(TPACPI_DBG_INIT, | 6374 | dbg_printk(TPACPI_DBG_INIT, |
6366 | "%s installed\n", ibm->name); | 6375 | "%s installed\n", ibm->name); |
6367 | 6376 | ||
6368 | if (ibm->read) { | 6377 | if (ibm->read) { |
6369 | entry = create_proc_entry(ibm->name, | 6378 | entry = create_proc_entry(ibm->name, |
6370 | S_IFREG | S_IRUGO | S_IWUSR, | 6379 | S_IFREG | S_IRUGO | S_IWUSR, |
6371 | proc_dir); | 6380 | proc_dir); |
6372 | if (!entry) { | 6381 | if (!entry) { |
6373 | printk(TPACPI_ERR "unable to create proc entry %s\n", | 6382 | printk(TPACPI_ERR "unable to create proc entry %s\n", |
6374 | ibm->name); | 6383 | ibm->name); |
6375 | ret = -ENODEV; | 6384 | ret = -ENODEV; |
6376 | goto err_out; | 6385 | goto err_out; |
6377 | } | 6386 | } |
6378 | entry->owner = THIS_MODULE; | 6387 | entry->owner = THIS_MODULE; |
6379 | entry->data = ibm; | 6388 | entry->data = ibm; |
6380 | entry->read_proc = &dispatch_procfs_read; | 6389 | entry->read_proc = &dispatch_procfs_read; |
6381 | if (ibm->write) | 6390 | if (ibm->write) |
6382 | entry->write_proc = &dispatch_procfs_write; | 6391 | entry->write_proc = &dispatch_procfs_write; |
6383 | ibm->flags.proc_created = 1; | 6392 | ibm->flags.proc_created = 1; |
6384 | } | 6393 | } |
6385 | 6394 | ||
6386 | list_add_tail(&ibm->all_drivers, &tpacpi_all_drivers); | 6395 | list_add_tail(&ibm->all_drivers, &tpacpi_all_drivers); |
6387 | 6396 | ||
6388 | return 0; | 6397 | return 0; |
6389 | 6398 | ||
6390 | err_out: | 6399 | err_out: |
6391 | dbg_printk(TPACPI_DBG_INIT, | 6400 | dbg_printk(TPACPI_DBG_INIT, |
6392 | "%s: at error exit path with result %d\n", | 6401 | "%s: at error exit path with result %d\n", |
6393 | ibm->name, ret); | 6402 | ibm->name, ret); |
6394 | 6403 | ||
6395 | ibm_exit(ibm); | 6404 | ibm_exit(ibm); |
6396 | return (ret < 0)? ret : 0; | 6405 | return (ret < 0)? ret : 0; |
6397 | } | 6406 | } |
6398 | 6407 | ||
6399 | /* Probing */ | 6408 | /* Probing */ |
6400 | 6409 | ||
6401 | /* returns 0 - probe ok, or < 0 - probe error. | 6410 | /* returns 0 - probe ok, or < 0 - probe error. |
6402 | * Probe ok doesn't mean thinkpad found. | 6411 | * Probe ok doesn't mean thinkpad found. |
6403 | * On error, kfree() cleanup on tp->* is not performed, caller must do it */ | 6412 | * On error, kfree() cleanup on tp->* is not performed, caller must do it */ |
6404 | static int __must_check __init get_thinkpad_model_data( | 6413 | static int __must_check __init get_thinkpad_model_data( |
6405 | struct thinkpad_id_data *tp) | 6414 | struct thinkpad_id_data *tp) |
6406 | { | 6415 | { |
6407 | const struct dmi_device *dev = NULL; | 6416 | const struct dmi_device *dev = NULL; |
6408 | char ec_fw_string[18]; | 6417 | char ec_fw_string[18]; |
6409 | char const *s; | 6418 | char const *s; |
6410 | 6419 | ||
6411 | if (!tp) | 6420 | if (!tp) |
6412 | return -EINVAL; | 6421 | return -EINVAL; |
6413 | 6422 | ||
6414 | memset(tp, 0, sizeof(*tp)); | 6423 | memset(tp, 0, sizeof(*tp)); |
6415 | 6424 | ||
6416 | if (dmi_name_in_vendors("IBM")) | 6425 | if (dmi_name_in_vendors("IBM")) |
6417 | tp->vendor = PCI_VENDOR_ID_IBM; | 6426 | tp->vendor = PCI_VENDOR_ID_IBM; |
6418 | else if (dmi_name_in_vendors("LENOVO")) | 6427 | else if (dmi_name_in_vendors("LENOVO")) |
6419 | tp->vendor = PCI_VENDOR_ID_LENOVO; | 6428 | tp->vendor = PCI_VENDOR_ID_LENOVO; |
6420 | else | 6429 | else |
6421 | return 0; | 6430 | return 0; |
6422 | 6431 | ||
6423 | s = dmi_get_system_info(DMI_BIOS_VERSION); | 6432 | s = dmi_get_system_info(DMI_BIOS_VERSION); |
6424 | tp->bios_version_str = kstrdup(s, GFP_KERNEL); | 6433 | tp->bios_version_str = kstrdup(s, GFP_KERNEL); |
6425 | if (s && !tp->bios_version_str) | 6434 | if (s && !tp->bios_version_str) |
6426 | return -ENOMEM; | 6435 | return -ENOMEM; |
6427 | if (!tp->bios_version_str) | 6436 | if (!tp->bios_version_str) |
6428 | return 0; | 6437 | return 0; |
6429 | tp->bios_model = tp->bios_version_str[0] | 6438 | tp->bios_model = tp->bios_version_str[0] |
6430 | | (tp->bios_version_str[1] << 8); | 6439 | | (tp->bios_version_str[1] << 8); |
6431 | 6440 | ||
6432 | /* | 6441 | /* |
6433 | * ThinkPad T23 or newer, A31 or newer, R50e or newer, | 6442 | * ThinkPad T23 or newer, A31 or newer, R50e or newer, |
6434 | * X32 or newer, all Z series; Some models must have an | 6443 | * X32 or newer, all Z series; Some models must have an |
6435 | * up-to-date BIOS or they will not be detected. | 6444 | * up-to-date BIOS or they will not be detected. |
6436 | * | 6445 | * |
6437 | * See http://thinkwiki.org/wiki/List_of_DMI_IDs | 6446 | * See http://thinkwiki.org/wiki/List_of_DMI_IDs |
6438 | */ | 6447 | */ |
6439 | while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) { | 6448 | while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) { |
6440 | if (sscanf(dev->name, | 6449 | if (sscanf(dev->name, |
6441 | "IBM ThinkPad Embedded Controller -[%17c", | 6450 | "IBM ThinkPad Embedded Controller -[%17c", |
6442 | ec_fw_string) == 1) { | 6451 | ec_fw_string) == 1) { |
6443 | ec_fw_string[sizeof(ec_fw_string) - 1] = 0; | 6452 | ec_fw_string[sizeof(ec_fw_string) - 1] = 0; |
6444 | ec_fw_string[strcspn(ec_fw_string, " ]")] = 0; | 6453 | ec_fw_string[strcspn(ec_fw_string, " ]")] = 0; |
6445 | 6454 | ||
6446 | tp->ec_version_str = kstrdup(ec_fw_string, GFP_KERNEL); | 6455 | tp->ec_version_str = kstrdup(ec_fw_string, GFP_KERNEL); |
6447 | if (!tp->ec_version_str) | 6456 | if (!tp->ec_version_str) |
6448 | return -ENOMEM; | 6457 | return -ENOMEM; |
6449 | tp->ec_model = ec_fw_string[0] | 6458 | tp->ec_model = ec_fw_string[0] |
6450 | | (ec_fw_string[1] << 8); | 6459 | | (ec_fw_string[1] << 8); |
6451 | break; | 6460 | break; |
6452 | } | 6461 | } |
6453 | } | 6462 | } |
6454 | 6463 | ||
6455 | s = dmi_get_system_info(DMI_PRODUCT_VERSION); | 6464 | s = dmi_get_system_info(DMI_PRODUCT_VERSION); |
6456 | if (s && !strnicmp(s, "ThinkPad", 8)) { | 6465 | if (s && !strnicmp(s, "ThinkPad", 8)) { |
6457 | tp->model_str = kstrdup(s, GFP_KERNEL); | 6466 | tp->model_str = kstrdup(s, GFP_KERNEL); |
6458 | if (!tp->model_str) | 6467 | if (!tp->model_str) |
6459 | return -ENOMEM; | 6468 | return -ENOMEM; |
6460 | } | 6469 | } |
6461 | 6470 | ||
6462 | s = dmi_get_system_info(DMI_PRODUCT_NAME); | 6471 | s = dmi_get_system_info(DMI_PRODUCT_NAME); |
6463 | tp->nummodel_str = kstrdup(s, GFP_KERNEL); | 6472 | tp->nummodel_str = kstrdup(s, GFP_KERNEL); |
6464 | if (s && !tp->nummodel_str) | 6473 | if (s && !tp->nummodel_str) |
6465 | return -ENOMEM; | 6474 | return -ENOMEM; |
6466 | 6475 | ||
6467 | return 0; | 6476 | return 0; |
6468 | } | 6477 | } |
6469 | 6478 | ||
6470 | static int __init probe_for_thinkpad(void) | 6479 | static int __init probe_for_thinkpad(void) |
6471 | { | 6480 | { |
6472 | int is_thinkpad; | 6481 | int is_thinkpad; |
6473 | 6482 | ||
6474 | if (acpi_disabled) | 6483 | if (acpi_disabled) |
6475 | return -ENODEV; | 6484 | return -ENODEV; |
6476 | 6485 | ||
6477 | /* | 6486 | /* |
6478 | * Non-ancient models have better DMI tagging, but very old models | 6487 | * Non-ancient models have better DMI tagging, but very old models |
6479 | * don't. | 6488 | * don't. |
6480 | */ | 6489 | */ |
6481 | is_thinkpad = (thinkpad_id.model_str != NULL); | 6490 | is_thinkpad = (thinkpad_id.model_str != NULL); |
6482 | 6491 | ||
6483 | /* ec is required because many other handles are relative to it */ | 6492 | /* ec is required because many other handles are relative to it */ |
6484 | TPACPI_ACPIHANDLE_INIT(ec); | 6493 | TPACPI_ACPIHANDLE_INIT(ec); |
6485 | if (!ec_handle) { | 6494 | if (!ec_handle) { |
6486 | if (is_thinkpad) | 6495 | if (is_thinkpad) |
6487 | printk(TPACPI_ERR | 6496 | printk(TPACPI_ERR |
6488 | "Not yet supported ThinkPad detected!\n"); | 6497 | "Not yet supported ThinkPad detected!\n"); |
6489 | return -ENODEV; | 6498 | return -ENODEV; |
6490 | } | 6499 | } |
6491 | 6500 | ||
6492 | /* | 6501 | /* |
6493 | * Risks a regression on very old machines, but reduces potential | 6502 | * Risks a regression on very old machines, but reduces potential |
6494 | * false positives a damn great deal | 6503 | * false positives a damn great deal |
6495 | */ | 6504 | */ |
6496 | if (!is_thinkpad) | 6505 | if (!is_thinkpad) |
6497 | is_thinkpad = (thinkpad_id.vendor == PCI_VENDOR_ID_IBM); | 6506 | is_thinkpad = (thinkpad_id.vendor == PCI_VENDOR_ID_IBM); |
6498 | 6507 | ||
6499 | if (!is_thinkpad && !force_load) | 6508 | if (!is_thinkpad && !force_load) |
6500 | return -ENODEV; | 6509 | return -ENODEV; |
6501 | 6510 | ||
6502 | return 0; | 6511 | return 0; |
6503 | } | 6512 | } |
6504 | 6513 | ||
6505 | 6514 | ||
6506 | /* Module init, exit, parameters */ | 6515 | /* Module init, exit, parameters */ |
6507 | 6516 | ||
6508 | static struct ibm_init_struct ibms_init[] __initdata = { | 6517 | static struct ibm_init_struct ibms_init[] __initdata = { |
6509 | { | 6518 | { |
6510 | .init = thinkpad_acpi_driver_init, | 6519 | .init = thinkpad_acpi_driver_init, |
6511 | .data = &thinkpad_acpi_driver_data, | 6520 | .data = &thinkpad_acpi_driver_data, |
6512 | }, | 6521 | }, |
6513 | { | 6522 | { |
6514 | .init = hotkey_init, | 6523 | .init = hotkey_init, |
6515 | .data = &hotkey_driver_data, | 6524 | .data = &hotkey_driver_data, |
6516 | }, | 6525 | }, |
6517 | { | 6526 | { |
6518 | .init = bluetooth_init, | 6527 | .init = bluetooth_init, |
6519 | .data = &bluetooth_driver_data, | 6528 | .data = &bluetooth_driver_data, |
6520 | }, | 6529 | }, |
6521 | { | 6530 | { |
6522 | .init = wan_init, | 6531 | .init = wan_init, |
6523 | .data = &wan_driver_data, | 6532 | .data = &wan_driver_data, |
6524 | }, | 6533 | }, |
6525 | #ifdef CONFIG_THINKPAD_ACPI_VIDEO | 6534 | #ifdef CONFIG_THINKPAD_ACPI_VIDEO |
6526 | { | 6535 | { |
6527 | .init = video_init, | 6536 | .init = video_init, |
6528 | .data = &video_driver_data, | 6537 | .data = &video_driver_data, |
6529 | }, | 6538 | }, |
6530 | #endif | 6539 | #endif |
6531 | { | 6540 | { |
6532 | .init = light_init, | 6541 | .init = light_init, |
6533 | .data = &light_driver_data, | 6542 | .data = &light_driver_data, |
6534 | }, | 6543 | }, |
6535 | #ifdef CONFIG_THINKPAD_ACPI_DOCK | 6544 | #ifdef CONFIG_THINKPAD_ACPI_DOCK |
6536 | { | 6545 | { |
6537 | .init = dock_init, | 6546 | .init = dock_init, |
6538 | .data = &dock_driver_data[0], | 6547 | .data = &dock_driver_data[0], |
6539 | }, | 6548 | }, |
6540 | { | 6549 | { |
6541 | .init = dock_init2, | 6550 | .init = dock_init2, |
6542 | .data = &dock_driver_data[1], | 6551 | .data = &dock_driver_data[1], |
6543 | }, | 6552 | }, |
6544 | #endif | 6553 | #endif |
6545 | #ifdef CONFIG_THINKPAD_ACPI_BAY | 6554 | #ifdef CONFIG_THINKPAD_ACPI_BAY |
6546 | { | 6555 | { |
6547 | .init = bay_init, | 6556 | .init = bay_init, |
6548 | .data = &bay_driver_data, | 6557 | .data = &bay_driver_data, |
6549 | }, | 6558 | }, |
6550 | #endif | 6559 | #endif |
6551 | { | 6560 | { |
6552 | .init = cmos_init, | 6561 | .init = cmos_init, |
6553 | .data = &cmos_driver_data, | 6562 | .data = &cmos_driver_data, |
6554 | }, | 6563 | }, |
6555 | { | 6564 | { |
6556 | .init = led_init, | 6565 | .init = led_init, |
6557 | .data = &led_driver_data, | 6566 | .data = &led_driver_data, |
6558 | }, | 6567 | }, |
6559 | { | 6568 | { |
6560 | .init = beep_init, | 6569 | .init = beep_init, |
6561 | .data = &beep_driver_data, | 6570 | .data = &beep_driver_data, |
6562 | }, | 6571 | }, |
6563 | { | 6572 | { |
6564 | .init = thermal_init, | 6573 | .init = thermal_init, |
6565 | .data = &thermal_driver_data, | 6574 | .data = &thermal_driver_data, |
6566 | }, | 6575 | }, |
6567 | { | 6576 | { |
6568 | .data = &ecdump_driver_data, | 6577 | .data = &ecdump_driver_data, |
6569 | }, | 6578 | }, |
6570 | { | 6579 | { |
6571 | .init = brightness_init, | 6580 | .init = brightness_init, |
6572 | .data = &brightness_driver_data, | 6581 | .data = &brightness_driver_data, |
6573 | }, | 6582 | }, |
6574 | { | 6583 | { |
6575 | .data = &volume_driver_data, | 6584 | .data = &volume_driver_data, |
6576 | }, | 6585 | }, |
6577 | { | 6586 | { |
6578 | .init = fan_init, | 6587 | .init = fan_init, |
6579 | .data = &fan_driver_data, | 6588 | .data = &fan_driver_data, |
6580 | }, | 6589 | }, |
6581 | }; | 6590 | }; |
6582 | 6591 | ||
6583 | static int __init set_ibm_param(const char *val, struct kernel_param *kp) | 6592 | static int __init set_ibm_param(const char *val, struct kernel_param *kp) |
6584 | { | 6593 | { |
6585 | unsigned int i; | 6594 | unsigned int i; |
6586 | struct ibm_struct *ibm; | 6595 | struct ibm_struct *ibm; |
6587 | 6596 | ||
6588 | if (!kp || !kp->name || !val) | 6597 | if (!kp || !kp->name || !val) |
6589 | return -EINVAL; | 6598 | return -EINVAL; |
6590 | 6599 | ||
6591 | for (i = 0; i < ARRAY_SIZE(ibms_init); i++) { | 6600 | for (i = 0; i < ARRAY_SIZE(ibms_init); i++) { |
6592 | ibm = ibms_init[i].data; | 6601 | ibm = ibms_init[i].data; |
6593 | WARN_ON(ibm == NULL); | 6602 | WARN_ON(ibm == NULL); |
6594 | 6603 | ||
6595 | if (!ibm || !ibm->name) | 6604 | if (!ibm || !ibm->name) |
6596 | continue; | 6605 | continue; |
6597 | 6606 | ||
6598 | if (strcmp(ibm->name, kp->name) == 0 && ibm->write) { | 6607 | if (strcmp(ibm->name, kp->name) == 0 && ibm->write) { |
6599 | if (strlen(val) > sizeof(ibms_init[i].param) - 2) | 6608 | if (strlen(val) > sizeof(ibms_init[i].param) - 2) |
6600 | return -ENOSPC; | 6609 | return -ENOSPC; |
6601 | strcpy(ibms_init[i].param, val); | 6610 | strcpy(ibms_init[i].param, val); |
6602 | strcat(ibms_init[i].param, ","); | 6611 | strcat(ibms_init[i].param, ","); |
6603 | return 0; | 6612 | return 0; |
6604 | } | 6613 | } |
6605 | } | 6614 | } |
6606 | 6615 | ||
6607 | return -EINVAL; | 6616 | return -EINVAL; |
6608 | } | 6617 | } |
6609 | 6618 | ||
6610 | module_param(experimental, int, 0); | 6619 | module_param(experimental, int, 0); |
6611 | MODULE_PARM_DESC(experimental, | 6620 | MODULE_PARM_DESC(experimental, |
6612 | "Enables experimental features when non-zero"); | 6621 | "Enables experimental features when non-zero"); |
6613 | 6622 | ||
6614 | module_param_named(debug, dbg_level, uint, 0); | 6623 | module_param_named(debug, dbg_level, uint, 0); |
6615 | MODULE_PARM_DESC(debug, "Sets debug level bit-mask"); | 6624 | MODULE_PARM_DESC(debug, "Sets debug level bit-mask"); |
6616 | 6625 | ||
6617 | module_param(force_load, bool, 0); | 6626 | module_param(force_load, bool, 0); |
6618 | MODULE_PARM_DESC(force_load, | 6627 | MODULE_PARM_DESC(force_load, |
6619 | "Attempts to load the driver even on a " | 6628 | "Attempts to load the driver even on a " |
6620 | "mis-identified ThinkPad when true"); | 6629 | "mis-identified ThinkPad when true"); |
6621 | 6630 | ||
6622 | module_param_named(fan_control, fan_control_allowed, bool, 0); | 6631 | module_param_named(fan_control, fan_control_allowed, bool, 0); |
6623 | MODULE_PARM_DESC(fan_control, | 6632 | MODULE_PARM_DESC(fan_control, |
6624 | "Enables setting fan parameters features when true"); | 6633 | "Enables setting fan parameters features when true"); |
6625 | 6634 | ||
6626 | module_param_named(brightness_mode, brightness_mode, int, 0); | 6635 | module_param_named(brightness_mode, brightness_mode, int, 0); |
6627 | MODULE_PARM_DESC(brightness_mode, | 6636 | MODULE_PARM_DESC(brightness_mode, |
6628 | "Selects brightness control strategy: " | 6637 | "Selects brightness control strategy: " |
6629 | "0=auto, 1=EC, 2=CMOS, 3=both"); | 6638 | "0=auto, 1=EC, 2=CMOS, 3=both"); |
6630 | 6639 | ||
6631 | module_param(brightness_enable, uint, 0); | 6640 | module_param(brightness_enable, uint, 0); |
6632 | MODULE_PARM_DESC(brightness_enable, | 6641 | MODULE_PARM_DESC(brightness_enable, |
6633 | "Enables backlight control when 1, disables when 0"); | 6642 | "Enables backlight control when 1, disables when 0"); |
6634 | 6643 | ||
6635 | module_param(hotkey_report_mode, uint, 0); | 6644 | module_param(hotkey_report_mode, uint, 0); |
6636 | MODULE_PARM_DESC(hotkey_report_mode, | 6645 | MODULE_PARM_DESC(hotkey_report_mode, |
6637 | "used for backwards compatibility with userspace, " | 6646 | "used for backwards compatibility with userspace, " |
6638 | "see documentation"); | 6647 | "see documentation"); |
6639 | 6648 | ||
6640 | #define TPACPI_PARAM(feature) \ | 6649 | #define TPACPI_PARAM(feature) \ |
6641 | module_param_call(feature, set_ibm_param, NULL, NULL, 0); \ | 6650 | module_param_call(feature, set_ibm_param, NULL, NULL, 0); \ |
6642 | MODULE_PARM_DESC(feature, "Simulates thinkpad-acpi procfs command " \ | 6651 | MODULE_PARM_DESC(feature, "Simulates thinkpad-acpi procfs command " \ |
6643 | "at module load, see documentation") | 6652 | "at module load, see documentation") |
6644 | 6653 | ||
6645 | TPACPI_PARAM(hotkey); | 6654 | TPACPI_PARAM(hotkey); |
6646 | TPACPI_PARAM(bluetooth); | 6655 | TPACPI_PARAM(bluetooth); |
6647 | TPACPI_PARAM(video); | 6656 | TPACPI_PARAM(video); |
6648 | TPACPI_PARAM(light); | 6657 | TPACPI_PARAM(light); |
6649 | #ifdef CONFIG_THINKPAD_ACPI_DOCK | 6658 | #ifdef CONFIG_THINKPAD_ACPI_DOCK |
6650 | TPACPI_PARAM(dock); | 6659 | TPACPI_PARAM(dock); |
6651 | #endif | 6660 | #endif |
6652 | #ifdef CONFIG_THINKPAD_ACPI_BAY | 6661 | #ifdef CONFIG_THINKPAD_ACPI_BAY |
6653 | TPACPI_PARAM(bay); | 6662 | TPACPI_PARAM(bay); |
6654 | #endif /* CONFIG_THINKPAD_ACPI_BAY */ | 6663 | #endif /* CONFIG_THINKPAD_ACPI_BAY */ |
6655 | TPACPI_PARAM(cmos); | 6664 | TPACPI_PARAM(cmos); |
6656 | TPACPI_PARAM(led); | 6665 | TPACPI_PARAM(led); |
6657 | TPACPI_PARAM(beep); | 6666 | TPACPI_PARAM(beep); |
6658 | TPACPI_PARAM(ecdump); | 6667 | TPACPI_PARAM(ecdump); |
6659 | TPACPI_PARAM(brightness); | 6668 | TPACPI_PARAM(brightness); |
6660 | TPACPI_PARAM(volume); | 6669 | TPACPI_PARAM(volume); |
6661 | TPACPI_PARAM(fan); | 6670 | TPACPI_PARAM(fan); |
6662 | 6671 | ||
6663 | static void thinkpad_acpi_module_exit(void) | 6672 | static void thinkpad_acpi_module_exit(void) |
6664 | { | 6673 | { |
6665 | struct ibm_struct *ibm, *itmp; | 6674 | struct ibm_struct *ibm, *itmp; |
6666 | 6675 | ||
6667 | tpacpi_lifecycle = TPACPI_LIFE_EXITING; | 6676 | tpacpi_lifecycle = TPACPI_LIFE_EXITING; |
6668 | 6677 | ||
6669 | list_for_each_entry_safe_reverse(ibm, itmp, | 6678 | list_for_each_entry_safe_reverse(ibm, itmp, |
6670 | &tpacpi_all_drivers, | 6679 | &tpacpi_all_drivers, |
6671 | all_drivers) { | 6680 | all_drivers) { |
6672 | ibm_exit(ibm); | 6681 | ibm_exit(ibm); |
6673 | } | 6682 | } |
6674 | 6683 | ||
6675 | dbg_printk(TPACPI_DBG_INIT, "finished subdriver exit path...\n"); | 6684 | dbg_printk(TPACPI_DBG_INIT, "finished subdriver exit path...\n"); |
6676 | 6685 | ||
6677 | if (tpacpi_inputdev) { | 6686 | if (tpacpi_inputdev) { |
6678 | if (tp_features.input_device_registered) | 6687 | if (tp_features.input_device_registered) |
6679 | input_unregister_device(tpacpi_inputdev); | 6688 | input_unregister_device(tpacpi_inputdev); |
6680 | else | 6689 | else |
6681 | input_free_device(tpacpi_inputdev); | 6690 | input_free_device(tpacpi_inputdev); |
6682 | } | 6691 | } |
6683 | 6692 | ||
6684 | if (tpacpi_hwmon) | 6693 | if (tpacpi_hwmon) |
6685 | hwmon_device_unregister(tpacpi_hwmon); | 6694 | hwmon_device_unregister(tpacpi_hwmon); |
6686 | 6695 | ||
6687 | if (tp_features.sensors_pdev_attrs_registered) | 6696 | if (tp_features.sensors_pdev_attrs_registered) |
6688 | device_remove_file(&tpacpi_sensors_pdev->dev, | 6697 | device_remove_file(&tpacpi_sensors_pdev->dev, |
6689 | &dev_attr_thinkpad_acpi_pdev_name); | 6698 | &dev_attr_thinkpad_acpi_pdev_name); |
6690 | if (tpacpi_sensors_pdev) | 6699 | if (tpacpi_sensors_pdev) |
6691 | platform_device_unregister(tpacpi_sensors_pdev); | 6700 | platform_device_unregister(tpacpi_sensors_pdev); |
6692 | if (tpacpi_pdev) | 6701 | if (tpacpi_pdev) |
6693 | platform_device_unregister(tpacpi_pdev); | 6702 | platform_device_unregister(tpacpi_pdev); |
6694 | 6703 | ||
6695 | if (tp_features.sensors_pdrv_attrs_registered) | 6704 | if (tp_features.sensors_pdrv_attrs_registered) |
6696 | tpacpi_remove_driver_attributes(&tpacpi_hwmon_pdriver.driver); | 6705 | tpacpi_remove_driver_attributes(&tpacpi_hwmon_pdriver.driver); |
6697 | if (tp_features.platform_drv_attrs_registered) | 6706 | if (tp_features.platform_drv_attrs_registered) |
6698 | tpacpi_remove_driver_attributes(&tpacpi_pdriver.driver); | 6707 | tpacpi_remove_driver_attributes(&tpacpi_pdriver.driver); |
6699 | 6708 | ||
6700 | if (tp_features.sensors_pdrv_registered) | 6709 | if (tp_features.sensors_pdrv_registered) |
6701 | platform_driver_unregister(&tpacpi_hwmon_pdriver); | 6710 | platform_driver_unregister(&tpacpi_hwmon_pdriver); |
6702 | 6711 | ||
6703 | if (tp_features.platform_drv_registered) | 6712 | if (tp_features.platform_drv_registered) |
6704 | platform_driver_unregister(&tpacpi_pdriver); | 6713 | platform_driver_unregister(&tpacpi_pdriver); |
6705 | 6714 | ||
6706 | if (proc_dir) | 6715 | if (proc_dir) |
6707 | remove_proc_entry(TPACPI_PROC_DIR, acpi_root_dir); | 6716 | remove_proc_entry(TPACPI_PROC_DIR, acpi_root_dir); |
6708 | 6717 | ||
6709 | if (tpacpi_wq) | 6718 | if (tpacpi_wq) |
6710 | destroy_workqueue(tpacpi_wq); | 6719 | destroy_workqueue(tpacpi_wq); |
6711 | 6720 | ||
6712 | kfree(thinkpad_id.bios_version_str); | 6721 | kfree(thinkpad_id.bios_version_str); |
6713 | kfree(thinkpad_id.ec_version_str); | 6722 | kfree(thinkpad_id.ec_version_str); |
6714 | kfree(thinkpad_id.model_str); | 6723 | kfree(thinkpad_id.model_str); |
6715 | } | 6724 | } |
6716 | 6725 | ||
6717 | 6726 | ||
6718 | static int __init thinkpad_acpi_module_init(void) | 6727 | static int __init thinkpad_acpi_module_init(void) |
6719 | { | 6728 | { |
6720 | int ret, i; | 6729 | int ret, i; |
6721 | 6730 | ||
6722 | tpacpi_lifecycle = TPACPI_LIFE_INIT; | 6731 | tpacpi_lifecycle = TPACPI_LIFE_INIT; |
6723 | 6732 | ||
6724 | /* Parameter checking */ | 6733 | /* Parameter checking */ |
6725 | if (hotkey_report_mode > 2) | 6734 | if (hotkey_report_mode > 2) |
6726 | return -EINVAL; | 6735 | return -EINVAL; |
6727 | 6736 | ||
6728 | /* Driver-level probe */ | 6737 | /* Driver-level probe */ |
6729 | 6738 | ||
6730 | ret = get_thinkpad_model_data(&thinkpad_id); | 6739 | ret = get_thinkpad_model_data(&thinkpad_id); |
6731 | if (ret) { | 6740 | if (ret) { |
6732 | printk(TPACPI_ERR | 6741 | printk(TPACPI_ERR |
6733 | "unable to get DMI data: %d\n", ret); | 6742 | "unable to get DMI data: %d\n", ret); |
6734 | thinkpad_acpi_module_exit(); | 6743 | thinkpad_acpi_module_exit(); |
6735 | return ret; | 6744 | return ret; |
6736 | } | 6745 | } |
6737 | ret = probe_for_thinkpad(); | 6746 | ret = probe_for_thinkpad(); |
6738 | if (ret) { | 6747 | if (ret) { |
6739 | thinkpad_acpi_module_exit(); | 6748 | thinkpad_acpi_module_exit(); |
6740 | return ret; | 6749 | return ret; |
6741 | } | 6750 | } |
6742 | 6751 | ||
6743 | /* Driver initialization */ | 6752 | /* Driver initialization */ |
6744 | 6753 | ||
6745 | TPACPI_ACPIHANDLE_INIT(ecrd); | 6754 | TPACPI_ACPIHANDLE_INIT(ecrd); |
6746 | TPACPI_ACPIHANDLE_INIT(ecwr); | 6755 | TPACPI_ACPIHANDLE_INIT(ecwr); |
6747 | 6756 | ||
6748 | tpacpi_wq = create_singlethread_workqueue(TPACPI_WORKQUEUE_NAME); | 6757 | tpacpi_wq = create_singlethread_workqueue(TPACPI_WORKQUEUE_NAME); |
6749 | if (!tpacpi_wq) { | 6758 | if (!tpacpi_wq) { |
6750 | thinkpad_acpi_module_exit(); | 6759 | thinkpad_acpi_module_exit(); |
6751 | return -ENOMEM; | 6760 | return -ENOMEM; |
6752 | } | 6761 | } |
6753 | 6762 | ||
6754 | proc_dir = proc_mkdir(TPACPI_PROC_DIR, acpi_root_dir); | 6763 | proc_dir = proc_mkdir(TPACPI_PROC_DIR, acpi_root_dir); |
6755 | if (!proc_dir) { | 6764 | if (!proc_dir) { |
6756 | printk(TPACPI_ERR | 6765 | printk(TPACPI_ERR |
6757 | "unable to create proc dir " TPACPI_PROC_DIR); | 6766 | "unable to create proc dir " TPACPI_PROC_DIR); |
6758 | thinkpad_acpi_module_exit(); | 6767 | thinkpad_acpi_module_exit(); |
6759 | return -ENODEV; | 6768 | return -ENODEV; |
6760 | } | 6769 | } |
6761 | proc_dir->owner = THIS_MODULE; | 6770 | proc_dir->owner = THIS_MODULE; |
6762 | 6771 | ||
6763 | ret = platform_driver_register(&tpacpi_pdriver); | 6772 | ret = platform_driver_register(&tpacpi_pdriver); |
6764 | if (ret) { | 6773 | if (ret) { |
6765 | printk(TPACPI_ERR | 6774 | printk(TPACPI_ERR |
6766 | "unable to register main platform driver\n"); | 6775 | "unable to register main platform driver\n"); |
6767 | thinkpad_acpi_module_exit(); | 6776 | thinkpad_acpi_module_exit(); |
6768 | return ret; | 6777 | return ret; |
6769 | } | 6778 | } |
6770 | tp_features.platform_drv_registered = 1; | 6779 | tp_features.platform_drv_registered = 1; |
6771 | 6780 | ||
6772 | ret = platform_driver_register(&tpacpi_hwmon_pdriver); | 6781 | ret = platform_driver_register(&tpacpi_hwmon_pdriver); |
6773 | if (ret) { | 6782 | if (ret) { |
6774 | printk(TPACPI_ERR | 6783 | printk(TPACPI_ERR |
6775 | "unable to register hwmon platform driver\n"); | 6784 | "unable to register hwmon platform driver\n"); |
6776 | thinkpad_acpi_module_exit(); | 6785 | thinkpad_acpi_module_exit(); |
6777 | return ret; | 6786 | return ret; |
6778 | } | 6787 | } |
6779 | tp_features.sensors_pdrv_registered = 1; | 6788 | tp_features.sensors_pdrv_registered = 1; |
6780 | 6789 | ||
6781 | ret = tpacpi_create_driver_attributes(&tpacpi_pdriver.driver); | 6790 | ret = tpacpi_create_driver_attributes(&tpacpi_pdriver.driver); |
6782 | if (!ret) { | 6791 | if (!ret) { |
6783 | tp_features.platform_drv_attrs_registered = 1; | 6792 | tp_features.platform_drv_attrs_registered = 1; |
6784 | ret = tpacpi_create_driver_attributes( | 6793 | ret = tpacpi_create_driver_attributes( |
6785 | &tpacpi_hwmon_pdriver.driver); | 6794 | &tpacpi_hwmon_pdriver.driver); |
6786 | } | 6795 | } |
6787 | if (ret) { | 6796 | if (ret) { |
6788 | printk(TPACPI_ERR | 6797 | printk(TPACPI_ERR |
6789 | "unable to create sysfs driver attributes\n"); | 6798 | "unable to create sysfs driver attributes\n"); |
6790 | thinkpad_acpi_module_exit(); | 6799 | thinkpad_acpi_module_exit(); |
6791 | return ret; | 6800 | return ret; |
6792 | } | 6801 | } |
6793 | tp_features.sensors_pdrv_attrs_registered = 1; | 6802 | tp_features.sensors_pdrv_attrs_registered = 1; |
6794 | 6803 | ||
6795 | 6804 | ||
6796 | /* Device initialization */ | 6805 | /* Device initialization */ |
6797 | tpacpi_pdev = platform_device_register_simple(TPACPI_DRVR_NAME, -1, | 6806 | tpacpi_pdev = platform_device_register_simple(TPACPI_DRVR_NAME, -1, |
6798 | NULL, 0); | 6807 | NULL, 0); |
6799 | if (IS_ERR(tpacpi_pdev)) { | 6808 | if (IS_ERR(tpacpi_pdev)) { |
6800 | ret = PTR_ERR(tpacpi_pdev); | 6809 | ret = PTR_ERR(tpacpi_pdev); |
6801 | tpacpi_pdev = NULL; | 6810 | tpacpi_pdev = NULL; |
6802 | printk(TPACPI_ERR "unable to register platform device\n"); | 6811 | printk(TPACPI_ERR "unable to register platform device\n"); |
6803 | thinkpad_acpi_module_exit(); | 6812 | thinkpad_acpi_module_exit(); |
6804 | return ret; | 6813 | return ret; |
6805 | } | 6814 | } |
6806 | tpacpi_sensors_pdev = platform_device_register_simple( | 6815 | tpacpi_sensors_pdev = platform_device_register_simple( |
6807 | TPACPI_HWMON_DRVR_NAME, | 6816 | TPACPI_HWMON_DRVR_NAME, |
6808 | -1, NULL, 0); | 6817 | -1, NULL, 0); |
6809 | if (IS_ERR(tpacpi_sensors_pdev)) { | 6818 | if (IS_ERR(tpacpi_sensors_pdev)) { |
6810 | ret = PTR_ERR(tpacpi_sensors_pdev); | 6819 | ret = PTR_ERR(tpacpi_sensors_pdev); |
6811 | tpacpi_sensors_pdev = NULL; | 6820 | tpacpi_sensors_pdev = NULL; |
6812 | printk(TPACPI_ERR | 6821 | printk(TPACPI_ERR |
6813 | "unable to register hwmon platform device\n"); | 6822 | "unable to register hwmon platform device\n"); |
6814 | thinkpad_acpi_module_exit(); | 6823 | thinkpad_acpi_module_exit(); |
6815 | return ret; | 6824 | return ret; |
6816 | } | 6825 | } |
6817 | ret = device_create_file(&tpacpi_sensors_pdev->dev, | 6826 | ret = device_create_file(&tpacpi_sensors_pdev->dev, |
6818 | &dev_attr_thinkpad_acpi_pdev_name); | 6827 | &dev_attr_thinkpad_acpi_pdev_name); |
6819 | if (ret) { | 6828 | if (ret) { |
6820 | printk(TPACPI_ERR | 6829 | printk(TPACPI_ERR |
6821 | "unable to create sysfs hwmon device attributes\n"); | 6830 | "unable to create sysfs hwmon device attributes\n"); |
6822 | thinkpad_acpi_module_exit(); | 6831 | thinkpad_acpi_module_exit(); |
6823 | return ret; | 6832 | return ret; |
6824 | } | 6833 | } |
6825 | tp_features.sensors_pdev_attrs_registered = 1; | 6834 | tp_features.sensors_pdev_attrs_registered = 1; |
6826 | tpacpi_hwmon = hwmon_device_register(&tpacpi_sensors_pdev->dev); | 6835 | tpacpi_hwmon = hwmon_device_register(&tpacpi_sensors_pdev->dev); |
6827 | if (IS_ERR(tpacpi_hwmon)) { | 6836 | if (IS_ERR(tpacpi_hwmon)) { |
6828 | ret = PTR_ERR(tpacpi_hwmon); | 6837 | ret = PTR_ERR(tpacpi_hwmon); |
6829 | tpacpi_hwmon = NULL; | 6838 | tpacpi_hwmon = NULL; |
6830 | printk(TPACPI_ERR "unable to register hwmon device\n"); | 6839 | printk(TPACPI_ERR "unable to register hwmon device\n"); |
6831 | thinkpad_acpi_module_exit(); | 6840 | thinkpad_acpi_module_exit(); |
6832 | return ret; | 6841 | return ret; |
6833 | } | 6842 | } |
6834 | mutex_init(&tpacpi_inputdev_send_mutex); | 6843 | mutex_init(&tpacpi_inputdev_send_mutex); |
6835 | tpacpi_inputdev = input_allocate_device(); | 6844 | tpacpi_inputdev = input_allocate_device(); |
6836 | if (!tpacpi_inputdev) { | 6845 | if (!tpacpi_inputdev) { |
6837 | printk(TPACPI_ERR "unable to allocate input device\n"); | 6846 | printk(TPACPI_ERR "unable to allocate input device\n"); |
6838 | thinkpad_acpi_module_exit(); | 6847 | thinkpad_acpi_module_exit(); |
6839 | return -ENOMEM; | 6848 | return -ENOMEM; |
6840 | } else { | 6849 | } else { |
6841 | /* Prepare input device, but don't register */ | 6850 | /* Prepare input device, but don't register */ |
6842 | tpacpi_inputdev->name = "ThinkPad Extra Buttons"; | 6851 | tpacpi_inputdev->name = "ThinkPad Extra Buttons"; |
6843 | tpacpi_inputdev->phys = TPACPI_DRVR_NAME "/input0"; | 6852 | tpacpi_inputdev->phys = TPACPI_DRVR_NAME "/input0"; |
6844 | tpacpi_inputdev->id.bustype = BUS_HOST; | 6853 | tpacpi_inputdev->id.bustype = BUS_HOST; |
6845 | tpacpi_inputdev->id.vendor = (thinkpad_id.vendor) ? | 6854 | tpacpi_inputdev->id.vendor = (thinkpad_id.vendor) ? |
6846 | thinkpad_id.vendor : | 6855 | thinkpad_id.vendor : |
6847 | PCI_VENDOR_ID_IBM; | 6856 | PCI_VENDOR_ID_IBM; |
6848 | tpacpi_inputdev->id.product = TPACPI_HKEY_INPUT_PRODUCT; | 6857 | tpacpi_inputdev->id.product = TPACPI_HKEY_INPUT_PRODUCT; |
6849 | tpacpi_inputdev->id.version = TPACPI_HKEY_INPUT_VERSION; | 6858 | tpacpi_inputdev->id.version = TPACPI_HKEY_INPUT_VERSION; |
6850 | } | 6859 | } |
6851 | for (i = 0; i < ARRAY_SIZE(ibms_init); i++) { | 6860 | for (i = 0; i < ARRAY_SIZE(ibms_init); i++) { |
6852 | ret = ibm_init(&ibms_init[i]); | 6861 | ret = ibm_init(&ibms_init[i]); |
6853 | if (ret >= 0 && *ibms_init[i].param) | 6862 | if (ret >= 0 && *ibms_init[i].param) |
6854 | ret = ibms_init[i].data->write(ibms_init[i].param); | 6863 | ret = ibms_init[i].data->write(ibms_init[i].param); |
6855 | if (ret < 0) { | 6864 | if (ret < 0) { |
6856 | thinkpad_acpi_module_exit(); | 6865 | thinkpad_acpi_module_exit(); |
6857 | return ret; | 6866 | return ret; |
6858 | } | 6867 | } |
6859 | } | 6868 | } |
6860 | ret = input_register_device(tpacpi_inputdev); | 6869 | ret = input_register_device(tpacpi_inputdev); |
6861 | if (ret < 0) { | 6870 | if (ret < 0) { |
6862 | printk(TPACPI_ERR "unable to register input device\n"); | 6871 | printk(TPACPI_ERR "unable to register input device\n"); |
6863 | thinkpad_acpi_module_exit(); | 6872 | thinkpad_acpi_module_exit(); |
6864 | return ret; | 6873 | return ret; |
6865 | } else { | 6874 | } else { |
6866 | tp_features.input_device_registered = 1; | 6875 | tp_features.input_device_registered = 1; |
6867 | } | 6876 | } |
6868 | 6877 | ||
6869 | tpacpi_lifecycle = TPACPI_LIFE_RUNNING; | 6878 | tpacpi_lifecycle = TPACPI_LIFE_RUNNING; |
6870 | return 0; | 6879 | return 0; |
6871 | } | 6880 | } |
6872 | 6881 | ||
6873 | /* Please remove this in year 2009 */ | 6882 | /* Please remove this in year 2009 */ |
6874 | MODULE_ALIAS("ibm_acpi"); | 6883 | MODULE_ALIAS("ibm_acpi"); |
6875 | 6884 | ||
6876 | MODULE_ALIAS(TPACPI_DRVR_SHORTNAME); | 6885 | MODULE_ALIAS(TPACPI_DRVR_SHORTNAME); |
6877 | 6886 | ||
6878 | /* | 6887 | /* |
6879 | * DMI matching for module autoloading | 6888 | * DMI matching for module autoloading |
6880 | * | 6889 | * |
6881 | * See http://thinkwiki.org/wiki/List_of_DMI_IDs | 6890 | * See http://thinkwiki.org/wiki/List_of_DMI_IDs |
6882 | * See http://thinkwiki.org/wiki/BIOS_Upgrade_Downloads | 6891 | * See http://thinkwiki.org/wiki/BIOS_Upgrade_Downloads |
6883 | * | 6892 | * |
6884 | * Only models listed in thinkwiki will be supported, so add yours | 6893 | * Only models listed in thinkwiki will be supported, so add yours |
6885 | * if it is not there yet. | 6894 | * if it is not there yet. |
6886 | */ | 6895 | */ |
6887 | #define IBM_BIOS_MODULE_ALIAS(__type) \ | 6896 | #define IBM_BIOS_MODULE_ALIAS(__type) \ |
6888 | MODULE_ALIAS("dmi:bvnIBM:bvr" __type "ET??WW") | 6897 | MODULE_ALIAS("dmi:bvnIBM:bvr" __type "ET??WW") |
6889 | 6898 | ||
6890 | /* Non-ancient thinkpads */ | 6899 | /* Non-ancient thinkpads */ |
6891 | MODULE_ALIAS("dmi:bvnIBM:*:svnIBM:*:pvrThinkPad*:rvnIBM:*"); | 6900 | MODULE_ALIAS("dmi:bvnIBM:*:svnIBM:*:pvrThinkPad*:rvnIBM:*"); |
6892 | MODULE_ALIAS("dmi:bvnLENOVO:*:svnLENOVO:*:pvrThinkPad*:rvnLENOVO:*"); | 6901 | MODULE_ALIAS("dmi:bvnLENOVO:*:svnLENOVO:*:pvrThinkPad*:rvnLENOVO:*"); |
6893 | 6902 | ||
6894 | /* Ancient thinkpad BIOSes have to be identified by | 6903 | /* Ancient thinkpad BIOSes have to be identified by |
6895 | * BIOS type or model number, and there are far less | 6904 | * BIOS type or model number, and there are far less |
6896 | * BIOS types than model numbers... */ | 6905 | * BIOS types than model numbers... */ |
6897 | IBM_BIOS_MODULE_ALIAS("I[B,D,H,I,M,N,O,T,W,V,Y,Z]"); | 6906 | IBM_BIOS_MODULE_ALIAS("I[B,D,H,I,M,N,O,T,W,V,Y,Z]"); |
6898 | IBM_BIOS_MODULE_ALIAS("1[0,3,6,8,A-G,I,K,M-P,S,T]"); | 6907 | IBM_BIOS_MODULE_ALIAS("1[0,3,6,8,A-G,I,K,M-P,S,T]"); |
6899 | IBM_BIOS_MODULE_ALIAS("K[U,X-Z]"); | 6908 | IBM_BIOS_MODULE_ALIAS("K[U,X-Z]"); |
6900 | 6909 | ||
6901 | MODULE_AUTHOR("Borislav Deianov, Henrique de Moraes Holschuh"); | 6910 | MODULE_AUTHOR("Borislav Deianov, Henrique de Moraes Holschuh"); |
6902 | MODULE_DESCRIPTION(TPACPI_DESC); | 6911 | MODULE_DESCRIPTION(TPACPI_DESC); |
6903 | MODULE_VERSION(TPACPI_VERSION); | 6912 | MODULE_VERSION(TPACPI_VERSION); |
6904 | MODULE_LICENSE("GPL"); | 6913 | MODULE_LICENSE("GPL"); |
6905 | 6914 | ||
6906 | module_init(thinkpad_acpi_module_init); | 6915 | module_init(thinkpad_acpi_module_init); |
6907 | module_exit(thinkpad_acpi_module_exit); | 6916 | module_exit(thinkpad_acpi_module_exit); |
6908 | 6917 |
include/acpi/acpi_bus.h
1 | /* | 1 | /* |
2 | * acpi_bus.h - ACPI Bus Driver ($Revision: 22 $) | 2 | * acpi_bus.h - ACPI Bus Driver ($Revision: 22 $) |
3 | * | 3 | * |
4 | * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> | 4 | * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> |
5 | * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> | 5 | * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> |
6 | * | 6 | * |
7 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 7 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
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 as published by | 10 | * it under the terms of the GNU General Public License as published by |
11 | * the Free Software Foundation; either version 2 of the License, or (at | 11 | * the Free Software Foundation; either version 2 of the License, or (at |
12 | * your option) any later version. | 12 | * your option) any later version. |
13 | * | 13 | * |
14 | * This program is distributed in the hope that it will be useful, but | 14 | * This program is distributed in the hope that it will be useful, but |
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | 15 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
17 | * General Public License for more details. | 17 | * General Public License for more details. |
18 | * | 18 | * |
19 | * You should have received a copy of the GNU General Public License along | 19 | * You should have received a copy of the GNU General Public License along |
20 | * with this program; if not, write to the Free Software Foundation, Inc., | 20 | * with this program; if not, write to the Free Software Foundation, Inc., |
21 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | 21 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. |
22 | * | 22 | * |
23 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 23 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
24 | */ | 24 | */ |
25 | 25 | ||
26 | #ifndef __ACPI_BUS_H__ | 26 | #ifndef __ACPI_BUS_H__ |
27 | #define __ACPI_BUS_H__ | 27 | #define __ACPI_BUS_H__ |
28 | 28 | ||
29 | #include <linux/device.h> | 29 | #include <linux/device.h> |
30 | 30 | ||
31 | #include <acpi/acpi.h> | 31 | #include <acpi/acpi.h> |
32 | 32 | ||
33 | #define PREFIX "ACPI: " | 33 | #define PREFIX "ACPI: " |
34 | 34 | ||
35 | /* TBD: Make dynamic */ | 35 | /* TBD: Make dynamic */ |
36 | #define ACPI_MAX_HANDLES 10 | 36 | #define ACPI_MAX_HANDLES 10 |
37 | struct acpi_handle_list { | 37 | struct acpi_handle_list { |
38 | u32 count; | 38 | u32 count; |
39 | acpi_handle handles[ACPI_MAX_HANDLES]; | 39 | acpi_handle handles[ACPI_MAX_HANDLES]; |
40 | }; | 40 | }; |
41 | 41 | ||
42 | /* acpi_utils.h */ | 42 | /* acpi_utils.h */ |
43 | acpi_status | 43 | acpi_status |
44 | acpi_extract_package(union acpi_object *package, | 44 | acpi_extract_package(union acpi_object *package, |
45 | struct acpi_buffer *format, struct acpi_buffer *buffer); | 45 | struct acpi_buffer *format, struct acpi_buffer *buffer); |
46 | acpi_status | 46 | acpi_status |
47 | acpi_evaluate_integer(acpi_handle handle, | 47 | acpi_evaluate_integer(acpi_handle handle, |
48 | acpi_string pathname, | 48 | acpi_string pathname, |
49 | struct acpi_object_list *arguments, unsigned long long *data); | 49 | struct acpi_object_list *arguments, unsigned long long *data); |
50 | acpi_status | 50 | acpi_status |
51 | acpi_evaluate_reference(acpi_handle handle, | 51 | acpi_evaluate_reference(acpi_handle handle, |
52 | acpi_string pathname, | 52 | acpi_string pathname, |
53 | struct acpi_object_list *arguments, | 53 | struct acpi_object_list *arguments, |
54 | struct acpi_handle_list *list); | 54 | struct acpi_handle_list *list); |
55 | 55 | ||
56 | #ifdef CONFIG_ACPI | 56 | #ifdef CONFIG_ACPI |
57 | 57 | ||
58 | #include <linux/proc_fs.h> | 58 | #include <linux/proc_fs.h> |
59 | 59 | ||
60 | #define ACPI_BUS_FILE_ROOT "acpi" | 60 | #define ACPI_BUS_FILE_ROOT "acpi" |
61 | extern struct proc_dir_entry *acpi_root_dir; | 61 | extern struct proc_dir_entry *acpi_root_dir; |
62 | 62 | ||
63 | enum acpi_bus_removal_type { | 63 | enum acpi_bus_removal_type { |
64 | ACPI_BUS_REMOVAL_NORMAL = 0, | 64 | ACPI_BUS_REMOVAL_NORMAL = 0, |
65 | ACPI_BUS_REMOVAL_EJECT, | 65 | ACPI_BUS_REMOVAL_EJECT, |
66 | ACPI_BUS_REMOVAL_SUPRISE, | 66 | ACPI_BUS_REMOVAL_SUPRISE, |
67 | ACPI_BUS_REMOVAL_TYPE_COUNT | 67 | ACPI_BUS_REMOVAL_TYPE_COUNT |
68 | }; | 68 | }; |
69 | 69 | ||
70 | enum acpi_bus_device_type { | 70 | enum acpi_bus_device_type { |
71 | ACPI_BUS_TYPE_DEVICE = 0, | 71 | ACPI_BUS_TYPE_DEVICE = 0, |
72 | ACPI_BUS_TYPE_POWER, | 72 | ACPI_BUS_TYPE_POWER, |
73 | ACPI_BUS_TYPE_PROCESSOR, | 73 | ACPI_BUS_TYPE_PROCESSOR, |
74 | ACPI_BUS_TYPE_THERMAL, | 74 | ACPI_BUS_TYPE_THERMAL, |
75 | ACPI_BUS_TYPE_SYSTEM, | 75 | ACPI_BUS_TYPE_SYSTEM, |
76 | ACPI_BUS_TYPE_POWER_BUTTON, | 76 | ACPI_BUS_TYPE_POWER_BUTTON, |
77 | ACPI_BUS_TYPE_SLEEP_BUTTON, | 77 | ACPI_BUS_TYPE_SLEEP_BUTTON, |
78 | ACPI_BUS_DEVICE_TYPE_COUNT | 78 | ACPI_BUS_DEVICE_TYPE_COUNT |
79 | }; | 79 | }; |
80 | 80 | ||
81 | struct acpi_driver; | 81 | struct acpi_driver; |
82 | struct acpi_device; | 82 | struct acpi_device; |
83 | 83 | ||
84 | /* | 84 | /* |
85 | * ACPI Driver | 85 | * ACPI Driver |
86 | * ----------- | 86 | * ----------- |
87 | */ | 87 | */ |
88 | 88 | ||
89 | typedef int (*acpi_op_add) (struct acpi_device * device); | 89 | typedef int (*acpi_op_add) (struct acpi_device * device); |
90 | typedef int (*acpi_op_remove) (struct acpi_device * device, int type); | 90 | typedef int (*acpi_op_remove) (struct acpi_device * device, int type); |
91 | typedef int (*acpi_op_lock) (struct acpi_device * device, int type); | 91 | typedef int (*acpi_op_lock) (struct acpi_device * device, int type); |
92 | typedef int (*acpi_op_start) (struct acpi_device * device); | 92 | typedef int (*acpi_op_start) (struct acpi_device * device); |
93 | typedef int (*acpi_op_stop) (struct acpi_device * device, int type); | 93 | typedef int (*acpi_op_stop) (struct acpi_device * device, int type); |
94 | typedef int (*acpi_op_suspend) (struct acpi_device * device, | 94 | typedef int (*acpi_op_suspend) (struct acpi_device * device, |
95 | pm_message_t state); | 95 | pm_message_t state); |
96 | typedef int (*acpi_op_resume) (struct acpi_device * device); | 96 | typedef int (*acpi_op_resume) (struct acpi_device * device); |
97 | typedef int (*acpi_op_scan) (struct acpi_device * device); | 97 | typedef int (*acpi_op_scan) (struct acpi_device * device); |
98 | typedef int (*acpi_op_bind) (struct acpi_device * device); | 98 | typedef int (*acpi_op_bind) (struct acpi_device * device); |
99 | typedef int (*acpi_op_unbind) (struct acpi_device * device); | 99 | typedef int (*acpi_op_unbind) (struct acpi_device * device); |
100 | typedef int (*acpi_op_shutdown) (struct acpi_device * device); | 100 | typedef int (*acpi_op_shutdown) (struct acpi_device * device); |
101 | 101 | ||
102 | struct acpi_bus_ops { | 102 | struct acpi_bus_ops { |
103 | u32 acpi_op_add:1; | 103 | u32 acpi_op_add:1; |
104 | u32 acpi_op_remove:1; | 104 | u32 acpi_op_remove:1; |
105 | u32 acpi_op_lock:1; | 105 | u32 acpi_op_lock:1; |
106 | u32 acpi_op_start:1; | 106 | u32 acpi_op_start:1; |
107 | u32 acpi_op_stop:1; | 107 | u32 acpi_op_stop:1; |
108 | u32 acpi_op_suspend:1; | 108 | u32 acpi_op_suspend:1; |
109 | u32 acpi_op_resume:1; | 109 | u32 acpi_op_resume:1; |
110 | u32 acpi_op_scan:1; | 110 | u32 acpi_op_scan:1; |
111 | u32 acpi_op_bind:1; | 111 | u32 acpi_op_bind:1; |
112 | u32 acpi_op_unbind:1; | 112 | u32 acpi_op_unbind:1; |
113 | u32 acpi_op_shutdown:1; | 113 | u32 acpi_op_shutdown:1; |
114 | u32 reserved:21; | 114 | u32 reserved:21; |
115 | }; | 115 | }; |
116 | 116 | ||
117 | struct acpi_device_ops { | 117 | struct acpi_device_ops { |
118 | acpi_op_add add; | 118 | acpi_op_add add; |
119 | acpi_op_remove remove; | 119 | acpi_op_remove remove; |
120 | acpi_op_lock lock; | 120 | acpi_op_lock lock; |
121 | acpi_op_start start; | 121 | acpi_op_start start; |
122 | acpi_op_stop stop; | 122 | acpi_op_stop stop; |
123 | acpi_op_suspend suspend; | 123 | acpi_op_suspend suspend; |
124 | acpi_op_resume resume; | 124 | acpi_op_resume resume; |
125 | acpi_op_scan scan; | 125 | acpi_op_scan scan; |
126 | acpi_op_bind bind; | 126 | acpi_op_bind bind; |
127 | acpi_op_unbind unbind; | 127 | acpi_op_unbind unbind; |
128 | acpi_op_shutdown shutdown; | 128 | acpi_op_shutdown shutdown; |
129 | }; | 129 | }; |
130 | 130 | ||
131 | struct acpi_driver { | 131 | struct acpi_driver { |
132 | char name[80]; | 132 | char name[80]; |
133 | char class[80]; | 133 | char class[80]; |
134 | const struct acpi_device_id *ids; /* Supported Hardware IDs */ | 134 | const struct acpi_device_id *ids; /* Supported Hardware IDs */ |
135 | struct acpi_device_ops ops; | 135 | struct acpi_device_ops ops; |
136 | struct device_driver drv; | 136 | struct device_driver drv; |
137 | struct module *owner; | 137 | struct module *owner; |
138 | }; | 138 | }; |
139 | 139 | ||
140 | /* | 140 | /* |
141 | * ACPI Device | 141 | * ACPI Device |
142 | * ----------- | 142 | * ----------- |
143 | */ | 143 | */ |
144 | 144 | ||
145 | /* Status (_STA) */ | 145 | /* Status (_STA) */ |
146 | 146 | ||
147 | struct acpi_device_status { | 147 | struct acpi_device_status { |
148 | u32 present:1; | 148 | u32 present:1; |
149 | u32 enabled:1; | 149 | u32 enabled:1; |
150 | u32 show_in_ui:1; | 150 | u32 show_in_ui:1; |
151 | u32 functional:1; | 151 | u32 functional:1; |
152 | u32 battery_present:1; | 152 | u32 battery_present:1; |
153 | u32 reserved:27; | 153 | u32 reserved:27; |
154 | }; | 154 | }; |
155 | 155 | ||
156 | /* Flags */ | 156 | /* Flags */ |
157 | 157 | ||
158 | struct acpi_device_flags { | 158 | struct acpi_device_flags { |
159 | u32 dynamic_status:1; | 159 | u32 dynamic_status:1; |
160 | u32 hardware_id:1; | 160 | u32 hardware_id:1; |
161 | u32 compatible_ids:1; | 161 | u32 compatible_ids:1; |
162 | u32 bus_address:1; | 162 | u32 bus_address:1; |
163 | u32 unique_id:1; | 163 | u32 unique_id:1; |
164 | u32 removable:1; | 164 | u32 removable:1; |
165 | u32 ejectable:1; | 165 | u32 ejectable:1; |
166 | u32 lockable:1; | 166 | u32 lockable:1; |
167 | u32 suprise_removal_ok:1; | 167 | u32 suprise_removal_ok:1; |
168 | u32 power_manageable:1; | 168 | u32 power_manageable:1; |
169 | u32 performance_manageable:1; | 169 | u32 performance_manageable:1; |
170 | u32 wake_capable:1; /* Wakeup(_PRW) supported? */ | 170 | u32 wake_capable:1; /* Wakeup(_PRW) supported? */ |
171 | u32 force_power_state:1; | 171 | u32 force_power_state:1; |
172 | u32 reserved:19; | 172 | u32 reserved:19; |
173 | }; | 173 | }; |
174 | 174 | ||
175 | /* File System */ | 175 | /* File System */ |
176 | 176 | ||
177 | struct acpi_device_dir { | 177 | struct acpi_device_dir { |
178 | struct proc_dir_entry *entry; | 178 | struct proc_dir_entry *entry; |
179 | }; | 179 | }; |
180 | 180 | ||
181 | #define acpi_device_dir(d) ((d)->dir.entry) | 181 | #define acpi_device_dir(d) ((d)->dir.entry) |
182 | 182 | ||
183 | /* Plug and Play */ | 183 | /* Plug and Play */ |
184 | 184 | ||
185 | typedef char acpi_bus_id[5]; | 185 | typedef char acpi_bus_id[5]; |
186 | typedef unsigned long acpi_bus_address; | 186 | typedef unsigned long acpi_bus_address; |
187 | typedef char acpi_hardware_id[15]; | 187 | typedef char acpi_hardware_id[15]; |
188 | typedef char acpi_unique_id[9]; | 188 | typedef char acpi_unique_id[9]; |
189 | typedef char acpi_device_name[40]; | 189 | typedef char acpi_device_name[40]; |
190 | typedef char acpi_device_class[20]; | 190 | typedef char acpi_device_class[20]; |
191 | 191 | ||
192 | struct acpi_device_pnp { | 192 | struct acpi_device_pnp { |
193 | acpi_bus_id bus_id; /* Object name */ | 193 | acpi_bus_id bus_id; /* Object name */ |
194 | acpi_bus_address bus_address; /* _ADR */ | 194 | acpi_bus_address bus_address; /* _ADR */ |
195 | acpi_hardware_id hardware_id; /* _HID */ | 195 | acpi_hardware_id hardware_id; /* _HID */ |
196 | struct acpi_compatible_id_list *cid_list; /* _CIDs */ | 196 | struct acpi_compatible_id_list *cid_list; /* _CIDs */ |
197 | acpi_unique_id unique_id; /* _UID */ | 197 | acpi_unique_id unique_id; /* _UID */ |
198 | acpi_device_name device_name; /* Driver-determined */ | 198 | acpi_device_name device_name; /* Driver-determined */ |
199 | acpi_device_class device_class; /* " */ | 199 | acpi_device_class device_class; /* " */ |
200 | }; | 200 | }; |
201 | 201 | ||
202 | #define acpi_device_bid(d) ((d)->pnp.bus_id) | 202 | #define acpi_device_bid(d) ((d)->pnp.bus_id) |
203 | #define acpi_device_adr(d) ((d)->pnp.bus_address) | 203 | #define acpi_device_adr(d) ((d)->pnp.bus_address) |
204 | #define acpi_device_hid(d) ((d)->pnp.hardware_id) | 204 | #define acpi_device_hid(d) ((d)->pnp.hardware_id) |
205 | #define acpi_device_uid(d) ((d)->pnp.unique_id) | 205 | #define acpi_device_uid(d) ((d)->pnp.unique_id) |
206 | #define acpi_device_name(d) ((d)->pnp.device_name) | 206 | #define acpi_device_name(d) ((d)->pnp.device_name) |
207 | #define acpi_device_class(d) ((d)->pnp.device_class) | 207 | #define acpi_device_class(d) ((d)->pnp.device_class) |
208 | 208 | ||
209 | /* Power Management */ | 209 | /* Power Management */ |
210 | 210 | ||
211 | struct acpi_device_power_flags { | 211 | struct acpi_device_power_flags { |
212 | u32 explicit_get:1; /* _PSC present? */ | 212 | u32 explicit_get:1; /* _PSC present? */ |
213 | u32 power_resources:1; /* Power resources */ | 213 | u32 power_resources:1; /* Power resources */ |
214 | u32 inrush_current:1; /* Serialize Dx->D0 */ | 214 | u32 inrush_current:1; /* Serialize Dx->D0 */ |
215 | u32 power_removed:1; /* Optimize Dx->D0 */ | 215 | u32 power_removed:1; /* Optimize Dx->D0 */ |
216 | u32 reserved:28; | 216 | u32 reserved:28; |
217 | }; | 217 | }; |
218 | 218 | ||
219 | struct acpi_device_power_state { | 219 | struct acpi_device_power_state { |
220 | struct { | 220 | struct { |
221 | u8 valid:1; | 221 | u8 valid:1; |
222 | u8 explicit_set:1; /* _PSx present? */ | 222 | u8 explicit_set:1; /* _PSx present? */ |
223 | u8 reserved:6; | 223 | u8 reserved:6; |
224 | } flags; | 224 | } flags; |
225 | int power; /* % Power (compared to D0) */ | 225 | int power; /* % Power (compared to D0) */ |
226 | int latency; /* Dx->D0 time (microseconds) */ | 226 | int latency; /* Dx->D0 time (microseconds) */ |
227 | struct acpi_handle_list resources; /* Power resources referenced */ | 227 | struct acpi_handle_list resources; /* Power resources referenced */ |
228 | }; | 228 | }; |
229 | 229 | ||
230 | struct acpi_device_power { | 230 | struct acpi_device_power { |
231 | int state; /* Current state */ | 231 | int state; /* Current state */ |
232 | struct acpi_device_power_flags flags; | 232 | struct acpi_device_power_flags flags; |
233 | struct acpi_device_power_state states[4]; /* Power states (D0-D3) */ | 233 | struct acpi_device_power_state states[4]; /* Power states (D0-D3) */ |
234 | }; | 234 | }; |
235 | 235 | ||
236 | /* Performance Management */ | 236 | /* Performance Management */ |
237 | 237 | ||
238 | struct acpi_device_perf_flags { | 238 | struct acpi_device_perf_flags { |
239 | u8 reserved:8; | 239 | u8 reserved:8; |
240 | }; | 240 | }; |
241 | 241 | ||
242 | struct acpi_device_perf_state { | 242 | struct acpi_device_perf_state { |
243 | struct { | 243 | struct { |
244 | u8 valid:1; | 244 | u8 valid:1; |
245 | u8 reserved:7; | 245 | u8 reserved:7; |
246 | } flags; | 246 | } flags; |
247 | u8 power; /* % Power (compared to P0) */ | 247 | u8 power; /* % Power (compared to P0) */ |
248 | u8 performance; /* % Performance ( " ) */ | 248 | u8 performance; /* % Performance ( " ) */ |
249 | int latency; /* Px->P0 time (microseconds) */ | 249 | int latency; /* Px->P0 time (microseconds) */ |
250 | }; | 250 | }; |
251 | 251 | ||
252 | struct acpi_device_perf { | 252 | struct acpi_device_perf { |
253 | int state; | 253 | int state; |
254 | struct acpi_device_perf_flags flags; | 254 | struct acpi_device_perf_flags flags; |
255 | int state_count; | 255 | int state_count; |
256 | struct acpi_device_perf_state *states; | 256 | struct acpi_device_perf_state *states; |
257 | }; | 257 | }; |
258 | 258 | ||
259 | /* Wakeup Management */ | 259 | /* Wakeup Management */ |
260 | struct acpi_device_wakeup_flags { | 260 | struct acpi_device_wakeup_flags { |
261 | u8 valid:1; /* Can successfully enable wakeup? */ | 261 | u8 valid:1; /* Can successfully enable wakeup? */ |
262 | u8 prepared:1; /* Has the wake-up capability been enabled? */ | 262 | u8 prepared:1; /* Has the wake-up capability been enabled? */ |
263 | u8 run_wake:1; /* Run-Wake GPE devices */ | 263 | u8 run_wake:1; /* Run-Wake GPE devices */ |
264 | }; | 264 | }; |
265 | 265 | ||
266 | struct acpi_device_wakeup_state { | 266 | struct acpi_device_wakeup_state { |
267 | u8 enabled:1; | 267 | u8 enabled:1; |
268 | }; | 268 | }; |
269 | 269 | ||
270 | struct acpi_device_wakeup { | 270 | struct acpi_device_wakeup { |
271 | acpi_handle gpe_device; | 271 | acpi_handle gpe_device; |
272 | acpi_integer gpe_number; | 272 | acpi_integer gpe_number; |
273 | acpi_integer sleep_state; | 273 | acpi_integer sleep_state; |
274 | struct acpi_handle_list resources; | 274 | struct acpi_handle_list resources; |
275 | struct acpi_device_wakeup_state state; | 275 | struct acpi_device_wakeup_state state; |
276 | struct acpi_device_wakeup_flags flags; | 276 | struct acpi_device_wakeup_flags flags; |
277 | }; | 277 | }; |
278 | 278 | ||
279 | /* Device */ | 279 | /* Device */ |
280 | 280 | ||
281 | struct acpi_device { | 281 | struct acpi_device { |
282 | acpi_handle handle; | 282 | acpi_handle handle; |
283 | struct acpi_device *parent; | 283 | struct acpi_device *parent; |
284 | struct list_head children; | 284 | struct list_head children; |
285 | struct list_head node; | 285 | struct list_head node; |
286 | struct list_head wakeup_list; | 286 | struct list_head wakeup_list; |
287 | struct list_head g_list; | 287 | struct list_head g_list; |
288 | struct acpi_device_status status; | 288 | struct acpi_device_status status; |
289 | struct acpi_device_flags flags; | 289 | struct acpi_device_flags flags; |
290 | struct acpi_device_pnp pnp; | 290 | struct acpi_device_pnp pnp; |
291 | struct acpi_device_power power; | 291 | struct acpi_device_power power; |
292 | struct acpi_device_wakeup wakeup; | 292 | struct acpi_device_wakeup wakeup; |
293 | struct acpi_device_perf performance; | 293 | struct acpi_device_perf performance; |
294 | struct acpi_device_dir dir; | 294 | struct acpi_device_dir dir; |
295 | struct acpi_device_ops ops; | 295 | struct acpi_device_ops ops; |
296 | struct acpi_driver *driver; | 296 | struct acpi_driver *driver; |
297 | void *driver_data; | 297 | void *driver_data; |
298 | struct device dev; | 298 | struct device dev; |
299 | struct acpi_bus_ops bus_ops; /* workaround for different code path for hotplug */ | 299 | struct acpi_bus_ops bus_ops; /* workaround for different code path for hotplug */ |
300 | enum acpi_bus_removal_type removal_type; /* indicate for different removal type */ | 300 | enum acpi_bus_removal_type removal_type; /* indicate for different removal type */ |
301 | }; | 301 | }; |
302 | 302 | ||
303 | static inline void *acpi_driver_data(struct acpi_device *d) | 303 | static inline void *acpi_driver_data(struct acpi_device *d) |
304 | { | 304 | { |
305 | return d->driver_data; | 305 | return d->driver_data; |
306 | } | 306 | } |
307 | 307 | ||
308 | #define to_acpi_device(d) container_of(d, struct acpi_device, dev) | 308 | #define to_acpi_device(d) container_of(d, struct acpi_device, dev) |
309 | #define to_acpi_driver(d) container_of(d, struct acpi_driver, drv) | 309 | #define to_acpi_driver(d) container_of(d, struct acpi_driver, drv) |
310 | 310 | ||
311 | /* acpi_device.dev.bus == &acpi_bus_type */ | 311 | /* acpi_device.dev.bus == &acpi_bus_type */ |
312 | extern struct bus_type acpi_bus_type; | 312 | extern struct bus_type acpi_bus_type; |
313 | 313 | ||
314 | /* | 314 | /* |
315 | * Events | 315 | * Events |
316 | * ------ | 316 | * ------ |
317 | */ | 317 | */ |
318 | 318 | ||
319 | struct acpi_bus_event { | 319 | struct acpi_bus_event { |
320 | struct list_head node; | 320 | struct list_head node; |
321 | acpi_device_class device_class; | 321 | acpi_device_class device_class; |
322 | acpi_bus_id bus_id; | 322 | acpi_bus_id bus_id; |
323 | u32 type; | 323 | u32 type; |
324 | u32 data; | 324 | u32 data; |
325 | }; | 325 | }; |
326 | 326 | ||
327 | extern struct kobject *acpi_kobj; | 327 | extern struct kobject *acpi_kobj; |
328 | extern int acpi_bus_generate_netlink_event(const char*, const char*, u8, int); | 328 | extern int acpi_bus_generate_netlink_event(const char*, const char*, u8, int); |
329 | void acpi_bus_private_data_handler(acpi_handle, u32, void *); | 329 | void acpi_bus_private_data_handler(acpi_handle, u32, void *); |
330 | int acpi_bus_get_private_data(acpi_handle, void **); | 330 | int acpi_bus_get_private_data(acpi_handle, void **); |
331 | extern int acpi_notifier_call_chain(struct acpi_device *, u32, u32); | 331 | extern int acpi_notifier_call_chain(struct acpi_device *, u32, u32); |
332 | extern int register_acpi_notifier(struct notifier_block *); | 332 | extern int register_acpi_notifier(struct notifier_block *); |
333 | extern int unregister_acpi_notifier(struct notifier_block *); | 333 | extern int unregister_acpi_notifier(struct notifier_block *); |
334 | 334 | ||
335 | extern int register_acpi_bus_notifier(struct notifier_block *nb); | 335 | extern int register_acpi_bus_notifier(struct notifier_block *nb); |
336 | extern void unregister_acpi_bus_notifier(struct notifier_block *nb); | 336 | extern void unregister_acpi_bus_notifier(struct notifier_block *nb); |
337 | /* | 337 | /* |
338 | * External Functions | 338 | * External Functions |
339 | */ | 339 | */ |
340 | 340 | ||
341 | int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device); | 341 | int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device); |
342 | void acpi_bus_data_handler(acpi_handle handle, u32 function, void *context); | 342 | void acpi_bus_data_handler(acpi_handle handle, u32 function, void *context); |
343 | int acpi_bus_get_status(struct acpi_device *device); | 343 | int acpi_bus_get_status(struct acpi_device *device); |
344 | int acpi_bus_get_power(acpi_handle handle, int *state); | 344 | int acpi_bus_get_power(acpi_handle handle, int *state); |
345 | int acpi_bus_set_power(acpi_handle handle, int state); | 345 | int acpi_bus_set_power(acpi_handle handle, int state); |
346 | bool acpi_bus_power_manageable(acpi_handle handle); | 346 | bool acpi_bus_power_manageable(acpi_handle handle); |
347 | bool acpi_bus_can_wakeup(acpi_handle handle); | 347 | bool acpi_bus_can_wakeup(acpi_handle handle); |
348 | #ifdef CONFIG_ACPI_PROC_EVENT | 348 | #ifdef CONFIG_ACPI_PROC_EVENT |
349 | int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data); | 349 | int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data); |
350 | int acpi_bus_generate_proc_event4(const char *class, const char *bid, u8 type, int data); | 350 | int acpi_bus_generate_proc_event4(const char *class, const char *bid, u8 type, int data); |
351 | int acpi_bus_receive_event(struct acpi_bus_event *event); | 351 | int acpi_bus_receive_event(struct acpi_bus_event *event); |
352 | #else | 352 | #else |
353 | static inline int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data) | 353 | static inline int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data) |
354 | { return 0; } | 354 | { return 0; } |
355 | #endif | 355 | #endif |
356 | int acpi_bus_register_driver(struct acpi_driver *driver); | 356 | int acpi_bus_register_driver(struct acpi_driver *driver); |
357 | void acpi_bus_unregister_driver(struct acpi_driver *driver); | 357 | void acpi_bus_unregister_driver(struct acpi_driver *driver); |
358 | int acpi_bus_add(struct acpi_device **child, struct acpi_device *parent, | 358 | int acpi_bus_add(struct acpi_device **child, struct acpi_device *parent, |
359 | acpi_handle handle, int type); | 359 | acpi_handle handle, int type); |
360 | int acpi_bus_trim(struct acpi_device *start, int rmdevice); | 360 | int acpi_bus_trim(struct acpi_device *start, int rmdevice); |
361 | int acpi_bus_start(struct acpi_device *device); | 361 | int acpi_bus_start(struct acpi_device *device); |
362 | acpi_status acpi_bus_get_ejd(acpi_handle handle, acpi_handle * ejd); | 362 | acpi_status acpi_bus_get_ejd(acpi_handle handle, acpi_handle * ejd); |
363 | int acpi_match_device_ids(struct acpi_device *device, | 363 | int acpi_match_device_ids(struct acpi_device *device, |
364 | const struct acpi_device_id *ids); | 364 | const struct acpi_device_id *ids); |
365 | int acpi_create_dir(struct acpi_device *); | 365 | int acpi_create_dir(struct acpi_device *); |
366 | void acpi_remove_dir(struct acpi_device *); | 366 | void acpi_remove_dir(struct acpi_device *); |
367 | 367 | ||
368 | /* | 368 | /* |
369 | * Bind physical devices with ACPI devices | 369 | * Bind physical devices with ACPI devices |
370 | */ | 370 | */ |
371 | #include <linux/device.h> | 371 | #include <linux/device.h> |
372 | struct acpi_bus_type { | 372 | struct acpi_bus_type { |
373 | struct list_head list; | 373 | struct list_head list; |
374 | struct bus_type *bus; | 374 | struct bus_type *bus; |
375 | /* For general devices under the bus */ | 375 | /* For general devices under the bus */ |
376 | int (*find_device) (struct device *, acpi_handle *); | 376 | int (*find_device) (struct device *, acpi_handle *); |
377 | /* For bridges, such as PCI root bridge, IDE controller */ | 377 | /* For bridges, such as PCI root bridge, IDE controller */ |
378 | int (*find_bridge) (struct device *, acpi_handle *); | 378 | int (*find_bridge) (struct device *, acpi_handle *); |
379 | }; | 379 | }; |
380 | int register_acpi_bus_type(struct acpi_bus_type *); | 380 | int register_acpi_bus_type(struct acpi_bus_type *); |
381 | int unregister_acpi_bus_type(struct acpi_bus_type *); | 381 | int unregister_acpi_bus_type(struct acpi_bus_type *); |
382 | struct device *acpi_get_physical_device(acpi_handle); | 382 | struct device *acpi_get_physical_device(acpi_handle); |
383 | struct device *acpi_get_physical_pci_device(acpi_handle); | ||
384 | |||
383 | /* helper */ | 385 | /* helper */ |
384 | acpi_handle acpi_get_child(acpi_handle, acpi_integer); | 386 | acpi_handle acpi_get_child(acpi_handle, acpi_integer); |
385 | acpi_handle acpi_get_pci_rootbridge_handle(unsigned int, unsigned int); | 387 | acpi_handle acpi_get_pci_rootbridge_handle(unsigned int, unsigned int); |
386 | #define DEVICE_ACPI_HANDLE(dev) ((acpi_handle)((dev)->archdata.acpi_handle)) | 388 | #define DEVICE_ACPI_HANDLE(dev) ((acpi_handle)((dev)->archdata.acpi_handle)) |
387 | 389 | ||
388 | #ifdef CONFIG_PM_SLEEP | 390 | #ifdef CONFIG_PM_SLEEP |
389 | int acpi_pm_device_sleep_state(struct device *, int *); | 391 | int acpi_pm_device_sleep_state(struct device *, int *); |
390 | int acpi_pm_device_sleep_wake(struct device *, bool); | 392 | int acpi_pm_device_sleep_wake(struct device *, bool); |
391 | #else /* !CONFIG_PM_SLEEP */ | 393 | #else /* !CONFIG_PM_SLEEP */ |
392 | static inline int acpi_pm_device_sleep_state(struct device *d, int *p) | 394 | static inline int acpi_pm_device_sleep_state(struct device *d, int *p) |
393 | { | 395 | { |
394 | if (p) | 396 | if (p) |
395 | *p = ACPI_STATE_D0; | 397 | *p = ACPI_STATE_D0; |
396 | return ACPI_STATE_D3; | 398 | return ACPI_STATE_D3; |
397 | } | 399 | } |
398 | static inline int acpi_pm_device_sleep_wake(struct device *dev, bool enable) | 400 | static inline int acpi_pm_device_sleep_wake(struct device *dev, bool enable) |
399 | { | 401 | { |
400 | return -ENODEV; | 402 | return -ENODEV; |
401 | } | 403 | } |
402 | #endif /* !CONFIG_PM_SLEEP */ | 404 | #endif /* !CONFIG_PM_SLEEP */ |
403 | 405 | ||
404 | #endif /* CONFIG_ACPI */ | 406 | #endif /* CONFIG_ACPI */ |
405 | 407 | ||
406 | #endif /*__ACPI_BUS_H__*/ | 408 | #endif /*__ACPI_BUS_H__*/ |
407 | 409 |
include/linux/acpi.h
1 | /* | 1 | /* |
2 | * acpi.h - ACPI Interface | 2 | * acpi.h - ACPI Interface |
3 | * | 3 | * |
4 | * Copyright (C) 2001 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> | 4 | * Copyright (C) 2001 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> |
5 | * | 5 | * |
6 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 6 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify | 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 | 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 | 10 | * the Free Software Foundation; either version 2 of the License, or |
11 | * (at your option) any later version. | 11 | * (at your option) any later version. |
12 | * | 12 | * |
13 | * This program is distributed in the hope that it will be useful, | 13 | * This program is distributed in the hope that it will be useful, |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | * GNU General Public License for more details. | 16 | * GNU General Public License for more details. |
17 | * | 17 | * |
18 | * You should have received a copy of the GNU General Public License | 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 | 19 | * along with this program; if not, write to the Free Software |
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 | */ | 23 | */ |
24 | 24 | ||
25 | #ifndef _LINUX_ACPI_H | 25 | #ifndef _LINUX_ACPI_H |
26 | #define _LINUX_ACPI_H | 26 | #define _LINUX_ACPI_H |
27 | 27 | ||
28 | #include <linux/ioport.h> /* for struct resource */ | 28 | #include <linux/ioport.h> /* for struct resource */ |
29 | 29 | ||
30 | #ifdef CONFIG_ACPI | 30 | #ifdef CONFIG_ACPI |
31 | 31 | ||
32 | #ifndef _LINUX | 32 | #ifndef _LINUX |
33 | #define _LINUX | 33 | #define _LINUX |
34 | #endif | 34 | #endif |
35 | 35 | ||
36 | #include <linux/list.h> | 36 | #include <linux/list.h> |
37 | #include <linux/mod_devicetable.h> | 37 | #include <linux/mod_devicetable.h> |
38 | 38 | ||
39 | #include <acpi/acpi.h> | 39 | #include <acpi/acpi.h> |
40 | #include <acpi/acpi_bus.h> | 40 | #include <acpi/acpi_bus.h> |
41 | #include <acpi/acpi_drivers.h> | 41 | #include <acpi/acpi_drivers.h> |
42 | #include <acpi/acpi_numa.h> | 42 | #include <acpi/acpi_numa.h> |
43 | #include <asm/acpi.h> | 43 | #include <asm/acpi.h> |
44 | #include <linux/dmi.h> | 44 | #include <linux/dmi.h> |
45 | 45 | ||
46 | 46 | ||
47 | enum acpi_irq_model_id { | 47 | enum acpi_irq_model_id { |
48 | ACPI_IRQ_MODEL_PIC = 0, | 48 | ACPI_IRQ_MODEL_PIC = 0, |
49 | ACPI_IRQ_MODEL_IOAPIC, | 49 | ACPI_IRQ_MODEL_IOAPIC, |
50 | ACPI_IRQ_MODEL_IOSAPIC, | 50 | ACPI_IRQ_MODEL_IOSAPIC, |
51 | ACPI_IRQ_MODEL_PLATFORM, | 51 | ACPI_IRQ_MODEL_PLATFORM, |
52 | ACPI_IRQ_MODEL_COUNT | 52 | ACPI_IRQ_MODEL_COUNT |
53 | }; | 53 | }; |
54 | 54 | ||
55 | extern enum acpi_irq_model_id acpi_irq_model; | 55 | extern enum acpi_irq_model_id acpi_irq_model; |
56 | 56 | ||
57 | enum acpi_interrupt_id { | 57 | enum acpi_interrupt_id { |
58 | ACPI_INTERRUPT_PMI = 1, | 58 | ACPI_INTERRUPT_PMI = 1, |
59 | ACPI_INTERRUPT_INIT, | 59 | ACPI_INTERRUPT_INIT, |
60 | ACPI_INTERRUPT_CPEI, | 60 | ACPI_INTERRUPT_CPEI, |
61 | ACPI_INTERRUPT_COUNT | 61 | ACPI_INTERRUPT_COUNT |
62 | }; | 62 | }; |
63 | 63 | ||
64 | #define ACPI_SPACE_MEM 0 | 64 | #define ACPI_SPACE_MEM 0 |
65 | 65 | ||
66 | enum acpi_address_range_id { | 66 | enum acpi_address_range_id { |
67 | ACPI_ADDRESS_RANGE_MEMORY = 1, | 67 | ACPI_ADDRESS_RANGE_MEMORY = 1, |
68 | ACPI_ADDRESS_RANGE_RESERVED = 2, | 68 | ACPI_ADDRESS_RANGE_RESERVED = 2, |
69 | ACPI_ADDRESS_RANGE_ACPI = 3, | 69 | ACPI_ADDRESS_RANGE_ACPI = 3, |
70 | ACPI_ADDRESS_RANGE_NVS = 4, | 70 | ACPI_ADDRESS_RANGE_NVS = 4, |
71 | ACPI_ADDRESS_RANGE_COUNT | 71 | ACPI_ADDRESS_RANGE_COUNT |
72 | }; | 72 | }; |
73 | 73 | ||
74 | 74 | ||
75 | /* Table Handlers */ | 75 | /* Table Handlers */ |
76 | 76 | ||
77 | typedef int (*acpi_table_handler) (struct acpi_table_header *table); | 77 | typedef int (*acpi_table_handler) (struct acpi_table_header *table); |
78 | 78 | ||
79 | typedef int (*acpi_table_entry_handler) (struct acpi_subtable_header *header, const unsigned long end); | 79 | typedef int (*acpi_table_entry_handler) (struct acpi_subtable_header *header, const unsigned long end); |
80 | 80 | ||
81 | char * __acpi_map_table (unsigned long phys_addr, unsigned long size); | 81 | char * __acpi_map_table (unsigned long phys_addr, unsigned long size); |
82 | int early_acpi_boot_init(void); | 82 | int early_acpi_boot_init(void); |
83 | int acpi_boot_init (void); | 83 | int acpi_boot_init (void); |
84 | int acpi_boot_table_init (void); | 84 | int acpi_boot_table_init (void); |
85 | int acpi_mps_check (void); | 85 | int acpi_mps_check (void); |
86 | int acpi_numa_init (void); | 86 | int acpi_numa_init (void); |
87 | 87 | ||
88 | int acpi_table_init (void); | 88 | int acpi_table_init (void); |
89 | int acpi_table_parse (char *id, acpi_table_handler handler); | 89 | int acpi_table_parse (char *id, acpi_table_handler handler); |
90 | int __init acpi_table_parse_entries(char *id, unsigned long table_size, | 90 | int __init acpi_table_parse_entries(char *id, unsigned long table_size, |
91 | int entry_id, acpi_table_entry_handler handler, unsigned int max_entries); | 91 | int entry_id, acpi_table_entry_handler handler, unsigned int max_entries); |
92 | int acpi_table_parse_madt (enum acpi_madt_type id, acpi_table_entry_handler handler, unsigned int max_entries); | 92 | int acpi_table_parse_madt (enum acpi_madt_type id, acpi_table_entry_handler handler, unsigned int max_entries); |
93 | int acpi_parse_mcfg (struct acpi_table_header *header); | 93 | int acpi_parse_mcfg (struct acpi_table_header *header); |
94 | void acpi_table_print_madt_entry (struct acpi_subtable_header *madt); | 94 | void acpi_table_print_madt_entry (struct acpi_subtable_header *madt); |
95 | 95 | ||
96 | /* the following four functions are architecture-dependent */ | 96 | /* the following four functions are architecture-dependent */ |
97 | void acpi_numa_slit_init (struct acpi_table_slit *slit); | 97 | void acpi_numa_slit_init (struct acpi_table_slit *slit); |
98 | void acpi_numa_processor_affinity_init (struct acpi_srat_cpu_affinity *pa); | 98 | void acpi_numa_processor_affinity_init (struct acpi_srat_cpu_affinity *pa); |
99 | void acpi_numa_memory_affinity_init (struct acpi_srat_mem_affinity *ma); | 99 | void acpi_numa_memory_affinity_init (struct acpi_srat_mem_affinity *ma); |
100 | void acpi_numa_arch_fixup(void); | 100 | void acpi_numa_arch_fixup(void); |
101 | 101 | ||
102 | #ifdef CONFIG_ACPI_HOTPLUG_CPU | 102 | #ifdef CONFIG_ACPI_HOTPLUG_CPU |
103 | /* Arch dependent functions for cpu hotplug support */ | 103 | /* Arch dependent functions for cpu hotplug support */ |
104 | int acpi_map_lsapic(acpi_handle handle, int *pcpu); | 104 | int acpi_map_lsapic(acpi_handle handle, int *pcpu); |
105 | int acpi_unmap_lsapic(int cpu); | 105 | int acpi_unmap_lsapic(int cpu); |
106 | #endif /* CONFIG_ACPI_HOTPLUG_CPU */ | 106 | #endif /* CONFIG_ACPI_HOTPLUG_CPU */ |
107 | 107 | ||
108 | int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base); | 108 | int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base); |
109 | int acpi_unregister_ioapic(acpi_handle handle, u32 gsi_base); | 109 | int acpi_unregister_ioapic(acpi_handle handle, u32 gsi_base); |
110 | void acpi_irq_stats_init(void); | 110 | void acpi_irq_stats_init(void); |
111 | extern u32 acpi_irq_handled; | 111 | extern u32 acpi_irq_handled; |
112 | 112 | ||
113 | extern struct acpi_mcfg_allocation *pci_mmcfg_config; | 113 | extern struct acpi_mcfg_allocation *pci_mmcfg_config; |
114 | extern int pci_mmcfg_config_num; | 114 | extern int pci_mmcfg_config_num; |
115 | 115 | ||
116 | extern int sbf_port; | 116 | extern int sbf_port; |
117 | extern unsigned long acpi_realmode_flags; | 117 | extern unsigned long acpi_realmode_flags; |
118 | 118 | ||
119 | int acpi_register_gsi (u32 gsi, int triggering, int polarity); | 119 | int acpi_register_gsi (u32 gsi, int triggering, int polarity); |
120 | int acpi_gsi_to_irq (u32 gsi, unsigned int *irq); | 120 | int acpi_gsi_to_irq (u32 gsi, unsigned int *irq); |
121 | 121 | ||
122 | #ifdef CONFIG_X86_IO_APIC | 122 | #ifdef CONFIG_X86_IO_APIC |
123 | extern int acpi_get_override_irq(int bus_irq, int *trigger, int *polarity); | 123 | extern int acpi_get_override_irq(int bus_irq, int *trigger, int *polarity); |
124 | #else | 124 | #else |
125 | #define acpi_get_override_irq(bus, trigger, polarity) (-1) | 125 | #define acpi_get_override_irq(bus, trigger, polarity) (-1) |
126 | #endif | 126 | #endif |
127 | /* | 127 | /* |
128 | * This function undoes the effect of one call to acpi_register_gsi(). | 128 | * This function undoes the effect of one call to acpi_register_gsi(). |
129 | * If this matches the last registration, any IRQ resources for gsi | 129 | * If this matches the last registration, any IRQ resources for gsi |
130 | * are freed. | 130 | * are freed. |
131 | */ | 131 | */ |
132 | void acpi_unregister_gsi (u32 gsi); | 132 | void acpi_unregister_gsi (u32 gsi); |
133 | 133 | ||
134 | struct acpi_prt_entry { | 134 | struct acpi_prt_entry { |
135 | struct list_head node; | 135 | struct list_head node; |
136 | struct acpi_pci_id id; | 136 | struct acpi_pci_id id; |
137 | u8 pin; | 137 | u8 pin; |
138 | struct { | 138 | struct { |
139 | acpi_handle handle; | 139 | acpi_handle handle; |
140 | u32 index; | 140 | u32 index; |
141 | } link; | 141 | } link; |
142 | u32 irq; | 142 | u32 irq; |
143 | }; | 143 | }; |
144 | 144 | ||
145 | struct acpi_prt_list { | 145 | struct acpi_prt_list { |
146 | int count; | 146 | int count; |
147 | struct list_head entries; | 147 | struct list_head entries; |
148 | }; | 148 | }; |
149 | 149 | ||
150 | struct pci_dev; | 150 | struct pci_dev; |
151 | 151 | ||
152 | int acpi_pci_irq_enable (struct pci_dev *dev); | 152 | int acpi_pci_irq_enable (struct pci_dev *dev); |
153 | void acpi_penalize_isa_irq(int irq, int active); | 153 | void acpi_penalize_isa_irq(int irq, int active); |
154 | 154 | ||
155 | void acpi_pci_irq_disable (struct pci_dev *dev); | 155 | void acpi_pci_irq_disable (struct pci_dev *dev); |
156 | 156 | ||
157 | struct acpi_pci_driver { | 157 | struct acpi_pci_driver { |
158 | struct acpi_pci_driver *next; | 158 | struct acpi_pci_driver *next; |
159 | int (*add)(acpi_handle handle); | 159 | int (*add)(acpi_handle handle); |
160 | void (*remove)(acpi_handle handle); | 160 | void (*remove)(acpi_handle handle); |
161 | }; | 161 | }; |
162 | 162 | ||
163 | int acpi_pci_register_driver(struct acpi_pci_driver *driver); | 163 | int acpi_pci_register_driver(struct acpi_pci_driver *driver); |
164 | void acpi_pci_unregister_driver(struct acpi_pci_driver *driver); | 164 | void acpi_pci_unregister_driver(struct acpi_pci_driver *driver); |
165 | 165 | ||
166 | extern int ec_read(u8 addr, u8 *val); | 166 | extern int ec_read(u8 addr, u8 *val); |
167 | extern int ec_write(u8 addr, u8 val); | 167 | extern int ec_write(u8 addr, u8 val); |
168 | extern int ec_transaction(u8 command, | 168 | extern int ec_transaction(u8 command, |
169 | const u8 *wdata, unsigned wdata_len, | 169 | const u8 *wdata, unsigned wdata_len, |
170 | u8 *rdata, unsigned rdata_len, | 170 | u8 *rdata, unsigned rdata_len, |
171 | int force_poll); | 171 | int force_poll); |
172 | 172 | ||
173 | #if defined(CONFIG_ACPI_WMI) || defined(CONFIG_ACPI_WMI_MODULE) | 173 | #if defined(CONFIG_ACPI_WMI) || defined(CONFIG_ACPI_WMI_MODULE) |
174 | 174 | ||
175 | typedef void (*wmi_notify_handler) (u32 value, void *context); | 175 | typedef void (*wmi_notify_handler) (u32 value, void *context); |
176 | 176 | ||
177 | extern acpi_status wmi_evaluate_method(const char *guid, u8 instance, | 177 | extern acpi_status wmi_evaluate_method(const char *guid, u8 instance, |
178 | u32 method_id, | 178 | u32 method_id, |
179 | const struct acpi_buffer *in, | 179 | const struct acpi_buffer *in, |
180 | struct acpi_buffer *out); | 180 | struct acpi_buffer *out); |
181 | extern acpi_status wmi_query_block(const char *guid, u8 instance, | 181 | extern acpi_status wmi_query_block(const char *guid, u8 instance, |
182 | struct acpi_buffer *out); | 182 | struct acpi_buffer *out); |
183 | extern acpi_status wmi_set_block(const char *guid, u8 instance, | 183 | extern acpi_status wmi_set_block(const char *guid, u8 instance, |
184 | const struct acpi_buffer *in); | 184 | const struct acpi_buffer *in); |
185 | extern acpi_status wmi_install_notify_handler(const char *guid, | 185 | extern acpi_status wmi_install_notify_handler(const char *guid, |
186 | wmi_notify_handler handler, void *data); | 186 | wmi_notify_handler handler, void *data); |
187 | extern acpi_status wmi_remove_notify_handler(const char *guid); | 187 | extern acpi_status wmi_remove_notify_handler(const char *guid); |
188 | extern acpi_status wmi_get_event_data(u32 event, struct acpi_buffer *out); | 188 | extern acpi_status wmi_get_event_data(u32 event, struct acpi_buffer *out); |
189 | extern bool wmi_has_guid(const char *guid); | 189 | extern bool wmi_has_guid(const char *guid); |
190 | 190 | ||
191 | #endif /* CONFIG_ACPI_WMI */ | 191 | #endif /* CONFIG_ACPI_WMI */ |
192 | 192 | ||
193 | #define ACPI_VIDEO_OUTPUT_SWITCHING 0x0001 | ||
194 | #define ACPI_VIDEO_DEVICE_POSTING 0x0002 | ||
195 | #define ACPI_VIDEO_ROM_AVAILABLE 0x0004 | ||
196 | #define ACPI_VIDEO_BACKLIGHT 0x0008 | ||
197 | #define ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR 0x0010 | ||
198 | #define ACPI_VIDEO_BACKLIGHT_FORCE_VIDEO 0x0020 | ||
199 | #define ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VENDOR 0x0040 | ||
200 | #define ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VIDEO 0x0080 | ||
201 | #define ACPI_VIDEO_BACKLIGHT_DMI_VENDOR 0x0100 | ||
202 | #define ACPI_VIDEO_BACKLIGHT_DMI_VIDEO 0x0200 | ||
203 | #define ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VENDOR 0x0400 | ||
204 | #define ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VIDEO 0x0800 | ||
205 | |||
206 | #if defined(CONFIG_ACPI_VIDEO) || defined(CONFIG_ACPI_VIDEO_MODULE) | ||
207 | |||
208 | extern long acpi_video_get_capabilities(acpi_handle graphics_dev_handle); | ||
209 | extern long acpi_is_video_device(struct acpi_device *device); | ||
210 | extern int acpi_video_backlight_support(void); | ||
211 | extern int acpi_video_display_switch_support(void); | ||
212 | |||
213 | #else | ||
214 | |||
215 | static inline long acpi_video_get_capabilities(acpi_handle graphics_dev_handle) | ||
216 | { | ||
217 | return 0; | ||
218 | } | ||
219 | |||
220 | static inline long acpi_is_video_device(struct acpi_device *device) | ||
221 | { | ||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | static inline int acpi_video_backlight_support(void) | ||
226 | { | ||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | static inline int acpi_video_display_switch_support(void) | ||
231 | { | ||
232 | return 0; | ||
233 | } | ||
234 | |||
235 | #endif /* defined(CONFIG_ACPI_VIDEO) || defined(CONFIG_ACPI_VIDEO_MODULE) */ | ||
236 | |||
193 | extern int acpi_blacklisted(void); | 237 | extern int acpi_blacklisted(void); |
194 | #ifdef CONFIG_DMI | 238 | #ifdef CONFIG_DMI |
195 | extern void acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d); | 239 | extern void acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d); |
196 | extern int acpi_osi_setup(char *str); | 240 | extern int acpi_osi_setup(char *str); |
197 | #endif | 241 | #endif |
198 | 242 | ||
199 | #ifdef CONFIG_ACPI_NUMA | 243 | #ifdef CONFIG_ACPI_NUMA |
200 | int acpi_get_pxm(acpi_handle handle); | 244 | int acpi_get_pxm(acpi_handle handle); |
201 | int acpi_get_node(acpi_handle *handle); | 245 | int acpi_get_node(acpi_handle *handle); |
202 | #else | 246 | #else |
203 | static inline int acpi_get_pxm(acpi_handle handle) | 247 | static inline int acpi_get_pxm(acpi_handle handle) |
204 | { | 248 | { |
205 | return 0; | 249 | return 0; |
206 | } | 250 | } |
207 | static inline int acpi_get_node(acpi_handle *handle) | 251 | static inline int acpi_get_node(acpi_handle *handle) |
208 | { | 252 | { |
209 | return 0; | 253 | return 0; |
210 | } | 254 | } |
211 | #endif | 255 | #endif |
212 | extern int acpi_paddr_to_node(u64 start_addr, u64 size); | 256 | extern int acpi_paddr_to_node(u64 start_addr, u64 size); |
213 | 257 | ||
214 | extern int pnpacpi_disabled; | 258 | extern int pnpacpi_disabled; |
215 | 259 | ||
216 | #define PXM_INVAL (-1) | 260 | #define PXM_INVAL (-1) |
217 | #define NID_INVAL (-1) | 261 | #define NID_INVAL (-1) |
218 | 262 | ||
219 | int acpi_check_resource_conflict(struct resource *res); | 263 | int acpi_check_resource_conflict(struct resource *res); |
220 | 264 | ||
221 | int acpi_check_region(resource_size_t start, resource_size_t n, | 265 | int acpi_check_region(resource_size_t start, resource_size_t n, |
222 | const char *name); | 266 | const char *name); |
223 | int acpi_check_mem_region(resource_size_t start, resource_size_t n, | 267 | int acpi_check_mem_region(resource_size_t start, resource_size_t n, |
224 | const char *name); | 268 | const char *name); |
225 | 269 | ||
226 | #ifdef CONFIG_PM_SLEEP | 270 | #ifdef CONFIG_PM_SLEEP |
227 | void __init acpi_no_s4_hw_signature(void); | 271 | void __init acpi_no_s4_hw_signature(void); |
228 | void __init acpi_old_suspend_ordering(void); | 272 | void __init acpi_old_suspend_ordering(void); |
229 | #endif /* CONFIG_PM_SLEEP */ | 273 | #endif /* CONFIG_PM_SLEEP */ |
230 | #else /* CONFIG_ACPI */ | 274 | #else /* CONFIG_ACPI */ |
231 | 275 | ||
232 | static inline int early_acpi_boot_init(void) | 276 | static inline int early_acpi_boot_init(void) |
233 | { | 277 | { |
234 | return 0; | 278 | return 0; |
235 | } | 279 | } |
236 | static inline int acpi_boot_init(void) | 280 | static inline int acpi_boot_init(void) |
237 | { | 281 | { |
238 | return 0; | 282 | return 0; |
239 | } | 283 | } |
240 | 284 | ||
241 | static inline int acpi_boot_table_init(void) | 285 | static inline int acpi_boot_table_init(void) |
242 | { | 286 | { |
243 | return 0; | 287 | return 0; |
244 | } | 288 | } |
245 | 289 | ||
246 | static inline int acpi_mps_check(void) | 290 | static inline int acpi_mps_check(void) |
247 | { | 291 | { |
248 | return 0; | 292 | return 0; |
249 | } | 293 | } |
250 | 294 | ||
251 | static inline int acpi_check_resource_conflict(struct resource *res) | 295 | static inline int acpi_check_resource_conflict(struct resource *res) |
252 | { | 296 | { |
253 | return 0; | 297 | return 0; |
254 | } | 298 | } |
255 | 299 | ||
256 | static inline int acpi_check_region(resource_size_t start, resource_size_t n, | 300 | static inline int acpi_check_region(resource_size_t start, resource_size_t n, |
257 | const char *name) | 301 | const char *name) |
258 | { | 302 | { |
259 | return 0; | 303 | return 0; |
260 | } | 304 | } |
261 | 305 | ||
262 | static inline int acpi_check_mem_region(resource_size_t start, | 306 | static inline int acpi_check_mem_region(resource_size_t start, |
263 | resource_size_t n, const char *name) | 307 | resource_size_t n, const char *name) |
264 | { | 308 | { |
265 | return 0; | 309 | return 0; |
266 | } | 310 | } |
267 | 311 | ||
268 | #endif /* !CONFIG_ACPI */ | 312 | #endif /* !CONFIG_ACPI */ |
269 | #endif /*_LINUX_ACPI_H*/ | 313 | #endif /*_LINUX_ACPI_H*/ |
270 | 314 |