All of lore.kernel.org
 help / color / mirror / Atom feed
From: Florian Echtler <floe@butterbrot.org>
To: David Woodhouse <dwmw2@infradead.org>
Cc: Ike Panhc <ike.pan@canonical.com>,
	platform-driver-x86@vger.kernel.org, linux-acpi@vger.kernel.org,
	Matthew Garrett <mjg@redhat.com>, Len Brown <len.brown@intel.com>,
	Randy Dunlap <randy.dunlap@oracle.com>,
	Corentin Chary <corentincj@iksaif.net>,
	Andrew Morton <akpm@linux-foundation.org>,
	Alan Cox <alan@linux.intel.com>, Thomas Renninger <trenn@suse.de>,
	linux-kernel@vger.kernel.org
Subject: Re: [PATCH] ideapad-laptop: add new driver
Date: Sun, 15 Aug 2010 10:20:44 +0200	[thread overview]
Message-ID: <1281860444.24589.3.camel@flunder> (raw)
In-Reply-To: <1281692078.23680.487.camel@localhost>

[-- Attachment #1: Type: text/plain, Size: 442 bytes --]

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


[-- Attachment #2: lenovo_ec.c --]
[-- Type: text/x-csrc, Size: 27251 bytes --]

/*
 * 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);


      parent reply	other threads:[~2010-08-15  8:20 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-08-13  4:08 [PATCH] ideapad-laptop: add new driver Ike Panhc
2010-08-13  6:37 ` Corentin Chary
2010-08-13  6:37   ` Corentin Chary
2010-08-13  6:53   ` Ike Panhc
2010-08-13  7:01     ` Corentin Chary
2010-08-13  7:15       ` Ike Panhc
2010-08-13  9:22     ` David Woodhouse
2010-08-13  9:14 ` David Woodhouse
2010-08-13  9:27   ` Ike Panhc
2010-08-13  9:34     ` David Woodhouse
2010-08-14  2:56       ` Ike Panhc
2010-08-14  9:49         ` David Woodhouse
2010-08-15  2:33         ` Len Brown
2010-08-15  8:14       ` Florian Echtler
2010-08-15  8:20       ` Florian Echtler [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1281860444.24589.3.camel@flunder \
    --to=floe@butterbrot.org \
    --cc=akpm@linux-foundation.org \
    --cc=alan@linux.intel.com \
    --cc=corentincj@iksaif.net \
    --cc=dwmw2@infradead.org \
    --cc=ike.pan@canonical.com \
    --cc=len.brown@intel.com \
    --cc=linux-acpi@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mjg@redhat.com \
    --cc=platform-driver-x86@vger.kernel.org \
    --cc=randy.dunlap@oracle.com \
    --cc=trenn@suse.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.