diff -Nru la-2.6.8.1/drivers/acpi/pcc_acpi.c linux-2.6.8.1/drivers/acpi/pcc_acpi.c --- la-2.6.8.1/drivers/acpi/pcc_acpi.c 2004-08-20 13:20:49.000000000 -0700 +++ linux-2.6.8.1/drivers/acpi/pcc_acpi.c 2004-08-21 22:52:32.000000000 -0700 @@ -20,6 +20,11 @@ *--------------------------------------------------------------------------- * * ChangeLog: + * Aug.20, 2004 David Bronaugh + * - v0.6 Correct brightness controls to reflect reality + * based on information gleaned by Hiroshi Miura + * and discussions with Hiroshi Miura + * * Aug.10, 2004 Hiroshi Miura * - v0.5 support LCD brightness control * based on the disclosed information by MEI. @@ -39,7 +44,7 @@ * */ -#define ACPI_PCC_VERSION "0.5" +#define ACPI_PCC_VERSION "0.6" #include #include @@ -56,10 +61,10 @@ ACPI_MODULE_NAME ("pcc_acpi") MODULE_AUTHOR("Hiroshi Miura"); -MODULE_DESCRIPTION("ACPI HotKey driver for lets note"); +MODULE_DESCRIPTION("ACPI HotKey driver for Panasonic Lets Note laptops"); MODULE_LICENSE("GPL"); -#define LOGPREFIX "acpi_pcc: " +#define LOGPREFIX "pcc_acpi: " /**************************************************** * Define ACPI PATHs @@ -81,15 +86,24 @@ #define PROC_PCC "pcc" #define PROC_VIDEO "video" -#define ACPI_HOTKEY_DRIVER_NAME "PCC HotKey Driver" +#define ACPI_PCC_DRIVER_NAME "PCC HotKey Driver" #define ACPI_HOTKEY_DEVICE_NAME "HotKey" #define ACPI_HOTKEY_CLASS "HKEY" +/* LCD_TYPEs: 0 = Normal, 1 = Semi-transparent + ENV_STATEs: Normal temp=0x01, High temp=0x81, N/A=0x00 +*/ +enum SINF_BITS { SINF_NUM_BATTERIES, SINF_LCD_TYPE, SINF_AC_MAX_BRIGHT, + SINF_AC_MIN_BRIGHT, SINF_AC_CUR_BRIGHT, SINF_DC_MAX_BRIGHT, + SINF_DC_MIN_BRIGHT, SINF_DC_CUR_BRIGHT, SINF_MUTE, + SINF_RESERVED, SINF_ENV_STATE, +}; + static int acpi_pcc_hotkey_add (struct acpi_device *device); static int acpi_pcc_hotkey_remove (struct acpi_device *device, int type); static struct acpi_driver acpi_hotkey_driver = { - .name = ACPI_HOTKEY_DRIVER_NAME, + .name = ACPI_PCC_DRIVER_NAME, .class = ACPI_HOTKEY_CLASS, .ids = HKEY_HID, .ops = { @@ -104,8 +118,17 @@ unsigned long status; }; -static int -write_sset(int func, int val) +typedef struct _ProcItem +{ + const char* name; + char* (*read_func)(char*); + unsigned long (*write_func)(const char*, unsigned long); +} ProcItem; + +static int num_sifr; +static struct proc_dir_entry* acpi_pcc_dir; + +static int write_sset(int func, int val) { struct acpi_object_list params; union acpi_object in_objs[2]; @@ -124,8 +147,7 @@ return_VALUE(status == AE_OK); } -static int -read_acpi_int(acpi_handle handle, const char* methodName, int* pVal) +static int read_acpi_int(acpi_handle handle, const char* methodName, int* pVal) { struct acpi_buffer results; union acpi_object out_objs[1]; @@ -136,55 +158,49 @@ status = acpi_evaluate_object(handle, (char*)methodName, 0, &results); if (ACPI_FAILURE(status)) { - printk(KERN_INFO "acpi evaluate error on %s\n", methodName); + printk(KERN_INFO LOGPREFIX "acpi evaluate error on %s\n", + methodName); return (-EFAULT); } if (out_objs[0].type == ACPI_TYPE_INTEGER) { *pVal = out_objs[0].integer.value; } else { - printk(KERN_INFO "return value is not int\n"); + printk(KERN_INFO LOGPREFIX "return value is not int\n"); status = AE_ERROR; } return (status == AE_OK); } -static struct proc_dir_entry* acpi_pcc_dir; - -typedef struct _ProcItem -{ - const char* name; - char* (*read_func)(char*); - unsigned long (*write_func)(const char*, unsigned long); -} ProcItem; - - /* register utils for proc handler */ -static int -dispatch_read(char* page, char** start, off_t off, int count, int* eof, - ProcItem* item) +static int dispatch_read(char* page, char** start, off_t off, int count, + int* eof, ProcItem* item) { char* p = page; int len; - if (off == 0) { - if (item->read_func) - p = item->read_func(p); + if (off == 0 && item->read_func) { + p = item->read_func(p); } /* ISSUE: I don't understand this code */ len = (p - page); - if (len <= off+count) *eof = 1; + if (len <= off+count) { + *eof = 1; + } *start = page + off; len -= off; - if (len>count) len = count; - if (len<0) len = 0; + if (len > count) { + len = count; + } + if (len < 0) { + len = 0; + } return len; } -static int -dispatch_write(struct file* file, __user const char* buffer, +static int dispatch_write(struct file* file, __user const char* buffer, unsigned long count, ProcItem* item) { int result; @@ -197,8 +213,7 @@ tmp_buffer = kmalloc(count + 1, GFP_KERNEL); if (copy_from_user(tmp_buffer, buffer, count)) { result = -EFAULT; - } - else { + } else { tmp_buffer[count] = 0; result = item->write_func(tmp_buffer, count); } @@ -206,41 +221,34 @@ return result; } -static int* sinf; -static int num_sifr; - -static int -acpi_pcc_init_sinf_buffer(void) +static inline int acpi_pcc_get_sqty(void) { - acpi_status status = AE_OK; - - ACPI_FUNCTION_TRACE("acpi_pcc_init_sinf_buffer"); + int s; - if (!read_acpi_int(NULL, DEVICE_NAME_HKEY "." METHOD_HKEY_SQTY, &num_sifr)){ - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "evaluation error HKEY.SQTY\n")); - return_VALUE(-EINVAL); - } + ACPI_FUNCTION_TRACE("acpi_pcc_get_sqty"); - if ((sinf = (int*)kmalloc(sizeof(int) * (num_sifr + 1), GFP_KERNEL)) == NULL ) { - status = AE_ERROR; + if (read_acpi_int(NULL, DEVICE_NAME_HKEY "." METHOD_HKEY_SQTY, &s)) { + return s; + } else { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "evaluation error HKEY.SQTY\n")); + return -EINVAL; } - return_VALUE(status == AE_OK); } -static int -acpi_pcc_retrive_biosdata(void) +static int acpi_pcc_retrieve_biosdata(u32* sinf) { acpi_status status; struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; union acpi_object *hkey = NULL; int i; - ACPI_FUNCTION_TRACE("acpi_pcc_retrive_biosdata"); + ACPI_FUNCTION_TRACE("acpi_pcc_retrieve_biosdata"); status = acpi_evaluate_object(NULL, DEVICE_NAME_HKEY "." METHOD_HKEY_SINF, 0 , &buffer); if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "evaluation error HEKY.SINF\n")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "evaluation error HKEY.SINF\n")); return_VALUE(0); } @@ -259,7 +267,7 @@ for (i = 0; i < hkey->package.count; i++) { union acpi_object *element = &(hkey->package.elements[i]); if (likely(element->type == ACPI_TYPE_INTEGER)) { - sinf[i] = (int)element->integer.value; + sinf[i] = element->integer.value; } else ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid HKEY.SINF data\n")); } @@ -270,91 +278,160 @@ return_VALUE(status == AE_OK); } -static char* -acpi_pcc_read_brightness(char* p) +static char* acpi_pcc_read_sinf_field(char* p, int field) { - int i; + u32* sinf; - if (!acpi_pcc_retrive_biosdata()) + if (!(sinf = kmalloc(sizeof(u32) * num_sifr, GFP_KERNEL))) { + printk(KERN_INFO LOGPREFIX "Couldn't allocate %i bytes\n", + sizeof(u32) * num_sifr); return p; + } - for (i = 2; i < 8 ; i++) { - p += sprintf(p, "%d", sinf[i]); - switch (i) { - case 2: - case 3: - case 5: - case 6: - p += sprintf(p, ","); - break; - case 4: - case 7: - p += sprintf(p, "\n"); - break; - default: - p += sprintf(p, ","); - } + if (acpi_pcc_retrieve_biosdata(sinf)) { + p += sprintf(p, "%d\n", sinf[field]); + } else { + printk(KERN_INFO LOGPREFIX "Couldn't retrieve BIOS data\n"); } - + + kfree(sinf); return p; } -static char* -read_mute(char* p) +/* Sinf read methods */ +static char* acpi_pcc_read_num_batteries(char* p) { - if (!acpi_pcc_retrive_biosdata()) - return p; + return acpi_pcc_read_sinf_field(p, SINF_NUM_BATTERIES); +} - p += sprintf(p, "%d\n", sinf[8]); +static char* acpi_pcc_read_lcd_type(char* p) +{ + return acpi_pcc_read_sinf_field(p, SINF_LCD_TYPE); +} - return p; +static char* acpi_pcc_read_ac_max_brightness(char* p) +{ + return acpi_pcc_read_sinf_field(p, SINF_AC_MAX_BRIGHT); } -static unsigned long -write_mute(const char* buffer, unsigned long count) +static char* acpi_pcc_read_ac_min_brightness(char* p) { - int value; + return acpi_pcc_read_sinf_field(p, SINF_AC_MIN_BRIGHT); +} + +static char* acpi_pcc_read_ac_brightness(char* p) +{ + return acpi_pcc_read_sinf_field(p, SINF_AC_CUR_BRIGHT); +} + +static char* acpi_pcc_read_dc_max_brightness(char* p) +{ + return acpi_pcc_read_sinf_field(p, SINF_DC_MAX_BRIGHT); +} + +static char* acpi_pcc_read_dc_min_brightness(char* p) +{ + return acpi_pcc_read_sinf_field(p, SINF_DC_MIN_BRIGHT); +} + +static char* acpi_pcc_read_dc_brightness(char* p) +{ + return acpi_pcc_read_sinf_field(p, SINF_DC_CUR_BRIGHT); +} + +static char* acpi_pcc_read_mute(char* p) +{ + return acpi_pcc_read_sinf_field(p, SINF_MUTE); +} + +static char* acpi_pcc_read_env_state(char* p) +{ + return acpi_pcc_read_sinf_field(p, SINF_ENV_STATE); +} + +static unsigned long acpi_pcc_write_mute(const char* buffer, + unsigned long count) +{ + u32 value; if (sscanf(buffer, "%i", &value) == 1 && value >= 0 && value <= 1) { - write_sset(8, value); + write_sset(SINF_MUTE, value); } return count; } -static unsigned long -acpi_pcc_write_brightness(const char* buffer, unsigned long count) -{ - int value1, value2; +static unsigned long acpi_pcc_write_brightness(const char* buffer, + unsigned long count, + int min_index, int max_index, + int cur_index) +{ + u32 bright; + u32* sinf; + + if (!(sinf = kmalloc(sizeof(u32) * num_sifr, GFP_KERNEL))) { + printk(KERN_INFO LOGPREFIX "Couldn't allocate %i bytes\n", + sizeof(u32) * num_sifr); + return count; + } + + if (!acpi_pcc_retrieve_biosdata(sinf)) { + printk(KERN_INFO LOGPREFIX "Couldn't retrieve BIOS data\n"); + goto end; + } + + if (!sscanf(buffer, "%i", &bright)) { + printk(KERN_INFO LOGPREFIX "Invalid DC brightness\n"); + goto end; + } - if (sscanf(buffer, "%i,%i", &value1, &value2) == 2 && value1 >= 0 && value1 < 2 && value2 >=0 && value2 < 20) { - write_sset((value1 == 1)?7:4, value2); - } else - printk("write_brightness error\n"); + if (bright >= sinf[min_index] && bright <= sinf[max_index]) { + write_sset(cur_index, bright); + } +end: + kfree(sinf); return count; } -static char* -acpi_pcc_read_version(char* p) + +static unsigned long acpi_pcc_write_ac_brightness(const char* buffer, + unsigned long count) +{ + return acpi_pcc_write_brightness(buffer, count, SINF_AC_MIN_BRIGHT, + SINF_AC_MAX_BRIGHT, + SINF_AC_CUR_BRIGHT); +} + +static unsigned long acpi_pcc_write_dc_brightness(const char* buffer, + unsigned long count) +{ + return acpi_pcc_write_brightness(buffer, count, SINF_DC_MIN_BRIGHT, + SINF_DC_MAX_BRIGHT, + SINF_DC_CUR_BRIGHT); +} + +static char* acpi_pcc_read_version(char* p) { - p += sprintf(p, "%s version %s\n", ACPI_HOTKEY_DRIVER_NAME, ACPI_PCC_VERSION); + p += sprintf(p, "%s version %s\n", ACPI_PCC_DRIVER_NAME, + ACPI_PCC_VERSION); + p += sprintf(p, "%i functions\n", num_sifr); return p; } /* hotkey driver */ -static int -acpi_pcc_hotkey_get_key(struct acpi_hotkey *hotkey) +static int acpi_pcc_hotkey_get_key(struct acpi_hotkey *hotkey) { int result; int status; status = read_acpi_int(hotkey->handle, METHOD_HKEY_QUERY, &result); - if (!status) { + if (status > 0) { printk(KERN_INFO LOGPREFIX "error getting hotkey status\n"); - } else + } else { hotkey->status = result; + } return (status); } @@ -369,8 +446,9 @@ switch(event) { case HKEY_NOTIFY: - if (acpi_pcc_hotkey_get_key(hotkey)) + if (acpi_pcc_hotkey_get_key(hotkey)) { acpi_bus_generate_event(hotkey->device, event, hotkey->status); + } break; default: /* nothing to do */ @@ -383,37 +461,52 @@ * proc and module init */ +/* Note: These functions map *exactly* to the SINF/SSET functions */ ProcItem pcc_proc_items[] = { - { "brightness" , acpi_pcc_read_brightness , acpi_pcc_write_brightness}, - { "mute", read_mute, write_mute}, + { "num_batteries", acpi_pcc_read_num_batteries, NULL }, + { "lcd_type", acpi_pcc_read_lcd_type, NULL }, + { "ac_brightness_max" , acpi_pcc_read_ac_max_brightness, NULL }, + { "ac_brightness_min" , acpi_pcc_read_ac_min_brightness, NULL }, + { "ac_brightness" , acpi_pcc_read_ac_brightness, + acpi_pcc_write_ac_brightness}, + { "dc_brightness_max" , acpi_pcc_read_dc_max_brightness, NULL }, + { "dc_brightness_min" , acpi_pcc_read_dc_min_brightness, NULL }, + { "dc_brightness" , acpi_pcc_read_dc_brightness, + acpi_pcc_write_dc_brightness}, + { "mute", acpi_pcc_read_mute, acpi_pcc_write_mute}, { "version", acpi_pcc_read_version , NULL}, + { "environment_state", acpi_pcc_read_env_state, NULL }, { NULL , NULL , NULL}, }; -static acpi_status __init -add_device(ProcItem *proc_items, struct proc_dir_entry* proc_entry) +static acpi_status __init add_device(ProcItem *proc_items, + struct proc_dir_entry* proc_entry) { struct proc_dir_entry* proc; ProcItem* item; + int i; - for (item = proc_items; item->name; ++item) - { + for (item = proc_items, i = 0; item->name && i <= num_sifr; + ++item, ++i) { proc = create_proc_read_entry(item->name, - S_IFREG | S_IRUGO | S_IWUSR, - proc_entry, (read_proc_t*)dispatch_read, item); - if (proc) + S_IFREG | S_IRUGO | S_IWUSR, + proc_entry, + (read_proc_t*)dispatch_read, + item); + if (proc) { proc->owner = THIS_MODULE; - if (proc && item->write_func) + } + if (proc && item->write_func) { proc->write_proc = (write_proc_t*)dispatch_write; + } } return(AE_OK); } -static int __init -acpi_pcc_proc_init(void) +static int __init acpi_pcc_proc_init(void) { acpi_status status = AE_OK; @@ -430,8 +523,8 @@ return (status == AE_OK); } -static acpi_status __exit -remove_device(ProcItem *proc_items, struct proc_dir_entry* proc_entry) +static acpi_status __exit remove_device(ProcItem *proc_items, + struct proc_dir_entry* proc_entry) { ProcItem* item; @@ -441,8 +534,7 @@ } -static int -acpi_pcc_hotkey_add (struct acpi_device *device) +static int acpi_pcc_hotkey_add (struct acpi_device *device) { acpi_status status = AE_OK; struct acpi_hotkey *hotkey = NULL; @@ -452,9 +544,6 @@ if (!device) return_VALUE(-EINVAL); - acpi_pcc_proc_init(); - acpi_pcc_init_sinf_buffer(); - hotkey = kmalloc(sizeof(struct acpi_hotkey), GFP_KERNEL); if (!hotkey) return_VALUE(-ENOMEM); @@ -478,12 +567,15 @@ kfree(hotkey); return_VALUE(-ENODEV); } + + num_sifr = acpi_pcc_get_sqty(); + acpi_pcc_proc_init(); + return_VALUE(0); } -static int -acpi_pcc_hotkey_remove(struct acpi_device *device, int type) +static int acpi_pcc_hotkey_remove(struct acpi_device *device, int type) { acpi_status status = AE_OK; struct acpi_hotkey *hotkey = NULL; @@ -511,8 +603,7 @@ return_VALUE(status == AE_OK); } -static int __init -acpi_pcc_init(void) +static int __init acpi_pcc_init(void) { acpi_status result = AE_OK;