Re: [PATCH] ideapad-laptop: add new driver
From: Florian Echtler
Date: Sun Aug 15 2010 - 13:08:49 EST
On Fri, 2010-08-13 at 10:34 +0100, David Woodhouse wrote:
> Do you know how to restore it? Or do you have a copy of the 'lenovo-ec'
> module that it apparently contains?
Hello David,
I do have that module: I coaxed it out of Lenovo with the help of
gpl-violations.org as no source was available on my S10-3t. Since it is
flagged as Dual BSD/GPL license, there should be no harm in posting it
here. I hope it helps you in some way.
Florian
/*
* lenovo_s11_ec.c Lenovo_S11 ACPI EC Extras
*/
#include <linux/init.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h> /* printk() */
#include <linux/slab.h> /* kmalloc() */
#include <linux/fs.h> /* everything... */
#include <linux/errno.h> /* error codes */
#include <linux/types.h> /* size_t */
#include <linux/proc_fs.h>
#include <linux/delay.h>
#include <linux/fcntl.h> /* O_ACCMODE */
#include <asm/system.h> /* cli(), *_flags */
#include <asm/uaccess.h> /* copy_from/to_user */
#include <asm/io.h> /* inb, outb */
#include <linux/sched.h> /* set_cpus_allowed */
#include <linux/acpi.h>
#include <linux/seq_file.h>
#include <acpi/acpi_drivers.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
typedef unsigned long long evaluate_size_t;
#else
typedef unsigned long evaluate_size_t;
#endif
static DECLARE_MUTEX(gecn_sem);
static DECLARE_MUTEX(secn_sem);
static struct proc_dir_entry *lenovo_ec_fs_dir;
static char *model = NULL;
struct acpi_lenovo_cs2_device {
acpi_handle handle;
char DECN;
char GECN;
char SECN;
};
struct acpi_lenovo_cs2_device lenovo_cs2_device;
static acpi_handle vpc0_handle;
MODULE_LICENSE("Dual BSD/GPL");
module_param(model, charp, S_IRUGO);
/*
* Proc handle for reading the status of ec device.
*/
static int acpi_s11_ec_read_camera(struct seq_file *seq, void *offset)
{
char tmp;
if(ec_read(0xb8,&tmp)){
printk("ec_read fail\n");
return -EFAULT;
}
seq_printf(seq, "%d\n",!(tmp & 0x8) == 0);
return 0;
}
static int acpi_s11_ec_read_wifi(struct seq_file *seq, void *offset)
{
char tmp;
if(ec_read(0xbb,&tmp)){
printk("ec_read fail\n");
return -EFAULT;
}
seq_printf(seq, "%d\n",!(tmp & 0x1) == 0);
return 0;
}
static int acpi_s11_ec_read_dvme(struct seq_file *seq, void *offset)
{
char tmp;
if(ec_read(0xb8,&tmp)){
printk("ec_read fail\n");
return -EFAULT;
}
seq_printf(seq, "%d\n",!(tmp & 0x80) == 0);
return 0;
}
static int acpi_s11_ec_read_tp(struct seq_file *seq, void *offset)
{
char tmp;
if(ec_write(0x00,0x1b)){
printk("ec_write fail\n");
return -EFAULT;
}
mdelay(10);
if(ec_read(0x01,&tmp)){
printk("ec_read_fail\n");
return -EFAULT;
}
seq_printf(seq, "%d\n",tmp);
return 0;
}
static int acpi_s11_ec_read_antenna(struct seq_file *seq, void *offset)
{
char tmp;
if(ec_read(0xbb,&tmp)){
printk("ec_read_fail\n");
return -EFAULT;
}
seq_printf(seq, "%d\n",!(tmp & 0x10) == 0);
return 0;
}
static int acpi_s11_ec_read_w3g(struct seq_file *seq, void *offset)
{
char tmp;
if(ec_read(0xbb,&tmp)){
printk("ec_read_fail\n");
return -EFAULT;
}
seq_printf(seq, "%d\n",((tmp >> 6) & 0x1) == 1);
return 0;
}
static int acpi_s11_ec_read_brightness(struct seq_file *seq, void *offset)
{
char tmp;
int i;
if(ec_read(0xb9,&tmp)){
printk("ec_read fail\n");
return -EFAULT;
}
seq_printf(seq, "levels: ");
for(i=0;i<=100;i=i+10)
seq_printf(seq," %d",i);
seq_printf(seq, "\ncurrent: %d\n",tmp*10);
return 0;
}
static int acpi_s11_ec_write_camera(struct file *file, const char __user *buffer, size_t count, loff_t *data)
{
char tmp;
if(buffer[0]!='0' && buffer[0]!='1'){
return count;
}
if(ec_read(0xb8,&tmp)){
printk("ec_read fail\n");
return -EFAULT;
}
ec_write(0xb8, buffer[0]== '1' ? (0x08 | tmp) : (~0x08 & tmp));
return count;
}
static int acpi_s11_ec_write_wifi(struct file *file, const char __user *buffer, size_t count, loff_t *data)
{
char tmp;
if(buffer[0]!='0' && buffer[0]!='1'){
return count;
}
if(ec_read(0xbb,&tmp)){
printk("ec_read fail\n");
return -EFAULT;
}
ec_write(0xbb, buffer[0]== '1' ? (0x01 | tmp) : (~0x01 & tmp));
return count;
}
static int acpi_s11_ec_write_dvme(struct file *file, const char __user *buffer, size_t count, loff_t *data)
{
char tmp;
if(buffer[0] != '0' && buffer[0] != '1'){
return count;
}
if(ec_read(0xb8,&tmp)){
printk("ec_read fail\n");
return -EFAULT;
}
ec_write(0xb8, buffer[0]== '1' ? (0x80 | tmp) : (~0x80 & tmp));
return count;
}
static int acpi_s11_ec_write_brightness(struct file *file, const char __user *buffer, size_t count, loff_t *data)
{
unsigned int level = 0;
char str[5] = { 0 };
if(copy_from_user(str,buffer,count))
return -EFAULT;
str[count] = 0;
level = simple_strtoul(str, NULL, 0);
if(level > 100)
return -EFAULT;
if(ec_write(0xb9,(level / 10))){
printk("ec_write fail\n");
return -EFAULT;
}
return count;
}
static int acpi_s11_ec_write_w3g(struct file *file, const char __user *buffer, size_t count, loff_t *data)
{
char tmp;
if(buffer[0]!='0' && buffer[0]!='1'){
return count;
}
if(ec_read(0xbb,&tmp)){
printk("ec_read fail\n");
return -EFAULT;
}
ec_write(0xbb, buffer[0]== '1' ? (0x80 | tmp) : (~0x80 & tmp));
return count;
}
static int acpi_s11_ec_camera_open_fs(struct inode *inode, struct file *file)
{
return single_open(file, acpi_s11_ec_read_camera, PDE(inode)->data);
}
static int acpi_s11_ec_wifi_open_fs(struct inode *inode, struct file *file)
{
return single_open(file, acpi_s11_ec_read_wifi, PDE(inode)->data);
}
static int acpi_s11_ec_tp_open_fs(struct inode *inode, struct file *file)
{
return single_open(file, acpi_s11_ec_read_tp, PDE(inode)->data);
}
static int acpi_s11_ec_antenna_open_fs(struct inode *inode, struct file *file)
{
return single_open(file, acpi_s11_ec_read_antenna, PDE(inode)->data);
}
static int acpi_s11_ec_w3g_open_fs(struct inode *inode, struct file *file)
{
return single_open(file, acpi_s11_ec_read_w3g, PDE(inode)->data);
}
static int acpi_s11_ec_dvme_open_fs(struct inode *inode, struct file *file)
{
return single_open(file, acpi_s11_ec_read_dvme, PDE(inode)->data);
}
static int acpi_s11_ec_brightness_open_fs(struct inode *inode, struct file *file)
{
return single_open(file, acpi_s11_ec_read_brightness, PDE(inode)->data);
}
static struct file_operations acpi_s11_ec_camera_ops = {
.open = acpi_s11_ec_camera_open_fs,
.read = seq_read,
.write = acpi_s11_ec_write_camera,
.llseek = seq_lseek,
.release = single_release,
.owner = THIS_MODULE,
};
static struct file_operations acpi_s11_ec_wifi_ops = {
.open = acpi_s11_ec_wifi_open_fs,
.read = seq_read,
.write = acpi_s11_ec_write_wifi,
.llseek = seq_lseek,
.release = single_release,
.owner = THIS_MODULE,
};
static struct file_operations acpi_s11_ec_tp_ops = {
.open = acpi_s11_ec_tp_open_fs,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
.owner = THIS_MODULE,
};
static struct file_operations acpi_s11_ec_antenna_ops = {
.open = acpi_s11_ec_antenna_open_fs,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
.owner = THIS_MODULE,
};
static struct file_operations acpi_s11_ec_w3g_ops = {
.open = acpi_s11_ec_w3g_open_fs,
.read = seq_read,
.write = acpi_s11_ec_write_w3g,
.llseek = seq_lseek,
.release = single_release,
.owner = THIS_MODULE,
};
static struct file_operations acpi_s11_ec_dvme_ops = {
.open = acpi_s11_ec_dvme_open_fs,
.read = seq_read,
.write = acpi_s11_ec_write_dvme,
.llseek = seq_lseek,
.release = single_release,
.owner = THIS_MODULE,
};
static struct file_operations acpi_s11_ec_brightness_ops = {
.open = acpi_s11_ec_brightness_open_fs,
.read = seq_read,
.write = acpi_s11_ec_write_brightness,
.llseek = seq_lseek,
.release = single_release,
.owner = THIS_MODULE,
};
static int acpi_s20_ec_read_antenna(struct seq_file *seq, void *offset)
{
char tmp;
if(ec_read(0x52,&tmp)){
printk("ec_read_fail\n");
return -EFAULT;
}
seq_printf(seq, "%d\n",!(tmp & 0x01) == 0);
return 0;
}
static int acpi_s20_ec_read_w3g(struct seq_file *seq, void *offset)
{
evaluate_size_t tmp;
acpi_evaluate_integer(vpc0_handle, "_CFG", NULL,
&tmp);
seq_printf(seq, "%d\n",((tmp >> 17) & 0x1) == 1);
return 0;
}
static int acpi_s20_ec_read_wifi(struct seq_file *seq, void *offset)
{
char tmp;
if(ec_read(0x71,&tmp)){
printk("ec_read fail\n");
return -EFAULT;
}
seq_printf(seq, "%d\n",!(tmp & 0x1) == 0);
return 0;
}
static int acpi_s20_ec_antenna_open_fs(struct inode *inode, struct file *file)
{
return single_open(file, acpi_s20_ec_read_antenna, PDE(inode)->data);
}
static int acpi_s20_ec_w3g_open_fs(struct inode *inode, struct file *file)
{
return single_open(file, acpi_s20_ec_read_w3g, PDE(inode)->data);
}
static int acpi_s20_ec_wifi_open_fs(struct inode *inode, struct file *file)
{
return single_open(file, acpi_s20_ec_read_wifi, PDE(inode)->data);
}
static struct file_operations acpi_s20_ec_antenna_ops = {
.open = acpi_s20_ec_antenna_open_fs,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
.owner = THIS_MODULE,
};
static struct file_operations acpi_s20_ec_w3g_ops = {
.open = acpi_s20_ec_w3g_open_fs,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
.owner = THIS_MODULE,
};
static struct file_operations acpi_s20_ec_wifi_ops = {
.open = acpi_s20_ec_wifi_open_fs,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
.owner = THIS_MODULE,
};
static int acpi_cs2_ec_read_w3g(struct seq_file *seq, void *offset)
{
evaluate_size_t tmp;
union acpi_object arg0 = { ACPI_TYPE_INTEGER };
struct acpi_object_list args = { 1, &arg0 };
arg0.integer.value = 4;
if (lenovo_cs2_device.GECN != 1){
seq_printf(seq, "No device\n");
return 0;
}
else{
if (down_interruptible(&gecn_sem)){
return -ERESTARTSYS;
}
acpi_evaluate_integer(lenovo_cs2_device.handle, "GECN", &args, &tmp);
up(&gecn_sem);
seq_printf(seq, "%d\n",(int)tmp);
return 0;
}
}
static int acpi_cs2_ec_read_antenna(struct seq_file *seq, void *offset)
{
evaluate_size_t tmp;
union acpi_object arg0 = { ACPI_TYPE_INTEGER };
struct acpi_object_list args = { 1, &arg0 };
arg0.integer.value = 5;
if (lenovo_cs2_device.GECN != 1){
seq_printf(seq, "No device\n");
return 0;
}
else{
if (down_interruptible(&gecn_sem)){
return -ERESTARTSYS;
}
acpi_evaluate_integer(lenovo_cs2_device.handle, "GECN", &args, &tmp);
up(&gecn_sem);
seq_printf(seq, "%d\n",(int)tmp);
return 0;
}
}
static int acpi_cs2_ec_read_wifi(struct seq_file *seq, void *offset)
{
evaluate_size_t tmp;
union acpi_object arg0 = { ACPI_TYPE_INTEGER };
struct acpi_object_list args = { 1, &arg0 };
arg0.integer.value = 2;
if (lenovo_cs2_device.GECN != 1){
seq_printf(seq, "No device\n");
return 0;
}
else{
if (down_interruptible(&gecn_sem)){
return -ERESTARTSYS;
}
acpi_evaluate_integer(lenovo_cs2_device.handle, "GECN", &args, &tmp);
up(&gecn_sem);
seq_printf(seq, "%d\n",(int)tmp);
return 0;
}
}
static int acpi_cs2_ec_read_camera(struct seq_file *seq, void *offset)
{
evaluate_size_t tmp;
union acpi_object arg0 = { ACPI_TYPE_INTEGER };
struct acpi_object_list args = { 1, &arg0 };
arg0.integer.value = 1;
if (lenovo_cs2_device.GECN != 1){
seq_printf(seq, "No device\n");
return 0;
}
else{
if (down_interruptible(&gecn_sem)){
return -ERESTARTSYS;
}
acpi_evaluate_integer(lenovo_cs2_device.handle, "GECN", &args, &tmp);
up(&gecn_sem);
seq_printf(seq, "%d\n",(int)tmp);
return 0;
}
}
static int acpi_cs2_ec_read_bluetooth(struct seq_file *seq, void *offset)
{
evaluate_size_t tmp;
union acpi_object arg0 = { ACPI_TYPE_INTEGER };
struct acpi_object_list args = { 1, &arg0 };
arg0.integer.value = 3;
if (lenovo_cs2_device.GECN != 1){
seq_printf(seq, "No device\n");
return 0;
}
else{
if (down_interruptible(&gecn_sem)){
return -ERESTARTSYS;
}
acpi_evaluate_integer(lenovo_cs2_device.handle, "GECN", &args, &tmp);
up(&gecn_sem);
seq_printf(seq, "%d\n",(int)tmp);
return 0;
}
}
static int acpi_cs2_ec_write_camera(struct file *file, const char __user *buffer, size_t count, loff_t *data)
{
union acpi_object in_arg[2];
struct acpi_object_list args = { 2, in_arg };
if(buffer[0]!='0' && buffer[0]!='1'){
return count;
}
in_arg[0].type = ACPI_TYPE_INTEGER;
in_arg[0].integer.value = 1;
in_arg[1].type = ACPI_TYPE_INTEGER;
in_arg[1].integer.value = (buffer[0] == '1');
if (lenovo_cs2_device.SECN == 1){
if (down_interruptible(&secn_sem)){
return -ERESTARTSYS;
}
acpi_evaluate_object(lenovo_cs2_device.handle, "SECN", &args, NULL);
up(&secn_sem);
}
return count;
}
static int acpi_cs2_ec_write_wifi(struct file *file, const char __user *buffer, size_t count, loff_t *data)
{
union acpi_object in_arg[2];
struct acpi_object_list args = { 2, in_arg };
if(buffer[0]!='0' && buffer[0]!='1'){
return count;
}
in_arg[0].type = ACPI_TYPE_INTEGER;
in_arg[0].integer.value = 2;
in_arg[1].type = ACPI_TYPE_INTEGER;
in_arg[1].integer.value = (buffer[0] == '1');
if (lenovo_cs2_device.SECN == 1){
if (down_interruptible(&secn_sem)){
return -ERESTARTSYS;
}
acpi_evaluate_object(lenovo_cs2_device.handle, "SECN", &args, NULL);
up(&secn_sem);
}
return count;
}
static int acpi_cs2_ec_write_w3g(struct file *file, const char __user *buffer, size_t count, loff_t *data)
{
union acpi_object in_arg[2];
struct acpi_object_list args = { 2, in_arg };
if(buffer[0]!='0' && buffer[0]!='1'){
return count;
}
in_arg[0].type = ACPI_TYPE_INTEGER;
in_arg[0].integer.value = 4;
in_arg[1].type = ACPI_TYPE_INTEGER;
in_arg[1].integer.value = (buffer[0] == '1');
if (lenovo_cs2_device.SECN == 1){
if (down_interruptible(&secn_sem)){
return -ERESTARTSYS;
}
acpi_evaluate_object(lenovo_cs2_device.handle, "SECN", &args, NULL);
up(&secn_sem);
}
return count;
}
static int acpi_cs2_ec_write_bluetooth(struct file *file, const char __user *buffer, size_t count, loff_t *data)
{
union acpi_object in_arg[2];
struct acpi_object_list args = { 2, in_arg };
if(buffer[0]!='0' && buffer[0]!='1'){
return count;
}
in_arg[0].type = ACPI_TYPE_INTEGER;
in_arg[0].integer.value = 3;
in_arg[1].type = ACPI_TYPE_INTEGER;
in_arg[1].integer.value = (buffer[0] == '1');
if (lenovo_cs2_device.SECN == 1){
if (down_interruptible(&secn_sem)){
return -ERESTARTSYS;
}
acpi_evaluate_object(lenovo_cs2_device.handle, "SECN", &args, NULL);
up(&secn_sem);
}
return count;
}
static int acpi_cs2_ec_antenna_open_fs(struct inode *inode, struct file *file)
{
return single_open(file, acpi_cs2_ec_read_antenna, PDE(inode)->data);
}
static int acpi_cs2_ec_w3g_open_fs(struct inode *inode, struct file *file)
{
return single_open(file, acpi_cs2_ec_read_w3g, PDE(inode)->data);
}
static int acpi_cs2_ec_wifi_open_fs(struct inode *inode, struct file *file)
{
return single_open(file, acpi_cs2_ec_read_wifi, PDE(inode)->data);
}
static int acpi_cs2_ec_camera_open_fs(struct inode *inode, struct file *file)
{
return single_open(file, acpi_cs2_ec_read_camera, PDE(inode)->data);
}
static int acpi_cs2_ec_bluetooth_open_fs(struct inode *inode, struct file *file)
{
return single_open(file, acpi_cs2_ec_read_bluetooth, PDE(inode)->data);
}
static struct file_operations acpi_cs2_ec_antenna_ops = {
.open = acpi_cs2_ec_antenna_open_fs,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
.owner = THIS_MODULE,
};
static struct file_operations acpi_cs2_ec_w3g_ops = {
.open = acpi_cs2_ec_w3g_open_fs,
.read = seq_read,
.write = acpi_cs2_ec_write_w3g,
.llseek = seq_lseek,
.release = single_release,
.owner = THIS_MODULE,
};
static struct file_operations acpi_cs2_ec_wifi_ops = {
.open = acpi_cs2_ec_wifi_open_fs,
.read = seq_read,
.write = acpi_cs2_ec_write_wifi,
.llseek = seq_lseek,
.release = single_release,
.owner = THIS_MODULE,
};
static struct file_operations acpi_cs2_ec_camera_ops = {
.open = acpi_cs2_ec_camera_open_fs,
.read = seq_read,
.write = acpi_cs2_ec_write_camera,
.llseek = seq_lseek,
.release = single_release,
.owner = THIS_MODULE,
};
static struct file_operations acpi_cs2_ec_bluetooth_ops = {
.open = acpi_cs2_ec_bluetooth_open_fs,
.read = seq_read,
.write = acpi_cs2_ec_write_bluetooth,
.llseek = seq_lseek,
.release = single_release,
.owner = THIS_MODULE,
};
static int acpi_m3b_ec_read_antenna(struct seq_file *seq, void *offset)
{
char tmp;
if(ec_read(0x52,&tmp)){
printk("ec_read_fail\n");
return -EFAULT;
}
seq_printf(seq, "%d\n",!(tmp & 0x01) == 0);
return 0;
}
static int acpi_m3b_ec_antenna_open_fs(struct inode *inode, struct file *file)
{
return single_open(file, acpi_m3b_ec_read_antenna, PDE(inode)->data);
}
static struct file_operations acpi_m3b_ec_antenna_ops = {
.open = acpi_m3b_ec_antenna_open_fs,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
.owner = THIS_MODULE,
};
/*
* This function is used to regiter the ec device's proc file and operations
*/
static int lenovo_ec_proc_add(char *name,struct file_operations *acpi_ec_ops,struct proc_dir_entry *dir)
{
struct proc_dir_entry * entry = NULL;
entry = create_proc_entry(name, S_IRUGO,
dir);
if (!entry)
return -ENODEV;
else {
entry->proc_fops = acpi_ec_ops;
entry->data = NULL;
entry->owner = THIS_MODULE;
}
return 0;
}
/*
* The lenovo S11 has six ec devices : camera, wifi, brightness controller, touch pad, dvm enalbe, antenna.
*/
static int lenovo_s11_ec_init(void)
{
int result;
printk("Lenovo s11 ec driver init\n");
result = lenovo_ec_proc_add("camera",&acpi_s11_ec_camera_ops,lenovo_ec_fs_dir);
if(result == -ENODEV)
return result;
result = lenovo_ec_proc_add("wifi", &acpi_s11_ec_wifi_ops,lenovo_ec_fs_dir);
if(result == -ENODEV)
return result;
result = lenovo_ec_proc_add("tp", &acpi_s11_ec_tp_ops,lenovo_ec_fs_dir);
if(result == -ENODEV)
return result;
result = lenovo_ec_proc_add("dvme", &acpi_s11_ec_dvme_ops,lenovo_ec_fs_dir);
if(result == -ENODEV)
return result;
result = lenovo_ec_proc_add("brightness", &acpi_s11_ec_brightness_ops,lenovo_ec_fs_dir);
if(result == -ENODEV)
return result;
result = lenovo_ec_proc_add("antenna", &acpi_s11_ec_antenna_ops,lenovo_ec_fs_dir);
if(result == -ENODEV)
return result;
result = lenovo_ec_proc_add("w3g", &acpi_s11_ec_w3g_ops,lenovo_ec_fs_dir);
if(result == -ENODEV)
return result;
return 0;
}
static void lenovo_s11_ec_exit(void)
{
printk("Lenovo_s11 ec driver remove\n");
remove_proc_entry("camera", lenovo_ec_fs_dir);
remove_proc_entry("wifi", lenovo_ec_fs_dir);
remove_proc_entry("tp", lenovo_ec_fs_dir);
remove_proc_entry("dvme", lenovo_ec_fs_dir);
remove_proc_entry("brightness", lenovo_ec_fs_dir);
remove_proc_entry("antenna", lenovo_ec_fs_dir);
remove_proc_entry("w3g", lenovo_ec_fs_dir);
return;
}
static acpi_status
find_vpc0(acpi_handle handle, u32 lvl, void *context, void **rv)
{
char prefix[80] = {'\0'};
int *vpc;
struct acpi_buffer buffer = {sizeof(prefix), prefix };
vpc = context;
acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer);
if (strcmp(prefix,"VPC0") == 0){
vpc0_handle = handle;
*vpc = 1;
}
return AE_OK;
}
static int lenovo_s20_vpn_init(void)
{
int vpc0 = 0;
acpi_handle h_dummy1;
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX, find_vpc0, &vpc0, NULL);
if (vpc0 == 1){
if (ACPI_SUCCESS(acpi_get_handle(vpc0_handle, "_CFG", &h_dummy1)))
return 0;
}
return -1;
}
static int lenovo_s20_ec_init(void)
{
int result;
printk("Lenovo s20 ec driver init\n");
result = lenovo_s20_vpn_init();
if(result == -1)
return -ENODEV;
result = lenovo_ec_proc_add("antenna",&acpi_s20_ec_antenna_ops,lenovo_ec_fs_dir);
if(result == -ENODEV)
return result;
result = lenovo_ec_proc_add("w3g",&acpi_s20_ec_w3g_ops,lenovo_ec_fs_dir);
if(result == -ENODEV)
return result;
result = lenovo_ec_proc_add("wifi",&acpi_s20_ec_wifi_ops,lenovo_ec_fs_dir);
if(result == -ENODEV)
return result;
return 0;
}
static void lenovo_s20_ec_exit(void)
{
printk("Lenovo_s20 ec driver remove\n");
remove_proc_entry("antenna", lenovo_ec_fs_dir);
remove_proc_entry("w3g", lenovo_ec_fs_dir);
remove_proc_entry("wifi", lenovo_ec_fs_dir);
}
static acpi_status
find_sb(acpi_handle handle, u32 lvl, void *context, void **rv)
{
char prefix[80] = {'\0'};
int *sb;
struct acpi_buffer buffer = {sizeof(prefix), prefix };
sb = context;
acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer);
if (strcmp(prefix,"_SB_") == 0){
lenovo_cs2_device.handle = handle;
*sb = 1;
}
return AE_OK;
}
static int lenovo_cs2_rootpath_init(void)
{
int sb = 0;
acpi_handle h_dummy1;
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX, find_sb, &sb, NULL);
if (sb == 1){
if (ACPI_SUCCESS(acpi_get_handle(lenovo_cs2_device.handle, "DECN", &h_dummy1)))
lenovo_cs2_device.DECN = 1;
else
lenovo_cs2_device.DECN = 0;
if (ACPI_SUCCESS(acpi_get_handle(lenovo_cs2_device.handle, "SECN", &h_dummy1)))
lenovo_cs2_device.SECN = 1;
else
lenovo_cs2_device.SECN = 0;
if (ACPI_SUCCESS(acpi_get_handle(lenovo_cs2_device.handle, "GECN", &h_dummy1)))
lenovo_cs2_device.GECN = 1;
else
lenovo_cs2_device.GECN = 0;
return 0;
}
else{
lenovo_cs2_device.GECN = 0;
lenovo_cs2_device.SECN = 0;
lenovo_cs2_device.DECN = 0;
return -1;
}
}
static int lenovo_cs2_ec_init(void)
{
int result;
printk("Lenovo cs2 ec driver init\n");
result = lenovo_cs2_rootpath_init();
if(result == -1)
return -ENODEV;
result = lenovo_ec_proc_add("antenna",&acpi_cs2_ec_antenna_ops,lenovo_ec_fs_dir);
if(result == -ENODEV)
return result;
result = lenovo_ec_proc_add("w3g",&acpi_cs2_ec_w3g_ops,lenovo_ec_fs_dir);
if(result == -ENODEV)
return result;
result = lenovo_ec_proc_add("wifi",&acpi_cs2_ec_wifi_ops,lenovo_ec_fs_dir);
if(result == -ENODEV)
return result;
result = lenovo_ec_proc_add("camera",&acpi_cs2_ec_camera_ops,lenovo_ec_fs_dir);
if(result == -ENODEV)
return result;
result = lenovo_ec_proc_add("bluetooth",&acpi_cs2_ec_bluetooth_ops,lenovo_ec_fs_dir);
if(result == -ENODEV)
return result;
return 0;
}
static void lenovo_cs2_ec_exit(void)
{
printk("Lenovo_cs2 ec driver remove\n");
remove_proc_entry("antenna", lenovo_ec_fs_dir);
remove_proc_entry("w3g", lenovo_ec_fs_dir);
remove_proc_entry("wifi", lenovo_ec_fs_dir);
remove_proc_entry("camera", lenovo_ec_fs_dir);
}
static int lenovo_m3b_ec_init(void)
{
/* Use the acpi method interface same as Lenovo CS2*/
int result;
printk("Lenovo mariana-3b ec driver init\n");
result = lenovo_cs2_rootpath_init();
if(result == -1)
return -ENODEV;
result = lenovo_ec_proc_add("antenna",&acpi_cs2_ec_antenna_ops,lenovo_ec_fs_dir);
if(result == -ENODEV)
return result;
result = lenovo_ec_proc_add("w3g",&acpi_cs2_ec_w3g_ops,lenovo_ec_fs_dir);
if(result == -ENODEV)
return result;
result = lenovo_ec_proc_add("wifi",&acpi_cs2_ec_wifi_ops,lenovo_ec_fs_dir);
if(result == -ENODEV)
return result;
result = lenovo_ec_proc_add("camera",&acpi_cs2_ec_camera_ops,lenovo_ec_fs_dir);
if(result == -ENODEV)
return result;
result = lenovo_ec_proc_add("bluetooth",&acpi_cs2_ec_bluetooth_ops,lenovo_ec_fs_dir);
if(result == -ENODEV)
return result;
return 0;
}
static void lenovo_m3b_ec_exit(void)
{
printk("Lenovo mariana-3b ec driver remove\n");
remove_proc_entry("antenna", lenovo_ec_fs_dir);
}
static int lenovo_ec_init(void)
{
lenovo_ec_fs_dir = proc_mkdir("lenovo",acpi_root_dir);
if (model != NULL){
if (strncmp(model, "S11", 3) == 0)
lenovo_s11_ec_init();
else if (strncmp(model, "S20", 3) == 0)
lenovo_s20_ec_init();
else if (strncmp(model, "CS2", 3) == 0)
lenovo_cs2_ec_init();
else if (strncmp(model, "M3B", 3) == 0)
lenovo_m3b_ec_init();
}
return 0;
}
static void lenovo_ec_exit(void)
{
if (model != NULL){
if (strncmp(model, "S11", 3) == 0)
lenovo_s11_ec_exit();
else if (strncmp(model, "S20", 3) == 0)
lenovo_s20_ec_exit();
else if (strncmp(model, "CS2", 3) == 0)
lenovo_cs2_ec_exit();
else if (strncmp(model, "M3B", 3) == 0)
lenovo_m3b_ec_exit();
}
remove_proc_entry("lenovo", acpi_root_dir);
}
module_init(lenovo_ec_init);
module_exit(lenovo_ec_exit);