Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
58ac7aa0
Commit
58ac7aa0
authored
Aug 10, 2010
by
David Woodhouse
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add Lenovo ideapad driver
Signed-off-by:
David Woodhouse
<
David.Woodhouse@intel.com
>
parent
f6cec0ae
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
290 additions
and
0 deletions
+290
-0
drivers/platform/x86/Kconfig
drivers/platform/x86/Kconfig
+7
-0
drivers/platform/x86/Makefile
drivers/platform/x86/Makefile
+1
-0
drivers/platform/x86/ideapad_acpi.c
drivers/platform/x86/ideapad_acpi.c
+282
-0
No files found.
drivers/platform/x86/Kconfig
View file @
58ac7aa0
...
...
@@ -219,6 +219,13 @@ config SONYPI_COMPAT
---help---
Build the sonypi driver compatibility code into the sony-laptop driver.
config IDEAPAD_ACPI
tristate "Lenovo IdeaPad ACPI Laptop Extras"
depends on ACPI
depends on RFKILL
help
This is a driver for the rfkill switches on Lenovo IdeaPad netbooks.
config THINKPAD_ACPI
tristate "ThinkPad ACPI Laptop Extras"
depends on ACPI
...
...
drivers/platform/x86/Makefile
View file @
58ac7aa0
...
...
@@ -15,6 +15,7 @@ obj-$(CONFIG_ACERHDF) += acerhdf.o
obj-$(CONFIG_HP_WMI)
+=
hp-wmi.o
obj-$(CONFIG_TC1100_WMI)
+=
tc1100-wmi.o
obj-$(CONFIG_SONY_LAPTOP)
+=
sony-laptop.o
obj-$(CONFIG_IDEAPAD_ACPI)
+=
ideapad_acpi.o
obj-$(CONFIG_THINKPAD_ACPI)
+=
thinkpad_acpi.o
obj-$(CONFIG_FUJITSU_LAPTOP)
+=
fujitsu-laptop.o
obj-$(CONFIG_PANASONIC_LAPTOP)
+=
panasonic-laptop.o
...
...
drivers/platform/x86/ideapad_acpi.c
0 → 100644
View file @
58ac7aa0
/*
* ideapad_acpi.c - Lenovo IdeaPad ACPI Extras
*
* Copyright © 2010 Intel Corporation
* Copyright © 2010 David Woodhouse <dwmw2@infradead.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include <linux/rfkill.h>
#define IDEAPAD_DEV_CAMERA 0
#define IDEAPAD_DEV_WLAN 1
#define IDEAPAD_DEV_BLUETOOTH 2
#define IDEAPAD_DEV_3G 3
#define IDEAPAD_DEV_KILLSW 4
static
struct
rfkill
*
ideapad_rfkill
[
5
];
static
const
char
*
ideapad_rfk_names
[]
=
{
"ideapad_camera"
,
"ideapad_wlan"
,
"ideapad_bluetooth"
,
"ideapad_3g"
,
"ideapad_rfkill"
};
static
const
int
ideapad_rfk_types
[]
=
{
0
,
RFKILL_TYPE_WLAN
,
RFKILL_TYPE_BLUETOOTH
,
RFKILL_TYPE_WWAN
,
RFKILL_TYPE_WLAN
};
static
int
ideapad_dev_exists
(
int
device
)
{
acpi_status
status
;
union
acpi_object
in_param
;
struct
acpi_object_list
input
=
{
1
,
&
in_param
};
struct
acpi_buffer
output
;
union
acpi_object
out_obj
;
output
.
length
=
sizeof
(
out_obj
);
output
.
pointer
=
&
out_obj
;
in_param
.
type
=
ACPI_TYPE_INTEGER
;
in_param
.
integer
.
value
=
device
+
1
;
status
=
acpi_evaluate_object
(
NULL
,
"
\\
_SB_.DECN"
,
&
input
,
&
output
);
if
(
ACPI_FAILURE
(
status
))
{
printk
(
KERN_WARNING
"IdeaPAD
\\
_SB_.DECN method failed %d. Is this an IdeaPAD?
\n
"
,
status
);
return
-
ENODEV
;
}
if
(
out_obj
.
type
!=
ACPI_TYPE_INTEGER
)
{
printk
(
KERN_WARNING
"IdeaPAD
\\
_SB_.DECN method returned unexpected type
\n
"
);
return
-
ENODEV
;
}
return
out_obj
.
integer
.
value
;
}
static
int
ideapad_dev_get_state
(
int
device
)
{
acpi_status
status
;
union
acpi_object
in_param
;
struct
acpi_object_list
input
=
{
1
,
&
in_param
};
struct
acpi_buffer
output
;
union
acpi_object
out_obj
;
output
.
length
=
sizeof
(
out_obj
);
output
.
pointer
=
&
out_obj
;
in_param
.
type
=
ACPI_TYPE_INTEGER
;
in_param
.
integer
.
value
=
device
+
1
;
status
=
acpi_evaluate_object
(
NULL
,
"
\\
_SB_.GECN"
,
&
input
,
&
output
);
if
(
ACPI_FAILURE
(
status
))
{
printk
(
KERN_WARNING
"IdeaPAD
\\
_SB_.GECN method failed %d
\n
"
,
status
);
return
-
ENODEV
;
}
if
(
out_obj
.
type
!=
ACPI_TYPE_INTEGER
)
{
printk
(
KERN_WARNING
"IdeaPAD
\\
_SB_.GECN method returned unexpected type
\n
"
);
return
-
ENODEV
;
}
return
out_obj
.
integer
.
value
;
}
static
int
ideapad_dev_set_state
(
int
device
,
int
state
)
{
acpi_status
status
;
union
acpi_object
in_params
[
2
];
struct
acpi_object_list
input
=
{
2
,
in_params
};
in_params
[
0
].
type
=
ACPI_TYPE_INTEGER
;
in_params
[
0
].
integer
.
value
=
device
+
1
;
in_params
[
1
].
type
=
ACPI_TYPE_INTEGER
;
in_params
[
1
].
integer
.
value
=
state
;
status
=
acpi_evaluate_object
(
NULL
,
"
\\
_SB_.SECN"
,
&
input
,
NULL
);
if
(
ACPI_FAILURE
(
status
))
{
printk
(
KERN_WARNING
"IdeaPAD
\\
_SB_.SECN method failed %d
\n
"
,
status
);
return
-
ENODEV
;
}
return
0
;
}
static
ssize_t
show_ideapad_cam
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
{
int
state
=
ideapad_dev_get_state
(
IDEAPAD_DEV_CAMERA
);
if
(
state
<
0
)
return
state
;
return
sprintf
(
buf
,
"%d
\n
"
,
state
);
}
static
ssize_t
store_ideapad_cam
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
count
)
{
int
ret
,
state
;
if
(
!
count
)
return
0
;
if
(
sscanf
(
buf
,
"%i"
,
&
state
)
!=
1
)
return
-
EINVAL
;
ret
=
ideapad_dev_set_state
(
IDEAPAD_DEV_CAMERA
,
state
);
if
(
ret
<
0
)
return
ret
;
return
count
;
}
static
DEVICE_ATTR
(
camera_power
,
0644
,
show_ideapad_cam
,
store_ideapad_cam
);
static
int
ideapad_rfk_set
(
void
*
data
,
bool
blocked
)
{
int
device
=
(
unsigned
long
)
data
;
if
(
device
==
IDEAPAD_DEV_KILLSW
)
return
-
EINVAL
;
return
ideapad_dev_set_state
(
device
,
!
blocked
);
}
static
struct
rfkill_ops
ideapad_rfk_ops
=
{
.
set_block
=
ideapad_rfk_set
,
};
static
void
ideapad_sync_rfk_state
(
void
)
{
int
hw_blocked
=
!
ideapad_dev_get_state
(
IDEAPAD_DEV_KILLSW
);
int
i
;
rfkill_set_hw_state
(
ideapad_rfkill
[
IDEAPAD_DEV_KILLSW
],
hw_blocked
);
for
(
i
=
IDEAPAD_DEV_WLAN
;
i
<
IDEAPAD_DEV_KILLSW
;
i
++
)
if
(
ideapad_rfkill
[
i
])
rfkill_set_hw_state
(
ideapad_rfkill
[
i
],
hw_blocked
);
if
(
hw_blocked
)
return
;
for
(
i
=
IDEAPAD_DEV_WLAN
;
i
<
IDEAPAD_DEV_KILLSW
;
i
++
)
if
(
ideapad_rfkill
[
i
])
rfkill_set_sw_state
(
ideapad_rfkill
[
i
],
!
ideapad_dev_get_state
(
i
));
}
static
int
ideapad_register_rfkill
(
struct
acpi_device
*
device
,
int
dev
)
{
int
ret
;
ideapad_rfkill
[
dev
]
=
rfkill_alloc
(
ideapad_rfk_names
[
dev
],
&
device
->
dev
,
ideapad_rfk_types
[
dev
],
&
ideapad_rfk_ops
,
(
void
*
)(
long
)
dev
);
if
(
!
ideapad_rfkill
[
dev
])
return
-
ENOMEM
;
ret
=
rfkill_register
(
ideapad_rfkill
[
dev
]);
if
(
ret
)
{
rfkill_destroy
(
ideapad_rfkill
[
dev
]);
return
ret
;
}
return
0
;
}
static
void
ideapad_unregister_rfkill
(
int
dev
)
{
if
(
!
ideapad_rfkill
[
dev
])
return
;
rfkill_unregister
(
ideapad_rfkill
[
dev
]);
rfkill_destroy
(
ideapad_rfkill
[
dev
]);
}
static
const
struct
acpi_device_id
ideapad_device_ids
[]
=
{
{
"VPC2004"
,
0
},
{
""
,
0
},
};
MODULE_DEVICE_TABLE
(
acpi
,
ideapad_device_ids
);
static
int
ideapad_acpi_add
(
struct
acpi_device
*
device
)
{
int
i
;
int
devs_present
[
5
];
for
(
i
=
IDEAPAD_DEV_CAMERA
;
i
<
IDEAPAD_DEV_KILLSW
;
i
++
)
{
devs_present
[
i
]
=
ideapad_dev_exists
(
i
);
if
(
devs_present
[
i
]
<
0
)
return
devs_present
[
i
];
}
/* The hardware switch is always present */
devs_present
[
IDEAPAD_DEV_KILLSW
]
=
1
;
if
(
devs_present
[
IDEAPAD_DEV_CAMERA
])
{
int
ret
=
device_create_file
(
&
device
->
dev
,
&
dev_attr_camera_power
);
if
(
ret
)
return
ret
;
}
for
(
i
=
IDEAPAD_DEV_WLAN
;
i
<=
IDEAPAD_DEV_KILLSW
;
i
++
)
{
if
(
!
devs_present
[
i
])
continue
;
ideapad_register_rfkill
(
device
,
i
);
}
ideapad_sync_rfk_state
();
return
0
;
}
static
int
ideapad_acpi_remove
(
struct
acpi_device
*
device
,
int
type
)
{
int
i
;
device_remove_file
(
&
device
->
dev
,
&
dev_attr_camera_power
);
for
(
i
=
0
;
i
<
5
;
i
++
)
ideapad_unregister_rfkill
(
i
);
return
0
;
}
static
void
ideapad_acpi_notify
(
struct
acpi_device
*
device
,
u32
event
)
{
ideapad_sync_rfk_state
();
}
static
struct
acpi_driver
ideapad_acpi_driver
=
{
.
name
=
"ideapad_acpi"
,
.
class
=
"IdeaPad"
,
.
ids
=
ideapad_device_ids
,
.
ops
.
add
=
ideapad_acpi_add
,
.
ops
.
remove
=
ideapad_acpi_remove
,
.
ops
.
notify
=
ideapad_acpi_notify
,
.
owner
=
THIS_MODULE
,
};
static
int
__init
ideapad_acpi_module_init
(
void
)
{
acpi_bus_register_driver
(
&
ideapad_acpi_driver
);
return
0
;
}
static
void
__exit
ideapad_acpi_module_exit
(
void
)
{
acpi_bus_unregister_driver
(
&
ideapad_acpi_driver
);
}
MODULE_AUTHOR
(
"David Woodhouse <dwmw2@infradead.org>"
);
MODULE_DESCRIPTION
(
"IdeaPad ACPI Extras"
);
MODULE_LICENSE
(
"GPL"
);
module_init
(
ideapad_acpi_module_init
);
module_exit
(
ideapad_acpi_module_exit
);
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment